1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.internal.template

File InternalTemplateManager.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart7.png
64% of files have more coverage

Code metrics

80
229
59
6
897
636
111
0.48
3.88
9.83
1.88

Classes

Class Line # Actions
InternalTemplateManager 100 169 0% 73 102
0.613636461.4%
InternalTemplateManager.AbtractTemplate 166 17 0% 11 8
0.7333333573.3%
InternalTemplateManager.EnvironmentTemplate 226 2 0% 2 0
1.0100%
InternalTemplateManager.DefaultTemplate 240 4 0% 3 0
1.0100%
InternalTemplateManager.DefaultTemplateContent 258 29 0% 17 19
0.604166760.4%
InternalTemplateManager.FilesystemTemplateContent 377 8 0% 5 5
0.6428571364.3%
 

Contributing tests

This file is covered by 23 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.internal.template;
21   
22    import java.io.PrintWriter;
23    import java.io.StringReader;
24    import java.io.StringWriter;
25    import java.io.Writer;
26    import java.lang.reflect.Type;
27    import java.net.URI;
28    import java.net.URL;
29    import java.nio.charset.StandardCharsets;
30    import java.util.ArrayList;
31    import java.util.Arrays;
32    import java.util.Collections;
33    import java.util.HashMap;
34    import java.util.List;
35    import java.util.Map;
36    import java.util.regex.Matcher;
37    import java.util.regex.Pattern;
38   
39    import javax.inject.Inject;
40    import javax.inject.Named;
41    import javax.inject.Provider;
42    import javax.inject.Singleton;
43   
44    import org.apache.commons.io.IOUtils;
45    import org.slf4j.Logger;
46    import org.xwiki.component.annotation.Component;
47    import org.xwiki.component.manager.ComponentLookupException;
48    import org.xwiki.component.manager.ComponentManager;
49    import org.xwiki.configuration.ConfigurationSource;
50    import org.xwiki.environment.Environment;
51    import org.xwiki.filter.input.InputSource;
52    import org.xwiki.filter.input.InputStreamInputSource;
53    import org.xwiki.filter.input.ReaderInputSource;
54    import org.xwiki.filter.input.StringInputSource;
55    import org.xwiki.job.event.status.JobProgressManager;
56    import org.xwiki.model.reference.DocumentReference;
57    import org.xwiki.model.reference.DocumentReferenceResolver;
58    import org.xwiki.properties.BeanManager;
59    import org.xwiki.properties.ConverterManager;
60    import org.xwiki.properties.PropertyException;
61    import org.xwiki.properties.RawProperties;
62    import org.xwiki.properties.annotation.PropertyId;
63    import org.xwiki.rendering.block.Block;
64    import org.xwiki.rendering.block.GroupBlock;
65    import org.xwiki.rendering.block.RawBlock;
66    import org.xwiki.rendering.block.VerbatimBlock;
67    import org.xwiki.rendering.block.WordBlock;
68    import org.xwiki.rendering.block.XDOM;
69    import org.xwiki.rendering.internal.transformation.MutableRenderingContext;
70    import org.xwiki.rendering.parser.ContentParser;
71    import org.xwiki.rendering.renderer.BlockRenderer;
72    import org.xwiki.rendering.renderer.printer.WikiPrinter;
73    import org.xwiki.rendering.renderer.printer.WriterWikiPrinter;
74    import org.xwiki.rendering.syntax.Syntax;
75    import org.xwiki.rendering.transformation.RenderingContext;
76    import org.xwiki.rendering.transformation.TransformationContext;
77    import org.xwiki.rendering.transformation.TransformationManager;
78    import org.xwiki.security.authorization.AuthorExecutor;
79    import org.xwiki.skin.Resource;
80    import org.xwiki.skin.ResourceRepository;
81    import org.xwiki.skin.Skin;
82    import org.xwiki.template.Template;
83    import org.xwiki.template.TemplateContent;
84    import org.xwiki.velocity.VelocityManager;
85   
86    import com.xpn.xwiki.XWiki;
87    import com.xpn.xwiki.internal.skin.AbstractEnvironmentResource;
88    import com.xpn.xwiki.internal.skin.InternalSkinManager;
89    import com.xpn.xwiki.internal.skin.WikiResource;
90    import com.xpn.xwiki.user.api.XWikiRightService;
91   
92    /**
93    * Internal toolkit to experiment on templates.
94    *
95    * @version $Id: f3da3fa5f9607d3128d68ae13fe09bb7ea9fecc2 $
96    * @since 7.0M1
97    */
98    @Component(roles = InternalTemplateManager.class)
99    @Singleton
 
100    public class InternalTemplateManager
101    {
102    private static final Pattern PROPERTY_LINE = Pattern.compile("^##!(.+)=(.*)$\r?\n?", Pattern.MULTILINE);
103   
104    /**
105    * The reference of the superadmin user.
106    */
107    private static final DocumentReference SUPERADMIN_REFERENCE =
108    new DocumentReference("xwiki", XWiki.SYSTEM_SPACE, XWikiRightService.SUPERADMIN_USER);
109   
110    @Inject
111    private Environment environment;
112   
113    @Inject
114    private ContentParser parser;
115   
116    @Inject
117    private VelocityManager velocityManager;
118   
119    /**
120    * Used to execute transformations.
121    */
122    @Inject
123    private TransformationManager transformationManager;
124   
125    @Inject
126    @Named("context")
127    private Provider<ComponentManager> componentManagerProvider;
128   
129    @Inject
130    private RenderingContext renderingContext;
131   
132    @Inject
133    @Named("plain/1.0")
134    private BlockRenderer plainRenderer;
135   
136    @Inject
137    @Named("xwikicfg")
138    private ConfigurationSource xwikicfg;
139   
140    @Inject
141    @Named("all")
142    private ConfigurationSource allConfiguration;
143   
144    @Inject
145    @Named("currentmixed")
146    private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver;
147   
148    @Inject
149    private BeanManager beanManager;
150   
151    @Inject
152    private ConverterManager converter;
153   
154    @Inject
155    private AuthorExecutor authorExecutor;
156   
157    @Inject
158    private InternalSkinManager skins;
159   
160    @Inject
161    private JobProgressManager progress;
162   
163    @Inject
164    private Logger logger;
165   
 
166    private static abstract class AbtractTemplate<T extends TemplateContent, R extends Resource<?>> implements Template
167    {
168    protected R resource;
169   
170    protected T content;
171   
 
172  97567 toggle public AbtractTemplate(R resource)
173    {
174  97554 this.resource = resource;
175    }
176   
 
177  176543 toggle @Override
178    public String getId()
179    {
180  176544 return this.resource.getId();
181    }
182   
 
183  0 toggle @Override
184    public String getPath()
185    {
186  0 return this.resource.getPath();
187    }
188   
 
189  86619 toggle @Override
190    public TemplateContent getContent() throws Exception
191    {
192  86628 if (this.content == null) {
193    // TODO: work with streams instead of forcing String
194  86591 String strinContent;
195   
196  86595 try (InputSource source = this.resource.getInputSource()) {
197  86598 if (source instanceof StringInputSource) {
198  2 strinContent = source.toString();
199  86590 } else if (source instanceof ReaderInputSource) {
200  0 strinContent = IOUtils.toString(((ReaderInputSource) source).getReader());
201  86595 } else if (source instanceof InputStreamInputSource) {
202    // It's impossible to know the real attachment encoding, but let's assume that they respect the
203    // standard and use UTF-8 (which is required for the files located on the filesystem)
204  86588 strinContent = IOUtils.toString(((InputStreamInputSource) source).getInputStream(),
205    StandardCharsets.UTF_8);
206    } else {
207  0 return null;
208    }
209    }
210   
211  86599 this.content = getContentInternal(strinContent);
212    }
213   
214  86615 return this.content;
215    }
216   
217    protected abstract T getContentInternal(String content) throws Exception;
218   
 
219  0 toggle @Override
220    public String toString()
221    {
222  0 return this.resource.getId();
223    }
224    }
225   
 
226    private class EnvironmentTemplate extends AbtractTemplate<FilesystemTemplateContent, AbstractEnvironmentResource>
227    {
 
228  97554 toggle EnvironmentTemplate(AbstractEnvironmentResource resource)
229    {
230  97568 super(resource);
231    }
232   
 
233  86588 toggle @Override
234    protected FilesystemTemplateContent getContentInternal(String content)
235    {
236  86591 return new FilesystemTemplateContent(content);
237    }
238    }
239   
 
240    private class DefaultTemplate extends AbtractTemplate<DefaultTemplateContent, Resource<?>>
241    {
 
242  4 toggle DefaultTemplate(Resource<?> resource)
243    {
244  4 super(resource);
245    }
246   
 
247  4 toggle @Override
248    protected DefaultTemplateContent getContentInternal(String content)
249    {
250  4 if (this.resource instanceof WikiResource) {
251  3 return new DefaultTemplateContent(content, ((WikiResource<?>) this.resource).getAuthorReference());
252    } else {
253  1 return new DefaultTemplateContent(content);
254    }
255    }
256    }
257   
 
258    private class DefaultTemplateContent implements RawProperties, TemplateContent
259    {
260    // TODO: work with streams instead
261    protected String content;
262   
263    protected boolean authorProvided;
264   
265    protected DocumentReference authorReference;
266   
267    @PropertyId("source.syntax")
268    public Syntax sourceSyntax;
269   
270    @PropertyId("raw.syntax")
271    public Syntax rawSyntax;
272   
273    protected Map<String, Object> properties = new HashMap<>();
274   
 
275  86596 toggle DefaultTemplateContent(String content)
276    {
277  86583 this.content = content;
278   
279  86587 init();
280    }
281   
 
282  3 toggle DefaultTemplateContent(String content, DocumentReference authorReference)
283    {
284  3 this(content);
285   
286  3 setAuthorReference(authorReference);
287    }
288   
 
289  0 toggle @Override
290    public Syntax getSourceSyntax()
291    {
292  0 return this.sourceSyntax;
293    }
294   
 
295  0 toggle @Override
296    public Syntax getRawSyntax()
297    {
298  0 return this.rawSyntax;
299    }
300   
 
301  0 toggle @Override
302    public <T> T getProperty(String name, T def)
303    {
304  0 if (!this.properties.containsKey(name)) {
305  0 return def;
306    }
307   
308  0 if (def != null) {
309  0 return getProperty(name, def.getClass());
310    }
311   
312  0 return (T) this.properties.get(name);
313    }
314   
 
315  0 toggle @Override
316    public <T> T getProperty(String name, Type type)
317    {
318  0 return converter.convert(type, this.properties.get(name));
319    }
320   
 
321  86586 toggle protected void init()
322    {
323  86583 Matcher matcher = PROPERTY_LINE.matcher(this.content);
324   
325  86586 Map<String, String> map = new HashMap<>();
326  86591 while (matcher.find()) {
327  1 String key = matcher.group(1);
328  1 String value = matcher.group(2);
329   
330  1 map.put(key, value);
331   
332    // Remove the line from the content
333  1 this.content = this.content.substring(matcher.end());
334    }
335   
336  86586 try {
337  86579 InternalTemplateManager.this.beanManager.populate(this, map);
338    } catch (PropertyException e) {
339    // Should never happen
340  0 InternalTemplateManager.this.logger.error("Failed to populate properties of template", e);
341    }
342   
343    // The default is xhtml to support old templates
344  86580 if (this.rawSyntax == null && this.sourceSyntax == null) {
345  86580 this.rawSyntax = Syntax.XHTML_1_0;
346    }
347    }
348   
 
349  6782 toggle @Override
350    public String getContent()
351    {
352  6782 return this.content;
353    }
354   
 
355  79682 toggle @PropertyId("author")
356    @Override
357    public DocumentReference getAuthorReference()
358    {
359  79681 return this.authorReference;
360    }
361   
 
362  86573 toggle protected void setAuthorReference(DocumentReference authorReference)
363    {
364  86577 this.authorReference = authorReference;
365  86578 this.authorProvided = true;
366    }
367   
368    // RawProperties
369   
 
370  0 toggle @Override
371    public void set(String propertyName, Object value)
372    {
373  0 this.properties.put(propertyName, value);
374    }
375    }
376   
 
377    private class FilesystemTemplateContent extends DefaultTemplateContent
378    {
 
379  86584 toggle public FilesystemTemplateContent(String content)
380    {
381  86581 super(content);
382   
383    // Give programming right to filesystem templates by default
384  86576 setPrivileged(true);
385    }
386   
387    /**
388    * {@inheritDoc}
389    * <p>
390    * Allow filesystem template to indicate the user to executed them with.
391    * </p>
392    *
393    * @see #setAuthorReference(DocumentReference)
394    */
 
395  86572 toggle @Override
396    public void setAuthorReference(DocumentReference authorReference)
397    {
398  86579 super.setAuthorReference(authorReference);
399    }
400   
401    /**
402    * Made public to be seen as bean property.
403    *
404    * @since 6.3.1
405    * @since 6.4M1
406    */
 
407  0 toggle @SuppressWarnings("unused")
408    public boolean isPrivileged()
409    {
410  0 return SUPERADMIN_REFERENCE.equals(getAuthorReference());
411    }
412   
413    /**
414    * Made public to be seen as bean property.
415    *
416    * @since 6.3.1
417    * @since 6.4M1
418    */
 
419  86571 toggle public void setPrivileged(boolean privileged)
420    {
421  86575 if (privileged) {
422  86576 setAuthorReference(SUPERADMIN_REFERENCE);
423    } else {
424    // Reset author
425  0 this.authorReference = null;
426  0 this.authorProvided = false;
427    }
428    }
429    }
430   
 
431  59980 toggle private String getResourcePath(String suffixPath, String templateName, boolean testExist)
432    {
433  59979 String templatePath = suffixPath + templateName;
434   
435    // Prevent inclusion of templates from other directories
436  59974 String normalizedTemplate = URI.create(templatePath).normalize().toString();
437  59975 if (!normalizedTemplate.startsWith(suffixPath)) {
438  0 this.logger.warn("Direct access to template file [{}] refused. Possible break-in attempt!",
439    normalizedTemplate);
440   
441  0 return null;
442    }
443   
444  59972 if (testExist) {
445    // Check if the resource exist
446  59984 if (this.environment.getResource(templatePath) == null) {
447  1791 return null;
448    }
449    }
450   
451  58193 return templatePath;
452    }
453   
 
454  0 toggle private void renderError(Throwable throwable, Writer writer)
455    {
456  0 XDOM xdom = generateError(throwable);
457   
458  0 render(xdom, writer);
459    }
460   
 
461  0 toggle private XDOM generateError(Throwable throwable)
462    {
463  0 List<Block> errorBlocks = new ArrayList<Block>();
464   
465    // Add short message
466  0 Map<String, String> errorBlockParams = Collections.singletonMap("class", "xwikirenderingerror");
467  0 errorBlocks.add(
468    new GroupBlock(Arrays.<Block>asList(new WordBlock("Failed to render step content")), errorBlockParams));
469   
470    // Add complete error
471  0 StringWriter writer = new StringWriter();
472  0 throwable.printStackTrace(new PrintWriter(writer));
473  0 Block descriptionBlock = new VerbatimBlock(writer.toString(), false);
474  0 Map<String, String> errorDescriptionBlockParams =
475    Collections.singletonMap("class", "xwikirenderingerrordescription hidden");
476  0 errorBlocks.add(new GroupBlock(Arrays.asList(descriptionBlock), errorDescriptionBlockParams));
477   
478  0 return new XDOM(errorBlocks);
479    }
480   
 
481  842 toggle private void transform(Block block)
482    {
483  842 TransformationContext txContext =
484  842 new TransformationContext(block instanceof XDOM ? (XDOM) block : new XDOM(Arrays.asList(block)),
485    this.renderingContext.getDefaultSyntax(), this.renderingContext.isRestricted());
486   
487  842 txContext.setId(this.renderingContext.getTransformationId());
488  842 txContext.setTargetSyntax(getTargetSyntax());
489   
490  842 try {
491  842 this.transformationManager.performTransformations(block, txContext);
492    } catch (Exception e) {
493  0 throw new RuntimeException(e);
494    }
495    }
496   
497    /**
498    * @param templateName the template to parse
499    * @return the result of the template parsing
500    */
 
501  149 toggle public XDOM getXDOMNoException(String templateName)
502    {
503  149 XDOM xdom;
504   
505  149 try {
506  149 xdom = getXDOM(templateName);
507    } catch (Throwable e) {
508  0 this.logger.error("Error while getting template [{}] XDOM", templateName, e);
509   
510  0 xdom = generateError(e);
511    }
512   
513  149 return xdom;
514    }
515   
516    /**
517    * @param template the template to parse
518    * @return the result of the template parsing
519    * @since 8.3RC1
520    */
 
521  0 toggle public XDOM getXDOMNoException(Template template)
522    {
523  0 XDOM xdom;
524   
525  0 try {
526  0 xdom = getXDOM(template);
527    } catch (Throwable e) {
528  0 this.logger.error("Error while getting template [{}] XDOM", template.getId(), e);
529   
530  0 xdom = generateError(e);
531    }
532   
533  0 return xdom;
534    }
535   
 
536  149 toggle public XDOM getXDOM(Template template) throws Exception
537    {
538  149 XDOM xdom;
539   
540  149 if (template != null) {
541  149 DefaultTemplateContent content = (DefaultTemplateContent) template.getContent();
542   
543  149 xdom = getXDOM(template, content);
544    } else {
545  0 xdom = new XDOM(Collections.<Block>emptyList());
546    }
547   
548  149 return xdom;
549    }
550   
 
551  991 toggle private XDOM getXDOM(Template template, DefaultTemplateContent content) throws Exception
552    {
553  991 XDOM xdom;
554   
555  991 if (content.sourceSyntax != null) {
556  1 xdom = this.parser.parse(content.content, content.sourceSyntax);
557    } else {
558  990 String result = evaluateContent(template, content);
559  990 xdom = new XDOM(Arrays.asList(new RawBlock(result, content.rawSyntax)));
560    }
561   
562  991 return xdom;
563    }
564   
 
565  149 toggle public XDOM getXDOM(String templateName) throws Exception
566    {
567  149 Template template = getTemplate(templateName);
568   
569  149 return getXDOM(template);
570    }
571   
 
572  0 toggle public String renderNoException(String template)
573    {
574  0 Writer writer = new StringWriter();
575   
576  0 renderNoException(template, writer);
577   
578  0 return writer.toString();
579    }
580   
 
581  0 toggle public void renderNoException(String templateName, Writer writer)
582    {
583  0 try {
584  0 render(templateName, writer);
585    } catch (Exception e) {
586  0 this.logger.error("Error while rendering template [{}]", templateName, e);
587   
588  0 renderError(e, writer);
589    }
590    }
591   
592    /**
593    * @since 8.3RC1
594    */
 
595  0 toggle public void renderNoException(Template template, Writer writer)
596    {
597  0 try {
598  0 render(template, writer);
599    } catch (Exception e) {
600  0 this.logger.error("Error while rendering template [{}]", template, e);
601   
602  0 renderError(e, writer);
603    }
604    }
605   
 
606  78826 toggle public String render(String templateName) throws Exception
607    {
608  78823 return renderFromSkin(templateName, (Skin) null);
609    }
610   
 
611  0 toggle public String renderFromSkin(String templateName, String skinId) throws Exception
612    {
613  0 Skin skin = this.skins.getSkin(skinId);
614   
615  0 return skin != null ? renderFromSkin(templateName, skin) : null;
616    }
617   
 
618  78817 toggle public String renderFromSkin(String templateName, Skin skin) throws Exception
619    {
620  78817 Writer writer = new StringWriter();
621   
622  78820 renderFromSkin(templateName, skin, writer);
623   
624  78828 return writer.toString();
625    }
626   
 
627  0 toggle public void render(String templateName, Writer writer) throws Exception
628    {
629  0 renderFromSkin(templateName, null, writer);
630    }
631   
 
632  78813 toggle public void renderFromSkin(final String templateName, ResourceRepository reposirory, final Writer writer)
633    throws Exception
634    {
635  78813 this.progress.startStep(templateName, "template.render.message", "Render template [{}]", templateName);
636   
637  78825 try {
638  78826 final Template template =
639  78825 reposirory != null ? getTemplate(templateName, reposirory) : getTemplate(templateName);
640   
641  78823 if (template != null) {
642  78822 final DefaultTemplateContent content = (DefaultTemplateContent) template.getContent();
643   
644  78810 if (content.authorProvided) {
645  78804 this.authorExecutor.call(() -> {
646  78807 render(template, content, writer);
647   
648  78822 return null;
649    }, content.getAuthorReference());
650    } else {
651  1 render(template, content, writer);
652    }
653    }
654    } finally {
655  78821 this.progress.endStep(templateName);
656    }
657    }
658   
 
659  0 toggle public void render(Template template, Writer writer) throws Exception
660    {
661  0 DefaultTemplateContent content = (DefaultTemplateContent) template.getContent();
662   
663  0 render(template, content, writer);
664    }
665   
 
666  78806 toggle private void render(Template template, DefaultTemplateContent content, Writer writer) throws Exception
667    {
668  78802 if (content.sourceSyntax != null) {
669  1 XDOM xdom = execute(template, content);
670   
671  1 render(xdom, writer);
672    } else {
673  78813 evaluateContent(template, content, writer);
674    }
675    }
676   
 
677  1 toggle private void render(XDOM xdom, Writer writer)
678    {
679  1 WikiPrinter printer = new WriterWikiPrinter(writer);
680   
681  1 BlockRenderer blockRenderer;
682  1 try {
683  1 blockRenderer =
684    this.componentManagerProvider.get().getInstance(BlockRenderer.class, getTargetSyntax().toIdString());
685    } catch (ComponentLookupException e) {
686  0 blockRenderer = this.plainRenderer;
687    }
688   
689  1 blockRenderer.render(xdom, printer);
690    }
691   
 
692  0 toggle public XDOM executeNoException(String templateName)
693    {
694  0 XDOM xdom;
695   
696  0 try {
697  0 xdom = execute(templateName);
698    } catch (Throwable e) {
699  0 this.logger.error("Error while executing template [{}]", templateName, e);
700   
701  0 xdom = generateError(e);
702    }
703   
704  0 return xdom;
705    }
706   
707    /**
708    * @since 8.3RC1
709    */
 
710  0 toggle public XDOM executeNoException(Template template)
711    {
712  0 XDOM xdom;
713   
714  0 try {
715  0 xdom = execute(template);
716    } catch (Throwable e) {
717  0 this.logger.error("Error while executing template [{}]", template.getId(), e);
718   
719  0 xdom = generateError(e);
720    }
721   
722  0 return xdom;
723    }
724   
 
725  842 toggle private XDOM execute(Template template, DefaultTemplateContent content) throws Exception
726    {
727  842 XDOM xdom = getXDOM(template, content);
728   
729  842 transform(xdom);
730   
731  842 return xdom;
732    }
733   
 
734  841 toggle public XDOM execute(String templateName) throws Exception
735    {
736  841 final Template template = getTemplate(templateName);
737   
738  841 if (template != null) {
739  841 final DefaultTemplateContent content = (DefaultTemplateContent) template.getContent();
740   
741  841 if (content.authorProvided) {
742  841 return this.authorExecutor.call(() -> execute(template, content), content.getAuthorReference());
743    } else {
744  0 return execute(template, content);
745    }
746    }
747   
748  0 return null;
749    }
750   
 
751  0 toggle public XDOM execute(Template template) throws Exception
752    {
753  0 if (template != null) {
754  0 final DefaultTemplateContent content = (DefaultTemplateContent) template.getContent();
755   
756  0 if (content.authorProvided) {
757  0 return this.authorExecutor.call(() -> execute(template, content), content.getAuthorReference());
758    } else {
759  0 return execute(template, content);
760    }
761    }
762   
763  0 return null;
764    }
765   
 
766  990 toggle private String evaluateContent(Template template, DefaultTemplateContent content) throws Exception
767    {
768  990 Writer writer = new StringWriter();
769   
770  990 evaluateContent(template, content, writer);
771   
772  990 return writer.toString();
773    }
774   
 
775  79802 toggle private void evaluateContent(Template template, DefaultTemplateContent content, Writer writer) throws Exception
776    {
777    // Use the Transformation id as the name passed to the Velocity Engine. This name is used internally
778    // by Velocity as a cache index key for caching macros.
779  79801 String namespace = this.renderingContext.getTransformationId();
780   
781  79806 boolean renderingContextPushed = false;
782  79806 if (namespace == null) {
783  7690 namespace = template.getId() != null ? template.getId() : "unknown namespace";
784   
785  7691 if (this.renderingContext instanceof MutableRenderingContext) {
786    // Make the current velocity template id available
787  7691 ((MutableRenderingContext) this.renderingContext).push(this.renderingContext.getTransformation(),
788    this.renderingContext.getXDOM(), this.renderingContext.getDefaultSyntax(), namespace,
789    this.renderingContext.isRestricted(), this.renderingContext.getTargetSyntax());
790   
791  7691 renderingContextPushed = true;
792    }
793    }
794   
795  79800 try {
796  79803 this.velocityManager.evaluate(writer, namespace, new StringReader(content.content));
797    } finally {
798    // Get rid of temporary rendering context
799  79813 if (renderingContextPushed) {
800  7688 ((MutableRenderingContext) this.renderingContext).pop();
801    }
802    }
803    }
804   
 
805  843 toggle private Syntax getTargetSyntax()
806    {
807  843 Syntax targetSyntax = this.renderingContext.getTargetSyntax();
808   
809  843 return targetSyntax != null ? targetSyntax : Syntax.PLAIN_1_0;
810    }
811   
 
812  59981 toggle private EnvironmentTemplate getFileSystemTemplate(String suffixPath, String templateName)
813    {
814  59975 String path = getResourcePath(suffixPath, templateName, true);
815   
816  59984 return path != null
817    ? new EnvironmentTemplate(new TemplateEnvironmentResource(path, templateName, this.environment)) : null;
818    }
819   
 
820  1791 toggle private Template getClassloaderTemplate(String suffixPath, String templateName)
821    {
822  1791 return getClassloaderTemplate(Thread.currentThread().getContextClassLoader(), suffixPath, templateName);
823    }
824   
 
825  1791 toggle private Template getClassloaderTemplate(ClassLoader classloader, String suffixPath, String templateName)
826    {
827  1791 String templatePath = suffixPath + templateName;
828   
829  1791 URL url = classloader.getResource(templatePath);
830   
831  1791 return url != null ? new DefaultTemplate(new ClassloaderResource(url, templateName)) : null;
832    }
833   
 
834  39379 toggle private Template createTemplate(Resource<?> resource)
835    {
836  39370 Template template;
837   
838  39370 if (resource instanceof AbstractEnvironmentResource) {
839  39363 template = new EnvironmentTemplate((AbstractEnvironmentResource) resource);
840    } else {
841  3 template = new DefaultTemplate(resource);
842    }
843   
844  39366 return template;
845    }
846   
 
847  0 toggle public Template getResourceTemplate(String templateName, ResourceRepository repository)
848    {
849  0 Resource<?> resource = repository.getLocalResource(templateName);
850  0 if (resource != null) {
851  0 return createTemplate(resource);
852    }
853   
854  0 return null;
855    }
856   
 
857  99362 toggle public Template getTemplate(String templateName, ResourceRepository repository)
858    {
859  99355 Resource<?> resource = repository.getResource(templateName);
860  99349 if (resource != null) {
861  39369 return createTemplate(resource);
862    }
863   
864  59971 return null;
865    }
866   
 
867  92606 toggle public Template getTemplate(String templateName)
868    {
869  92599 Template template = null;
870   
871    // Try from skin
872  92584 Skin skin = this.skins.getCurrentSkin(false);
873  92612 if (skin != null) {
874  92611 template = getTemplate(templateName, skin);
875    }
876   
877    // Try from base skin if no skin is set
878  92594 if (skin == null) {
879  0 Skin baseSkin = this.skins.getCurrentParentSkin(false);
880  0 if (baseSkin != null) {
881  0 template = getTemplate(templateName, baseSkin);
882    }
883    }
884   
885    // Try from /templates/ environment resources
886  92582 if (template == null) {
887  59970 template = getFileSystemTemplate("/templates/", templateName);
888    }
889   
890    // Try from current Thread classloader
891  92593 if (template == null) {
892  1791 template = getClassloaderTemplate("templates/", templateName);
893    }
894   
895  92580 return template;
896    }
897    }