Fix FELIX-3749 (https://issues.apache.org/jira/browse/FELIX-3749)
Apply patch from Guillaume Sauthier, forgot some files...
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1407407 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java
new file mode 100644
index 0000000..6b7904c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ClassMetadataCollector.java
@@ -0,0 +1,162 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ClassMetadataCollector extends EmptyVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * Output information.
+ */
+ private Reporter reporter;
+
+ /**
+ * Workbench where produced Elements will be merged and hierarchically organized.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Class currently being analyzed.
+ */
+ private ClassNode node;
+
+ private Element componentMetadata;
+
+ private Element instanceMetadata;
+
+ public ClassMetadataCollector(BindingRegistry registry, Reporter reporter) {
+ this.registry = registry;
+ this.reporter = reporter;
+ node = new ClassNode();
+ }
+
+ /**
+ * Build metadata. May be {@literal null} if no "component type" was found.
+ * @return Build metadata. May be {@literal null} if no "component type" was found.
+ */
+ public Element getComponentMetadata() {
+ return componentMetadata;
+ }
+
+ /**
+ * Build metadata. May be {@literal null} if no "component type" was found.
+ * @return Build metadata. May be {@literal null} if no "component type" was found.
+ */
+ public Element getInstanceMetadata() {
+ return instanceMetadata;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ node.visit(version, access, name, signature, superName, interfaces);
+ workbench = new ComponentWorkbench(registry, node);
+ }
+
+ /**
+ * Visit class annotations.
+ * This method detects @component and @provides annotations.
+ * @param desc : annotation descriptor.
+ * @param visible : is the annotation visible at runtime.
+ * @return the annotation visitor.
+ * @see org.objectweb.asm.ClassAdapter#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .type(node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+ /**
+ * Visit a field.
+ * Call the field collector visitor.
+ * @param access : field access.
+ * @param name : field name
+ * @param desc : field descriptor
+ * @param signature : field signature
+ * @param value : field value (static field only)
+ * @return the field visitor.
+ * @see org.objectweb.asm.ClassAdapter#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ return new FieldMetadataCollector(workbench, new FieldNode(access, name, desc, signature, value));
+ }
+
+ /**
+ * Visit a method.
+ * Call the method collector visitor.
+ * @param access : method access
+ * @param name : method name
+ * @param desc : method descriptor
+ * @param signature : method signature
+ * @param exceptions : method exceptions
+ * @return the Method Visitor.
+ * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return new MethodMetadataCollector(workbench, new MethodNode(access, name, desc, signature, exceptions), reporter);
+ }
+
+ /**
+ * End of the visit : compute final elements.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ @Override
+ public void visitEnd() {
+ if (workbench.getRoot() == null) {
+ // No 'top-level' element has been contributed
+
+ if (!workbench.getElements().isEmpty()) {
+ // There are other annotation's contribution on this type (additional handler declaration/configuration)
+ // That means that there is a missing 'component type' annotation
+
+ reporter.warn("Class %s has not been marked as a component type (no @Component, @Handler, ...). It will be ignored in manipulation.",
+ workbench.getType().getClassName());
+ return;
+ } // else: no root and no elements
+ return;
+ }
+
+ componentMetadata = workbench.build();
+ instanceMetadata = workbench.getInstance();
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java
new file mode 100644
index 0000000..2fdd6c5
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbench.java
@@ -0,0 +1,152 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentWorkbench {
+
+ /**
+ * Root element (usually <component /> or <handler/>).
+ * Maybe null until set.
+ */
+ private Element root;
+
+ /**
+ * Instance element (may be {@literal null}).
+ */
+ private Element instance;
+
+ /**
+ * Map of [element ids, element].
+ * This map is used to easily get an already created element.
+ */
+ private Map<String, Element> m_ids = new TreeMap<String, Element>();
+
+ /**
+ * Map of [element, referto].
+ * This map is used to recreate the element hierarchy.
+ * Stored element are added under referred element.
+ */
+ private Map<Element, String> m_elements = new LinkedHashMap<Element, String>();
+
+ private Type type;
+
+ private BindingRegistry bindingRegistry;
+
+ private ClassNode classNode;
+
+ public ComponentWorkbench(BindingRegistry bindingRegistry, ClassNode node) {
+ this.bindingRegistry = bindingRegistry;
+ this.classNode = node;
+ this.type = Type.getObjectType(node.name);
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public BindingRegistry getBindingRegistry() {
+ return bindingRegistry;
+ }
+
+ public ClassNode getClassNode() {
+ return classNode;
+ }
+
+ /**
+ * The identified root Element. May be null if at the visit time, the root as not been identified.
+ * @return the root Element. or {@literal null} if not defined at the execution time.
+ */
+ public Element getRoot() {
+ return root;
+ }
+
+ public void setRoot(Element root) {
+ // TODO check if root already assigned
+ this.root = root;
+ }
+
+ public Element getInstance() {
+ return instance;
+ }
+
+ public void setInstance(Element instance) {
+ this.instance = instance;
+ }
+
+ public Map<String, Element> getIds() {
+ return m_ids;
+ }
+
+ public Map<Element, String> getElements() {
+ return m_elements;
+ }
+
+ public Element build() {
+
+ if (root == null) {
+ // No 'top level' component Element has been registered
+ return null;
+ }
+
+ // Iterates on all contributed Elements
+ for (Element current : m_elements.keySet()) {
+
+ // If the traversed Element has a reference to another Element,
+ // it has to be moved inside that referenced Element
+ // This is useful for contributing data to other handlers
+
+ String refId = m_elements.get(current);
+ if (refId == null) {
+ // No reference provided, just add it a a direct child
+ root.addElement(current);
+ } else {
+
+ // Get the referenced Element (if any)
+ Element ref = m_ids.get(refId);
+ if (ref == null) {
+ // Add to the root Element
+ root.addElement(current);
+ } else {
+ // Add as child of the referenced Element
+ ref.addElement(current);
+ }
+ }
+ }
+
+ // Clear
+ m_ids.clear();
+ m_elements.clear();
+
+ return root;
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java
new file mode 100644
index 0000000..2efe009
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/FieldMetadataCollector.java
@@ -0,0 +1,72 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.tree.FieldNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadataCollector extends EmptyVisitor implements FieldVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * The workbench currently in use.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Visited field.
+ */
+ private FieldNode node;
+
+ public FieldMetadataCollector(ComponentWorkbench workbench, FieldNode node) {
+ this.workbench = workbench;
+ this.node = node;
+ this.registry = workbench.getBindingRegistry();
+ }
+
+ /**
+ * Visit annotations on the current field.
+ * @param desc : annotation name
+ * @param visible : is the annotation a runtime annotation.
+ * @return the annotation visitor visiting the annotation
+ * @see org.objectweb.asm.FieldVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .field(node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.java
new file mode 100644
index 0000000..874ecd4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/MethodMetadataCollector.java
@@ -0,0 +1,102 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadataCollector extends EmptyVisitor implements MethodVisitor {
+
+ /**
+ * Binding's registry.
+ */
+ private BindingRegistry registry;
+
+ /**
+ * Output informations.
+ */
+ private Reporter reporter;
+
+ /**
+ * The workbench currently in use.
+ */
+ private ComponentWorkbench workbench;
+
+ /**
+ * Visited field.
+ */
+ private MethodNode node;
+
+ public MethodMetadataCollector(ComponentWorkbench workbench, MethodNode node, Reporter reporter) {
+ this.workbench = workbench;
+ this.reporter = reporter;
+ this.node = node;
+ this.registry = workbench.getBindingRegistry();
+ }
+
+ /**
+ * Visit method annotations.
+ *
+ * @param desc : annotation name.
+ * @param visible : is the annotation visible at runtime.
+ * @return the visitor paring the visited annotation.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .method(node)
+ .annotatedWith(desc)
+ .get();
+
+ }
+
+ /**
+ * Visit a parameter annotation.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitParameterAnnotation(int index,
+ String desc,
+ boolean visible) {
+ // Only process annotations on constructor
+ if (node.name.equals("<init>")) {
+
+ // Return the visitor to be executed (may be null)
+ return registry.selection(workbench)
+ .parameter(node, index)
+ .annotatedWith(desc)
+ .get();
+
+ }
+ return super.visitParameterAnnotation(index, desc, visible);
+ }
+
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java
new file mode 100644
index 0000000..d9ec4a8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/module/DefaultBindingModule.java
@@ -0,0 +1,318 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.module;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Controller;
+import org.apache.felix.ipojo.annotations.Handler;
+import org.apache.felix.ipojo.annotations.HandlerDeclaration;
+import org.apache.felix.ipojo.annotations.Instantiate;
+import org.apache.felix.ipojo.annotations.Invalidate;
+import org.apache.felix.ipojo.annotations.Modified;
+import org.apache.felix.ipojo.annotations.PostRegistration;
+import org.apache.felix.ipojo.annotations.PostUnregistration;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.annotations.ServiceController;
+import org.apache.felix.ipojo.annotations.ServiceProperty;
+import org.apache.felix.ipojo.annotations.Unbind;
+import org.apache.felix.ipojo.annotations.Updated;
+import org.apache.felix.ipojo.annotations.Validate;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ComponentVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ControllerVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.FieldPropertyVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.HandlerDeclarationVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.HandlerVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.InstantiateVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.LifecycleVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.MethodPropertyVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ParameterPropertyVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.PostRegistrationVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ProvidesVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.RequiresVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.ServiceControllerVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.UpdatedVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.Action;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.MethodBindVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.bind.ParameterBindVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.apache.felix.ipojo.manipulator.spi.AbsBindingModule;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.lang.annotation.ElementType;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultBindingModule extends AbsBindingModule {
+
+ /**
+ * Configure all the iPOJO's default annotation's bindings.
+ */
+ public void configure() {
+
+ // Class level annotations
+ // --------------------------------
+ bind(Component.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ComponentVisitor(context.getWorkbench(), context.getReporter());
+ }
+ });
+
+ bind(Handler.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new HandlerVisitor(context.getWorkbench(), context.getReporter());
+ }
+ });
+
+ bind(Provides.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ProvidesVisitor(context.getWorkbench());
+ }
+ });
+
+
+ bind(HandlerDeclaration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Reporter reporter = context.getReporter();
+ return new HandlerDeclarationVisitor(context.getWorkbench(), getFreshDocumentBuilder(reporter), reporter);
+ }
+ });
+
+ bind(Instantiate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new InstantiateVisitor(context.getWorkbench());
+ }
+ });
+
+ // Field level annotations
+ // --------------------------------
+ bind(Requires.class)
+ .when(on(ElementType.FIELD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new RequiresVisitor(context.getWorkbench(), ((FieldNode) context.getNode()).name);
+ }
+ })
+ .when(on(ElementType.PARAMETER))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ParameterBindVisitor(context.getWorkbench(), Action.BIND, context.getParameterIndex());
+ }
+ });
+
+ bind(Controller.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ return new ControllerVisitor(context.getWorkbench(), ((FieldNode) context.getNode()).name);
+ }
+ });
+
+ bind(ServiceProperty.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ String name = ((FieldNode) context.getNode()).name;
+ ComponentWorkbench workbench = context.getWorkbench();
+
+ if (!workbench.getIds().containsKey("provides")) {
+ // The provides annotation is already computed.
+ context.getReporter().warn("The component does not provide services, skip ServiceProperty for {}", name);
+ return null;
+ } else {
+ // Get the provides element
+ Element provides = workbench.getIds().get("provides");
+ return new FieldPropertyVisitor(name, provides);
+ }
+
+ }
+ });
+
+ bind(ServiceController.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ String name = ((FieldNode) context.getNode()).name;
+ ComponentWorkbench workbench = context.getWorkbench();
+
+ if (!workbench.getIds().containsKey("provides")) { // The provides annotation is already computed.
+ context.getReporter().warn("The component does not provide services, skip @ServiceController for {}", name);
+ return null;
+ } else {
+ // Get the provides element
+ Element provides = workbench.getIds().get("provides");
+ return new ServiceControllerVisitor(name, provides);
+ }
+
+ }
+ });
+
+ bind(Property.class)
+ .when(on(ElementType.FIELD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ Element properties = Elements.getPropertiesElement(workbench);
+ String name = ((FieldNode) context.getNode()).name;
+ return new FieldPropertyVisitor(name, properties);
+ }
+
+ })
+ .when(on(ElementType.METHOD))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ // @Property on method parameter
+ Element properties = Elements.getPropertiesElement(workbench);
+ String name = ((MethodNode) context.getNode()).name;
+ return new MethodPropertyVisitor(properties, name);
+ }
+ })
+ .when(on(ElementType.PARAMETER))
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+
+ ComponentWorkbench workbench = context.getWorkbench();
+ // @Property on method parameter
+ Element properties = Elements.getPropertiesElement(workbench);
+ MethodNode method = (MethodNode) context.getNode();
+ return new ParameterPropertyVisitor(properties, method, context.getParameterIndex());
+ }
+ });
+
+ bind(Validate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new LifecycleVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name),
+ LifecycleVisitor.Transition.VALIDATE);
+ }
+ });
+
+ bind(Invalidate.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new LifecycleVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name),
+ LifecycleVisitor.Transition.INVALIDATE);
+ }
+ });
+
+ bind(Updated.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new UpdatedVisitor(context.getWorkbench(),
+ Names.computeEffectiveMethodName(node.name));
+ }
+ });
+
+ bind(Bind.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.BIND, node.name);
+ }
+ });
+
+ bind(Unbind.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.UNBIND, node.name);
+ }
+ });
+
+ bind(Modified.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new MethodBindVisitor(context.getWorkbench(), Action.MODIFIED, node.name);
+ }
+ });
+
+ bind(PostRegistration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new PostRegistrationVisitor(context.getWorkbench(), node.name);
+ }
+ });
+
+ bind(PostUnregistration.class)
+ .to(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ MethodNode node = (MethodNode) context.getNode();
+ return new PostRegistrationVisitor(context.getWorkbench(), node.name);
+ }
+ });
+ }
+
+ private DocumentBuilder m_builder;
+
+
+ /**
+ * Creates a 'fresh' document builder.
+ * @return a new document builder is not already created, else reset
+ * the created one, and return it.
+ */
+ protected DocumentBuilder getFreshDocumentBuilder(Reporter reporter) {
+ if (m_builder == null) {
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try {
+ m_builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ // TODO GSA is this acceptable to throw a RuntimeException here ?
+ reporter.warn("Cannot get a fresh DocumentBuilder", e);
+ }
+
+ return m_builder;
+ }
+
+ // The builder has to be reseted
+ m_builder.reset();
+
+ return m_builder;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java
new file mode 100644
index 0000000..e60e751
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Binding.java
@@ -0,0 +1,59 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.registry;
+
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * Triple storing the source annotation, the associated factory and the predicate for conditional support.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Binding {
+ private Class<? extends Annotation> annotationType;
+ private AnnotationVisitorFactory factory;
+ private Predicate predicate;
+
+ public Class<? extends Annotation> getAnnotationType() {
+ return annotationType;
+ }
+
+ public void setAnnotationType(Class<? extends Annotation> annotationType) {
+ this.annotationType = annotationType;
+ }
+
+ public AnnotationVisitorFactory getFactory() {
+ return factory;
+ }
+
+ public void setFactory(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ }
+
+ public Predicate getPredicate() {
+ return predicate;
+ }
+
+ public void setPredicate(Predicate predicate) {
+ this.predicate = predicate;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java
new file mode 100644
index 0000000..cefbf20
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistry.java
@@ -0,0 +1,83 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.registry;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.objectweb.asm.Type;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores all the {@link Binding}s coming from the {@link org.apache.felix.ipojo.manipulator.spi.Module}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BindingRegistry {
+ private Map<String, List<Binding>> tree;
+ private Reporter reporter;
+
+ /**
+ * When no other Binding is selected, the default Bindings list is used.
+ */
+ private List<Binding> defaultBindings;
+
+ public BindingRegistry(Reporter reporter) {
+ this.reporter = reporter;
+ tree = new HashMap<String, List<Binding>>();
+ defaultBindings = new ArrayList<Binding>();
+ }
+
+ /**
+ * Stores the given Bindings
+ */
+ public void addBindings(Iterable<Binding> bindings) {
+ for (Binding binding : bindings) {
+ Type type = Type.getType(binding.getAnnotationType());
+
+ List<Binding> potential = tree.get(type.getDescriptor());
+ if (potential == null) {
+ // Annotation is not already found in supported list
+ potential = new ArrayList<Binding>();
+ tree.put(type.getDescriptor(), potential);
+ }
+
+ potential.add(binding);
+ }
+ }
+
+ /**
+ * Initiate a {@link Selection} for the given workbench.
+ */
+ public Selection selection(ComponentWorkbench workbench) {
+ return new Selection(this, workbench, reporter);
+ }
+
+ public List<Binding> getBindings(String descriptor) {
+ return tree.get(descriptor);
+ }
+
+ public List<Binding> getDefaultBindings() {
+ return defaultBindings;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java
new file mode 100644
index 0000000..1d26d80
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/Selection.java
@@ -0,0 +1,124 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.registry;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MemberNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A {@link Selection} is used to select a subset of all supported {@link AnnotationVisitor}.
+ * It's a query DSL.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Selection implements Iterable<AnnotationVisitor> {
+
+ private BindingRegistry registry;
+ private ComponentWorkbench workbench;
+ private Reporter reporter;
+ private MemberNode node;
+ private int index = -1;
+ private String annotation;
+ private ElementType elementType = null;
+
+ public Selection(BindingRegistry registry, ComponentWorkbench workbench, Reporter reporter) {
+ this.registry = registry;
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ public Selection field(FieldNode node) {
+ this.node = node;
+ this.elementType = ElementType.FIELD;
+ return this;
+ }
+
+ public Selection method(MethodNode node) {
+ this.node = node;
+ this.elementType = ElementType.METHOD;
+ return this;
+ }
+
+ public Selection type(ClassNode node) {
+ this.node = node;
+ this.elementType = ElementType.TYPE;
+ return this;
+ }
+
+ public Selection parameter(MethodNode node, int index) {
+ this.index = index;
+ this.node = node;
+ this.elementType = ElementType.PARAMETER;
+ return this;
+ }
+
+ public Selection annotatedWith(String desc) {
+ this.annotation = desc;
+ return this;
+ }
+
+ public AnnotationVisitor get() {
+ Iterator<AnnotationVisitor> i = iterator();
+ if (iterator().hasNext()) {
+ return i.next();
+ }
+ return null;
+ }
+
+ public Iterator<AnnotationVisitor> iterator() {
+
+ List<AnnotationVisitor> visitors = new ArrayList<AnnotationVisitor>();
+
+ BindingContext context = new BindingContext(workbench, reporter, Type.getType(annotation), node, elementType, index);
+ List<Binding> predicates = registry.getBindings(annotation);
+
+ if (predicates != null && !predicates.isEmpty()) {
+ collectMatchingVisitors(predicates, context, visitors);
+ }
+
+ if (visitors.isEmpty() && !registry.getDefaultBindings().isEmpty()) {
+ collectMatchingVisitors(registry.getDefaultBindings(), context, visitors);
+ }
+
+
+ return visitors.iterator();
+ }
+
+ private void collectMatchingVisitors(List<Binding> bindings, BindingContext context, List<AnnotationVisitor> visitors) {
+ for (Binding binding : bindings) {
+ if (binding.getPredicate().matches(context)) {
+ AnnotationVisitor visitor = binding.getFactory().newAnnotationVisitor(context);
+ visitors.add(visitor);
+ }
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java
new file mode 100644
index 0000000..5f0f58b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitor.java
@@ -0,0 +1,138 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parse the @Component annotation.
+ * @see org.apache.felix.ipojo.annotations.Component
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private Reporter reporter;
+
+ /**
+ * Element 'properties'.
+ */
+ private Element m_props = new Element("properties", "");
+
+ private Element component = new Element("component", "");
+
+ private ComponentWorkbench workbench;
+
+ public ComponentVisitor(ComponentWorkbench workbench, Reporter reporter) {
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Visit @Component annotation attribute.
+ * @param name attribute name
+ * @param value attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("public_factory") || name.equals("publicFactory")) {
+ // public_factory is deprecated, but must sill be supported
+ String factory = value.toString();
+ if (factory != null && factory.equalsIgnoreCase("false")) {
+ component.addAttribute(new Attribute("public", "false"));
+ } else {
+ component.addAttribute(new Attribute("public", "true"));
+ }
+ return;
+ }
+
+ if (name.equals("name")) {
+ component.addAttribute(new Attribute("name", value.toString()));
+ return;
+ }
+ if (name.equals("immediate")) {
+ component.addAttribute(new Attribute("immediate", value.toString()));
+ return;
+ }
+ if (name.equals("architecture")) {
+ component.addAttribute(new Attribute("architecture", value.toString()));
+ return;
+ }
+ if (name.equals("propagation") && (value != null)) {
+ if (arePropertiesEmpty()) {
+ initComponentProperties();
+ }
+ m_props.addAttribute(new Attribute("propagation", value.toString()));
+ return;
+ }
+ if (name.equals("managedservice") && (value != null)) {
+ if (arePropertiesEmpty()) {
+ initComponentProperties();
+ }
+ m_props.addAttribute(new Attribute("pid", value.toString()));
+ return;
+ }
+ if ((name.equals("factory_method") || name.equals("factoryMethod")) && (value != null)) {
+ // factory_method is deprecated, but must still be supported.
+ component.addAttribute(new Attribute("factory-method", value.toString()));
+ return;
+ }
+ if (name.equals("version") && (value != null)) {
+ component.addAttribute(new Attribute("version", value.toString()));
+ }
+ }
+
+ private boolean arePropertiesEmpty() {
+ return m_props.getElements().length == 0;
+ }
+
+ private void initComponentProperties() {
+ workbench.getElements().put(m_props, null);
+ workbench.getIds().put("properties", m_props);
+ }
+
+ /**
+ * End of the visit.
+ * Append to the "component" element computed attribute.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ String classname = workbench.getType().getClassName();
+
+ if (component.getAttribute("name") == null) {
+ component.addAttribute(new Attribute("name", classname));
+ }
+
+ component.addAttribute(new Attribute("classname", classname));
+
+ if (workbench.getRoot() == null) {
+ workbench.setRoot(component);
+ } else {
+ // Error case: 2 component type's annotations (@Component and @Handler for example) on the same class
+ reporter.error("Multiple 'component type' annotations on the class '{}'.", classname);
+ reporter.warn("@Component will be ignored.");
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java
new file mode 100644
index 0000000..e7d33af
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ControllerVisitor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parses the @Controller annotation.
+ * @see org.apache.felix.ipojo.annotations.Controller
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ControllerVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+
+ private String field;
+
+ public ControllerVisitor(ComponentWorkbench workbench, String field) {
+ this.workbench = workbench;
+ this.field = field;
+ }
+
+ /**
+ * Visit @Handler annotation attributes.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visitEnd() {
+ Element controller = new Element("controller", "");
+ controller.addAttribute(new Attribute("field", field));
+ workbench.getElements().put(controller, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java
new file mode 100644
index 0000000..1c2bfdc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/FieldPropertyVisitor.java
@@ -0,0 +1,151 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parses a Property or ServiceProperty annotation.
+ * @see org.apache.felix.ipojo.annotations.ServiceProperty
+ * @see org.apache.felix.ipojo.annotations.Property
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldPropertyVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * Parent element element.
+ */
+ private Element m_parent;
+
+ /**
+ * Field name.
+ */
+ private String m_field;
+
+ /**
+ * Property name.
+ */
+ private String m_name;
+
+ /**
+ * Property value.
+ */
+ private String m_value;
+
+ /**
+ * Property mandatory aspect.
+ */
+ private String m_mandatory;
+
+ /**
+ * Property type.
+ */
+ private String m_type;
+
+
+ /**
+ * Constructor without field
+ * @param parent : element element..
+ */
+ public FieldPropertyVisitor(Element parent) {
+ this(null, parent);
+ }
+
+ /**
+ * Constructor.
+ * @param parent : element element.
+ * @param field : field name.
+ */
+ public FieldPropertyVisitor(String field, Element parent) {
+ m_parent = parent;
+ m_field = field;
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ m_name = value.toString();
+ return;
+ }
+ if (name.equals("value")) {
+ m_value = value.toString();
+ return;
+ }
+ if (name.equals("mandatory")) {
+ m_mandatory = value.toString();
+ return;
+ }
+ if (name.equals("type")) {
+ m_type = value.toString();
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "property" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_field != null && m_name == null) {
+ m_name = m_field;
+ }
+
+
+ Element[] props = m_parent.getElements("property");
+ Element prop = null;
+ for (int i = 0; prop == null && props != null && i < props.length; i++) {
+ String name = props[i].getAttribute("name");
+ if (name != null && name.equals(m_name)) {
+ prop = props[i];
+ }
+ }
+
+ if (prop == null) {
+ prop = new Element("property", "");
+ m_parent.addElement(prop);
+ if (m_name != null) {
+ prop.addAttribute(new Attribute("name", m_name));
+ }
+ }
+
+ if (m_field != null) {
+ prop.addAttribute(new Attribute("field", m_field));
+ }
+ if (m_type != null) {
+ prop.addAttribute(new Attribute("type", m_type));
+ }
+
+ if (m_value != null) {
+ prop.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_mandatory != null) {
+ prop.addAttribute(new Attribute("mandatory", m_mandatory));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java
new file mode 100644
index 0000000..2570afc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerDeclarationVisitor.java
@@ -0,0 +1,157 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Parse the @HandlerDeclaration annotation.
+ * @see org.apache.felix.ipojo.annotations.HandlerDeclaration
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerDeclarationVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * XML accepted by the handler.
+ */
+ private String m_value;
+
+ private DocumentBuilder builder;
+
+ private ComponentWorkbench workbench;
+ private Reporter reporter;
+
+ public HandlerDeclarationVisitor(ComponentWorkbench workbench, DocumentBuilder builder, Reporter reporter) {
+ this.workbench = workbench;
+ this.builder = builder;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Parses the value attribute.
+ * @param name 'value'
+ * @param value the value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ // there is only a 'value' attribute
+ this.m_value = (String) value;
+ }
+
+ /**
+ * End of the visit.
+ * Builds the XML document.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // The value is an XML document
+ InputStream is = new ByteArrayInputStream(m_value.getBytes());
+ Document document = null;
+ try {
+ document = builder.parse(is);
+ Element e = convertDOMElements(document.getDocumentElement());
+ workbench.getElements().put(e, null);
+ } catch (Exception e) {
+ reporter.warn("Cannot convert {} to iPOJO Elements.", m_value, e);
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ reporter.trace("Cannot close correctly the value input stream ({}).", m_value, e);
+ }
+ }
+ }
+
+ /**
+ * Converts recursively the given XML Element into an iPOJO Element.
+ * @param xmlElement DOM Element to be converted
+ */
+ private static Element convertDOMElements(final org.w3c.dom.Element xmlElement) {
+
+ // Create an equivalent iPOJO element
+ Element converted = transformElement(xmlElement);
+
+ convertDOMElements(converted, xmlElement);
+
+ return converted;
+ }
+
+ /**
+ * Converts recursively the given XML Element into an iPOJO Element.
+ * @param root iPOJO root Element
+ * @param xmlElement DOM Element to be converted
+ */
+ private static void convertDOMElements(final Element root,
+ final org.w3c.dom.Element xmlElement) {
+
+ // Convert attributes if any
+ if (xmlElement.hasAttributes()) {
+ NamedNodeMap attributes = xmlElement.getAttributes();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ Attr attr = (Attr) attributes.item(i);
+ root.addAttribute(transformAttribute(attr));
+ }
+ }
+
+ // Convert child elements if any
+ if (xmlElement.hasChildNodes()) {
+ NodeList children = xmlElement.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+
+ // Create an equivalent iPOJO element
+ org.w3c.dom.Element child = (org.w3c.dom.Element) children.item(i);
+ Element converted = transformElement(child);
+
+ // Add converted element as a root's child
+ root.addElement(converted);
+
+ // Recursive call
+ convertDOMElements(converted, child);
+ }
+ }
+
+ }
+
+ private static Attribute transformAttribute(Attr attr) {
+ return new Attribute(attr.getName(),
+ attr.getNamespaceURI(),
+ attr.getValue());
+ }
+
+ private static Element transformElement(org.w3c.dom.Element xmlElement) {
+ return new Element(xmlElement.getLocalName(), xmlElement.getNamespaceURI());
+ }
+
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java
new file mode 100644
index 0000000..0bc16fd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/HandlerVisitor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parses the @Handler annotation.
+ * @see org.apache.felix.ipojo.annotations.Handler
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class HandlerVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private Element handler = new Element("handler", "");
+
+ private ComponentWorkbench workbench;
+
+ private Reporter reporter;
+
+ public HandlerVisitor(ComponentWorkbench workbench, Reporter reporter) {
+ this.workbench = workbench;
+ this.reporter = reporter;
+ }
+
+ /**
+ * Visit @Handler annotation attributes.
+ * @param name : annotation attribute name
+ * @param value : annotation attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ handler.addAttribute(new Attribute("name", value.toString()));
+ return;
+ }
+ if (name.equals("namespace")) {
+ handler.addAttribute(new Attribute("namespace", value.toString()));
+ return;
+ }
+ if (name.equals("level")) {
+ handler.addAttribute(new Attribute("level", value.toString()));
+ return;
+ }
+ if (name.equals("architecture")) {
+ handler.addAttribute(new Attribute("architecture", value.toString()));
+ }
+ }
+
+
+ /**
+ * End of the visit.
+ * Append to the "component" element computed attribute.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ String classname = workbench.getType().getClassName();
+ handler.addAttribute(new Attribute("classname", classname));
+
+ if (workbench.getRoot() == null) {
+ workbench.setRoot(handler);
+ } else {
+ // Error case: 2 component type's annotations (@Component and @Handler for example) on the same class
+ reporter.error("Multiple 'component type' annotations on the class '{}'.", classname);
+ reporter.warn("@Handler will be ignored.");
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java
new file mode 100644
index 0000000..51beb15
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/InstantiateVisitor.java
@@ -0,0 +1,66 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parse the @Instantitate annotation.
+ * @see org.apache.felix.ipojo.annotations.Instantiate
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InstantiateVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private Element instance = new Element("instance", "");
+
+ private ComponentWorkbench workbench;
+
+ public InstantiateVisitor(ComponentWorkbench workbench) {
+ this.workbench = workbench;
+ }
+
+ /**
+ * Visit an annotation attribute.
+ * @param name the attribute name
+ * @param value the attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ instance.addAttribute(new Attribute("name", (String) value));
+ }
+ }
+
+ /**
+ * End of the visit. Creates the instance element.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // TODO Is this really the classname that we need here ? Or the component's name ?
+ instance.addAttribute(new Attribute("component", workbench.getType().getClassName()));
+
+ workbench.setInstance(instance);
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java
new file mode 100644
index 0000000..61ea087
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/LifecycleVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parse @Validate and @Invalidate annotations.
+ * @see org.apache.felix.ipojo.annotations.Validate
+ * @see org.apache.felix.ipojo.annotations.Invalidate
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class LifecycleVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ public static enum Transition {
+ VALIDATE, INVALIDATE
+ }
+
+ private ComponentWorkbench workbench;
+ private String name;
+ private Transition transition;
+
+ public LifecycleVisitor(ComponentWorkbench workbench, String name, Transition transition) {
+ this.workbench = workbench;
+ this.name = name;
+ this.transition = transition;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element cb = new Element("callback", "");
+ cb.addAttribute(new Attribute("transition", transition.name().toLowerCase()));
+ cb.addAttribute(new Attribute("method", name));
+ workbench.getElements().put(cb, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java
new file mode 100644
index 0000000..5804c6c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/MethodPropertyVisitor.java
@@ -0,0 +1,163 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodPropertyVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element m_parent;
+
+ /**
+ * Attached method.
+ */
+ private String m_method;
+
+ /**
+ * Property name.
+ */
+ private String m_name;
+
+ /**
+ * Property id.
+ */
+ private String m_id;
+
+ /**
+ * Property value.
+ */
+ private String m_value;
+
+ /**
+ * Property mandatory aspect.
+ */
+ private String m_mandatory;
+
+ /**
+ * Constructor.
+ *
+ * @param parent : element element.
+ * @param method : attached method.
+ */
+ public MethodPropertyVisitor(Element parent, String method) {
+ m_parent = parent;
+ m_method = method;
+ }
+
+ /**
+ * Visit annotation attributes.
+ *
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("name")) {
+ m_name = value.toString();
+ return;
+ }
+ if (name.equals("value")) {
+ m_value = value.toString();
+ return;
+ }
+ if (name.equals("mandatory")) {
+ m_mandatory = value.toString();
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ }
+ }
+
+ /**
+ * End of the visit.
+ * Append the computed element to the element element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element prop = visitEndCommon();
+
+ prop.addAttribute(new Attribute("method", m_method));
+
+ }
+
+ protected Element visitEndCommon() {
+ m_method = computeEffectiveMethodName(m_method);
+
+ // If neither name nor id is provided, try to extract the name
+ if (m_name == null && m_id == null && m_method.startsWith("set")) {
+ m_name = m_method.substring("set".length());
+ m_id = m_name;
+ // Else align the two values
+ } else if (m_name != null && m_id == null) {
+ m_id = m_name;
+ } else if (m_id != null && m_name == null) {
+ m_name = m_id;
+ }
+
+ Element prop = getPropertyElement();
+
+ if (m_value != null) {
+ prop.addAttribute(new Attribute("value", m_value));
+ }
+ if (m_mandatory != null) {
+ prop.addAttribute(new Attribute("mandatory", m_mandatory));
+ }
+ return prop;
+ }
+
+ private Element getPropertyElement() {
+
+ // Gather all the <property> Elements
+ Element[] props = m_parent.getElements("property");
+ Element prop = null;
+ for (int i = 0; props != null && prop == null && i < props.length; i++) {
+
+ // Get the first one with the good name
+ String name = props[i].getAttribute("name");
+ if (name != null && name.equals(m_name)) {
+ prop = props[i];
+ }
+ }
+
+ // Create the Element if not present
+ if (prop == null) {
+ prop = new Element("property", "");
+ m_parent.addElement(prop);
+ if (m_name != null) {
+ prop.addAttribute(new Attribute("name", m_name));
+ }
+ }
+
+ return prop;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java
new file mode 100644
index 0000000..fb5ca87
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ParameterPropertyVisitor.java
@@ -0,0 +1,66 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterPropertyVisitor extends MethodPropertyVisitor implements AnnotationVisitor {
+
+ /**
+ * If this is a parameter annotation, the index of the parameter.
+ */
+ private int m_index = -1;
+
+ private MethodNode node;
+
+ /**
+ * Constructor.
+ *
+ * @param parent : element element.
+ * @param method : attached method.
+ * @param index : the parameter index
+ */
+ public ParameterPropertyVisitor(Element parent, MethodNode method, int index) {
+ super(parent, method.name);
+ this.node = method;
+ m_index = index;
+ }
+
+ /**
+ * End of the visit.
+ * Append the computed element to the element element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element prop = visitEndCommon();
+ String type = Type.getArgumentTypes(node.desc)[m_index].getClassName();
+ prop.addAttribute(new Attribute("type", type));
+ prop.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java
new file mode 100644
index 0000000..873fde8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostRegistrationVisitor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * @see org.apache.felix.ipojo.annotations.PostRegistration
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PostRegistrationVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public PostRegistrationVisitor(ComponentWorkbench workbench, String name) {
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element provides = null;
+ if (workbench.getIds().containsKey("provides")) {
+ provides = workbench.getIds().get("provides");
+ provides.addAttribute(new Attribute("post-registration", name));
+ }
+ // Else ignore annotation ...
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java
new file mode 100644
index 0000000..eae941e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/PostUnregistrationVisitor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * @see org.apache.felix.ipojo.annotations.PostUnregistration
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PostUnregistrationVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public PostUnregistrationVisitor(ComponentWorkbench workbench, String name) {
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element provides = null;
+ if (workbench.getIds().containsKey("provides")) {
+ provides = workbench.getIds().get("provides");
+ provides.addAttribute(new Attribute("post-unregistration", name));
+ }
+ // Else ignore annotation ...
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java
new file mode 100644
index 0000000..d23aa33
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ProvidesVisitor.java
@@ -0,0 +1,126 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parse the @Provides annotation.
+ * @see org.apache.felix.ipojo.annotations.Provides
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ProvidesVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+
+ /**
+ * Provides element.
+ */
+ private Element m_prov = new Element("provides", "");
+
+ public ProvidesVisitor(ComponentWorkbench workbench) {
+ this.workbench = workbench;
+ }
+
+ /**
+ * Visit @provides annotation attributes.
+ * @param name : annotation attribute name
+ * @param value : annotation attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("factory")) { // Should be deprecated
+ m_prov.addAttribute(new Attribute("factory", value.toString()));
+ }
+ if (name.equals("strategy")) {
+ m_prov.addAttribute(new Attribute("strategy", value.toString()));
+ }
+ }
+
+ /**
+ * Visit specifications array.
+ * @param name : attribute name
+ * @return a visitor visiting each element of the array.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String name) {
+ if (name.equals("specifications")) {
+ return new InterfaceArrayVisitor();
+ } else if (name.equals("properties")) {
+ // Create a new simple visitor to visit the nested ServiceProperty annotations
+ // Collected properties are collected in m_prov
+ return new EmptyVisitor() {
+ public AnnotationVisitor visitAnnotation(String ignored, String desc) {
+ return new FieldPropertyVisitor(m_prov);
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * End of the visit.
+ * Append to the element element the computed "provides" element.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ workbench.getIds().put("provides", m_prov);
+ workbench.getElements().put(m_prov, null);
+ }
+
+ private class InterfaceArrayVisitor extends EmptyVisitor {
+ /**
+ * List of parsed interface.
+ */
+ private String m_itfs;
+
+ /**
+ * Visit one element of the array.
+ * @param arg0 : null
+ * @param arg1 : element value.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ if (m_itfs == null) {
+ m_itfs = "{" + ((Type) arg1).getClassName();
+ } else {
+ m_itfs += "," + ((Type) arg1).getClassName();
+ }
+ }
+
+ /**
+ * End of the array visit.
+ * Add the attribute to 'provides' element.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ m_prov.addAttribute(new Attribute("specifications", m_itfs + "}"));
+ }
+
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
new file mode 100644
index 0000000..73ae8a0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
@@ -0,0 +1,210 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * AnnotationVisitor parsing the @Requires annotation.
+ * @see org.apache.felix.ipojo.annotations.Requires
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class RequiresVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+
+ private ComponentWorkbench workbench;
+
+ /**
+ * Dependency field.
+ */
+ private String m_field;
+
+ /**
+ * Dependency filter.
+ */
+ private String m_filter;
+
+ /**
+ * Is the dependency optional ?
+ */
+ private String m_optional;
+
+ /**
+ * Dependency specification.
+ */
+ private String m_specification;
+
+ /**
+ * Dependency id.
+ */
+ private String m_id;
+
+ /**
+ * Binding policy.
+ */
+ private String m_policy;
+
+ /**
+ * Default-Implementation attribute.
+ */
+ private String m_defaultImplementation;
+
+ /**
+ * Enable or Disable Nullable pattern.
+ */
+ private String m_nullable;
+
+ /**
+ * Comparator.
+ */
+ private String m_comparator;
+
+ /**
+ * From attribute.
+ */
+ private String m_from;
+
+ /**
+ * Proxy attribute.
+ */
+ private String m_proxy;
+
+ /**
+ * Constructor.
+ * @param name : field name.
+ */
+ public RequiresVisitor(ComponentWorkbench workbench, String name) {
+ this.workbench = workbench;
+ this.m_field = name;
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("filter")) {
+ m_filter = value.toString();
+ return;
+ }
+ if (name.equals("optional")) {
+ m_optional = value.toString();
+ return;
+ }
+ if (name.equals("nullable")) {
+ m_nullable = value.toString();
+ return;
+ }
+ if (name.equals("policy")) {
+ m_policy = value.toString();
+ return;
+ }
+ if (name.equals("defaultimplementation")) {
+ Type type = Type.getType(value.toString());
+ m_defaultImplementation = type.getClassName();
+ return;
+ }
+ if (name.equals("specification")) {
+ m_specification = value.toString();
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ return;
+ }
+ if (name.equals("comparator")) {
+ Type type = Type.getType(value.toString());
+ m_comparator = type.getClassName();
+ return;
+ }
+ if (name.equals("from")) {
+ m_from = value.toString();
+ return;
+ }
+ if (name.equals("proxy")) {
+ m_proxy = value.toString();
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "requires" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ Element requires = null;
+ if (m_id == null) {
+ requires = workbench.getIds().get(m_field);
+ } else {
+ requires = workbench.getIds().get(m_id);
+ }
+
+ if (requires == null) {
+ requires = new Element("requires", "");
+ }
+
+ requires.addAttribute(new Attribute("field", m_field));
+ if (m_specification != null) {
+ requires.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_filter != null) {
+ requires.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_optional != null) {
+ requires.addAttribute(new Attribute("optional", m_optional));
+ }
+ if (m_nullable != null) {
+ requires.addAttribute(new Attribute("nullable", m_nullable));
+ }
+ if (m_defaultImplementation != null) {
+ requires.addAttribute(new Attribute("default-implementation", m_defaultImplementation));
+ }
+ if (m_policy != null) {
+ requires.addAttribute(new Attribute("policy", m_policy));
+ }
+ if (m_id != null) {
+ requires.addAttribute(new Attribute("id", m_id));
+ }
+ if (m_comparator != null) {
+ requires.addAttribute(new Attribute("comparator", m_comparator));
+ }
+ if (m_from != null) {
+ requires.addAttribute(new Attribute("from", m_from));
+ }
+ if (m_proxy != null) {
+ requires.addAttribute(new Attribute("proxy", m_proxy));
+ }
+
+ if (m_id != null) {
+ workbench.getIds().put(m_id, requires);
+ } else {
+ workbench.getIds().put(m_field, requires);
+ }
+
+ workbench.getElements().put(requires, null);
+ }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java
new file mode 100644
index 0000000..5aad731
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ServiceControllerVisitor.java
@@ -0,0 +1,80 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parses a @ServiceController annotation.
+ * @see org.apache.felix.ipojo.annotations.ServiceController
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceControllerVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element provides;
+
+ /**
+ * Provides element.
+ */
+ private Element controller = new Element("controller", "");
+
+ /**
+ * Constructor.
+ * @param provides : element element.
+ * @param field : field name.
+ */
+ public ServiceControllerVisitor(String field, Element provides) {
+ this.provides = provides;
+ controller.addAttribute(new Attribute("field", field));
+ }
+
+ /**
+ * Visit one "simple" annotation.
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("value")) {
+ controller.addAttribute(new Attribute("value", value.toString()));
+ return;
+ }
+ if (name.equals("specification")) {
+ String spec = ((Type) value).getClassName();
+ controller.addAttribute(new Attribute("specification", spec));
+ }
+ }
+
+ /**
+ * End of the annotation.
+ * Create a "controller" element
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ provides.addElement(controller);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java
new file mode 100644
index 0000000..7a3d844
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/UpdatedVisitor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * @see org.apache.felix.ipojo.annotations.Updated
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class UpdatedVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ private ComponentWorkbench workbench;
+ private String name;
+
+ public UpdatedVisitor(ComponentWorkbench workbench, String name) {
+ this.workbench = workbench;
+ this.name = name;
+ }
+
+ @Override
+ public void visitEnd() {
+ Element properties = Elements.getPropertiesElement(workbench);
+ properties.addAttribute(new Attribute("updated", name));
+
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java
new file mode 100644
index 0000000..29461ce
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/AbstractBindVisitor.java
@@ -0,0 +1,210 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbstractBindVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ protected ComponentWorkbench workbench;
+ protected Action action;
+
+ public AbstractBindVisitor(ComponentWorkbench workbench, Action action) {
+ this.workbench = workbench;
+ this.action = action;
+ }
+
+ /**
+ * Requirement filter.
+ */
+ protected String m_filter;
+ /**
+ * Is the requirement optional?
+ */
+ protected String m_optional;
+ /**
+ * Is the requirement aggregate?
+ */
+ protected String m_aggregate;
+ /**
+ * Required specification.
+ */
+ protected String m_specification;
+ /**
+ * Requirement id.
+ */
+ protected String m_id;
+ /**
+ * Binding policy.
+ */
+ protected String m_policy;
+ /**
+ * Comparator.
+ */
+ protected String m_comparator;
+ /**
+ * From attribute.
+ */
+ protected String m_from;
+
+ /**
+ * Visit annotation's attributes.
+ *
+ * @param name : annotation name
+ * @param value : annotation value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (name.equals("filter")) {
+ m_filter = value.toString();
+ return;
+ }
+ if (name.equals("optional")) {
+ m_optional = value.toString();
+ return;
+ }
+ if (name.equals("aggregate")) {
+ m_aggregate = value.toString();
+ return;
+ }
+ if (name.equals("specification")) {
+ m_specification = value.toString();
+ return;
+ }
+ if (name.equals("policy")) {
+ m_policy = value.toString();
+ return;
+ }
+ if (name.equals("id")) {
+ m_id = value.toString();
+ return;
+ }
+ if (name.equals("comparator")) {
+ Type type = Type.getType(value.toString());
+ m_comparator = type.getClassName();
+ return;
+ }
+ if (name.equals("from")) {
+ m_from = value.toString();
+ }
+
+ }
+
+ public void visitEnd() {
+ }
+
+ protected Element getRequiresElement() {
+
+ // Check if it is a full-determined requirement
+ Element requires = workbench.getIds().get(m_id);
+ if (requires == null) {
+ // Add the complete requires
+ requires = createRequiresElement();
+ } else {
+ if (!completeExistingRequires(requires))
+ return null;
+ }
+
+ return requires;
+ }
+
+ protected boolean completeExistingRequires(Element requires) {
+
+ if (!completeAttribute(requires, "specification", m_specification))
+ return false;
+
+ if (!completeAttribute(requires, "optional", m_optional))
+ return false;
+
+ if (!completeAttribute(requires, "aggregate", m_aggregate))
+ return false;
+
+ if (!completeAttribute(requires, "filter", m_filter))
+ return false;
+
+ if (!completeAttribute(requires, "policy", m_policy))
+ return false;
+
+ if (!completeAttribute(requires, "comparator", m_comparator))
+ return false;
+
+ if (!completeAttribute(requires, "from", m_from))
+ return false;
+
+ return true;
+ }
+
+ private boolean completeAttribute(Element requires, String name, String value) {
+ // If we have a value
+ if (value != null) {
+
+ String old = requires.getAttribute(name);
+ if (old == null) {
+ // If the old value was not set, just set the new value
+ requires.addAttribute(new Attribute(name, value));
+ } else if (!value.equals(old)) {
+ //
+ System.err.println("The '" + name + "' attribute has changed: " + old + " -> " + value);
+ return false;
+ } // Otherwise, the old and new value are equals
+ }
+ return true;
+ }
+
+ protected Element createRequiresElement() {
+ Element requires;
+ requires = new Element("requires", "");
+ if (m_specification != null) {
+ requires.addAttribute(new Attribute("specification", m_specification));
+ }
+ if (m_aggregate != null) {
+ requires.addAttribute(new Attribute("aggregate", m_aggregate));
+ }
+ if (m_filter != null) {
+ requires.addAttribute(new Attribute("filter", m_filter));
+ }
+ if (m_optional != null) {
+ requires.addAttribute(new Attribute("optional", m_optional));
+ }
+ if (m_policy != null) {
+ requires.addAttribute(new Attribute("policy", m_policy));
+ }
+ if (m_id != null) {
+ requires.addAttribute(new Attribute("id", m_id));
+ }
+ if (m_comparator != null) {
+ requires.addAttribute(new Attribute("comparator", m_comparator));
+ }
+ if (m_from != null) {
+ requires.addAttribute(new Attribute("from", m_from));
+ }
+ return requires;
+ }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java
new file mode 100644
index 0000000..5ed64a1
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/Action.java
@@ -0,0 +1,27 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.bind;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public enum Action {
+ BIND, MODIFIED, UNBIND
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java
new file mode 100644
index 0000000..6be36fc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/MethodBindVisitor.java
@@ -0,0 +1,72 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * Parse @Bind & @Unbind annotations on methods.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodBindVisitor extends AbstractBindVisitor {
+
+ /**
+ * Method name.
+ */
+ private String m_name;
+
+ public MethodBindVisitor(ComponentWorkbench workbench, Action action, String method) {
+ super(workbench, action);
+ this.m_name = method;
+ }
+
+ /**
+ * End of the visit.
+ * Create or append the requirement info to a created or already existing "requires" element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_id == null) {
+ String identifier = Names.getMethodIdentifier(m_name);
+ if (identifier != null) {
+ m_id = identifier;
+ } else {
+ System.err.println("Cannot determine the id of the " + action.name() + " method : " + computeEffectiveMethodName(m_name));
+ return;
+ }
+ }
+
+ Element requires = getRequiresElement();
+
+ Element callback = new Element("callback", "");
+ callback.addAttribute(new Attribute("method", computeEffectiveMethodName(m_name)));
+ callback.addAttribute(new Attribute("type", action.name().toLowerCase()));
+ requires.addElement(callback);
+
+ workbench.getIds().put(m_id, requires);
+ workbench.getElements().put(requires, null);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java
new file mode 100644
index 0000000..b3063ee
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/bind/ParameterBindVisitor.java
@@ -0,0 +1,63 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.bind;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Parse @Bind & @Unbind annotations on method's parameters.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterBindVisitor extends AbstractBindVisitor {
+
+ /**
+ * For annotation parameter,
+ * the parameter index.
+ */
+ private int m_index;
+
+ public ParameterBindVisitor(ComponentWorkbench workbench, Action action, int index) {
+ super(workbench, action);
+ m_index = index;
+ }
+
+ /**
+ * End of the visit.
+ * Create or append the requirement info to a created or already existing "requires" element.
+ *
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_id == null) {
+ m_id = Integer.toString(m_index);
+ }
+
+ Element requires = getRequiresElement();
+
+ // Specific for parameters
+ requires.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+
+ workbench.getIds().put(m_id, requires);
+ workbench.getElements().put(requires, null);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java
new file mode 100644
index 0000000..b2edce0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/FieldGenericVisitor.java
@@ -0,0 +1,37 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.FieldNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldGenericVisitor extends RootGenericVisitor {
+ public FieldGenericVisitor(ComponentWorkbench workbench, Element element, FieldNode node) {
+ super(workbench, element, ElementType.FIELD);
+ element.addAttribute(new Attribute("field", node.name));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java
new file mode 100644
index 0000000..cd1296a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/GenericVisitor.java
@@ -0,0 +1,109 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+import java.lang.reflect.Array;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class GenericVisitor extends EmptyVisitor implements AnnotationVisitor {
+ protected Element element;
+
+ public GenericVisitor(Element element) {
+ this.element = element;
+ }
+
+ /**
+ * Visit a 'simple' annotation attribute.
+ * This method is used for primitive arrays too.
+ * @param name : attribute name
+ * @param value : attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (value.getClass().isArray()) {
+ // Primitive arrays case
+ String v = null;
+ int index = Array.getLength(value);
+ for (int i = 0; i < index; i++) {
+ if (v == null) {
+ v = "{" + Array.get(value, i);
+ } else {
+ v += "," + Array.get(value, i);
+ }
+ }
+ v += "}";
+ element.addAttribute(new Attribute(name, v));
+ return;
+ }
+
+ // Attributes are added as normal attributes
+ if (!(value instanceof Type)) {
+ element.addAttribute(new Attribute(name, value.toString()));
+ } else {
+ // Attributes of type class need a special handling
+ element.addAttribute(new Attribute(name, ((Type) value).getClassName()));
+ }
+
+ }
+
+ /**
+ * Visit a sub-annotation.
+ * @param name : attribute name.
+ * @param descriptor : annotation description
+ * @return an annotation visitor which will visit the given annotation
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String name, String descriptor) {
+ // Sub annotations are mapped to sub-elements
+ Element sub = Elements.buildElement(Type.getType(descriptor));
+ element.addElement(sub);
+ return new GenericVisitor(sub);
+ }
+
+ /**
+ * Visit an array attribute.
+ * @param name : attribute name
+ * @return a visitor which will visit each element of the array
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(String)
+ */
+ public AnnotationVisitor visitArray(String name) {
+ return new SubArrayVisitor(element, name);
+ }
+
+ /**
+ * Visits an enumeration attribute.
+ * @param name the attribute name
+ * @param desc the enumeration descriptor
+ * @param value the attribute value
+ * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)
+ */
+ public void visitEnum(String name, String desc, String value) {
+ element.addAttribute(new Attribute(name, value));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java
new file mode 100644
index 0000000..29c558a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/MethodGenericVisitor.java
@@ -0,0 +1,39 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+
+import static org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Names.computeEffectiveMethodName;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodGenericVisitor extends RootGenericVisitor {
+ public MethodGenericVisitor(ComponentWorkbench workbench, Element element, MethodNode node) {
+ super(workbench, element, ElementType.METHOD);
+ element.addAttribute(new Attribute("method", computeEffectiveMethodName(node.name)));
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java
new file mode 100644
index 0000000..c3e59e7
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/ParameterGenericVisitor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ParameterGenericVisitor extends RootGenericVisitor {
+ private int index;
+ private MethodNode node;
+
+ public ParameterGenericVisitor(ComponentWorkbench workbench, Element element, MethodNode node, int index) {
+ super(workbench, element, ElementType.PARAMETER);
+ this.node = node;
+ this.index = index;
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+
+ String type = Type.getArgumentTypes(node.desc)[index].getClassName();
+ // TODO Is the 'index' attribute required ?
+ element.addAttribute(new Attribute("index", Integer.toString(index)));
+ element.addAttribute(new Attribute("type", type));
+ element.addAttribute(new Attribute("constructor-parameter", Integer.toString(index)));
+
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java
new file mode 100644
index 0000000..2bb65aa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/RootGenericVisitor.java
@@ -0,0 +1,107 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class RootGenericVisitor extends GenericVisitor {
+ private ComponentWorkbench workbench;
+
+ /**
+ * Id attribute (if found)
+ * else use the annotation package name.
+ */
+ private String m_id;
+
+ /**
+ * Parent attribute (if found)
+ * else use the annotation package name.
+ */
+ private String m_parent;
+
+ /**
+ * Describes the structure that supports the traversed annotation.
+ */
+ private ElementType type;
+
+ public RootGenericVisitor(ComponentWorkbench workbench, Element element, ElementType type) {
+ super(element);
+ this.workbench = workbench;
+ this.type = type;
+ }
+
+ /**
+ * Visit a 'simple' annotation attribute.
+ * This method is used for primitive arrays too.
+ * @param name : attribute name
+ * @param value : attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ super.visit(name, value);
+
+ if (name.equals("id")) {
+ m_id = value.toString();
+ } else if (name.equals("parent")) {
+ m_parent = value.toString();
+ }
+ }
+
+ /**
+ * End of the visit.
+ * All attribute were visited, we can update collectors data.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+
+ if (m_id != null) {
+ // An ID has been provided as annotation attribute
+ // Register our element under that ID
+ workbench.getIds().put(m_id, element);
+ } else {
+ // No ID provided, generate a new one from the element's namespace (aka handler's namespace)
+ m_id = element.getNameSpace();
+ if (!workbench.getIds().containsKey(m_id) && isClassType()) {
+ // No Elements were already registered under that namespace
+ workbench.getIds().put(m_id, element);
+ } else {
+ // ID already registered by another annotation
+ if (m_parent == null) {
+ // If no parent specified, place this element under the 'class level' Element (default)
+ m_parent = element.getNameSpace();
+ } // Otherwise, place this element under the specified Element (contribution)
+ }
+ }
+
+ workbench.getElements().put(element, m_parent);
+
+ }
+
+ private boolean isClassType() {
+ return ElementType.TYPE.equals(type);
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java
new file mode 100644
index 0000000..e70727d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/SubArrayVisitor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Elements;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SubArrayVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * Parent element.
+ */
+ private Element m_elem;
+
+ /**
+ * Attribute name.
+ */
+ private String m_name;
+
+ /**
+ * Attribute value.
+ * (accumulator)
+ */
+ private String m_acc;
+
+ /**
+ * Constructor.
+ * @param elem : element element.
+ * @param name : attribute name.
+ */
+ public SubArrayVisitor(Element elem, String name) {
+ m_elem = elem;
+ m_name = name;
+ }
+
+ /**
+ * Visit a 'simple' element of the visited array.
+ * @param name : null
+ * @param value : element value.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(String, Object)
+ */
+ public void visit(String name, Object value) {
+ if (m_acc == null) {
+ if (!(value instanceof Type)) {
+ m_acc = "{" + value.toString();
+ } else {
+ // Attributes of type class need a special handling
+ m_acc = "{" + ((Type) value).getClassName();
+ }
+ } else {
+ if (!(value instanceof Type)) {
+ m_acc = m_acc + "," + value.toString();
+ } else {
+ // Attributes of type class need a special handling
+ m_acc = m_acc + "," + ((Type) value).getClassName();
+ }
+ }
+ }
+
+ /**
+ * Visits an enumeration attribute.
+ * @param name the attribute name
+ * @param desc the enumeration descriptor
+ * @param value the attribute value
+ */
+ public void visitEnum(String name, String desc, String value) {
+ if (m_acc == null) {
+ m_acc = "{" + value;
+ } else {
+ m_acc = m_acc + "," + value;
+ }
+ }
+
+
+ /**
+ * Visit an annotation element of the visited array.
+ * @param name : null
+ * @param desc : annotation to visit
+ * @return the visitor which will visit the annotation
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(String, String)
+ */
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ // Sub annotations are map to sub-elements
+ Element elem = Elements.buildElement(Type.getType(desc));
+ m_elem.addElement(elem);
+ return new GenericVisitor(elem);
+ }
+
+ /**
+ * End of the visit.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_acc != null) {
+ // We have analyzed an attribute
+ m_elem.addAttribute(new Attribute(m_name, m_acc + "}"));
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java
new file mode 100644
index 0000000..9da0437
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/generic/TypeGenericVisitor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.generic;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TypeGenericVisitor extends RootGenericVisitor {
+ public TypeGenericVisitor(ComponentWorkbench workbench, Element element) {
+ super(workbench, element, ElementType.TYPE);
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java
new file mode 100644
index 0000000..877794a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Bindings.java
@@ -0,0 +1,165 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.util;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.BindingRegistry;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.FieldGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.MethodGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.ParameterGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.TypeGenericVisitor;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.manipulator.spi.Module;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.ElementType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.regex.Pattern;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.and;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.pattern;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Bindings {
+
+ private static List<Binding> DEFAULT_BINDINGS;
+ static {
+ DEFAULT_BINDINGS = new ArrayList<Binding>();
+ DEFAULT_BINDINGS.add(newGenericTypeBinding());
+ DEFAULT_BINDINGS.add(newGenericFieldBinding());
+ DEFAULT_BINDINGS.add(newGenericMethodBinding());
+ DEFAULT_BINDINGS.add(newGenericParameterBinding());
+ DEFAULT_BINDINGS = Collections.unmodifiableList(DEFAULT_BINDINGS);
+ }
+
+ private static Binding newGenericTypeBinding() {
+ Binding binding = new Binding();
+ // ElementType is TYPE
+ // Annotation descriptor is matching generic pattern
+ binding.setPredicate(
+ and(
+ on(ElementType.TYPE),
+ customAnnotationPattern()
+ ));
+ binding.setFactory(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Element element = Elements.buildElement(context.getAnnotationType());
+ return new TypeGenericVisitor(context.getWorkbench(), element);
+ }
+ });
+ return binding;
+ }
+
+ private static Predicate customAnnotationPattern() {
+ return pattern("(.*\\.ipojo\\..*)|(.*\\.handler\\..*)").matches();
+ }
+
+ private static Binding newGenericFieldBinding() {
+ Binding binding = new Binding();
+ // ElementType is FIELD
+ // Annotation descriptor is matching generic pattern
+ binding.setPredicate(
+ and(
+ on(ElementType.FIELD),
+ customAnnotationPattern()
+ ));
+ binding.setFactory(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Element element = Elements.buildElement(context.getAnnotationType());
+ return new FieldGenericVisitor(context.getWorkbench(), element, (FieldNode) context.getNode());
+ }
+ });
+ return binding;
+ }
+
+ private static Binding newGenericMethodBinding() {
+ Binding binding = new Binding();
+ // ElementType is METHOD
+ // Annotation descriptor is matching generic pattern
+ binding.setPredicate(
+ and(
+ on(ElementType.METHOD),
+ customAnnotationPattern()
+ ));
+ binding.setFactory(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Element element = Elements.buildElement(context.getAnnotationType());
+ return new MethodGenericVisitor(context.getWorkbench(), element, (MethodNode) context.getNode());
+ }
+ });
+ return binding;
+ }
+
+ private static Binding newGenericParameterBinding() {
+ Binding binding = new Binding();
+ // ElementType is METHOD
+ // Annotation descriptor is matching generic pattern
+ binding.setPredicate(
+ and(
+ on(ElementType.PARAMETER),
+ customAnnotationPattern()
+ ));
+ binding.setFactory(new AnnotationVisitorFactory() {
+ public AnnotationVisitor newAnnotationVisitor(BindingContext context) {
+ Element element = Elements.buildElement(context.getAnnotationType());
+ return new ParameterGenericVisitor(context.getWorkbench(), element, (MethodNode) context.getNode(), context.getParameterIndex());
+ }
+ });
+ return binding;
+ }
+
+
+ public static BindingRegistry newBindingRegistry(Reporter reporter) {
+
+ BindingRegistry registry = new BindingRegistry(reporter);
+ ServiceLoader<Module> loader = ServiceLoader.load(Module.class, classloader());
+
+ // Build each Module and add its contributed Bindings in the registry
+ for (Module module : loader) {
+ module.configure();
+ registry.addBindings(module);
+ }
+
+ // Do not forget the default Bindings
+ registry.getDefaultBindings().addAll(DEFAULT_BINDINGS);
+
+ return registry;
+ }
+
+ public static List<Binding> getDefaultBindings() {
+ return DEFAULT_BINDINGS;
+ }
+
+ private static ClassLoader classloader() {
+ return Bindings.class.getClassLoader();
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java
new file mode 100644
index 0000000..28439b6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Elements.java
@@ -0,0 +1,61 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.util;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.Type;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Elements {
+
+ /**
+ * Build the {@link Element} object from the given descriptor.
+ * It splits the annotation's classname in 2 parts (up to the last '.')
+ * first part (package's name) becomes the Element's namespace, and second
+ * part (class simple name) becomes the Element's name.
+ * @param type annotation descriptor
+ * @return the new element
+ */
+ public static Element buildElement(Type type) {
+ String name = type.getClassName();
+ int index = name.lastIndexOf('.');
+ String local = name.substring(index + 1);
+ String namespace = name.substring(0, index);
+ return new Element(local, namespace);
+ }
+
+ /**
+ * Return the Element named {@literal properties}, creates one if missing.
+ * @param workbench source for search
+ * @return the {@literal properties} Element (never null).
+ */
+ public static Element getPropertiesElement(ComponentWorkbench workbench) {
+ Element properties = workbench.getIds().get("properties");
+ if (properties == null) {
+ properties = new Element("properties", "");
+ workbench.getIds().put("properties", properties);
+ workbench.getElements().put(properties, null);
+ }
+ return properties;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java
new file mode 100644
index 0000000..390ee43
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/util/Names.java
@@ -0,0 +1,89 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor.util;
+
+import org.apache.felix.ipojo.manipulation.MethodCreator;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Names {
+
+ /**
+ * Computes the real method name. This method is useful when the annotation is collected on an manipulated method
+ * (prefixed by <code>__M_</code>). This method just removes the prefix if found.
+ * @param name the collected method name
+ * @return the effective method name, can be the collected method name if the method name does not start with
+ * the prefix.
+ */
+ public static String computeEffectiveMethodName(String name) {
+ if (name != null && name.startsWith(MethodCreator.PREFIX)) {
+ return name.substring(MethodCreator.PREFIX.length());
+ } else {
+ return name;
+ }
+ }
+
+ /**
+ * Extract an identifier from the given method name.
+ * It removes some pre-defined prefixes ({@literal bind}, {@literal unbind},
+ * {@literal set}, {@literal unset}, {@literal modified}).
+ * @param method method's name
+ * @return the method's identifier
+ */
+ public static String getMethodIdentifier(final String method) {
+
+ String effectiveName = computeEffectiveMethodName(method);
+
+ if (effectiveName.startsWith("bind")) {
+ return effectiveName.substring("bind".length());
+ }
+
+ if (effectiveName.startsWith("set")) {
+ return effectiveName.substring("set".length());
+ }
+
+ if (effectiveName.startsWith("unbind")) {
+ return effectiveName.substring("unbind".length());
+ }
+
+ if (effectiveName.startsWith("unset")) {
+ return effectiveName.substring("unset".length());
+ }
+
+ if (effectiveName.startsWith("modified")) {
+ return effectiveName.substring("modified".length());
+ }
+
+ return null;
+
+ }
+
+ /**
+ * Check if the given annotation descriptor is an iPOJO custom annotation.
+ * A valid iPOJO custom annotation must contains 'ipojo' or 'handler' in its qualified name.
+ * @param desc annotation descriptor
+ * @return {@literal true} if the given descriptor is an iPOJO custom annotation
+ */
+ public static boolean isCustomAnnotation(final String desc) {
+ String lowerCase = desc.toLowerCase();
+ return lowerCase.contains("ipojo") || lowerCase.contains("handler");
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java
new file mode 100644
index 0000000..d4317be
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModule.java
@@ -0,0 +1,148 @@
+/*
+ * 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.felix.ipojo.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.alwaysTrue;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.onlySupportedElements;
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.or;
+
+/**
+ * All provided {@link Module}s have to inherit from this class.
+ * It provides a simple to use DSL to express annotation bindings.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbsBindingModule implements Module {
+
+ /**
+ * Build dindings.
+ */
+ private List<Binding> bindings = new ArrayList<Binding>();
+
+ public Iterator<Binding> iterator() {
+ return bindings.iterator();
+ }
+
+ /**
+ * Initiate an annotation binding.
+ * Examples:
+ * <pre>
+ * AnnotationVisitorFactory factory = new CompositeVisitorFactory();
+ * bind(Composite.class).to(factory);
+ * bind(Composite.class).when(.. some condition ..)
+ * .to(factory);
+ * </pre>
+ * @param annotationType the annotation that will be bound to the {@link AnnotationVisitorFactory}
+ */
+ protected AnnotationBindingBuilder bind(Class<? extends Annotation> annotationType) {
+ return new AnnotationBindingBuilder(bindings, annotationType);
+ }
+
+ /**
+ * DSL helper class.
+ */
+ public class AnnotationBindingBuilder {
+ private Class<? extends Annotation> annotationType;
+ private AnnotationVisitorFactory factory;
+ private List<Binding> registry;
+
+ public AnnotationBindingBuilder(List<Binding> registry,
+ Class<? extends Annotation> annotationType) {
+ this.registry = registry;
+ this.annotationType = annotationType;
+ }
+
+ /**
+ * Declares a {@link Predicate} that will add a condition to the annotation binding.
+ * @see org.apache.felix.ipojo.manipulator.spi.helper.Predicates
+ * @param predicate the predicate to use
+ */
+ public ConditionalBindingBuilder when(Predicate predicate) {
+ return new ConditionalBindingBuilder(this, predicate);
+ }
+
+ /**
+ * Complete the annotation binding with the {@link AnnotationVisitorFactory} to be executed
+ * when the annotation is found.
+ * @param factory to be executed when the annotation is found.
+ */
+ public void to(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ registry.add(build());
+ }
+
+ /**
+ * Creates the Binding.
+ */
+ private Binding build() {
+ Binding binding = new Binding();
+ binding.setAnnotationType(annotationType);
+ binding.setPredicate(onlySupportedElements(annotationType));
+ binding.setFactory(factory);
+ return binding;
+ }
+
+ }
+
+ public class ConditionalBindingBuilder {
+ private AnnotationBindingBuilder parent;
+ private Predicate predicate;
+ private AnnotationVisitorFactory factory;
+
+ public ConditionalBindingBuilder(AnnotationBindingBuilder parent, Predicate predicate) {
+ this.parent = parent;
+ this.predicate = predicate;
+ }
+
+ /**
+ * Complete the annotation binding with the {@link AnnotationVisitorFactory} to be executed
+ * when the annotation is found.
+ * @param factory to be executed when the annotation is found.
+ */
+ public AnnotationBindingBuilder to(AnnotationVisitorFactory factory) {
+ this.factory = factory;
+ bindings.add(build());
+
+ return parent;
+ }
+
+ /**
+ * Creates the Binding.
+ */
+ private Binding build() {
+ Binding binding = parent.build();
+ binding.setPredicate(predicate);
+ binding.setFactory(factory);
+ return binding;
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java
new file mode 100644
index 0000000..b29d3cc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/AnnotationVisitorFactory.java
@@ -0,0 +1,34 @@
+/*
+ * 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.felix.ipojo.manipulator.spi;
+
+import org.objectweb.asm.AnnotationVisitor;
+
+/**
+ * Produces a new {@link AnnotationVisitor} instance for the given {@link BindingContext}.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface AnnotationVisitorFactory {
+
+ /**
+ * May return {@literal null} if no visitor can be created.
+ */
+ AnnotationVisitor newAnnotationVisitor(BindingContext context);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java
new file mode 100644
index 0000000..14129bf
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/BindingContext.java
@@ -0,0 +1,81 @@
+/*
+ * 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.felix.ipojo.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.MemberNode;
+
+import java.lang.annotation.ElementType;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BindingContext {
+
+ /**
+ *
+ */
+ private ComponentWorkbench workbench;
+ private MemberNode node;
+ private ElementType elementType;
+ private int parameterIndex;
+ private Reporter reporter;
+ private Type annotationType;
+
+ public BindingContext(final ComponentWorkbench workbench,
+ final Reporter reporter,
+ final Type annotationType,
+ final MemberNode node,
+ final ElementType elementType,
+ final int parameterIndex) {
+ this.workbench = workbench;
+ this.reporter = reporter;
+ this.annotationType = annotationType;
+ this.node = node;
+ this.elementType = elementType;
+ this.parameterIndex = parameterIndex;
+ }
+
+ public ComponentWorkbench getWorkbench() {
+ return workbench;
+ }
+
+ public MemberNode getNode() {
+ return node;
+ }
+
+ public ElementType getElementType() {
+ return elementType;
+ }
+
+ public int getParameterIndex() {
+ return parameterIndex;
+ }
+
+ public Reporter getReporter() {
+ return reporter;
+ }
+
+ public Type getAnnotationType() {
+ return annotationType;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java
new file mode 100644
index 0000000..e5f4b5c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Module.java
@@ -0,0 +1,36 @@
+/*
+ * 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.felix.ipojo.manipulator.spi;
+
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+
+/**
+ * A Module is the contributions from third party to the iPOJO manipulation process.
+ * It is dedicated to Annotation binding support (executing a given ASM AnnotationVisitor
+ * when a particular annotation is found).
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Module extends Iterable<Binding> {
+
+ /**
+ * Configure the bindings provided by this module.
+ */
+ void configure();
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java
new file mode 100644
index 0000000..cee734b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/Predicate.java
@@ -0,0 +1,39 @@
+/*
+ * 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.felix.ipojo.manipulator.spi;
+
+/**
+ * A Predicate is executed with a given {@link BindingContext} and returns {@literal true} if the
+ * {@link #matches(BindingContext)} operation is a success. It returns {@literal false} otherwise.
+ * Predicates can be used to determine if the traversed element (can be found on {@link BindingContext})
+ * matches some properties.
+ *
+ * @see org.apache.felix.ipojo.manipulator.spi.helper.Predicates
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Predicate {
+
+ /**
+ * Returns {@literal true} if the context is matching the predicate.
+ * @param context Binding information source
+ * @return {@literal true} if the context is matching the predicate, {@literal false} otherwise.
+ */
+ boolean matches(BindingContext context);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java
new file mode 100644
index 0000000..ddc4022
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/spi/helper/Predicates.java
@@ -0,0 +1,224 @@
+/*
+ * 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.felix.ipojo.manipulator.spi.helper;
+
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.regex.Pattern;
+
+/**
+ * Ready-to-use {@link Predicate} implementations.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Predicates {
+ public static Node node() {
+ return new Node();
+ }
+
+ public static Reference reference(String refId) {
+ return new Reference(refId);
+ }
+
+ public static Matcher pattern(String regex) {
+ return new Matcher(regex);
+ }
+
+ /**
+ * Restrict to the given {@link ElementType}.
+ * @param type expected {@link ElementType}
+ */
+ public static Predicate on(final ElementType type) {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return context.getElementType().equals(type);
+ }
+ };
+ }
+
+ /**
+ * Always return {@literal true}.
+ */
+ public static Predicate alwaysTrue() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Successful if all given predicates are satisfied.
+ * @param predicates predicates to be satisfied
+ */
+ public static Predicate and(final Predicate... predicates) {
+
+ // Optimization
+ if (predicates.length == 1) {
+ return predicates[0];
+ }
+
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+
+ for (Predicate predicate : predicates) {
+ // Quit with first failure
+ if (!predicate.matches(context)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ }
+
+ /**
+ * Successful if at least one of the given predicates is satisfied.
+ * @param predicates predicates to be satisfied (at least one)
+ */
+ public static Predicate or(final Collection<Predicate> predicates) {
+
+ // Optimization
+ if (predicates.size() == 1) {
+ return predicates.iterator().next();
+ }
+
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+
+ for (Predicate predicate : predicates) {
+ // Quit with first success
+ if (predicate.matches(context)) {
+ return true;
+ }
+ }
+ // No predicate were matching
+ return false;
+ }
+ };
+ }
+
+ /**
+ * Successful if at least one of the given predicates is satisfied.
+ * @param predicates predicates to be satisfied (at least one)
+ */
+ public static Predicate or(final Predicate... predicates) {
+ return or(Arrays.asList(predicates));
+ }
+
+ /**
+ * Restrict to the supported {@link ElementType}(s) of the annotation (use the @Target, if provided).
+ * @param annotationType annotation to explore
+ */
+ public static Predicate onlySupportedElements(final Class<? extends Annotation> annotationType) {
+ Target target = annotationType.getAnnotation(Target.class);
+ if (target == null) {
+ return alwaysTrue();
+ }
+
+ Collection<Predicate> supportedTypes = new HashSet<Predicate>();
+ for (ElementType type : target.value()) {
+ supportedTypes.add(on(type));
+ }
+
+ return or(supportedTypes);
+ }
+
+ public static class Reference {
+
+ private String refId;
+
+ public Reference(String refId) {
+ this.refId = refId;
+ }
+
+ /**
+ * Restrict execution if the {@link org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench}
+ * contains the given reference's name.
+ */
+ public Predicate exists() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return context.getWorkbench().getIds().containsKey(refId);
+ }
+ };
+ }
+ }
+
+ public static class Matcher {
+
+ private Pattern pattern;
+
+ public Matcher(String regex) {
+ pattern = Pattern.compile(regex);
+ }
+
+ /**
+ * Restrict execution if the annotation's classname matches the given pattern.
+ */
+ public Predicate matches() {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ return pattern.matcher(context.getAnnotationType().getClassName()).matches();
+ }
+ };
+ }
+ }
+
+ public static class Node {
+ /**
+ * Restrict execution if the supported {@literal Node} has the given name.
+ */
+ public Predicate named(final String expected) {
+ return new Predicate() {
+ public boolean matches(BindingContext context) {
+ if (context.getNode() instanceof FieldNode) {
+ FieldNode field = (FieldNode) context.getNode();
+ return field.name.equals(expected);
+ }
+
+ if (context.getNode() instanceof MethodNode) {
+ MethodNode method = (MethodNode) context.getNode();
+ return method.name.equals(expected);
+ }
+
+ if (context.getNode() instanceof ClassNode) {
+ ClassNode clazz = (ClassNode) context.getNode();
+ return clazz.name.equals(expected);
+ }
+
+ // Parameters have no name in bytecode
+
+ return false;
+ }
+ };
+ }
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module b/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
new file mode 100644
index 0000000..d3b15f9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/META-INF/services/org.apache.felix.ipojo.manipulator.spi.Module
@@ -0,0 +1 @@
+org.apache.felix.ipojo.manipulator.metadata.annotation.module.DefaultBindingModule
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java
new file mode 100644
index 0000000..b8afe16
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/ComponentWorkbenchTestCase.java
@@ -0,0 +1,90 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.ClassNode;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/12/12
+ * Time: 11:17 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ComponentWorkbenchTestCase extends TestCase {
+ public void testBuildWithNoTopLevelElements() throws Exception {
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ Element built = workbench.build();
+ assertNull(built);
+
+ }
+
+ public void testSimpleBuild() throws Exception {
+
+ Element root = new Element("root", null);
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ workbench.setRoot(root);
+ Element built = workbench.build();
+
+ assertEquals("root", built.getName());
+ assertNull(built.getNameSpace());
+ assertEquals(0, built.getAttributes().length);
+ assertEquals(0, built.getElements().length);
+
+ }
+
+ public void testElementsAreHierarchicallyPlaced() throws Exception {
+
+ Element root = new Element("root", null);
+ Element child = new Element("child", null);
+
+ ComponentWorkbench workbench = new ComponentWorkbench(null, node());
+ workbench.setRoot(root);
+ workbench.getElements().put(child, null);
+
+ Element built = workbench.build();
+
+ assertEquals("root", built.getName());
+ assertNull(built.getNameSpace());
+ assertEquals(0, built.getAttributes().length);
+ assertEquals(1, built.getElements().length);
+
+ Element builtChild = built.getElements("child")[0];
+
+ assertEquals("child", builtChild.getName());
+ assertNull(builtChild.getNameSpace());
+ assertEquals(0, builtChild.getAttributes().length);
+ assertEquals(0, builtChild.getElements().length);
+
+
+ }
+
+
+ private static ClassNode node() {
+ ClassNode node = new ClassNode();
+ node.name = "my/Component";
+ return node;
+ }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistryTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistryTestCase.java
new file mode 100644
index 0000000..7c1bbf4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/BindingRegistryTestCase.java
@@ -0,0 +1,82 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.registry;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.Predicate;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.Type;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/11/12
+ * Time: 10:31 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class BindingRegistryTestCase extends TestCase {
+
+ private BindingRegistry registry;
+
+ @Mock
+ private Reporter reporter;
+ @Mock
+ private AnnotationVisitorFactory factory;
+ @Mock
+ private Predicate predicate;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ registry = new BindingRegistry(reporter);
+ }
+
+ public void testBindingAddition() throws Exception {
+ registry.addBindings(Collections.singletonList(binding()));
+
+ List<Binding> predicates = registry.getBindings(Type.getType(Provides.class).getDescriptor());
+
+ assertEquals(1, predicates.size());
+ Binding found = predicates.get(0);
+ assertNotNull(found);
+ assertEquals(predicate, found.getPredicate());
+ assertEquals(factory, found.getFactory());
+ }
+
+ public void testGetBindingsWhenEmpty() throws Exception {
+ assertNull(registry.getBindings(Type.getType(Provides.class).getDescriptor()));
+ assertNotNull(registry.selection(null));
+ }
+
+ private Binding binding() {
+ Binding binding = new Binding();
+ binding.setAnnotationType(Provides.class);
+ binding.setFactory(factory);
+ binding.setPredicate(predicate);
+ return binding;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java
new file mode 100644
index 0000000..5055ed0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/registry/SelectionTestCase.java
@@ -0,0 +1,252 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.registry;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.FieldGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.MethodGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.ParameterGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.generic.TypeGenericVisitor;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.visitor.util.Bindings;
+import org.apache.felix.ipojo.manipulator.spi.AbsBindingModule;
+import org.apache.felix.ipojo.manipulator.spi.AnnotationVisitorFactory;
+import org.apache.felix.ipojo.manipulator.spi.BindingContext;
+import org.hamcrest.Matcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.when;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/11/12
+ * Time: 10:49 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class SelectionTestCase extends TestCase {
+ private BindingRegistry registry;
+
+ @Mock
+ private Reporter reporter;
+ @Mock
+ private AnnotationVisitorFactory factory;
+ @Mock
+ private AnnotationVisitor visitor;
+
+ @Override
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ registry = new BindingRegistry(reporter);
+ when(factory.newAnnotationVisitor(any(BindingContext.class)))
+ .thenReturn(visitor);
+ }
+
+ public void testSelectionOnClassNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnTypeOnly.class);
+ module.configure();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnTypeOnly.class, equalTo(visitor));
+ assertFieldSelection(OnTypeOnly.class, nullValue());
+ assertMethodSelection(OnTypeOnly.class, nullValue());
+ assertParameterSelection(OnTypeOnly.class, nullValue());
+ }
+
+ public void testSelectionOnFieldNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnFieldOnly.class);
+ module.configure();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnFieldOnly.class, nullValue());
+ assertFieldSelection(OnFieldOnly.class, equalTo(visitor));
+ assertMethodSelection(OnFieldOnly.class, nullValue());
+ assertParameterSelection(OnFieldOnly.class, nullValue());
+
+ }
+
+ public void testSelectionOnMethodNodeOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnMethodOnly.class);
+ module.configure();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnMethodOnly.class, nullValue());
+ assertFieldSelection(OnMethodOnly.class, nullValue());
+ assertMethodSelection(OnMethodOnly.class, equalTo(visitor));
+ assertParameterSelection(OnMethodOnly.class, nullValue());
+
+ }
+
+ public void testSelectionOnMethodParameterOnly() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnParameterOnly.class);
+ module.configure();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnParameterOnly.class, nullValue());
+ assertFieldSelection(OnParameterOnly.class, nullValue());
+ assertMethodSelection(OnParameterOnly.class, nullValue());
+ assertParameterSelection(OnParameterOnly.class, equalTo(visitor));
+
+ }
+
+ public void testSelectionOBothMethodAndParameter() throws Exception {
+
+ AbsBindingModule module = new MonoBindingModule(OnBothMethodAndParameter.class);
+ module.configure();
+ registry.addBindings(module);
+
+ // Verifications
+ assertClassSelection(OnBothMethodAndParameter.class, nullValue());
+ assertFieldSelection(OnBothMethodAndParameter.class, nullValue());
+ assertMethodSelection(OnBothMethodAndParameter.class, equalTo(visitor));
+ assertParameterSelection(OnBothMethodAndParameter.class, equalTo(visitor));
+
+ }
+
+ public void testSelectionForGenericVisitors() throws Exception {
+
+ assertClassSelection(OnTypeOnly.class, nullValue());
+ assertFieldSelection(OnFieldOnly.class, nullValue());
+ assertMethodSelection(OnMethodOnly.class, nullValue());
+ assertParameterSelection(OnParameterOnly.class, nullValue());
+
+ registry.getDefaultBindings().addAll(Bindings.getDefaultBindings());
+
+ // Verifications
+ assertClassSelection(OnTypeOnly.class, instanceOf(TypeGenericVisitor.class));
+ assertFieldSelection(OnFieldOnly.class, instanceOf(FieldGenericVisitor.class));
+ assertMethodSelection(OnMethodOnly.class, instanceOf(MethodGenericVisitor.class));
+ assertParameterSelection(OnParameterOnly.class, instanceOf(ParameterGenericVisitor.class));
+
+ }
+
+ private void assertClassSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.type(classNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertFieldSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.field(fieldNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertMethodSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.method(methodNode());
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private void assertParameterSelection(Class<? extends Annotation> type, Matcher matcher) {
+ Selection selection = new Selection(registry, null, reporter);
+ selection.parameter(methodNode(), 0);
+ selection.annotatedWith(descriptor(type));
+
+ assertTrue(matcher.matches(selection.get()));
+ }
+
+ private MethodNode methodNode() {
+ return new MethodNode(0, "method", "(java/lang/String)V", null, null);
+ }
+
+ private ClassNode classNode() {
+ ClassNode node = new ClassNode();
+ node.visit(0, 0, "my/Component", null, "java/lang/Object", null);
+ return node;
+ }
+
+ public void testSelectionWithEmptyRegistry() throws Exception {
+ Selection selection = new Selection(registry, null, reporter);
+
+ selection.field(fieldNode())
+ .annotatedWith(descriptor(OnTypeOnly.class));
+
+ assertNull(selection.get());
+ }
+
+ private String descriptor(Class<? extends Annotation> type) {
+ return Type.getType(type).getDescriptor();
+ }
+
+ private FieldNode fieldNode() {
+ return new FieldNode(0,
+ "field",
+ Type.getType(Object.class).getDescriptor(),
+ null,
+ null);
+ }
+
+ @Target(ElementType.TYPE)
+ private @interface OnTypeOnly {}
+
+ @Target(ElementType.FIELD)
+ private @interface OnFieldOnly {}
+
+ @Target(ElementType.METHOD)
+ private @interface OnMethodOnly {}
+
+ @Target(ElementType.PARAMETER)
+ private @interface OnParameterOnly {}
+
+ @Target({ElementType.PARAMETER, ElementType.METHOD})
+ private @interface OnBothMethodAndParameter {}
+
+
+ private class MonoBindingModule extends AbsBindingModule {
+ private Class<? extends Annotation> type;
+
+ public MonoBindingModule(Class<? extends Annotation> aClass) {
+ this.type = aClass;
+ }
+
+ public void configure() {
+ bind(type).to(factory);
+ }
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java
new file mode 100644
index 0000000..c3f5914
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/ComponentVisitorTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * 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.felix.ipojo.manipulator.metadata.annotation.visitor;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.ComponentWorkbench;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.tree.ClassNode;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/10/12
+ * Time: 5:46 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ComponentVisitorTestCase extends TestCase {
+
+ public void testDefaultNameIsClassname() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("my.Component", root.getAttribute("name"));
+ }
+
+ public void testNameAttribute() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("name", "changed");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("changed", root.getAttribute("name"));
+ }
+
+ public void testPublicFactoryDeprecationSupport() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("public_factory", "false");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("false", root.getAttribute("public"));
+ }
+
+ public void testFactoryMethodDeprecationSupport() throws Exception {
+ Reporter reporter = mock(Reporter.class);
+ ComponentWorkbench workbench = new ComponentWorkbench(null, clazz());
+ ComponentVisitor visitor = new ComponentVisitor(workbench, reporter);
+ visitor.visit("factory_method", "create");
+ visitor.visitEnd();
+
+ Element root = workbench.getRoot();
+ assertNotNull(root);
+ assertEquals("create", root.getAttribute("factory-method"));
+ }
+
+ private ClassNode clazz() {
+ ClassNode node = new ClassNode();
+ node.name = "my/Component";
+ return node;
+ }
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java
new file mode 100644
index 0000000..c1bb23e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/spi/AbsBindingModuleTestCase.java
@@ -0,0 +1,139 @@
+package org.apache.felix.ipojo.manipulator.spi;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.manipulator.metadata.annotation.registry.Binding;
+
+import java.lang.annotation.ElementType;
+import java.util.Iterator;
+
+import static org.apache.felix.ipojo.manipulator.spi.helper.Predicates.on;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.only;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/10/12
+ * Time: 10:37 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class AbsBindingModuleTestCase extends TestCase {
+
+ public void testSimpleBinding() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(Provides.class, one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Only 1 Binding
+ assertFalse(i.hasNext());
+ }
+
+ public void testTwoBindings() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ bind(Requires.class).to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(Provides.class, one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(Requires.class, two.getAnnotationType());
+ assertEquals(factory, two.getFactory());
+ }
+
+ public void testTwoBindingsForSameAnnotation() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ final AnnotationVisitorFactory factory2 = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class).to(factory);
+ bind(Provides.class).to(factory2);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(Provides.class, one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(Provides.class, two.getAnnotationType());
+ assertEquals(factory2, two.getFactory());
+ }
+
+ public void testConditionalBinding() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class)
+ .when(on(ElementType.FIELD))
+ .to(factory);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(Provides.class, one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Only 1 Binding
+ assertFalse(i.hasNext());
+ }
+
+ public void testConditionalBindings() throws Exception {
+ final AnnotationVisitorFactory factory = mock(AnnotationVisitorFactory.class);
+ final AnnotationVisitorFactory factory2 = mock(AnnotationVisitorFactory.class);
+ AbsBindingModule module = new AbsBindingModule() {
+ public void configure() {
+ bind(Provides.class)
+ .when(on(ElementType.FIELD))
+ .to(factory)
+ .when(on(ElementType.PARAMETER))
+ .to(factory2);
+ }
+ };
+ module.configure();
+
+ Iterator<Binding> i = module.iterator();
+ Binding one = i.next();
+ assertNotNull(one);
+ assertEquals(Provides.class, one.getAnnotationType());
+ assertEquals(factory, one.getFactory());
+
+ // Second Binding
+ Binding two = i.next();
+ assertNotNull(two);
+ assertEquals(Provides.class, two.getAnnotationType());
+ assertEquals(factory2, two.getFactory());
+ }
+
+
+}