001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.html;
018
019import static org.apache.juneau.collections.JsonMap.*;
020
021import java.io.*;
022import java.lang.reflect.*;
023import java.nio.charset.*;
024import java.util.*;
025import java.util.function.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.httppart.*;
030import org.apache.juneau.internal.*;
031import org.apache.juneau.serializer.*;
032import org.apache.juneau.svl.*;
033
034/**
035 * Context object that lives for the duration of a single serialization of {@link HtmlSerializer} and its subclasses.
036 *
037 * <p>
038 * See {@link Serializer} for details.
039 *
040 * <h5 class='section'>Notes:</h5><ul>
041 *    <li class='warn'>This class is not thread safe and is typically discarded after one use.
042 * </ul>
043 *
044 * <h5 class='section'>See Also:</h5><ul>
045 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlBasics">HTML Basics</a>
046
047 * </ul>
048 */
049public class HtmlDocSerializerSession extends HtmlStrippedDocSerializerSession {
050
051   //-----------------------------------------------------------------------------------------------------------------
052   // Static
053   //-----------------------------------------------------------------------------------------------------------------
054
055   private static final VarResolver DEFAULT_VR = VarResolver.create().defaultVars().vars(HtmlWidgetVar.class).build();
056
057   /**
058    * Creates a new builder for this object.
059    *
060    * @param ctx The context creating this session.
061    * @return A new builder.
062    */
063   public static Builder create(HtmlDocSerializer ctx) {
064      return new Builder(ctx);
065   }
066
067   //-----------------------------------------------------------------------------------------------------------------
068   // Builder
069   //-----------------------------------------------------------------------------------------------------------------
070
071   /**
072    * Builder class.
073    */
074   public static class Builder extends HtmlStrippedDocSerializerSession.Builder {
075
076      HtmlDocSerializer ctx;
077
078      /**
079       * Constructor
080       *
081       * @param ctx The context creating this session.
082       */
083      protected Builder(HtmlDocSerializer ctx) {
084         super(ctx);
085         this.ctx = ctx;
086      }
087
088      @Override
089      public HtmlDocSerializerSession build() {
090         return new HtmlDocSerializerSession(this);
091      }
092      @Override /* Overridden from Builder */
093      public <T> Builder apply(Class<T> type, Consumer<T> apply) {
094         super.apply(type, apply);
095         return this;
096      }
097
098      @Override /* Overridden from Builder */
099      public Builder debug(Boolean value) {
100         super.debug(value);
101         return this;
102      }
103
104      @Override /* Overridden from Builder */
105      public Builder properties(Map<String,Object> value) {
106         super.properties(value);
107         return this;
108      }
109
110      @Override /* Overridden from Builder */
111      public Builder property(String key, Object value) {
112         super.property(key, value);
113         return this;
114      }
115
116      @Override /* Overridden from Builder */
117      public Builder unmodifiable() {
118         super.unmodifiable();
119         return this;
120      }
121
122      @Override /* Overridden from Builder */
123      public Builder locale(Locale value) {
124         super.locale(value);
125         return this;
126      }
127
128      @Override /* Overridden from Builder */
129      public Builder localeDefault(Locale value) {
130         super.localeDefault(value);
131         return this;
132      }
133
134      @Override /* Overridden from Builder */
135      public Builder mediaType(MediaType value) {
136         super.mediaType(value);
137         return this;
138      }
139
140      @Override /* Overridden from Builder */
141      public Builder mediaTypeDefault(MediaType value) {
142         super.mediaTypeDefault(value);
143         return this;
144      }
145
146      @Override /* Overridden from Builder */
147      public Builder timeZone(TimeZone value) {
148         super.timeZone(value);
149         return this;
150      }
151
152      @Override /* Overridden from Builder */
153      public Builder timeZoneDefault(TimeZone value) {
154         super.timeZoneDefault(value);
155         return this;
156      }
157
158      @Override /* Overridden from Builder */
159      public Builder javaMethod(Method value) {
160         super.javaMethod(value);
161         return this;
162      }
163
164      @Override /* Overridden from Builder */
165      public Builder resolver(VarResolverSession value) {
166         super.resolver(value);
167         return this;
168      }
169
170      @Override /* Overridden from Builder */
171      public Builder schema(HttpPartSchema value) {
172         super.schema(value);
173         return this;
174      }
175
176      @Override /* Overridden from Builder */
177      public Builder schemaDefault(HttpPartSchema value) {
178         super.schemaDefault(value);
179         return this;
180      }
181
182      @Override /* Overridden from Builder */
183      public Builder uriContext(UriContext value) {
184         super.uriContext(value);
185         return this;
186      }
187
188      @Override /* Overridden from Builder */
189      public Builder fileCharset(Charset value) {
190         super.fileCharset(value);
191         return this;
192      }
193
194      @Override /* Overridden from Builder */
195      public Builder streamCharset(Charset value) {
196         super.streamCharset(value);
197         return this;
198      }
199
200      @Override /* Overridden from Builder */
201      public Builder useWhitespace(Boolean value) {
202         super.useWhitespace(value);
203         return this;
204      }
205   }
206
207   //-----------------------------------------------------------------------------------------------------------------
208   // Instance
209   //-----------------------------------------------------------------------------------------------------------------
210
211   /**
212    * Constructor.
213    *
214    * @param builder The builder for this object.
215    */
216   protected HtmlDocSerializerSession(Builder builder) {
217      super(builder);
218      ctx = builder.ctx;
219      addVarBean(HtmlWidgetMap.class, ctx.getWidgets());
220   }
221
222   private final HtmlDocSerializer ctx;
223
224   @Override /* SerializerSession */
225   protected VarResolverSession createDefaultVarResolverSession() {
226      return DEFAULT_VR.createSession();
227   }
228
229   /**
230    * Returns the {@link HtmlDocSerializer.Builder#navlinks(String...)} setting value in this context.
231    *
232    * @return
233    *    The {@link HtmlDocSerializer.Builder#navlinks(String...)} setting value in this context.
234    *    <jk>null</jk> if not specified.
235    *    Never an empty map.
236    */
237   public final String[] getNavLinks() {
238      return ctx.navlinks;
239   }
240
241   @Override /* Serializer */
242   protected void doSerialize(SerializerPipe out, Object o) throws IOException, SerializeException {
243
244      try (HtmlWriter w = getHtmlWriter(out)) {
245         try {
246            getTemplate().writeTo(this, w, o);
247         } catch (Exception e) {
248            throw new SerializeException(e);
249         }
250      }
251   }
252
253   /**
254    * Calls the parent {@link #doSerialize(SerializerPipe, Object)} method which invokes just the HTML serializer.
255    *
256    * @param out
257    *    Where to send the output from the serializer.
258    * @param o The object being serialized.
259    * @throws Exception Error occurred during serialization.
260    */
261   public void parentSerialize(Object out, Object o) throws Exception {
262      try (SerializerPipe pipe = createPipe(out)) {
263         super.doSerialize(pipe, o);
264      }
265   }
266   //-----------------------------------------------------------------------------------------------------------------
267   // Properties
268   //-----------------------------------------------------------------------------------------------------------------
269
270   /**
271    * Aside section contents.
272    *
273    * @see HtmlDocSerializer.Builder#aside(String...)
274    * @return
275    *    The overridden contents of the aside section on the HTML page.
276    */
277   protected final String[] getAside() {
278      return ctx.aside;
279   }
280
281   /**
282    * Aside section contents float.
283    *
284    * @see HtmlDocSerializer.Builder#asideFloat(AsideFloat)
285    * @return
286    *    The location of where to place the aside section.
287    */
288   protected final AsideFloat getAsideFloat() {
289      return ctx.asideFloat;
290   }
291
292   /**
293    * Footer section contents.
294    *
295    * @see HtmlDocSerializer.Builder#footer(String...)
296    * @return
297    *    The overridden contents of the footer section on the HTML page.
298    */
299   protected final String[] getFooter() {
300      return ctx.footer;
301   }
302
303   /**
304    * Additional head section content.
305    *
306    * @see HtmlDocSerializer.Builder#head(String...)
307    * @return
308    *    HTML content to add to the head section of the HTML page.
309    */
310   protected final String[] getHead() {
311      return ctx.head;
312   }
313
314   /**
315    * Header section contents.
316    *
317    * @see HtmlDocSerializer.Builder#header(String...)
318    * @return
319    *    The overridden contents of the header section on the HTML page.
320    */
321   protected final String[] getHeader() {
322      return ctx.header;
323   }
324
325   /**
326    * Nav section contents.
327    *
328    * @see HtmlDocSerializer.Builder#nav(String...)
329    * @return
330    *    The overridden contents of the nav section on the HTML page.
331    */
332   protected final String[] getNav() {
333      return ctx.nav;
334   }
335
336   /**
337    * Page navigation links.
338    *
339    * @see HtmlDocSerializer.Builder#navlinks(String...)
340    * @return
341    *    Navigation links to add to the HTML page.
342    */
343   protected final String[] getNavlinks() {
344      return ctx.navlinks;
345   }
346
347   /**
348    * No-results message.
349    *
350    * @see HtmlDocSerializer.Builder#noResultsMessage(String)
351    * @return
352    *    The message used when serializing an empty array or empty list.
353    */
354   protected final String getNoResultsMessage() {
355      return ctx.getNoResultsMessage();
356   }
357
358   /**
359    * Prevent word wrap on page.
360    *
361    * @see HtmlDocSerializer.Builder#nowrap()
362    * @return
363    *    <jk>true</jk> if <js>"* {white-space:nowrap}"</js> should be added to the CSS instructions on the page to prevent word wrapping.
364    */
365   protected final boolean isNowrap() {
366      return ctx.nowrap;
367   }
368
369   /**
370    * Resolve $ variables in serialized POJO.
371    *
372    * @see HtmlDocSerializer.Builder#resolveBodyVars()
373    * @return
374    *    <jk>true</jk> if $ variables in serialized POJO should be resolved.
375    */
376   protected final boolean isResolveBodyVars() {
377      return ctx.resolveBodyVars;
378   }
379
380   /**
381    * Javascript code.
382    *
383    * @see HtmlDocSerializer.Builder#script(String...)
384    * @return
385    *    Arbitrary Javascript to add to the HTML page.
386    */
387   protected final String[] getScript() {
388      return ctx.script;
389   }
390
391   /**
392    * CSS style code.
393    *
394    * @see HtmlDocSerializer.Builder#style(String...)
395    * @return
396    *    The CSS instructions to add to the HTML page.
397    */
398   protected final String[] getStyle() {
399      return ctx.style;
400   }
401
402   /**
403    * Stylesheet import URLs.
404    *
405    * @see HtmlDocSerializer.Builder#stylesheet(String...)
406    * @return
407    *    The link to the stylesheet of the HTML page.
408    */
409   protected final String[] getStylesheet() {
410      return ctx.stylesheet;
411   }
412
413   /**
414    * HTML document template.
415    *
416    * @see HtmlDocSerializer.Builder#template(Class)
417    * @return
418    *    The template to use for serializing the page.
419    */
420   protected final HtmlDocTemplate getTemplate() {
421      return ctx.getTemplate();
422   }
423
424   /**
425    * Performs an action on all widgets defined in his session.
426    *
427    * @param action The action to perform.
428    * @see HtmlDocSerializer.Builder#widgets(Class...)
429    * @return This object.
430    */
431   protected final HtmlDocSerializerSession forEachWidget(Consumer<HtmlWidget> action) {
432      ctx.forEachWidget(action);
433      return this;
434   }
435
436   //-----------------------------------------------------------------------------------------------------------------
437   // Other methods
438   //-----------------------------------------------------------------------------------------------------------------
439
440   @Override /* ContextSession */
441   protected JsonMap properties() {
442      return filteredMap("ctx", ctx, "varResolver", getVarResolver());
443   }
444}