View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2018 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.qa.glnm.maven.freemarker.util;
21  
22  import java.io.File;
23  import java.io.FileWriter;
24  import java.io.IOException;
25  import java.util.HashMap;
26  import java.util.Map;
27  
28  import org.slf4j.Logger;
29  import org.slf4j.LoggerFactory;
30  
31  import freemarker.template.Configuration;
32  import freemarker.template.Template;
33  import freemarker.template.TemplateException;
34  import freemarker.template.TemplateExceptionHandler;
35  import io.wcm.qa.glnm.configuration.GaleniumConfiguration;
36  import io.wcm.qa.glnm.exceptions.GaleniumException;
37  import io.wcm.qa.glnm.interaction.Element;
38  import io.wcm.qa.glnm.interaction.FormElement;
39  import io.wcm.qa.glnm.maven.freemarker.methods.ClassNameFromSelectorMethod;
40  import io.wcm.qa.glnm.maven.freemarker.methods.ClassNameFromSpecMethod;
41  import io.wcm.qa.glnm.maven.freemarker.methods.ClassNameFromStringMethod;
42  import io.wcm.qa.glnm.maven.freemarker.methods.ConstantNameMethod;
43  import io.wcm.qa.glnm.maven.freemarker.methods.EscapeJavaDocMethod;
44  import io.wcm.qa.glnm.maven.freemarker.methods.EscapeJavaMethod;
45  import io.wcm.qa.glnm.maven.freemarker.methods.FullSelectorClassNameFromSelectorMethod;
46  import io.wcm.qa.glnm.maven.freemarker.methods.FullWebElementClassNameFromSelectorMethod;
47  import io.wcm.qa.glnm.maven.freemarker.methods.PackageNameMethod;
48  import io.wcm.qa.glnm.maven.freemarker.pojo.InteractionPojo;
49  import io.wcm.qa.glnm.maven.freemarker.pojo.SpecPojo;
50  import io.wcm.qa.glnm.selectors.base.NestedSelector;
51  
52  /**
53   * Utility methods to build data models for use in freemarker code generation.
54   *
55   * @since 1.0.0
56   */
57  public final class FreemarkerUtil {
58  
59    private static final Configuration CONFIGURATION = generateConfiguration();
60  
61    private static final Logger LOG = LoggerFactory.getLogger(FreemarkerUtil.class);
62  
63    private FreemarkerUtil() {
64      // do not instantiate
65    }
66  
67    /**
68     * <p>getDataModelForInteractiveSelector.</p>
69     *
70     * @param packageRoot package for interactive selector interface
71     * @param interfaceName name of interactive selector interface to implement
72     * @param className of interactive selector class
73     * @return data model for generating interactive selector interface
74     */
75    public static Map<String, Object> getDataModelForInteractiveSelector(String packageRoot, String interfaceName, String className) {
76      Map<String, Object> model = getCommonDataModel();
77      model.put("elementInteraction", new InteractionPojo(Element.class));
78      model.put("formElementInteraction", new InteractionPojo(FormElement.class));
79      model.put("interactiveSelectorPackage", packageRoot);
80      model.put("interactiveSelectorBaseClassName", className);
81      model.put("interactiveSelectorInterfaceClassName", interfaceName);
82  
83      return model;
84    }
85  
86    /**
87     * <p>getDataModelForSelector.</p>
88     *
89     * @param selector selector to build data model for
90     * @param spec selector is taken from
91     * @param packageName package of interactive selector interface
92     * @param interactiveClassName name of class
93     * @param interactiveInterfaceName name of interactive selector interface
94     * @return data model for use in generating selector class
95     */
96    public static Map<String, Object> getDataModelForSelector(
97        NestedSelector selector,
98        SpecPojo spec,
99        String packageName,
100       String interactiveClassName,
101       String interactiveInterfaceName) {
102     Map<String, Object> model = getDataModelForInteractiveSelector(packageName, interactiveInterfaceName, interactiveClassName);
103     model.put("className", new ClassNameFromSelectorMethod());
104     model.put("spec", spec);
105     model.put("this", selector);
106 
107     return model;
108   }
109 
110   /**
111    * <p>getDataModelForSpec.</p>
112    *
113    * @param spec to generate Java class for
114    * @param packagePrefixSpecs root package
115    * @return data model for generating spec class
116    */
117   public static Map<String, Object> getDataModelForSpec(SpecPojo spec, String packagePrefixSpecs) {
118     Map<String, Object> model = getCommonDataModel();
119     model.put("className", new ClassNameFromSpecMethod());
120     model.put("classNameFromString", new ClassNameFromStringMethod());
121     model.put("specRootPackageName", packagePrefixSpecs);
122     model.put("spec", spec);
123     return model;
124   }
125 
126   /**
127    * <p>getDataModelForWebElement.</p>
128    *
129    * @param selector selector to build data model for
130    * @param spec selector is taken from
131    * @param packageName package of interactive selector interface
132    * @param interactiveClassName name of interactive selector implementation
133    * @param interactiveInterfaceName name of interactive selector interface
134    * @return data model for use in generating selector class
135    */
136   public static Map<String, Object> getDataModelForWebElement(
137       NestedSelector selector,
138       SpecPojo spec,
139       String packageName,
140       String interactiveClassName,
141       String interactiveInterfaceName) {
142     Map<String, Object> model = getDataModelForSelector(selector, spec, packageName, interactiveClassName, interactiveInterfaceName);
143     model.put("gweClassName", new FullWebElementClassNameFromSelectorMethod());
144     model.put("selectorClassName", new FullSelectorClassNameFromSelectorMethod());
145     return model;
146   }
147 
148   /**
149    * <p>getOutputFile.</p>
150    *
151    * @param outputDir directory
152    * @param outputPackage package
153    * @param outputClassName class name
154    * @return file to write generated code to
155    */
156   public static File getOutputFile(File outputDir, String outputPackage, String outputClassName) {
157     File outputDirectoryPackage = new File(outputDir, outputPackage.replaceAll("\\.", "/"));
158     outputDirectoryPackage.mkdirs();
159     File outputFile = new File(outputDirectoryPackage, outputClassName + ".java");
160     return outputFile;
161   }
162 
163   /**
164    * <p>getTemplate.</p>
165    *
166    * @param directory template root folder
167    * @param name name of template
168    * @return freemarker template
169    */
170   public static Template getTemplate(File directory, String name) {
171     try {
172       CONFIGURATION.setDirectoryForTemplateLoading(directory);
173       Template template = CONFIGURATION.getTemplate(name);
174       return template;
175     }
176     catch (IOException ex) {
177       throw new GaleniumException("exception when getting template.", ex);
178     }
179   }
180 
181   /**
182    * Actually process template to generate code.
183    *
184    * @param template to process
185    * @param dataModel to use
186    * @param outputFile to write to
187    */
188   public static void process(Template template, Map<String, Object> dataModel, File outputFile) {
189     FileWriter out = null;
190     try {
191       out = new FileWriter(outputFile);
192       LOG.debug("generating '" + outputFile.getPath() + "'");
193       template.process(dataModel, out);
194       LOG.info("generated '" + outputFile.getPath() + "'");
195     }
196     catch (IOException | TemplateException ex) {
197       throw new GaleniumException("template exception", ex);
198     }
199     finally {
200       if (out != null) {
201         try {
202           out.close();
203         }
204         catch (IOException ex) {
205           throw new GaleniumException("could not close writer when processing Freemarker template.", ex);
206         }
207       }
208     }
209   }
210 
211   private static Configuration generateConfiguration() {
212     Configuration cfg = new Configuration();
213     cfg.setDefaultEncoding("UTF-8");
214     cfg.setTemplateExceptionHandler(getExceptionHandler());
215     return cfg;
216   }
217 
218   private static Map<String, Object> getCommonDataModel() {
219     Map<String, Object> model = new HashMap<>();
220     model.put("escapeXml", new EscapeJavaDocMethod());
221     model.put("escapeJava", new EscapeJavaMethod());
222     model.put("constantName", new ConstantNameMethod());
223     model.put("packageName", new PackageNameMethod());
224     return model;
225   }
226 
227   private static TemplateExceptionHandler getExceptionHandler() {
228     if (GaleniumConfiguration.isSparseReporting()) {
229       return TemplateExceptionHandler.RETHROW_HANDLER;
230     }
231     else {
232       return TemplateExceptionHandler.DEBUG_HANDLER;
233     }
234   }
235 
236 }