summaryrefslogtreecommitdiff
path: root/qpid/java/broker-codegen
diff options
context:
space:
mode:
authorRobert Godfrey <rgodfrey@apache.org>2014-04-28 02:25:27 +0000
committerRobert Godfrey <rgodfrey@apache.org>2014-04-28 02:25:27 +0000
commite93df1d676c748f942daaf5fb0c4d4dd4ea867a2 (patch)
tree334bdee0947d54ee5e9f366331e222db2e749d38 /qpid/java/broker-codegen
parent206d461b36995e741ca5a1edcdb2b28f8835832a (diff)
downloadqpid-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')
-rw-r--r--qpid/java/broker-codegen/build.xml28
-rw-r--r--qpid/java/broker-codegen/pom.xml48
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/License.java43
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ConfiguredObjectFactoryGenerator.java169
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactory.java30
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/model/ManagedObjectFactoryConstructor.java30
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableProcessor.java209
-rw-r--r--qpid/java/broker-codegen/src/main/java/org/apache/qpid/server/plugin/PluggableService.java28
-rw-r--r--qpid/java/broker-codegen/src/main/resources/META-INF/services/javax.annotation.processing.Processor20
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