View Javadoc
1   package org.codehaus.modello.plugin.velocity;
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.Writer;
24  import java.nio.charset.StandardCharsets;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.nio.file.Paths;
28  import java.util.Map;
29  import java.util.Objects;
30  import java.util.Properties;
31  
32  import org.apache.velocity.Template;
33  import org.apache.velocity.VelocityContext;
34  import org.apache.velocity.runtime.RuntimeInstance;
35  import org.codehaus.modello.ModelloException;
36  import org.codehaus.modello.ModelloParameterConstants;
37  import org.codehaus.modello.model.Model;
38  import org.codehaus.modello.model.Version;
39  import org.codehaus.modello.plugin.AbstractModelloGenerator;
40  import org.codehaus.plexus.util.io.CachingWriter;
41  
42  public class VelocityGenerator
43          extends AbstractModelloGenerator
44  {
45      public static final String VELOCITY_TEMPLATES = "modello.velocity.template";
46  
47      public static final String VELOCITY_PARAMETERS = "modello.velocity.parameters";
48  
49      @Override
50      public void generate( Model model, Properties parameters ) throws ModelloException
51      {
52          try
53          {
54              Map<String, String> params = ( Map ) Objects.requireNonNull( parameters.get( VELOCITY_PARAMETERS ) );
55              String templates = getParameter( parameters, VELOCITY_TEMPLATES );
56              String output = getParameter( parameters, ModelloParameterConstants.OUTPUT_DIRECTORY );
57  
58              Properties props = new Properties();
59              props.put( "resource.loader.file.path", getParameter( parameters, "basedir" ) );
60              RuntimeInstance velocity = new RuntimeInstance();
61              velocity.init( props );
62  
63              VelocityContext context = new VelocityContext();
64              for ( Map.Entry<Object, Object> prop : parameters.entrySet() )
65              {
66                  context.put( prop.getKey().toString(), prop.getValue() );
67              }
68              for ( Map.Entry<String, String> prop : params.entrySet() )
69              {
70                  context.put( prop.getKey(), prop.getValue() );
71              }
72              Version version = new Version( getParameter( parameters, ModelloParameterConstants.VERSION ) );
73              context.put( "version", version );
74              context.put( "model", model );
75              context.put( "Helper", new Helper( version ) );
76  
77              for ( String templatePath : templates.split( "," ) )
78              {
79                  Template template = velocity.getTemplate( templatePath );
80  
81                  try ( Writer w = new RedirectingWriter( Paths.get( output ) ) )
82                  {
83                      template.merge( context, w );
84                  }
85              }
86          }
87          catch ( Exception e )
88          {
89              throw new ModelloException( "Unable to run velocity template", e );
90          }
91  
92      }
93  
94      static class RedirectingWriter extends Writer
95      {
96          Path dir;
97          StringBuilder sb = new StringBuilder();
98          Writer current;
99  
100         RedirectingWriter( Path dir )
101         {
102             this.dir = dir;
103         }
104 
105         @Override
106         public void write( char[] cbuf, int off, int len ) throws IOException
107         {
108             for ( int i = 0; i < len; i++ )
109             {
110                 if ( cbuf[ off + i ] == '\n' )
111                 {
112                     if ( sb.length() > 0 && sb.charAt( sb.length() - 1 ) == '\r' )
113                     {
114                         sb.setLength( sb.length() - 1 );
115                     }
116                     writeLine( sb.toString() );
117                     sb.setLength( 0 );
118                 }
119                 else
120                 {
121                     sb.append( cbuf[ off + i ] );
122                 }
123             }
124         }
125 
126         protected void writeLine( String line ) throws IOException
127         {
128             if ( line.startsWith( "#MODELLO-VELOCITY#REDIRECT " ) )
129             {
130                 String file = line.substring( "#MODELLO-VELOCITY#REDIRECT ".length() );
131                 if ( current != null )
132                 {
133                     current.close();
134                 }
135                 Path out = dir.resolve( file );
136                 Files.createDirectories( out.getParent() );
137                 current = new CachingWriter( out, StandardCharsets.UTF_8 );
138             }
139             else if ( current != null )
140             {
141                 current.write( line );
142                 current.write( "\n" );
143             }
144         }
145 
146         @Override
147         public void flush() throws IOException
148         {
149             if ( current != null )
150             {
151                 current.flush();
152             }
153         }
154 
155         @Override
156         public void close() throws IOException
157         {
158             if ( current != null )
159             {
160                 current.close();
161                 current = null;
162             }
163         }
164     }
165 
166 }