GalenSpecsMojo.java
/* #%L
* wcm.io
* %%
* Copyright (C) 2018 wcm.io
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package io.wcm.qa.glnm.maven.freemarker;
import static org.apache.commons.lang3.ArrayUtils.EMPTY_STRING_ARRAY;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.DirectoryScanner;
import freemarker.template.Template;
import io.wcm.qa.glnm.configuration.ConfigurationUtil;
import io.wcm.qa.glnm.configuration.GaleniumConfiguration;
import io.wcm.qa.glnm.exceptions.GaleniumException;
import io.wcm.qa.glnm.maven.freemarker.pojo.SelectorPojo;
import io.wcm.qa.glnm.maven.freemarker.pojo.SpecPojo;
import io.wcm.qa.glnm.maven.freemarker.util.FormatUtil;
import io.wcm.qa.glnm.maven.freemarker.util.FreemarkerUtil;
import io.wcm.qa.glnm.selectors.base.Selector;
/**
* Goal which finds Galen specs, extracts objects and generates Java code from it.
*
* @since 1.0.0
*/
@Mojo(name = "specs", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class GalenSpecsMojo extends AbstractMojo {
/**
* Root directory for generated output.
*/
@Parameter(defaultValue = "${project.build.directory}/target/specs", property = "inputDir", required = true)
private String inputDirectory;
/**
* Name of Freemarker template to use for abstract interactive selector base class.
*/
@Parameter(defaultValue = "interactive-selector-base.ftlh", property = "interactiveSelectorBaseTemplate")
private String interactiveSelectorBaseTemplate;
/**
* Name of Freemarker template to use for interactive selector interface.
*/
@Parameter(defaultValue = "interactive-selector.ftlh", property = "interactiveSelectorInterfaceTemplate")
private String interactiveSelectorInterfaceTemplate;
/**
* Root directory for generated output.
*/
@Parameter(defaultValue = "${project.build.directory}/generated-sources/java", property = "outputDir", required = true)
private File outputDirectory;
/**
* Package name to generate {@link Selector} code into.
*/
@Parameter(defaultValue = "io.wcm.qa.glnm.selectors", property = "packagePrefixSelectors", required = true)
private String packagePrefixSelectors;
/**
* Package name to generate {@link Selector} code into.
*/
@Parameter(defaultValue = "io.wcm.qa.glnm.specs", property = "packagePrefixSpecs", required = true)
private String packagePrefixSpecs;
/**
* A set of file patterns to exclude from selector generation.
*/
@Parameter(property = "selectorExcludes")
private String[] selectorExcludes;
/**
* A set of file patterns to include in selector generation.
*/
@Parameter(property = "selectorIncludes")
private String[] selectorIncludes;
/**
* Name of Freemarker template to use for generating top level classes.
*/
@Parameter(defaultValue = "selector.ftlh", property = "selectorTemplate")
private String selectorTemplate;
/**
* A set of file patterns to exclude from spec generation.
*/
@Parameter(property = "specExcludes")
private String[] specExcludes;
/**
* A set of file patterns to include in spec generation.
*/
@Parameter(property = "specIncludes")
private String[] specIncludes;
private final Collection<SpecPojo> specsForSelectors = new ArrayList<>();
private final Collection<SpecPojo> specsForSpecs = new ArrayList<>();
/**
* Name of Freemarker template to use for recursively generating static inner classes.
*/
@Parameter(defaultValue = "spec.ftlh", property = "specTemplate")
private String specTemplate;
/**
* To be transferred to system properties when running plugin. Mostly used to manipulate
* {@link GaleniumConfiguration}.
*/
@Parameter(property = "systemPropertyVariables")
private Map<String, String> systemPropertyVariables;
/**
* Directory containing the Freemarker templates.
*/
@Parameter(defaultValue = "${project.basedir}/src/main/resources/freemarker", property = "templateDir", required = true)
private File templateDirectory;
@Parameter(defaultValue = "web-element.ftlh", property = "webElementTemplate")
private String webElementTemplate;
/** {@inheritDoc} */
@Override
public void execute() throws MojoExecutionException {
if (!initPlugin()) {
// if initialization does not work, plugin does not work
throw new GaleniumException("Plugin initialization failed.");
}
// handle spec files and collect objects
parseSpecs();
// prepare Freemarker data model and process template
generateCode();
}
private boolean checkDirectory(File directory) {
getLog().info("checking directory: " + directory.getPath());
if (!directory.isDirectory()) {
getLog().error("directory not found: " + directory.getPath());
return false;
}
return true;
}
private boolean checkInputParams() {
return checkDirectory(templateDirectory);
}
private void generateCode() {
generateInteractiveSelectorInterfaceCode();
generateInteractiveSelectorBaseCode();
generateSelectorCode();
generateWebElementCode();
generateSpecCode();
}
private void generateInteractiveSelectorBaseCode() {
Template template = FreemarkerUtil.getTemplate(templateDirectory, interactiveSelectorBaseTemplate);
String className = getInteractiveSelectorBaseClassName();
String interfaceName = getInteractiveSelectorInterfaceClassName();
String packageName = getInteractiveSelectorPackageName();
Map<String, Object> model = FreemarkerUtil.getDataModelForInteractiveSelector(packageName, interfaceName, className);
File outputFile = FreemarkerUtil.getOutputFile(outputDirectory, packageName, className);
FreemarkerUtil.process(template, model, outputFile);
}
private void generateInteractiveSelectorInterfaceCode() {
Template template = FreemarkerUtil.getTemplate(templateDirectory, interactiveSelectorInterfaceTemplate);
String className = getInteractiveSelectorBaseClassName();
String interfaceName = getInteractiveSelectorInterfaceClassName();
String packageName = getInteractiveSelectorPackageName();
Map<String, Object> model = FreemarkerUtil.getDataModelForInteractiveSelector(packageName, interfaceName, className);
File outputFile = FreemarkerUtil.getOutputFile(outputDirectory, packageName, interfaceName);
FreemarkerUtil.process(template, model, outputFile);
}
private void generateSelectorCode() {
// same template for all selectors
getLog().info("fetching selector template");
Template template = FreemarkerUtil.getTemplate(templateDirectory, selectorTemplate);
for (SpecPojo specPojo : specsForSelectors) {
getLog().info("generating data models for '" + specPojo.getSpecPath() + "'");
for (SelectorPojo selector : specPojo.getRootSelectors()) {
getLog().info("generating data model for '" + selector.elementName() + "'");
Map<String, Object> dataModelForSelector = FreemarkerUtil.getDataModelForSelector(
selector,
specPojo,
getInteractiveSelectorPackageName(),
getInteractiveSelectorBaseClassName(),
getInteractiveSelectorInterfaceClassName());
getLog().debug("processing template");
FreemarkerUtil.process(template, dataModelForSelector, getSelectorOutputFile(selector, specPojo));
}
}
}
private void generateSpecCode() {
// same template for all specs
getLog().info("fetching spec template");
Template template = FreemarkerUtil.getTemplate(templateDirectory, specTemplate);
for (SpecPojo specPojo : specsForSpecs) {
getLog().info("generating data model for '" + specPojo.getSpecPath() + "'");
Map<String, Object> dataModelForSpec = FreemarkerUtil.getDataModelForSpec(specPojo, packagePrefixSpecs);
getLog().debug("processing template");
FreemarkerUtil.process(template, dataModelForSpec, getSpecOutputFile(specPojo));
}
}
private void generateWebElementCode() {
// same template for all webelements
getLog().info("fetching webelement template");
Template template = FreemarkerUtil.getTemplate(templateDirectory, webElementTemplate);
for (SpecPojo specPojo : specsForSelectors) {
getLog().info("generating data models for '" + specPojo.getSpecPath() + "'");
for (SelectorPojo selector : specPojo.getRootSelectors()) {
getLog().info("generating data model for '" + selector.elementName() + "'");
Map<String, Object> dataModelForSelector = FreemarkerUtil.getDataModelForWebElement(
selector,
specPojo,
getInteractiveSelectorPackageName(),
getInteractiveSelectorBaseClassName(),
getInteractiveSelectorInterfaceClassName());
getLog().debug("processing template");
FreemarkerUtil.process(template, dataModelForSelector, getWebElementOutputFile(selector, specPojo));
}
}
}
private File getWebElementOutputFile(SelectorPojo selector, SpecPojo specPojo) {
String outputPackage = FormatUtil.getSelectorsPackageName(packagePrefixSelectors, specPojo);
String className = FormatUtil.getClassName(selector) + "Gwe";
return FreemarkerUtil.getOutputFile(outputDirectory, outputPackage, className);
}
private String[] getIncludedFiles(String baseDir, String[] includes, String[] excludes) {
if (new File(baseDir).isDirectory()) {
DirectoryScanner directoryScanner = new DirectoryScanner();
directoryScanner.setIncludes(includes);
directoryScanner.setExcludes(excludes);
directoryScanner.setBasedir(baseDir);
directoryScanner.scan();
String[] includedFiles = directoryScanner.getIncludedFiles();
return includedFiles;
}
return EMPTY_STRING_ARRAY;
}
private String[] getIncludedFilesForSelectors() {
return getIncludedFiles(inputDirectory, selectorIncludes, selectorExcludes);
}
private String[] getIncludedFilesForSpecs() {
return getIncludedFiles(inputDirectory, specIncludes, specExcludes);
}
private String getInteractiveSelectorBaseClassName() {
return FormatUtil.getClassName(new File(interactiveSelectorBaseTemplate));
}
private String getInteractiveSelectorInterfaceClassName() {
return FormatUtil.getClassName(new File(interactiveSelectorInterfaceTemplate));
}
private String getInteractiveSelectorPackageName() {
return packagePrefixSelectors;
}
private File getSelectorOutputFile(SelectorPojo selector, SpecPojo spec) {
String outputPackage = FormatUtil.getSelectorsPackageName(packagePrefixSelectors, spec);
String className = FormatUtil.getClassName(selector);
return FreemarkerUtil.getOutputFile(outputDirectory, outputPackage, className);
}
private File getSpecOutputFile(SpecPojo spec) {
String outputPackage = packagePrefixSpecs;
String className = FormatUtil.getClassName(spec);
return FreemarkerUtil.getOutputFile(outputDirectory, outputPackage, className);
}
private void storeSpecForSelector(SpecPojo specPojo) {
specsForSelectors.add(specPojo);
}
private void storeSpecForSpec(SpecPojo specPojo) {
specsForSpecs.add(specPojo);
}
protected boolean initPlugin() {
// transfer system properties
ConfigurationUtil.addToSystemProperties(systemPropertyVariables);
System.setProperty("packageRootName", packagePrefixSelectors);
System.setProperty("galenium.specPath", inputDirectory);
// check input parameters
if (!checkInputParams()) {
return false;
}
return true;
}
protected void parseSpecs() {
getLog().info("processing spec files for selectors");
for (String specPath : getIncludedFilesForSelectors()) {
storeSpecForSelector(new SpecPojo(specPath));
}
getLog().info("processing spec files for specs");
for (String specPath : getIncludedFilesForSpecs()) {
storeSpecForSpec(new SpecPojo(specPath));
}
}
}