diff options
| author | Robert Godfrey <rgodfrey@apache.org> | 2014-04-28 02:25:27 +0000 |
|---|---|---|
| committer | Robert Godfrey <rgodfrey@apache.org> | 2014-04-28 02:25:27 +0000 |
| commit | e93df1d676c748f942daaf5fb0c4d4dd4ea867a2 (patch) | |
| tree | 334bdee0947d54ee5e9f366331e222db2e749d38 /qpid/java/broker-codegen | |
| parent | 206d461b36995e741ca5a1edcdb2b28f8835832a (diff) | |
| download | qpid-python-e93df1d676c748f942daaf5fb0c4d4dd4ea867a2.tar.gz | |
QPID-5726 : [Java Broker] Use annotation processing to generate object factories and service definitions
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1590547 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java/broker-codegen')
9 files changed, 605 insertions, 0 deletions
diff --git a/qpid/java/broker-codegen/build.xml b/qpid/java/broker-codegen/build.xml new file mode 100644 index 0000000000..d6be1310c3 --- /dev/null +++ b/qpid/java/broker-codegen/build.xml @@ -0,0 +1,28 @@ +<!-- + - + - Licensed to the Apache Software Foundation (ASF) under one + - or more contributor license agreements. See the NOTICE file + - distributed with this work for additional information + - regarding copyright ownership. The ASF licenses this file + - to you 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. + - + --> +<project name="Broker Codegen" default="build"> + <import file="../module.xml"/> + + <property name="module.genpom" value="false"/> + + <target name="bundle" depends="bundle-tasks"/> + +</project> diff --git a/qpid/java/broker-codegen/pom.xml b/qpid/java/broker-codegen/pom.xml new file mode 100644 index 0000000000..1dd2802b4f --- /dev/null +++ b/qpid/java/broker-codegen/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-java-build</artifactId> + <version>0.28-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>qpid-broker-codegen</artifactId> + <name>Qpid Broker Code Generation</name> + <description>Code Generation For Broker and Plugins</description> + + <dependencies> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin-version}</version> + <configuration> + <compilerArgument>-proc:none</compilerArgument> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/License.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/License.java new file mode 100644 index 0000000000..15c01246a7 --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/License.java @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ +package org.apache.qpid.server; + +public interface License +{ + String[] LICENSE = { + " Licensed to the Apache Software Foundation (ASF) under one", + " or more contributor license agreements. See the NOTICE file", + " distributed with this work for additional information", + " regarding copyright ownership. The ASF licenses this file", + " to you 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." + }; +} diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryGenerator.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryGenerator.java new file mode 100644 index 0000000000..658b468c3b --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryGenerator.java @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ +package org.apache.qpid.server.model; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Filer; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +import org.apache.qpid.server.License; + +public class ConfiguredObjectFactoryGenerator extends AbstractProcessor +{ + @Override + public SourceVersion getSupportedSourceVersion() + { + return SourceVersion.latest(); + } + + @Override + public Set<String> getSupportedAnnotationTypes() + { + return new HashSet<>(Arrays.asList(ManagedObjectFactory.class.getName(), ManagedObjectFactoryConstructor.class.getName())); + } + + @Override + public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) + { + + if(roundEnv.processingOver()) + { + + return true; + } + + Filer filer = processingEnv.getFiler(); + + try + { + + for (Element e : roundEnv.getElementsAnnotatedWith(ManagedObjectFactoryConstructor.class)) + { + if(e.getKind() == ElementKind.CONSTRUCTOR) + { + ExecutableElement constructorElement = (ExecutableElement) e; + String factoryName = generateObjectFactory(filer, constructorElement); + } + } + + } + catch (Exception e) + { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error: " + e.getLocalizedMessage()); + } + + return true; + } + + private String generateObjectFactory(final Filer filer, final ExecutableElement constructorElement) + { + TypeElement classElement = (TypeElement) constructorElement.getEnclosingElement(); + String factoryName = classElement.getQualifiedName().toString() + "Factory"; + String factorySimpleName = classElement.getSimpleName().toString() + "Factory"; + String objectSimpleName = classElement.getSimpleName().toString(); + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating factory file for " + classElement.getQualifiedName().toString()); + + PackageElement packageElement = (PackageElement) classElement.getEnclosingElement(); + + try + { + JavaFileObject factoryFile = filer.createSourceFile(factoryName); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(factoryFile.openOutputStream(), "UTF-8")); + pw.println("/*"); + for(String headerLine : License.LICENSE) + { + pw.println(" *" + headerLine); + } + pw.println(" */"); + pw.println(); + pw.print("package "); + pw.print(packageElement.getQualifiedName()); + pw.println(";"); + pw.println(); + + pw.println("import java.util.Map;"); + pw.println(); + pw.println("import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory;"); + pw.println("import org.apache.qpid.server.model.ConfiguredObject;"); + pw.println("import org.apache.qpid.server.plugin.PluggableService;"); + pw.println(); + pw.println("@PluggableService"); + pw.println("public final class " + factorySimpleName + " extends AbstractConfiguredObjectTypeFactory<"+ objectSimpleName +">"); + pw.println("{"); + pw.println(" public " + factorySimpleName + "()"); + pw.println(" {"); + pw.println(" super(" + objectSimpleName + ".class);"); + pw.println(" }"); + pw.println(); + pw.println(" @Override"); + pw.println(" protected "+objectSimpleName+" createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents)"); + pw.println(" {"); + pw.print(" return new "+objectSimpleName+"(attributes"); + boolean first = true; + for(VariableElement param : constructorElement.getParameters()) + { + if(first) + { + first = false; + } + else + { + TypeMirror erasureType = processingEnv.getTypeUtils().erasure(param.asType()); + pw.print(", getParent("+erasureType.toString()+".class,parents)"); + } + } + pw.println(");"); + pw.println(" }"); + + pw.println("}"); + + pw.close(); + } + catch (IOException e) + { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Failed to write factory file: " + + factoryName + + " - " + + e.getLocalizedMessage()); + } + + return factoryName; + } + +} diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactory.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactory.java new file mode 100644 index 0000000000..b74e25df7f --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactory.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ +package org.apache.qpid.server.model; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.SOURCE) + +public @interface ManagedObjectFactory +{ +} diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactoryConstructor.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactoryConstructor.java new file mode 100644 index 0000000000..285f96db12 --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactoryConstructor.java @@ -0,0 +1,30 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ +package org.apache.qpid.server.model; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.SOURCE) + +public @interface ManagedObjectFactoryConstructor +{ +} diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableProcessor.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableProcessor.java new file mode 100644 index 0000000000..8cf5692dd5 --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableProcessor.java @@ -0,0 +1,209 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * + */ +package org.apache.qpid.server.plugin; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Filer; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.NoType; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +import org.apache.qpid.server.License; + +public class PluggableProcessor extends AbstractProcessor +{ + private Map<String, Set<String>> factoryImplementations = new HashMap<>(); + + + @Override + public SourceVersion getSupportedSourceVersion() + { + return SourceVersion.latest(); + } + + @Override + public Set<String> getSupportedAnnotationTypes() + { + return Collections.singleton(PluggableService.class.getName()); + } + + @Override + public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) + { + if(roundEnv.processingOver()) + { + generateServiceFiles(processingEnv.getFiler()); + + return true; + } + try + { + + for (Element e : roundEnv.getElementsAnnotatedWith(PluggableService.class)) + { + + if (e.getKind() == ElementKind.CLASS) + { + TypeElement classElement = (TypeElement) e; + Set<String> pluggableTypes = getPluggableTypes(classElement); + for(String pluggableType : pluggableTypes) + { + Set<String> existingFactories = factoryImplementations.get(pluggableType); + if(existingFactories == null) + { + existingFactories = new HashSet<>(); + factoryImplementations.put(pluggableType, existingFactories); + } + existingFactories.add(classElement.getQualifiedName().toString()); + } + } + } + + } + catch (Exception e) + { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Error: " + e.getLocalizedMessage()); + } + + return true; + } + + private Set<String> getPluggableTypes(final TypeElement classElement) + { + + final Set<String> types = new HashSet<>(); + + List<? extends TypeMirror> interfaces = classElement.getInterfaces(); + for(TypeMirror typeMirror : interfaces) + { + TypeElement interfaceElt = (TypeElement) processingEnv.getTypeUtils().asElement(typeMirror); + if(interfaceElt.getQualifiedName().toString().equals("org.apache.qpid.server.plugin.Pluggable")) + { + types.add(classElement.getQualifiedName().toString()); + } + else + { + types.addAll(getPluggableTypes(interfaceElt)); + } + + } + TypeMirror superClass = classElement.getSuperclass(); + if(!(superClass instanceof NoType)) + { + types.addAll(getPluggableTypes((TypeElement) processingEnv.getTypeUtils().asElement(superClass))); + } + + return types; + } + + private void generateServiceFiles(Filer filer) + { + for(String serviceName : factoryImplementations.keySet()) + { + processingEnv.getMessager() + .printMessage(Diagnostic.Kind.NOTE, "Generating service file for " + serviceName); + + String relativeName = "META-INF/services/" + serviceName; + + try + { + FileObject serviceFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", relativeName); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(serviceFile.openOutputStream(), "UTF-8")); + + for (String headerLine : License.LICENSE) + { + pw.println("#" + headerLine); + } + pw.println("#"); + pw.println("# Note: Parts of this file are auto-generated from annotations."); + pw.println("#"); + for (String implementation : factoryImplementations.get(serviceName)) + { + pw.println(implementation); + } + + pw.close(); + } + catch (IOException e) + { + processingEnv.getMessager() + .printMessage(Diagnostic.Kind.ERROR, + "Failed to write services file: " + + relativeName + + " - " + + e.getLocalizedMessage() + ); + } + } + } + + private String loadExistingServicesFile(final Filer filer, String serviceName) + { + String relativeName = "META-INF/services/" + serviceName; + try + { + + FileObject existingFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", relativeName); + BufferedReader r = new BufferedReader(new InputStreamReader(existingFile.openInputStream(), "UTF-8")); + String line; + while((line=r.readLine())!=null) + { + if(!line.matches(" *#")) + { + factoryImplementations.get(serviceName).add(line); + } + } + r.close(); + } + catch (FileNotFoundException e) + { + // no existing file (ignore) + } + catch (IOException e) + { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Error loading existing services file: " + relativeName + + " - " + e.getLocalizedMessage()); + } + return relativeName; + } + +} diff --git a/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableService.java b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableService.java new file mode 100644 index 0000000000..07799ca71a --- /dev/null +++ b/qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableService.java @@ -0,0 +1,28 @@ +package org.apache.qpid.server.plugin;/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.SOURCE) +public @interface PluggableService +{ +} diff --git a/qpid/java/broker-codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/qpid/java/broker-codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 0000000000..3219c441a3 --- /dev/null +++ b/qpid/java/broker-codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# +org.apache.qpid.server.model.ConfiguredObjectFactoryGenerator +org.apache.qpid.server.plugin.PluggableProcessor |
