001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.html;
014
015import static org.apache.juneau.html.HtmlDocSerializer.*;
016
017import java.io.IOException;
018import java.util.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.serializer.*;
022import org.apache.juneau.svl.*;
023
024/**
025 * Context object that lives for the duration of a single serialization of {@link HtmlSerializer} and its subclasses.
026 *
027 * <p>
028 * See {@link Serializer} for details.
029 *
030 * <p>
031 * This class is NOT thread safe.  It is meant to be discarded after one-time use.
032 */
033public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
034
035   private static final VarResolver DEFAULT_VR = VarResolver.create().defaultVars().vars(HtmlWidgetVar.class).build();
036
037   private final HtmlDocSerializer ctx;
038   private final String[] navlinks, head, header, nav, aside, footer;
039   private final Set<String> style, stylesheet, script;
040   private final boolean nowrap;
041
042   /**
043    * Create a new session using properties specified in the context.
044    *
045    * @param ctx
046    *    The context creating this session object.
047    *    The context contains all the configuration settings for this object.
048    * @param args
049    *    Runtime arguments.
050    */
051   protected HtmlDocSerializerSession(HtmlDocSerializer ctx, SerializerSessionArgs args) {
052      super(ctx, args);
053      this.ctx = ctx;
054
055      header = getProperty(HTMLDOC_header, String[].class, ctx.getHeader());
056      nav = getProperty(HTMLDOC_nav, String[].class, ctx.getNav());
057      aside = getProperty(HTMLDOC_aside, String[].class, ctx.getAside());
058      footer = getProperty(HTMLDOC_footer, String[].class, ctx.getFooter());
059      navlinks = getProperty(HTMLDOC_navlinks, String[].class, ctx.getNavlinks());
060
061      // These can contain dups after variable resolution, so de-dup them with hashsets.
062      style = new LinkedHashSet<>(Arrays.asList(getProperty(HTMLDOC_style, String[].class, ctx.getStyle())));
063      stylesheet = new LinkedHashSet<>(Arrays.asList(getProperty(HTMLDOC_stylesheet, String[].class, ctx.getStylesheet())));
064      script = new LinkedHashSet<>(Arrays.asList(getProperty(HTMLDOC_script, String[].class, ctx.getScript())));
065
066      head = getProperty(HTMLDOC_head, String[].class, ctx.getHead());
067      nowrap = getProperty(HTMLDOC_nowrap, boolean.class, ctx.isNowrap());
068
069      varSessionObject(HtmlWidgetVar.SESSION_htmlWidgets, ctx.getWidgets());
070   }
071
072   @Override /* SerializerSession */
073   protected VarResolverSession createDefaultVarResolverSession() {
074      return DEFAULT_VR.createSession();
075   }
076
077   /**
078    * Returns the {@link HtmlDocSerializer#HTMLDOC_navlinks} setting value in this context.
079    *
080    * @return
081    *    The {@link HtmlDocSerializer#HTMLDOC_navlinks} setting value in this context.
082    *    <jk>null</jk> if not specified.
083    *    Never an empty map.
084    */
085   public final String[] getNavLinks() {
086      return navlinks;
087   }
088
089   @Override /* Serializer */
090   protected void doSerialize(SerializerPipe out, Object o) throws IOException, SerializeException {
091
092      try (HtmlWriter w = getHtmlWriter(out)) {
093         try {
094            getTemplate().writeTo(this, w, o);
095         } catch (Exception e) {
096            throw new SerializeException(e);
097         }
098      }
099   }
100
101   /**
102    * Calls the parent {@link #doSerialize(SerializerPipe, Object)} method which invokes just the HTML serializer.
103    *
104    * @param out
105    *    Where to send the output from the serializer.
106    * @param o The object being serialized.
107    * @throws Exception Error occurred during serialization.
108    */
109   public void parentSerialize(Object out, Object o) throws Exception {
110      try (SerializerPipe pipe = createPipe(out)) {
111         super.doSerialize(pipe, o);
112      }
113   }
114   //-----------------------------------------------------------------------------------------------------------------
115   // Properties
116   //-----------------------------------------------------------------------------------------------------------------
117
118   /**
119    * Configuration property:  Aside section contents.
120    *
121    * @see HtmlDocSerializer#HTMLDOC_aside
122    * @return
123    *    The overridden contents of the aside section on the HTML page.
124    */
125   protected final String[] getAside() {
126      return aside;
127   }
128
129   /**
130    * Configuration property:  Footer section contents.
131    *
132    * @see HtmlDocSerializer#HTMLDOC_footer
133    * @return
134    *    The overridden contents of the footer section on the HTML page.
135    */
136   protected final String[] getFooter() {
137      return footer;
138   }
139
140   /**
141    * Configuration property:  Additional head section content.
142    *
143    * @see HtmlDocSerializer#HTMLDOC_head
144    * @return
145    *    HTML content to add to the head section of the HTML page.
146    */
147   protected final String[] getHead() {
148      return head;
149   }
150
151   /**
152    * Configuration property:  Header section contents.
153    *
154    * @see HtmlDocSerializer#HTMLDOC_header
155    * @return
156    *    The overridden contents of the header section on the HTML page.
157    */
158   protected final String[] getHeader() {
159      return header;
160   }
161
162   /**
163    * Configuration property:  Nav section contents.
164    *
165    * @see HtmlDocSerializer#HTMLDOC_nav
166    * @return
167    *    The overridden contents of the nav section on the HTML page.
168    */
169   protected final String[] getNav() {
170      return nav;
171   }
172
173   /**
174    * Configuration property:  Page navigation links.
175    *
176    * @see HtmlDocSerializer#HTMLDOC_navlinks
177    * @return
178    *    Navigation links to add to the HTML page.
179    */
180   protected final String[] getNavlinks() {
181      return navlinks;
182   }
183
184   /**
185    * Configuration property:  No-results message.
186    *
187    * @see HtmlDocSerializer#HTMLDOC_noResultsMessage
188    * @return
189    *    The message used when serializing an empty array or empty list.
190    */
191   protected final String getNoResultsMessage() {
192      return ctx.getNoResultsMessage();
193   }
194
195   /**
196    * Configuration property:  Prevent word wrap on page.
197    *
198    * @see HtmlDocSerializer#HTMLDOC_nowrap
199    * @return
200    *    <jk>true</jk> if <js>"* {white-space:nowrap}"</js> shoudl be added to the CSS instructions on the page to prevent word wrapping.
201    */
202   protected final boolean isNowrap() {
203      return nowrap;
204   }
205
206   /**
207    * Configuration property:  Javascript code.
208    *
209    * @see HtmlDocSerializer#HTMLDOC_script
210    * @return
211    *    Arbitrary Javascript to add to the HTML page.
212    */
213   protected final Set<String> getScript() {
214      return script;
215   }
216
217   /**
218    * Configuration property:  CSS style code.
219    *
220    * @see HtmlDocSerializer#HTMLDOC_style
221    * @return
222    *    The CSS instructions to add to the HTML page.
223    */
224   protected final Set<String> getStyle() {
225      return style;
226   }
227
228   /**
229    * Configuration property:  Stylesheet import URLs.
230    *
231    * @see HtmlDocSerializer#HTMLDOC_stylesheet
232    * @return
233    *    The link to the stylesheet of the HTML page.
234    */
235   protected final Set<String> getStylesheet() {
236      return stylesheet;
237   }
238
239   /**
240    * Configuration property:  HTML document template.
241    *
242    * @see HtmlDocSerializer#HTMLDOC_template
243    * @return
244    *    The template to use for serializing the page.
245    */
246   protected final HtmlDocTemplate getTemplate() {
247      return ctx.getTemplate();
248   }
249
250   /**
251    * Configuration property:  Page navigation links.
252    *
253    * @see HtmlDocSerializer#HTMLDOC_navlinks
254    * @return
255    *    Navigation links to add to the HTML page.
256    */
257   protected final Collection<HtmlWidget> getWidgets() {
258      return ctx.getWidgets().values();
259   }
260
261   //-----------------------------------------------------------------------------------------------------------------
262   // Other methods
263   //-----------------------------------------------------------------------------------------------------------------
264
265   @Override /* Session */
266   public ObjectMap toMap() {
267      return super.toMap()
268         .append("HtmlDocSerializerSession", new DefaultFilteringObjectMap()
269            .append("aside", aside)
270            .append("head", head)
271            .append("header", header)
272            .append("footer", footer)
273            .append("nav", nav)
274            .append("navlinks", navlinks)
275            .append("script", script)
276            .append("style", style)
277            .append("stylesheet", stylesheet)
278            .append("varResolver", getVarResolver())
279         );
280   }
281}