Mixed part of patch (FELIX-270)...I needed to do an "svn add".
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@530141 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java
new file mode 100644
index 0000000..bb461e0
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionException.java
@@ -0,0 +1,55 @@
+/*
+ * 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.composite.service.provides;
+
+/**
+ * Exception throwed when a composition error occurs.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class CompositionException extends Exception {
+
+ /**
+ * serialVersionUID.
+ */
+ private static final long serialVersionUID = -3063353267573738105L;
+
+ /**
+ * Message.
+ */
+ private String m_message;
+
+ /**
+ * Constructor.
+ * @param message : a message.
+ */
+ public CompositionException(String message) {
+ m_message = message;
+ }
+
+ /**
+ * Get the excepttion message.
+ * @return the message.
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ return m_message;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java
new file mode 100644
index 0000000..abfe1c9
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/CompositionMetadata.java
@@ -0,0 +1,321 @@
+/*
+ * 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.composite.service.provides;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.ipojo.composite.service.provides.manipulation.Manipulator;
+import org.apache.felix.ipojo.composite.service.provides.manipulation.POJOWriter;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.util.Logger;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Check and build a compostion, i.e. a pojo containing the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class CompositionMetadata {
+
+ /**
+ * Implemented composition.
+ */
+ private SpecificationMetadata m_specification;
+
+ /**
+ * Name of the composition.
+ */
+ private String m_name;
+
+ /**
+ * Bundle Context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Manipulated field of the build Pojo.
+ */
+ private HashMap m_manipulatedFields = new HashMap();
+
+ /**
+ * Manipulated interface of the build Pojo.
+ */
+ private String[] m_manipulatedInterfaces = new String[0];
+
+ /**
+ * Reference on the handler.
+ */
+ private ProvidedServiceHandler m_handler;
+
+ /**
+ * List of Mappings.
+ */
+ private List m_mappings = new ArrayList();
+
+ /**
+ * Constructor.
+ * @param bc : bundle context
+ * @param description : 'provides' element
+ * @param psh : parent handler
+ * @param name : name of the composition.
+ */
+ public CompositionMetadata(BundleContext bc, Element description, ProvidedServiceHandler psh, String name) {
+ m_context = bc;
+ m_handler = psh;
+ // Get the composition name
+ m_name = description.getAttribute("specification") + name;
+
+ // Get implemented service specification
+ String spec = description.getAttribute("specification");
+ m_specification = new SpecificationMetadata(spec, m_context, false, false, m_handler);
+
+ Element[] mappings = description.getElements("delegation");
+ for (int i = 0; i < mappings.length; i++) {
+ String methodName = mappings[i].getAttribute("method");
+ MethodMetadata method = m_specification.getMethodByName(methodName);
+ if (method == null) {
+ m_handler.getManager().getFactory().getLogger().log(Logger.ERROR, "The method " + methodName + " does not exist in the specicifation " + spec);
+ return;
+ }
+
+ if (mappings[i].getAttribute("policy").equalsIgnoreCase("All")) {
+ method.setAllPolicy();
+ }
+ }
+ }
+
+ protected BundleContext getBundleContext() {
+ return m_context;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public SpecificationMetadata getSpecificationMetadata() {
+ return m_specification;
+ }
+
+ /**
+ * Build Available Mappings.
+ */
+ private void buildAvailableMappingList() {
+ int index = 0;
+
+ for (int i = 0; i < m_handler.getSpecifications().size(); i++) {
+ SpecificationMetadata spec = (SpecificationMetadata) m_handler.getSpecifications().get(i);
+ FieldMetadata field = new FieldMetadata(spec);
+ field.setName("_field" + index);
+ if (spec.isOptional()) {
+ field.setOptional(true);
+ }
+ if (spec.isAggregate()) {
+ field.setAggregate(true);
+ }
+ Mapping map = new Mapping(spec, field);
+ m_mappings.add(map);
+ index++;
+ }
+ }
+
+ /**
+ * Build the delegation mapping.
+ * @throws CompositionException : occurs when the mapping cannot be infers correctly
+ */
+ protected void buildMapping() throws CompositionException {
+ buildAvailableMappingList();
+
+ // Dependency closure is OK, now look for method delegation
+ Map/* <MethodMetadata, Mapping> */availableMethods = new HashMap();
+
+ for (int i = 0; i < m_mappings.size(); i++) {
+ Mapping map = (Mapping) m_mappings.get(i);
+ SpecificationMetadata spec = map.getSpecification();
+ for (int j = 0; j < spec.getMethods().size(); j++) {
+ MethodMetadata method = (MethodMetadata) spec.getMethods().get(j);
+ availableMethods.put(method, map);
+ }
+ }
+
+ // For each needed method search if available and store the mapping
+ for (int j = 0; j < m_specification.getMethods().size(); j++) {
+ MethodMetadata method = (MethodMetadata) m_specification.getMethods().get(j);
+ Set keys = availableMethods.keySet();
+ Iterator it = keys.iterator();
+ boolean found = false;
+ while (it.hasNext() & !found) {
+ MethodMetadata met = (MethodMetadata) it.next();
+ if (met.equals(method)) {
+ found = true;
+ FieldMetadata field = ((Mapping) availableMethods.get(met)).getField();
+ field.setUseful(true);
+ method.setDelegation(field);
+ // Test optionality
+ if (field.isOptional() && !method.getExceptions().contains("java/lang/UnsupportedOperationException")) {
+ m_handler.getManager().getFactory().getLogger().log(Logger.WARNING, "The method " + method.getMethodName() + " could not be provided correctly : the specification " + field.getSpecification().getName() + " is optional");
+ }
+ }
+ }
+ if (!found) {
+ throw new CompositionException("Composition non consistent : " + method.getMethodName() + " could not be delegated");
+ }
+ }
+ }
+
+ /**
+ * Build a service implementation.
+ * @return the byte[] of the POJO.
+ */
+ protected byte[] buildPOJO() {
+ String resource = m_specification.getName().replace('.', '/') + ".class";
+ URL url = getBundleContext().getBundle().getResource(resource);
+ byte[] pojo = POJOWriter.dump(url, m_specification.getName(), m_name, getFieldList(), getMethodList());
+ Manipulator m = new Manipulator();
+ try {
+ byte[] ff = m.process(pojo);
+ m_manipulatedFields = m.getFields();
+ m_manipulatedInterfaces = m.getInterfaces();
+ return ff;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Build service implementation metadata.
+ * @return Component Type metadata.
+ */
+ protected Element buildMetadata() {
+ Element elem = new Element("component", "");
+ Attribute className = new Attribute("className", m_name);
+ Attribute factory = new Attribute("factory", "no");
+ elem.addAttribute(className);
+ elem.addAttribute(factory);
+
+ // Provides
+ Element provides = new Element("provides", "");
+ provides.addAttribute(new Attribute("specification", m_specification.getName()));
+ elem.addElement(provides);
+
+ // Dependencies
+ List fields = getFieldList();
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful()) {
+ Element dep = new Element("Dependency", "");
+ dep.addAttribute(new Attribute("field", field.getName()));
+ if (field.getSpecification().isOptional()) {
+ dep.addAttribute(new Attribute("optional", "true"));
+ }
+ elem.addElement(dep);
+ }
+ }
+
+ // Insert information to metadata
+ Element manip = new Element("Manipulation", "");
+ for (int j = 0; j < m_manipulatedInterfaces.length; j++) {
+ // Create an interface element for each implemented interface
+ Element itf = new Element("Interface", "");
+ Attribute att = new Attribute("name", m_manipulatedInterfaces[j]);
+ itf.addAttribute(att);
+ manip.addElement(itf);
+ }
+
+ Iterator it = m_manipulatedFields.keySet().iterator();
+ while (it.hasNext()) {
+ Element field = new Element("Field", "");
+ String name = (String) it.next();
+ String type = (String) m_manipulatedFields.get(name);
+ Attribute attName = new Attribute("name", name);
+ Attribute attType = new Attribute("type", type);
+ field.addAttribute(attName);
+ field.addAttribute(attType);
+ manip.addElement(field);
+ }
+
+ elem.addElement(manip);
+
+ return elem;
+ }
+
+ /**
+ * Get the field list to use for the delegation.
+ * @return the field list.
+ */
+ private List getFieldList() {
+ List list = new ArrayList();
+ for (int i = 0; i < m_mappings.size(); i++) {
+ Mapping map = (Mapping) m_mappings.get(i);
+ list.add(map.getField());
+ }
+ return list;
+ }
+
+ /**
+ * Get the method lsit contained in the implemented specification.
+ * @return the List of implemented method.
+ */
+ private List getMethodList() {
+ return m_specification.getMethods();
+ }
+
+ /**
+ * Store links between Field and pointed Specification.
+ */
+ private class Mapping {
+
+ /**
+ * Specification.
+ */
+ private SpecificationMetadata m_spec;
+
+ /**
+ * Field.
+ */
+ private FieldMetadata m_field;
+
+ /**
+ * Constructor.
+ * @param spec : specification metadata.
+ * @param field : the field.
+ */
+ public Mapping(SpecificationMetadata spec, FieldMetadata field) {
+ m_spec = spec;
+ m_field = field;
+ }
+
+ public SpecificationMetadata getSpecification() {
+ return m_spec;
+ }
+
+ public FieldMetadata getField() {
+ return m_field;
+ }
+
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java
new file mode 100644
index 0000000..cb5c7cd
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/FieldMetadata.java
@@ -0,0 +1,105 @@
+/*
+ * 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.composite.service.provides;
+
+/**
+ * Field used inside a composition.
+ * This class contains all information useful for the generation.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class FieldMetadata {
+
+ /**
+ * Name of the field.
+ */
+ private String m_name;
+
+ /**
+ * Is the field an array?
+ */
+ private boolean m_isAggregate = false;
+
+ /**
+ * Interface of the field.
+ */
+ private SpecificationMetadata m_specification;
+
+ /**
+ * Is the field useful in this composition.
+ */
+ private boolean m_isUseful;
+
+ /**
+ * Is the dependency for this field optional.
+ */
+ private boolean m_isOptional = false;
+
+ /**
+ * Constructor.
+ * @param specification : interface of the field.
+ */
+ public FieldMetadata(SpecificationMetadata specification) {
+ super();
+ this.m_specification = specification;
+ if (m_specification.isAggregate()) {
+ m_isAggregate = true;
+ }
+ }
+
+ public boolean isAggregate() {
+ return m_isAggregate;
+ }
+
+ public void setAggregate(boolean aggregate) {
+ m_isAggregate = aggregate;
+ }
+
+ public String getName() {
+ return m_name;
+ }
+
+ public void setName(String name) {
+ this.m_name = name;
+ }
+
+ public SpecificationMetadata getSpecification() {
+ return m_specification;
+ }
+
+ public void setSpecification(SpecificationMetadata specification) {
+ this.m_specification = specification;
+ }
+
+ public boolean isUseful() {
+ return m_isUseful;
+ }
+
+ public void setUseful(boolean useful) {
+ m_isUseful = useful;
+ }
+
+ public boolean isOptional() {
+ return m_isOptional;
+ }
+
+ public void setOptional(boolean opt) {
+ m_isOptional = opt;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java
new file mode 100644
index 0000000..8591b9b
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/MethodMetadata.java
@@ -0,0 +1,173 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.ArrayList;
+
+import org.apache.felix.ipojo.handlers.dependency.nullable.MethodSignature;
+
+/**
+ * Information on Method for the composition.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class MethodMetadata {
+
+ /**
+ * ONE POLICY.
+ */
+ public static final int ONE_POLICY = 1;
+
+ /**
+ * ALL POLICY.
+ */
+ public static final int ALL_POLICY = 2;
+
+ /**
+ * Method Name.
+ */
+ private String m_methodName;
+
+ /**
+ * Internal Descriptor.
+ */
+ private String m_descriptor;
+
+ /**
+ * List of arguments.
+ */
+ private ArrayList/* <String> */m_arguments = new ArrayList/* <String> */();
+
+ /**
+ * List of exceptions.
+ */
+ private ArrayList/* <String> */m_exceptions = new ArrayList/* <String> */();
+
+ /**
+ * Delegator field.
+ */
+ private FieldMetadata m_delegation;
+
+ /**
+ * Delegation policy (default = ONE).
+ */
+ private int m_policy = ONE_POLICY;
+
+ /**
+ * Constructor.
+ * @param name : name of the method.
+ * @param desc : description of the method.
+ */
+ public MethodMetadata(String name, String desc) {
+ m_methodName = name;
+ m_descriptor = desc;
+ }
+
+ /**
+ * Add an argument.
+ * @param type : type of the argument.
+ */
+ public void addArgument(String type) {
+ m_arguments.add(type);
+ }
+
+ /**
+ * Add an exception.
+ * @param exception : name of the exception.
+ */
+ public void addException(String exception) {
+ m_exceptions.add(exception);
+ }
+
+ public ArrayList/* <String> */getArguments() {
+ return m_arguments;
+ }
+
+ public ArrayList/* <String> */getExceptions() {
+ return m_exceptions;
+ }
+
+ public String getMethodName() {
+ return m_methodName;
+ }
+
+
+
+ public void setDelegation(FieldMetadata dm) {
+ m_delegation = dm;
+ }
+
+ public FieldMetadata getDelegation() {
+ return m_delegation;
+ }
+
+ /**
+ * Check if two method metadata are equals.
+ * @param mm : the method metadata to compare with the current method metadata.
+ * @return true if the two method are equals
+ */
+ public boolean equals(MethodMetadata mm) {
+ // Test if the name are the same, #args and #exception are the same.
+ if (!mm.getMethodName().equals(m_methodName) || mm.getArguments().size() != m_arguments.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < m_arguments.size(); i++) {
+ if (!m_arguments.get(i).equals(mm.getArguments().get(i))) {
+ return false;
+ }
+ }
+
+// for (int i = 0; i < m_exceptions.size(); i++) {
+// if (! mm.getExceptions().contains(m_exceptions.get(i))) { return false; }
+// }
+
+ return true;
+ }
+
+ /**
+ * Equals method for Method Signature.
+ * @param ms : the method signatur to compare.
+ * @return true if the given method signature is equals to the current method metadata.
+ */
+ public boolean equals(MethodSignature ms) {
+ // the method is equals to the method signature if the name and the desc are similar.
+ if (!m_methodName.equals(ms.getName())) {
+ return false;
+ }
+ if (!m_descriptor.equals(ms.getDesc())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int getPolicy() {
+ return m_policy;
+ }
+
+ /**
+ * Activate the all policy for this method.
+ */
+ public void setAllPolicy() {
+ m_policy = ALL_POLICY;
+ }
+
+ public String getDescription() { return m_descriptor; }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java
new file mode 100644
index 0000000..4d7ae97
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedService.java
@@ -0,0 +1,199 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.CompositeManager;
+import org.apache.felix.ipojo.ServiceContext;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+
+/**
+ * Composite Provided Service.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ProvidedService {
+
+ /**
+ * Composite Manager.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * Composition Model.
+ */
+ private CompositionMetadata m_composition;
+
+ /**
+ * generated POJO class.
+ */
+ private byte[] m_clazz;
+
+ /**
+ * Metadata of the POJO.
+ */
+ private Element m_metadata;
+
+ /**
+ * Internal context.
+ */
+ private ServiceContext m_scope;
+
+ /**
+ * External context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * Created Factory.
+ */
+ private ComponentFactory m_factory;
+
+ /**
+ * Created Instance.
+ */
+ private ComponentInstance m_instance;
+
+ /**
+ * Exporter.
+ */
+ private ServiceExporter m_exports;
+
+ /**
+ * Constructor.
+ * The delegation mapping is infers in this method.
+ * @param handler : the handler.
+ * @param element : 'provides' element.
+ * @param name : name of this provided service.
+ */
+ public ProvidedService(ProvidedServiceHandler handler, Element element, String name) {
+ m_manager = handler.getManager();
+ m_scope = m_manager.getServiceContext();
+ m_context = m_manager.getContext();
+ m_composition = new CompositionMetadata(m_manager.getContext(), element, handler, name);
+ try {
+ m_composition.buildMapping();
+ } catch (CompositionException e) {
+ return;
+ }
+ }
+
+ /**
+ * Start method.
+ * Build service implementation type, factory and instance.
+ */
+ public void start() {
+ m_clazz = m_composition.buildPOJO();
+ m_metadata = m_composition.buildMetadata();
+
+ // Create the factory
+ m_factory = new ComponentFactory(m_context, m_clazz, m_metadata);
+ m_factory.start();
+
+ Properties p = new Properties();
+ String name = m_composition.getSpecificationMetadata().getName() + "Provider";
+ p.put("name", name);
+ try {
+ m_instance = m_factory.createComponentInstance(p, m_scope);
+ } catch (UnacceptableConfiguration e) {
+ return;
+ }
+ // Create the exports
+ m_exports = new ServiceExporter(m_composition.getSpecificationMetadata().getName(), "(" + Constants.SERVICE_PID + "=" + name + ")", false, false,
+ m_scope, m_context, this);
+ }
+
+ /**
+ * Stop the provided service.
+ * Kill the exporter, the instance and the factory.
+ */
+ public void stop() {
+ if (m_exports != null) {
+ m_exports.stop();
+ m_exports = null;
+ }
+ if (m_instance != null) {
+ m_instance.dispose();
+ m_instance = null;
+ }
+ if (m_factory != null) {
+ m_factory.stop();
+ m_factory = null;
+ }
+ }
+
+ protected CompositeManager getManager() {
+ return m_manager;
+ }
+
+ /**
+ * The exporter becomes valid.
+ * @param exporter : the exporter
+ */
+ public void validating(ServiceExporter exporter) {
+ }
+
+ /**
+ * The exporter becomes invalid.
+ * @param exporter : the exporter
+ */
+ public void invalidating(ServiceExporter exporter) {
+ }
+
+ /**
+ * Unregister published service.
+ */
+ protected void unregister() {
+ if (m_exports != null) {
+ m_instance.stop();
+ m_exports.stop();
+ }
+ }
+
+ /**
+ * Register published service.
+ */
+ protected void register() {
+ if (m_exports != null) {
+ m_instance.start();
+ m_exports.start();
+ }
+ }
+
+ public String getSpecification() {
+ return m_composition.getSpecificationMetadata().getName();
+ }
+
+ /**
+ * Check the provided service state.
+ * @return true if the exporter is publishing.
+ */
+ public boolean getState() {
+ if (m_exports != null && m_exports.isPublishing()) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java
new file mode 100644
index 0000000..9175f3a
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandler.java
@@ -0,0 +1,192 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.CompositeHandler;
+import org.apache.felix.ipojo.CompositeManager;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Composite Provided Service Handler.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandler extends CompositeHandler {
+
+ /**
+ * Reference on the instance.
+ */
+ private CompositeManager m_manager;
+
+ /**
+ * External context.
+ */
+ private BundleContext m_context;
+
+ /**
+ * List of "available" services in the internal context.
+ */
+ private List m_services = new ArrayList();
+
+ /**
+ * List of managed services.
+ */
+ private ArrayList m_managedServices = new ArrayList();
+
+ /**
+ * Configure the handler.
+ *
+ * @param im : the instance manager
+ * @param metadata : the metadata of the component
+ * @param configuration : the instance configuration
+ * @see org.apache.felix.ipojo.CompositeHandler#configure(org.apache.felix.ipojo.CompositeManager,
+ * org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+ */
+ public void configure(CompositeManager im, Element metadata, Dictionary configuration) {
+ m_manager = im;
+ m_context = im.getContext();
+
+ // Get composition metadata
+ Element[] provides = metadata.getElements("provides", "");
+ if (provides.length == 0) {
+ return;
+ }
+
+ // Compute imports and instances
+ computeAvailableServices(metadata);
+
+ for (int i = 0; i < provides.length; i++) {
+ ProvidedService ps = new ProvidedService(this, provides[i], "" + i);
+ m_managedServices.add(ps);
+ im.getComponentDescription().addProvidedServiceSpecification(ps.getSpecification());
+ }
+
+ im.register(this);
+ }
+
+ /**
+ * Start metod.
+ * Start all managed provided service.
+ * @see org.apache.felix.ipojo.CompositeHandler#start()
+ */
+ public void start() {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService ps = (ProvidedService) m_managedServices.get(i);
+ ps.start();
+ }
+
+ }
+
+ /**
+ * Stop method.
+ * Stop all managedprovided service.
+ * @see org.apache.felix.ipojo.CompositeHandler#stop()
+ */
+ public void stop() {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService ps = (ProvidedService) m_managedServices.get(i);
+ ps.stop();
+ }
+ }
+
+ /**
+ * Handler state changed.
+ * @param state : the new instance state.
+ * @see org.apache.felix.ipojo.CompositeHandler#stateChanged(int)
+ */
+ public void stateChanged(int state) {
+ if (state == ComponentInstance.INVALID) {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService ps = (ProvidedService) m_managedServices.get(i);
+ ps.unregister();
+ }
+ return;
+ }
+
+ // If the new state is VALID => regiter all the services
+ if (state == ComponentInstance.VALID) {
+ for (int i = 0; i < m_managedServices.size(); i++) {
+ ProvidedService ps = (ProvidedService) m_managedServices.get(i);
+ ps.register();
+ }
+ return;
+ }
+ }
+
+ protected CompositeManager getManager() {
+ return m_manager;
+ }
+
+ /**
+ * Build the list of available specification.
+ * @return the list of available specification.
+ */
+ protected List getSpecifications() {
+ return m_services;
+ }
+
+ /**
+ * Build available specification.
+ *
+ * @param metadata : composite metadata
+ */
+ private void computeAvailableServices(Element metadata) {
+ // Get instantiated services :
+ Element[] services = metadata.getElements("service", "");
+ for (int i = 0; i < services.length; i++) {
+ String itf = services[i].getAttribute("specification");
+ boolean agg = false;
+ boolean opt = false;
+ if (services[i].containsAttribute("aggregate") && services[i].getAttribute("aggregate").equalsIgnoreCase("true")) {
+ agg = true;
+ }
+ if (services[i].containsAttribute("optional") && services[i].getAttribute("optional").equalsIgnoreCase("true")) {
+ opt = true;
+ }
+ SpecificationMetadata sm = new SpecificationMetadata(itf, m_context, agg, opt, this);
+ m_services.add(sm);
+ }
+
+ Element[] imports = metadata.getElements("import", "");
+ for (int i = 0; i < imports.length; i++) {
+ String itf = imports[i].getAttribute("specification");
+ boolean agg = false;
+ boolean opt = false;
+ if (imports[i].containsAttribute("aggregate") && imports[i].getAttribute("aggregate").equalsIgnoreCase("true")) {
+ agg = true;
+ }
+ if (imports[i].containsAttribute("optional") && imports[i].getAttribute("optional").equalsIgnoreCase("true")) {
+ opt = true;
+ }
+ SpecificationMetadata sm = new SpecificationMetadata(itf, m_context, agg, opt, this);
+ m_services.add(sm);
+ }
+ }
+
+ public HandlerDescription getDescription() {
+ return new ProvidedServiceHandlerDescription(true, m_managedServices);
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java
new file mode 100644
index 0000000..336ed14
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ProvidedServiceHandlerDescription.java
@@ -0,0 +1,73 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Provided Service Handler Description for composite.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ProvidedServiceHandlerDescription extends HandlerDescription {
+
+ /**
+ * Provided Service Description list.
+ */
+ private List m_providedServices = new ArrayList();
+
+ /**
+ * Constructor.
+ *
+ * @param isValid : the validity of the provided service handler.
+ * @param ps : The list of Provided Service.
+ */
+ public ProvidedServiceHandlerDescription(boolean isValid, List ps) {
+ super(ProvidedServiceHandler.class.getName(), isValid);
+ m_providedServices = ps;
+ }
+
+ /**
+ * Get the handler description.
+ * @return the provided service handler description
+ * @see org.apache.felix.ipojo.architecture.HandlerDescription#getHandlerInfo()
+ */
+ public Element getHandlerInfo() {
+ Element services = super.getHandlerInfo();
+ for (int i = 0; i < m_providedServices.size(); i++) {
+ ProvidedService ps = (ProvidedService) m_providedServices.get(i);
+ Element service = new Element("service", "");
+ String state = "unregistered";
+ if (ps.getState()) {
+ state = "registered";
+ }
+ String spec = "[" + ps.getSpecification() + "]";
+ service.addAttribute(new Attribute("Specification", spec));
+ service.addAttribute(new Attribute("State", state));
+ services.addElement(service);
+ }
+ return services;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
new file mode 100644
index 0000000..29aa30f
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/ServiceExporter.java
@@ -0,0 +1,364 @@
+/*
+ * 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.composite.service.provides;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.ipojo.ServiceContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Export an service from the scope to the parent context.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ServiceExporter implements ServiceListener {
+
+ /**
+ * Destination context.
+ */
+ private BundleContext m_destination;
+
+ /**
+ * Origin context.
+ */
+ private ServiceContext m_origin;
+
+ /**
+ * Exported specification.
+ */
+ private String m_specification;
+
+ /**
+ * LDAP filter filtering internal provider.
+ */
+ private Filter m_filter;
+
+ /**
+ * String form of the LDAP filter.
+ */
+ private String m_filterStr;
+
+ /**
+ * Should be exported several providers.
+ */
+ private boolean m_aggregate = false;
+
+ /**
+ * Is this exports optional?
+ */
+ private boolean m_optional = false;
+
+ /**
+ * Reference on the provided service.
+ */
+ private ProvidedService m_ps;
+
+ /**
+ * Is the export valid?
+ */
+ private boolean m_isValid;
+
+ private class Record {
+ /**
+ * Internal Reference.
+ */
+ private ServiceReference m_ref;
+ /**
+ * External Registration.
+ */
+ private ServiceRegistration m_reg;
+ /**
+ * Exposed object.
+ */
+ private Object m_svcObject;
+ }
+
+ /**
+ * List of managed records.
+ */
+ private List/* <Record> */m_records = new ArrayList()/* <Record> */;
+
+ /**
+ * Constructor.
+ *
+ * @param specification : exported service specification.
+ * @param filter : LDAP filter
+ * @param multiple : is the export an aggregate export?
+ * @param optional : is the export optional?
+ * @param from : internal service context
+ * @param to : external bundle context
+ * @param exp : handler
+ */
+ public ServiceExporter(String specification, String filter, boolean multiple, boolean optional, ServiceContext from, BundleContext to, ProvidedService exp) {
+ this.m_destination = to;
+ this.m_origin = from;
+ this.m_ps = exp;
+ try {
+ this.m_filter = to.createFilter(filter);
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ return;
+ }
+ this.m_aggregate = multiple;
+ this.m_specification = specification;
+ this.m_optional = optional;
+ }
+
+ /**
+ * Start method.
+ * Start the export and the provider tracking.
+ */
+ public synchronized void start() {
+ try {
+ ServiceReference[] refs = m_origin.getServiceReferences(m_specification, null);
+ if (refs != null) {
+ for (int i = 0; i < refs.length; i++) {
+ if (m_filter.match(refs[i])) {
+ Record rec = new Record();
+ rec.m_ref = refs[i];
+ m_records.add(rec);
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+
+ // Publish available services
+ if (m_records.size() > 0) {
+ if (m_aggregate) {
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ } else {
+ Record rec = (Record) m_records.get(0);
+ if (rec.m_reg == null) {
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+ }
+
+ // Register service listener
+ try {
+ m_origin.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + m_specification + ")");
+ } catch (InvalidSyntaxException e) {
+ e.printStackTrace();
+ }
+
+ m_isValid = isSatisfied();
+ }
+
+ /**
+ * Transform service reference property in a dictionary.
+ * Service.PID and Factory.PID are injected too.
+ * @param ref : the service reference.
+ * @return the dictionary containing all property of the given service reference.
+ */
+ private Dictionary getProps(ServiceReference ref) {
+ Properties prop = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ prop.put(keys[i], ref.getProperty(keys[i]));
+ }
+
+ prop.put(Constants.SERVICE_PID, m_ps.getManager().getInstanceName());
+ prop.put("factory.pid", m_ps.getManager().getFactory().getName());
+
+ return prop;
+ }
+
+ /**
+ * Stop method.
+ * Remove the service listener and unregister all exported service.
+ */
+ public synchronized void stop() {
+ m_origin.removeServiceListener(this);
+
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ rec.m_svcObject = null;
+ if (rec.m_reg != null) {
+ rec.m_reg.unregister();
+ m_origin.ungetService(rec.m_ref);
+ rec.m_ref = null;
+ }
+ }
+
+ m_records.clear();
+
+ }
+
+ /**
+ * Check exporter validity.
+ * @return true if the exports is optional, or a service is really exported
+ */
+ public boolean isSatisfied() {
+ return m_optional || m_records.size() > 0;
+ }
+
+ /**
+ * Check if a service is published.
+ * @return true if at least one service is published by this handler
+ */
+ public boolean isPublishing() {
+ return m_records.size() > 0;
+ }
+
+ /**
+ * Get the list of records using the given reference.
+ * @param ref : the service reference
+ * @return the list of records using the given reference, empty if no record used this reference
+ */
+ private List/* <Record> */getRecordsByRef(ServiceReference ref) {
+ List l = new ArrayList();
+ for (int i = 0; i < m_records.size(); i++) {
+ Record rec = (Record) m_records.get(i);
+ if (rec.m_ref == ref) {
+ l.add(rec);
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Service Listener Implementation.
+ * @param ev : the service event
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent ev) {
+ if (ev.getType() == ServiceEvent.REGISTERED) {
+ arrivalManagement(ev.getServiceReference());
+ }
+ if (ev.getType() == ServiceEvent.UNREGISTERING) {
+ departureManagement(ev.getServiceReference());
+ }
+
+ if (ev.getType() == ServiceEvent.MODIFIED) {
+ if (m_filter.match(ev.getServiceReference())) {
+ // Test if the ref is always matching with the filter
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => update
+ // the properties
+ for (int i = 0; i < l.size(); i++) { // Stop the implied
+ // record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) {
+ rec.m_reg.setProperties(getProps(rec.m_ref));
+ }
+ }
+ } else { // it is a new mathcing service => add it
+ arrivalManagement(ev.getServiceReference());
+ }
+ } else {
+ List l = getRecordsByRef(ev.getServiceReference());
+ if (l.size() > 0) { // The ref is already contained => the
+ // service does no more match
+ departureManagement(ev.getServiceReference());
+ }
+ }
+ }
+ }
+
+ /**
+ * Manage the arrival of a service.
+ * @param ref : the new service reference.
+ */
+ private synchronized void arrivalManagement(ServiceReference ref) {
+ // Check if the new service match
+ if (m_filter.match(ref)) {
+ // Add it to the record list
+ Record rec = new Record();
+ rec.m_ref = ref;
+ m_records.add(rec);
+ // Publishing ?
+ if (m_records.size() == 1 || m_aggregate) { // If the service is the
+ // first one, or if it
+ // is a multiple imports
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ // Compute the new state
+ if (!m_isValid && isSatisfied()) {
+ m_isValid = true;
+ m_ps.validating(this);
+ }
+ }
+ }
+
+ /**
+ * Manage the departure of a service.
+ * @param ref : the new service reference.
+ */
+ private synchronized void departureManagement(ServiceReference ref) {
+ List l = getRecordsByRef(ref);
+ for (int i = 0; i < l.size(); i++) { // Stop the implied record
+ Record rec = (Record) l.get(i);
+ if (rec.m_reg != null) {
+ rec.m_svcObject = null;
+ rec.m_reg.unregister();
+ rec.m_reg = null;
+ m_origin.ungetService(rec.m_ref);
+ }
+ }
+ m_records.removeAll(l);
+
+ // Check the validity & if we need to reimport the service
+ if (m_records.size() > 0) {
+ // There is other available services
+ if (!m_aggregate) { // Import the next one
+ Record rec = (Record) m_records.get(0);
+ if (rec.m_svcObject == null) { // It is the first service who
+ // disappears - create the next
+ // one
+ rec.m_svcObject = m_origin.getService(rec.m_ref);
+ rec.m_reg = m_destination.registerService(m_specification, rec.m_svcObject, getProps(rec.m_ref));
+ }
+ }
+ } else {
+ if (!m_optional) {
+ m_isValid = false;
+ m_ps.invalidating(this);
+ }
+ }
+ }
+
+
+ protected String getSpecification() {
+ return m_specification;
+ }
+
+
+ public String getFilter() {
+ return m_filterStr;
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.java
new file mode 100644
index 0000000..b007a87
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/SpecificationMetadata.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.composite.service.provides;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.felix.ipojo.handlers.dependency.nullable.MethodSignature;
+import org.apache.felix.ipojo.handlers.dependency.nullable.MethodSignatureVisitor;
+import org.apache.felix.ipojo.util.Logger;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Type;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Represent a service specification.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class SpecificationMetadata {
+
+ /**
+ * Name of the specification, i.e. name of the interface.
+ */
+ private String m_name;
+
+ /**
+ * List of the method contained in the specification.
+ */
+ private ArrayList/* <MethodMetadata> */m_methods = new ArrayList/* <MethodMetadata> */();
+
+ /**
+ * Is the specificatino an aggregate?
+ */
+ private boolean m_isAggregate;
+
+ /**
+ * Is the specification optional?
+ */
+ private boolean m_isOptional = false;
+
+ /**
+ * Reference on the handler.
+ */
+ private ProvidedServiceHandler m_handler;
+
+ public String getName() {
+ return m_name;
+ }
+
+ public ArrayList/* <MethodMetadata> */getMethods() {
+ return m_methods;
+ }
+
+ /**
+ * Add a method metadata to the current specification.
+ * @param mm : the method metadata to add.
+ */
+ public void addMethod(MethodMetadata mm) {
+ m_methods.add(mm);
+ }
+
+ /**
+ * Get a method by its name.
+ * @param name : method name
+ * @return the method metadata contained in the current specification with the given name. Null if the method is not found.
+ */
+ public MethodMetadata getMethodByName(String name) {
+ for (int i = 0; i < m_methods.size(); i++) {
+ MethodMetadata met = (MethodMetadata) m_methods.get(i);
+ if (met.getMethodName().equals(name)) {
+ return met;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Constructor.
+ * @param name : specification name.
+ * @param bc : bundle context.
+ * @param isAggregate : is the specification aggregate.
+ * @param isOptional : is the specification optional.
+ * @param psd : the handler.
+ */
+ public SpecificationMetadata(String name, BundleContext bc, boolean isAggregate, boolean isOptional, ProvidedServiceHandler psd) {
+ m_name = name;
+ m_handler = psd;
+
+ // Populate methods :
+ URL url = bc.getBundle().getResource(name.replace('.', '/') + ".class");
+ InputStream is = null;
+ ClassReader cr = null;
+ MethodSignatureVisitor msv = null;
+ try {
+ is = url.openStream();
+ cr = new ClassReader(is);
+ msv = new MethodSignatureVisitor();
+ cr.accept(msv, true);
+ is.close();
+ } catch (IOException e) {
+ m_handler.getManager().getFactory().getLogger().log(Logger.ERROR, "Cannot open " + name + " : " + e.getMessage());
+ return;
+ }
+
+ MethodSignature[] containsMethods = msv.getMethods();
+ for (int i = 0; i < containsMethods.length; i++) {
+ MethodSignature met = containsMethods[i];
+ String desc = met.getDesc();
+ MethodMetadata method = new MethodMetadata(met.getName(), desc);
+
+ Type[] args = Type.getArgumentTypes(desc);
+ String[] exceptionClasses = met.getException();
+ for (int j = 0; j < args.length; j++) {
+ method.addArgument(args[j].getClassName());
+ }
+ for (int j = 0; j < exceptionClasses.length; j++) {
+ method.addException(exceptionClasses[j]);
+ }
+
+ addMethod(method);
+ }
+
+ m_isAggregate = isAggregate;
+ m_isOptional = isOptional;
+ }
+
+ public boolean isAggregate() {
+ return m_isAggregate;
+ }
+
+ public boolean isOptional() {
+ return m_isOptional;
+ }
+
+ public void setIsOptional(boolean optional) {
+ m_isOptional = optional;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ClassChecker.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ClassChecker.java
new file mode 100644
index 0000000..50d8d47
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ClassChecker.java
@@ -0,0 +1,213 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Check if the class is already manipulated.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ClassChecker implements ClassVisitor, Opcodes {
+
+ /**
+ * True if the class is already manipulated.
+ */
+ private boolean m_isAlreadyManipulated = false;
+
+ /**
+ * Interfaces implemented by the component.
+ */
+ private String[] m_itfs = new String[0];
+
+ /**
+ * Field hashmap [field name, type] discovered in the component class.
+ */
+ private HashMap m_fields = new HashMap();
+
+ /**
+ * Method List of method descriptor discovered in the component class.
+ */
+ private List m_methods = new ArrayList()/* <MethodDesciptor> */;
+
+ /**
+ * Check if the _cm field already exists.
+ * @param access : Field visibility
+ * @param name : Field name
+ * @param desc : Field description
+ * @param signature : Field signature
+ * @param value : field default value (static only)
+ * @return The field visitor for this field
+ * @see org.objectweb.asm.ClassVisitor#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) {
+
+ if (access == ACC_PRIVATE && name.equals("_cm") && desc.equals("Lorg/apache/felix/ipojo/InstanceManager;")) {
+ m_isAlreadyManipulated = true;
+ }
+
+ Type type = Type.getType(desc);
+ if (type.getSort() == Type.ARRAY) {
+ if (type.getInternalName().startsWith("L")) {
+ String internalType = type.getInternalName().substring(1);
+ String nameType = internalType.replace('/', '.');
+ m_fields.put(name, nameType + "[]");
+ } else {
+ String nameType = type.getClassName().substring(0, type.getClassName().length() - 2);
+ m_fields.put(name, nameType + "[]");
+ }
+ } else {
+ m_fields.put(name, type.getClassName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Check if the class is already manipulated.
+ * @return true if the class is already manipulated.
+ */
+ public boolean isalreadyManipulated() {
+ return m_isAlreadyManipulated;
+ }
+
+ /**
+ * Visit a class.
+ * @param version : Bytecode version
+ * @param access : Class visibility
+ * @param name : Class name
+ * @param signature : Class signature
+ * @param superName : Super Class
+ * @param interfaces : Interfaces imlemented by the class
+ * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String,
+ * java.lang.String, java.lang.String, java.lang.String[])
+ */
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ // Store the interfaces :
+ m_itfs = interfaces;
+ }
+
+ /**
+ * Visit source.
+ * @param arg0 :
+ * @param arg1 :
+ * @see org.objectweb.asm.ClassVisitor#visitSource(java.lang.String, java.lang.String)
+ */
+ public void visitSource(String arg0, String arg1) {
+ }
+
+ /**
+ * Visit a outer class.
+ * @param arg0 :
+ * @param arg1 :
+ * @param arg2 :
+ * @see org.objectweb.asm.ClassVisitor#visitOuterClass(java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitOuterClass(String arg0, String arg1, String arg2) {
+ }
+
+ /**
+ * Visit an annotation.
+ * @param arg0 :
+ * @param arg1 :
+ * @return The annotation visitor (null)
+ * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
+ return null;
+ }
+
+ /**
+ * Visit an Attribute.
+ * @param arg0 :
+ * @see org.objectweb.asm.ClassVisitor#visitAttribute(org.objectweb.asm.Attribute)
+ */
+ public void visitAttribute(Attribute arg0) {
+ }
+
+ /**
+ * Visit an inner class.
+ * @param arg0 :
+ * @param arg1 :
+ * @param arg2 :
+ * @param arg3 :
+ * @see org.objectweb.asm.ClassVisitor#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)
+ */
+ public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) {
+ }
+
+ /**
+ * Visit a method.
+ * @param access : Method visibility
+ * @param name : Method name
+ * @param desc : Method description
+ * @param signature : Method signature
+ * @param exceptions : Method exceptions list
+ * @return The method visitor for this method
+ * @see org.objectweb.asm.ClassVisitor#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 null;
+ }
+
+ /**
+ * End of the visit.
+ * @see org.objectweb.asm.ClassVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ }
+
+ /**
+ * Get the interfaces implemented by the visited class.
+ * @return the interfaces implemented by the component class.
+ */
+ public String[] getInterfaces() {
+ return m_itfs;
+ }
+
+ /**
+ * Get the field contained in the visited class.
+ * @return the field hashmap [field_name, type].
+ */
+ public HashMap getFields() {
+ return m_fields;
+ }
+
+ /**
+ * Get the list of the method contained in the visited class.
+ * @return the method list of [method, signature].
+ */
+ public List getMethods() {
+ return m_methods;
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ConstructorCodeAdapter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ConstructorCodeAdapter.java
new file mode 100644
index 0000000..a4c694d
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ConstructorCodeAdapter.java
@@ -0,0 +1,176 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Constructor Adapter : add a component manager argument inside a constructor.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ConstructorCodeAdapter extends MethodAdapter implements Opcodes {
+
+ /**
+ * The owner class of the field. m_owner : String
+ */
+ private String m_owner;
+
+ /**
+ * Is super constructor already invoked?
+ */
+ private boolean m_superDetected;
+
+ /**
+ * PropertyCodeAdapter constructor. A new FiledCodeAdapter should be create
+ * for each method visit.
+ *
+ * @param mv MethodVisitor
+ * @param owner Name of the class
+ */
+ public ConstructorCodeAdapter(final MethodVisitor mv, final String owner) {
+ super(mv);
+ m_owner = owner;
+ m_superDetected = false;
+ }
+
+ /**
+ * Visit Method for Field instance (GETFIELD).
+ *
+ * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String,
+ * String)
+ * @param opcode : visited operation code
+ * @param owner : owner of the field
+ * @param name : name of the field
+ * @param desc : decriptor of the field
+ */
+ public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
+ if (owner.equals(m_owner)) {
+ if (opcode == GETFIELD) {
+ String gDesc = "()" + desc;
+ visitMethodInsn(INVOKEVIRTUAL, owner, "_get" + name, gDesc);
+ return;
+ } else if (opcode == PUTFIELD) {
+ // replaces PUTFIELD f by INVOKESPECIAL _setf
+ String sDesc = "(" + desc + ")V";
+ visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc);
+ return;
+ }
+ }
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ /**
+ * Visit a method instruction.
+ * Insert an invoke on _setComponentManager.
+ * @param opcode : instructino code
+ * @param owner : owning class
+ * @param name : name of the method
+ * @param desc : method description
+ * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)
+ */
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ // A method call is detected, check if it is the super call :
+ if (!m_superDetected) {
+ m_superDetected = true;
+ // The first invocation is the super call
+ // 1) Visit the super constructor :
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor
+ // invocation
+
+ // 2) Load the object and the component manager argument
+ mv.visitVarInsn(ALOAD, 0);
+ // mv.visitVarInsn(ALOAD,
+ // Type.getArgumentTypes(m_constructorDesc).length);
+ mv.visitVarInsn(ALOAD, 1); // CM is always the first argument
+ // 3) Initialize the field
+ mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setComponentManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V");
+ // insertion finished
+ } else {
+ mv.visitMethodInsn(opcode, owner, name, desc);
+ }
+ }
+
+ /**
+ * Visit a variable.
+ * @param opcode : instruction code
+ * @param var : visited variable
+ * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
+ */
+ public void visitVarInsn(int opcode, int var) {
+ if (!m_superDetected) {
+ return; // Do nothing the ALOAD 0 will be injected by
+ // visitMethodInsn
+ } else {
+ if (var == 0) {
+ mv.visitVarInsn(opcode, var);
+ } else { // ALOAD 0 (THIS)
+ mv.visitVarInsn(opcode, var + 1);
+ } // All other variable count
+ }
+ }
+
+ /**
+ * Visit a variable to increment it.
+ * @param var : incrementied variable
+ * @param increment : increment
+ * @see org.objectweb.asm.MethodAdapter#visitIincInsn(int, int)
+ */
+ public void visitIincInsn(int var, int increment) {
+ if (var != 0) {
+ mv.visitIincInsn(var + 1, increment);
+ } else {
+ mv.visitIincInsn(var, increment);
+ } // Increment the current object ???
+ }
+
+ /**
+ * Visit a local variable.
+ * Add a visit on m_manager.
+ * @param name : variable name
+ * @param desc : variable description
+ * @param signature : variable signature
+ * @param start : start label of the variable definition
+ * @param end : end label of the variable definition
+ * @param index : vairable nuber.
+ * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)
+ */
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ if (index == 0) {
+ mv.visitLocalVariable(name, desc, signature, start, end, index);
+ mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);
+ }
+ mv.visitLocalVariable(name, desc, signature, start, end, index + 1);
+ }
+
+ /**
+ * Computer visit max.
+ * Add a local variable.
+ * @param maxStack : stack max size.
+ * @param maxLocals : maximum of visited local variable.
+ * @see org.objectweb.asm.MethodAdapter#visitMaxs(int, int)
+ */
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv.visitMaxs(maxStack, maxLocals + 1);
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ManipulationProperty.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ManipulationProperty.java
new file mode 100644
index 0000000..c2daec0
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/ManipulationProperty.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.composite.service.provides.manipulation;
+
+/**
+ * Store properties for the manipulation process.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ *
+ */
+public class ManipulationProperty {
+
+ /**
+ * iPOJO Package name.
+ */
+ protected static final String IPOJO_PACKAGE_NAME = "org.apache.felix.ipojo";
+
+ /**
+ * Activator internal package name.
+ */
+ protected static final String IPOJO_INTERNAL_PACKAGE_NAME = "org/apache/felix/ipojo/";
+
+ /**
+ * Ipojo internal package name for internal descriptor.
+ */
+ protected static final String IPOJO_INTERNAL_DESCRIPTOR = "L" + IPOJO_INTERNAL_PACKAGE_NAME;
+
+ /**
+ * Helper array for bytecode manipulation of primitive type.
+ */
+ protected static final String[][] PRIMITIVE_BOXING_INFORMATION = new String[][] {
+ { "V", "ILLEGAL", "ILLEGAL" }, // void type [0]
+ { "Z", "java/lang/Boolean", "booleanValue" }, // boolean [1]
+ { "C", "java/lang/Character", "charValue" }, // char [2]
+ { "B", "java/lang/Byte", "byteValue" }, // byte [3]
+ { "S", "java/lang/Short", "shortValue" }, // short [4]
+ { "I", "java/lang/Integer", "intValue" }, // int [5]
+ { "F", "java/lang/Float", "floatValue" }, // float [6]
+ { "J", "java/lang/Long", "longValue" }, // long [7]
+ { "D", "java/lang/Double", "doubleValue" } // double [8]
+ };
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/Manipulator.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/Manipulator.java
new file mode 100644
index 0000000..ff9b20a
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/Manipulator.java
@@ -0,0 +1,117 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * iPOJO Bytecode Manipulator.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ *
+ */
+public class Manipulator {
+ /**
+ * Store the visited fields : [name fo the field, type of the field].
+ */
+ private HashMap m_fields = new HashMap();
+
+ /**
+ * Store the interface implemented by the class.
+ */
+ private String[] m_interfaces = new String[0];
+
+ /**
+ * Return the hashmap [name of the field, type of the field]. This
+ * information is found when the class is manipulated It is a clone of the
+ * original hashmap to avoid modification by handlers
+ *
+ * @return the hashmap [name of the field, type of the field].
+ */
+ public HashMap getFields() {
+ return m_fields;
+ }
+
+ /**
+ * Return the hashmap [name of the field, type of the field]. This
+ * information is found when the class is manipulated It is a clone of the
+ * original hashmap to avoid modification by handlers
+ *
+ * @return the hashmap [name of the field, type of the field].
+ */
+ public String[] getInterfaces() {
+ return m_interfaces;
+ }
+
+ /**
+ * Manipulate the given byte array.
+ *
+ * @param origin : original class.
+ * @return the manipulated class.
+ * @throws IOException : if an error occurs during the manipulation.
+ */
+ public byte[] process(byte[] origin) throws IOException {
+ InputStream is1 = new ByteArrayInputStream(origin);
+
+ // First check if the class is already manipulated :
+ ClassReader ckReader = new ClassReader(is1);
+ ClassChecker ck = new ClassChecker();
+ ckReader.accept(ck, true);
+ is1.close();
+
+ m_fields = ck.getFields();
+
+ // Get interface and remove POJO interface is presents
+ String[] its = ck.getInterfaces();
+ ArrayList l = new ArrayList();
+ for (int i = 0; i < its.length; i++) {
+ l.add(its[i]);
+ }
+ l.remove("org/apache/felix/ipojo/Pojo");
+
+ m_interfaces = new String[l.size()];
+ for (int i = 0; i < m_interfaces.length; i++) {
+ m_interfaces[i] = ((String) l.get(i)).replace('/', '.');
+ }
+
+ ClassWriter finalWriter = null;
+ if (!ck.isalreadyManipulated()) {
+ // Manipulation ->
+ // Add the _setComponentManager method
+ // Instrument all fields
+ InputStream is2 = new ByteArrayInputStream(origin);
+ ClassReader cr0 = new ClassReader(is2);
+ ClassWriter cw0 = new ClassWriter(true);
+ PreprocessClassAdapter preprocess = new PreprocessClassAdapter(cw0);
+ cr0.accept(preprocess, false);
+ is2.close();
+ finalWriter = cw0;
+ }
+ // The file is in the bundle
+ return finalWriter.toByteArray();
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/POJOWriter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/POJOWriter.java
new file mode 100644
index 0000000..2dc57e1
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/POJOWriter.java
@@ -0,0 +1,405 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.felix.ipojo.composite.service.provides.FieldMetadata;
+import org.apache.felix.ipojo.composite.service.provides.MethodMetadata;
+import org.apache.felix.ipojo.composite.service.provides.SpecificationMetadata;
+import org.apache.felix.ipojo.handlers.dependency.nullable.MethodSignature;
+import org.apache.felix.ipojo.handlers.dependency.nullable.MethodSignatureVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Create the proxy class.
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class POJOWriter implements Opcodes {
+
+ /**
+ * Create a class.
+ * @param cw : class writer
+ * @param className : class name
+ * @param spec : implemented specification
+ */
+ private static void createClass(ClassWriter cw, String className, String spec) {
+ // Create the class
+ cw.visit(V1_2, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", new String[] { spec.replace('.', '/') });
+ }
+
+ /**
+ * Inject field in the current class.
+ * @param cw : class writer.
+ * @param fields : list of field to inject.
+ */
+ private static void injectFields(ClassWriter cw, List fields) {
+ // Inject fields
+ for (int i = 0; i < fields.size(); i++) {
+ FieldMetadata field = (FieldMetadata) fields.get(i);
+ if (field.isUseful()) {
+ SpecificationMetadata spec = field.getSpecification();
+ String fieldName = field.getName();
+ String desc = "";
+ if (field.isAggregate()) {
+ desc = "[L" + spec.getName().replace('.', '/') + ";";
+ } else {
+ desc = "L" + spec.getName().replace('.', '/') + ";";
+ }
+
+ cw.visitField(Opcodes.ACC_PRIVATE, fieldName, desc, null, null);
+ }
+ }
+ }
+
+ /**
+ * Return the proxy classname for the contract contractname by delegating on available service.
+ * @param url URL of the needed contract
+ * @param contractName : The interface to implement
+ * @param className : The class name to create
+ * @param fields : the list of fields on which delegate
+ * @param methods : the list of method on which delegate
+ * @return byte[] : the build class
+ */
+ public static byte[] dump(URL url, String contractName, String className, List fields, List methods) {
+
+ ClassReader cr = null;
+ InputStream is = null;
+ byte[] b = null;
+ try {
+ is = url.openStream();
+ cr = new ClassReader(is);
+ MethodSignatureVisitor msv = new MethodSignatureVisitor();
+ cr.accept(msv, true);
+ is.close();
+
+ MethodSignature[] methodsSign = msv.getMethods();
+
+ ClassWriter cw = new ClassWriter(true);
+
+ // Create the class
+ className = className.replace('.', '/');
+ createClass(cw, className, contractName);
+
+ // Inject fields inside the POJO
+ injectFields(cw, fields);
+
+ // Inject a constructor <INIT>()V
+ MethodVisitor cst = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ cst.visitVarInsn(ALOAD, 0);
+ cst.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ cst.visitInsn(RETURN);
+ cst.visitMaxs(0, 0);
+ cst.visitEnd();
+
+ for (int i = 0; i < methodsSign.length; ++i) {
+ MethodSignature method = methodsSign[i];
+
+ // Get the field for this method
+ // 1) find the MethodMetadata
+ FieldMetadata delegator = null; // field to delegate
+ MethodMetadata methodDelegator = null; // field to delegate
+ for (int j = 0; j < methods.size(); j++) {
+ MethodMetadata methodMeta = (MethodMetadata) methods.get(j);
+ if (methodMeta.equals(method)) {
+ delegator = methodMeta.getDelegation();
+ methodDelegator = methodMeta;
+ }
+ }
+
+ generateOneMethod(cw, className, methodDelegator, method, delegator);
+
+ }
+
+ // End process
+ cw.visitEnd();
+ b = cw.toByteArray();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ // Write the class :
+// try {
+// FileOutputStream fos = new FileOutputStream(
+// "F:\\dev\\workspaces\\iPOJO_dev\\Test_Manipulator\\manipulated\\org\\apache\\felix\\ipojo\\test\\scenarios\\component\\"
+// + className.replace('/', '.') + ".class");
+//
+// fos.write(b);
+//
+// fos.close();
+// } catch (Exception e) {
+// System.err.println("Exception : " + e.getMessage());
+// }
+
+ return b;
+ }
+
+ /**
+ * Generate on method.
+ * @param cw : class writer
+ * @param className : the current class name
+ * @param method : the method to generate
+ * @param sign : method signature to generate
+ * @param delegator : the field on which delegate
+ */
+ private static void generateOneMethod(ClassWriter cw, String className, MethodMetadata method, MethodSignature sign, FieldMetadata delegator) {
+ String desc = sign.getDesc();
+ String name = sign.getName();
+ String signa = sign.getSignature();
+ String[] exc = sign.getException();
+
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, desc, signa, exc);
+
+ if (delegator.isOptional()) {
+ if (!delegator.isAggregate()) {
+ generateOptionalCase(mv, delegator, className);
+ }
+ if (delegator.isAggregate() /*&& method.getPolicy() == MethodMetadata.ONE_POLICY*/) {
+ generateOptionalAggregateCase(mv, delegator, className);
+ }
+ }
+
+ if (!delegator.isAggregate()) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+
+ // Loads args
+ Type[] args = Type.getArgumentTypes(desc);
+ for (int i = 0; i < args.length; i++) {
+ writeLoad(args[i], i + 1, mv);
+ }
+
+ // Invoke
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+
+ // Return
+ writeReturn(Type.getReturnType(desc), mv);
+ } else {
+ if (method.getPolicy() == MethodMetadata.ONE_POLICY) {
+ // Aggregate and One Policy
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ICONST_0); // Take the first one
+ mv.visitInsn(AALOAD);
+
+ // Loads args
+ Type[] args = Type.getArgumentTypes(desc);
+ for (int i = 0; i < args.length; i++) {
+ writeLoad(args[i], i + 1, mv);
+ }
+
+ // Invoke
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+
+ // Return
+ writeReturn(Type.getReturnType(desc), mv);
+ } else { // All policy
+ if (Type.getReturnType(desc).getSort() != Type.VOID) {
+ System.err.println("All policy cannot be used on method which does not return void");
+ }
+
+ Type[] args = Type.getArgumentTypes(desc);
+ int index = args.length + 1;
+
+ // Init
+ mv.visitInsn(ICONST_0);
+ mv.visitVarInsn(ISTORE, index);
+ Label l1b = new Label();
+ mv.visitLabel(l1b);
+ Label l2b = new Label();
+ mv.visitJumpInsn(GOTO, l2b);
+
+ // Loop
+ Label l3b = new Label();
+ mv.visitLabel(l3b);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitVarInsn(ILOAD, index);
+ mv.visitInsn(AALOAD);
+
+ // Loads args
+ for (int i = 0; i < args.length; i++) {
+ writeLoad(args[i], i + 1, mv);
+ }
+
+ mv.visitMethodInsn(INVOKEINTERFACE, delegator.getSpecification().getName().replace('.', '/'), name, desc);
+
+ Label l4b = new Label();
+ mv.visitLabel(l4b);
+ mv.visitIincInsn(index, 1); // i++;
+
+ // Condition
+ mv.visitLabel(l2b);
+ mv.visitVarInsn(ILOAD, index);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitJumpInsn(IF_ICMPLT, l3b);
+
+ Label l5b = new Label();
+ mv.visitLabel(l5b);
+ mv.visitInsn(RETURN);
+ }
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate Optional Case for aggregate field.
+ * @param mv : method visitor
+ * @param delegator : Field on which delegate
+ * @param className : current class name
+ */
+ private static void generateOptionalAggregateCase(MethodVisitor mv, FieldMetadata delegator, String className) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "[L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitInsn(ARRAYLENGTH);
+ Label l1a = new Label();
+ mv.visitJumpInsn(IFNE, l1a);
+ Label l2a = new Label();
+ mv.visitLabel(l2a);
+ mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn("Operation not supported");
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(l1a);
+ }
+
+ /**
+ * Generate Optional case for non aggregate fields.
+ *
+ * @param mv : the method visitor
+ * @param delegator : the field on which delegate.
+ * @param className : the name of the current class.
+ */
+ private static void generateOptionalCase(MethodVisitor mv, FieldMetadata delegator, String className) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, className, delegator.getName(), "L" + delegator.getSpecification().getName().replace('.', '/') + ";");
+ mv.visitTypeInsn(INSTANCEOF, "org/apache/felix/ipojo/Nullable");
+ Label end = new Label();
+ mv.visitJumpInsn(IFEQ, end);
+ Label begin = new Label();
+ mv.visitLabel(begin);
+ mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn("Operation not supported");
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(end);
+ }
+
+ /**
+ * Write a return instruction according to the given type.
+ * @param t : the type
+ * @param mv : the method visitor
+ */
+ private static void writeReturn(Type t, MethodVisitor mv) {
+ switch (t.getSort()) {
+ case Type.BOOLEAN:
+ case Type.INT:
+ case Type.BYTE:
+ case Type.CHAR:
+ case Type.SHORT:
+ // Integer or Boolean : return 0 ( false)
+ mv.visitInsn(IRETURN);
+ break;
+ case Type.LONG:
+ // mv.visitInsn(LCONST_0);
+ mv.visitInsn(LRETURN);
+ break;
+ case Type.DOUBLE:
+ // Double : return 0.0
+ // mv.visitInsn(DCONST_0);
+ mv.visitInsn(DRETURN);
+ break;
+ case Type.FLOAT:
+ // Double : return 0.0
+ // mv.visitInsn(DCONST_0);
+ mv.visitInsn(FRETURN);
+ break;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ // Return always null for array and object
+ // mv.visitInsn(ACONST_NULL);
+ mv.visitInsn(ARETURN);
+ break;
+ case Type.VOID:
+ mv.visitInsn(RETURN);
+ break;
+ default:
+ System.err.println("Type not yet managed : " + t);
+ break;
+ }
+ }
+
+ /**
+ * Write a load instruction according to the given type.
+ * @param t : the type
+ * @param mv : the method visitor
+ * @param index : variable name (index)
+ */
+ private static void writeLoad(Type t, int index, MethodVisitor mv) {
+ switch (t.getSort()) {
+ case Type.BOOLEAN:
+ case Type.INT:
+ case Type.BYTE:
+ case Type.CHAR:
+ case Type.SHORT:
+ // Integer or Boolean : return 0 ( false)
+ mv.visitVarInsn(ILOAD, index);
+ break;
+ case Type.LONG:
+ // mv.visitInsn(LCONST_0);
+ mv.visitVarInsn(LLOAD, index);
+ break;
+ case Type.FLOAT:
+ // mv.visitInsn(LCONST_0);
+ mv.visitVarInsn(FLOAD, index);
+ break;
+ case Type.DOUBLE:
+ // Double : return 0.0
+ // mv.visitInsn(DCONST_0);
+ mv.visitVarInsn(DLOAD, index);
+ break;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ // Return always null for array and object
+ // mv.visitInsn(ACONST_NULL);
+ mv.visitVarInsn(ALOAD, index);
+ break;
+ default:
+ System.err.println("Type not yet managed : " + t);
+ break;
+ }
+ }
+
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessClassAdapter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessClassAdapter.java
new file mode 100644
index 0000000..1e12640
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessClassAdapter.java
@@ -0,0 +1,661 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * Manipulate the class. - Add a component manager field (_cm) - Create getter
+ * and setter for each fields - Store information about field - Store
+ * information about implemented interfaces - Change GETFIELD and PUTFIELD to
+ * called the getter and setter method
+ *
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ *
+ */
+public class PreprocessClassAdapter extends ClassAdapter implements Opcodes {
+
+ /**
+ * Constant : POJO interface.
+ */
+ private static final String POJO_INTERFACE = "org/apache/felix/ipojo/Pojo";
+
+ /**
+ * The owner. m_owner : String
+ */
+ private String m_owner;
+
+ /**
+ * Constructor.
+ *
+ * @param cv : Class visitor
+ */
+ public PreprocessClassAdapter(final ClassVisitor cv) {
+ super(cv);
+ }
+
+ /**
+ * The visit method. - Insert the _cm field - Create the _initialize method -
+ * Create the _cm setter method
+ *
+ * @see org.objectweb.asm.ClassVisitor#visit(int, int, String, String,
+ * String, String[])
+ * @param version : Version
+ * @param access : Access modifier
+ * @param name : name of the visited element
+ * @param signature : singature of the visited element
+ * @param superName : superclasses (extend clause)
+ * @param interfaces : implement clause
+ */
+ public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
+
+ m_owner = name;
+
+ // Insert _cm field
+ FieldVisitor fv = super.visitField(ACC_PRIVATE, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;", null, null);
+ fv.visitEnd();
+
+ // Create the _cmSetter(ComponentManager cm) method
+ createComponentManagerSetter();
+
+ // Add the getComponentInstance
+ createGetComponentInstanceMethod();
+
+ // Add the POJO interface to the interface list
+ // Check that the POJO interface isnot already in the list
+ boolean found = false;
+ for (int i = 0; i < interfaces.length; i++) {
+ if (interfaces[i].equals(POJO_INTERFACE)) {
+ found = true;
+ }
+ }
+ String[] itfs;
+ if (!found) {
+ itfs = new String[interfaces.length + 1];
+ for (int i = 0; i < interfaces.length; i++) {
+ itfs[i] = interfaces[i];
+ }
+ itfs[interfaces.length] = POJO_INTERFACE;
+ } else {
+ itfs = interfaces;
+ }
+
+ String str = "";
+ for (int i = 0; i < itfs.length; i++) {
+ str += itfs[i] + " ";
+ }
+
+ super.visit(version, access, name, signature, superName, itfs);
+ }
+
+ /**
+ * visit method method :-).
+ *
+ * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String,
+ * java.lang.String, java.lang.String, java.lang.String[])
+ * @param access : access modifier
+ * @param name : name of the method
+ * @param desc : descriptor of the method
+ * @param signature : signature of the method
+ * @param exceptions : exception launched by the method
+ * @return MethodVisitor
+ */
+ public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
+ // The method is a constructor, adapt the constructor to add a
+ // ComponentManager argument
+ if (name.equals("<init>")) {
+ // 1) change the constructor descriptor (add a component manager arg
+ // as first argument)
+ String newDesc = desc.substring(1);
+ newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;
+
+ // Insert the new constructor
+ MethodVisitor mv = super.visitMethod(ACC_PUBLIC, "<init>", newDesc, null, null);
+
+ if (mv == null) {
+ return null;
+ } else {
+ return new ConstructorCodeAdapter(mv, m_owner);
+ }
+
+ } else {
+ MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
+ if (mv == null) {
+ return null;
+ } else {
+ return new PreprocessCodeAdapter(mv, m_owner);
+ }
+ }
+
+ }
+
+ /**
+ * Create the setter method for the _cm field.
+ */
+ private void createComponentManagerSetter() {
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_setComponentManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+
+ mv.visitInsn(RETURN);
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the getComponentInstance method.
+ */
+ private void createGetComponentInstanceMethod() {
+ MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getComponentInstance", "()Lorg/apache/felix/ipojo/ComponentInstance;", null, null);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitInsn(ARETURN);
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * visit Field method.
+ *
+ * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String,
+ * java.lang.String, java.lang.String, java.lang.Object)
+ * @param access : acces modifier
+ * @param name : name of the field
+ * @param desc : description of the field
+ * @param signature : signature of the field
+ * @param value : value of the field
+ * @return FieldVisitor
+ */
+ public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {
+ if ((access & ACC_STATIC) == 0) {
+ Type type = Type.getType(desc);
+
+ // Keep the field in the code
+ FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
+
+ if (type.getSort() == Type.ARRAY) {
+
+ String gDesc = "()" + desc;
+ createArrayGetter(name, gDesc);
+
+ // Generates setter method
+ String sDesc = "(" + desc + ")V";
+ createArraySetter(name, sDesc);
+
+ } else {
+
+ // Generate the getter method
+ String gDesc = "()" + desc;
+ createSimpleGetter(name, gDesc, type);
+
+ // Generates setter method
+ String sDesc = "(" + desc + ")V";
+ createSimpleSetter(name, sDesc, type);
+ }
+
+ return fv;
+
+ }
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ /**
+ * Generate a setter method for an array field.
+ * @param name : name of the field.
+ * @param desc : description of the method
+ */
+ private void createArraySetter(String name, String desc) {
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_set" + name, desc, null, null);
+
+ String internalType = desc.substring(1);
+ internalType = internalType.substring(0, internalType.length() - 2);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalType);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+ mv.visitInsn(RETURN);
+
+ // End
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Generate a getter method for an array field.
+ * @param name : name of the field.
+ * @param desc : description of the method
+ */
+ private void createArrayGetter(String name, String desc) {
+
+ String methodName = "_get" + name;
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, null);
+
+ String internalType = desc.substring(2);
+
+ mv.visitVarInsn(ALOAD, 0);
+ // mv.visitFieldInsn(GETFIELD, m_owner, name,
+ // "["+type.getInternalName()+";");
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitTypeInsn(CHECKCAST, internalType);
+ mv.visitVarInsn(ASTORE, 3);
+
+ Label l3a = new Label();
+ mv.visitLabel(l3a);
+
+ mv.visitVarInsn(ALOAD, 1);
+ Label l4a = new Label();
+ mv.visitJumpInsn(IFNULL, l4a);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
+
+ Label l5a = new Label();
+ mv.visitJumpInsn(IFNE, l5a);
+ mv.visitLabel(l4a);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalType + ")V");
+ mv.visitLabel(l5a);
+
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitInsn(ARETURN);
+
+ // End
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the getter for service dependency.
+ *
+ * @param name : field of the dependency
+ * @param desc : description of the getter method
+ * @param type : type to return
+ */
+ private void createSimpleGetter(String name, String desc, Type type) {
+
+ String methodName = "_get" + name;
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, methodName, desc, null, null);
+
+ switch (type.getSort()) {
+ // Generate the getter method for boolean, char, byte shot as for int.
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ case Type.INT:
+ String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ String unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitVarInsn(type.getOpcode(ISTORE), 1);
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 3);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 4);
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);
+ mv.visitVarInsn(type.getOpcode(ISTORE), 5);
+ Label l5 = new Label();
+ mv.visitLabel(l5);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 5);
+ Label l6 = new Label();
+ mv.visitJumpInsn(type.getOpcode(IF_ICMPEQ), l6);
+ Label l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 5);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");
+ mv.visitLabel(l6);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 5);
+ mv.visitInsn(type.getOpcode(IRETURN));
+ break;
+
+ // Generate the getter for long
+ case Type.LONG:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitVarInsn(LSTORE, 1);
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(LLOAD, 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 3); // Double Space
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 4);
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 5);
+ mv.visitVarInsn(ALOAD, 5);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);
+ mv.visitVarInsn(LSTORE, 6);
+ l5 = new Label();
+ mv.visitLabel(l5);
+ mv.visitVarInsn(LLOAD, 1);
+ mv.visitVarInsn(LLOAD, 6);
+ mv.visitInsn(LCMP);
+ l6 = new Label();
+ mv.visitJumpInsn(IFEQ, l6);
+ l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(LLOAD, 6);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");
+ mv.visitLabel(l6);
+ mv.visitVarInsn(LLOAD, 6);
+ mv.visitInsn(LRETURN);
+ break;
+
+ // Generate the getter for double
+ case Type.DOUBLE:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitVarInsn(DSTORE, 1);
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(DLOAD, 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 3); // Double Space
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 4);
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 5);
+ mv.visitVarInsn(ALOAD, 5);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);
+ mv.visitVarInsn(DSTORE, 6);
+ l5 = new Label();
+ mv.visitLabel(l5);
+ mv.visitVarInsn(DLOAD, 1);
+ mv.visitVarInsn(DLOAD, 6);
+ mv.visitInsn(DCMPL);
+ l6 = new Label();
+ mv.visitJumpInsn(IFEQ, l6);
+ l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(DLOAD, 6);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");
+ mv.visitLabel(l6);
+ mv.visitVarInsn(DLOAD, 6);
+ mv.visitInsn(DRETURN);
+ break;
+
+ // Generate for float.
+ case Type.FLOAT:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+ unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
+ mv.visitVarInsn(FSTORE, 1);
+
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(FLOAD, 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 2); // One Space
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 3);
+
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitTypeInsn(CHECKCAST, boxingType);
+ mv.visitVarInsn(ASTORE, 4);
+
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);
+ mv.visitVarInsn(FSTORE, 5);
+
+ l5 = new Label();
+ mv.visitLabel(l5);
+
+ mv.visitVarInsn(FLOAD, 1);
+ mv.visitVarInsn(FLOAD, 5);
+ mv.visitInsn(FCMPL);
+ l6 = new Label();
+ mv.visitJumpInsn(IFEQ, l6);
+
+ l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(FLOAD, 5);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(" + internalName + ")V");
+ mv.visitLabel(l6);
+
+ mv.visitVarInsn(FLOAD, 5);
+ mv.visitInsn(FRETURN);
+
+ break;
+
+ //Generate for array.
+ case Type.OBJECT:
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");
+ mv.visitVarInsn(ASTORE, 1);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getterCallback",
+ "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, 2);
+
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitTypeInsn(CHECKCAST, type.getInternalName());
+ mv.visitVarInsn(ASTORE, 3);
+
+ Label l3b = new Label();
+ mv.visitLabel(l3b);
+
+ mv.visitVarInsn(ALOAD, 1);
+ Label l4b = new Label();
+ mv.visitJumpInsn(IFNULL, l4b);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
+
+ Label l5b = new Label();
+ mv.visitJumpInsn(IFNE, l5b);
+ mv.visitLabel(l4b);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_set" + name, "(L" + type.getInternalName() + ";)V");
+ mv.visitLabel(l5b);
+
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitInsn(ARETURN);
+
+ break;
+
+ default:
+ break;
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+
+ /**
+ * Create the setter method for one property. The name of the method is
+ * _set+name of the field
+ *
+ * @param name : name of the field representing a property
+ * @param desc : description of the setter method
+ * @param type : type of the property
+ */
+ private void createSimpleSetter(String name, String desc, Type type) {
+ MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_set" + name, desc, null, null);
+
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ case Type.CHAR:
+ case Type.BYTE:
+ case Type.SHORT:
+ case Type.INT:
+ case Type.FLOAT:
+ String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 2);
+
+ Label l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+ Label l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitInsn(RETURN);
+ break;
+
+ case Type.LONG:
+ case Type.DOUBLE:
+ internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
+ boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
+ l1 = new Label();
+ mv.visitLabel(l1);
+
+ mv.visitTypeInsn(NEW, boxingType);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(type.getOpcode(ILOAD), 1);
+ mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");
+ mv.visitVarInsn(ASTORE, 3); // Double space
+
+ l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+ l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitInsn(RETURN);
+ break;
+
+ case Type.OBJECT:
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, m_owner, name, "L" + type.getInternalName() + ";");
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, m_owner, "_cm", "Lorg/apache/felix/ipojo/InstanceManager;");
+ mv.visitLdcInsn(name);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "setterCallback", "(Ljava/lang/String;Ljava/lang/Object;)V");
+
+ mv.visitInsn(RETURN);
+ break;
+ default:
+ break;
+ }
+
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+ }
+}
diff --git a/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessCodeAdapter.java b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessCodeAdapter.java
new file mode 100644
index 0000000..868eece
--- /dev/null
+++ b/ipojo/src/main/java/org/apache/felix/ipojo/composite/service/provides/manipulation/PreprocessCodeAdapter.java
@@ -0,0 +1,73 @@
+/*
+ * 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.composite.service.provides.manipulation;
+
+import org.objectweb.asm.MethodAdapter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Manipulate a method to change all getter and setter on field by invocations on getter and setter callbacks.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class PreprocessCodeAdapter extends MethodAdapter implements Opcodes {
+
+ /**
+ * The owner class of the field. m_owner : String
+ */
+ private String m_owner;
+
+ /**
+ * PropertyCodeAdapter constructor. A new FieldCodeAdapter should be create
+ * for each method visit.
+ *
+ * @param mv MethodVisitor
+ * @param owner Name of the class
+ */
+ public PreprocessCodeAdapter(final MethodVisitor mv, final String owner) {
+ super(mv);
+ m_owner = owner;
+ }
+
+ /**
+ * Visit Method for Filed instance (GETFIELD).
+ *
+ * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String,
+ * String)
+ * @param opcode : visited operation code
+ * @param owner : owner of the field
+ * @param name : name of the field
+ * @param desc : decriptor of the field
+ */
+ public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {
+ if (owner.equals(m_owner)) {
+ if (opcode == GETFIELD) {
+ String gDesc = "()" + desc;
+ visitMethodInsn(INVOKEVIRTUAL, owner, "_get" + name, gDesc);
+ return;
+ } else if (opcode == PUTFIELD) {
+ String sDesc = "(" + desc + ")V";
+ visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc);
+ return;
+ }
+ }
+ super.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+}