
org.bitbucket.bradleysmithllc.etlunit.maven.FeatureCompilerMojo Maven / Gradle / Ivy
package org.bitbucket.bradleysmithllc.etlunit.maven;
/*
* #%L
* etlunit-feature-compiler Maven Mojo
* %%
* Copyright (C) 2010 - 2014 bradleysmithllc
* %%
* 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%
*/
import com.fasterxml.jackson.databind.JsonNode;
import com.sun.codemodel.*;
import org.apache.commons.lang.ClassUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.*;
import org.apache.maven.project.MavenProject;
import org.bitbucket.bradleysmithllc.etlunit.ExecutionContext;
import org.bitbucket.bradleysmithllc.etlunit.TestAssertionFailure;
import org.bitbucket.bradleysmithllc.etlunit.TestExecutionError;
import org.bitbucket.bradleysmithllc.etlunit.TestWarning;
import org.bitbucket.bradleysmithllc.etlunit.context.VariableContext;
import org.bitbucket.bradleysmithllc.etlunit.feature.*;
import org.bitbucket.bradleysmithllc.etlunit.io.FileBuilder;
import org.bitbucket.bradleysmithllc.etlunit.listener.ClassResponder;
import org.bitbucket.bradleysmithllc.etlunit.listener.OperationProcessor;
import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestMethod;
import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestOperation;
import org.bitbucket.bradleysmithllc.etlunit.parser.ETLTestValueObject;
import org.bitbucket.bradleysmithllc.etlunit.util.EtlUnitStringUtils;
import org.jsonschema2pojo.GenerationConfig;
import org.jsonschema2pojo.Jackson2Annotator;
import org.jsonschema2pojo.SchemaStore;
import org.jsonschema2pojo.rules.RuleFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Generates stubs based on json descriptors.
*/
@Mojo(
name = "generate-gson-proxies",
requiresDependencyResolution = ResolutionScope.COMPILE,
defaultPhase = LifecyclePhase.GENERATE_SOURCES
)
@Execute(
goal = "generate-gson-proxies",
phase = LifecyclePhase.GENERATE_SOURCES
)
public class FeatureCompilerMojo
extends AbstractMojo {
@Parameter(
property = "project"
)
protected MavenProject mavenProject;
@Parameter(
name = "inputDirectory",
defaultValue = "${basedir}/src/main/resources"
)
private File inputDirectory;
@Parameter(
name = "outputDirectory",
defaultValue = "${project.build.directory}/generated-sources/etlunit"
)
private File outputDirectory;
public void execute()
throws MojoExecutionException {
File f = outputDirectory;
if (!f.exists()) {
f.mkdirs();
}
JCodeModel cm = new JCodeModel();
//for (Object res : mavenProject.getResources())
//{
// Resource re = (Resource) res;
// File fi = new File(re.getDirectory());
if (inputDirectory.exists()) {
File
services =
new FileBuilder(inputDirectory).subdir("META-INF")
.subdir("services")
.name("org.bitbucket.bradleysmithllc.etlunit.feature.Feature")
.file();
// check for a services entry for an etlunit feature
if (services.exists()) {
getLog().info("Processing services file: " + services);
// scan this file for features
try {
BufferedReader br = new BufferedReader(new FileReader(services));
String fname;
while ((fname = br.readLine()) != null) {
processFeatureClassName(fname, cm);
}
} catch (Exception e) {
e.printStackTrace();
throw new MojoExecutionException("Failure reading services file", e);
}
}
}
//}
try {
cm.build(outputDirectory);
} catch (IOException e) {
throw new MojoExecutionException("", e);
}
if (mavenProject != null) {
mavenProject.addCompileSourceRoot(outputDirectory.getAbsolutePath());
}
}
private void processFeatureClassName(String fname, JCodeModel cm)
throws
Exception {
// load this class into the vm
try {
Class fcl = Class.forName(fname);
Package aPackage = fcl.getPackage();
JPackage pack = cm.rootPackage();
if (aPackage != null) {
pack = cm._package(aPackage.getName());
}
processFeatureClass(fcl, pack);
} catch (ClassNotFoundException cfne) {
// didn't work - try to use a resource meta info instead
List cplist = (List) mavenProject.getTestClasspathElements();
List urllist = new ArrayList();
urllist.add(inputDirectory.toURI().toURL());
for (String path : cplist)
{
urllist.add(new File(path).toURI().toURL());
}
URL [] urls = urllist.toArray(new URL[cplist.size()]);
URLClassLoader ucl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
ResourceFeatureMetaInfo rfmi = new ResourceFeatureMetaInfo(fname, ucl);
JPackage pack = cm.rootPackage();
String npack = ClassUtils.getPackageName(fname);
if (npack != null && !npack.equals("")) {
pack = cm._package(npack);
}
processMetaInfo(rfmi, pack);
}
}
private void processFeatureClass(Class fcl, JPackage pack)
throws
IllegalAccessException,
InstantiationException,
IOException,
JClassAlreadyExistsException {
getLog().info("Generating stubs for feature: " + fcl.getSimpleName());
Feature f = (Feature) fcl.newInstance();
FeatureMetaInfo metaInfo = f.getMetaInfo();
if (metaInfo != null) {
processMetaInfo(metaInfo, pack);
}
}
private void processMetaInfo(FeatureMetaInfo metaInfo, JPackage pack)
throws IOException, JClassAlreadyExistsException {
getLog().info("Processing meta info " + metaInfo.getDescribingClassName());
// move the package down into a json sub package
pack = pack.subPackage("json");
JsonNode vald = metaInfo.getFeatureConfigurationValidatorNode();
if (vald != null) {
processFeatureConfiguration(metaInfo, vald, pack);
}
Map exportedOperations = metaInfo.getExportedOperations();
if (exportedOperations != null) {
processOperations(metaInfo, exportedOperations, pack);
}
}
private void processFeatureConfiguration(FeatureMetaInfo metaInfo, JsonNode vald, JPackage pack)
throws IOException, JClassAlreadyExistsException {
getLog().info("Processing configuration");
generateSourceFromSchema(vald,
ClassUtils.getShortClassName(metaInfo.getDescribingClassName()) + "Configuration",
pack);
}
private void processOperations(FeatureMetaInfo metaInfo, Map exportedOperations, JPackage pack)
throws IOException, JClassAlreadyExistsException {
getLog().info("Processing operations");
JPackage spack = pack.subPackage(EtlUnitStringUtils.preparePropertyForPackageName(metaInfo.getFeatureName()));
for (Map.Entry entry : exportedOperations.entrySet()) {
processOperation(entry.getValue(), spack);
}
}
private void processOperation(FeatureOperation value, JPackage pack)
throws IOException, JClassAlreadyExistsException {
getLog().info("Processing operation: '" + value.getName() + "'");
pack = pack.subPackage(EtlUnitStringUtils.preparePropertyForPackageName(value.getName()));
if (value.getSignatures().size() > 0)
{
for (FeatureOperationSignature sig : value.getSignatures()) {
processOperationSignature(value, sig, pack);
}
}
}
private void processOperationSignature(FeatureOperation value, FeatureOperationSignature sig, JPackage pack)
throws IOException, JClassAlreadyExistsException {
getLog().info("Processing operation signature: '" + (sig.isSubOperation()
? (value.getName() + "." + sig.getId())
: sig.getId()) + "'");
JsonNode validator = sig.getValidatorNode();
if (validator != null) {
String s = EtlUnitStringUtils.makeProperPropertyName((sig.isSubOperation() ? sig.getId() : value.getName()) + "Request");
pack = sig.isSubOperation() ? pack.subPackage(EtlUnitStringUtils.preparePropertyForPackageName(sig.getId())) : pack;
JDefinedClass jc = generateSourceFromSchema(validator, s, pack);
generateInterfaceForOperation(
sig.isSubOperation() ? sig.getId() : value.getName(),
(sig.isSubOperation() ? sig.getId() : value.getName()) + "Handler",
pack,
jc,
false
);
}
}
private JDefinedClass generateInterfaceForOperation(String operationName, String className, JClassContainer cm, JDefinedClass opClass, boolean omitMethod)
throws IOException, JClassAlreadyExistsException {
className = EtlUnitStringUtils.makeProperPropertyName(className);
getLog().info("Creating processor interface: " + operationName);
JDefinedClass definedClass = cm._interface(className);
JClass refOP = cm.owner().ref(OperationProcessor.class);
JClass refCR = cm.owner().ref(ClassResponder.class);
JClass refac = cm.owner().ref(ClassResponder.action_code.class);
definedClass._extends(refOP);
definedClass._extends(refCR);
if (!omitMethod) {
JMethod meth = definedClass.method(JMod.PUBLIC | JMod.ABSTRACT, refac, EtlUnitStringUtils.checkForJavaKeywords(EtlUnitStringUtils.makePropertyName(
operationName)));
meth.param(opClass, "request");
meth.param(ETLTestMethod.class, "testMethod");
meth.param(ETLTestOperation.class, "testOperation");
meth.param(ETLTestValueObject.class, "valueObject");
meth.param(VariableContext.class, "variableContext");
meth.param(ExecutionContext.class, "executionContext");
meth._throws(TestAssertionFailure.class);
meth._throws(TestExecutionError.class);
meth._throws(TestWarning.class);
}
return definedClass;
}
private JDefinedClass generateSourceFromSchema(JsonNode schema, String className, JClassContainer cm)
throws IOException, JClassAlreadyExistsException {
String packageName = cm.getPackage().name();
String fullyQualifiedName = cm.getPackage().isUnnamed() ? "" : (packageName + ".") + className;
getLog().info("Creating schema container: " + fullyQualifiedName);
System.out.println(schema);
GenerationConfig generationConfig = new CustomGenerationConfig();
RuleFactory ruleFactory = new RuleFactory(
generationConfig,
new Jackson2Annotator(generationConfig),
new SchemaStore()
);
ruleFactory.getSchemaRule().apply(className, schema, null, cm, new PojoSchema(null, schema));
JDefinedClass cl = cm.owner()._getClass(fullyQualifiedName);
if (cl == null)
{
Iterator it = cm.owner().packages();
while (it.hasNext())
{
JPackage pa = it.next();
Iterator itp = pa.classes();
while (itp.hasNext())
{
System.out.println(itp.next());
}
}
throw new IllegalStateException(fullyQualifiedName);
}
return cl;
}
public void setOutputDirectory(File outputDirectory) {
this.outputDirectory = outputDirectory;
}
public void setInputDirectory(File inputDirectory) {
this.inputDirectory = inputDirectory;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy