1 package org.apache.velocity.site.doxia.runner;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.Reader;
25 import java.io.StringWriter;
26 import java.util.Iterator;
27
28 import org.apache.commons.collections.ExtendedProperties;
29 import org.apache.commons.collections.iterators.ArrayIterator;
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.velocity.Template;
32 import org.apache.velocity.VelocityContext;
33 import org.apache.velocity.app.VelocityEngine;
34 import org.apache.velocity.runtime.RuntimeConstants;
35 import org.apache.velocity.site.doxia.util.VelocityDoxiaRendererException;
36 import org.apache.velocity.site.doxia.velocity.DoxiaLibraryLoader;
37 import org.apache.velocity.site.doxia.velocity.DoxiaResourceLoader;
38 import org.apache.velocity.site.doxia.velocity.DoxiaVelocityContextFactory;
39 import org.apache.velocity.site.doxia.velocity.PlexusLogger;
40 import org.codehaus.plexus.logging.LogEnabled;
41 import org.codehaus.plexus.logging.Logger;
42
43 /**
44 * @plexus.component role="org.apache.velocity.site.doxia.runner.VelocityRunner"
45 *
46 * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a>
47 * @version $Revision: 526751 $
48 */
49 public final class DefaultVelocityRunner implements VelocityRunner, LogEnabled
50 {
51
52 /** Plexus Logger object */
53 private Logger logger = null;
54
55 /**
56 * Velocity Engine instance. Now you could argue that Plexus offers a
57 * Velocity component that could be used. However what this component not
58 * offers is an actual Engine instance but a configured singleton. This
59 * parser lives from the fact that we can customize its configuration, its
60 * loaders and macro libraries. Nothing of this is offered by the Plexus
61 * Velocity component so it is not usable here.
62 */
63 private final VelocityEngine engine;
64
65 /**
66 * The Velocity Context Factory. This gets managed by Plexus as a singleton.
67 * However as we are not inside the Mojo API here, we must use the Plexus
68 * requirement annotation, not the Mojo component annotation. Yes, this is
69 * important (and confusing, too).
70 *
71 * @plexus.requirement role="org.apache.velocity.site.doxia.velocity.DoxiaVelocityContextFactory"
72 */
73 private DoxiaVelocityContextFactory doxiaVelocityContextFactory;
74
75 /**
76 * The Velocity Library Loader. This gets managed by Plexus as a singleton.
77 * However as we are not inside the Mojo API here, we must use the Plexus
78 * requirement annotation, not the Mojo component annotation. Yes, this is
79 * important (and confusing, too).
80 *
81 * @plexus.requirement role="org.apache.velocity.site.doxia.velocity.DoxiaLibraryLoader"
82 */
83 private DoxiaLibraryLoader doxiaLibraryLoader;
84
85 /**
86 * Logger for Velocity.
87 *
88 * @plexus.requirement role="org.apache.velocity.site.doxia.velocity.PlexusLogger"
89 */
90 private PlexusLogger plexusLogger;
91
92 /**
93 * The Velocity Resource Loader.
94 *
95 * @plexus.requirement role="org.apache.velocity.site.doxia.velocity.DoxiaResourceLoader"
96 */
97 private DoxiaResourceLoader doxiaResourceLoader;
98
99 public DefaultVelocityRunner()
100 {
101 this.engine = new VelocityEngine();
102 }
103
104 /**
105 * @see LogEnabled#enableLogging(Logger)
106 */
107 public void enableLogging(final Logger logger)
108 {
109 this.logger = logger;
110 }
111
112 public void initVelocity() throws VelocityDoxiaRendererException
113 {
114
115 InputStream inputStream = null;
116 ExtendedProperties properties = new ExtendedProperties();
117
118 // We load a default properties file from the classpath. This file in in
119 // the src/main/resources directory
120 // It is intentionally *NOT* named velocity.properties!
121 try
122 {
123 inputStream = getClass().getResourceAsStream("doxia-velocity-renderer.properties");
124 properties.load(inputStream);
125 }
126 catch (IOException ioe)
127 {
128 logger.error("Could not load Default properties: ", ioe);
129 }
130 finally
131 {
132 if (inputStream != null)
133 {
134 try
135 {
136 inputStream.close();
137 }
138 catch (IOException ioe2)
139 {
140 logger.error("While closing Stream: ", ioe2);
141 }
142 }
143 }
144
145 engine.setExtendedProperties(properties);
146
147 // We have a custom Plexus Logger for Velocity messages.
148 engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, plexusLogger);
149
150 // Add the Resource Loader instance to the Velocity configuration.
151 engine.setProperty("doxia-loader." + RuntimeConstants.RESOURCE_LOADER + ".instance", doxiaResourceLoader);
152
153 engine.setProperty("doxia-library-loader." + RuntimeConstants.RESOURCE_LOADER + ".instance", doxiaLibraryLoader);
154
155 // Add all configured Velocity Macro libraries to the configuration, so
156 // they are loaded immediately at init time.
157 String[] knownLibraries = doxiaLibraryLoader.getKnownLibraries();
158
159 if (knownLibraries != null)
160 {
161 for (Iterator it = new ArrayIterator(knownLibraries); it.hasNext();)
162 {
163 String library = (String) it.next();
164
165 if (StringUtils.isNotEmpty(library))
166 {
167 engine.addProperty(RuntimeConstants.VM_LIBRARY, library);
168 }
169 }
170 }
171
172 try
173 {
174 engine.init();
175 }
176 catch (RuntimeException re)
177 {
178 throw re;
179 }
180 catch (Exception e)
181 {
182 throw new VelocityDoxiaRendererException("Velocity Init:", e);
183 }
184 }
185
186 /**
187 * This is the actual parsing stage. We pull the template from the Reader
188 * using the {@link DoxiaResourceLoader}, render the Template into a String
189 * and then pass the actual rendering to the injected Renderer (Xdoc or
190 * Apt).
191 *
192 * @param reader
193 * The reader which returns the actual template data.
194 * @param sink
195 * The Doxia Sink to send our information to.
196 *
197 * @throws parseException
198 * When Velocity can not load or process the template.
199 */
200 public final synchronized String parseVelocity(final Reader reader) throws Exception
201 {
202 // Set the Reader in the Resource loader.
203 doxiaResourceLoader.setTemplateReader(reader);
204
205 // Name must be the empty string so the doxia-loader gets hit.
206 Template renderTemplate = engine.getTemplate("");
207 VelocityContext ctx = doxiaVelocityContextFactory.getVelocityContext();
208
209 StringWriter writer = new StringWriter();
210
211 renderTemplate.merge(ctx, writer);
212 writer.flush();
213
214 return writer.toString();
215 }
216 }