1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.maven.doxia.siterenderer;
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.LinkedHashSet;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31
32 import org.apache.maven.artifact.Artifact;
33 import org.apache.maven.doxia.parser.Parser;
34 import org.apache.maven.doxia.site.SiteModel;
35 import org.apache.maven.doxia.site.skin.SkinModel;
36 import org.codehaus.plexus.util.ReaderFactory;
37 import org.codehaus.plexus.util.WriterFactory;
38
39 /**
40 * Context for a site rendering.
41 *
42 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
43 */
44 public class SiteRenderingContext {
45
46 public static class SiteDirectory {
47 private File path;
48 private boolean editable;
49 private boolean skipDuplicates;
50 private final Collection<File> editableSourceDirectories = new LinkedHashSet<>();
51
52 public SiteDirectory(File path, boolean editable) {
53 this(path, editable, false);
54 }
55
56 /**
57 *
58 * @param path path to the site directory containing Doxia sources files, expected to have a Doxia Site layout, i.e. one directory per Doxia parser module
59 * @param editable {@code true} if the site directory is expected to be editable
60 * @param skipDuplicates flag indicating if duplicates in this directory should be skipped ({@code true}) or lead to an exception ({@code false})
61 * @since 2.1
62 */
63 public SiteDirectory(File path, boolean editable, boolean skipDuplicates) {
64 this.path = path;
65 this.editable = editable;
66 this.skipDuplicates = skipDuplicates;
67 }
68
69 public File getPath() {
70 return path;
71 }
72
73 public boolean isEditable() {
74 return editable;
75 }
76
77 public boolean isSkipDuplicates() {
78 return skipDuplicates;
79 }
80
81 /**
82 * Add an alternative source directory to this site directory.
83 * This will implicitly turn it into an editable site directory. Multiple source directories can be used, the first one containing a file with a given name will be used for that file,
84 * the others will be ignored. This allows to have a main source directory and an optional overlay directory with custom files.
85 * Only necessary to call if the source directory is different from the site directory, otherwise the site directory will be used as source directory.
86 * @param sourceDirectory
87 * @since 2.1
88 */
89 public void addAlternativeEditableSourceDirectory(File sourceDirectory) {
90 editableSourceDirectories.add(sourceDirectory);
91 editable = true;
92 }
93
94 /**
95 * Get the source directories for this site directory. If no alternative source directory has been added via {@link #addAlternativeEditableSourceDirectory(File)}
96 * the site directory itself ({@link #getPath()}) will be returned as the only source directory.
97 * If the site directory is not editable, an empty collection will be returned.
98 * @return the source directories for this site directory
99 * @since 2.1
100 */
101 public Collection<File> getEditableSourceDirectories() {
102 if (!editable) {
103 return Collections.emptyList();
104 }
105 if (editableSourceDirectories.isEmpty()) {
106 return Collections.singleton(path);
107 } else {
108 return Collections.unmodifiableCollection(editableSourceDirectories);
109 }
110 }
111 }
112
113 private String inputEncoding = ReaderFactory.FILE_ENCODING;
114
115 private String outputEncoding = WriterFactory.UTF_8;
116
117 private String templateName;
118
119 private ClassLoader templateClassLoader;
120
121 private Map<String, ?> templateProperties;
122
123 private Locale locale = Locale.ROOT;
124
125 private List<Locale> siteLocales = new ArrayList<>();
126
127 private SiteModel siteModel;
128
129 private String defaultTitle;
130
131 private Artifact skin;
132
133 private SkinModel skinModel;
134
135 private File rootDirectory;
136
137 private List<SiteDirectory> siteDirectories = new ArrayList<>();
138
139 private Map<String, String> moduleExcludes;
140
141 private boolean validate;
142
143 private Date publishDate;
144
145 private File processedContentOutput;
146
147 private ParserConfigurator parserConfigurator;
148
149 private final Map<String, Object> attributes = new HashMap<>();
150
151 /**
152 * If input documents should be validated before parsing.
153 * By default no validation is performed.
154 *
155 * @return true if validation is switched on.
156 * @since 1.1.3
157 */
158 public boolean isValidate() {
159 return validate;
160 }
161
162 /**
163 * Switch on/off validation.
164 *
165 * @param validate true to switch on validation.
166 * @since 1.1.3
167 */
168 public void setValidate(boolean validate) {
169 this.validate = validate;
170 }
171
172 /**
173 * <p>Getter for the field <code>templateName</code>.</p>
174 *
175 * @return a {@link java.lang.String} object.
176 */
177 public String getTemplateName() {
178 return templateName;
179 }
180
181 /**
182 * <p>Getter for the field <code>templateClassLoader</code>.</p>
183 *
184 * @return a {@link java.lang.ClassLoader} object.
185 */
186 public ClassLoader getTemplateClassLoader() {
187 return templateClassLoader;
188 }
189
190 /**
191 * <p>Setter for the field <code>templateClassLoader</code>.</p>
192 *
193 * @param templateClassLoader a {@link java.lang.ClassLoader} object.
194 */
195 public void setTemplateClassLoader(ClassLoader templateClassLoader) {
196 this.templateClassLoader = templateClassLoader;
197 }
198
199 /**
200 * <p>Getter for the field <code>templateProperties</code>.</p>
201 *
202 * @return a {@link java.util.Map} object.
203 */
204 public Map<String, ?> getTemplateProperties() {
205 return templateProperties;
206 }
207
208 /**
209 * <p>Setter for the field <code>templateProperties</code>.</p>
210 *
211 * @param templateProperties a {@link java.util.Map} object.
212 */
213 public void setTemplateProperties(Map<String, ?> templateProperties) {
214 this.templateProperties = Collections.unmodifiableMap(templateProperties);
215 }
216
217 /**
218 * <p>Getter for the field <code>locale</code>.</p>
219 *
220 * @return a {@link java.util.Locale} object.
221 */
222 public Locale getLocale() {
223 return locale;
224 }
225
226 /**
227 * <p>Setter for the field <code>locale</code>.</p>
228 *
229 * @param locale a {@link java.util.Locale} object.
230 */
231 public void setLocale(Locale locale) {
232 this.locale = locale;
233 }
234
235 /**
236 * <p>Getter for the field <code>siteLocales</code> -
237 * a list of locales available for this site context.</p>
238 *
239 * @return a {@link java.util.List} object with {@link java.util.Locale} objects.
240 */
241 public List<Locale> getSiteLocales() {
242 return siteLocales;
243 }
244
245 /**
246 * <p>Adds passed locales to the list of site locales.</p>
247 *
248 * @param locales List of {@link java.util.Locale} objects to add to the site locales list.
249 */
250 public void addSiteLocales(List<Locale> locales) {
251 siteLocales.addAll(locales);
252 }
253
254 /**
255 * <p>Getter for the field <code>siteModel</code>.</p>
256 *
257 * @return a {@link org.apache.maven.doxia.site.SiteModel} object.
258 */
259 public SiteModel getSiteModel() {
260 return siteModel;
261 }
262
263 /**
264 * <p>Setter for the field <code>siteModel</code>.</p>
265 *
266 * @param siteModel a {@link org.apache.maven.doxia.site.SiteModel} object.
267 */
268 public void setSiteModel(SiteModel siteModel) {
269 this.siteModel = siteModel;
270 }
271
272 /**
273 * <p>Setter for the field <code>defaultTitle</code>.</p>
274 *
275 * @param defaultTitle a {@link java.lang.String} object.
276 */
277 public void setDefaultTitle(String defaultTitle) {
278 this.defaultTitle = defaultTitle;
279 }
280
281 /**
282 * <p>Getter for the field <code>defaultTitle</code>.</p>
283 *
284 * @return a {@link java.lang.String} object.
285 */
286 public String getDefaultTitle() {
287 return defaultTitle;
288 }
289
290 /**
291 * <p>Getter for the field <code>skin</code>.</p>
292 *
293 * @return a {@link Artifact} object.
294 */
295 public Artifact getSkin() {
296 return skin;
297 }
298
299 /**
300 * <p>Setter for the field <code>skinJarFile</code>.</p>
301 *
302 * @param skin an {@link Artifact} object.
303 */
304 public void setSkin(Artifact skin) {
305 this.skin = skin;
306 }
307
308 /**
309 * <p>Getter for the field <code>skinModel</code>.</p>
310 *
311 * @return a {@link SkinModel} object.
312 */
313 public SkinModel getSkinModel() {
314 return skinModel;
315 }
316
317 /**
318 * <p>Setter for the field <code>skinModel</code>.</p>
319 *
320 * @param skinModel a {@link SkinModel} object.
321 */
322 public void setSkinModel(SkinModel skinModel) {
323 this.skinModel = skinModel;
324 }
325
326 /**
327 * <p>Setter for the field <code>templateName</code>.</p>
328 *
329 * @param templateName a {@link java.lang.String} object.
330 */
331 public void setTemplateName(String templateName) {
332 this.templateName = templateName;
333 }
334
335 /**
336 * @deprecated use {@link #addSiteDirectory(SiteDirectory)}
337 */
338 @Deprecated
339 public void addSiteDirectory(File siteDirectory) {
340 addSiteDirectory(new SiteDirectory(siteDirectory, true));
341 }
342
343 /**
344 * Add a site directory, expected to have a Doxia Site layout, ie one directory per Doxia parser module containing
345 * files with parser extension. Typical values are <code>src/site</code> or <code>target/generated-site</code>.
346 *
347 * @param siteDirectory a {@link SiteDirectory} object.
348 * @since 2.0.0
349 */
350 public void addSiteDirectory(SiteDirectory siteDirectory) {
351 this.siteDirectories.add(siteDirectory);
352 }
353
354 /**
355 * <p>Getter for the field <code>siteDirectories</code>.</p>
356 *
357 * @return List of site directories.
358 */
359 public List<SiteDirectory> getSiteDirectories() {
360 return siteDirectories;
361 }
362
363 /**
364 * <p>Getter for the field <code>moduleExcludes</code>.</p>
365 *
366 * @return a map defining exclude patterns (comma separated) by parser id.
367 */
368 public Map<String, String> getModuleExcludes() {
369 return moduleExcludes;
370 }
371
372 /**
373 * <p>Setter for the field <code>moduleExcludes</code>.</p>
374 *
375 * @param moduleExcludes a {@link java.util.Map} object.
376 */
377 public void setModuleExcludes(Map<String, String> moduleExcludes) {
378 this.moduleExcludes = moduleExcludes;
379 }
380
381 /**
382 * <p>Getter for the field <code>inputEncoding</code>.</p>
383 *
384 * @return a {@link java.lang.String} object.
385 */
386 public String getInputEncoding() {
387 return inputEncoding;
388 }
389
390 /**
391 * <p>Setter for the field <code>inputEncoding</code>.</p>
392 *
393 * @param inputEncoding a {@link java.lang.String} object.
394 */
395 public void setInputEncoding(String inputEncoding) {
396 this.inputEncoding = inputEncoding;
397 }
398
399 /**
400 * <p>Getter for the field <code>outputEncoding</code>.</p>
401 *
402 * @return a {@link java.lang.String} object.
403 */
404 public String getOutputEncoding() {
405 return outputEncoding;
406 }
407
408 /**
409 * <p>Setter for the field <code>outputEncoding</code>.</p>
410 *
411 * @param outputEncoding a {@link java.lang.String} object.
412 */
413 public void setOutputEncoding(String outputEncoding) {
414 this.outputEncoding = outputEncoding;
415 }
416
417 /**
418 * <p>If you want to specify a specific publish date instead of the current date.</p>
419 *
420 * @return the publish date, can be {@code null}
421 */
422 public Date getPublishDate() {
423 return publishDate;
424 }
425
426 /**
427 * <p>Specify a specific publish date instead of the current date.</p>
428 *
429 * @param publishDate the publish date
430 */
431 public void setPublishDate(Date publishDate) {
432 this.publishDate = publishDate;
433 }
434
435 /**
436 * Directory where to save content after Velocity processing (<code>*.vm</code>), but before parsing it with Doxia.
437 *
438 * @return not null if the documents are to be saved
439 * @since 1.7
440 */
441 public File getProcessedContentOutput() {
442 return processedContentOutput;
443 }
444
445 /**
446 * Where to (eventually) save content after Velocity processing (<code>*.vm</code>), but before parsing it with
447 * Doxia?
448 *
449 * @param processedContentOutput not null if the documents are to be saved
450 * @since 1.7
451 */
452 public void setProcessedContentOutput(File processedContentOutput) {
453 this.processedContentOutput = processedContentOutput;
454 }
455
456 /**
457 * Root directory, to calculate relative path to every site directories.
458 * Corresponds to the <code>pom.xml</code> directory for Maven build.
459 *
460 * @return the root directory
461 * @since 1.8
462 */
463 public File getRootDirectory() {
464 return rootDirectory;
465 }
466
467 /**
468 * Set the root directory.
469 *
470 * @param rootDirectory the root directory
471 * @since 1.8
472 */
473 public void setRootDirectory(File rootDirectory) {
474 this.rootDirectory = rootDirectory;
475 }
476
477 /**
478 * Return the configurator for {@link Parser parsers}.
479 * @return the parser configurator (may be {@code null} in which case the default configuration is applied)
480 * @since 2.0.0
481 */
482 public ParserConfigurator getParserConfigurator() {
483 return parserConfigurator;
484 }
485
486 /**
487 * Set the configurator to use for {@link Parser parsers}.
488 * @param parserConfigurator the configurator
489 * @since 2.0.0
490 */
491 public void setParserConfigurator(ParserConfigurator parserConfigurator) {
492 this.parserConfigurator = parserConfigurator;
493 }
494
495 /**
496 * Gets the map of attributes that can be used to cache items per site rendering context.
497 * This is a free-form map that can be used for example
498 * from the {@link ContextCustomizer} to cache items that can be reused among different documents of the same site.
499 *
500 * @return a map of attributes, the returned map is immutable.
501 * @see #putAttribute(String, Object)
502 * @see #removeAttribute(String)
503 * @since 2.1.0
504 */
505 public Map<String, Object> getAttributes() {
506 return Collections.unmodifiableMap(attributes);
507 }
508
509 /**
510 * Puts an attribute in the context attributes map, this can be used to cache items per site rendering context.
511 * It overrides any existing value for the same key and returns the previous value associated with the key, or {@code null}
512 * if there was no mapping for the key or if the map previously associated {@code null} with the key.
513 *
514 * @param key the key with which the specified value is to be associated
515 * @param value the value to be associated with the specified key
516 * @return the previous value associated with the key, or {@code null}
517 * @see #getAttributes()
518 * @see #removeAttribute(String)
519 * @since 2.1.0
520 */
521 public Object putAttribute(String key, Object value) {
522 return this.attributes.put(key, value);
523 }
524
525 /**
526 * Removes the mapping for a key from this attributes map if it is present.
527 *
528 * @param key key whose mapping is to be removed from the map
529 * @return the previous value associated with key, or {@code null} if there was no mapping for key or if the map previously associated {@code null} with the key.
530 * @see #getAttributes()
531 * @see #putAttribute(String, Object)
532 * @since 2.1.0
533 */
534 public Object removeAttribute(String key) {
535 return this.attributes.remove(key);
536 }
537 }