Fixed FELIX-3078 and FELIX-3079

The new manipulation process is now easily embeddable and the process can be extended.

Thanks to Guillaume Sauthier for this hard work.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1159173 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/ant/pom.xml b/ipojo/ant/pom.xml
index 35bd3fd..59c440e 100644
--- a/ipojo/ant/pom.xml
+++ b/ipojo/ant/pom.xml
@@ -46,7 +46,7 @@
     <dependency>
       <groupId>org.apache.felix</groupId>
       <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
-      <version>1.8.0</version>
+      <version>1.9.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>xerces</groupId>
@@ -121,6 +121,14 @@
           <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/AntReporter.java b/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/AntReporter.java
new file mode 100644
index 0000000..b99b852
--- /dev/null
+++ b/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/AntReporter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.task;
+
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+import org.apache.tools.ant.Project;
+
+/**
+ * An {@code AntReporter} wraps an Ant project (central place for logging in ant
+ * into an iPOJO Reporter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AntReporter extends EmptyReporter {
+
+    /**
+     * Ant Project (used for log).
+     */
+    private Project project;
+
+    public AntReporter(Project project) {
+        this.project = project;
+    }
+
+    @Override
+    public void trace(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        project.log(formatted, Project.MSG_DEBUG);
+    }
+
+    @Override
+    public void info(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        project.log(formatted, Project.MSG_INFO);
+    }
+
+    @Override
+    public void warn(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        project.log(formatted, Project.MSG_WARN);
+        getWarnings().add(formatted);
+    }
+
+    @Override
+    public void error(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        project.log(formatted, Project.MSG_ERR);
+        getErrors().add(formatted);
+    }
+
+}
diff --git a/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java b/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java
index 2731ed8..9d1f101 100644
--- a/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java
+++ b/ipojo/ant/src/main/java/org/apache/felix/ipojo/task/IPojoTask.java
@@ -24,6 +24,7 @@
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Task;
+import sun.awt.geom.AreaOp;
 
 /**
  * iPOJO Ant Task. This Ant task manipulates an input bundle.
@@ -192,7 +193,8 @@
             }
         }
 
-        Pojoization pojo = new Pojoization();
+        AntReporter reporter = new AntReporter(getProject());
+        Pojoization pojo = new Pojoization(reporter);
         if (m_ignoreAnnotations) {
             pojo.disableAnnotationProcessing();
         }
@@ -204,10 +206,12 @@
         } else {
             pojo.directoryPojoization(m_directory, m_metadata, m_manifest);
         }
-        for (int i = 0; i < pojo.getWarnings().size(); i++) {
-            log((String) pojo.getWarnings().get(i), Project.MSG_WARN);
+        for (int i = 0; i < reporter.getWarnings().size(); i++) {
+            log((String) reporter.getWarnings().get(i), Project.MSG_WARN);
         }
-        if (pojo.getErrors().size() > 0) { throw new BuildException((String) pojo.getErrors().get(0)); }
+        if (reporter.getErrors().size() > 0) {
+            throw new BuildException((String) reporter.getErrors().get(0));
+        }
 
         if (m_input != null) {
             String out;
diff --git a/ipojo/manipulator/pom.xml b/ipojo/manipulator/pom.xml
index a6755bb..9d35cb3 100644
--- a/ipojo/manipulator/pom.xml
+++ b/ipojo/manipulator/pom.xml
@@ -46,10 +46,21 @@
         </exclusion>
       </exclusions>
     </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+        <version>1.4.0</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+        <version>1.8.0</version>
+      </dependency>
     <dependency>
-      <groupId>org.apache.felix</groupId>
-      <artifactId>org.apache.felix.ipojo.metadata</artifactId>
-      <version>1.4.0</version>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.8.5</version>
+      <scope>test</scope>
     </dependency>
   </dependencies>
   <build>
@@ -65,7 +76,7 @@
             <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
             <Bundle-Vendor> The Apache Software Foundation </Bundle-Vendor>
             <Bundle-Description> iPOJO Manipulator </Bundle-Description>
-            <Export-Package> org.apache.felix.ipojo.manipulator
+            <Export-Package> org.apache.felix.ipojo.manipulator.*
             </Export-Package>
             <Private-Package> org.apache.felix.ipojo.manipulation,
               org.apache.felix.ipojo.manipulation.annotations,
@@ -75,8 +86,8 @@
               META-INF/LICENSE=LICENSE,
               META-INF/LICENSE.asm=LICENSE.asm,
               META-INF/NOTICE=NOTICE,
-              xsd=src/main/resources,
-              META-INF/DEPENDENCIES=DEPENDENCIES
+              META-INF/DEPENDENCIES=DEPENDENCIES,
+              {maven-resources}
             </Include-Resource>
             <Import-Package>!org.objectweb.asm.tree, *</Import-Package>
           </instructions>
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
index 606a4e8..e1522ed 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -1,157 +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.manipulation;

-

-import java.io.ByteArrayInputStream;

-import java.io.IOException;

-import java.io.InputStream;

-import java.util.Iterator;

-import java.util.List;

-import java.util.Map;

-

-import org.apache.felix.ipojo.metadata.Attribute;

-import org.apache.felix.ipojo.metadata.Element;

-import org.objectweb.asm.ClassReader;

-import org.objectweb.asm.ClassWriter;

-

-/**

- * iPOJO Byte code Manipulator.

- * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

- *

- */

-public class Manipulator {

-    /**

-     * Store the visited fields : [name of the field, type of the field].

-     */

-    private Map m_fields;

-

-    /**

-     * Store the interface implemented by the class.

-     */

-    private List m_interfaces;

-

-    /**

-     * Store the methods list.

-     */

-    private List m_methods;

-

-    /**

-     * Pojo super class.

-     */

-    private String m_superClass;

-

-    /**

-     * List of owned inner classed.

-     */

-    private List m_inners;

-

-    /**

-     * Manipulate the given byte array.

-     * @param origin : original class.

-     * @return the manipulated class, if the class is already manipulated, the original class.

-     * @throws IOException : if an error occurs during the manipulation.

-     */

-    public byte[] manipulate(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, ClassReader.SKIP_FRAMES);

-        is1.close();

-

-        m_fields = ck.getFields(); // Get visited fields (contains only POJO fields)

-

-        // Get interfaces and super class.

-        m_interfaces = ck.getInterfaces();

-        m_superClass = ck.getSuperClass();

-

-        // Get the methods list

-        m_methods = ck.getMethods();

-

-        m_inners = ck.getInnerClasses();

-

-        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(ClassWriter.COMPUTE_MAXS);

-            //CheckClassAdapter ch = new CheckClassAdapter(cw0);

-            MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);

-            cr0.accept(preprocess, ClassReader.SKIP_FRAMES);

-            is2.close();

-            finalWriter = cw0;

-        }

-        // The file is in the bundle

-        if (ck.isalreadyManipulated()) {

-            return origin;

-        } else {

-            return finalWriter.toByteArray();

-        }

-    }

-

-    /**

-     * Compute component type manipulation metadata.

-     * @return the manipulation metadata of the class.

-     */

-    public Element getManipulationMetadata() {

-        Element elem = new Element("Manipulation", "");

-

-        if (m_superClass != null) {

-            elem.addAttribute(new Attribute("super", m_superClass));

-        }

-

-        for (int j = 0; j < m_interfaces.size(); j++) {

-            Element itf = new Element("Interface", "");

-            Attribute att = new Attribute("name", m_interfaces.get(j).toString());

-            itf.addAttribute(att);

-            elem.addElement(itf);

-        }

-

-        for (Iterator it = m_fields.keySet().iterator(); it.hasNext();) {

-            Element field = new Element("Field", "");

-            String name = (String) it.next();

-            String type = (String) m_fields.get(name);

-            Attribute attName = new Attribute("name", name);

-            Attribute attType = new Attribute("type", type);

-            field.addAttribute(attName);

-            field.addAttribute(attType);

-            elem.addElement(field);

-        }

-

-        for (int j = 0; j < m_methods.size(); j++) {

-            MethodDescriptor method = (MethodDescriptor) m_methods.get(j);

-            elem.addElement(method.getElement());

-        }

-

-        return elem;

-    }

-

-    public Map getFields() {

-        return m_fields;

-    }

-

-    public List getInnerClasses() {

-        return m_inners;

-    }

-

-}

+/*
+ * 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.manipulation;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * iPOJO Byte code Manipulator.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class Manipulator {
+    /**
+     * Store the visited fields : [name of the field, type of the field].
+     */
+    private Map m_fields;
+
+    /**
+     * Store the interface implemented by the class.
+     */
+    private List m_interfaces;
+
+    /**
+     * Store the methods list.
+     */
+    private List m_methods;
+
+    /**
+     * Pojo super class.
+     */
+    private String m_superClass;
+
+    /**
+     * List of owned inner classed.
+     */
+    private List<String> m_inners;
+
+    /**
+     * Manipulate the given byte array.
+     * @param origin : original class.
+     * @return the manipulated class, if the class is already manipulated, the original class.
+     * @throws IOException : if an error occurs during the manipulation.
+     */
+    public byte[] manipulate(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, ClassReader.SKIP_FRAMES);
+        is1.close();
+
+        m_fields = ck.getFields(); // Get visited fields (contains only POJO fields)
+
+        // Get interfaces and super class.
+        m_interfaces = ck.getInterfaces();
+        m_superClass = ck.getSuperClass();
+
+        // Get the methods list
+        m_methods = ck.getMethods();
+
+        m_inners = ck.getInnerClasses();
+
+        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(ClassWriter.COMPUTE_MAXS);
+            //CheckClassAdapter ch = new CheckClassAdapter(cw0);
+            MethodCreator preprocess = new MethodCreator(cw0, m_fields, m_methods);
+            cr0.accept(preprocess, ClassReader.SKIP_FRAMES);
+            is2.close();
+            finalWriter = cw0;
+        }
+        // The file is in the bundle
+        if (ck.isalreadyManipulated()) {
+            return origin;
+        } else {
+            return finalWriter.toByteArray();
+        }
+    }
+
+    /**
+     * Compute component type manipulation metadata.
+     * @return the manipulation metadata of the class.
+     */
+    public Element getManipulationMetadata() {
+        Element elem = new Element("Manipulation", "");
+
+        if (m_superClass != null) {
+            elem.addAttribute(new Attribute("super", m_superClass));
+        }
+
+        for (int j = 0; j < m_interfaces.size(); j++) {
+            Element itf = new Element("Interface", "");
+            Attribute att = new Attribute("name", m_interfaces.get(j).toString());
+            itf.addAttribute(att);
+            elem.addElement(itf);
+        }
+
+        for (Iterator it = m_fields.keySet().iterator(); it.hasNext();) {
+            Element field = new Element("Field", "");
+            String name = (String) it.next();
+            String type = (String) m_fields.get(name);
+            Attribute attName = new Attribute("name", name);
+            Attribute attType = new Attribute("type", type);
+            field.addAttribute(attName);
+            field.addAttribute(attType);
+            elem.addElement(field);
+        }
+
+        for (int j = 0; j < m_methods.size(); j++) {
+            MethodDescriptor method = (MethodDescriptor) m_methods.get(j);
+            elem.addElement(method.getElement());
+        }
+
+        return elem;
+    }
+
+    public Map getFields() {
+        return m_fields;
+    }
+
+    public List<String> getInnerClasses() {
+        return m_inners;
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java
new file mode 100644
index 0000000..77596a7
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.util.jar.Manifest;
+
+/**
+ * A {@code ManifestProvider} is responsible of providing the original
+ * {@link Manifest} of the manipulated Bundle.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestProvider {
+
+    /**
+     * Returns the original bundle's Manifest.
+     * @return Manifest of the bundle
+     */
+    Manifest getManifest();
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
new file mode 100644
index 0000000..0048a13
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.ipojo.manipulation.InnerClassManipulator;
+import org.apache.felix.ipojo.manipulation.Manipulator;
+
+/**
+ * A {@code ManipulationEngine} is responsible to drive the component's
+ * classes manipulation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationEngine {
+
+    /**
+     * List of component types.
+     */
+    private List<ManipulationUnit> manipulationUnits = new ArrayList<ManipulationUnit>();
+
+    /**
+     * Error reporting.
+     */
+    private Reporter m_reporter;
+
+    /**
+     * Bytecode store.
+     */
+    private ResourceStore m_store;
+
+    /**
+     * The visitor handling output result.
+     */
+    private ManipulationVisitor manipulationVisitor;
+
+    /**
+     * Add information related to a discovered component that will be manipulated.
+     * @param component additional component
+     */
+    public void addManipulationUnit(ManipulationUnit component) {
+        manipulationUnits.add(component);
+    }
+
+    public void setManipulationVisitor(ManipulationVisitor manipulationVisitor) {
+        this.manipulationVisitor = manipulationVisitor;
+    }
+
+    /**
+     * @param reporter Feedback reporter.
+     */
+    public void setReporter(Reporter reporter) {
+        this.m_reporter = reporter;
+    }
+
+    /**
+     * Provides the bytecode store that allows to retrieve bytecode of the
+     * component's related resources (inner classes for example).
+     * @param store Helps to locate bytecode for classes.
+     */
+    public void setResourceStore(ResourceStore store) {
+        this.m_store = store;
+    }
+
+    /**
+     * Manipulates classes of all the given component's.
+     */
+    public void generate() {
+
+        // Iterates over the list of discovered components
+        // Note that this list includes components from metadata.xml AND from annotations
+
+        for (ManipulationUnit info : manipulationUnits) {
+
+            byte[] bytecode;
+            try {
+                bytecode = m_store.read(info.getResourcePath());
+            } catch (IOException e) {
+                m_reporter.error("Cannot find bytecode for class '" + info.getClassName() + "': no bytecode found.");
+                return;
+            }
+
+            // Is the visitor interested in this component ?
+            ManipulationResultVisitor result = manipulationVisitor.visitManipulationResult(info.getComponentMetadata());
+
+            if (result != null) {
+                // Should always be the case
+
+                // Manipulate the original bytecode and store the modified one
+                Manipulator manipulator = new Manipulator();
+                try {
+                    byte[] out = manipulator.manipulate(bytecode);
+                    // Call the visitor
+                    result.visitClassStructure(manipulator.getManipulationMetadata());
+                    result.visitManipulatedResource(info.getResourcePath(), out);
+                } catch (IOException e) {
+                    m_reporter.error("Cannot manipulate the class " + info.getClassName() + " : " + e.getMessage());
+                    return;
+                }
+
+
+                // Visit inner classes
+                for (String inner : manipulator.getInnerClasses()) {
+                    // Get the bytecode and start manipulation
+                    String resourcePath = inner + ".class";
+                    String outerClassInternalName = info.getClassName().replace('.', '/');
+                    byte[] innerClassBytecode;
+                    try {
+                        innerClassBytecode = m_store.read(resourcePath);
+                    } catch (IOException e) {
+                        m_reporter.error("Cannot find inner class '" + resourcePath + "'");
+                        return;
+                    }
+
+                    // Manipulate inner class
+                    try {
+                        InnerClassManipulator innerManipulator = new InnerClassManipulator(outerClassInternalName, manipulator.getFields().keySet());
+                        byte[] manipulated = innerManipulator.manipulate(innerClassBytecode);
+                        // Propagate manipulated resource
+                        result.visitManipulatedResource(resourcePath, manipulated);
+                    } catch (IOException e) {
+                        m_reporter.error("Cannot manipulate inner class '" + resourcePath + "'");
+                        return;
+                    }
+                }
+
+                // All resources have been manipulated for this component
+                result.visitEnd();
+            }
+        }
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java
new file mode 100644
index 0000000..702abfd
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Visit manipulation results.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManipulationResultVisitor {
+
+    /**
+     * Called once per visitor with the class' structure discovered during manipulation.
+     * @param structure Component's structure (discovered during manipulation, not the data from metadata.xml)
+     */
+    void visitClassStructure(Element structure);
+
+    /**
+     * Accept a manipulated resource (main component class or inner classes).
+     * @param type type name
+     * @param resource manipulated bytecode
+     */
+    void visitManipulatedResource(String type, byte[] resource);
+
+    /**
+     * Called when all resources from this manipulation result have been processed.
+     */
+    void visitEnd();
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
new file mode 100644
index 0000000..3fb4aa5
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Component Info.
+ * Represent a component type to be manipulated or already manipulated.
+ * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
+ */
+public class ManipulationUnit {
+
+    private Element m_componentMetadata;
+
+    private String m_resourcePath;
+
+    private String m_className;
+
+    /**
+     * Constructor.
+     * @param resourcePath class name
+     * @param meta component type metadata
+     */
+    public ManipulationUnit(String resourcePath, Element meta) {
+        this.m_resourcePath = resourcePath;
+        this.m_componentMetadata = meta;
+        this.m_className = Strings.asClassName(resourcePath);
+    }
+
+    /**
+     * @return Component Type metadata.
+     */
+    public Element getComponentMetadata() {
+        return m_componentMetadata;
+    }
+
+    /**
+     * @return Resource path
+     */
+    public String getResourcePath() {
+        return m_resourcePath;
+    }
+
+    /**
+     * @return Fully qualified class name
+     */
+    public String getClassName() {
+        return m_className;
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java
new file mode 100644
index 0000000..c04bd57
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Visit manipulation results.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManipulationVisitor {
+
+    /**
+     * Accept a manipulation result for the given component metadata.
+     * @param metadata component's metadata (from XML or annotations)
+     * @return a ManipulationResultVisitor if interested in theses manipulation results
+     */
+    ManipulationResultVisitor visitManipulationResult(Element metadata);
+
+    /**
+     * Visit metadata not associated with a component (ie no bytecode manipulation needed).
+     * @param metadata usually {@code instance}/{@code composite} metadata
+     */
+    void visitMetadata(Element metadata);
+
+    /**
+     * Called when all metadata have been processed.
+     */
+    void visitEnd();
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java
new file mode 100644
index 0000000..b6aecd0
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code MetadataProvider} is responsible to provide iPOJO's metadata.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface MetadataProvider {
+
+    /**
+     * Gather all the metadata.
+     * @return a list of iPOJO metadata (never return null)
+     * @throws IOException if something wet wrong during gathering.
+     */
+    List<Element> getMetadatas() throws IOException;
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
index e406c82..6c0171b 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -19,45 +19,29 @@
 package org.apache.felix.ipojo.manipulator;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.Vector;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
 
-import org.apache.felix.ipojo.manipulation.InnerClassManipulator;
-import org.apache.felix.ipojo.manipulation.Manipulator;
-import org.apache.felix.ipojo.manipulation.MethodCreator;
-import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
-import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.manipulator.manifest.FileManifestProvider;
+import org.apache.felix.ipojo.manipulator.metadata.AnnotationMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.CompositeMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.EmptyMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.FileMetadataProvider;
+import org.apache.felix.ipojo.manipulator.metadata.StreamMetadataProvider;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.reporter.SystemReporter;
+import org.apache.felix.ipojo.manipulator.store.DirectoryResourceStore;
+import org.apache.felix.ipojo.manipulator.store.JarFileResourceStore;
+import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder;
+import org.apache.felix.ipojo.manipulator.store.mapper.WABResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.manipulator.visitor.check.CheckFieldConsistencyVisitor;
+import org.apache.felix.ipojo.manipulator.visitor.writer.ManipulatedResourcesWriter;
 import org.apache.felix.ipojo.metadata.Element;
-import org.apache.felix.ipojo.xml.parser.ParseException;
 import org.apache.felix.ipojo.xml.parser.SchemaResolver;
-import org.apache.felix.ipojo.xml.parser.XMLMetadataParser;
-import org.objectweb.asm.ClassReader;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * Pojoization allows creating an iPOJO bundle from a "normal" bundle.
@@ -71,36 +55,6 @@
     public static final String IPOJO_PACKAGE_VERSION = " 1.8.0";
 
     /**
-     * List of component types.
-     */
-    private List m_components;
-
-    /**
-     * Metadata (in internal format).
-     */
-    private List/*Element*/ m_metadata = new ArrayList/*Element*/();
-
-    /**
-     * Errors which occur during the manipulation.
-     */
-    private List m_errors = new ArrayList();
-
-    /**
-     * Warnings which occur during the manipulation.
-     */
-    private List m_warnings = new ArrayList();
-
-    /**
-     * Class map (class name, byte[]).
-     */
-    private Map m_classes = new HashMap();
-
-    /**
-     * Referenced packages by the composite.
-     */
-    private List m_referredPackages;
-
-    /**
      * Flag describing if we need or not compute annotations.
      * By default, compute the annotations.
      */
@@ -109,49 +63,21 @@
     /**
      * Flag describing if we need or not use local XSD files
      * (i.e. use the {@link SchemaResolver} or not).
-     * If <code>true</code> the local XSD are not used.
+     * If <code>true</code> the local XSD are used (default to {@literal false}).
      */
-    private boolean m_ignoreLocalXSD;
+    private boolean m_useLocalXSD = false;
 
     /**
-     * Input jar file.
+     * Reporter for error reporting.
      */
-    private JarFile m_inputJar;
+    private Reporter m_reporter;
 
-    /**
-     * The manipulated directory.
-     */
-    private File m_dir;
-
-    /**
-     * The manifest location.
-     */
-    private File m_manifest;
-
-    /**
-     * Manifest attribute filter, with default iPOJO filters
-     */
-    private List/*IManifestAttributeFilter*/ m_manifestAttributeFilters = new ArrayList/*IManifestAttributeFilter*/();
-
-    /**
-     * Add an error in the error list.
-     * @param mes : error message.
-     */
-    protected void error(String mes) {
-        System.err.println(mes);
-        m_errors.add(mes);
+    public Pojoization() {
+        this(new SystemReporter());
     }
 
-    /**
-     * Add a warning in the warning list.
-     * @param mes : warning message
-     */
-    public void warn(String mes) {
-        m_warnings.add(mes);
-    }
-
-    public List getErrors() {
-        return m_errors;
+    public Pojoization(Reporter m_reporter) {
+        this.m_reporter = m_reporter;
     }
 
     /**
@@ -166,10 +92,27 @@
      * XSD files from the classloader.
      */
     public void setUseLocalXSD() {
-        m_ignoreLocalXSD = false;
+        m_useLocalXSD = true;
     }
 
     /**
+     * @return all the errors (fatal) reported by the manipulation process.
+     */
+    public List getErrors() {
+        // Simple delegation for backward compatibility
+        return m_reporter.getErrors();
+    }
+
+    /**
+     * @return all the warnings (non fatal) reported by the manipulation process.
+     */
+    public List getWarnings() {
+        // Simple delegation for backward compatibility
+        return m_reporter.getWarnings();
+    }
+
+
+    /**
      * Manipulates an input bundle.
      * This method creates an iPOJO bundle based on the given metadata file.
      * The original and final bundles must be different.
@@ -178,34 +121,41 @@
      * @param metadata the iPOJO metadata input stream.
      */
     public void pojoization(File in, File out, InputStream metadata) {
-        parseXMLMetadata(metadata);
-        if (m_metadata == null) { // An error occurs during the parsing.
-            return;
-        }
-        // m_metadata can be either an empty array or an Element
-        // array with component type description. It also can be null
-        // if no metadata file is given.
 
+        StreamMetadataProvider provider = new StreamMetadataProvider(metadata, m_reporter);
+        provider.setValidateUsingLocalSchemas(m_useLocalXSD);
+
+        ResourceStore store;
         try {
-            m_inputJar = new JarFile(in);
+            JarFile origin = new JarFile(in);
+            JarFileResourceStore jfrs = new JarFileResourceStore(origin, out);
+            if (in.getName().endsWith(".war")) {
+                // this is a war file, use the right mapper
+                jfrs.setResourceMapper(new WABResourceMapper());
+            }
+            jfrs.setManifest(origin.getManifest());
+            DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+            dmb.setMetadataRenderer(new MetadataRenderer());
+            jfrs.setManifestBuilder(dmb);
+            store = jfrs;
         } catch (IOException e) {
-            error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+            m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
             return;
         }
 
-        // Get the list of declared component
-        computeDeclaredComponents();
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
 
-        // Start the manipulation
-        manipulateJarFile(out);
+        pojoization(store, provider, visitor);
+    }
 
-        // Check that all declared components are manipulated
-        for (int i = 0; i < m_components.size(); i++) {
-            ComponentInfo ci = (ComponentInfo) m_components.get(i);
-            if (!ci.m_isManipulated) {
-                error("The component " + ci.m_classname + " is declared but not in the bundle");
-            }
-        }
+    private ManipulationVisitor createDefaultVisitorChain(ResourceStore store) {
+        ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+        writer.setReporter(m_reporter);
+        writer.setResourceStore(store);
+
+        CheckFieldConsistencyVisitor checkFieldConsistencyVisitor = new CheckFieldConsistencyVisitor(writer);
+        checkFieldConsistencyVisitor.setReporter(m_reporter);
+        return checkFieldConsistencyVisitor;
     }
 
     /**
@@ -217,31 +167,35 @@
      * @param metadataFile the iPOJO metadata file (XML).
      */
     public void pojoization(File in, File out, File metadataFile) {
-        // Get the metadata.xml location if not null
+
+        MetadataProvider provider = new EmptyMetadataProvider();
         if (metadataFile != null) {
-            parseXMLMetadata(metadataFile);
+            FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+            fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+            provider = fileMetadataProvider;
         }
 
+        ResourceStore store;
         try {
-            m_inputJar = new JarFile(in);
+            JarFile origin = new JarFile(in);
+            JarFileResourceStore jfrs = new JarFileResourceStore(origin, out);
+            if (in.getName().endsWith(".war")) {
+                // this is a war file, use the right mapper
+                jfrs.setResourceMapper(new WABResourceMapper());
+            }
+            jfrs.setManifest(origin.getManifest());
+            DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+            dmb.setMetadataRenderer(new MetadataRenderer());
+            jfrs.setManifestBuilder(dmb);
+            store = jfrs;
         } catch (IOException e) {
-            error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+            m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
             return;
         }
 
-        // Get the list of declared component
-        computeDeclaredComponents();
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
 
-        // Start the manipulation
-        manipulateJarFile(out);
-
-        // Check that all declared components are manipulated
-        for (int i = 0; i < m_components.size(); i++) {
-            ComponentInfo ci = (ComponentInfo) m_components.get(i);
-            if (!ci.m_isManipulated) {
-                error("The component " + ci.m_classname + " is declared but not in the bundle");
-            }
-        }
+        pojoization(store, provider, visitor);
     }
 
     /**
@@ -254,1021 +208,112 @@
      */
     public void directoryPojoization(File directory, File metadataFile, File manifestFile) {
     	// Get the metadata.xml location if not null
+        MetadataProvider provider = new EmptyMetadataProvider();
         if (metadataFile != null) {
-            parseXMLMetadata(metadataFile);
+            FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+            fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+            provider = fileMetadataProvider;
         }
 
-        if (directory.exists() && directory.isDirectory()) {
-            m_dir = directory;
-        } else {
-            error("The directory " + directory.getAbsolutePath() + " does not exist or is not a directory.");
-        }
-
-
+        ManifestProvider manifestProvider;
         if (manifestFile != null) {
-            if (manifestFile.exists()) {
-                m_manifest = manifestFile;
+            if (manifestFile.isFile()) {
+                try {
+                    manifestProvider = new FileManifestProvider(manifestFile);
+                } catch (IOException e) {
+                    m_reporter.error("Cannot read Manifest from '" + manifestFile.getAbsolutePath() + "'");
+                    return;
+                }
             } else {
-                error("The manifest file " + manifestFile.getAbsolutePath() + " does not exist");
+                m_reporter.error("The manifest file " + manifestFile.getAbsolutePath() + " does not exist");
+                return;
             }
-        }
-        // If the manifest is not specified, the m_dir/META-INF/MANIFEST.MF is used.
-
-        // Get the list of declared component
-        computeDeclaredComponents();
-
-        // Start the manipulation
-        manipulateDirectory();
-
-        // Check that all declared components are manipulated
-        for (int i = 0; i < m_components.size(); i++) {
-            ComponentInfo ci = (ComponentInfo) m_components.get(i);
-            if (!ci.m_isManipulated) {
-                error("The component " + ci.m_classname + " is declared but not in the bundle");
-            }
-        }
-
-    }
-
-    /**
-     * Parse the content of the class to detect annotated classes.
-     * @param inC the class to inspect.
-     */
-    private void computeAnnotations(byte[] inC) {
-        ClassReader cr = new ClassReader(inC);
-        MetadataCollector collector = new MetadataCollector();
-        cr.accept(collector, 0);
-
-        if (collector.isIgnoredBecauseOfMissingComponent()) {
-        	// No @Component, just skip.
-            //warn("Annotation processing ignored in " + collector.getClassName() + " - @Component missing");
-        } else if (collector.isComponentType()) {
-            boolean toskip = false;
-            for (int i = 0; !toskip && i < m_metadata.size(); i++) {
-                Element meta = (Element)  m_metadata.get(i);
-                if (! meta.getName().equals("instance") // Only if its a component type definition,
-                                                        // so skip instance declaration
-                        && meta.containsAttribute("name")
-                        && meta.getAttribute("name").equalsIgnoreCase(collector.getComponentTypeDeclaration().getAttribute("name"))) {
-                    toskip = true;
-                    warn("The component type " + collector.getComponentTypeDeclaration().getAttribute("name") + " is overriden by the metadata file");
-                }
-            }
-            if (!toskip) {
-                // if no metadata or empty one, create a new array.
-                Element elem = collector.getComponentTypeDeclaration();
-                m_metadata.add(elem);
-
-                String name = elem.getAttribute("classname");
-                name = name.replace('.', '/');
-                name += ".class";
-
-                // Creates the ComponentInfo and store bytecode
-                ComponentInfo info = new ComponentInfo(name, elem);
-                info.m_bytecode = inC;
-                m_components.add(info);
-
-                // Instantiate ?
-                if (collector.getInstanceDeclaration() != null) {
-                    //warn("Declaring an empty instance of " + elem.getAttribute("classname"));
-                    m_metadata.add(collector.getInstanceDeclaration());
-                }
-            }
-        }
-    }
-
-    /**
-     * Copies an input stream into an output stream but does not close the streams.
-     * @param in the input stream
-     * @param out the output stream
-     * @throws IOException if the stream cannot be copied
-     */
-    private static void copyStreamWithoutClosing(InputStream in, OutputStream out) throws IOException {
-        byte[] b = new byte[4096];
-        for (int n; (n = in.read(b)) != -1;) {
-            out.write(b, 0, n);
-        }
-    }
-
-    /**
-     * Gets the class name from the jar entry.
-     * This method handles the WAR case.
-     * @param entry the entry
-     * @return the class name
-     */
-    private String getClassNameForEntry(JarEntry entry) {
-    	// If we're manipulating a war file remove the WEB-INF/classes prefix.
-    	if (entry.getName().startsWith("WEB-INF/classes/")) {
-        	return entry.getName().substring("WEB-INF/classes/".length());
         } else {
-        	return entry.getName();
-        }
-    }
-
-    /**
-     * Manipulate the input bundle.
-     * @param out final bundle
-     */
-    private void manipulateJarFile(File out) {
-        manipulateComponents(); // Manipulate classes
-        m_referredPackages = getReferredPackages();
-        Manifest mf = doManifest(); // Compute the manifest
-
-        // Create a new Jar file
-        FileOutputStream fos = null;
-        JarOutputStream jos = null;
-        try {
-            fos = new FileOutputStream(out);
-            jos = new JarOutputStream(fos, mf);
-        } catch (FileNotFoundException e1) {
-            error("Cannot manipulate the Jar file : the output file " + out.getAbsolutePath() + " is not found");
-            return;
-        } catch (IOException e) {
-            error("Cannot manipulate the Jar file : cannot access to " + out.getAbsolutePath());
-            return;
-        }
-
-        try {
-            // Copy classes and resources
-            Enumeration entries = m_inputJar.entries();
-            while (entries.hasMoreElements()) {
-                JarEntry curEntry = (JarEntry) entries.nextElement();
-
-                // If the class was manipulated, write out the manipulated
-                // version of the bytecode
-
-                String classEntry = getClassNameForEntry(curEntry);
-                if (m_classes.containsKey(classEntry)) {
-                    JarEntry je = new JarEntry(curEntry.getName());
-                    byte[] outClazz = (byte[]) m_classes.get(classEntry);
-                    if (outClazz != null && outClazz.length != 0) {
-                        jos.putNextEntry(je); // copy the entry header to jos
-                        jos.write(outClazz);
-                        jos.closeEntry();
-                    } else { // The class is already manipulated
-                        jos.putNextEntry(curEntry);
-                        InputStream currIn = m_inputJar.getInputStream(curEntry);
-                        copyStreamWithoutClosing(currIn, jos);
-
-                        currIn.close();
-                        jos.closeEntry();
-                    }
-                } else {
-                    // Do not copy the manifest
-                    if (!curEntry.getName().equals("META-INF/MANIFEST.MF")) {
-                        // copy the entry header to jos
-                        jos.putNextEntry(curEntry);
-                        InputStream currIn = m_inputJar.getInputStream(curEntry);
-                        copyStreamWithoutClosing(currIn, jos);
-                        currIn.close();
-                        jos.closeEntry();
-                    }
+            // If the manifest is not specified, the m_dir/META-INF/MANIFEST.MF is used.
+            File metaInf = new File(directory, "META-INF");
+            File original = new File(metaInf, "MANIFEST.MF");
+            if (original.isFile()) {
+                try {
+                    manifestProvider = new FileManifestProvider(original);
+                } catch (IOException e) {
+                    m_reporter.error("Cannot read Manifest from '" + original.getAbsolutePath() + "'");
+                    return;
                 }
-            }
-        } catch (IOException e) {
-            error("Cannot manipulate the Jar file : " + e.getMessage());
-            return;
-        }
-
-        try {
-            m_inputJar.close();
-            jos.close();
-            fos.close();
-            jos = null;
-            fos = null;
-        } catch (IOException e) {
-            error("Cannot close the new Jar file : " + e.getMessage());
-            return;
-        }
-    }
-
-    /**
-     * Manipulate the input directory.
-     */
-    private void manipulateDirectory() {
-        manipulateComponents(); // Manipulate classes
-        m_referredPackages = getReferredPackages();
-        Manifest mf = doManifest(); // Compute the manifest
-        if (mf == null) {
-            error("Cannot found input manifest");
-            return;
-        }
-
-        // Write every manipulated file.
-        Iterator it = m_classes.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry entry = (Map.Entry) it.next();
-            String classname = (String) entry.getKey();
-            byte[] clazz = (byte[]) entry.getValue();
-            // The class name is already a path
-            File classFile = new File(m_dir, classname);
-            try {
-                setBytecode(classFile, clazz);
-            } catch (IOException e) {
-                error("Cannot manipulate the file : the output file " +  classname + " is not found");
+            } else {
+                m_reporter.error("The manifest file " + original.getAbsolutePath() + " does not exist");
                 return;
             }
         }
 
-        // Write manifest
-        try {
-            writeManifest(mf);
-        } catch (IOException e) {
-            error("Cannot write the manifest file : " + e.getMessage());
-        }
-
-    }
-
-    /**
-     * Manipulate classes of the input Jar.
-     */
-    private void manipulateComponents() {
-
-        // 1. Discover components described with annotations
-        // Only do this if annotations are enabled
-        if (!m_ignoreAnnotations) {
-            Enumeration entries = getClassFiles();
-
-            while (entries.hasMoreElements()) {
-                String curName = (String) entries.nextElement();
-                try {
-                    // Need to load the bytecode for each .class entry
-                    byte[] in = getBytecode(curName);
-
-                    // This method adds the class to the component list
-                    // if that bytecode is annotated with @Component.
-
-                    // We check the array size to avoid manipulating empty files
-                    // produced by incremental compilers (like Eclipse Compiler)
-                    if(in != null && in.length > 0) {
-                        computeAnnotations(in);
-                    } else {
-                        error("Cannot compute annotations from " + curName + " : Empty file");
-                    }
-                } catch (IOException e) {
-                    error("Cannot read the class : " + curName);
-                    return;
-                }
+        DirectoryResourceStore store;
+        if (directory.exists() && directory.isDirectory()) {
+            store = new DirectoryResourceStore(directory);
+            File webinf = new File(directory, "WEB-INF");
+            if (directory.getName().endsWith(".war") || webinf.isDirectory()) {
+                // this is a war file, use the right mapper
+                store.setResourceMapper(new WABResourceMapper());
             }
-        }
-
-        // 2. Iterates over the list of discovered components
-        // Note that this list includes components from metadata.xml AND from annotations
-
-        for (int i = 0; i < m_components.size(); i++) {
-            ComponentInfo info = (ComponentInfo) m_components.get(i);
-
-            // Get the bytecode if necessary
-            if (info.m_bytecode == null) {
-                try {
-                    info.m_bytecode = getBytecode(info.m_classname);
-                } catch (IOException e) {
-                    error("Cannot extract bytecode for component '" + info.m_classname + "'");
-                    return;
-                }
-            }
-            // Manipulate the original bytecode and store the modified one
-            byte[] outClazz = manipulateComponent(info.m_bytecode, info);
-            m_classes.put(info.m_classname, outClazz);
-
-            // Are there any inner classes to be manipulated ?
-            if (!info.m_inners.isEmpty()) {
-                for (int k = 0; k < info.m_inners.size(); k++) {
-                    String innerCN = (String) info.m_inners.get(k) + ".class";
-                    try {
-                        // Get the bytecode and start manipulation
-                        byte[] innerClassBytecode = getBytecode(innerCN);
-                        manipulateInnerClass(innerClassBytecode, innerCN, info);
-                    } catch (IOException e) {
-                        error("Cannot manipulate inner class '" + innerCN + "'");
-                        return;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Gets a byte array that contains the bytecode of the given classname.
-     * This method can be overridden by sub-classes.
-     * @param classname name of a class to be read
-     * @return a byte array
-     * @throws IOException if the classname cannot be read
-     */
-    protected byte[] getBytecode(final String classname) throws IOException {
-
-        InputStream currIn = null;
-        byte[] in = new byte[0];
-        try {
-            // Get the stream to read
-            currIn = getInputStream(classname);
-            int c;
-
-            // Fill the byte array with IS content
-            while ((c = currIn.read()) >= 0) {
-                byte[] in2 = new byte[in.length + 1];
-                System.arraycopy(in, 0, in2, 0, in.length);
-                in2[in.length] = (byte) c;
-                in = in2;
-            }
-        } finally {
-            // Close the stream
-            if (currIn != null) {
-                try {
-                    currIn.close();
-                } catch (IOException e) {
-                    // Ignored
-                }
-            }
-        }
-
-        return in;
-    }
-
-    /**
-     * Gets an input stream on the given class.
-     * This methods manages Jar files and directories.
-     * If also looks into WEB-INF/classes to support WAR files.
-     * This method may be overridden.
-     * @param classname the class name
-     * @return the input stream
-     * @throws IOException if the file cannot be read
-     */
-    protected InputStream getInputStream(String classname) throws IOException {
-        if (m_inputJar != null) {
-            // Fix entry name if needed
-            if (! classname.endsWith(".class")) {
-                classname += ".class";
-            }
-            JarEntry je = m_inputJar.getJarEntry(classname);
-            if (je == null) {
-            	// Try in WEB-INF/classes (WAR files)
-            	je = m_inputJar.getJarEntry("WEB-INF/classes/" + classname);
-            	if (je == null) {
-            		// If still null, throw an exception.
-            		throw new IOException("The class " + classname + " connot be found in the input Jar file");
-            	}
-            }
-            return m_inputJar.getInputStream(je);
+            store.setManifest(manifestProvider.getManifest());
+            DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+            dmb.setMetadataRenderer(new MetadataRenderer());
+            store.setManifestBuilder(dmb);
         } else {
-            // Directory
-            File file = new File(m_dir, classname);
-            return new FileInputStream(file);
+            m_reporter.error("The directory " + directory.getAbsolutePath() + " does not exist or is not a directory.");
+            return;
         }
-    }
 
-    /**
-     * Gets the list of class files.
-     * The content of the returned enumeration contains file names.
-     * It is possible to get input stream on those file by using
-     * {@link Pojoization#getInputStream(String)} method.
-     * @return the list of class files.
-     */
-    private Enumeration getClassFiles() {
-        Vector files = new Vector();
-        if (m_inputJar != null) {
-            Enumeration enumeration = m_inputJar.entries();
-            while (enumeration.hasMoreElements()) {
-                JarEntry je = (JarEntry) enumeration.nextElement();
-                if (je.getName().endsWith(".class")) {
-                    files.add(je.getName());
-                }
-            }
-        } else {
-            searchClassFiles(m_dir, files);
-        }
-        return files.elements();
-    }
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
 
-    /**
-     * Navigates across directories to find class files.
-     * Sub-classes can override this method to customize the searched
-     * files.
-     * @param dir the directory to analyze
-     * @param classes discovered classes
-     */
-    protected void searchClassFiles(File dir, List classes) {
-        File[] files = dir.listFiles();
-        for (int i = 0; i < files.length; i++) {
-            if (files[i].isDirectory()) {
-                searchClassFiles(files[i], classes);
-            } else if (files[i].getName().endsWith(".class")) {
-                classes.add(computeRelativePath(files[i].getAbsolutePath()));
-            }
-        }
-    }
-
-//    /**
-//     * Manipulates an inner class.
-//     * @param inputJar input jar
-//     * @param je inner class jar entry
-//     * @param innerClassName inner class name
-//     * @param ci component info of the component owning the inner class
-//     * @throws IOException the inner class cannot be read
-//     */
-//    private void manipulateInnerClass(JarFile inputJar, JarEntry je, String innerClassName, ComponentInfo ci) throws IOException {
-//        InputStream currIn = inputJar.getInputStream(je);
-//        byte[] in = new byte[0];
-//        int c;
-//        while ((c = currIn.read()) >= 0) {
-//            byte[] in2 = new byte[in.length + 1];
-//            System.arraycopy(in, 0, in2, 0, in.length);
-//            in2[in.length] = (byte) c;
-//            in = in2;
-//        }
-//        // Remove '.class' from class name.
-//        InnerClassManipulator man = new InnerClassManipulator(ci.m_classname.substring(0, ci.m_classname.length() - 6), ci.m_fields);
-//        byte[] out = man.manipulate(in);
-//
-//        m_classes.put(je.getName(), out);
-//
-//    }
-
-    /**
-     * Computes a relative path for the given absolute path.
-     * This methods computes the relative path according to the directory
-     * containing classes for the given class path.
-     * @param absolutePath the absolute path of the class
-     * @return the relative path of the class based on the directory containing
-     * classes.
-     */
-    private String computeRelativePath(String absolutePath) {
-        String root = m_dir.getAbsolutePath();
-        String path = absolutePath.substring(root.length() + 1);
-        return path.replace('\\', '/'); // To support Windows systems, the \ are replaced by /
-        //return path.replace('/', File.separatorChar);
-    }
-
-    /**
-     * Manipulates an inner class.
-     * @param in input bytecode of the inner file to manipulate
-     * @param cn the inner class name (ends with .class)
-     * @param ci component info of the component owning the inner class
-     * @throws IOException the inner class cannot be read
-     */
-    private void manipulateInnerClass(byte[] in, String cn, ComponentInfo ci) throws IOException {
-        // Remove '.class' from class name.
-        String name = ci.m_classname.substring(0, ci.m_classname.length() - 6);
-        InnerClassManipulator man = new InnerClassManipulator(name, ci.m_fields);
-        byte[] out = man.manipulate(in);
-
-        m_classes.put(cn, out);
+        pojoization(store, provider, visitor);
 
     }
 
-    /**
-     * Gets the manifest.
-     * This method handles Jar and directories.
-     * For Jar file, the input jar manifest is returned.
-     * For directories, if specified the specifies manifest is returned.
-     * Otherwise, try directory/META-INF/MANIFEST.MF
-     * @return the Manifest.
-     * @throws IOException if the manifest cannot be found
-     */
-    private Manifest getManifest() throws IOException {
-        if (m_inputJar != null) {
-            return m_inputJar.getManifest();
-        } else {
-            return new Manifest(getManifestInputStream());
-        }
-    }
+    public void pojoization(final ResourceStore store,
+                            final MetadataProvider metadata,
+                            final ManipulationVisitor visitor) {
 
-    /**
-     * Create the manifest.
-     * Set the bundle imports and iPOJO-components clauses
-     * @return the generated manifest.
-     */
-    private Manifest doManifest() {
-        Manifest mf = null;
+        ManipulationEngine engine = new ManipulationEngine();
+        engine.setResourceStore(store);
+        engine.setReporter(m_reporter);
+        engine.setManipulationVisitor(visitor);
+
         try {
-            mf = getManifest();
-        } catch (IOException e) {
-            // Could not happen, the input bundle is a bundle so must have a manifest.
-            error("Cannot get the manifest : " + e.getMessage());
-            return null;
-        }
-        Attributes att = mf.getMainAttributes();
-        setImports(att); // Set the imports (add ipojo and handler namespaces
-        setPOJOMetadata(att); // Add iPOJO-Component
-        setCreatedBy(att); // Add iPOJO to the creators
-        return mf;
-    }
 
-    /**
-     * Manipulate a component class.
-     * @param in : the byte array of the class to manipulate
-     * @param ci : attached component info (containing metadata and manipulation metadata)
-     * @return the generated class (byte array)
-     */
-    private byte[] manipulateComponent(byte[] in, ComponentInfo ci) {
-        Manipulator man = new Manipulator();
-        try {
-            byte[] out = man.manipulate(in); // iPOJO manipulation
-            ci.detectMissingFields(man.getFields()); // Detect missing field
-            // Insert information to metadata
-            ci.m_componentMetadata.addElement(man.getManipulationMetadata());
-            ci.m_isManipulated = true;
-            ci.m_inners = man.getInnerClasses();
-            ci.m_fields = man.getFields().keySet();
-            return out;
-        } catch (IOException e) {
-            error("Cannot manipulate the class " + ci.m_classname + " : " + e.getMessage());
-            return null;
-        }
-    }
+            // Creates a composite to store multiple metadata providers
+            CompositeMetadataProvider composite = new CompositeMetadataProvider(m_reporter);
+            composite.addMetadataProvider(metadata);
 
-    /**
-     * Return the list of "concrete" component.
-     */
-    private void computeDeclaredComponents() {
-        List componentClazzes = new ArrayList();
-        for (int i = 0; i < m_metadata.size(); i++) {
-            Element meta = (Element) m_metadata.get(i);
-            String name = meta.getAttribute("classname");
-            if (name != null) { // Only handler and component have a classname attribute
-                name = name.replace('.', '/');
-                name += ".class";
-                componentClazzes.add(new ComponentInfo(name, meta));
+            if (!m_ignoreAnnotations) {
+                composite.addMetadataProvider(new AnnotationMetadataProvider(store, m_reporter));
             }
-        }
-        m_components = componentClazzes;
-    }
 
-    /**
-     * Component Info.
-     * Represent a component type to be manipulated or already manipulated.
-     * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
-     */
-    private class ComponentInfo {
-        /**
-         * Component Type metadata.
-         */
-        Element m_componentMetadata;
+            // Get metadata
+            List<Element> metadatas = composite.getMetadatas();
 
-        /**
-         * Component Type implementation class.
-         */
-        String m_classname;
-
-        /**
-         * Is the class already manipulated.
-         */
-        boolean m_isManipulated;
-
-        /**
-         * List of inner classes of the implementation class.
-         */
-        List m_inners;
-
-        /**
-         * Set of fields of the implementation class.
-         */
-        Set m_fields;
-
-        /**
-         * Initial (unmodified) bytecode of the component's class.
-         * May be null !!
-         */
-        byte[] m_bytecode;
-
-        /**
-         * Constructor.
-         * @param cn : class name
-         * @param met : component type metadata
-         */
-        ComponentInfo(String cn, Element met) {
-            this.m_classname = cn;
-            this.m_componentMetadata = met;
-            m_isManipulated = false;
-        }
-
-        /**
-         * Detects missing fields.
-         * If a referenced field does not exist in the class
-         * the method throws an error breaking the build process.
-         * @param fields : field found in the manipulated class
-         */
-        void detectMissingFields(Map fields) {
-            // First, compute the list of referred fields
-            List list = new ArrayList();
-            computeReferredFields(list, m_componentMetadata);
-            // Then, try to find each referred field in the given field map
-            for (int i = 0; i < list.size(); i++) {
-                if (!fields.containsKey(list.get(i))) {
-                    error("The field " + list.get(i) + " is referenced in the "
-                            + "metadata but does not exist in the " + m_classname + " class");
-                }
-            }
-        }
-
-        /**
-         * Looks for 'field' attribute in the given metadata.
-         * @param list : discovered field (accumulator)
-         * @param metadata : metadata to inspect
-         */
-        private void computeReferredFields(List list, Element metadata) {
-            String field = metadata.getAttribute("field");
-            if (field != null && ! list.contains(field)) {
-                list.add(field);
-            }
-            for (int i = 0; i < metadata.getElements().length; i++) {
-                computeReferredFields(list, metadata.getElements()[i]);
-            }
-        }
-
-    }
-
-    /**
-     * Set the create-by in the manifest.
-     * @param att : manifest attribute.
-     */
-    private void setCreatedBy(Attributes att) {
-        String prev = att.getValue("Created-By");
-        if (prev == null) {
-            att.putValue("Created-By", "iPOJO " + IPOJO_PACKAGE_VERSION);
-        } else {
-            if (prev.indexOf("iPOJO") == -1) { // Avoid appending iPOJO several times
-                att.putValue("Created-By", prev + " & iPOJO " + IPOJO_PACKAGE_VERSION);
-            }
-        }
-    }
-
-    /**
-     * Add imports to the given manifest attribute list. This method add ipojo imports and handler imports (if needed).
-     * @param att : the manifest attribute list to modify.
-     */
-    private void setImports(Attributes att) {
-        Map imports = parseHeader(att.getValue("Import-Package"));
-        Map ver = new TreeMap();
-        ver.put("version", IPOJO_PACKAGE_VERSION);
-        if (!imports.containsKey("org.apache.felix.ipojo")) {
-            imports.put("org.apache.felix.ipojo", ver);
-        }
-        if (!imports.containsKey("org.apache.felix.ipojo.architecture")) {
-            imports.put("org.apache.felix.ipojo.architecture", ver);
-        }
-        if (!imports.containsKey("org.osgi.service.cm")) {
-            Map verCM = new TreeMap();
-            verCM.put("version", "1.2");
-            imports.put("org.osgi.service.cm", verCM);
-        }
-        if (!imports.containsKey("org.osgi.service.log")) {
-            Map verCM = new TreeMap();
-            verCM.put("version", "1.3");
-            imports.put("org.osgi.service.log", verCM);
-        }
-
-        // Add referred imports from the metadata
-        for (int i = 0; i < m_referredPackages.size(); i++) {
-            String pack = (String) m_referredPackages.get(i);
-            imports.put(pack, new TreeMap());
-        }
-
-        // Write imports
-        att.putValue("Import-Package", printClauses(imports, "resolution:"));
-    }
-
-    /**
-     * Add iPOJO-Components to the given manifest attribute list. This method add the iPOJO-Components header and its value (according to the metadata) to the manifest.
-     * @param att : the manifest attribute list to modify.
-     */
-    private void setPOJOMetadata(Attributes att) {
-        StringBuffer meta = new StringBuffer();
-        for (int i = 0; i < m_metadata.size(); i++) {
-            Element metadata = (Element) m_metadata.get(i);
-            meta.append(buildManifestMetadata(metadata, new StringBuffer()));
-        }
-        if (meta.length() != 0) {
-            att.putValue("iPOJO-Components", meta.toString());
-        }
-    }
-
-    /**
-     * Standard OSGi header parser. This parser can handle the format clauses ::= clause ( ',' clause ) + clause ::= name ( ';' name ) (';' key '=' value )
-     * This is mapped to a Map { name => Map { attr|directive => value } }
-     *
-     * @param value : String to parse.
-     * @return parsed map.
-     */
-    public Map parseHeader(String value) {
-        if (value == null || value.trim().length() == 0) {
-            return new HashMap();
-        }
-
-        Map result = new HashMap();
-        QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
-        char del;
-        do {
-            boolean hadAttribute = false;
-            Map clause = new HashMap();
-            List aliases = new ArrayList();
-            aliases.add(qt.nextToken());
-            del = qt.getSeparator();
-            while (del == ';') {
-                String adname = qt.nextToken();
-                if ((del = qt.getSeparator()) != '=') {
-                    if (hadAttribute) {
-                        throw new IllegalArgumentException("Header contains name field after attribute or directive: " + adname + " from " + value);
-                    }
-                    aliases.add(adname);
+            // Construct ManipulationUnits
+            // And collect non-component metadata
+            for (Element meta : metadatas) {
+                String name = Metadatas.getComponentType(meta);
+                if (name != null) {
+                    // Only handler and component have a classname attribute
+                    String path = Strings.asResourcePath(name);
+                    engine.addManipulationUnit(new ManipulationUnit(path, meta));
                 } else {
-                    String advalue = qt.nextToken();
-                    clause.put(adname, advalue);
-                    del = qt.getSeparator();
-                    hadAttribute = true;
+                    visitor.visitMetadata(meta);
                 }
             }
-            for (Iterator i = aliases.iterator(); i.hasNext();) {
-                result.put(i.next(), clause);
-            }
-        } while (del == ',');
-        return result;
-    }
-
-    /**
-     * Print a standard Map based OSGi header.
-     *
-     * @param exports : map { name => Map { attribute|directive => value } }
-     * @param allowedDirectives : list of allowed directives.
-     * @return the clauses
-     */
-    public String printClauses(Map exports, String allowedDirectives) {
-        StringBuffer sb = new StringBuffer();
-        String del = "";
-
-        for (Iterator i = exports.entrySet().iterator(); i.hasNext();) {
-            Map.Entry entry = (Map.Entry) i.next();
-            String name = (String) entry.getKey();
-            Map map = (Map) entry.getValue();
-            sb.append(del);
-            sb.append(name);
-
-            for (Iterator j = map.entrySet().iterator(); j.hasNext();) {
-                Map.Entry entry2 = (Map.Entry) j.next();
-                String key = (String) entry2.getKey();
-
-                // Skip directives we do not recognize
-                if (key.endsWith(":") && allowedDirectives.indexOf(key) < 0) {
-                    continue;
-                }
-
-                String value = (String) entry2.getValue();
-                sb.append(";");
-                sb.append(key);
-                sb.append("=");
-                boolean dirty = value.indexOf(',') >= 0 || value.indexOf(';') >= 0;
-                if (dirty) {
-                    sb.append("\"");
-                }
-                sb.append(value);
-                if (dirty) {
-                    sb.append("\"");
-                }
-            }
-            del = ", ";
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Parse the XML metadata from the given file.
-     * @param metadataFile the metadata file
-     */
-    private void parseXMLMetadata(File metadataFile) {
-    	if (metadataFile.isDirectory()) {
-    		// Traverse the directory and parse all files.
-    		File[] files = metadataFile.listFiles();
-    		for (int i = 0; i< files.length; i++) {
-    			parseXMLMetadata(files[i]);
-    		}
-    	} else if (metadataFile.getName().endsWith(".xml")) { // Detect XML by extension,
-    														  // others are ignored.
-	        try {
-	            InputStream stream = null;
-	            URL url = metadataFile.toURI().toURL();
-	            if (url == null) {
-	                warn("Cannot find the metadata file : " + metadataFile.getAbsolutePath());
-	                m_metadata = new ArrayList/*Element*/();
-	            } else {
-	                stream = url.openStream();
-	                parseXMLMetadata(stream); // m_metadata is set by the method.
-	            }
-	        } catch (MalformedURLException e) {
-	            error("Cannot open the metadata input stream from " + metadataFile.getAbsolutePath() + ": " + e.getMessage());
-	            m_metadata = null;
-	        } catch (IOException e) {
-	            error("Cannot open the metadata input stream: " + metadataFile.getAbsolutePath() + ": " + e.getMessage());
-	            m_metadata = null;
-	        }
-
-	        // m_metadata can be either an empty array or an Element
-	        // array with component type description. It also can be null
-	        // if no metadata file is given.
-    	}
-    }
-
-    /**
-     * Parses XML Metadata.
-     * @param stream metadata input stream.
-     */
-    private void parseXMLMetadata(InputStream stream) {
-        Element[] meta = null;
-        try {
-            XMLReader parser = XMLReaderFactory.createXMLReader();
-            XMLMetadataParser handler = new XMLMetadataParser();
-            parser.setContentHandler(handler);
-            parser.setFeature("http://xml.org/sax/features/validation",
-                    true);
-            parser.setFeature("http://apache.org/xml/features/validation/schema",
-                    true);
-
-            parser.setErrorHandler(handler);
-
-            if (! m_ignoreLocalXSD) {
-                parser.setEntityResolver(new SchemaResolver());
-            }
-
-            InputSource is = new InputSource(stream);
-            parser.parse(is);
-            meta = handler.getMetadata();
-            stream.close();
 
         } catch (IOException e) {
-            error("Cannot open the metadata input stream: " + e.getMessage());
-        } catch (ParseException e) {
-            error("Parsing error when parsing the XML file: " + e.getMessage());
-        } catch (SAXParseException e) {
-            error("Error during metadata parsing at line " + e.getLineNumber() + " : " + e.getMessage());
-        } catch (SAXException e) {
-            error("Parsing error when parsing (Sax Error) the XML file: " + e.getMessage());
+            m_reporter.error("Cannot load metadata " + e.getMessage());
+            return;
         }
 
-        if (meta == null || meta.length == 0) {
-            warn("Neither component types, nor instances in the XML metadata");
-        }
+        // Start the manipulation
+        engine.generate();
 
-        m_metadata.addAll(Arrays.asList(meta));
+        // Tell the visitor that we have finished
+        visitor.visitEnd();
+
     }
-
-    /**
-     * Get packages referenced by component.
-     * @return the list of referenced packages.
-     */
-    private List getReferredPackages() {
-        List referred = new ArrayList();
-        for (int i = 0; i < m_metadata.size(); i++) {
-            Element[] elems = ((Element) m_metadata.get(i)).getElements();
-            for (int j = 0; j < elems.length; j++) {
-                String att = elems[j].getAttribute("specification");
-                if (att != null) {
-                    int last = att.lastIndexOf('.');
-                    if (last != -1) {
-                        referred.add(att.substring(0, last));
-                    }
-                }
-            }
-        }
-        return referred;
-    }
-
-    /**
-     * Generate manipulation metadata.
-     * @param element : actual element.
-     * @param actual : actual manipulation metadata.
-     * @return : given manipulation metadata + manipulation metadata of the given element.
-     */
-    private StringBuffer buildManifestMetadata(Element element, StringBuffer actual) {
-    	// If the element is already here, do not re-add the element.
-        if(isInjectedElement(element)) {
-            return actual;
-        }
-
-        StringBuffer result = new StringBuffer();
-        if (element.getNameSpace() == null) {
-            result.append(actual + element.getName() + " { ");
-        } else {
-            result.append(actual + element.getNameSpace() + ":" + element.getName() + " { ");
-        }
-
-        Attribute[] atts = element.getAttributes();
-        for (int i = 0; i < atts.length; i++) {
-            Attribute current = (Attribute) atts[i];
-
-            if (current.getNameSpace() == null) {
-                result.append("$" + current.getName() + "=\"" + current.getValue() + "\" ");
-            } else {
-                result.append("$" + current.getNameSpace() + ":" + current.getName() + "=\"" + current.getValue() + "\" ");
-            }
-        }
-
-        Element[] elems = element.getElements();
-        for (int i = 0; i < elems.length; i++) {
-            result = buildManifestMetadata(elems[i], result);
-        }
-
-        result.append("}");
-        return result;
-    }
-
-    /**
-     * Checks if the given element is an iPOJO generated element from a prior treatment
-     * @return <code>true</code> if the given element was already injected by iPOJO
-     */
-    private boolean isInjectedElement(final Element element) {
-        Attribute[] atts = element.getAttributes();
-
-        if (m_manifestAttributeFilters == null) {
-            return false;
-        }
-
-        for (int i = 0; i < atts.length; i++) {
-
-            // First test : iPOJO injected elements filter
-            String value = atts[i].getValue();
-            if (value.startsWith(MethodCreator.PREFIX)
-                || value.contains("org.apache.felix.ipojo.InstanceManager")
-                || value.contains("_setInstanceManager")) {
-                    return true;
-            }
-
-            // Second test : customized filters
-            Iterator iterator = m_manifestAttributeFilters.iterator();
-            while (iterator.hasNext()) {
-                ManifestAttributeFilter filter = (ManifestAttributeFilter) iterator.next();
-                if (filter.accept(atts[i])) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Adds a Manifest attribute filter to the list
-     * @param filter The new Manifest attribute filter
-     */
-    public void addManifestAttributeFilters(final ManifestAttributeFilter filter) {
-        if (filter != null) {
-            m_manifestAttributeFilters.add(filter);
-        }
-    }
-
-    /**
-     * Retrieves an OutputStream to write in the Manifest.
-     * @return A valid output stream
-     */
-    protected void writeManifest(Manifest mf) throws IOException {
-        if (m_manifest == null) {
-            m_manifest = new File(m_dir, "META-INF/MANIFEST.MF");
-            if (! m_manifest.exists()) {
-                throw new IOException("Cannot find the manifest file : " + m_manifest.getAbsolutePath());
-            }
-        } else {
-            if (! m_manifest.exists()) {
-                throw new IOException("Cannot find the manifest file : " + m_manifest.getAbsolutePath());
-            }
-        }
-
-        mf.write(new FileOutputStream(m_manifest));
-    }
-
-    /**
-     * Retrieves an InputStream to read the Manifest.
-     * @return A valid input stream
-     */
-    protected InputStream getManifestInputStream() throws IOException {
-        if (m_manifest == null) {
-            File manFile = new File(m_dir, "META-INF/MANIFEST.MF");
-            if (manFile.exists()) {
-                return new FileInputStream(manFile);
-            } else {
-                throw new IOException("Cannot find the manifest file : " + manFile.getAbsolutePath());
-            }
-        } else {
-            if (m_manifest.exists()) {
-                return new FileInputStream(m_manifest);
-            } else {
-                throw new IOException("Cannot find the manifest file : " + m_manifest.getAbsolutePath());
-            }
-        }
-    }
-
-    /**
-     * Writes the .class raw data to the storage support
-     * @param classFile - Output .class file
-     * @param rawClass - Raw class representation
-     * @throws IOException - Something wrong occurred while writing the file
-     */
-    protected void setBytecode(final File classFile, final byte[] rawClass) throws IOException {
-        OutputStream os = new FileOutputStream(classFile);
-        os.write(rawClass);
-        os.close();
-    }
-
-    public List getWarnings() {
-        return m_warnings;
-    }
-
 }
 
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java
new file mode 100644
index 0000000..33445f0
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.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.manipulator;
+
+import java.util.List;
+
+/**
+ * A {@code Reporter} is responsible to handle feedback from within the
+ * manipulation process in order to let API consumers deal with errors
+ * and warnings.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Reporter {
+
+    /**
+     * Add aa trace message
+     * It accepts a {@link Throwable} as last argument.
+     * @param message trace message.
+     * @param args message's argument
+     */
+    void trace(String message, Object... args);
+
+    /**
+     * Add an informative message
+     * It accepts a {@link Throwable} as last argument.
+     * @param message info message.
+     * @param args message's argument
+     */
+    void info(String message, Object... args);
+
+    /**
+     * Add a message in the warning list.
+     * It accepts a {@link Throwable} as last argument.
+     * @param message warning message.
+     * @param args message's argument
+     */
+    void warn(String message, Object... args);
+
+    /**
+     * Add a message in the error list.
+     * It accepts a {@link Throwable} as last argument.
+     * @param message error message.
+     * @param args message's argument
+     */
+    void error(String message, Object... args);
+
+    /**
+     * @return all the errors (fatal) reported by the manipulation process.
+     */
+    List<String> getErrors();
+
+    /**
+     * @return all the warnings (non fatal) reported by the manipulation process.
+     */
+    List<String> getWarnings();
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
new file mode 100644
index 0000000..a3cd1f2
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.IOException;
+import java.util.jar.Manifest;
+
+/**
+ * Abstract input/output for the manipulation process.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceStore {
+
+    /**
+     * Return the bytecode of the given class name.
+     * @param path normalized resource path (format: {@literal org/objectweb/asm/Visitor.class})
+     * @return the byte array representing the given class
+     * @throws IOException if resource was not found
+     */
+    byte[] read(String path) throws IOException;
+
+    /**
+     * Browse all resources available in this store.
+     * @param visitor is called for each available resource
+     */
+    void accept(ResourceVisitor visitor);
+
+    /**
+     * Notify the store that resource will be written.
+     * @throws IOException if there was an error
+     */
+    void open() throws IOException;
+
+    /**
+     * Writes the given Element into this store.
+     * Typically a store implementation will use this to build a Manifest.
+     * @param metadata Element metadata to be inserted
+     */
+    void writeMetadata(Element metadata);
+
+    /**
+     * Notify the builder that a new resource has been built and should
+     * be stored in the resulting bundle.
+     * @param resourcePath resource name of the class (format: {@literal org/objectweb/asm/Visitor.class})
+     * @param resource content of the resource
+     * @throws IOException if there was an error storing the resource
+     */
+    void write(String resourcePath, byte[] resource) throws IOException;
+
+    /**
+     * Close the store: no methods will be called anymore on this instance.
+     * @throws IOException if close failed
+     */
+    void close() throws IOException;
+
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java
new file mode 100644
index 0000000..00d75d3
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+/**
+ * A {@code ResourceVisitor} is invoked when a potential class is
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceVisitor {
+
+    /**
+     * Visit a resource discovered in the original bundle.
+     * @param name resource's name (format: {@literal org/objectweb/asm/Visitor.class})
+     */
+    void visit(String name);
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java
new file mode 100644
index 0000000..519913d
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.manifest;
+
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ManifestProvider;
+
+/**
+ * A {@code DirectManifestProvider} simply serves an already available {@link Manifest}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DirectManifestProvider implements ManifestProvider {
+
+    /**
+     * Served Manifest.
+     */
+    private Manifest manifest;
+
+    /**
+     * Construct a provider servicing the given manifest.
+     * @param manifest Manifest to be serviced
+     */
+    public DirectManifestProvider(Manifest manifest) {
+        this.manifest = manifest;
+    }
+
+    public Manifest getManifest() {
+        return manifest;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java
new file mode 100644
index 0000000..3299d15
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.manifest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.ManifestProvider;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+
+/**
+ * A {@code FileManifestProvider} reads a {@link Manifest} from the given input {@link File}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileManifestProvider implements ManifestProvider {
+
+    /**
+     * Read manifest.
+     */
+    private Manifest manifest;
+
+    /**
+     * Read the manifest from the given input file
+     * @param resource File pointing to a Manifest file
+     * @throws IOException if there is an error during File IO operations
+     *         or if the file is not a valid manifest.
+     */
+    public FileManifestProvider(File resource) throws IOException {
+        manifest = new Manifest();
+        InputStream is = null;
+        try {
+            is = new FileInputStream(resource);
+            manifest.read(is);
+        } finally {
+            Streams.close(is);
+        }
+    }
+
+    public Manifest getManifest() {
+        return manifest;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
new file mode 100644
index 0000000..4a056cd
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.ClassReader;
+
+/**
+ * A {@code AnnotationMetadataProvider} loads iPOJO metadata from bytecode of classes.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AnnotationMetadataProvider implements MetadataProvider {
+
+    private ResourceStore store;
+
+    private Reporter reporter;
+
+    public AnnotationMetadataProvider(final ResourceStore store,
+                                      final Reporter reporter) {
+        this.store = store;
+        this.reporter = reporter;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        final List<Element> metadata = new ArrayList<Element>();
+
+
+        store.accept(new ResourceVisitor() {
+            public void visit(String name) {
+                if (name.endsWith(".class")) {
+
+                    // Read file's content
+                    byte[] data = null;
+                    try {
+                        data = store.read(name);
+                    } catch (IOException e) {
+                        reporter.warn("Cannot read content of " + name);
+                    }
+
+                    // We check the array size to avoid manipulating empty files
+                    // produced by incremental compilers (like Eclipse Compiler)
+                    if (data != null && data.length > 0) {
+                        computeAnnotations(data, metadata);
+                    } else {
+                        reporter.error("Cannot compute annotations from " + name + " : Empty file");
+                    }
+                }
+            }
+        });
+
+        return metadata;
+    }
+
+    /**
+     * Parse the content of the class to detect annotated classes.
+     * @param bytecode the class to inspect.
+     * @param metadata
+     */
+    private void computeAnnotations(byte[] bytecode, List<Element> metadata) {
+
+        ClassReader cr = new ClassReader(bytecode);
+        MetadataCollector collector = new MetadataCollector();
+        cr.accept(collector, 0);
+
+        if (collector.isIgnoredBecauseOfMissingComponent()) {
+        	// No @Component, just skip.
+            //warn("Annotation processing ignored in " + collector.getClassName() + " - @Component missing");
+        } else if (collector.isComponentType()) {
+
+            // if no metadata or empty one, create a new array.
+            metadata.add(collector.getComponentTypeDeclaration());
+
+            // Instantiate ?
+            if (collector.getInstanceDeclaration() != null) {
+                //warn("Declaring an empty instance of " + elem.getAttribute("classname"));
+                metadata.add(collector.getInstanceDeclaration());
+            }
+        }
+    }
+
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java
new file mode 100644
index 0000000..b22e2aa
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code CacheableMetadataProvider} provides simple caching methods to avoid
+ * calling {@link MetadataProvider#getMetadatas()} twice.
+ *
+ * TODO Do we really need this ? ATM it is not used ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CacheableMetadataProvider implements MetadataProvider {
+
+    /**
+     * Delegate.
+     */
+    private MetadataProvider delegate;
+
+    /**
+     * Cached elements.
+     */
+    private List<Element> cached;
+
+    public CacheableMetadataProvider(MetadataProvider delegate) {
+        this.delegate = delegate;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        // Only ask the delegate if cache is empty
+        if (cached == null) {
+            cached = new ArrayList<Element>();
+            cached.addAll(delegate.getMetadatas());
+        }
+        return cached;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java
new file mode 100644
index 0000000..87aaf8a
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code CompositeMetadataProvider} is responsible to detect duplicates
+ * component's declaration.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CompositeMetadataProvider implements MetadataProvider {
+
+    private List<MetadataProvider> providers = new ArrayList<MetadataProvider>();
+    private Reporter reporter;
+
+    public CompositeMetadataProvider(Reporter reporter) {
+        this.reporter = reporter;
+    }
+
+    public void addMetadataProvider(MetadataProvider provider) {
+        this.providers.add(provider);
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+        List<Element> metadata = new ArrayList<Element>();
+        for (MetadataProvider provider : providers) {
+
+            List<Element> loaded = provider.getMetadatas();
+
+            // Analyze each newly loaded metadata
+            // And find duplicate component definition
+
+            for (Element meta : loaded) {
+                if (isInstance(meta)) {
+                    // This is an instance, just add it to the list
+                    metadata.add(meta);
+                } else {
+                    // Handler or Component
+                    // Finds duplicate (if any)
+                    String name = getComponentName(meta);
+                    if (name != null) {
+                        if (isDuplicate(metadata, name)) {
+                            // TODO Try to add more information here, but what ?
+                            reporter.warn("The component type " + name + " is duplicated.");
+                        } else {
+                            metadata.add(meta);
+                        }
+                    } else {
+                        // no name, strange, but add it to the list
+                        metadata.add(meta);
+                    }
+                }
+            }
+        }
+        return metadata;
+    }
+
+    private boolean isDuplicate(List<Element> elements, String name) {
+        for (Element element : elements) {
+            if (!isInstance(element) && name.equals(getComponentName(element))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String getComponentName(Element element) {
+        return element.getAttribute("name");
+    }
+
+    private boolean isInstance(Element element) {
+        return "instance".equals(element.getName());
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java
new file mode 100644
index 0000000..b7b99ad
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code EmptyMetadataProvider} simply returns an empty list of Element.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EmptyMetadataProvider implements MetadataProvider {
+
+    public List<Element> getMetadatas() throws IOException {
+        // Do not use Collections.emptyList() as the manipulator
+        // adds discovered components in this list
+        // TODO maybe the manipulator can have it's own list add we simply addAll() ?
+        return new ArrayList<Element>();
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java
new file mode 100644
index 0000000..55cbc22
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code FileMetadataProvider} is responsible of loading all the {@literal .xml} files in the given directory.
+ * It also accepts a direct reference to a {@literal metadata.xml} file.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileMetadataProvider implements MetadataProvider {
+
+    /**
+     * Metadata source (file or directory).
+     */
+    private File source;
+
+    /**
+     * Feedback reporter.
+     */
+    private Reporter reporter;
+
+    /**
+     * Validate using local schemas or not ?
+     */
+    private boolean validateUsingLocalSchemas = false;
+
+    /**
+     * Constructs a metadata provider using the given source File (directory
+     * or file) to load iPOJO metadata.
+     * @param source source of the metadata
+     * @param reporter feedback reporter
+     */
+    public FileMetadataProvider(File source, Reporter reporter) {
+        this.source = source;
+        this.reporter = reporter;
+    }
+
+    public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+        this.validateUsingLocalSchemas = validateUsingLocalSchemas;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        List<Element> metadata = new ArrayList<Element>();
+        traverse(source, metadata);
+        return metadata;
+    }
+
+    private void traverse(File file, List<Element> metadata) {
+        if (file.isDirectory()) {
+            // Traverse the directory and parse all files.
+            File[] files = file.listFiles();
+            for (File child : files) {
+                traverse(child, metadata);
+            }
+        } else if (file.getName().endsWith(".xml")) { // Detect XML by extension,
+                                                      // others are ignored.
+            loadFileMetadata(file, metadata);
+        }
+
+    }
+
+    private void loadFileMetadata(File file, List<Element> metadata) {
+        try {
+            // Sanity check, should be OK, but we never know ...
+            InputStream stream = null;
+            URL url = file.toURI().toURL();
+            if (url == null) {
+                reporter.warn("Cannot find the metadata file : " + source.getAbsolutePath());
+            } else {
+                stream = url.openStream();
+                StreamMetadataProvider provider = new StreamMetadataProvider(stream, reporter);
+                provider.setValidateUsingLocalSchemas(validateUsingLocalSchemas);
+                metadata.addAll(provider.getMetadatas());
+            }
+        } catch (MalformedURLException e) {
+            reporter.error("Cannot open the metadata input stream from " + source.getAbsolutePath() + ": " + e.getMessage());
+        } catch (IOException e) {
+            reporter.error("Cannot open the metadata input stream: " + source.getAbsolutePath() + ": " + e.getMessage());
+        }
+
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java
new file mode 100644
index 0000000..8cd861b
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.xml.parser.ParseException;
+import org.apache.felix.ipojo.xml.parser.SchemaResolver;
+import org.apache.felix.ipojo.xml.parser.XMLMetadataParser;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * A {@code StreamManifestProvider} knows how to load metadata from an InputStream.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StreamMetadataProvider implements MetadataProvider {
+
+    private InputStream stream;
+
+    private Reporter reporter;
+
+    private boolean validateUsingLocalSchemas = false;
+
+    public StreamMetadataProvider(InputStream stream, Reporter reporter) {
+        this.stream = stream;
+        this.reporter = reporter;
+    }
+
+    /**
+     * Force XML schemas resolution to be performed locally
+     */
+    public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+        this.validateUsingLocalSchemas = validateUsingLocalSchemas;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        // First time we've been called: parse the XML Stream
+        List<Element> metadata = new ArrayList<Element>();
+
+        try {
+            XMLMetadataParser handler = new XMLMetadataParser();
+
+            XMLReader parser = XMLReaderFactory.createXMLReader();
+            parser.setContentHandler(handler);
+            parser.setFeature("http://xml.org/sax/features/validation", true);
+            parser.setFeature("http://apache.org/xml/features/validation/schema", true);
+            parser.setErrorHandler(handler);
+            if (validateUsingLocalSchemas) {
+                parser.setEntityResolver(new SchemaResolver());
+            }
+
+            // Parse the XML
+            InputSource is = new InputSource(stream);
+            parser.parse(is);
+            Element[] meta = handler.getMetadata();
+
+            // Add parsed metadata
+            if (meta != null) {
+                metadata.addAll(Arrays.asList(meta));
+            }
+
+            // Output a warning message if no metadata was found
+            if (meta == null || meta.length == 0) {
+                reporter.warn("Neither component types, nor instances in the XML metadata");
+            }
+
+        } catch (IOException e) {
+            reporter.error("Cannot open the metadata input stream: " + e.getMessage());
+        } catch (ParseException e) {
+            reporter.error("Parsing error when parsing the XML file: " + e.getMessage());
+        } catch (SAXParseException e) {
+            reporter.error("Error during metadata parsing at line " + e.getLineNumber() + " : " + e.getMessage());
+        } catch (SAXException e) {
+            reporter.error("Parsing error when parsing (Sax Error) the XML file: " + e.getMessage());
+        } finally {
+            Streams.close(stream);
+        }
+
+        return metadata;
+
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java
new file mode 100644
index 0000000..b5d1291
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java
@@ -0,0 +1,59 @@
+/**
+ * JOnAS: Java(TM) Open Application Server
+ * Copyright (C) 2011 Bull S.A.S.
+ * Contact: jonas-team@ow2.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ *
+ * --------------------------------------------------------------------------
+ * $Id: $
+ * --------------------------------------------------------------------------
+ */
+
+
+package org.apache.felix.ipojo.manipulator.render;
+
+import org.apache.felix.ipojo.manipulation.MethodCreator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code ManipulatedMetadataFilter} is ...
+ *
+ * @author Guillaume Sauthier
+ */
+public class ManipulatedMetadataFilter implements MetadataFilter {
+
+    public boolean accept(Element element) {
+
+        // TODO I'm sure we can do better then testing blindly all attributes
+        // iPOJO manipulated elements filter
+        for (Attribute attribute : element.getAttributes()) {
+            String value = attribute.getValue();
+
+            // Filters:
+            // * manipulated methods
+            // * fields for the InstanceManager
+            // * InstanceManager setter
+            if (value.startsWith(MethodCreator.PREFIX)
+                    || value.contains("org.apache.felix.ipojo.InstanceManager")
+                    || value.contains("_setInstanceManager")) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java
new file mode 100644
index 0000000..3bfc2a5
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.render;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Defines a filter to be tested against Element before rendering them into the Manifest.
+ * If one filter accept the element, the given Element will be filtered, other filters will be ignored.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface MetadataFilter {
+
+    /**
+     * Tests if the given {@link Element} is accepted by the filter.
+     * @param element the tested element.
+     * @return {@literal true} if the filter accept the value (element will
+     *         be omitted from the rendered metadata), {@literal false} otherwise.
+     */
+    public boolean accept(final Element element);
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java
new file mode 100644
index 0000000..e70904f
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.render;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code MetadataRenderer} renders a given {@link Element} into a String.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MetadataRenderer {
+
+    private List<MetadataFilter> filters = new ArrayList<MetadataFilter>();
+
+    public MetadataRenderer() {
+        // By default, filter metadata coming from prior manipulation.
+        this.addMetadataFilter(new ManipulatedMetadataFilter());
+    }
+
+    /**
+     * Add a metadata filter
+     * @param filter added filter
+     */
+    public void addMetadataFilter(MetadataFilter filter) {
+        this.filters.add(filter);
+    }
+
+    /**
+     * Generate manipulation metadata.
+     * @param element rendered element.
+     * @return given manipulation metadata + manipulation metadata of the given element.
+     */
+    public String render(Element element) {
+        StringBuilder builder = new StringBuilder();
+        renderElement(element, builder);
+        return builder.toString();
+    }
+
+    private void renderElement(Element element, StringBuilder builder) {
+
+    	// If the element is already here, do not re-add the element.
+        if(!isFiltered(element)) {
+
+            // Print the beginning of the element
+            startElement(element, builder);
+
+            // Render all attributes
+            for (Attribute attribute : element.getAttributes()) {
+                renderAttribute(attribute, builder);
+            }
+
+            // Render child elements
+            for (Element child : element.getElements()) {
+                renderElement(child, builder);
+            }
+
+            // Print the end of the element
+            endElement(builder);
+        }
+
+
+    }
+
+    private void startElement(Element element, StringBuilder builder) {
+        // Default namespace is empty
+        String namespace = "";
+        if (element.getNameSpace() != null) {
+            namespace = element.getNameSpace() + ":";
+        }
+
+        builder.append(namespace)
+                .append(element.getName())
+                .append(" { ");
+    }
+
+    private void endElement(StringBuilder builder) {
+        builder.append("}");
+    }
+
+    private void renderAttribute(Attribute current, StringBuilder builder) {
+
+        // Default namespace is empty
+        String namespace = "";
+        if (current.getNameSpace() != null) {
+            namespace = current.getNameSpace() + ":";
+        }
+
+        // Render the attribute
+        builder.append("$")
+                .append(namespace)
+                .append(current.getName())
+                .append("=")
+                .append(quoted(current.getValue()))
+                .append(" ");
+    }
+
+    private String quoted(String value) {
+        return "\"" + value + "\"";
+    }
+
+    /**
+     * Checks if the given element is an iPOJO generated element from a prior treatment
+     * @param element Element to be tested
+     * @return <code>true</code> if the given element was already injected by iPOJO
+     */
+    private boolean isFiltered(final Element element) {
+
+        // Iterates over all the filters and return the first positive answer (if any)
+        for (MetadataFilter filter : filters) {
+            if (filter.accept(element)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java
new file mode 100644
index 0000000..95b906d
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.reporter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Collections5;
+
+/**
+ * An {@code EmptyReporter} is the basis implementation for Reporters.
+ * It is basically a no-op implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EmptyReporter implements Reporter {
+
+    /**
+     * List of warnings
+     */
+    private List<String> warnings = new ArrayList<String>();
+
+    /**
+     * List of errors
+     */
+    private List<String> errors = new ArrayList<String>();
+
+    public void trace(String message, Object... args) {}
+
+    public void info(String message, Object... args) {}
+
+    public void warn(String message, Object... args) {}
+
+    public void error(String message, Object... args) {}
+
+    public List<String> getErrors() {
+        return errors;
+    }
+
+    public List<String> getWarnings() {
+        return warnings;
+    }
+
+    protected Object[] getMessageArguments(Object... args) {
+        Object[] params = args;
+        if (args != null && args.length > 1) {
+            if (args[args.length - 1] instanceof Throwable) {
+                // last argument is an Exception, remove it
+                params = Collections5.copyOf(args, args.length - 1);
+            }
+        }
+
+        return params;
+    }
+
+    protected Throwable getThrowable(Object... args) {
+        Throwable throwable = null;
+        if (args != null && args.length > 1) {
+            if (args[args.length - 1] instanceof Throwable) {
+                // last argument is an Exception
+                throwable = (Throwable) args[args.length - 1];
+            }
+        }
+        return throwable;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java
new file mode 100644
index 0000000..18e9310
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.reporter;
+
+import java.io.PrintStream;
+
+/**
+ * A {@code SystemReporter} reports feedback from within the manipulation process.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SystemReporter extends EmptyReporter {
+
+    /**
+     * Micro enum used to prefix messages.
+     */
+    private enum Level {
+        TRACE("#"),
+        INFO("I"),
+        WARN("W"),
+        ERROR("E");
+
+        private String value;
+
+        Level(String value) {
+            this.value = value;
+        }
+
+        public String append(String message) {
+            return value + " " + message;
+        }
+    }
+
+    /**
+     * Enable/disable trace logging.
+     */
+    private boolean enableTrace = false;
+
+    public void setEnableTrace(boolean enableTrace) {
+        this.enableTrace = enableTrace;
+    }
+
+    private void log(PrintStream stream, Level level, String formatted, Throwable throwable) {
+        // Print the message
+        stream.println(level.append(formatted));
+
+        // And the exception if any
+        if (throwable != null) {
+            throwable.printStackTrace(stream);
+        }
+    }
+
+    @Override
+    public void trace(String message, Object... args) {
+        if (enableTrace) {
+            String formatted = String.format(message, getMessageArguments(args));
+            log(System.out, Level.TRACE, formatted, getThrowable());
+        }
+    }
+
+    @Override
+    public void info(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        log(System.out, Level.INFO, formatted, getThrowable());
+    }
+
+    @Override
+    public void warn(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable throwable = getThrowable();
+        log(System.out, Level.WARN, formatted, throwable);
+
+        // Append Exception message if any
+        if (throwable != null) {
+            formatted += " ";
+            formatted += throwable.getMessage();
+        }
+        getWarnings().add(formatted);
+    }
+
+    @Override
+    public void error(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable throwable = getThrowable();
+        log(System.out, Level.ERROR, formatted, throwable);
+
+        // Append Exception message if any
+        if (throwable != null) {
+            formatted += " ";
+            formatted += throwable.getMessage();
+        }
+        getErrors().add(formatted);
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
new file mode 100644
index 0000000..a92e738
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.store.mapper.FileSystemResourceMapper;
+import org.apache.felix.ipojo.manipulator.store.mapper.IdentityResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.jar.Manifest;
+
+/**
+ * A {@link DirectoryResourceStore} knows how to read and write
+ * resources from (to respectively) a File directory.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DirectoryResourceStore implements ResourceStore {
+
+    /**
+     * Source directory where bytecode is read.
+     */
+    private File source;
+
+    /**
+     * Target directory.
+     */
+    private File target;
+
+    /**
+     * The builder of the updated manifest.
+     */
+    private ManifestBuilder manifestBuilder;
+
+    /**
+     * Original manifest to be updated.
+     */
+    private Manifest manifest;
+
+    /**
+     * Resource Mapper.
+     */
+    private ResourceMapper mapper = new FileSystemResourceMapper(new IdentityResourceMapper());
+
+    public DirectoryResourceStore(File source) {
+        this(source, source);
+    }
+
+    public DirectoryResourceStore(File source, File target) {
+        this.source = source;
+        this.target = target;
+    }
+
+    public void setResourceMapper(ResourceMapper mapper) {
+        this.mapper = new FileSystemResourceMapper(mapper);
+    }
+
+    public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+        this.manifestBuilder = manifestBuilder;
+    }
+
+    public void setManifest(Manifest manifest) {
+        this.manifest = manifest;
+    }
+
+    public byte[] read(String path) throws IOException {
+        File resource = new File(source, mapper.internalize(path));
+        if (!resource.isFile()) {
+            throw new IOException("File '" + resource + "' is not found (for class " + path + ").");
+        }
+        return Streams.readBytes(new FileInputStream(resource));
+    }
+
+    public void accept(ResourceVisitor visitor) {
+        traverseDirectory(source, visitor);
+    }
+
+    private void traverseDirectory(File directory, ResourceVisitor visitor) {
+        for (File child : directory.listFiles()) {
+            if (child.isDirectory()) {
+                traverseDirectory(child, visitor);
+            } else {
+                visitor.visit(getRelativeName(child));
+            }
+        }
+    }
+
+    private String getRelativeName(File file) {
+        String relative = file.getPath().substring(source.getPath().length());
+        return mapper.externalize(relative);
+    }
+
+    public void open() throws IOException {
+
+        // Update the manifest
+        Manifest updated = manifestBuilder.build(manifest);
+
+        // Write it on disk
+        File metaInf = new File(target, "META-INF");
+        File resource = new File(metaInf, "MANIFEST.MF");
+        OutputStream os = new FileOutputStream(resource);
+        try {
+            updated.write(os);
+        } finally {
+            Streams.close(os);
+        }
+
+    }
+
+    public void writeMetadata(Element metadata) {
+        manifestBuilder.addMetada(Collections.singletonList(metadata));
+        manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+    }
+
+    public void write(String resourcePath, byte[] bytecode) throws IOException {
+
+        // Internalize the name
+        File resource = new File(target, mapper.internalize(resourcePath));
+
+        // Create intermediate directories if needed
+        if (!resource.getParentFile().exists()) {
+            resource.getParentFile().mkdirs();
+        }
+
+        FileOutputStream fos = new FileOutputStream(resource);
+        try {
+            fos.write(bytecode);
+            fos.flush();
+        } finally {
+            Streams.close(fos);
+        }
+    }
+
+    public void close() throws IOException {
+        // Nothing to do
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java
new file mode 100644
index 0000000..c9fd3e5
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.store.mapper.IdentityResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+/**
+ * A {@link JarFileResourceStore} knows how to read and write
+ * resources from (to respectively) a Jar File.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class JarFileResourceStore implements ResourceStore {
+
+    /**
+     * Source Jar.
+     */
+    private JarFile source;
+
+    /**
+     * Target File.
+     */
+    private File target;
+
+    /**
+     * Modified resources.
+     */
+    private Map<String, byte[]> content;
+
+    /**
+     * Resource Mapper.
+     */
+    private ResourceMapper mapper = new IdentityResourceMapper();
+
+    /**
+     * The builder of the updated manifest.
+     */
+    private ManifestBuilder manifestBuilder;
+
+    /**
+     * Original manifest to be updated.
+     */
+    private Manifest manifest;
+
+    /**
+     * Construct a {@link JarFileResourceStore} wrapping the given original bundle,
+     * and configured to output in the given target file.
+     * @param source original Bundle
+     * @param target File where the updated Bundle will be outputted
+     * @throws IOException if there is an error retrieving the Manifest from the original JarFile
+     */
+    public JarFileResourceStore(JarFile source, File target) throws IOException {
+        this.source = source;
+        this.target = target;
+
+        // TODO ensure File is not null and not an existing file/directory
+        this.target = target;
+        if (source != null) {
+            this.manifest = source.getManifest();
+        } else {
+            this.manifest = new Manifest();
+        }
+        this.content = new TreeMap<String, byte[]>();
+    }
+
+    public void setResourceMapper(ResourceMapper mapper) {
+        this.mapper = mapper;
+    }
+
+    public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+        this.manifestBuilder = manifestBuilder;
+    }
+
+    public void setManifest(Manifest manifest) {
+        this.manifest = manifest;
+    }
+
+    public byte[] read(String path) throws IOException {
+        ZipEntry entry = source.getEntry(getInternalPath(path));
+        if (entry == null) {
+            throw new IOException("Jar Entry is not found for class " + path + ".");
+        }
+        return Streams.readBytes(source.getInputStream(entry));
+    }
+
+    private String getInternalPath(String path) {
+        return mapper.internalize(path);
+    }
+
+    public void accept(ResourceVisitor visitor) {
+        List<JarEntry> entries = Collections.list(source.entries());
+        for (JarEntry entry : entries) {
+            String name = entry.getName();
+            if (!name.endsWith("/")) {
+                // Do not visit directories
+                visitor.visit(getExternalName(entry.getName()));
+            }
+        }
+    }
+
+    private String getExternalName(String path) {
+        return mapper.externalize(path);
+    }
+
+    public void open() throws IOException {
+        // Nothing to do
+    }
+
+    public void writeMetadata(Element metadata) {
+        manifestBuilder.addMetada(Collections.singletonList(metadata));
+        manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+    }
+
+    public void write(String resourcePath, byte[] resource) throws IOException {
+        this.content.put(resourcePath, resource);
+    }
+
+    public void close() throws IOException {
+
+        // Update the manifest
+        Manifest updated = manifestBuilder.build(manifest);
+
+        // Create a new Jar file
+        FileOutputStream fos = new FileOutputStream(target);
+        JarOutputStream jos = new JarOutputStream(fos, updated);
+
+        try {
+            // Copy classes and resources
+            List<JarEntry> entries = Collections.list(source.entries());
+            for (JarEntry entry : entries) {
+
+                // Ignore some entries (MANIFEST, ...)
+                if (isIgnored(entry)) {
+                    continue;
+                }
+
+                if (isUpdated(entry)) {
+                    // Write newer/updated resource (manipulated classes, ...)
+
+                    JarEntry je = new JarEntry(entry.getName());
+                    byte[] data = content.get(getInternalPath(entry.getName()));
+                    jos.putNextEntry(je);
+                    jos.write(data);
+                    jos.closeEntry();
+                } else {
+                    // Copy the resource as-is
+
+                    jos.putNextEntry(entry);
+                    InputStream is = source.getInputStream(entry);
+                    try {
+                        Streams.transfer(is, jos);
+                    } finally {
+                        Streams.close(is);
+                    }
+
+                    jos.closeEntry();
+
+                }
+            }
+        } finally {
+            try {
+                source.close();
+            } catch (IOException e) {
+                // Ignored
+            }
+            Streams.close(jos, fos);
+
+        }
+    }
+
+    private boolean isUpdated(JarEntry entry) {
+        // Check if that class was manipulated
+        if (entry.getName().endsWith(".class")) {
+            // Need to map this into an external+normalized path
+            String cleaned = getExternalName(entry.getName());
+            return content.containsKey(cleaned);
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isIgnored(JarEntry entry) {
+        return "META-INF/MANIFEST.MF".equals(entry.getName());
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java
new file mode 100644
index 0000000..f33aab5
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.render.MetadataFilter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code ManifestBuilder} is ...
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestBuilder {
+    /**
+     * Add all given package names in the referred packages list
+     * @param packageNames additional packages
+     */
+    void addReferredPackage(Set<String> packageNames);
+
+    /**
+     * Add all given metadata
+     * @param metadatas additional metadata
+     */
+    void addMetada(Collection<Element> metadatas);
+
+    /**
+     * Update the given manifest.
+     * @param original original manifest to be modified
+     * @return modified manifest
+     */
+    Manifest build(Manifest original);
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java
new file mode 100644
index 0000000..3003ba8
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+/**
+ * A {@code ResourceMapper} maps resource name from a reference to another one.
+ * Example: In a WAB, class names are to be mapped into {@literal WEB-INF/classes/}.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ResourceMapper {
+
+    /**
+     * Adapts the normalized resource name into internal format.
+     * @param name original class names (as a resource)
+     * @return the transformed resource's name
+     */
+    String internalize(String name);
+
+    /**
+     * Provides a normalized resource name from the store's internal format.
+     * @param name resource name in internal format
+     * @return normalized resource name
+     */
+    String externalize(String name);
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java
new file mode 100644
index 0000000..c6e7902
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store.builder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.QuotedTokenizer;
+import org.apache.felix.ipojo.manipulator.render.MetadataRenderer;
+import org.apache.felix.ipojo.manipulator.store.ManifestBuilder;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * A {@code DefaultManifestBuilder} handles the knowledge of iPOJO Manifest building.
+ * It is responsible to update a given Manifest with all gathered (additional)
+ * referenced packages (from the metadata.xml) + other iPOJO specific additions.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DefaultManifestBuilder implements ManifestBuilder {
+
+    /**
+     * Referenced packages (by the composites).
+     */
+    private List<String> m_referredPackages = new ArrayList<String>();
+
+    /**
+     * Computed metadatas from the bundle (XML files + annotations).
+     */
+    private List<Element> m_metadata = new ArrayList<Element>();
+
+    /**
+     * The metadata renderer used to print Elements.
+     */
+    private MetadataRenderer renderer;
+
+    /**
+     * Add all given package names in the referred packages list
+     * @param packageNames additional packages
+     */
+    public void addReferredPackage(Set<String> packageNames) {
+        m_referredPackages.addAll(packageNames);
+    }
+
+    /**
+     * Add all given metadata
+     * @param metadatas additional metadata
+     */
+    public void addMetada(Collection<Element> metadatas) {
+        m_metadata.addAll(metadatas);
+    }
+
+    public void setMetadataRenderer(MetadataRenderer renderer) {
+        this.renderer = renderer;
+    }
+
+    /**
+     * Update the given manifest.
+     * @param original original manifest to be modified
+     * @return modified manifest
+     */
+    public Manifest build(final Manifest original) {
+        Attributes att = original.getMainAttributes();
+
+         // Set the imports (add ipojo and handler namespaces
+        setImports(att);
+         // Add iPOJO-Component
+        setPOJOMetadata(att);
+         // Add iPOJO to the creators
+        setCreatedBy(att);
+
+        return original;
+    }
+
+    /**
+     * Add imports to the given manifest attribute list. This method add ipojo imports and handler imports (if needed).
+     * @param att : the manifest attribute list to modify.
+     */
+    private void setImports(Attributes att) {
+        Map imports = parseHeader(att.getValue("Import-Package"));
+        Map ver = new TreeMap();
+        ver.put("version", Pojoization.IPOJO_PACKAGE_VERSION);
+        if (!imports.containsKey("org.apache.felix.ipojo")) {
+            imports.put("org.apache.felix.ipojo", ver);
+        }
+        if (!imports.containsKey("org.apache.felix.ipojo.architecture")) {
+            imports.put("org.apache.felix.ipojo.architecture", ver);
+        }
+        if (!imports.containsKey("org.osgi.service.cm")) {
+            Map verCM = new TreeMap();
+            verCM.put("version", "1.2");
+            imports.put("org.osgi.service.cm", verCM);
+        }
+        if (!imports.containsKey("org.osgi.service.log")) {
+            Map verCM = new TreeMap();
+            verCM.put("version", "1.3");
+            imports.put("org.osgi.service.log", verCM);
+        }
+
+        // Add referred imports from the metadata
+        for (int i = 0; i < m_referredPackages.size(); i++) {
+            String pack = m_referredPackages.get(i);
+            imports.put(pack, new TreeMap());
+        }
+
+        // Write imports
+        att.putValue("Import-Package", printClauses(imports, "resolution:"));
+    }
+
+    /**
+     * Add iPOJO-Components to the given manifest attribute list. This method add the
+     * {@literal iPOJO-Components} header and its value (according to the metadata)
+     * to the manifest.
+     * @param att the manifest attribute list to modify.
+     */
+    private void setPOJOMetadata(Attributes att) {
+        StringBuilder meta = new StringBuilder();
+        for (Element metadata : m_metadata) {
+            meta.append(renderer.render(metadata));
+        }
+        if (meta.length() != 0) {
+            att.putValue("iPOJO-Components", meta.toString());
+        }
+    }
+
+    /**
+     * Set the create-by in the manifest.
+     * @param att : manifest attribute.
+     */
+    private void setCreatedBy(Attributes att) {
+        String prev = att.getValue("Created-By");
+        if (prev == null) {
+            att.putValue("Created-By", "iPOJO " + Pojoization.IPOJO_PACKAGE_VERSION);
+        } else {
+            if (prev.indexOf("iPOJO") == -1) {
+                // Avoid appending iPOJO several times
+                att.putValue("Created-By", prev + " & iPOJO " + Pojoization.IPOJO_PACKAGE_VERSION);
+            }
+        }
+    }
+
+    /**
+     * Standard OSGi header parser. This parser can handle the format
+     * <pre>
+     * clauses ::= clause ( ',' clause ) +
+     * clause ::= name ( ';' name ) (';' key '=' value )
+     * </pre>
+     * This is mapped to a Map { name => Map { attr|directive => value } }
+     *
+     * @param value String to parse.
+     * @return parsed map.
+     */
+    private Map parseHeader(String value) {
+        if (value == null || value.trim().length() == 0) {
+            return new HashMap();
+        }
+
+        Map result = new HashMap();
+        QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
+        char del;
+        do {
+            boolean hadAttribute = false;
+            Map clause = new HashMap();
+            List aliases = new ArrayList();
+            aliases.add(qt.nextToken());
+            del = qt.getSeparator();
+            while (del == ';') {
+                String adname = qt.nextToken();
+                if ((del = qt.getSeparator()) != '=') {
+                    if (hadAttribute) {
+                        throw new IllegalArgumentException("Header contains name field after attribute or directive: " + adname + " from " + value);
+                    }
+                    aliases.add(adname);
+                } else {
+                    String advalue = qt.nextToken();
+                    clause.put(adname, advalue);
+                    del = qt.getSeparator();
+                    hadAttribute = true;
+                }
+            }
+            for (Iterator i = aliases.iterator(); i.hasNext();) {
+                result.put(i.next(), clause);
+            }
+        } while (del == ',');
+        return result;
+    }
+
+    /**
+     * Print a standard Map based OSGi header.
+     *
+     * @param exports : map { name => Map { attribute|directive => value } }
+     * @param allowedDirectives list of allowed directives.
+     * @return the clauses
+     */
+    private String printClauses(Map exports, String allowedDirectives) {
+        StringBuffer sb = new StringBuffer();
+        String del = "";
+
+        for (Iterator i = exports.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            String name = (String) entry.getKey();
+            Map map = (Map) entry.getValue();
+            sb.append(del);
+            sb.append(name);
+
+            for (Iterator j = map.entrySet().iterator(); j.hasNext();) {
+                Map.Entry entry2 = (Map.Entry) j.next();
+                String key = (String) entry2.getKey();
+
+                // Skip directives we do not recognize
+                if (key.endsWith(":") && allowedDirectives.indexOf(key) < 0) {
+                    continue;
+                }
+
+                String value = (String) entry2.getValue();
+                sb.append(";");
+                sb.append(key);
+                sb.append("=");
+                boolean dirty = value.indexOf(',') >= 0 || value.indexOf(';') >= 0;
+                if (dirty) {
+                    sb.append("\"");
+                }
+                sb.append(value);
+                if (dirty) {
+                    sb.append("\"");
+                }
+            }
+            del = ", ";
+        }
+        return sb.toString();
+    }
+
+
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
new file mode 100644
index 0000000..a571473
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+
+import java.io.File;
+
+/**
+ * ResourceMapper mapping from and to system specific path..
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FileSystemResourceMapper implements ResourceMapper {
+
+    private ResourceMapper delegate;
+    private char separator;
+
+    public FileSystemResourceMapper(ResourceMapper delegate) {
+        this(delegate, File.separatorChar);
+    }
+
+    public FileSystemResourceMapper(ResourceMapper delegate, char separator) {
+        this.delegate = delegate;
+        this.separator = separator;
+    }
+
+    public String internalize(String name) {
+        // transform as system path the result of the internalization operation
+        return systemPath(delegate.internalize(name));
+    }
+
+    public String externalize(String name) {
+        // normalize he path before giving it to the delegate mapper
+        return delegate.externalize(normalizePath(name));
+    }
+
+    /**
+     * Normalize the given path. Normalization simply replace any
+     * File separator (system dependant) with {@literal '/'}.
+     * @param path system path
+     * @return normalized path
+     */
+    private String normalizePath(String path) {
+        return path.replace(separator, '/');
+    }
+
+    /**
+     * Return a system path from the given normalized path.
+     * @param path normalized path
+     * @return system path
+     */
+    private String systemPath(String path) {
+        return path.replace('/', separator);
+    }
+
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java
new file mode 100644
index 0000000..340981d
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * Identity mapper.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class IdentityResourceMapper implements ResourceMapper {
+    public String internalize(String name) {
+        return name;
+    }
+
+    public String externalize(String name) {
+        return name;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java
new file mode 100644
index 0000000..73fb4d5
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * A {@code WABResourceMapper} knows how to map resource names for a Web Application Bundle (WAB).
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ * TODO It is not actually used by default, that will probably lead to some Exception
+ */
+public class WABResourceMapper implements ResourceMapper {
+
+    public static final String WEB_INF_CLASSES = "WEB-INF/classes/";
+
+    public String internalize(String name) {
+        return WEB_INF_CLASSES + name;
+    }
+
+    public String externalize(String name) {
+        if (name.startsWith(WEB_INF_CLASSES)) {
+            return name.substring(WEB_INF_CLASSES.length());
+        } else {
+            throw new IllegalArgumentException("Path '" + name + "' do not start with '" + WEB_INF_CLASSES + "'");
+        }
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
new file mode 100644
index 0000000..fe95631
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.util;
+
+import java.lang.reflect.Array;
+
+/**
+ * {@code Collections5} is a static collection of methods being part of the Java6 Collections class.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Collections5 {
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static <T> T[] copyOf(T[] original, int newLength) {
+        return (T[]) copyOf(original, newLength, original.getClass());
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of the class <tt>newType</tt>.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @param newType the class of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws ArrayStoreException if an element copied from
+     *     <tt>original</tt> is not of a runtime type that can be stored in
+     *     an array of class <tt>newType</tt>
+     * @since 1.6
+     */
+    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
+        T[] copy = ((Object) newType == (Object) Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
new file mode 100644
index 0000000..94f1c2e
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.util;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * {@code Streams} is a utility class that helps to manipulate streams.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Metadatas {
+
+    /**
+     * Utility class: no public constructor
+     */
+    private Metadatas() {}
+
+    /**
+     * Return the {@literal classname} attribute value.
+     * @param meta metadata to be explored
+     * @return the {@literal classname} attribute value or {@literal null} if
+     *         the attribute does not exists.
+     */
+    public static String getComponentType(Element meta) {
+        return meta.getAttribute("classname");
+    }
+
+    /**
+     * Looks for 'field' attribute in the given metadata.
+     * @param fields discovered fields (accumulator)
+     * @param metadata metadata to inspect
+     */
+    public static void findFields(List<String> fields, Element metadata) {
+        String field = metadata.getAttribute("field");
+        if (field != null && !fields.contains(field)) {
+            fields.add(field);
+        }
+        for (Element element : metadata.getElements()) {
+            findFields(fields, element);
+        }
+    }
+
+    /**
+     * Get packages referenced by component.
+     * @param metadata Element base for the search
+     * @return the Set of referenced packages.
+     */
+    public static Set<String> findReferredPackages(Element metadata) {
+
+        Set<String> packages = new HashSet<String>();
+        Set<String> specifications = findAttributes(metadata, "specification");
+
+        // Extract the package name from each specification (aka interface)
+        for (String specification : specifications) {
+            String name = getPackageName(specification);
+            if (name != null) {
+                packages.add(name);
+            }
+        }
+
+        return packages;
+    }
+
+    private static String getPackageName(String specification) {
+        int last = specification.lastIndexOf('.');
+        if (last != -1) {
+            return specification.substring(0, last);
+        }
+        return null;
+    }
+
+    /**
+     * Find all the values of the specified attribute in the given element.
+     * @param metadata Element to be traversed
+     * @param attributeName Search attribute name
+     * @return Set of attribute values (no duplicate).
+     */
+    public static Set<String> findAttributes(Element metadata, String attributeName) {
+        Set<String> referred = new HashSet<String>();
+
+        // Search in the given element
+        if (metadata.containsAttribute(attributeName)) {
+            referred.add(metadata.getAttribute(attributeName));
+        }
+
+        // Search in children
+        for (Element elem : metadata.getElements()) {
+            Set<String> found = findAttributes(elem, attributeName);
+            referred.addAll(found);
+        }
+
+        // Return all found values
+        return referred;
+    }
+
+
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java
new file mode 100644
index 0000000..0edb0ce
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * {@code Streams} is a utility class that helps to manipulate streams.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Streams {
+
+    private static final int ONE_HUNDRED_KB = 102400;
+
+    private static final int FOUR_KB = 4096;
+
+    /**
+     * Utility class: no public constructor
+     */
+    private Streams() {}
+
+    /**
+     * Close all the streams
+     * @param streams Streams to be closed
+     */
+    public static void close(Closeable... streams) {
+        for (Closeable stream : streams) {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    // Ignored
+                }
+            }
+        }
+    }
+
+    /**
+     * Transfer the given {@link InputStream} content in the given {@link OutputStream}.
+     * @param is input
+     * @param os output
+     * @throws IOException if there is a transfer error.
+     */
+    public static void transfer(InputStream is, OutputStream os) throws IOException {
+        int read;
+        byte[] buffer = new byte[FOUR_KB];
+        while ((read = is.read(buffer)) != -1) {
+            os.write(buffer, 0, read);
+        }
+    }
+
+    /**
+     * Read the content of the given InputStream as a byte array.
+     * Notice that this method automatically closes the InputStream
+     * @param is source
+     * @return the content of the InputStream
+     * @throws IOException if stream's content cannot be read/written
+     */
+    public static byte[] readBytes(final InputStream is) throws IOException {
+        try {
+            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+            int read;
+            byte[] data = new byte[ONE_HUNDRED_KB];
+
+            while ((read = is.read(data, 0, data.length)) != -1) {
+                buffer.write(data, 0, read);
+            }
+
+            buffer.flush();
+
+            return buffer.toByteArray();
+        } finally {
+            close(is);
+        }
+
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java
new file mode 100644
index 0000000..68357de
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.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.manipulator.util;
+
+import java.io.File;
+
+/**
+ * {@code Strings} is a utility class that helps to manipulate String.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Strings {
+
+    /**
+     * Utility class: no public constructor
+     */
+    private Strings() {}
+
+    /**
+     * Transform a FQN of a class (format {@literal org.objectweb.asm.Visitor}) into
+     * a normalized resource name ({@literal org/objectweb/asm/Visitor.class}).
+     * @param classname FQN of a class to be transformed
+     * @return resource name
+     */
+    public static String asResourcePath(String classname) {
+        return classname.replace('.', '/').concat(".class");
+    }
+
+    /**
+     * Transform a normalized resource path ({@literal org/objectweb/asm/Visitor.class}) into
+     * a fully qualified class name (format {@literal org.objectweb.asm.Visitor}).
+     * @param path normalized resource path to be transformed
+     * @return class name
+     */
+    public static String asClassName(String path) {
+        String transformed = path.replace('/', '.');
+        return transformed.substring(0, transformed.length() - ".class".length());
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java
new file mode 100644
index 0000000..08934c3
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Empty ManipulationVisitor visitor.
+ * It is useful to extends this class to keep a working visitor chain.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationAdapter implements ManipulationVisitor {
+
+    private ManipulationVisitor delegate;
+
+    public ManipulationAdapter(ManipulationVisitor delegate) {
+        this.delegate = delegate;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        return new ManipulationResultAdapter(delegate.visitManipulationResult(metadata));
+    }
+
+    public void visitMetadata(Element metadata) {
+        delegate.visitMetadata(metadata);
+    }
+
+    public void visitEnd() {
+        delegate.visitEnd();
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java
new file mode 100644
index 0000000..237d3a4
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Empty ManipulationResultVisitor visitor.
+ * It is useful to extends this class to keep a working visitor chain.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulationResultAdapter implements ManipulationResultVisitor {
+
+    private ManipulationResultVisitor delegate;
+
+    public ManipulationResultAdapter(ManipulationResultVisitor delegate) {
+        this.delegate = delegate;
+    }
+
+    public void visitClassStructure(Element structure) {
+        delegate.visitClassStructure(structure);
+    }
+
+    public void visitManipulatedResource(String type, byte[] resource) {
+        delegate.visitManipulatedResource(type, resource);
+    }
+
+    public void visitEnd() {
+        delegate.visitEnd();
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java
new file mode 100644
index 0000000..00d2055
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.check;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.util.Metadatas;
+import org.apache.felix.ipojo.manipulator.visitor.ManipulationResultAdapter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This visitor checks that field referenced in the metadata are present in the bytecode.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CheckFieldConsistencyResultVisitor extends ManipulationResultAdapter {
+
+    /**
+     * Component's metadata.
+     */
+    private Element metadata;
+
+    /**
+     * Reporter for errors.
+     */
+    private Reporter reporter;
+
+    public CheckFieldConsistencyResultVisitor(ManipulationResultVisitor visitor) {
+        super(visitor);
+    }
+
+    public void setMetadata(Element metadata) {
+        this.metadata = metadata;
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.reporter = reporter;
+    }
+
+    public void visitClassStructure(Element structure) {
+
+        List<String> fieldsInStructure = new ArrayList<String>();
+        collectStructuralFields(fieldsInStructure, structure);
+
+        List<String> fieldsInMetadata = new ArrayList<String>();
+        Metadatas.findFields(fieldsInMetadata, metadata);
+
+        checkReferredFieldsAreInStructure(fieldsInMetadata, fieldsInStructure);
+
+        // Do this at the end because the writer insert the manipulation
+        // metadata inside the component Element
+        // So to avoid duplicate find, we need to execute this code at the end
+        super.visitClassStructure(structure);
+
+    }
+
+    private void collectStructuralFields(List<String> fieldsInStructure, Element structure) {
+        Element[] fields = structure.getElements("field");
+        if (fields != null) {
+            for (Element field : fields) {
+                fieldsInStructure.add(field.getAttribute("name"));
+            }
+        }
+    }
+
+    /**
+     * Detects missing fields.
+     * If a referenced field does not exist in the class
+     * the method throws an error breaking the build process.
+     * @param fieldsInMetadata
+     * @param fieldsInStructure
+     */
+    private void checkReferredFieldsAreInStructure(List<String> fieldsInMetadata, List<String> fieldsInStructure) {
+        // Then, try to find each referred field in the given field map
+        for (String fieldName : fieldsInMetadata) {
+            if (!fieldsInStructure.contains(fieldName)) {
+                reporter.error("The field " + fieldName + " is referenced in the "
+                        + "metadata but does not exist in the " + Metadatas.getComponentType(metadata)
+                        + " class");
+            }
+        }
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java
new file mode 100644
index 0000000..149834a
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.check;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.visitor.ManipulationAdapter;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Execute field verification.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CheckFieldConsistencyVisitor extends ManipulationAdapter {
+
+    private Reporter reporter;
+
+    public CheckFieldConsistencyVisitor(ManipulationVisitor visitor) {
+        super(visitor);
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.reporter = reporter;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        CheckFieldConsistencyResultVisitor rv = new CheckFieldConsistencyResultVisitor(super.visitManipulationResult(metadata));
+        rv.setMetadata(metadata);
+        rv.setReporter(reporter);
+        return rv;
+    }
+
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java
new file mode 100644
index 0000000..d89eb00
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.writer;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.ManipulationVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Write manipulation result in the backend (store).
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulatedResourcesWriter implements ManipulationVisitor {
+
+    private ResourceStore resourceStore;
+    private Reporter reporter;
+    private List<ManipulatedResultWriter> writers;
+
+    public ManipulatedResourcesWriter() {
+        this.writers = new ArrayList<ManipulatedResultWriter>();
+    }
+
+    public void setResourceStore(ResourceStore resourceStore) {
+        this.resourceStore = resourceStore;
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.reporter = reporter;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        this.resourceStore.writeMetadata(metadata);
+        ManipulatedResultWriter writer = new ManipulatedResultWriter(metadata);
+        writers.add(writer);
+        return writer;
+    }
+
+    public void visitMetadata(Element metadata) {
+        this.resourceStore.writeMetadata(metadata);
+    }
+
+    public void visitEnd() {
+
+        try {
+            resourceStore.open();
+            for (ManipulatedResultWriter writer : writers) {
+                for (Map.Entry<String, byte[]> entry : writer.getResources().entrySet()) {
+                    resourceStore.write(entry.getKey(), entry.getValue());
+                }
+            }
+            resourceStore.close();
+        } catch (IOException e) {
+            reporter.error("Cannot store manipulation result: " + e.getMessage());
+        }
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java
new file mode 100644
index 0000000..5710969
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.writer;
+
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Gather manipulated bytecode.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ManipulatedResultWriter implements ManipulationResultVisitor {
+
+    private Map<String, byte[]> resources;
+
+    private Element component;
+
+    public ManipulatedResultWriter(Element component) {
+        this.component = component;
+        resources = new HashMap<String, byte[]>();
+    }
+
+    public void visitClassStructure(Element structure) {
+        // Insert the manipulation structure in the component's metadata
+        component.addElement(structure);
+    }
+
+    public void visitManipulatedResource(String type, byte[] resource) {
+        this.resources.put(type, resource);
+    }
+
+    public void visitEnd() {
+        // nothing to do
+    }
+
+    public Map<String, byte[]> getResources() {
+        return resources;
+    }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
index 9edd5cb..2f46217 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -1,4 +1,4 @@
-/* 

+/*
  * 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

@@ -29,7 +29,7 @@
 

 /**

  * XML Metadata parser.

- * 

+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

  */

 public class XMLMetadataParser implements ContentHandler, ErrorHandler {

@@ -41,7 +41,7 @@
 

     /**

      * Get parsed metadata.

-     * The document must be parsed before calling this method. 

+     * The document must be parsed before calling this method.
      * @return : all the metadata.

      * @throws ParseException : occurs if an error occurs during the parsing.

      */

@@ -113,7 +113,7 @@
      * @param ch : character

      * @param start : start

      * @param length : length

-     * @throws SAXException : can never occurs. 

+     * @throws SAXException : can never occurs.
      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)

      */

     public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {

@@ -176,7 +176,7 @@
                 && (namespaceURI.equalsIgnoreCase("org.apache.felix.ipojo") || namespaceURI.equalsIgnoreCase("org.apache.felix.ipojo.composite"))) {

             namespace = null; // Remove the 'org.apache.felix.ipojo' namespace

         }

-        

+
         Element elem = new Element(localName, namespace);

         for (int i = 0; i < atts.getLength(); i++) {

             String name = (String) atts.getLocalName(i);

@@ -271,6 +271,7 @@
      */

     public void fatalError(SAXParseException saxparseexception)

         throws SAXException {

+        //TODO use reporter
         System.err.println("Fatal error during XML-Schema parsing : " + saxparseexception);

         throw saxparseexception;

     }

@@ -285,7 +286,8 @@
      */

     public void warning(SAXParseException saxparseexception)

         throws SAXException {

+        // TODO use reporter
         System.err.println("Warning : an error was detected in the metadata file : " + saxparseexception);

-        

+
     }

 }

diff --git a/ipojo/manipulator/src/main/resources/xsd/composite.xsd b/ipojo/manipulator/src/main/resources/xsd/composite.xsd
new file mode 100644
index 0000000..6a95fb8
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/composite.xsd
@@ -0,0 +1,147 @@
+<!--
+	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.
+-->
+<xs:schema elementFormDefault="qualified"
+	targetNamespace="org.apache.felix.ipojo.composite"
+	xmlns="org.apache.felix.ipojo.composite"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ipojo="org.apache.felix.ipojo">
+
+	<xs:import namespace="org.apache.felix.ipojo" schemaLocation="http://people.apache.org/~clement/ipojo/schemas/core.xsd"></xs:import>
+	<xs:complexType name="CompositeType">
+		<xs:choice minOccurs="0" maxOccurs="unbounded">
+			<xs:element ref="subservice" minOccurs="0"
+				maxOccurs="unbounded">
+			</xs:element>
+			<xs:element ref="provides" minOccurs="0"
+				maxOccurs="unbounded">
+			</xs:element>
+			<xs:element ref="instance" minOccurs="0"
+				maxOccurs="unbounded">
+			</xs:element>
+			<xs:any namespace="##other" processContents="lax"
+				minOccurs="0" maxOccurs="unbounded">
+			</xs:any>
+		</xs:choice>
+		<xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+		<xs:attribute name="public" type="xs:boolean" use="optional"></xs:attribute>
+		<xs:attribute name="architecture" type="xs:boolean"
+			use="optional">
+		</xs:attribute>
+	</xs:complexType>
+
+	<xs:element name="subservice" type="SubserviceType" />
+	<xs:element name="provides" type="CompositeProvidesType" />
+	
+	<xs:complexType name="CompositeProvidesType">
+		<xs:complexContent>
+			<xs:extension base="ipojo:ServiceDependencyType">
+				<xs:sequence>
+					<xs:element name="delegation" type="DelegationType"></xs:element>
+				</xs:sequence>
+				<xs:attribute name="specification" type="xs:string"
+					use="required">
+				</xs:attribute>
+
+				<xs:attribute name="action">
+					<xs:simpleType>
+						<xs:restriction base="xs:string">
+							<xs:enumeration value="implement"></xs:enumeration>
+							<xs:enumeration value="export"></xs:enumeration>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:attribute>
+
+
+
+			</xs:extension>
+		</xs:complexContent>
+	</xs:complexType>
+
+	<xs:complexType name="SubserviceType">
+		<xs:complexContent>
+			<xs:extension base="ipojo:ServiceDependencyType">
+
+				<xs:sequence minOccurs="0" maxOccurs="unbounded">
+					<xs:element name="property" type="CompositePropertyType"></xs:element>
+				</xs:sequence>
+				<xs:attribute name="action" use="required">
+					<xs:simpleType>
+						<xs:restriction base="xs:string">
+							<xs:enumeration value="import"></xs:enumeration>
+							<xs:enumeration value="instantiate"></xs:enumeration>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:attribute>
+
+				<xs:attribute name="specification" type="xs:string"
+					use="required">
+				</xs:attribute>
+				<xs:attribute name="context-source" type="xs:string"
+					use="optional">
+				</xs:attribute>
+				<xs:attribute name="scope">
+					<xs:simpleType>
+						<xs:restriction base="xs:string">
+							<xs:enumeration value="global"></xs:enumeration>
+							<xs:enumeration value="composite"></xs:enumeration>
+							<xs:enumeration value="composite+global"></xs:enumeration>
+						</xs:restriction>
+					</xs:simpleType>
+				</xs:attribute>
+			</xs:extension>
+		</xs:complexContent>
+	</xs:complexType>
+
+	<xs:simpleType name="actionType">
+		<xs:restriction base="xs:string"></xs:restriction>
+	</xs:simpleType>
+
+	<xs:complexType name="CompositePropertyType">
+		<xs:sequence minOccurs="0" maxOccurs="unbounded">
+			<xs:element name="property" type="CompositePropertyType" minOccurs="0" maxOccurs="unbounded"></xs:element>
+		</xs:sequence>
+		<xs:attribute name="name" type="xs:string" use="required"></xs:attribute>
+		<xs:attribute name="value" type="xs:string" use="optional"></xs:attribute>
+	</xs:complexType>
+
+	<xs:complexType name="CompositeInstanceType">
+		<xs:sequence minOccurs="0" maxOccurs="unbounded">
+			<xs:element name="property" type="CompositePropertyType"></xs:element>
+		</xs:sequence>
+		<xs:attribute name="name" type="xs:string" use="optional"></xs:attribute>
+		<xs:attribute name="component" type="xs:string"
+			use="required">
+		</xs:attribute>
+	</xs:complexType>
+
+    <xs:element name="instance" type="CompositeInstanceType"></xs:element>
+
+    <xs:element name="composite" type="CompositeType"></xs:element>
+
+    <xs:complexType name="DelegationType">
+    	<xs:attribute name="method" type="xs:string" use="required"></xs:attribute>
+    	<xs:attribute name="policy" use="required">
+    		<xs:simpleType>
+    			<xs:restriction base="xs:string">
+    				<xs:enumeration value="all"></xs:enumeration>
+    				<xs:enumeration value="one"></xs:enumeration>
+    			</xs:restriction>
+    		</xs:simpleType>
+    	</xs:attribute>
+    </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/resources/xsd/core.xsd b/ipojo/manipulator/src/main/resources/xsd/core.xsd
new file mode 100644
index 0000000..66cb2d5
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/core.xsd
@@ -0,0 +1,589 @@
+<!--
+  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.
+-->
+<xs:schema elementFormDefault="qualified" targetNamespace="org.apache.felix.ipojo"
+  xmlns="org.apache.felix.ipojo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:annotation>
+    <xs:documentation>iPOJO Core XML-Schema. This grammars models iPOJO descriptor using core
+      features. It provides several extensibility mechanism in order to compose this schema with
+      external handlers and other component implementation type such as
+      compositions.</xs:documentation>
+  </xs:annotation>
+  <xs:element name="ipojo">
+    <xs:complexType>
+      <xs:annotation>
+        <xs:documentation>iPOJO top level element.</xs:documentation>
+      </xs:annotation>
+      <xs:choice minOccurs="0" maxOccurs="unbounded">
+        <xs:element ref="handler" minOccurs="0" maxOccurs="unbounded">
+          <xs:annotation>
+            <xs:documentation>The handler declarations.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element ref="instance" minOccurs="0" maxOccurs="unbounded">
+          <xs:annotation>
+            <xs:documentation>The instance declarations.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:element ref="component" minOccurs="0" maxOccurs="unbounded">
+          <xs:annotation>
+            <xs:documentation>The component type declarations.</xs:documentation>
+          </xs:annotation>
+        </xs:element>
+        <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+        > </xs:any>
+      </xs:choice>
+    </xs:complexType>
+  </xs:element>
+  <xs:complexType name="HandlerType">
+    <xs:annotation>
+      <xs:documentation>Description of the handler.</xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="RootElementType">
+        <xs:sequence maxOccurs="unbounded" minOccurs="0">
+          <xs:any minOccurs="0" maxOccurs="unbounded" namespace="##any" processContents="skip"
+          > </xs:any>
+        </xs:sequence>
+        <xs:attribute name="classname" type="xs:string" use="required">
+          <xs:annotation>
+            <xs:documentation>The implementation class of the handler. The specified class must
+              implement (direcly or not) the "org.apache.felix.ipojo.Handler"
+              interface.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="name" type="xs:string" use="required">
+          <xs:annotation>
+            <xs:documentation>The name of the handler.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="namespace" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>The XML namespace of the handler.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="architecture" type="xs:boolean" use="optional" fixed="false">
+          <xs:annotation>
+            <xs:documentation>Enables or disables the architecture exposition. By default, the
+              architecture is not exposed. This allows handler introspection.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="level" type="xs:int" use="optional">
+          <xs:annotation>
+            <xs:documentation>The start level of the handler.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="InstanceType">
+    <xs:annotation>
+      <xs:documentation>Describes an instance of a component.</xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="RootElementType">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="property" type="InstancePropertyType">
+            <xs:annotation>
+              <xs:documentation>The instance properties.</xs:documentation>
+            </xs:annotation>
+          </xs:element>
+        </xs:sequence>
+        <xs:attribute name="component" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>The name of the instance component type.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="name" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>The (unique) name of the instance.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="version" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>The version of the factory to use.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="InstancePropertyType">
+    <xs:annotation>
+      <xs:documentation>Defines a property of an instance configuration.</xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element name="property" type="InstancePropertyType" minOccurs="0" maxOccurs="unbounded"/>
+    </xs:sequence>
+    <xs:attribute name="name" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Name of the property. Can be optional if a property is inside a structure.
+          The 'instance.name' property has a special semantic as it will be used as the instance
+          name.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="value" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Value of the property. Can be null for property containing other
+          properties.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="type" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Type of the property, used to create the adequate object. Supported values
+          are list, array, dictionary and map.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="RootElementType"/>
+  <xs:complexType name="ComponentType">
+    <xs:annotation>
+      <xs:documentation>Declares an atomic (i.e. primitive) component type.</xs:documentation>
+    </xs:annotation>
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element ref="callback" minOccurs="0" maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:documentation>Describes the method(s) to invoke when the component's state
+            changes.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:documentation>Indicates the component provided service(s). By default, all implemented
+            interfaces are published.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:documentation>Indicates the service requirements of the component.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element ref="properties" minOccurs="0" maxOccurs="unbounded">
+        <xs:annotation>
+          <xs:documentation>Describes the properties of the component.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element ref="controller" minOccurs="0" maxOccurs="1">
+        <xs:annotation>
+          <xs:documentation>Lifecycle controller for this component.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"
+      > </xs:any>
+    </xs:choice>
+    <xs:attribute name="name" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Specifies the name of the component type. This name is used to identify
+          the factory attached to this type. If not specified, the factory name is the
+          implementation class name.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="public" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Determines if the component type is public or private. A public factory
+          (default) can be used from any bundles.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="classname" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation>Specifies the implementation class of the component
+          type.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="architecture" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Enables or disables the architecture exposition. By default, the
+          architecture is exposed. This allows instance introspection.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="immediate" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Creates the object of the component implementation type as soon as the
+          component instance becomes valid. The default value is "true" if the component doesn't
+          provide any service, "false" otherwise.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="factory-method" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Factory method called to create POJO objects instead of the constructor.
+          The specified method must be a static method of the implementation class returning an
+          instance of this implementation class. The factory method can receive the bundle context
+          in argument.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="version" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Set the version of this component type</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="RequiresType">
+    <xs:annotation>
+      <xs:documentation>Description of component services requirements.</xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="ServiceDependencyType">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="callback" type="DependencyCallbackType">
+            <xs:annotation>
+              <xs:documentation>Service requirement method invocation description. Here can be
+                specified a bind method called when a service appears and an unbind method called
+                when a service disappears.</xs:documentation>
+            </xs:annotation>
+          </xs:element>
+        </xs:sequence>
+
+        <xs:attribute name="interface" type="xs:string" use="prohibited">
+          <xs:annotation>
+            <xs:documentation>The interface describing the required service type. This attribute is
+              needed only when using aggregate dependencies with field injection and when the type
+              of this field is a list, vector, collection and set. This attribute is deprecated, use
+              'specification'.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="field" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>The name of the field representing the service dependency in the
+              implementation class.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="nullable" type="xs:boolean" use="optional">
+          <xs:annotation>
+            <xs:documentation>Enable or disable the Nullable pattern on optional service
+              dependencies. By default, Nullable pattern is enabled. If disabled, iPOJO will inject
+              null instead of a Nullable object.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="default-implementation" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>Specifies the default implementation class for an optional service
+              dependency. If no providers are found, iPOJO creates an instance of the
+              default-implementation (nullary constructor) and injects it. The given class must
+              implement the required service interface.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="from" type="xs:string" use="optional">
+          <xs:annotation>
+            <xs:documentation>Specific service provider. The dependency can only be fulfilled by the
+              component with the matching name, or by the service with a matching
+              PID.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="proxy" type="xs:boolean" use="optional">
+          <xs:annotation>
+            <xs:documentation>Enables or Disable the proxy injection (on field
+              injection)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+
+        <xs:attribute name="scope" use="optional">
+          <xs:simpleType>
+            <xs:restriction base="xs:string">
+              <xs:enumeration value="global"/>
+              <xs:enumeration value="composite"/>
+              <xs:enumeration value="composite+global"/>
+            </xs:restriction>
+          </xs:simpleType>
+        </xs:attribute>
+
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="DependencyCallbackType">
+    <xs:annotation>
+      <xs:documentation>Dependency callbacks are used to receive notification when service providers
+        arrive and leave.</xs:documentation>
+    </xs:annotation>
+    <xs:attribute name="method" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation>Method to call</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="type" use="required">
+      <xs:annotation>
+        <xs:documentation> Type of callback (bind, unbind, or updated). Bind means that the method
+          will be called when a provider arrives. Unbind means that the method will be called when a
+          provider leaves. Updated means that a service was modified but is still valid for the
+          service dependency. </xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:restriction base="xs:string">
+          <xs:enumeration value="bind"/>
+          <xs:enumeration value="unbind"/>
+          <xs:enumeration value="modified"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="CallbackType">
+    <xs:annotation>
+      <xs:documentation>Lifecycle Callback. Allows a POJO to be notified when the instance becomes
+        valid or invalid.</xs:documentation>
+    </xs:annotation>
+    <xs:attribute name="method" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation>Specifies the method to call on the transition.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="transition" use="required">
+      <xs:annotation>
+        <xs:documentation>Specifies the transition when the callback needs to be
+          invoked.</xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:annotation>
+          <xs:documentation>Lifecycle transition state. "validate" means that the component's
+            instance was invalid and becomes valid, "invalidate" means that the component's intance
+            was valid and becomes invalid.</xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+          <xs:enumeration value="validate"/>
+          <xs:enumeration value="invalidate"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:element name="provides" type="ProvidesType" id="provides"/>
+  <xs:complexType name="ProvidesType">
+    <xs:annotation>
+      <xs:documentation>Provided service(s) description.</xs:documentation>
+    </xs:annotation>
+    <xs:sequence minOccurs="0" maxOccurs="unbounded">
+      <xs:choice>
+      <xs:element name="property" type="PropertyType">
+        <xs:annotation>
+          <xs:documentation>List of service specific properties.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+      <xs:element name="controller" minOccurs="0" maxOccurs="1" type="ServiceControllerType">
+          <xs:annotation>
+            <xs:documentation>Service Controller impacting the current provided
+              service</xs:documentation>
+          </xs:annotation>
+       </xs:element>
+      </xs:choice>
+    </xs:sequence>
+    <xs:attribute name="interface" type="xs:string" use="prohibited">
+      <xs:annotation>
+        <xs:documentation>Deprecated attribute, use 'specifications' instead of
+          'interface'</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="specifications" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>The list of service specifications (i.e. interfaces) to expose. By
+          default, all interfaces implemented by the component implementation class are
+          published.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="factory" type="xs:string" use="prohibited">
+      <xs:annotation>
+        <xs:documentation>Use 'strategy' instead of 'factory'</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="strategy" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>POJO creation strategy. By default, the POJO object is created once
+          (singleton). If the factory is set to "SERVICE", the creation policy follows the OSGi
+          service factory policy (one object object per asking bundle). INSTANCE allows creating one
+          different POJO object per asking instance. Finally, a custom strategy can be used by
+          specifying the qualified name of the class extending CreationPolicy</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="post-registration" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Defines a callback called after the service registration. The callback takes a ServiceReference
+        as parameter</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="post-unregistration" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Defines a callback called after the service unregistration. The callback takes a ServiceReference
+        as parameter</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="ServiceControllerType">
+    <xs:annotation>
+      <xs:documentation> Defines a service controller. </xs:documentation>
+    </xs:annotation>
+    <xs:attribute name="field" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation> Field of the controller </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="value" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Intiail value of the controller </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="PropertyType">
+    <xs:annotation>
+      <xs:documentation> Defines a component property. </xs:documentation>
+    </xs:annotation>
+    <xs:attribute name="field" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Field of the property </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="method" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Setter method of the property. This method is called to inject property
+          value. </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Name of the property. </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="value" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Default value of the property. </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="type" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation> Type of the property. </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="mandatory" type="xs:boolean" use="optional" default="false">
+      <xs:annotation>
+        <xs:documentation>Set the property as mandatory. A mandatory property MUST receive a value
+          either in the component type description or in the instance configuration. Properties are
+          optional by default.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:element name="callback" type="CallbackType" id="callback"/>
+  <xs:element name="controller" type="ControllerType" id="controller">
+    <xs:annotation>
+      <xs:documentation/>
+    </xs:annotation>
+  </xs:element>
+  <xs:element name="requires" type="RequiresType" id="requires"/>
+  <xs:element name="component" type="ComponentType" id="component"/>
+  <xs:element name="handler" type="HandlerType" id="handler"/>
+  <xs:element name="instance" type="InstanceType" id="instance"/>
+
+  <xs:element name="properties" type="PropertiesType" id="properties"/>
+  <xs:complexType name="PropertiesType">
+    <xs:annotation>
+      <xs:documentation>List of component, instance or service properties. This field will receive
+        the property value.</xs:documentation>
+    </xs:annotation>
+    <xs:sequence minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="property" type="PropertyType">
+        <xs:annotation>
+          <xs:documentation>The list of properties.</xs:documentation>
+        </xs:annotation>
+      </xs:element>
+    </xs:sequence>
+    <xs:attribute name="propagation" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Propagation of the component properties to the provided services. If this
+          parameter is set to "true", each time properties are reconfigured, they are propagated to
+          each service published by the component.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="pid" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Unique identifier used to reconfigure components properties (via Managed
+          Services) with the Configuration Admin.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="updated" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>Method called when a reconfiguration is done</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+
+  <xs:complexType name="ServiceDependencyType">
+    <xs:attribute name="specification" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>The specification describing the required service type. This attribute is
+          needed only when using aggregate dependencies with field injection and when the type of
+          this field is a list, vector, collection and set.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="optional" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Sets the service dependency optionality</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="aggregate" type="xs:boolean" use="optional">
+      <xs:annotation>
+        <xs:documentation>Sets the service dependency cardinality.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="policy" use="optional">
+      <xs:annotation>
+        <xs:documentation>Sets the binding policy of the dependency. Three policies are supported.
+          The dynamic policy supports service providers dynamism. The static policy freezes the
+          provider set as soon as the dependency is used. The dynamic-priority policy is an
+          extension of the dynamic policy, but providers are ranked.</xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:restriction base="xs:string">
+          <xs:enumeration value="dynamic"/>
+          <xs:enumeration value="static"/>
+          <xs:enumeration value="dynamic-priority"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+    <xs:attribute name="comparator" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>The comparator attribute allows specifying the class used to compare
+          providers. This class must implemented the java.util.Comparator class and must support the
+          comparison of service references.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="filter" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>LDAP filter used to filter providers</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="id" type="xs:string" use="optional">
+      <xs:annotation>
+        <xs:documentation>id of the service dependency. The id allows to indentify and to refert to
+          this dependency.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+
+  <xs:complexType name="ControllerType">
+    <xs:annotation>
+      <xs:documentation>Specifies the lifecycle controller of a component, which allows to validate
+        or invalidate component instances.</xs:documentation>
+    </xs:annotation>
+    <xs:attribute name="field" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation>The name of the component lifecycle controller field. The type of the
+          specified field must be boolean. Setting the value of the specified field to "true" means
+          the validation of the component instance while setting it to "false" means the
+          invalidation of the component instance.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+</xs:schema>
diff --git a/ipojo/manipulator/src/main/resources/xsd/event-admin.xsd b/ipojo/manipulator/src/main/resources/xsd/event-admin.xsd
new file mode 100644
index 0000000..b9c8271
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/event-admin.xsd
@@ -0,0 +1,90 @@
+<!--
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.event"
+	xmlns="org.apache.felix.ipojo.handlers.event"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="qualified">	
+
+    <xs:complexType name="PublisherType">
+        <xs:annotation>
+        	<xs:documentation>Description of an event publisher.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the event publisher, acting as a unique identifier.
+The name of the POJO's field that will be used to send events. The field is initialized at component instantiation time. The type of the field must be "org.apache.felix.ipojo.handlers.event.publisher.Publisher".</xs:documentation>
+        	</xs:annotation></xs:attribute>
+    	<xs:attribute name="field" type="xs:string" use="required">
+    		<xs:annotation>
+    			<xs:documentation>The name of the POJO field associated to this event publisher.
+Despite it creates a dependency between the component code and the handler, this system allows hiding the whole complexity of event sending.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="topics" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The comma-separated-list of the topics on which events will be sent. All subscribers that are listening to one of these topics will receive the events.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="synchronous" type="xs:boolean" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>Determines if event sending is synchronous or not. By default, events are sent asynchronously, but you can specify there the desired behaviour of the Publisher.
+The default value of this attribute is "false".</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-key" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The data key is used when you want to send data events. This attribute's value is the key, in the event's dictionary, in which sent data are stored. When you use the sendData method of the Publisher, the given object is placed in the event dictionary, associated with the specified data-key.
+The default value of this attribute is user.data.</xs:documentation></xs:annotation></xs:attribute>
+    </xs:complexType>
+    
+    <xs:complexType name="SubscriberType">
+        <xs:annotation>
+        	<xs:documentation>Description of an event subscriber.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the event subscriber, acting as a unique identifier.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="callback" type="xs:string" use="required">
+    		<xs:annotation>
+    			<xs:documentation>The name of the POJO's method that will be called each time an event is received.
+This method takes only one parameter, of typeorg.osgi.service.event.Eventby default, but this type can be overridden by defining the data-key and/or the data-type attributes.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="topics" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The comma-separated-list of the topics that the handler will listen to. Each event sent on a topic present in this list will be sent to the specified callback method.</xs:documentation></xs:annotation></xs:attribute>
+    	<xs:attribute name="filter" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The event filter is used to filter incoming events before sending them to the callback.
+The syntax of this field is described in the OSGi EventAdmin Specification. If you don't specify a filter, all events sent on the listened topics will be considered.</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-key" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>The data key is used when you want to receive data events. This attribute's value is the key corresponding to the received data in the event's dictionary.
+If you use this attribute, the parameter passed to the callback method is the the value associated to this key, not the whole event.
+This attribute is generally used with the data-typeattribute to specify the received object type.
+If an event is received and it does not contain such a key, it is ignored (with a warning message).</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    	<xs:attribute name="data-type" type="xs:string" use="optional">
+    		<xs:annotation>
+    			<xs:documentation>This attribute is associated to the data-key attribute. It specifies the type of objects (java.lang.Object by default) that the callback expects.
+It is used to determine the unique callback method (in case of multiple methods with the same name) and to check type compliance at event reception.
+Data events that are not corresponding to the specified type will be ignored (with a warning message).</xs:documentation>
+    		</xs:annotation></xs:attribute>
+    </xs:complexType>
+    
+    <xs:element name="publisher" type="PublisherType"></xs:element>
+    <xs:element name="subscriber" type="SubscriberType"></xs:element>
+    
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/resources/xsd/extender-pattern.xsd b/ipojo/manipulator/src/main/resources/xsd/extender-pattern.xsd
new file mode 100644
index 0000000..0e2ed9f
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/extender-pattern.xsd
@@ -0,0 +1,42 @@
+<!--
+	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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.extender"
+	xmlns="org.apache.felix.ipojo.extender"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="qualified">
+	<xs:element name="extender" type="ExtenderType"></xs:element>
+	<xs:complexType name="ExtenderType">
+        <xs:annotation>
+        	<xs:documentation>Description of the extender pattern configuration.
+The extender tracks extensions. The particularity of this architecture-style is that extensions are packaged in different bundles. An extension is detected by analyzing the bundle. The mark is currently a header in the bundle manifest. At each time a matching bundle appears or disappears, a callback is invoked. </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="onArrival" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>Declaring the method to invoke when a matching bundle arrives</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="onDeparture" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the method to invoke when a matching bundle leaves</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="extension" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the looked manifest header.</xs:documentation>
+			</xs:annotation></xs:attribute>
+	</xs:complexType>	
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/resources/xsd/jmx.xsd b/ipojo/manipulator/src/main/resources/xsd/jmx.xsd
new file mode 100644
index 0000000..80152e9
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/jmx.xsd
@@ -0,0 +1,177 @@
+<!--
+	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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handlers.jmx"
+	xmlns="org.apache.felix.ipojo.handlers.jmx"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="qualified">
+	<xs:element name="config" type="JMXType"></xs:element>
+
+	<xs:complexType name="JMXType">
+
+		<xs:annotation>
+			<xs:documentation>
+				Description of a JMX managed component.
+			</xs:documentation>
+		</xs:annotation>
+		<xs:choice minOccurs="0" maxOccurs="unbounded">
+			<xs:element name="method" type="JMXMethod">
+				<xs:annotation>
+					<xs:documentation>
+						The list of methods to expose.
+					</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+			<xs:element name="property" type="JMXProperty">
+				<xs:annotation>
+					<xs:documentation>
+						The list of attributes to expose.
+					</xs:documentation>
+				</xs:annotation>
+			</xs:element>
+		</xs:choice>
+		<xs:attribute name="usesMOSGi" type="xs:boolean"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Determines if the component must be register on the
+					MOSGi MBean server or not.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="objectName" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The complete object name of the managed component.
+					The syntax of this attribute must be compliant with
+					the ObjectName syntax, detailed in the JMX
+					specification. If neither domain nor name attributes
+					are specified, the default value is determined by
+					the package, the type and the instance name of the
+					component. This attribute overrides the domain and
+					name attributes.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="domain" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The domain of the managed object (i.e., the left
+					part of the object name). This attribute must be
+					compliant with the domain syntax, as described in
+					the JMX specification.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="name" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					The name property of the managed object. The value
+					of this attribute must comply with the ObjectName
+					value syntax, as described in the JMX specification.
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+
+		<xs:attribute name="preRegister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations before
+					beeing registered from the MBean server. The
+					signature of the specified method must be :
+					"ObjectName preRegister(MBeanServer server,
+					ObjectName name) throws Exception".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="postRegister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations after
+					beeing registered from the MBean server. The
+					signature of the specified method must be : "void
+					postRegister(Boolean registrationDone)".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="preDeregister" type="xs:string"
+			use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations before
+					beeing unregistered from the MBean server. The
+					signature of the specified method must be : "void
+					preDeregister() throws Exception".
+				</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="postDeregister" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>
+					Specifies method to carry out operations after
+					beeing unregistered from the MBean server. The
+					signature of the specified method must be : 
+					"void postDeregister()".</xs:documentation>
+			</xs:annotation></xs:attribute>
+	</xs:complexType>
+
+	<xs:complexType name="JMXProperty">
+        <xs:annotation>
+        	<xs:documentation>Description of an attribute to expose.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="field" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the component's field to expose.</xs:documentation></xs:annotation></xs:attribute>
+		<xs:attribute name="name" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>The name of the property as it will appear in JMX. If unspecified, the default value is the name of the exposed field.</xs:documentation></xs:annotation></xs:attribute>
+		<xs:attribute name="rights" use="optional">
+            <xs:annotation>
+            	<xs:documentation>Specify the access permission of the exposed field.</xs:documentation>
+            </xs:annotation>
+            <xs:simpleType>
+                <xs:annotation>
+                	<xs:documentation>Access permission of an exposed field. Accepted values are "r" (read-only access, the default value) and "w" (read and write access).</xs:documentation>
+                </xs:annotation>
+                <xs:restriction base="xs:string">
+					<xs:enumeration value="r"></xs:enumeration>
+					<xs:enumeration value="w"></xs:enumeration>
+				</xs:restriction>
+			</xs:simpleType>
+		</xs:attribute>
+		<xs:attribute name="notification" type="xs:boolean" use="optional">
+			<xs:annotation>
+				<xs:documentation>Enable or disable attribute change notification sending for this property. If set to &quot;true&quot;, a notification is sent each time the value of the field changes.</xs:documentation></xs:annotation></xs:attribute>
+	</xs:complexType>
+
+	<xs:complexType name="JMXMethod">
+        <xs:annotation>
+        	<xs:documentation>Description of a method to expose.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="name" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The name of the method to expose. If multiple methods have the same name, all of them are exposed.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="description" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>The description of the exposed method, as it will appear in JMX.</xs:documentation></xs:annotation></xs:attribute>
+	</xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/resources/xsd/temporal.xsd b/ipojo/manipulator/src/main/resources/xsd/temporal.xsd
new file mode 100644
index 0000000..3f2d47c
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/temporal.xsd
@@ -0,0 +1,57 @@
+<!--
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.handler.temporal"
+	xmlns="org.apache.felix.ipojo.handler.temporal"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="qualified">
+	<xs:element name="requires" type="TemporalServiceDependencyType"></xs:element>
+
+	<xs:complexType name="TemporalServiceDependencyType">
+
+        <xs:annotation>
+        	<xs:documentation>Description of a temporal dependency.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="field" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>The implementation field supporting the dependency.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="filter" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>Filter use to discover matching filter.</xs:documentation></xs:annotation></xs:attribute>
+		<xs:attribute name="timeout" type="xs:int" use="optional">
+			<xs:annotation>
+				<xs:documentation>Specifies the timeout after which the onTimeout policy is executed. The value is the time in ms to wait. -1 is used to indicate an infinite wait.</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="onTimeout" use="optional" type="xs:string">
+            <xs:annotation>
+            	<xs:documentation>Specifies the onTimeout policy. This determines the object to inject when the service stills unavailable when the timeout expires. Several values are supported: 'nullable' means that a Nullable object will be injected, 'empty-array' injects an empty array (only for aggregate dependency), 'null' injects Null, any other value are interpreted as the default implementation class to use. If the onTimetout attribute is not specified, a RuntimeException is thrown when the timeout is reached.</xs:documentation>
+            </xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="proxy" use="optional" type="xs:boolean">
+            <xs:annotation>
+            	<xs:documentation>Enables or Disables the proxy injection</xs:documentation>
+            </xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="specification" use="optional" type="xs:string">
+            <xs:annotation>
+            	<xs:documentation>Specifies the looked service specification. This attribute is mandatory when injecting in a Collection</xs:documentation>
+            </xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd b/ipojo/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd
new file mode 100644
index 0000000..f02afde
--- /dev/null
+++ b/ipojo/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd
@@ -0,0 +1,45 @@
+<!--
+	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.
+-->
+<xs:schema targetNamespace="org.apache.felix.ipojo.whiteboard"
+	xmlns="org.apache.felix.ipojo.whiteboard"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	elementFormDefault="qualified">
+	<xs:element name="wbp" type="WBPType"></xs:element>
+	<xs:complexType name="WBPType">
+        <xs:annotation>
+        	<xs:documentation>Description of the white-board architecture.</xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="onArrival" type="xs:string" use="required">
+        	<xs:annotation>
+        		<xs:documentation>Declaring the method to invoke when a matching service arrives.</xs:documentation>
+        	</xs:annotation></xs:attribute>
+		<xs:attribute name="onDeparture" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Declaring the method to invoke when a matching service leaves.</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="onModification" type="xs:string" use="optional">
+			<xs:annotation>
+				<xs:documentation>Method called when an injected service reference is modified but stills valid against the filter.</xs:documentation>
+			</xs:annotation></xs:attribute>
+		<xs:attribute name="filter" type="xs:string" use="required">
+			<xs:annotation>
+				<xs:documentation>Filter use to discover matching filter.</xs:documentation>
+			</xs:annotation></xs:attribute>
+	</xs:complexType>	
+</xs:schema>
\ No newline at end of file
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
index 68d4b5e..387dfca 100644
--- a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
@@ -11,6 +11,7 @@
 
 	public void testJarManipulation() {
 		Pojoization pojoization = new Pojoization();
+        pojoization.setUseLocalXSD();
 		File in = new File("target/test-classes/tests.manipulation-no-annotations.jar");
 		File out = new File("target/test-classes/tests.manipulation-no-annotations-manipulated.jar");
 		out.delete();
@@ -22,6 +23,7 @@
 
 	public void testManipulationWithAnnotations() {
 		Pojoization pojoization = new Pojoization();
+        pojoization.setUseLocalXSD();
 		File in = new File("target/test-classes/tests.manipulator-annotations.jar");
 		File out = new File("target/test-classes/tests.manipulation-annotations-manipulated.jar");
 		out.delete();
@@ -32,6 +34,7 @@
 
 	public void testJarManipulationJava5() {
 		Pojoization pojoization = new Pojoization();
+        pojoization.setUseLocalXSD();
 		File in = new File("target/test-classes/tests.manipulation.java5.jar");
 		File out = new File("target/test-classes/tests.manipulation.java5-manipulated.jar");
 		out.delete();
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java
new file mode 100644
index 0000000..b282b11
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import test.ClusterDaemon;
+import test.PojoWithInner;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ManipulationEngineTestCase extends TestCase {
+
+    @Mock
+    private Reporter reporter;
+
+    @Mock
+    private ResourceStore store;
+
+    @Mock
+    private ManipulationVisitor visitor;
+
+    @Mock
+    private ManipulationResultVisitor result;
+
+    @InjectMocks
+    private ManipulationEngine engine = new ManipulationEngine();
+
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testManipulationOfSimpleClass() throws Exception {
+
+        when(store.read(anyString())).thenReturn(from(ClusterDaemon.class));
+        when(visitor.visitManipulationResult(any(Element.class))).thenReturn(result);
+
+        String path = Strings.asResourcePath(ClusterDaemon.class.getName());
+        Element metadata = new Element("", "");
+        ManipulationUnit info = new ManipulationUnit(path, metadata);
+        engine.addManipulationUnit(info);
+
+        engine.generate();
+
+        verify(visitor).visitManipulationResult(eq(metadata));
+        verify(result).visitClassStructure(any(Element.class));
+        verify(result).visitManipulatedResource(eq(path), any(byte[].class));
+        verify(result).visitEnd();
+
+    }
+
+    public void testManipulationOfInnerClass() throws Exception {
+
+        when(visitor.visitManipulationResult(any(Element.class))).thenReturn(result);
+
+        String innerPath = Strings.asResourcePath(PojoWithInner.MyInner.class.getName());
+        when(store.read(innerPath)).thenReturn(from(PojoWithInner.MyInner.class));
+
+        String path = Strings.asResourcePath(PojoWithInner.class.getName());
+        when(store.read(path)).thenReturn(from(PojoWithInner.class));
+
+        Element metadata = new Element("", "");
+        ManipulationUnit info = new ManipulationUnit(path, metadata);
+        engine.addManipulationUnit(info);
+
+        engine.generate();
+
+        verify(visitor).visitManipulationResult(eq(metadata));
+        verify(result).visitClassStructure(any(Element.class));
+        verify(result).visitManipulatedResource(eq(path), any(byte[].class));
+        verify(result).visitManipulatedResource(eq(innerPath), any(byte[].class));
+        verify(result).visitEnd();
+
+    }
+
+    private byte[] from(Class<?> type) throws IOException {
+        ClassLoader loader = type.getClassLoader();
+        InputStream is = loader.getResourceAsStream(Strings.asResourcePath(type.getName()));
+        return Streams.readBytes(is);
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java
new file mode 100644
index 0000000..46cf8ae
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.manifest;
+
+import junit.framework.TestCase;
+
+import java.util.jar.Manifest;
+
+public class DirectManifestProviderTestCase extends TestCase {
+    public void testGetManifest() throws Exception {
+        Manifest origin = new Manifest();
+        DirectManifestProvider provider = new DirectManifestProvider(origin);
+
+        assertSame(origin, provider.getManifest());
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java
new file mode 100644
index 0000000..dc8abcc
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.manifest;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.jar.Manifest;
+
+public class FileManifestProviderTestCase extends TestCase {
+    public void testGetManifest() throws Exception {
+        File manifestFile = new File(new File("target", "test-classes"), "MANIFEST.MF");
+        FileManifestProvider provider = new FileManifestProvider(manifestFile);
+
+        Manifest manifest = provider.getManifest();
+
+        assertNotNull(manifest);
+        assertEquals("tests.manipulation.java5", manifest.getMainAttributes().getValue("Bundle-SymbolicName"));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java
new file mode 100644
index 0000000..3d9e287
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+import org.apache.felix.ipojo.metadata.Element;
+import test.AnnotatedComponent;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+
+public class AnnotationMetadataProviderTestCase extends TestCase {
+    public void testGetMetadatas() throws Exception {
+        MiniStore store = new MiniStore(AnnotatedComponent.class);
+        Reporter reporter = mock(Reporter.class);
+        AnnotationMetadataProvider provider = new AnnotationMetadataProvider(store, reporter);
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(1, meta.size());
+
+
+    }
+
+    private class MiniStore implements ResourceStore {
+
+        private Map<String, byte[]> resources;
+
+        public MiniStore(Class<?>... classes) throws IOException {
+            this.resources = new HashMap<String, byte[]>();
+            for (Class<?> type : classes) {
+                resources.put(Strings.asResourcePath(type.getName()), from(type));
+            }
+        }
+
+        public byte[] read(String path) throws IOException {
+            return resources.get(path);
+        }
+
+        public void accept(ResourceVisitor visitor) {
+            for (Map.Entry<String, byte[]> entry : resources.entrySet()) {
+                visitor.visit(entry.getKey());
+            }
+        }
+
+        public void open() throws IOException {}
+
+        public void writeMetadata(Element metadata) {}
+
+        public void write(String resourcePath, byte[] resource) throws IOException {}
+
+        public void close() throws IOException {}
+    }
+
+    private byte[] from(Class<?> type) throws IOException {
+        ClassLoader loader = type.getClassLoader();
+        InputStream is = loader.getResourceAsStream(Strings.asResourcePath(type.getName()));
+        return Streams.readBytes(is);
+    }
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java
new file mode 100644
index 0000000..5c29fb9
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.util.Collections;
+
+import static org.mockito.Mockito.*;
+
+public class CacheableMetadataProviderTestCase extends TestCase {
+    public void testGetMetadatas() throws Exception {
+        MetadataProvider delegate = mock(MetadataProvider.class);
+        CacheableMetadataProvider provider = new CacheableMetadataProvider(delegate);
+
+        Element returned = new Element("test", null);
+        when(delegate.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+        provider.getMetadatas();
+        provider.getMetadatas();
+        provider.getMetadatas();
+        provider.getMetadatas();
+
+        verify(delegate, atMost(1)).getMetadatas();
+
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java
new file mode 100644
index 0000000..bdd8338
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.MetadataProvider;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+
+public class CompositeMetadataProviderTestCase extends TestCase {
+
+    @Mock
+    private MetadataProvider delegate1;
+
+    @Mock
+    private MetadataProvider delegate2;
+
+    @Mock
+    private Reporter reporter;
+
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testGetMetadatas() throws Exception {
+        CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+        provider.addMetadataProvider(delegate1);
+        provider.addMetadataProvider(delegate2);
+
+        Element returned = newComponentElement("type1");
+        when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+        Element returned2 = newComponentElement("type2");
+        when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(2, meta.size());
+    }
+
+    public void testGetMetadatasWithDuplicate() throws Exception {
+        CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+        provider.addMetadataProvider(delegate1);
+        provider.addMetadataProvider(delegate2);
+
+        Element returned = newComponentElement("type1");
+        when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+        Element returned2 = newComponentElement("type1");
+        when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(1, meta.size());
+
+        verify(reporter).warn(anyString());
+    }
+
+    public void testGetMetadatasWithInstances() throws Exception {
+        CompositeMetadataProvider provider = new CompositeMetadataProvider(reporter);
+        provider.addMetadataProvider(delegate1);
+        provider.addMetadataProvider(delegate2);
+
+        Element returned = newInstanceElement("type1", "name1");
+        when(delegate1.getMetadatas()).thenReturn(Collections.singletonList(returned));
+
+        // Try with a duplicate instance name
+        Element returned2 = newInstanceElement("type1", "name2");
+        when(delegate2.getMetadatas()).thenReturn(Collections.singletonList(returned2));
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(2, meta.size());
+    }
+
+    private Element newComponentElement(String type) {
+        Element main = new Element("component", null);
+        main.addAttribute(new Attribute("name", type));
+        return main;
+    }
+
+    private Element newInstanceElement(String type, String name) {
+        Element main = new Element("instance", null);
+        main.addAttribute(new Attribute("component", type));
+        main.addAttribute(new Attribute("name", name));
+        return main;
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java
new file mode 100644
index 0000000..2698a67
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+
+public class EmptyMetadataProviderTestCase extends TestCase {
+    public void testGetMetadatas() throws Exception {
+        EmptyMetadataProvider provider = new EmptyMetadataProvider();
+        assertTrue(provider.getMetadatas().isEmpty());
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java
new file mode 100644
index 0000000..db851c8
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+
+public class FileMetadataProviderTestCase extends TestCase {
+    public void testGetMetadatasFromFile() throws Exception {
+        File metadata = new File(new File("target", "test-classes"), "metadata.xml");
+        Reporter reporter = mock(Reporter.class);
+        FileMetadataProvider provider = new FileMetadataProvider(metadata, reporter);
+        provider.setValidateUsingLocalSchemas(true);
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(3, meta.size());
+    }
+
+    public void testGetMetadatasFromDirectory() throws Exception {
+        File metadata = new File("target", "test-classes");
+        Reporter reporter = mock(Reporter.class);
+        FileMetadataProvider provider = new FileMetadataProvider(metadata, reporter);
+        provider.setValidateUsingLocalSchemas(true);
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(3, meta.size());
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java
new file mode 100644
index 0000000..9fa4f45
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.metadata;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Element;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class StreamMetadataProviderTestCase extends TestCase {
+
+    public void testGetMetadatas() throws Exception {
+        File metadata = new File(new File("target", "test-classes"), "metadata.xml");
+        FileInputStream fis = new FileInputStream(metadata);
+        Reporter reporter = mock(Reporter.class);
+
+        StreamMetadataProvider provider = new StreamMetadataProvider(fis, reporter);
+        provider.setValidateUsingLocalSchemas(true);
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(3, meta.size());
+    }
+
+    public void testWithEmptyMetadataXml() throws Exception {
+        File metadata = new File(new File("target", "test-classes"), "empty-metadata.xml");
+        FileInputStream fis = new FileInputStream(metadata);
+        Reporter reporter = mock(Reporter.class);
+
+        StreamMetadataProvider provider = new StreamMetadataProvider(fis, reporter);
+        provider.setValidateUsingLocalSchemas(true);
+
+        List<Element> meta = provider.getMetadatas();
+        assertEquals(0, meta.size());
+        verify(reporter).warn(anyString());
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java
new file mode 100644
index 0000000..7f8bbf6
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.render;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.manipulation.MethodCreator;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class ManipulatedMetadataFilterTestCase extends TestCase {
+
+    private ManipulatedMetadataFilter filter;
+
+    @Override
+    public void setUp() throws Exception {
+        filter = new ManipulatedMetadataFilter();
+    }
+
+    public void testFilterPrefixedMethod() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", MethodCreator.PREFIX + "PropertyName"));
+
+        Assert.assertTrue(filter.accept(main));
+    }
+
+    public void testFilterInstanceManagerValue() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", InstanceManager.class.getName()));
+
+        Assert.assertTrue(filter.accept(main));
+    }
+
+    public void testFilterInstanceManagerSetter() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", "_setInstanceManager"));
+
+        Assert.assertTrue(filter.accept(main));
+    }
+
+    public void testDoNotFilterOthers() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", "setPropertyName"));
+
+        Assert.assertFalse(filter.accept(main));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java
new file mode 100644
index 0000000..a9b0e2c
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.render;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class MetadataRendererTestCase extends TestCase {
+
+    private MetadataRenderer renderer;
+
+    @Override
+    public void setUp() throws Exception {
+        renderer = new MetadataRenderer();
+    }
+
+    public void testAddMetadataFilter() throws Exception {
+
+        // Auto remove all elements with a namespace
+        renderer.addMetadataFilter(new MetadataFilter() {
+            public boolean accept(Element element) {
+                return element.getNameSpace() != null;
+            }
+        });
+
+        Element main = new Element("test", null);
+        Element child = new Element("child", "uri");
+        main.addElement(child);
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { }", rendered);
+
+    }
+
+    public void testRenderElementWithNoNamespace() throws Exception {
+        Element main = new Element("test", null);
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { }", rendered);
+    }
+
+    public void testRenderElementWithEmptyNamespace() throws Exception {
+        Element main = new Element("test", "");
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { }", rendered);
+    }
+
+    public void testRenderElementWithDefaultNamespace() throws Exception {
+        // TODO Do we need to strip off default namespace ?
+        Element main = new Element("test", "org.apache.felix.ipojo");
+        String rendered = renderer.render(main);
+        Assert.assertEquals("org.apache.felix.ipojo:test { }", rendered);
+    }
+
+    public void testRenderElementWithNamespace() throws Exception {
+        Element main = new Element("test", "http://felix.apache.org/ipojo/testing");
+        String rendered = renderer.render(main);
+        Assert.assertEquals("http://felix.apache.org/ipojo/testing:test { }", rendered);
+    }
+
+    public void testRenderElementWithNoNamespaceAttribute() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", "attribute"));
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { $name=\"attribute\" }", rendered);
+    }
+
+    public void testRenderElementWithNamespaceAttribute() throws Exception {
+        Element main = new Element("test", null);
+        main.addAttribute(new Attribute("name", "ns-uri", "attribute"));
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { $ns-uri:name=\"attribute\" }", rendered);
+    }
+
+    public void testRenderElementWithChildren() throws Exception {
+        Element main = new Element("test", null);
+        Element child = new Element("child", null);
+        main.addElement(child);
+        String rendered = renderer.render(main);
+        Assert.assertEquals("test { child { }}", rendered);
+    }
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java
new file mode 100644
index 0000000..1179700
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+import org.apache.felix.ipojo.manipulator.util.Strings;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * A {@code DirectoryBytecodeStoreTestCase} is ...
+ *
+ */
+public class DirectoryResourceStoreTestCase extends TestCase {
+
+    private DirectoryResourceStore store;
+    private File classes;
+    private File out;
+
+    public void setUp() throws Exception {
+        classes = new File("target", "classes");
+        out = new File(classes, "test.txt");
+        store = new DirectoryResourceStore(classes);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        out.delete();
+    }
+
+    public void testAccessibleResources() throws Exception {
+        byte[] data = store.read(Streams.class.getName().replace('.', '/').concat(".class"));
+        assertNotNull("Data cannot be null", data);
+    }
+
+    public void testInaccessibleResources() throws Exception {
+        try {
+            store.read("something/that/do/not/exists.txt");
+            fail();
+        } catch (IOException ioe) {
+            // Expected
+        }
+    }
+
+    public void testResourceWriting() throws Exception {
+        store.write("test.txt", "Hello World".getBytes());
+        Assert.assertTrue(out.isFile());
+    }
+
+    public void testResourceVisitor() throws Exception {
+
+        // final String expectedPath = Strings.asResourcePath(Pojoization.class.getName());
+        ResourceVisitor visitor = mock(ResourceVisitor.class);
+        store.accept(visitor);
+
+        verify(visitor, atLeastOnce()).visit(anyString());
+
+        // TODO try to check that Pojoization class resource was called
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java
new file mode 100644
index 0000000..ed74c75
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.store;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.ResourceVisitor;
+import org.apache.felix.ipojo.manipulator.util.Streams;
+
+import java.io.File;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class JarFileResourceStoreTestCase extends TestCase {
+    public static final String RESOURCE_PATH = "org/apache/felix/ipojo/test/scenarios/component/Annotation.class";
+    private JarFileResourceStore store;
+    private File out;
+
+    public void setUp() throws Exception {
+        File classes = new File("target", "test-classes");
+        out = new File(classes, "test-store.jar");
+        JarFile jar = new JarFile(new File(classes, "tests.manipulation.java5.jar"));
+        store = new JarFileResourceStore(jar, out);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        out.delete();
+    }
+
+    public void testRead() throws Exception {
+        byte[] bytes = store.read(RESOURCE_PATH);
+        Assert.assertNotNull(bytes);
+    }
+
+    public void testAccept() throws Exception {
+        ResourceVisitor visitor = mock(ResourceVisitor.class);
+        store.accept(visitor);
+
+        verify(visitor, atLeastOnce()).visit(anyString());
+
+    }
+
+    public void testWrite() throws Exception {
+
+        ManifestBuilder builder = mock(ManifestBuilder.class);
+        Manifest manifest = new Manifest();
+        when(builder.build(any(Manifest.class))).thenReturn(manifest);
+        store.setManifestBuilder(builder);
+
+        store.write(RESOURCE_PATH, "Hello World".getBytes());
+
+        store.close();
+
+        JarFile outJar = new JarFile(out);
+        Assert.assertNotNull(outJar.getEntry(RESOURCE_PATH));
+        byte[] bytes = Streams.readBytes(outJar.getInputStream(outJar.getEntry(RESOURCE_PATH)));
+
+        Assert.assertEquals("Hello World", new String(bytes));
+
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java
new file mode 100644
index 0000000..1687468
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store.builder;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.store.ManifestBuilder;
+import org.apache.felix.ipojo.manipulator.store.builder.DefaultManifestBuilder;
+
+public class DefaultManifestBuilderTestCase extends TestCase {
+
+    private static final String ORG_OSGI_FRAMEWORK_VERSION_1_5 = "org.osgi.framework;version=1.5";
+    private Manifest manifest;
+    private ManifestBuilder builder;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        manifest = new Manifest();
+        Attributes attributes = manifest.getMainAttributes();
+        attributes.putValue("Import-Package", ORG_OSGI_FRAMEWORK_VERSION_1_5);
+        attributes.putValue("Created-By", "TestCase");
+
+        builder = new DefaultManifestBuilder();
+        builder.addReferredPackage(Collections.singleton("org.osgi.service.http"));
+    }
+
+    public void testManifestIsModified() throws Exception {
+        Manifest modified = builder.build(manifest);
+
+        // Created by header was properly modified
+        Assert.assertEquals("TestCase & iPOJO " + Pojoization.IPOJO_PACKAGE_VERSION,
+                            modified.getMainAttributes().getValue("Created-By"));
+
+        // As there was no metadata provided, no iPOJO-Components header should be present
+        Assert.assertNull(modified.getMainAttributes().getValue("iPOJO-Components"));
+
+        // Check that default manipulation introduced packages are present
+        String imported = modified.getMainAttributes().getValue("Import-Package");
+        Assert.assertTrue(imported.contains(ORG_OSGI_FRAMEWORK_VERSION_1_5));
+        Assert.assertTrue(imported.contains("org.apache.felix.ipojo"));
+        Assert.assertTrue(imported.contains("org.apache.felix.ipojo.architecture"));
+        Assert.assertTrue(imported.contains("org.osgi.service.cm"));
+        Assert.assertTrue(imported.contains("org.osgi.service.log"));
+    }
+
+
+    public void testCreatedByHeaderDoesNotContainIPojoTwice() throws Exception {
+
+        manifest.getMainAttributes().putValue("Created-By", "TestCase for iPOJO");
+
+        Manifest modified = builder.build(manifest);
+
+        // Created by header was properly not changed
+        Assert.assertEquals("TestCase for iPOJO",
+                            modified.getMainAttributes().getValue("Created-By"));
+    }
+
+    public void testReferredPackagesAreProperlyAdded() throws Exception {
+
+        List<String> p = Arrays.asList("org.apache.felix.ipojo.test", "org.apache.felix.ipojo.log");
+        builder.addReferredPackage(new HashSet<String>(p));
+
+        Manifest modified = builder.build(manifest);
+
+        // Check that referred packages are present
+        String imported = modified.getMainAttributes().getValue("Import-Package");
+        Assert.assertTrue(imported.contains("org.apache.felix.ipojo.test"));
+        Assert.assertTrue(imported.contains("org.apache.felix.ipojo.log"));
+    }
+
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java
new file mode 100644
index 0000000..dac3802
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class FileSystemResourceMapperTestCase extends TestCase {
+
+    public void testUnixInternalize() throws Exception {
+
+        ResourceMapper delegate = mock(ResourceMapper.class);
+        FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+        String path = "this/is/a/unix/like/path.extension";
+        when(delegate.internalize(eq(path))).thenReturn(path);
+
+        String result = mapper.internalize(path);
+
+        Assert.assertEquals(path, result);
+
+    }
+
+    public void testUnixExternalize() throws Exception {
+
+        ResourceMapper delegate = mock(ResourceMapper.class);
+        FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+        String path = "this/is/a/unix/like/path.extension";
+        when(delegate.externalize(eq(path))).thenReturn(path);
+
+        String result = mapper.externalize(path);
+
+        // unix path is already normalized
+        Assert.assertEquals(path, result);
+    }
+
+    public void ignoreWindowsExternalize() throws Exception {
+        // As Java doesn't like '\' alone in Strings I have to replace them on the fly :'(
+        // Grrr doesn't work as expected
+        ResourceMapper delegate = mock(ResourceMapper.class);
+        FileSystemResourceMapper mapper = new FileSystemResourceMapper(delegate);
+
+        String path = "c:\\this\\is\\a\\windows\\like\\path.extension";
+        when(delegate.externalize(eq(path))).thenReturn(path);
+
+        String expected = "c:/this/is/a/windows/like/path.extension";
+        String result = mapper.externalize(path);
+
+        // unix path is already normalized
+        Assert.assertEquals(expected, result);
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java
new file mode 100644
index 0000000..fc4f645
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class IdentityResourceMapperTestCase extends TestCase {
+    public void testInternalize() throws Exception {
+        IdentityResourceMapper mapper = new IdentityResourceMapper();
+        String path = "must/not/change";
+        Assert.assertEquals(path, mapper.internalize(path));
+    }
+
+    public void testExternalize() throws Exception {
+        IdentityResourceMapper mapper = new IdentityResourceMapper();
+        String path = "must/not/change";
+        Assert.assertEquals(path, mapper.externalize(path));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java
new file mode 100644
index 0000000..d15f8ac
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.store.mapper;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+public class WABResourceMapperTestCase extends TestCase {
+    public void testSimpleInternalize() throws Exception {
+        ResourceMapper mapper = new WABResourceMapper();
+        String path = "jndi.properties";
+        Assert.assertEquals("WEB-INF/classes/" + path, mapper.internalize(path));
+    }
+
+    public void testSimpleExternalize() throws Exception {
+        ResourceMapper mapper = new WABResourceMapper();
+        String path = "WEB-INF/classes/jndi.properties";
+        Assert.assertEquals("jndi.properties", mapper.externalize(path));
+    }
+
+    public void testExternalizeError() throws Exception {
+        ResourceMapper mapper = new WABResourceMapper();
+        String path = "jndi.properties";
+
+        try {
+            mapper.externalize(path);
+            fail("Should have thrown an IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // ok
+        }
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java
new file mode 100644
index 0000000..b3f2902
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.util;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class StreamsTestCase extends TestCase {
+    public void testSimpleClose() throws Exception {
+        Closeable closeable = mock(Closeable.class);
+        Streams.close(closeable);
+        verify(closeable).close();
+    }
+
+    public void testCloseWithNullParameter() throws Exception {
+        Closeable closeable = mock(Closeable.class);
+        Streams.close(closeable, null);
+        verify(closeable).close();
+    }
+
+    public void testTransfer() throws Exception {
+        String toBeRead = "Tadam";
+        ByteArrayInputStream bais = new ByteArrayInputStream(toBeRead.getBytes());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Streams.transfer(bais, baos);
+        Assert.assertEquals(toBeRead, new String(baos.toByteArray()));
+    }
+
+    public void testReadBytes() throws Exception {
+        String toBeRead = "Tadam";
+        ByteArrayInputStream bais = new ByteArrayInputStream(toBeRead.getBytes());
+        byte[] bytes = Streams.readBytes(bais);
+        Assert.assertEquals(toBeRead, new String(bytes));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java
new file mode 100644
index 0000000..44c7dd4
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.util;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+public class StringsTestCase extends TestCase {
+
+    private static final String CLASSNAME = StringsTestCase.class.getName();
+    private static final String PATH = "org/apache/felix/ipojo/manipulator/util/StringsTestCase.class";
+
+    public void testClassnameIsTransformedIntoNormalizedResourcePath() throws Exception {
+        Assert.assertEquals(PATH, Strings.asResourcePath(CLASSNAME));
+    }
+
+    public void testNormalizedResourcePathIsTransformedIntoClassname() throws Exception {
+        Assert.assertEquals(CLASSNAME, Strings.asClassName(PATH));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java
new file mode 100644
index 0000000..8539c60
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.check;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.ManipulationResultVisitor;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.*;
+
+
+public class CheckFieldConsistencyResultVisitorTestCase extends TestCase {
+
+    @Mock
+    private Reporter reporter;
+
+    @Mock
+    private ManipulationResultVisitor delegate;
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testVisitClassStructureOK() throws Exception {
+        Element component = newComponentElement();
+        CheckFieldConsistencyResultVisitor visitor = new CheckFieldConsistencyResultVisitor(delegate);
+        visitor.setReporter(reporter);
+        visitor.setMetadata(component);
+
+        Element manipulation = newManipulationElement(true);
+        visitor.visitClassStructure(manipulation);
+
+        verifyZeroInteractions(reporter);
+
+    }
+
+    public void testVisitClassStructureWithMissingFields() throws Exception {
+        Element component = newComponentElement();
+        CheckFieldConsistencyResultVisitor visitor = new CheckFieldConsistencyResultVisitor(delegate);
+        visitor.setReporter(reporter);
+        visitor.setMetadata(component);
+
+        Element manipulation = newManipulationElement(false);
+        visitor.visitClassStructure(manipulation);
+
+        verify(reporter).error(anyString());
+
+    }
+
+    private Element newManipulationElement(boolean complete) {
+        Element manipulation = new Element("manipulation", null);
+        if (complete) {
+            Element field = new Element("field", null);
+            field.addAttribute(new Attribute("name", "property"));
+            manipulation.addElement(field);
+        }
+
+        return manipulation;
+    }
+
+    private Element newComponentElement() {
+        Element component = new Element("component", null);
+        Element requires = new Element("requires", null);
+        requires.addAttribute(new Attribute("field", "property"));
+        component.addElement(requires);
+
+        return component;
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java
new file mode 100644
index 0000000..3bb4206
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.writer;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.manipulator.Reporter;
+import org.apache.felix.ipojo.manipulator.ResourceStore;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.mockito.Mockito.*;
+
+
+public class ManipulatedResourcesWriterTestCase extends TestCase {
+
+    @Mock
+    private Reporter reporter;
+
+    @Mock
+    private ResourceStore store;
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testVisitManipulationResult() throws Exception {
+        ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+        writer.setReporter(reporter);
+        writer.setResourceStore(store);
+
+        Element component = new Element("component", null);
+        assertNotNull(writer.visitManipulationResult(component));
+        verify(store).writeMetadata(same(component));
+    }
+
+    public void testVisitMetadata() throws Exception {
+        ManipulatedResourcesWriter writer = new ManipulatedResourcesWriter();
+        writer.setReporter(reporter);
+        writer.setResourceStore(store);
+
+        Element instance = new Element("instance", null);
+        writer.visitMetadata(instance);
+        verify(store).writeMetadata(same(instance));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java
new file mode 100644
index 0000000..8b5d149
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.manipulator.visitor.writer;
+
+import junit.framework.TestCase;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import static org.mockito.Mockito.*;
+
+
+public class ManipulatedResultWriterTestCase extends TestCase {
+
+    @Spy
+    private Element element = new Element("component", null);
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testVisitClassStructure() throws Exception {
+        ManipulatedResultWriter writer = new ManipulatedResultWriter(element);
+
+        Element manipulation = new Element("manipulation", null);
+        writer.visitClassStructure(manipulation);
+        verify(element).addElement(same(manipulation));
+    }
+
+    public void testVisitManipulatedResource() throws Exception {
+        ManipulatedResultWriter writer = new ManipulatedResultWriter(element);
+
+        writer.visitManipulatedResource("test.class", "Hello".getBytes());
+
+        assertNotNull(writer.getResources().get("test.class"));
+        assertEquals("Hello", new String(writer.getResources().get("test.class")));
+    }
+}
diff --git a/ipojo/manipulator/src/test/java/test/AnnotatedComponent.java b/ipojo/manipulator/src/test/java/test/AnnotatedComponent.java
new file mode 100644
index 0000000..186d4bb
--- /dev/null
+++ b/ipojo/manipulator/src/test/java/test/AnnotatedComponent.java
@@ -0,0 +1,18 @@
+package test;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: guillaume
+ * Date: 10/08/11
+ * Time: 21:56
+ * To change this template use File | Settings | File Templates.
+ */
+@Component
+public class AnnotatedComponent {
+
+    @Property
+    private String prop;
+}
diff --git a/ipojo/manipulator/src/test/resources/MANIFEST.MF b/ipojo/manipulator/src/test/resources/MANIFEST.MF
new file mode 100644
index 0000000..8bb4036
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Export-Package: org.apache.felix.ipojo.test.scenarios.manipulation.ser
+ vice
+Test-Suite: org.apache.felix.ipojo.test.scenarios.manipulation.Manipul
+ ationTestSuite
+Built-By: clement
+Tool: Bnd-0.0.357
+Bundle-Name: iPOJO Manipulation Test Suite For Java 5
+Created-By: Apache Maven Bundle Plugin
+Build-Jdk: 1.6.0_22
+Bundle-Version: 1.5.0.SNAPSHOT
+Bnd-LastModified: 1292008458378
+Bundle-ManifestVersion: 2
+Import-Package: junit.framework,org.apache.felix.ipojo;version="1.6",o
+ rg.apache.felix.ipojo.junit4osgi,org.apache.felix.ipojo.junit4osgi.he
+ lpers,org.apache.felix.ipojo.test.scenarios.manipulation.service,org.
+ osgi.framework;version="1.5"
+Bundle-SymbolicName: tests.manipulation.java5
+
diff --git a/ipojo/manipulator/src/test/resources/empty-metadata.xml b/ipojo/manipulator/src/test/resources/empty-metadata.xml
new file mode 100644
index 0000000..7308bd1
--- /dev/null
+++ b/ipojo/manipulator/src/test/resources/empty-metadata.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+       xmlns="org.apache.felix.ipojo" />
diff --git a/ipojo/plugin/pom.xml b/ipojo/plugin/pom.xml
index 408bfc9..0264577 100644
--- a/ipojo/plugin/pom.xml
+++ b/ipojo/plugin/pom.xml
@@ -118,6 +118,14 @@
           <configLocation>http://felix.apache.org/ipojo/dev/checkstyle_ipojo.xml</configLocation>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java b/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java
index 5fc4d6c..40b9261 100644
--- a/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java
+++ b/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/ManipulatorMojo.java
@@ -25,6 +25,7 @@
 import java.util.List;
 
 import org.apache.felix.ipojo.manipulator.Pojoization;
+import org.apache.felix.ipojo.manipulator.Reporter;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -222,7 +223,8 @@
 
         File out = new File(m_buildDirectory + File.separator + "_out.jar");
 
-        Pojoization pojo = new Pojoization();
+        Reporter reporter = new MavenReporter(getLog());
+        Pojoization pojo = new Pojoization(reporter);
         if (m_ignoreAnnotations) { pojo.disableAnnotationProcessing(); }
         if (!m_ignoreEmbeddedXSD) { pojo.setUseLocalXSD(); }
 
@@ -237,10 +239,12 @@
             pojo.pojoization(in, out, is);
         }
 
-        for (int i = 0; i < pojo.getWarnings().size(); i++) {
-            getLog().warn((String) pojo.getWarnings().get(i));
+        for (int i = 0; i < reporter.getWarnings().size(); i++) {
+            getLog().warn((String) reporter.getWarnings().get(i));
         }
-        if (pojo.getErrors().size() > 0) { throw new MojoExecutionException((String) pojo.getErrors().get(0)); }
+        if (reporter.getErrors().size() > 0) {
+            throw new MojoExecutionException((String) reporter.getErrors().get(0));
+        }
 
         if (m_classifier != null) {
             // The user want to attach the resulting jar
diff --git a/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java b/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java
new file mode 100644
index 0000000..6afdf97
--- /dev/null
+++ b/ipojo/plugin/src/main/java/org/apache/felix/ipojo/plugin/MavenReporter.java
@@ -0,0 +1,86 @@
+/*
+ * 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.plugin;
+
+import org.apache.felix.ipojo.manipulator.reporter.EmptyReporter;
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * A {@code MavenReporter} wraps a maven logging system into an iPOJO Reporter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MavenReporter extends EmptyReporter {
+
+    /**
+     * Maven logger.
+     */
+    private Log log;
+
+    public MavenReporter(Log log) {
+        this.log = log;
+    }
+
+    @Override
+    public void trace(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable t = getThrowable(args);
+        if (t != null) {
+            log.debug(formatted, t);
+        } else {
+            log.debug(formatted);
+        }
+    }
+
+    @Override
+    public void info(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable t = getThrowable(args);
+        if (t != null) {
+            log.info(formatted, t);
+        } else {
+            log.info(formatted);
+        }
+    }
+
+    @Override
+    public void warn(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable t = getThrowable(args);
+        if (t != null) {
+            log.warn(formatted, t);
+        } else {
+            log.warn(formatted);
+        }
+        getWarnings().add(formatted);
+    }
+
+    @Override
+    public void error(String message, Object... args) {
+        String formatted = String.format(message, getMessageArguments(args));
+        Throwable t = getThrowable(args);
+        if (t != null) {
+            log.error(formatted, t);
+        } else {
+            log.error(formatted);
+        }
+        getErrors().add(formatted);
+    }
+}