View Javadoc
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 }