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}