1. Project Clover database mar. avr. 16 2024 08:19:06 CEST
  2. Package org.devacfr.maven.skins.reflow.snippet

File SnippetContext.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart9.png
10% of files have more coverage

Code metrics

20
84
24
1
301
221
35
0,42
3,5
24
1,46

Classes

Class Line # Actions
SnippetContext 70 84 0% 35 16
0.87587,5%
 

Contributing tests

This file is covered by 6 tests. .

Source view

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.devacfr.maven.skins.reflow.snippet;
20   
21    import javax.annotation.Nonnull;
22    import javax.annotation.Nullable;
23   
24    import java.io.StringWriter;
25    import java.io.Writer;
26    import java.lang.ref.WeakReference;
27    import java.util.List;
28    import java.util.UUID;
29    import java.util.function.Consumer;
30   
31    import com.google.common.collect.Lists;
32    import org.apache.velocity.app.Velocity;
33    import org.apache.velocity.context.Context;
34    import org.apache.velocity.runtime.RuntimeConstants;
35    import org.apache.velocity.runtime.RuntimeSingleton;
36    import org.apache.velocity.tools.Scope;
37    import org.apache.velocity.tools.ToolManager;
38    import org.apache.velocity.tools.config.EasyFactoryConfiguration;
39    import org.apache.velocity.tools.generic.ClassTool;
40    import org.apache.velocity.tools.generic.ComparisonDateTool;
41    import org.apache.velocity.tools.generic.ContextTool;
42    import org.apache.velocity.tools.generic.DisplayTool;
43    import org.apache.velocity.tools.generic.EscapeTool;
44    import org.apache.velocity.tools.generic.FieldTool;
45    import org.apache.velocity.tools.generic.LinkTool;
46    import org.apache.velocity.tools.generic.LoopTool;
47    import org.apache.velocity.tools.generic.MathTool;
48    import org.apache.velocity.tools.generic.NumberTool;
49    import org.apache.velocity.tools.generic.RenderTool;
50    import org.apache.velocity.tools.generic.ResourceTool;
51    import org.apache.velocity.tools.generic.XmlTool;
52    import org.devacfr.maven.skins.reflow.HtmlTool;
53    import org.devacfr.maven.skins.reflow.ISkinConfig;
54    import org.devacfr.maven.skins.reflow.URITool;
55    import org.devacfr.maven.skins.reflow.snippet.ComponentToken.Type;
56    import org.jsoup.Jsoup;
57    import org.jsoup.nodes.Document;
58    import org.jsoup.nodes.Element;
59    import org.jsoup.nodes.Node;
60    import org.jsoup.nodes.TextNode;
61    import org.slf4j.Logger;
62    import org.slf4j.LoggerFactory;
63   
64    import static java.util.Objects.requireNonNull;
65   
66    /**
67    * @author Christophe Friederich
68    * @version 2.4
69    */
 
70    public class SnippetContext {
71   
72    /** */
73    private static final Logger LOGGER = LoggerFactory.getLogger(SnippetContext.class);
74   
75    /** */
76    private static final List<String> DEFAULT_PATHS = Lists.newArrayList("src/site/layouts/snippets",
77    "META-INF/skin/snippets");
78   
79    /** */
80    private final List<SnippetComponent<?>> components = Lists.newArrayList();
81   
82    /** **/
83    private String htmlSource;
84   
85    /** */
86    private final List<String> snippetPaths = Lists.newArrayList(DEFAULT_PATHS);
87   
88    /** */
89    private ISkinConfig config;
90   
91    /** */
92    private final ToolManager toolManager;
93   
94    /** */
95    private final WeakReference<SnippetParser> parser;
96   
 
97  7 toggle public SnippetContext(final SnippetParser parser) {
98  7 this.toolManager = createToolManaged();
99  7 this.parser = new WeakReference<>(parser);
100    }
101   
 
102  7 toggle public void reset() {
103  7 this.htmlSource = null;
104  7 this.components.clear();
105  7 this.config = null;
106    }
107   
 
108  0 toggle public String generateSnippetIdentifier() {
109  0 return "snippet-placement-" + UUID.randomUUID().toString();
110    }
111   
 
112  0 toggle public List<SnippetComponent<?>> getComponents() {
113  0 return components;
114    }
115   
 
116  0 toggle public SnippetParser getParser() {
117  0 return this.parser.get();
118    }
119   
 
120  1 toggle public ISkinConfig getConfig() {
121  1 return config;
122    }
123   
 
124  1 toggle public SnippetParser createChildParser() {
125  1 final SnippetParser parser = new SnippetParser();
126  1 getSnippetPaths().forEach(path -> parser.addResourcePath(path));
127  1 return parser;
128    }
129   
 
130  7 toggle void setConfig(final ISkinConfig config) {
131  7 this.config = config;
132    }
133   
 
134  1 toggle public List<String> getSnippetPaths() {
135  1 return snippetPaths;
136    }
137   
 
138  31 toggle void addComponent(final SnippetComponent<?> component) {
139  31 this.components.add(component);
140    }
141   
 
142  6 toggle void insertResourcePath(final String path, final int index) {
143  6 this.snippetPaths.add(index, path);
144    }
145   
 
146  3 toggle void addResourcePath(final String path) {
147  3 this.snippetPaths.add(path);
148    }
149   
 
150  7 toggle void setHtmlSource(final String htmlSource) {
151  7 this.htmlSource = htmlSource;
152    }
153   
 
154  7 toggle public String html() {
155  7 return htmlSource;
156    }
157   
 
158  1 toggle public Document document() {
159  1 return Jsoup.parse(html());
160    }
161   
 
162  29 toggle @Nonnull
163    SnippetComponent<?> create(@Nonnull final Element element,
164    @Nonnull final ComponentToken startToken,
165    @Nullable final ComponentToken endToken) {
166  29 requireNonNull(element);
167  29 requireNonNull(startToken);
168  29 final SnippetComponent<?> component = SnippetComponent.createSnippet(element, null, startToken.type());
169  29 addComponent(component);
170  29 recurciveCreateComponent(element, component);
171  29 return component;
172    }
173   
 
174  2 toggle @Nonnull
175    private SnippetComponent<?> create(@Nonnull final Element element, final Component<?> commponent) {
176  2 requireNonNull(element);
177  2 Type type = null;
178  2 if (element.hasAttr("shortcode")) {
179  2 type = Type.shortcode;
180  0 } else if (element.hasAttr("webcomponent")) {
181  0 type = Type.webComponent;
182    } else {
183  0 throw new SnippetParseException("Unknown snippet element");
184    }
185  2 final SnippetComponent<?> component = SnippetComponent.createSnippet(element, commponent, type);
186  2 addComponent(component);
187  2 recurciveCreateComponent(element, component);
188  2 return component;
189    }
190   
 
191  193 toggle private void recurciveCreateComponent(@Nonnull final Node element, final Component<?> parent) {
192  193 element.childNodes().forEach(child -> {
193  442 Component<?> component = null;
194    // accept textnode not empty as component.
195  442 if (child instanceof TextNode && ((TextNode) child).text().length() > 1) {
196  90 component = Component.createComponent(child, parent);
197  352 } else if (child instanceof Element) {
198  164 final Element el = (Element) child;
199  164 if (ComponentResolver.isSnippet(el)) {
200  2 component = create(el, parent);
201    } else {
202  162 component = Component.createComponent(el, parent);
203  162 recurciveCreateComponent(el, component);
204    }
205    }
206  442 if (component != null) {
207  254 parent.addChild(component);
208    }
209    });
210    }
211   
 
212  29 toggle protected void render(final SnippetComponent<?> component) {
213  29 traverseTee(component, c -> {
214  254 if (c instanceof SnippetComponent) {
215  2 ((SnippetComponent<?>) c).render(this);
216    }
217    });
218  29 component.render(this);
219    }
220   
 
221  283 toggle private void traverseTee(final Component<?> component, final Consumer<Component<?>> consumer) {
222  283 final Consumer<Component<?>> traverse = c -> traverseTee(c, consumer);
223  283 component.getChildren().forEach(consumer.andThen(traverse));
224    }
225   
 
226  31 toggle protected String renderComponent(final SnippetComponent<?> component) {
227  31 final StringWriter writer = new StringWriter();
228  31 mergeTemplate(component, writer);
229  31 return writer.toString();
230    }
231   
 
232  31 toggle protected void mergeTemplate(final SnippetComponent<?> component, final Writer writer) {
233  31 boolean found = false;
234  31 for (final String path : this.snippetPaths) {
235  83 final String filePath = path + '/' + component.getName() + ".vm";
236  83 if (Velocity.resourceExists(filePath)) {
237  31 found = true;
238  31 final Context context = createVelocityContext();
239  31 context.put("snippet", component);
240  31 context.put("snippetPath", filePath);
241  31 context.put("config", this.config);
242  31 context.put("velocity", Velocity.class);
243  31 context.put("site", this.config.getSiteModel());
244    // Use config option <absoluteResourceURL>http://mysite.com/</absoluteResourceURL>
245  31 context.put("resourcePath", this.config.getResourcePath());
246   
247  31 Velocity.mergeTemplate("META-INF/skin/snippets/_snippet.vm",
248    RuntimeSingleton.getString(RuntimeConstants.INPUT_ENCODING, RuntimeConstants.ENCODING_DEFAULT),
249    context,
250    writer);
251  31 break;
252    } else {
253  52 if (LOGGER.isDebugEnabled()) {
254  0 LOGGER.debug("Template for component '{}' not found in path:{} ", component, filePath);
255    }
256    }
257    }
258  31 if (!found) {
259  0 LOGGER.warn("The snippet '{}' template doesn't exist", component.getName());
260    }
261    }
262   
263    /**
264    * Creates a Velocity Context with all generic tools configured wit the site rendering context.
265    *
266    * @return a Velocity tools managed context
267    */
 
268  31 toggle protected Context createVelocityContext() {
269  31 return toolManager.createContext();
270    }
271   
272    /**
273    * @return
274    */
 
275  7 toggle protected ToolManager createToolManaged() {
276   
277  7 final EasyFactoryConfiguration config = new EasyFactoryConfiguration(false);
278  7 config.property("safeMode", Boolean.FALSE);
279  7 config.toolbox(Scope.REQUEST)
280    .tool(ContextTool.class)
281    .tool(LinkTool.class)
282    .tool(LoopTool.class)
283    .tool(RenderTool.class);
284  7 config.toolbox(Scope.APPLICATION)
285    .tool(ClassTool.class)
286    .tool(ComparisonDateTool.class)
287    .tool(DisplayTool.class)
288    .tool(EscapeTool.class)
289    .tool(FieldTool.class)
290    .tool(MathTool.class)
291    .tool(NumberTool.class)
292    .tool(ResourceTool.class)
293    .tool(XmlTool.class)
294    .tool(URITool.class)
295    .tool(HtmlTool.class);
296   
297  7 final ToolManager manager = new ToolManager(false, false);
298  7 manager.configure(config);
299  7 return manager;
300    }
301    }