View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.codehaus.modello.plugin.velocity;
20  
21  import java.io.IOException;
22  import java.io.Writer;
23  import java.nio.charset.StandardCharsets;
24  import java.nio.file.Files;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Map;
28  import java.util.Objects;
29  import java.util.Properties;
30  import org.apache.velocity.Template;
31  import org.apache.velocity.VelocityContext;
32  import org.apache.velocity.runtime.RuntimeInstance;
33  import org.codehaus.modello.ModelloException;
34  import org.codehaus.modello.ModelloParameterConstants;
35  import org.codehaus.modello.model.Model;
36  import org.codehaus.modello.model.Version;
37  import org.codehaus.modello.plugin.AbstractModelloGenerator;
38  import org.codehaus.plexus.util.io.CachingWriter;
39  
40  public class VelocityGenerator extends AbstractModelloGenerator {
41      public static final String VELOCITY_TEMPLATES = "modello.velocity.template";
42  
43      public static final String VELOCITY_PARAMETERS = "modello.velocity.parameters";
44  
45      @Override
46      public void generate(Model model, Properties parameters) throws ModelloException {
47          try {
48              Map<String, String> params = (Map) Objects.requireNonNull(parameters.get(VELOCITY_PARAMETERS));
49              String templates = getParameter(parameters, VELOCITY_TEMPLATES);
50              String output = getParameter(parameters, ModelloParameterConstants.OUTPUT_DIRECTORY);
51  
52              Properties props = new Properties();
53              props.put("resource.loader.file.path", getParameter(parameters, "basedir"));
54              RuntimeInstance velocity = new RuntimeInstance();
55              velocity.init(props);
56  
57              VelocityContext context = new VelocityContext();
58              for (Map.Entry<Object, Object> prop : parameters.entrySet()) {
59                  context.put(prop.getKey().toString(), prop.getValue());
60              }
61              for (Map.Entry<String, String> prop : params.entrySet()) {
62                  context.put(prop.getKey(), prop.getValue());
63              }
64              Version version = new Version(getParameter(parameters, ModelloParameterConstants.VERSION));
65              context.put("version", version);
66              context.put("model", model);
67              context.put("Helper", new Helper(version));
68  
69              for (String templatePath : templates.split(",")) {
70                  Template template = velocity.getTemplate(templatePath);
71  
72                  try (Writer w = new RedirectingWriter(Paths.get(output))) {
73                      template.merge(context, w);
74                  }
75              }
76          } catch (Exception e) {
77              throw new ModelloException("Unable to run velocity template", e);
78          }
79      }
80  
81      static class RedirectingWriter extends Writer {
82          Path dir;
83          StringBuilder sb = new StringBuilder();
84          Writer current;
85  
86          RedirectingWriter(Path dir) {
87              this.dir = dir;
88          }
89  
90          @Override
91          public void write(char[] cbuf, int off, int len) throws IOException {
92              for (int i = 0; i < len; i++) {
93                  if (cbuf[off + i] == '\n') {
94                      if (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\r') {
95                          sb.setLength(sb.length() - 1);
96                      }
97                      writeLine(sb.toString());
98                      sb.setLength(0);
99                  } else {
100                     sb.append(cbuf[off + i]);
101                 }
102             }
103         }
104 
105         protected void writeLine(String line) throws IOException {
106             if (line.startsWith("#MODELLO-VELOCITY#REDIRECT ")) {
107                 String file = line.substring("#MODELLO-VELOCITY#REDIRECT ".length());
108                 if (current != null) {
109                     current.close();
110                 }
111                 Path out = dir.resolve(file);
112                 Files.createDirectories(out.getParent());
113                 current = new CachingWriter(out, StandardCharsets.UTF_8);
114             } else if (current != null) {
115                 current.write(line);
116                 current.write("\n");
117             }
118         }
119 
120         @Override
121         public void flush() throws IOException {
122             if (current != null) {
123                 current.flush();
124             }
125         }
126 
127         @Override
128         public void close() throws IOException {
129             if (current != null) {
130                 current.close();
131                 current = null;
132             }
133         }
134     }
135 }