1 /*
2 * Copyright (c) 2012-2023, jcabi.com
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met: 1) Redistributions of source code must retain the above
8 * copyright notice, this list of conditions and the following
9 * disclaimer. 2) Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution. 3) Neither the name of the jcabi.com nor
13 * the names of its contributors may be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package com.jcabi.velocity;
31
32 import java.io.PrintWriter;
33 import java.io.StringWriter;
34 import java.util.Map;
35 import org.apache.velocity.Template;
36 import org.apache.velocity.VelocityContext;
37 import org.apache.velocity.app.VelocityEngine;
38 import org.apache.velocity.runtime.RuntimeConstants;
39 import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
40
41 /**
42 * Velocity page, builder/wrapper around Apache Velocity template.
43 *
44 * <p>The template should be in classpath:
45 *
46 * <pre> String text = new VelocityPage("com/foo/my-template.vm")
47 * .set("name", "John Doe")
48 * .toString();</pre>
49 *
50 * <p>At the moment all logging is forwarded to LOG4J. In Velocity 2.0 there
51 * will be an adapter for SLF4J and we'll use it: {@code Slf4jLogChute}.
52 *
53 * <p>The class is mutable and thread-safe.
54 *
55 * @see <a href="http://velocity.apache.org/engine/releases/velocity-1.7/user-guide.html">Velocity User Guide</a>
56 * @see <a href="http://velocity.apache.org/engine/releases/velocity-1.7/developer-guide.html">Velocity Developer Guide</a>
57 * @see <a href="http://velocity.apache.org/engine/devel/apidocs/org/apache/velocity/slf4j/Slf4jLogChute.html">Slf4jLogChute</a>
58 * @since 0.1.6
59 */
60 public final class VelocityPage {
61
62 /**
63 * The engine to use.
64 */
65 private static final VelocityEngine ENGINE = VelocityPage.init();
66
67 /**
68 * Name of resource.
69 */
70 private final transient String name;
71
72 /**
73 * The context.
74 */
75 private final transient VelocityContext context;
76
77 /**
78 * Public ctor, with absolute resource name in classpath.
79 * @param res Name of resource with template (absolute resource name in
80 * classpath)
81 */
82 public VelocityPage(final String res) {
83 this.name = res;
84 this.context = new VelocityContext();
85 }
86
87 /**
88 * Set the name to the value specified.
89 * @param prop Name of the property to set
90 * @param value The value to use
91 * @return This object
92 */
93 public VelocityPage set(final String prop, final Object value) {
94 synchronized (this.context) {
95 this.context.put(prop, value);
96 }
97 return this;
98 }
99
100 /**
101 * Set all names in one go.
102 * @param args Map of arguments
103 * @return This object
104 * @since 0.8
105 */
106 public VelocityPage set(final Map<String, Object> args) {
107 synchronized (this.context) {
108 for (final Map.Entry<String, Object> entry : args.entrySet()) {
109 this.context.put(entry.getKey(), entry.getValue());
110 }
111 }
112 return this;
113 }
114
115 @Override
116 public String toString() {
117 final Template template =
118 VelocityPage.ENGINE.getTemplate(this.name, "UTF-8");
119 final StringWriter writer = new StringWriter();
120 template.merge(this.context, new PrintWriter(writer));
121 return writer.toString();
122 }
123
124 /**
125 * Create and initialize Velocity engine.
126 * @return The engine to use
127 */
128 private static VelocityEngine init() {
129 final VelocityEngine engine = new VelocityEngine();
130 engine.setProperty("resource.loader", "cp");
131 engine.setProperty(
132 "cp.resource.loader.class",
133 ClasspathResourceLoader.class.getName()
134 );
135 engine.setProperty(
136 RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
137 "org.apache.velocity.runtime.log.Log4JLogChute"
138 );
139 engine.setProperty(
140 "runtime.log.logsystem.log4j.logger",
141 "org.apache.velocity"
142 );
143 engine.init();
144 return engine;
145 }
146
147 }