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