View Javadoc

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 }