new manipulator structure - moved the manipulator

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1209860 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/manipulator/DEPENDENCIES b/ipojo/manipulator/manipulator/DEPENDENCIES
new file mode 100644
index 0000000..c4f5ede
--- /dev/null
+++ b/ipojo/manipulator/manipulator/DEPENDENCIES
@@ -0,0 +1,18 @@
+Apache Felix iPOJO Manipulator
+Copyright 2008-2011 The Apache Software Foundation
+
+This software was developed at the Apache Software Foundation
+(http://www.apache.org) and may have dependencies on other
+Apache software licensed under Apache License 2.0.
+
+I. Included Third-Party Software
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
+
+II. Used Third-Party Software
+
+III. Overall License Summary
+- Apache License 2.0
+- BSD License
diff --git a/ipojo/manipulator/manipulator/LICENSE b/ipojo/manipulator/manipulator/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ipojo/manipulator/manipulator/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ipojo/manipulator/manipulator/LICENSE.asm b/ipojo/manipulator/manipulator/LICENSE.asm
new file mode 100644
index 0000000..75ad085
--- /dev/null
+++ b/ipojo/manipulator/manipulator/LICENSE.asm
@@ -0,0 +1,29 @@
+Copyright (c) 2000-2005 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holders nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ipojo/manipulator/manipulator/NOTICE b/ipojo/manipulator/manipulator/NOTICE
new file mode 100644
index 0000000..4665c8b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/NOTICE
@@ -0,0 +1,10 @@
+Apache Felix iPOJO Manipulator
+Copyright 2008-2011 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Copyright (c) 2000-2005 INRIA, France Telecom
+Licensed under BSD License.
diff --git a/ipojo/manipulator/manipulator/doc/changelog.txt b/ipojo/manipulator/manipulator/doc/changelog.txt
new file mode 100644
index 0000000..6ad10c6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/doc/changelog.txt
@@ -0,0 +1,99 @@
+Changes from the 1.8.0 to 1.8.2

+-------------------------------

+** Bug

+    * [FELIX-2825] - The maven-ipojo-plugin does not replace component classes in WAR files

+

+

+Changes from the 1.6.4 to 1.8.0

+-------------------------------

+** Bug

+    * [FELIX-2779] - iPOJO manipulator badly supports custom annotation attributes of type Class

+    * [FELIX-2664] - Native methods should not be manipulated

+

+** Improvement

+    * [FELIX-1424] - Constructor Injection

+    * [FELIX-1428] - Constructor injection of Configuration properties

+    * [FELIX-2620] - Change iPojo annotation parameters to follow java naming conventions

+    * [FELIX-2621] - Rename annotations to remove collisions

+    * [FELIX-2622] - Support static service properties that are not mirrored into fields

+    * [FELIX-2630] - Rename @Component attributes to follow the java naming conventions

+    * [FELIX-2732] - [iPOJO] Service modified callback should define a default method name

+    * [FELIX-2742] - Constructor injection of service dependencies

+    * [FELIX-2743] - Modify Pojoization to be more easily customizable

+    * [FELIX-2755] - Allow the manipulator and the different front end to use several metadata files

+

+Changes from the 1.6.2 to 1.6.4

+-------------------------------

+** Bug

+    * [FELIX-2430] - IPOJO manipulation (ant task) results in invalid classes throwing java.lang.VerifyError at runtime in InstanceManager

+

+** Improvement

+    * [FELIX-2420] - Enum support for @Property annotation

+    * [FELIX-2461] - Allow specifying the targeted service interface in the @ServiceController

+    * [FELIX-2485] - Improve the performance of the manipulator on large files

+    * [FELIX-2542] - Annotations on methods parameters are not moved on public methods after manipulation

+

+Changes from the 1.6.0 to 1.6.2

+-------------------------------

+** Improvement

+    * [FELIX-2296] - Access to ServiceReference in iPOJO service.

+

+Changes from the 1.4.2 to 1.6.0

+-------------------------------

+** Improvement

+    * [FELIX-1427] - Service injection with Smart Proxies

+    * [FELIX-1646] - Add @Handler annotation to declare handlers without metadata.xml

+    * [FELIX-1906] - Allow calling a method when service properties of an already injected service are modified

+

+** Wish

+    * [FELIX-1940] - Add @Instance annotation to declare instances without metadata.xml

+

+

+Changes from the 1.4.0 to 1.4.2

+-------------------------------

+** Bug

+    * [FELIX-1411] - Issue on windows to find components inside bundle

+    * [FELIX-1518] - iPOJO manipulator is really slow even when annotation are ignored

+

+

+Changes from 1.2.0 to 1.4.0

+---------------------------

+** Bug

+    * [FELIX-1302] - Manipulator never ignore annotations

+    * [FELIX-1319] - Issue in the metadata overiding analysis in iPOJO annotations

+

+** Improvement

+    * Update parent pom

+    * [FELIX-943] - Allow iPOJO manipulator to manipulate directories

+

+

+Changes from 1.0.0 to 1.2.0

+---------------------------

+** Bug

+    * [FELIX-788] - Failed to create object that extends super class with BundleContext argument

+

+** Improvement

+    * [FELIX-813] - Resolve XML-Schemas locally rather than from Internet

+    * [FELIX-830] - Simplify the "id/parent" resolution to compute the metadata hierarchy during annotation processing

+    * [FELIX-846] - Enhance the iPojo maven plugin to take metadata from pom.

+    * [FELIX-876] - Specification auto import is not supported for simple component types

+

+

+Changes from 0.8.0 to 1.0.0

+---------------------------

+** Bug

+    * [FELIX-649] - "Expecting to find object/array on stack" Error when asking for instance of an iPOJO component

+    * [FELIX-697] - Generation of a duplicated field when using generics

+    * [FELIX-739] - iPOJO and annotations support when manipulating

+    * [FELIX-751] - Wrong access for setter methods

+

+** Improvement

+    * [FELIX-655] - Add a 'from' attribute in the service dependencies

+    * [FELIX-678] - Improve missing fields detection during the packaging process

+    * [FELIX-687] - Support inner and nested classes

+    * [FELIX-716] - Provide XML schemas for iPOJO descriptors

+

+

+Version 0.8.0

+-------------

+    * Initial release

diff --git a/ipojo/manipulator/manipulator/pom.xml b/ipojo/manipulator/manipulator/pom.xml
new file mode 100644
index 0000000..0f225e2
--- /dev/null
+++ b/ipojo/manipulator/manipulator/pom.xml
@@ -0,0 +1,149 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>felix-parent</artifactId>
+    <version>1.2.1</version>
+    <relativePath>../../../pom/pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>bundle</packaging>
+  <artifactId>org.apache.felix.ipojo.manipulator</artifactId>
+  <version>1.9.0-SNAPSHOT</version>
+  <name>Apache Felix iPOJO Manipulator</name>
+
+  <description>
+  iPOJO bytecode manipulator. This manipulator is used to instrument java classes in order to be managed by iPOJO.
+  </description>
+
+  <dependencies>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-all</artifactId>
+      <version>3.3.1</version>
+      <exclusions>
+        <exclusion>
+          <groupId>asm</groupId>
+          <artifactId>asm-tree</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.ipojo.metadata</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>org.apache.felix.ipojo.annotations</artifactId>
+        <version>1.8.0</version>
+      </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.8.5</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.4.3</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Name>iPOJO Manipulator</Bundle-Name>
+            <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>
+            <Private-Package> org.apache.felix.ipojo.manipulation,
+              org.apache.felix.ipojo.manipulation.annotations,
+              org.apache.felix.ipojo.xml.parser, org.objectweb.asm,
+              org.objectweb.asm.commons </Private-Package>
+            <Include-Resource>
+              META-INF/LICENSE=LICENSE,
+              META-INF/LICENSE.asm=LICENSE.asm,
+              META-INF/NOTICE=NOTICE,
+              META-INF/DEPENDENCIES=DEPENDENCIES,
+              {maven-resources}
+            </Include-Resource>
+            <Import-Package>!org.objectweb.asm.tree, *</Import-Package>
+          </instructions>
+          <obrRepository>NONE</obrRepository>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>rat-maven-plugin</artifactId>
+        <configuration>
+          <excludeSubProjects>false</excludeSubProjects>
+          <useEclipseDefaultExcludes>true</useEclipseDefaultExcludes>
+          <useMavenDefaultExcludes>true</useMavenDefaultExcludes>
+          <excludes>
+            <param>doc/*</param>
+            <param>maven-eclipse.xml</param>
+            <param>.checkstyle</param>
+            <param>.externalToolBuilders/*</param>
+            <param>LICENSE.asm</param>
+            <param>DEPENDENCIES</param>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <enableRulesSummary>false</enableRulesSummary>
+          <violationSeverity>warning</violationSeverity>
+          <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>
+
+    <resources>
+    <resource>
+      <directory>src/main/resources</directory>
+    </resource>
+    <resource>
+      <directory>.</directory>
+      <targetPath>META-INF</targetPath>
+      <includes>
+        <include>LICENSE*</include>
+        <include>NOTICE*</include>
+        <include>DEPENDENCIES*</include>
+      </includes>
+    </resource>
+  </resources>
+  </build>
+</project>
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
new file mode 100644
index 0000000..fe073f3
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ClassChecker.java
@@ -0,0 +1,693 @@
+/*

+ * 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.util.ArrayList;

+import java.util.List;

+import java.util.Map;

+import java.util.TreeMap;

+

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.ClassVisitor;

+import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+import org.objectweb.asm.commons.EmptyVisitor;

+

+/**

+ * Checks that a POJO is already manipulated or not.

+ * Moreover it allows to get manipulation data about this class.

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

+ */

+public class ClassChecker extends EmptyVisitor implements ClassVisitor, Opcodes {

+

+    /**

+     * True if the class is already manipulated.

+     */

+    private boolean m_isAlreadyManipulated = false;

+

+    /**

+     * Interfaces implemented by the component.

+     */

+    private List<String> m_itfs = new ArrayList<String>();

+

+    /**

+     * Field map [field name, type] discovered in the component class.

+     */

+    private Map<String, String> m_fields = new TreeMap<String, String>();

+

+    /**

+     * Method List of method descriptor discovered in the component class.

+     */

+    private List<MethodDescriptor> m_methods = new ArrayList<MethodDescriptor>();

+

+    /**

+     * Super class if not java.lang.Object.

+     */

+    private String m_superClass;

+

+    /**

+     * Class name.

+     */

+    private String m_className;

+

+    /**

+     * List of visited inner class owned by the implementation class.

+     */

+    private List<String> m_inners = new ArrayList<String>();

+

+    /**

+     * <code>true</code> if the class supports annotations.

+     * This enables the analysis of the code to find and moves annotations.

+     */

+    private boolean m_supportAnnotation = false;

+

+    /**

+     * Check if the _cm field already exists.

+     * Update the field list.

+     * @param access : access of the field

+     * @param name : name of the field

+     * @param desc : description of the field

+     * @param signature : signature of the field

+     * @param value : value of the field (for static field only)

+     * @return the field visitor

+     * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+     */

+    public FieldVisitor visitField(int access, String name, String desc,

+            String signature, Object value) {

+

+        if (access == ACC_PRIVATE && name.equals(MethodCreator.IM_FIELD)

+                && desc.equals("Lorg/apache/felix/ipojo/InstanceManager;")) {

+            m_isAlreadyManipulated = true;

+        } else if (name.startsWith("class$")) { // Does not add class$* field generated by 'x.class'

+            return null;

+        } else if ((access & ACC_STATIC) == ACC_STATIC) {

+            return null;

+        }

+

+        Type type = Type.getType(desc);

+        if (type.getSort() == Type.ARRAY) {

+            if (type.getInternalName().startsWith("L")) {

+                String internalType = type.getInternalName().substring(1);

+                String nameType = internalType.replace('/', '.');

+                m_fields.put(name, nameType + "[]");

+            } else {

+                String nameType = type.getClassName().substring(0,

+                        type.getClassName().length() - 2);

+                m_fields.put(name, nameType + "[]");

+            }

+        } else {

+            m_fields.put(name, type.getClassName());

+        }

+

+        return null;

+    }

+

+    /**

+     * Add the inner class to the list of inner class to manipulate.

+     * The method checks that the inner class is really owned by the implementation class.

+     * @param name inner class qualified name

+     * @param outerName outer class name (may be null for anonymous class)

+     * @param innerName inner class simple (i.e. short) name

+     * @param access inner class visibility

+     * @see org.objectweb.asm.commons.EmptyVisitor#visitInnerClass(java.lang.String, java.lang.String, java.lang.String, int)

+     */

+    public void visitInnerClass(String name, String outerName, String innerName, int access) {

+        if (m_className.equals(outerName)  || outerName == null) { // Anonymous classes does not have an outer class.

+            m_inners.add(name);

+        }

+    }

+

+

+    /**

+     * Check if the class was already manipulated.

+     * @return true if the class is already manipulated.

+     */

+    public boolean isalreadyManipulated() {

+        return m_isAlreadyManipulated;

+    }

+

+    /**

+     * Visit the class.

+     * Update the implemented interface list.

+     * @param version : version of the class

+     * @param access : access of the class

+     * @param name : name of the class

+     * @param signature : signature of the class

+     * @param superName : super class of the class

+     * @param interfaces : implemented interfaces.

+     * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public void visit(int version, int access, String name, String signature,

+            String superName, String[] interfaces) {

+

+        m_supportAnnotation = version > V1_4 && version < V1_1;

+

+        if (! superName.equals("java/lang/Object")) {

+            m_superClass = superName.replace('/', '.');

+        }

+

+        for (int i = 0; i < interfaces.length; i++) {

+            if (! interfaces[i].equals("org/apache/felix/ipojo/Pojo")) {

+                m_itfs.add(interfaces[i].replace('/', '.'));

+            }

+        }

+

+        m_className = name;

+    }

+

+    /**

+     * Visit a method.

+     * Update the method list (except if it init or clinit.

+     * @param  access - the method's access flags (see Opcodes). This parameter also indicates if the method is synthetic and/or deprecated.

+     * @param name - the method's name.

+     * @param desc - the method's descriptor (see Type).

+     * @param signature - the method's signature. May be null if the method parameters, return type and exceptions do not use generic types.

+     * @param exceptions - the internal names of the method's exception classes (see getInternalName). May be null.

+     * @return nothing.

+     * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public MethodVisitor visitMethod(int access, String name, String desc,

+            String signature, String[] exceptions) {

+        if (!name.equals("<clinit>")) {

+

+            if (name.equals("<init>")) {

+                final MethodDescriptor md = new MethodDescriptor("$init", desc);

+                m_methods.add(md);

+                if (m_supportAnnotation) {

+                    return new AnnotationCollector(md);

+                }

+            } else {

+                // no constructors.

+                if (!(name.startsWith("_get") || // Avoid getter method

+                        name.startsWith("_set") || // Avoid setter method

+                        name.equals("_setComponentManager") || // Avoid the set method

+                        name.equals("getComponentInstance"))) { // Avoid the getComponentInstance method

+                    final MethodDescriptor md = new MethodDescriptor(name, desc);

+                    m_methods.add(md);

+                    if (m_supportAnnotation) {

+                        return new AnnotationCollector(md);

+                    }

+                }

+            }

+

+        }

+

+        return null;

+    }

+

+    /**

+     * Get collected interfaces.

+     * @return the interfaces implemented by the component class.

+     */

+    public List<String> getInterfaces() {

+        return m_itfs;

+    }

+

+    /**

+     * Get collected fields.

+     * @return the field map [field_name, type].

+     */

+    public Map<String, String> getFields() {

+        return m_fields;

+    }

+

+    /**

+     * Get collected methods.

+     * @return the method list of [method, signature].

+     */

+    public List<MethodDescriptor> getMethods() {

+        return m_methods;

+    }

+

+    public String getSuperClass() {

+        return m_superClass;

+    }

+

+    public List<String> getInnerClasses() {

+        return m_inners;

+    }

+

+    /**

+     * This class collects annotations in a method.

+     * This class creates an {@link AnnotationDescriptor}

+     * if an annotation is found during the visit.

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

+     */

+    private final class AnnotationCollector extends EmptyVisitor {

+        /**

+         * The method descriptor of the visited method.

+         */

+        private MethodDescriptor m_method;

+

+        /**

+         * Creates an annotation collector.

+         * @param md the method descriptor of the visited method.

+         */

+        private AnnotationCollector(MethodDescriptor md) {

+            m_method = md;

+        }

+

+        /**

+         * Visits an annotation.

+         * This class checks the visibility. If the annotation is visible,

+         * creates the {@link AnnotationDescriptor} corresponding to this annotation

+         * to visit this annotation. This {@link AnnotationDescriptor} is added to

+         * the {@link MethodDescriptor} of the visited method.

+         * @param name the name of the annotation

+         * @param visible is the annotation visible at runtime

+         * @return the {@link AnnotationDescriptor} to visit this annotation or

+         * <code>null</code> if the annotation is not visible.

+         * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)

+         */

+        public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+            if (visible) {

+                AnnotationDescriptor ann = new AnnotationDescriptor(name, visible);

+                m_method.addAnnotation(ann);

+                return ann;

+            }

+            return null;

+        }

+

+        public AnnotationVisitor visitParameterAnnotation(int id,

+                String name, boolean visible) {

+            if (visible) {

+                AnnotationDescriptor ann = new AnnotationDescriptor(name, visible);

+                m_method.addParameterAnnotation(id, ann);

+                return ann;

+            }

+            return null;

+        }

+

+

+    }

+

+    /**

+     * Describes a method or constructor annotation.

+     * This allows creating a copy of the annotations found in the original class

+     * to move them on inserted method. This class implements an

+     * {@link AnnotationVisitor} in order to create the copy.

+     * This class contains a <code>visit</code> method re-injecting the

+     * annotation in the generated method.

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

+     */

+    public class AnnotationDescriptor implements AnnotationVisitor {

+        /**

+         * The name of the annotation.

+         */

+        private String m_name;

+        /**

+         * Is the annotation visible at runtime?

+         */

+        private boolean m_visible;

+        /**

+         * The description of the annotation.

+         * This attribute is set only for nested annotations.

+         */

+        private String m_desc;

+        /**

+         * The list of 'simple' attributes.

+         */

+        private List<SimpleAttribute> m_simples = new ArrayList<SimpleAttribute>(0);

+        /**

+         * The list of attribute containing an

+         * enumeration value.

+         */

+        private List<EnumAttribute> m_enums = new ArrayList<EnumAttribute>(0);

+        /**

+         * The list of attribute which are

+         * annotations.

+         */

+        private List<AnnotationDescriptor> m_nested = new ArrayList<AnnotationDescriptor>(0);

+        /**

+         * The list of attribute which are

+         * arrays.

+         */

+        private List<ArrayAttribute> m_arrays = new ArrayList<ArrayAttribute>(0);

+

+

+        /**

+         * Creates an annotation descriptor.

+         * This constructor is used for 'root' annotations.

+         * @param name the name of the  annotation

+         * @param visible the visibility of the annotation at runtime

+         */

+        public AnnotationDescriptor(String name, boolean visible) {

+            m_name = name;

+            m_visible = visible;

+        }

+

+        /**

+         * Creates an annotation descriptor.

+         * This constructor is used for nested annotations.

+         * @param name the name of the  annotation

+         * @param desc the descriptor of the annotation

+         */

+        public AnnotationDescriptor(String name, String desc) {

+            m_name = name;

+            m_visible = true;

+            m_desc = desc;

+        }

+

+

+        /**

+         * Visits a simple attribute.

+         * @param arg0 the attribute name

+         * @param arg1 the attribute value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            m_simples.add(new SimpleAttribute(arg0, arg1));

+        }

+

+

+        /**

+         * Visits a nested annotation.

+         * @param arg0 the attribute name

+         * @param arg1 the annotation descriptor

+         * @return the annotation visitor parsing the nested annotation

+         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)

+         */

+        public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+            AnnotationDescriptor ad = new AnnotationDescriptor(arg0, arg1);

+            m_nested.add(ad);

+            return ad;

+        }

+

+

+        /**

+         * Visits an array attribute.

+         * @param arg0 the name of the attribute

+         * @return the annotation visitor parsing the content of the array,

+         * uses a specific {@link ArrayAttribute} to parse this array

+         * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)

+         */

+        public AnnotationVisitor visitArray(String arg0) {

+            ArrayAttribute aa = new ArrayAttribute(arg0);

+            m_arrays.add(aa);

+            return aa;

+        }

+

+

+        /**

+         * End of the visit.

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() { }

+

+

+        /**

+         * Visits an enumeration attribute.

+         * @param arg0 the attribute name

+         * @param arg1 the enumeration descriptor

+         * @param arg2 the attribute value

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)

+         */

+        public void visitEnum(String arg0, String arg1, String arg2) {

+            m_enums.add(new EnumAttribute(arg0, arg1, arg2));

+        }

+

+        /**

+         * Methods allowing to recreate the visited (stored) annotation

+         * into the destination method.

+         * This method recreate the annotations itself and any other

+         * attributes.

+         * @param mv the method visitor visiting the destination method.

+         */

+        public void visitAnnotation(MethodVisitor mv) {

+            AnnotationVisitor av = mv.visitAnnotation(m_name, m_visible);

+            for (int i = 0; i < m_simples.size(); i++) {

+                m_simples.get(i).visit(av);

+            }

+            for (int i = 0; i < m_enums.size(); i++) {

+                m_enums.get(i).visit(av);

+            }

+            for (int i = 0; i < m_nested.size(); i++) {

+                m_nested.get(i).visit(av);

+            }

+            for (int i = 0; i < m_arrays.size(); i++) {

+                m_arrays.get(i).visit(av);

+            }

+            av.visitEnd();

+        }

+

+        /**

+         * Methods allowing to recreate the visited (stored) parameter annotations

+         * into the destination method.

+         * This method recreate the annotations itself and any other

+         * attributes.

+         * @param id the paramter id

+         * @param mv the method visitor visiting the destination method.

+         */

+        public void visitParameterAnnotation(int id, MethodVisitor mv) {

+            AnnotationVisitor av = mv.visitParameterAnnotation(id, m_name, m_visible);

+            for (int i = 0; i < m_simples.size(); i++) {

+                m_simples.get(i).visit(av);

+            }

+            for (int i = 0; i < m_enums.size(); i++) {

+                m_enums.get(i).visit(av);

+            }

+            for (int i = 0; i < m_nested.size(); i++) {

+                m_nested.get(i).visit(av);

+            }

+            for (int i = 0; i < m_arrays.size(); i++) {

+                m_arrays.get(i).visit(av);

+            }

+            av.visitEnd();

+        }

+

+        /**

+         * Method allowing to recreate the visited (stored) annotation

+         * into the destination annotation. This method is used only

+         * for nested annotation.

+         * @param mv the annotation visitor to populate with the stored

+         * annotation

+         */

+        public void visit(AnnotationVisitor mv) {

+            AnnotationVisitor av = mv.visitAnnotation(m_name, m_desc);

+            for (int i = 0; i < m_simples.size(); i++) {

+                m_simples.get(i).visit(av);

+            }

+            for (int i = 0; i < m_enums.size(); i++) {

+                m_enums.get(i).visit(av);

+            }

+            for (int i = 0; i < m_nested.size(); i++) {

+                m_nested.get(i).visit(av);

+            }

+            for (int i = 0; i < m_arrays.size(); i++) {

+                m_arrays.get(i).visit(av);

+            }

+            av.visitEnd();

+        }

+

+

+    }

+

+    /**

+     * Describes an array attribute.

+     * This class is able to visit an annotation array attribute, and to

+     * recreate this array on another annotation.

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

+     */

+    public class ArrayAttribute implements AnnotationVisitor {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The content of the parsed array.

+         */

+        private List<Object> m_content = new ArrayList<Object>();

+

+        /**

+         * Creates an array attribute.

+         * @param name the name of the attribute.

+         */

+        public ArrayAttribute(String name) {

+            m_name = name;

+        }

+

+        /**

+         * Visits the content of the array. This method is called for

+         * simple values.

+         * @param arg0 <code>null</code>

+         * @param arg1 the value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            m_content.add(arg1);

+        }

+

+        /**

+         * Visits the content of the array. This method is called for

+         * nested annotations (annotations contained in the array).

+         * @param arg0 <code>null</code>

+         * @param arg1 the annotation descriptor

+         * @return an {@link AnnotationDescriptor} which creates a copy of

+         * the contained annotation.

+         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(String, String)

+         */

+        public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+            AnnotationDescriptor ad = new AnnotationDescriptor(null, arg1);

+            m_content.add(ad);

+            return ad;

+        }

+

+        /**

+         * Visits the content of the array. This method is called for

+         * nested arrays (arrays contained in the array).

+         * @param arg0 <code>null</code>

+         * @return an {@link ArrayDescriptor} which creates a copy of

+         * the contained array.

+         * @see org.objectweb.asm.AnnotationVisitor#visitArray(String)

+         */

+        public AnnotationVisitor visitArray(String arg0) {

+            ArrayAttribute aa = new ArrayAttribute(null);

+            m_content.add(aa);

+            return aa;

+        }

+

+        /**

+         * End of the array attribute visit.

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() {  }

+

+        /**

+         * Visits the content of the array. This method is called for

+         * enumeration values.

+         * @param arg0 <code>null</code>

+         * @param arg1 the enumeration descriptor

+         * @param arg2 the value

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnum(String, String, String)

+         */

+        public void visitEnum(String arg0, String arg1, String arg2) {

+            EnumAttribute ea = new EnumAttribute(null, arg1, arg2);

+            m_content.add(ea);

+        }

+

+        /**

+         * Recreates the visited array attribute. This method

+         * handle the generation of the object embedded in the

+         * array.

+         * @param av the annotation visitor on which the array attribute

+         * needs to be injected.

+         */

+        public void visit(AnnotationVisitor av) {

+            AnnotationVisitor content = av.visitArray(m_name);

+            for (int i = 0; i < m_content.size(); i++) {

+                Object component = m_content.get(i);

+                if (component instanceof AnnotationDescriptor) {

+                    ((AnnotationDescriptor) component).visit(content);

+                } else if (component instanceof EnumAttribute) {

+                    ((EnumAttribute) component).visit(content);

+                } else if (component instanceof ArrayAttribute) {

+                    ((ArrayAttribute) component).visit(content);

+                } else { // Simple

+                    content.visit(null, component);

+                }

+            }

+            content.visitEnd();

+        }

+

+    }

+

+    /**

+     * Describes a simple attribute.

+     * This class is able to visit an annotation simple attribute, and to

+     * recreate this attribute on another annotation.

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

+     */

+    public static final class SimpleAttribute {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The value of the attribute.

+         */

+        private Object m_value;

+

+        /**

+         * Creates a simple attribute.

+         * @param name the name of the attribute

+         * @param object the value of the attribute

+         */

+        private SimpleAttribute(String name, Object object) {

+            m_name = name;

+            m_value = object;

+        }

+

+        /**

+         * Recreates the attribute on the given annotation.

+         * @param visitor the visitor on which the attribute needs

+         * to be injected.

+         */

+        public void visit(AnnotationVisitor visitor) {

+            visitor.visit(m_name, m_value);

+        }

+    }

+

+    /**

+     * Describes an attribute. The value of this attribute is an enumerated

+     * value.

+     * This class is able to visit an annotation enumeration attribute, and to

+     * recreate this attribute on another annotation.

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

+     */

+    public static final class EnumAttribute {

+        /**

+         * The name of the attribute.

+         */

+        private String m_name;

+        /**

+         * The descriptor of the enumeration.

+         */

+        private String m_desc;

+        /**

+         * The value of the attribute.

+         */

+        private String m_value;

+

+        /**

+         * Creates a enumeration attribute.

+         * @param name the name of the attribute.

+         * @param desc the descriptor of the {@link Enum}

+         * @param value the enumerated value

+         */

+        private EnumAttribute(String name, String desc, String value) {

+            m_name = name;

+            m_value = value;

+            m_desc = desc;

+        }

+

+        /**

+         * Recreates the attribute on the given annotation.

+         * @param visitor the visitor on which the attribute needs

+         * to be injected.

+         */

+        public void visit(AnnotationVisitor visitor) {

+            visitor.visitEnum(m_name, m_desc, m_value);

+        }

+

+    }

+

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
new file mode 100644
index 0000000..144219c
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ConstructorCodeAdapter.java
@@ -0,0 +1,239 @@
+/*

+ * 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.util.Set;

+

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.commons.GeneratorAdapter;

+

+

+/**

+ * Constructor Adapter.

+ * This class adds an instance manager argument (so switch variable index).

+ * Moreover, it adapts field accesses to delegate accesses to the instance

+ * manager if needed.

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

+ */

+public class ConstructorCodeAdapter extends GeneratorAdapter implements Opcodes {

+

+    /**

+     * The class containing the field.

+     * m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Is the super call detected ?

+     */

+    private boolean m_superDetected;

+

+    /**

+     * The super class.

+     */

+    private String m_superClass;

+

+    /**

+     * Set of contained fields.

+     */

+    private Set<String> m_fields;

+

+

+    /**

+     * PropertyCodeAdapter constructor.

+     * A new FiledCodeAdapter should be create for each method visit.

+     * @param mv the MethodVisitor

+     * @param owner the name of the class

+     * @param fields the list of contained fields

+     * @param access the constructor access

+     * @param desc the constructor descriptor

+     * @param name the name

+     */

+    public ConstructorCodeAdapter(final MethodVisitor mv, final String owner, Set<String> fields, int access, String name, String desc, String superClass) {

+        super(mv, access, name, desc);

+        m_owner = owner;

+        m_superDetected = false;

+        m_fields = fields;

+        m_superClass = superClass;

+    }

+

+    /**

+     * Visits an annotation.

+     * If the annotation is visible, the annotation is removed. In fact

+     * the annotation was already moved to the method replacing this one.

+     * If the annotation is not visible, this annotation is kept on this method.

+     * @param name the name of the annotation

+     * @param visible the annotation visibility

+     * @return the <code>null</code> if the annotation is visible, otherwise returns

+     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}

+     * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+        // Annotations are moved to the injected constructor.

+        if (visible) {

+            return null;

+        } else {

+            return super.visitAnnotation(name, visible);

+        }

+    }

+

+

+    /**

+     * Adapts field accesses.

+     * If the field is owned by the visited class:

+     * <ul>

+     * <li><code>GETFIELD</code> are changed to a <code>__getX</code> invocation.</li>

+     * <li><code>SETFIELD</code> are changed to a <code>__setX</code> invocation.</li>

+     * </ul>

+     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)

+     * @param opcode the visited operation code

+     * @param owner the owner of the field

+     * @param name the name of the field

+     * @param desc the descriptor of the field

+     */

+    public void visitFieldInsn(

+            final int opcode,

+            final String owner,

+            final String name,

+            final String desc) {

+        if (m_fields.contains(name) && m_owner.equals(owner)) {

+            if (opcode == GETFIELD) {

+                String gDesc = "()" + desc;

+                mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);

+                return;

+            } else

+                if (opcode == PUTFIELD) {

+                    String sDesc = "(" + desc + ")V";

+                    mv.visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);

+                    return;

+                }

+        }

+        super.visitFieldInsn(opcode, owner, name, desc);

+    }

+

+    /**

+     * Visits a method invocation instruction.

+     * After the super constructor invocation, insert the _setComponentManager invocation.

+     * Otherwise, the method invocation doesn't change

+     * @param opcode the opcode

+     * @param owner the class owning the invoked method

+     * @param name the method name

+     * @param desc the method descriptor

+     * @see org.objectweb.asm.MethodAdapter#visitMethodInsn(int, java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {

+

+        // A method call is detected, check if it is the super call :

+        // the first init is not necessary the super call, so check that it is really the super class.

+        if (!m_superDetected && name.equals("<init>")  && owner.equals(m_superClass)) {

+            m_superDetected = true;

+            // The first invocation is the super call

+            // 1) Visit the super constructor :

+

+            //mv.visitVarInsn(ALOAD, 0); The ALOAD 0 was already visited. This previous visit allows

+                                         // Super constructor parameters.

+            mv.visitMethodInsn(opcode, owner, name, desc); // Super constructor invocation

+

+            // 2) Load the object and the component manager argument

+            mv.visitVarInsn(ALOAD, 0);

+            //mv.visitVarInsn(ALOAD, Type.getArgumentTypes(m_constructorDesc).length);

+            mv.visitVarInsn(ALOAD, 1);  // CM is always the first argument

+            // 3) Initialize the field

+            mv.visitMethodInsn(INVOKESPECIAL, m_owner, "_setInstanceManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V");

+

+        } else {

+            mv.visitMethodInsn(opcode, owner, name, desc);

+        }

+    }

+

+    /**

+     * Visits a variable instruction.

+     * This method increments the variable index if

+     * it is not <code>this</code> (i.e. 0). This increment

+     * is due to the instance manager parameter added in the method

+     * signature.

+     * @param opcode the opcode

+     * @param var the variable index

+     * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)

+     */

+    public void visitVarInsn(int opcode, int var) {

+        if (var == 0) {

+            mv.visitVarInsn(opcode, var); // ALOAD 0 (THIS)

+        } else {

+            mv.visitVarInsn(opcode, var + 1); // All other variable index must be incremented (due to

+                                              // the instance manager argument

+        }

+

+    }

+

+    /**

+     * Visits an increment instruction.

+     * This method increments the variable index if

+     * it is not <code>this</code> (i.e. 0). This increment

+     * is due to the instance manager parameter added in the method

+     * signature.

+     * @param var the variable index

+     * @param increment the increment

+     * @see org.objectweb.asm.MethodAdapter#visitIincInsn(int, int)

+     */

+    public void visitIincInsn(int var, int increment) {

+        if (var != 0) {

+            mv.visitIincInsn(var + 1, increment);

+        } else {

+            mv.visitIincInsn(var, increment); // Increment the current object ???

+        }

+    }

+

+    /**

+     * Visits a local variable.

+     * Adds _manager and increment others variable indexes.

+     * This variable has the same scope than <code>this</code> and

+     * has the <code>1</code> index.

+     * @param name the variable name

+     * @param desc the variable descriptor

+     * @param signature the variable signature

+     * @param start the beginning label

+     * @param end the ending label

+     * @param index the variable index

+     * @see org.objectweb.asm.MethodAdapter#visitLocalVariable(java.lang.String, java.lang.String, java.lang.String, org.objectweb.asm.Label, org.objectweb.asm.Label, int)

+     */

+    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {

+        if (index == 0) {

+            mv.visitLocalVariable(name, desc, signature, start, end, index);

+            mv.visitLocalVariable("_manager", "Lorg/apache/felix/ipojo/InstanceManager;", null, start, end, 1);

+        }

+        mv.visitLocalVariable(name, desc, signature, start, end, index + 1);

+    }

+

+    /**

+     * Visit max method.

+     * The stack size is incremented of 1. The

+     * local variable count is incremented of 2.

+     * @param maxStack the stack size.

+     * @param maxLocals the local variable count.

+     * @see org.objectweb.asm.MethodAdapter#visitMaxs(int, int)

+     */

+    public void visitMaxs(int maxStack, int maxLocals) {

+        mv.visitMaxs(maxStack + 1, maxLocals + 2);

+    }

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
new file mode 100644
index 0000000..2a90496
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassAdapter.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util.Set;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Adapts a inner class in order to allow accessing outer class fields.
+ * A manipulated inner class has access to the managed field of the outer class.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InnerClassAdapter extends ClassAdapter implements Opcodes {
+
+    /**
+     * Implementation class name.
+     */
+    private String m_outer;
+
+    /**
+     * List of fields of the implementation class.
+     */
+    private Set<String> m_fields;
+
+    /**
+     * Creates the inner class adapter.
+     * @param arg0 parent class visitor
+     * @param outerClass outer class (implementation class)
+     * @param fields fields of the implementation class
+     */
+    public InnerClassAdapter(ClassVisitor arg0, String outerClass, Set<String> fields) {
+        super(arg0);
+        m_outer = outerClass;
+        m_fields = fields;
+    }
+
+    /**
+     * Visits a method.
+     * This methods create a code visitor manipulating outer class field accesses.
+     * @param access method visibility
+     * @param name method name
+     * @param desc method descriptor
+     * @param signature method signature
+     * @param exceptions list of exceptions thrown by the method
+     * @return a code adapter manipulating field accesses
+     * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+     */
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+        return new MethodCodeAdapter(mv, m_outer, access, name, desc, m_fields);
+    }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
new file mode 100644
index 0000000..a3f9799
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/InnerClassManipulator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.Set;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * Manipulates inner class allowing outer class access. The manipulated class
+ * has access to managed field of the outer class.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class InnerClassManipulator {
+
+    /**
+     * Outer class class name.
+     */
+    private String m_outer;
+
+    /**
+     * Component class fields.
+     */
+    private Set<String> m_fields;
+
+    /**
+     * Creates an inner class manipulator.
+     * @param classname : class name
+     * @param fields : fields
+     */
+    public InnerClassManipulator(String classname, Set<String> fields) {
+        m_outer = classname;
+        m_fields = fields;
+    }
+
+    /**
+     * Manipulate the inner class.
+     * @param in input (i.e. original) class
+     * @return manipulated class
+     * @throws IOException the class cannot be read correctly
+     */
+    public byte[] manipulate(byte[] in) throws IOException {
+        InputStream is1 = new ByteArrayInputStream(in);
+
+        ClassReader cr = new ClassReader(is1);
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        InnerClassAdapter adapter = new InnerClassAdapter(cw, m_outer, m_fields);
+        cr.accept(adapter, ClassReader.SKIP_FRAMES);
+        is1.close();
+
+        return cw.toByteArray();
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
new file mode 100644
index 0000000..fd852a8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/ManipulationProperty.java
@@ -0,0 +1,124 @@
+/* 

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.felix.ipojo.manipulation;

+

+/**

+ * Store properties for the manipulation process.

+ * 

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

+ * 

+ */

+public class ManipulationProperty {

+    

+    /**

+     * Logger info level.

+     */

+    public static final int INFO = 0;

+    

+    /**

+     * Logger warning level. 

+     */

+    public static final int WARNING = 1;

+    

+    /**

+     * Logger severe level. 

+     */

+    public static final int SEVERE = 2;

+    

+    /**

+     * Activator internal package name.

+     */

+    protected static final String IPOJO_INTERNAL_PACKAGE_NAME = "org/apache/felix/ipojo/";

+

+    /**

+     * Ipojo internal package name for internal descriptor.

+     */

+    protected static final String IPOJO_INTERNAL_DESCRIPTOR = "L" + IPOJO_INTERNAL_PACKAGE_NAME;

+

+    /**

+     * iPOJO Package name.

+     */

+    protected static final String IPOJO_PACKAGE_NAME = "org.apache.felix.ipojo";

+

+    /**

+     * Helper array for byte code manipulation of primitive type.

+     */

+    static final String[][] PRIMITIVE_BOXING_INFORMATION = new String[][] { 

+        {"V", "ILLEGAL", "ILLEGAL"}, 

+        {"Z", "java/lang/Boolean", "booleanValue"},

+        {"C", "java/lang/Character", "charValue"}, 

+        {"B", "java/lang/Byte", "byteValue"}, 

+        {"S", "java/lang/Short", "shortValue"}, 

+        {"I", "java/lang/Integer", "intValue"},

+        {"F", "java/lang/Float", "floatValue"}, 

+        {"J", "java/lang/Long", "longValue"}, 

+        {"D", "java/lang/Double", "doubleValue"}

+    };

+    

+    /**

+     * Internal logger implementation.

+     */

+    protected static class Logger {

+        /**

+         * Log method.

+         * @param level : level

+         * @param message : message to log

+         */

+        public void log(int level, String message) {

+            if (level >= LOG_LEVEL) {

+                switch (level) {

+                    case INFO:

+                        System.err.println("[INFO] " + message);

+                        break;

+                    case WARNING:

+                        System.err.println("[WARNING] " + message);

+                        break;

+                    case SEVERE:

+                        System.err.println("[SEVERE] " + message);

+                        break;

+                    default:

+                        System.err.println("[SEVERE] " + message);

+                        break;

+                }

+            }

+        }

+    }

+

+    /**

+     * Manipulator logger.

+     */

+    private static Logger LOGGER;

+

+    /**

+     * Default logger level.

+     */

+    private static int LOG_LEVEL = WARNING;

+    

+

+    /**

+     * Get the manipulator logger.

+     * @return the logger used by the manipulator.

+     */

+    public static Logger getLogger() {

+        if (LOGGER == null) {

+            LOGGER = new Logger();

+        }

+        return LOGGER;

+    }

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
new file mode 100644
index 0000000..395a5d9
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/Manipulator.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.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<String, String> m_fields;
+
+    /**
+     * Store the interface implemented by the class.
+     */
+    private List<String> m_interfaces;
+
+    /**
+     * Store the methods list.
+     */
+    private List<MethodDescriptor> 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  | ClassWriter.COMPUTE_FRAMES);
+            //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<String> it = m_fields.keySet().iterator(); it.hasNext();) {
+            Element field = new Element("Field", "");
+            String name = it.next();
+            String type = 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<String, String> getFields() {
+        return m_fields;
+    }
+
+    public List<String> getInnerClasses() {
+        return m_inners;
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
new file mode 100644
index 0000000..5182977
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCodeAdapter.java
@@ -0,0 +1,121 @@
+/*

+ * 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.util.Set;

+

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.commons.GeneratorAdapter;

+

+/**

+ * Insert code calling callbacks at the entry and before the exit of a method.

+ * Moreover it replaces all GETFIELD and SETFIELD by getter and setter invocation.

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

+ */

+public class MethodCodeAdapter extends GeneratorAdapter implements Opcodes {

+

+    /**

+     * The owner class of the field. m_owner : String

+     */

+    private String m_owner;

+

+    /**

+     * Contained fields.

+     */

+    private Set<String> m_fields;

+

+    /**

+     * MethodCodeAdapter constructor.

+     * @param mv : MethodVisitor

+     * @param owner : Name of the class

+     * @param access : Method access

+     * @param name : Method name

+     * @param desc : Method descriptor

+     * @param fields : Contained fields

+     */

+    public MethodCodeAdapter(final MethodVisitor mv, final String owner, int access, String name, String desc, Set<String> fields) {

+        super(mv, access, name, desc);

+        m_owner = owner;

+        m_fields = fields;

+    }

+

+    /**

+     * Visit an instruction modifying a method (GETFIELD/PUTFIELD).

+     * @see org.objectweb.asm.MethodVisitor#visitFieldInsn(int, String, String, String)

+     * @param opcode : visited operation code

+     * @param owner : owner of the field

+     * @param name : name of the field

+     * @param desc : descriptor of the field

+     */

+    public void visitFieldInsn(final int opcode, final String owner, final String name, final String desc) {

+        if (owner.equals(m_owner) && m_fields.contains(name)) {

+            if (opcode == GETFIELD) {

+                String gDesc = "()" + desc;

+                visitMethodInsn(INVOKEVIRTUAL, owner, "__get" + name, gDesc);

+                return;

+            } else if (opcode == PUTFIELD) {

+                String sDesc = "(" + desc + ")V";

+                visitMethodInsn(INVOKEVIRTUAL, owner, "__set" + name, sDesc);

+                return;

+            }

+        }

+        super.visitFieldInsn(opcode, owner, name, desc);

+    }

+

+    /**

+     * Visits an annotation.

+     * If the annotation is visible, the annotation is removed. In fact

+     * the annotation was already moved to the method replacing this one.

+     * If the annotation is not visible, this annotation is kept on this method.

+     * @param name the name of the annotation

+     * @param visible the annotation visibility

+     * @return the <code>null</code> if the annotation is visible, otherwise returns

+     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}

+     * @see org.objectweb.asm.MethodAdapter#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String name, boolean visible) {

+        // Annotations are moved to the injected constructor.

+        if (visible) {

+            return null;

+        } else {

+            return super.visitAnnotation(name, visible);

+        }

+    }

+

+    /**

+     * Visits a parameter annotation.

+     * @param id the parameter number.

+     * @param name the annotation name

+     * @param visible if te annotation visibility

+     * @return the <code>null</code> if the annotation is visible, otherwise returns

+     * {@link GeneratorAdapter#visitAnnotation(String, boolean)}

+     * @see org.objectweb.asm.MethodAdapter#visitParameterAnnotation(int, java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitParameterAnnotation(int id, String name,

+            boolean visible) {

+        if (visible) {

+            return null;

+        } else {

+            return super.visitParameterAnnotation(id, name, visible);

+        }

+    }

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
new file mode 100644
index 0000000..60cff80
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodCreator.java
@@ -0,0 +1,1066 @@
+/*

+ * 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.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+import java.util.Map;

+import java.util.Set;

+

+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;

+import org.objectweb.asm.ClassAdapter;

+import org.objectweb.asm.ClassVisitor;

+import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.Label;

+import org.objectweb.asm.MethodVisitor;

+import org.objectweb.asm.Opcodes;

+import org.objectweb.asm.Type;

+import org.objectweb.asm.commons.GeneratorAdapter;

+

+/**

+ * iPOJO Class Adapter.

+ * This class adapt the visited class to link the class with the container.

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

+ */

+public class MethodCreator extends ClassAdapter implements Opcodes {

+

+    /**

+     * Instance Manager Field.

+     */

+    public static final  String IM_FIELD = "__IM";

+

+    /**

+     * All POJO method will be renamed by using this prefix.

+     */

+    public static final String PREFIX = "__M_";

+

+    /**

+     * POJO class.

+     */

+    private static final  String POJO = "org/apache/felix/ipojo/Pojo";

+

+    /**

+     * Filed flag prefix.

+     */

+    private static final  String FIELD_FLAG_PREFIX = "__F";

+

+    /**

+     * Method flag prefix.

+     */

+    private static final  String METHOD_FLAG_PREFIX = "__M";

+

+    /**

+     * onEntry method name.

+     */

+    private static final  String ENTRY = "onEntry";

+

+    /**

+     * onExit method name.

+     */

+    private static final  String EXIT = "onExit";

+

+    /**

+     * on Error method name.

+     */

+    private static final  String ERROR = "onError";

+

+    /**

+     * onGet method name.

+     */

+    private static final  String GET = "onGet";

+

+    /**

+     * onSet method name.

+     */

+    private static final  String SET = "onSet";

+

+    /**

+     * Name of the current manipulated class.

+     */

+    private String m_owner;

+

+    /**

+     * Set of fields detected in the class.

+     * (this set is given by the previous analysis)

+     */

+    private Set<String> m_fields;

+

+    /**

+     * List of methods contained in the class.

+     * This set contains method id.

+     */

+    private List<String> m_methods = new ArrayList<String>();

+

+    /**

+     * List of fields injected as method flag in the class.

+     * This set contains field name generate from method id.

+     */

+    private List<String> m_methodFlags = new ArrayList<String>();

+

+    /**

+     * The list of methods visited during the previous analysis.

+     * This list allows getting annotations to move to generated

+     * method.

+     */

+    private List<MethodDescriptor> m_visitedMethods = new ArrayList<MethodDescriptor>();

+

+    /**

+     * Set to <code>true</code> when a suitable constructor

+     * is found. If not set to <code>true</code> at the end

+     * of the visit, the manipulator injects a constructor.

+     */

+    private boolean m_foundSuitableConstructor = false;

+

+    /**

+     * Name of the super class.

+     */

+    private String m_superclass;

+

+    /**

+     * Constructor.

+     * @param arg0 : class visitor.

+     * @param fields : fields map detected during the previous class analysis.

+     * @param methods : the list of the detected method during the previous class analysis.

+     */

+    public MethodCreator(ClassVisitor arg0, Map<String, String> fields, List<MethodDescriptor> methods) {

+        super(arg0);

+        m_fields = fields.keySet();

+        m_visitedMethods = methods;

+    }

+

+    /**

+     * Visit method.

+     * This method store the current class name.

+     * Moreover the POJO interface is added to the list of implemented interface.

+     * Then the Instance manager field is added.

+     * @param version : version

+     * @param access : access flag

+     * @param name : class name

+     * @param signature : signature

+     * @param superName : parent class

+     * @param interfaces : implemented interface

+     * @see org.objectweb.asm.ClassAdapter#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {

+        m_owner = name;

+        m_superclass = superName;

+        addPOJOInterface(version, access, name, signature, superName, interfaces);

+        addIMField();

+    }

+

+    /**

+     * A method is visited.

+     * This method does not manipulate clinit and class$ methods.

+     * In the case of a constructor, this method will generate a constructor with the instance manager

+     * and will adapt the current constructor to call this constructor.

+     * For standard method, this method will create method header, rename the current method and adapt it.

+     * @param access : access flag.

+     * @param name : name of the method

+     * @param desc : method descriptor

+     * @param signature : signature

+     * @param exceptions : declared exceptions.

+     * @return the MethodVisitor wich will visit the method code.

+     * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])

+     */

+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

+        // Avoid manipulating special methods

+        if (name.equals("<clinit>") || name.equals("class$")) { return super.visitMethod(access, name, desc, signature, exceptions); }

+        // The constructor is manipulated separately

+        if (name.equals("<init>")) {

+            MethodDescriptor md = getMethodDescriptor("$init", desc);

+            // 1) change the constructor descriptor (add a component manager arg as first argument)

+            String newDesc = desc.substring(1);

+            newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

+

+            Type[] args = Type.getArgumentTypes(desc);

+

+            // TODO HERE ! => All constructor matches, no distinction between the different constructors.

+            generateConstructor(access, desc, signature, exceptions, md.getAnnotations(), md.getParameterAnnotations());

+

+            if (args.length == 0) {

+                m_foundSuitableConstructor = true;

+            } else if (args.length == 1 && args[0].getClassName().equals("org.osgi.framework.BundleContext")) {

+                m_foundSuitableConstructor = true;

+            }

+

+            // Insert the new constructor

+            MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "<init>", newDesc, signature, exceptions);

+            return new ConstructorCodeAdapter(mv, m_owner, m_fields, ACC_PRIVATE, name, newDesc, m_superclass);

+        }

+

+        if ((access & ACC_SYNTHETIC) == ACC_SYNTHETIC && name.startsWith("access$")) {

+            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

+            return new MethodCodeAdapter(mv, m_owner, access, name, desc, m_fields);

+        }

+

+        // Do nothing on static methods

+        if ((access & ACC_STATIC) == ACC_STATIC) { return super.visitMethod(access, name, desc, signature, exceptions); }

+

+        // Do nothing on native methods

+        if ((access & ACC_NATIVE) == ACC_NATIVE) { return super.visitMethod(access, name, desc, signature, exceptions); }

+

+        MethodDescriptor md = getMethodDescriptor(name, desc);

+        if (md == null) {

+            generateMethodHeader(access, name, desc, signature, exceptions, null, null);

+        } else {

+            generateMethodHeader(access, name, desc, signature, exceptions, md.getAnnotations(), md.getParameterAnnotations());

+        }

+

+        String id = generateMethodFlag(name, desc);

+        if (! m_methodFlags.contains(id)) {

+            FieldVisitor flagField = cv.visitField(Opcodes.ACC_PRIVATE, id, "Z", null, null);

+            flagField.visitEnd();

+            m_methodFlags.add(id);

+        }

+

+        MethodVisitor mv = super.visitMethod(ACC_PRIVATE, PREFIX + name, desc, signature, exceptions);

+        return new MethodCodeAdapter(mv, m_owner, ACC_PRIVATE, PREFIX + name, desc, m_fields);

+    }

+

+    /**

+     * Gets the method descriptor for the specified name and descriptor.

+     * The method descriptor is looked inside the

+     * {@link MethodCreator#m_visitedMethods}

+     * @param name the name of the method

+     * @param desc the descriptor of the method

+     * @return the method descriptor or <code>null</code> if not found.

+     */

+    private MethodDescriptor getMethodDescriptor(String name, String desc) {

+        for (int i = 0; i < m_visitedMethods.size(); i++) {

+            MethodDescriptor md = m_visitedMethods.get(i);

+            if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {

+                return md;

+            }

+        }

+        return null;

+    }

+

+    /**

+     * Visit a Field.

+     * This field access is replaced by an invocation to the getter method or to the setter method.

+     * (except for static field).

+     * Inject the getter and the setter method for this field.

+     * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)

+     * @param access : access modifier

+     * @param name : name of the field

+     * @param desc : description of the field

+     * @param signature : signature of the field

+     * @param value : value of the field

+     * @return FieldVisitor : null

+     */

+    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) {

+        if ((access & ACC_STATIC) == 0) {

+            FieldVisitor flag = cv.visitField(Opcodes.ACC_PRIVATE, FIELD_FLAG_PREFIX + name, "Z", null, null);

+            flag.visitEnd();

+

+            Type type = Type.getType(desc);

+

+            if (type.getSort() == Type.ARRAY) {

+                String gDesc = "()" + desc;

+                createArrayGetter(name, gDesc, type);

+

+                // Generates setter method

+                String sDesc = "(" + desc + ")V";

+                createArraySetter(name, sDesc, type);

+

+            } else {

+                // Generate the getter method

+                String gDesc = "()" + desc;

+                createSimpleGetter(name, gDesc, type);

+

+                // Generates setter method

+                String sDesc = "(" + desc + ")V";

+                createSimpleSetter(name, sDesc, type);

+            }

+

+        }

+        return cv.visitField(access, name, desc, signature, value);

+    }

+

+    /**

+     * Modify the given constructor to be something like:

+     * <code>

+     * this(null, params...);

+     * return;

+     * </code>

+     * The actual constructor is modified to support the instance manager argument.

+     * @param access : access flag

+     * @param descriptor : the original constructor descriptor

+     * @param signature : method signature

+     * @param exceptions : declared exception

+     * @param annotations : the annotations to move to this constructor.

+     */

+    private void generateConstructor(int access, String descriptor, String signature, String[] exceptions, List<AnnotationDescriptor> annotations, Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {

+         GeneratorAdapter mv = new GeneratorAdapter(

+                 cv.visitMethod(access, "<init>", descriptor, signature, exceptions),

+                 access, "<init>", descriptor);

+         // Compute the new signature

+         String newDesc = descriptor.substring(1); // Remove the first (

+         newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

+

+         mv.visitCode();

+         mv.visitVarInsn(ALOAD, 0);

+         mv.visitInsn(ACONST_NULL);

+         mv.loadArgs();

+         mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", newDesc);

+         mv.visitInsn(RETURN);

+

+         // Move annotations

+         if (annotations != null) {

+             for (int i = 0; i < annotations.size(); i++) {

+                 AnnotationDescriptor ad = annotations.get(i);

+                 ad.visitAnnotation(mv);

+             }

+         }

+

+         // Move parameter annotations if any

+         if (paramAnnotations != null  && ! paramAnnotations.isEmpty()) {

+             Iterator<Integer> ids = paramAnnotations.keySet().iterator();

+             while(ids.hasNext()) {

+                 Integer id = ids.next();

+                 List<AnnotationDescriptor> ads = paramAnnotations.get(id);

+                 for (int i = 0; i < ads.size(); i++) {

+                     AnnotationDescriptor ad = ads.get(i);

+                     ad.visitParameterAnnotation(id.intValue(), mv);

+                 }

+             }

+         }

+

+         mv.visitMaxs(0, 0);

+         mv.visitEnd();

+    }

+

+    /**

+     * Generate the method header of a POJO method.

+     * This method header encapsulate the POJO method call to

+     * signal entry exit and error to the container.

+     * @param access : access flag.

+     * @param name : method name.

+     * @param desc : method descriptor.

+     * @param signature : method signature.

+     * @param exceptions : declared exceptions.

+     * @param annotations : the annotations to move to this method.

+     * @param paramAnnotations : the parameter annotations to move to this method.

+     */

+    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions, List<AnnotationDescriptor> annotations, Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {

+        GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions), access, name, desc);

+

+        mv.visitCode();

+

+        Type returnType = Type.getReturnType(desc);

+

+        // Compute result and exception stack location

+        int result = -1;

+        int exception = -1;

+

+        //int arguments = mv.newLocal(Type.getType((new Object[0]).getClass()));

+

+        if (returnType.getSort() != Type.VOID) {

+            // The method returns something

+            result = mv.newLocal(returnType);

+            exception = mv.newLocal(Type.getType(Throwable.class));

+        } else {

+            exception = mv.newLocal(Type.getType(Throwable.class));

+        }

+

+        Label l0 = new Label();

+        Label l1 = new Label();

+        Label l2 = new Label();

+

+        mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, generateMethodFlag(name, desc), "Z");

+        mv.visitJumpInsn(IFNE, l0);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.loadArgs();

+        mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc);

+        mv.visitInsn(returnType.getOpcode(IRETURN));

+

+        // end of the non intercepted method invocation.

+

+        mv.visitLabel(l0);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitLdcInsn(generateMethodId(name, desc));

+        mv.loadArgArray();

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ENTRY, "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V");

+

+        mv.visitVarInsn(ALOAD, 0);

+

+        // Do not allow argument modification : just reload arguments.

+        mv.loadArgs();

+        mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc);

+

+        if (returnType.getSort() != Type.VOID) {

+            mv.visitVarInsn(returnType.getOpcode(ISTORE), result);

+        }

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitLdcInsn(generateMethodId(name, desc));

+        if (returnType.getSort() != Type.VOID) {

+            mv.visitVarInsn(returnType.getOpcode(ILOAD), result);

+            mv.box(returnType);

+        } else {

+            mv.visitInsn(ACONST_NULL);

+        }

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", EXIT, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");

+

+        mv.visitLabel(l1);

+        Label l7 = new Label();

+        mv.visitJumpInsn(GOTO, l7);

+        mv.visitLabel(l2);

+

+        mv.visitVarInsn(ASTORE, exception);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitLdcInsn(generateMethodId(name, desc));

+        mv.visitVarInsn(ALOAD, exception);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ERROR, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V");

+        mv.visitVarInsn(ALOAD, exception);

+        mv.visitInsn(ATHROW);

+

+        mv.visitLabel(l7);

+        if (returnType.getSort() != Type.VOID) {

+            mv.visitVarInsn(returnType.getOpcode(ILOAD), result);

+        }

+        mv.visitInsn(returnType.getOpcode(IRETURN));

+

+        // Move annotations

+        if (annotations != null) {

+            for (int i = 0; i < annotations.size(); i++) {

+                AnnotationDescriptor ad = annotations.get(i);

+                ad.visitAnnotation(mv);

+            }

+        }

+

+        // Move parameter annotations

+        if (paramAnnotations != null  && ! paramAnnotations.isEmpty()) {

+            Iterator<Integer> ids = paramAnnotations.keySet().iterator();

+            while(ids.hasNext()) {

+                Integer id = ids.next();

+                List<AnnotationDescriptor> ads = paramAnnotations.get(id);

+                for (int i = 0; i < ads.size(); i++) {

+                    AnnotationDescriptor ad = ads.get(i);

+                    ad.visitParameterAnnotation(id.intValue(), mv);

+                }

+            }

+        }

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Generate a method flag name.

+     * @param name : method name.

+     * @param desc : method descriptor.

+     * @return the method flag name

+     */

+    private String generateMethodFlag(String name, String desc) {

+        return METHOD_FLAG_PREFIX + generateMethodId(name, desc);

+    }

+

+    /**

+     * Generate the method id based on the given method name and method descriptor.

+     * The method Id is unique for this method and serves to create the flag field (so

+     * must follow field name Java restrictions).

+     * @param name : method name

+     * @param desc : method descriptor

+     * @return  method ID

+     */

+    private String generateMethodId(String name, String desc) {

+        StringBuffer id = new StringBuffer(name);

+        Type[] args = Type.getArgumentTypes(desc);

+        for (int i = 0; i < args.length; i++) {

+            String arg = args[i].getClassName();

+            if (arg.endsWith("[]")) {

+                arg = arg.substring(0, arg.length() - 2);

+                id.append("$" + arg.replace('.', '_') + "__");

+            } else {

+                id.append("$" + arg.replace('.', '_'));

+            }

+        }

+        if (!m_methods.contains(id.toString())) {

+            m_methods.add(id.toString());

+        }

+        return id.toString();

+    }

+

+    /**

+     * Add the instance manager field (__im).

+     */

+    private void addIMField() {

+        FieldVisitor fv = super.visitField(ACC_PRIVATE, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;", null, null);

+        fv.visitEnd();

+    }

+

+    /**

+     * Add the POJO interface to the visited class.

+     * @param version : class version

+     * @param access : class access

+     * @param name : class name

+     * @param signature : class signature

+     * @param superName : super class

+     * @param interfaces : implemented interfaces.

+     */

+    private void addPOJOInterface(int version, int access, String name, String signature, String superName, String[] interfaces) {

+

+        // Add the POJO interface to the interface list

+        // Check that the POJO interface is not already in the list

+        boolean found = false;

+        for (int i = 0; i < interfaces.length; i++) {

+            if (interfaces[i].equals(POJO)) {

+                found = true;

+            }

+        }

+        String[] itfs;

+        if (!found) {

+            itfs = new String[interfaces.length + 1];

+            for (int i = 0; i < interfaces.length; i++) {

+                itfs[i] = interfaces[i];

+            }

+            itfs[interfaces.length] = POJO;

+        } else {

+            itfs = interfaces;

+        }

+

+        cv.visit(version, access, name, signature, superName, itfs);

+    }

+

+    /**

+     * Visit end.

+     * Create helper methods.

+     * @see org.objectweb.asm.ClassAdapter#visitEnd()

+     */

+    public void visitEnd() {

+        // Create the component manager setter method

+        createSetInstanceManagerMethod();

+

+        // Add the getComponentInstance

+        createGetComponentInstanceMethod();

+

+        // Need to inject a constructor?

+        if (! m_foundSuitableConstructor) { // No adequate constructor, create one.

+            createSimpleConstructor();

+        }

+

+        m_methods.clear();

+        m_methodFlags.clear();

+

+        cv.visitEnd();

+    }

+

+    /**

+     * Creates a simple constructor with an instance manager

+     * in argument if no suitable constructor is found during

+     * the visit.

+     */

+    private void createSimpleConstructor() {

+        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>",

+                "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);

+        mv.visitCode();

+

+        // Super call

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitMethodInsn(INVOKESPECIAL, m_superclass, "<init>", "()V");

+

+        // Call set instance manager

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_setInstanceManager",

+                "(Lorg/apache/felix/ipojo/InstanceManager;)V");

+

+        mv.visitInsn(RETURN);

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the setter method for the __cm field.

+     */

+    private void createSetInstanceManagerMethod() {

+        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_setInstanceManager", "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);

+        mv.visitCode();

+

+        // If the given instance manager is null, just returns.

+        mv.visitVarInsn(ALOAD, 1);

+        Label l1 = new Label();

+        mv.visitJumpInsn(IFNONNULL, l1);

+        mv.visitInsn(RETURN);

+        mv.visitLabel(l1);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitFieldInsn(PUTFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredFields", "()Ljava/util/Set;");

+        mv.visitVarInsn(ASTORE, 2);

+

+        mv.visitVarInsn(ALOAD, 2);

+        Label endif = new Label();

+        mv.visitJumpInsn(IFNULL, endif);

+        Iterator<String> it = m_fields.iterator();

+        while (it.hasNext()) {

+            String field = it.next();

+            mv.visitVarInsn(ALOAD, 2);

+            mv.visitLdcInsn(field);

+            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z");

+            Label l3 = new Label();

+            mv.visitJumpInsn(IFEQ, l3);

+            mv.visitVarInsn(ALOAD, 0);

+            mv.visitInsn(ICONST_1);

+            mv.visitFieldInsn(PUTFIELD, m_owner, FIELD_FLAG_PREFIX + field, "Z");

+            mv.visitLabel(l3);

+        }

+        mv.visitLabel(endif);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredMethods", "()Ljava/util/Set;");

+        mv.visitVarInsn(ASTORE, 2);

+

+        mv.visitVarInsn(ALOAD, 2);

+        Label endif2 = new Label();

+        mv.visitJumpInsn(IFNULL, endif2);

+

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

+            String methodId = m_methods.get(i);

+            if (!methodId.equals("<init>")) {

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitLdcInsn(methodId);

+                mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z");

+                Label l3 = new Label();

+                mv.visitJumpInsn(IFEQ, l3);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitInsn(ICONST_1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, METHOD_FLAG_PREFIX + methodId, "Z");

+                mv.visitLabel(l3);

+            }

+        }

+

+        mv.visitLabel(endif2);

+        mv.visitInsn(RETURN);

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the getComponentInstance method.

+     */

+    private void createGetComponentInstanceMethod() {

+        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getComponentInstance", "()Lorg/apache/felix/ipojo/ComponentInstance;", null, null);

+        mv.visitCode();

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitInsn(ARETURN);

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create a getter method for an array.

+     * @param name : field name

+     * @param desc : method description

+     * @param type : contained type (inside the array)

+     */

+    private void createArraySetter(String name, String desc, Type type) {

+        MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);

+        mv.visitCode();

+

+        String internalType = desc.substring(1);

+        internalType = internalType.substring(0, internalType.length() - 2);

+

+        Label l1 = new Label();

+        mv.visitLabel(l1);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+        Label l2 = new Label();

+        mv.visitJumpInsn(IFNE, l2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitFieldInsn(PUTFIELD, m_owner, name, internalType);

+        mv.visitInsn(RETURN);

+        mv.visitLabel(l2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitLdcInsn(name);

+        mv.visitVarInsn(ALOAD, 1);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");

+

+        mv.visitInsn(RETURN);

+

+        // End

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create a setter method for an array.

+     * @param name : field name

+     * @param desc : method description

+     * @param type : contained type (inside the array)

+     */

+    private void createArrayGetter(String name, String desc, Type type) {

+        String methodName = "__get" + name;

+        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);

+        mv.visitCode();

+

+        String internalType = desc.substring(2);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+        Label l1 = new Label();

+        mv.visitJumpInsn(IFNE, l1);

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);

+        mv.visitInsn(ARETURN);

+        mv.visitLabel(l1);

+

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+        mv.visitVarInsn(ALOAD, 0);

+        mv.visitLdcInsn(name);

+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+        mv.visitTypeInsn(CHECKCAST, internalType);

+        mv.visitInsn(ARETURN);

+

+        // End

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the getter for a field.

+     * @param name : field of the dependency

+     * @param desc : description of the getter method

+     * @param type : type to return

+     */

+    private void createSimpleGetter(String name, String desc, Type type) {

+        String methodName = "__get" + name;

+        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);

+        mv.visitCode();

+

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+            case Type.CHAR:

+            case Type.BYTE:

+            case Type.SHORT:

+            case Type.INT:

+

+                String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                String unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                Label l0 = new Label();

+                mv.visitLabel(l0);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                Label l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(IRETURN);

+

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 1);

+

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitInsn(type.getOpcode(IRETURN));

+                break;

+

+            case Type.LONG:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                l0 = new Label();

+                mv.visitLabel(l0);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(LRETURN);

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 1);

+

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitInsn(LRETURN);

+

+                break;

+

+            case Type.DOUBLE:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                l0 = new Label();

+                mv.visitLabel(l0);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(DRETURN);

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 1);

+

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitInsn(DRETURN);

+

+                break;

+

+            case Type.FLOAT:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+                unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

+

+                l0 = new Label();

+                mv.visitLabel(l0);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);

+                mv.visitInsn(FRETURN);

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+                mv.visitVarInsn(ASTORE, 1);

+

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitTypeInsn(CHECKCAST, boxingType);

+                mv.visitVarInsn(ASTORE, 2);

+

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName);

+                mv.visitInsn(FRETURN);

+

+                break;

+

+            case Type.OBJECT:

+                l0 = new Label();

+                mv.visitLabel(l0);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                l1 = new Label();

+                mv.visitJumpInsn(IFNE, l1);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");

+                mv.visitInsn(ARETURN);

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET, "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;");

+                mv.visitTypeInsn(CHECKCAST, type.getInternalName());

+                mv.visitInsn(ARETURN);

+

+                break;

+

+            default:

+                ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE, "Manipulation problem in " + m_owner + " : a type is not implemented : " + type);

+                break;

+        }

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+    /**

+     * Create the setter method for one property. The name of the method is _set+name of the field

+     * @param name : name of the field representing a property

+     * @param desc : description of the setter method

+     * @param type : type of the property

+     */

+    private void createSimpleSetter(String name, String desc, Type type) {

+        MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);

+        mv.visitCode();

+

+        switch (type.getSort()) {

+            case Type.BOOLEAN:

+            case Type.CHAR:

+            case Type.BYTE:

+            case Type.SHORT:

+            case Type.INT:

+            case Type.FLOAT:

+                String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+

+                Label l1 = new Label();

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                Label l22 = new Label();

+                mv.visitJumpInsn(IFNE, l22);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l22);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 2);

+

+                Label l2 = new Label();

+                mv.visitLabel(l2);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 2);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");

+

+                Label l3 = new Label();

+                mv.visitLabel(l3);

+                mv.visitInsn(RETURN);

+                break;

+

+            case Type.LONG:

+            case Type.DOUBLE:

+                internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];

+                boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

+

+                l1 = new Label();

+                mv.visitLabel(l1);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                Label l23 = new Label();

+                mv.visitJumpInsn(IFNE, l23);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l23);

+

+                mv.visitTypeInsn(NEW, boxingType);

+                mv.visitInsn(DUP);

+                mv.visitVarInsn(type.getOpcode(ILOAD), 1);

+                mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V");

+                mv.visitVarInsn(ASTORE, 3); // Double space

+

+                l2 = new Label();

+                mv.visitLabel(l2);

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 3);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");

+

+                l3 = new Label();

+                mv.visitLabel(l3);

+                mv.visitInsn(RETURN);

+                break;

+

+            case Type.OBJECT:

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");

+                Label l24 = new Label();

+                mv.visitJumpInsn(IFNE, l24);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitFieldInsn(PUTFIELD, m_owner, name, "L" + type.getInternalName() + ";");

+                mv.visitInsn(RETURN);

+                mv.visitLabel(l24);

+

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

+                mv.visitVarInsn(ALOAD, 0);

+                mv.visitLdcInsn(name);

+                mv.visitVarInsn(ALOAD, 1);

+                mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET, "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V");

+

+                mv.visitInsn(RETURN);

+                break;

+            default:

+                ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE, "Manipulation Error : Cannot create the setter method for the field : " + name + " (" + type + ")");

+                break;

+        }

+

+        mv.visitMaxs(0, 0);

+        mv.visitEnd();

+    }

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
new file mode 100644
index 0000000..c715010
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/MethodDescriptor.java
@@ -0,0 +1,189 @@
+/*

+ * 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.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;

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

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

+import org.objectweb.asm.Type;

+

+/**

+ * Method Descriptor describe a method.

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

+ */

+public class MethodDescriptor {

+

+    /**

+     * Method name.

+     */

+    private String m_name;

+

+    /**

+     * Returned type.

+     */

+    private String m_returnType;

+

+    /**

+     * Argument types.

+     */

+    private String[] m_arguments;

+

+    /**

+     * The descriptor of the method.

+     */

+    private String m_desc;

+

+

+    /**

+     * The list of {@link AnnotationDescriptor} attached to this

+     * method.

+     */

+    private List<AnnotationDescriptor> m_annotations;

+

+    /**

+     * The association argument (number) - {@link AnnotationDescriptor}.

+     */

+    private Map<Integer, List<AnnotationDescriptor>> m_parameterAnnotations = new HashMap<Integer, List<AnnotationDescriptor>>();

+

+    /**

+     * Constructor.

+     * @param name : name of the method.

+     * @param desc : descriptor of the method.

+     */

+    public MethodDescriptor(String name, String desc) {

+        m_name = name;

+        m_desc = desc;

+        Type ret = Type.getReturnType(desc);

+        Type[] args = Type.getArgumentTypes(desc);

+

+        m_returnType = getType(ret);

+        m_arguments = new String[args.length];

+        for (int i = 0; i < args.length; i++) {

+            m_arguments[i] = getType(args[i]);

+        }

+    }

+

+    /**

+     * Add an annotation to the current method.

+     * @param ann annotation to add

+     */

+    public void addAnnotation(AnnotationDescriptor ann) {

+        if (m_annotations == null) {

+            m_annotations = new ArrayList<AnnotationDescriptor>();

+        }

+        m_annotations.add(ann);

+    }

+

+    /**

+     * Add an annotation to the current method.

+     * @param ann annotation to add

+     */

+    public void addParameterAnnotation(int id, AnnotationDescriptor ann) {

+        List<AnnotationDescriptor> list = m_parameterAnnotations.get(new Integer(id));

+        if (list == null) {

+            list = new ArrayList<AnnotationDescriptor>();

+            m_parameterAnnotations.put(new Integer(id), list);

+        }

+        list.add(ann);

+    }

+

+    public List<AnnotationDescriptor> getAnnotations() {

+        return m_annotations;

+    }

+

+    public Map<Integer, List<AnnotationDescriptor>> getParameterAnnotations() {

+        return m_parameterAnnotations;

+    }

+

+    public String getDescriptor() {

+        return m_desc;

+    }

+

+    /**

+     * Compute method manipulation metadata.

+     * @return the element containing metadata about this method.

+     */

+    public Element getElement() {

+        Element method = new Element("method", "");

+        method.addAttribute(new Attribute("name", m_name));

+

+        // Add return

+        if (!m_returnType.equals("void")) {

+            method.addAttribute(new Attribute("return", m_returnType));

+        }

+

+        // Add arguments

+        if (m_arguments.length > 0) {

+            StringBuffer args = new StringBuffer("{");

+            args.append(m_arguments[0]);

+            for (int i = 1; i < m_arguments.length; i++) {

+                args.append("," + m_arguments[i]);

+            }

+            args.append("}");

+            method.addAttribute(new Attribute("arguments", args.toString()));

+        }

+

+        return method;

+    }

+

+    /**

+     * Get the iPOJO internal type for the given type.

+     * @param type : type.

+     * @return the iPOJO internal type.

+     */

+    private String getType(Type type) {

+        switch (type.getSort()) {

+            case Type.ARRAY:

+                Type elemType = type.getElementType();

+                return getType(elemType) + "[]";

+            case Type.BOOLEAN:

+                return "boolean";

+            case Type.BYTE:

+                return "byte";

+            case Type.CHAR:

+                return "char";

+            case Type.DOUBLE:

+                return "double";

+            case Type.FLOAT:

+                return "float";

+            case Type.INT:

+                return "int";

+            case Type.LONG:

+                return "long";

+            case Type.OBJECT:

+                return type.getClassName();

+            case Type.SHORT:

+                return "short";

+            case Type.VOID:

+                return "void";

+            default:

+                return "unknown";

+        }

+    }

+

+    public String getName() {

+        return m_name;

+    }

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
new file mode 100644
index 0000000..e3e14f0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
@@ -0,0 +1,330 @@
+/*

+ * 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.annotations;

+

+import java.lang.reflect.Array;

+

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

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

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.Type;

+import org.objectweb.asm.commons.EmptyVisitor;

+

+/**

+ * Collect metadata from custom annotation.

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

+ */

+public class CustomAnnotationVisitor extends EmptyVisitor implements AnnotationVisitor {

+

+    /**

+     * Parent element.

+     */

+    private Element m_elem;

+

+    /**

+     * Id attribute (if found)

+     * else use the annotation package name.

+     */

+    private String m_id;

+

+    /**

+     * Parent attribute (if found)

+     * else use the annotation package name.

+     */

+    private String m_parent;

+

+    /**

+     * Is the custom annotation a first-order annotation.

+     */

+    private boolean m_root;

+

+    /**

+     * Is the visit annotation a class annotation?

+     */

+    private boolean m_classAnnotation;

+

+    /**

+     * Metadata collector.

+     */

+    private MetadataCollector m_collector;

+

+    /**

+     * Flag sets to true for parameter annotation.

+     */

+    private boolean m_isParameterAnnotation = false;

+

+    /**

+     * For parameter annotations, the index of the parameter.

+     */

+    private int m_index = -1;

+

+    /**

+     * For parameter annotation, the descriptor of the method.

+     */

+    private String m_desc;

+

+    /**

+     * Constructor.

+     * @param elem the parent element

+     * @param collector the metadata collector

+     * @param root is the annotation a root

+     * @param clazz the annotation is a class annotation.

+     */

+    public CustomAnnotationVisitor(Element elem, MetadataCollector collector, boolean root, boolean clazz) {

+        m_elem = elem;

+        m_root = root;

+        m_collector = collector;

+        m_classAnnotation = clazz;

+    }

+

+    /**

+     * Constructor used for parameter annotations

+     * @param elem the parent element

+     * @param collector the metadata collector

+     * @param root is the annotation a root

+     * @param clazz the annotation is a class annotation.

+     * @param index the index of the argument

+     * @param the descriptor of the method

+     */

+    public CustomAnnotationVisitor(Element elem, MetadataCollector collector, boolean root, boolean clazz, int index, String descriptor) {

+        m_elem = elem;

+        m_root = root;

+        m_collector = collector;

+        m_classAnnotation = clazz;

+        m_isParameterAnnotation = true;

+        m_index = index;

+        m_desc = descriptor;

+    }

+

+    /**

+     * Check if the given annotation descriptor is an iPOJO custom annotation.

+     * A valid iPOJO custom annotation must contains 'ipojo' or 'handler' in its qualified name.

+     * @param desc : annotation descriptor

+     * @return : true if the given descriptor is an iPOJO custom annotation

+     */

+    public static boolean isCustomAnnotation(String desc) {

+        desc = desc.toLowerCase();

+        if (desc.indexOf("ipojo") != -1 || desc.indexOf("handler") != -1) {

+            return true;

+        }

+        return false;

+    }

+

+    /**

+     * Build the element object from the given descriptor.

+     * @param desc : annotation descriptor

+     * @return : the element

+     */

+    public static Element buildElement(String desc) {

+        String s = (desc.replace('/', '.')).substring(1, desc.length() - 1);

+        int index = s.lastIndexOf('.');

+        String name = s.substring(index + 1);

+        String namespace = s.substring(0, index);

+        return new Element(name, namespace);

+    }

+

+

+    /**

+     * Visit a 'simple' annotation attribute.

+     * This method is used for primitive arrays too.

+     * @param arg0 : attribute name

+     * @param arg1 : attribute value

+     * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)

+     */

+    public void visit(String arg0, Object arg1) {

+        if (arg1.getClass().isArray()) {

+            // Primitive arrays case

+            String v = null;

+            int index = Array.getLength(arg1);

+            for (int i = 0; i < index; i++) {

+                if (v == null) {

+                    v = "{" + Array.get(arg1, i);

+                } else {

+                    v += "," + Array.get(arg1, i);

+                }

+            }

+            v += "}";

+            m_elem.addAttribute(new Attribute(arg0, v));

+            return;

+        }

+        

+        // Attributes are added as normal attributes

+        if (!(arg1 instanceof Type)) {

+            m_elem.addAttribute(new Attribute(arg0, arg1.toString()));            

+        } else {

+            // Attributes of type class need a special handling

+            m_elem.addAttribute(new Attribute(arg0, ((Type) arg1).getClassName()));        

+        }

+        

+        if (m_root) {

+            if (arg0.equals("id")) {

+                m_id = arg1.toString();

+            } else if (arg0.equals("parent")) {

+                m_parent = arg1.toString();

+            }

+        }

+    }

+

+    /**

+     * Visit a sub-annotation.

+     * @param arg0 : attribute name.

+     * @param arg1 : annotation description

+     * @return an annotation visitor which will visit the given annotation

+     * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, java.lang.String)

+     */

+    public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+        // Sub annotations are mapped to sub-elements

+        Element elem = buildElement(arg1);

+        m_elem.addElement(elem);

+        return new CustomAnnotationVisitor(elem, m_collector, false, false);

+    }

+

+    /**

+     * Visit an array attribute.

+     * @param arg0 : attribute name

+     * @return a visitor which will visit each element of the array

+     * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(java.lang.String)

+     */

+    public AnnotationVisitor visitArray(String arg0) {

+        return new SubArrayVisitor(m_elem, arg0);

+    }

+

+    /**

+     * Visits an enumeration attribute.

+     * @param arg0 the attribute name

+     * @param arg1 the enumeration descriptor

+     * @param arg2 the attribute value

+     * @see org.objectweb.asm.AnnotationVisitor#visitEnum(java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void visitEnum(String arg0, String arg1, String arg2) {

+        m_elem.addAttribute(new Attribute(arg0, arg2));

+    }

+

+    /**

+     * End of the visit.

+     * All attribute was visited, we can update collectors data.

+     * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()

+     */

+    public void visitEnd() {

+        if (m_root) {

+            if (m_id != null) {

+                m_collector.getIds().put(m_id, m_elem);

+            } else {

+            	m_id = m_elem.getNameSpace();

+                if (! m_collector.getIds().containsKey(m_elem.getNameSpace()) && m_classAnnotation) {

+                    // If the namespace is not already used, add the annotation as the

+                    // root element of this namespace.

+                    m_collector.getIds().put(m_elem.getNameSpace(), m_elem);

+                } else {

+                    // Already used, the element is the parent.

+                    if (m_parent == null) {

+                        m_parent = m_elem.getNameSpace();

+                    }

+                }

+            }

+

+            m_collector.getElements().put(m_elem, m_parent);

+

+            if (m_isParameterAnnotation) {

+            	String t = Type.getArgumentTypes(m_desc)[m_index].getClassName();

+            	m_elem.addAttribute(new Attribute("type", t));

+            	m_elem.addAttribute(

+            			new Attribute("constructor-parameter", Integer.toString(m_index)));

+            }

+        }

+    }

+

+    private class SubArrayVisitor extends EmptyVisitor implements AnnotationVisitor {

+        /**

+         * Parent element.

+         */

+        private Element m_elem;

+

+        /**

+         * Attribute name.

+         */

+        private String m_name;

+

+        /**

+         * Attribute value.

+         * (accumulator)

+         */

+        private String m_acc;

+

+        /**

+         * Constructor.

+         * @param elem : parent element.

+         * @param name : attribute name.

+         */

+        public SubArrayVisitor(Element elem, String name) {

+            m_elem = elem;

+            m_name = name;

+        }

+

+        /**

+         * Visit a 'simple' element of the visited array.

+         * @param arg0 : null

+         * @param arg1 : element value.

+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            if (m_acc == null) {

+                if (!(arg1 instanceof Type)) {

+                    m_acc = "{" + arg1.toString();            

+                } else {

+                    // Attributes of type class need a special handling

+                    m_acc = "{" + ((Type) arg1).getClassName();

+                }

+            } else {

+                if (!(arg1 instanceof Type)) {

+                    m_acc = m_acc + "," + arg1.toString();

+                } else {

+                    // Attributes of type class need a special handling

+                    m_acc = m_acc + "," + ((Type) arg1).getClassName();

+                }

+            }

+        }

+

+        /**

+         * Visit an annotation element of the visited array.

+         * @param arg0 : null

+         * @param arg1 : annotation to visit

+         * @return the visitor which will visit the annotation

+         * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, java.lang.String)

+         */

+        public AnnotationVisitor visitAnnotation(String arg0, String arg1) {

+            // Sub annotations are map to sub-elements

+            Element elem = buildElement(arg1);

+            m_elem.addElement(elem);

+            return new CustomAnnotationVisitor(elem, m_collector, false, false);

+        }

+

+        /**

+         * End of the visit.

+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()

+         */

+        public void visitEnd() {

+            if (m_acc != null) {

+                // We have analyzed an attribute

+                m_elem.addAttribute(new Attribute(m_name, m_acc + "}"));

+            }

+        }

+

+    }

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java
new file mode 100644
index 0000000..31905d6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java
@@ -0,0 +1,363 @@
+/* 

+ * 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.annotations;

+

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

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

+import org.objectweb.asm.AnnotationVisitor;

+import org.objectweb.asm.FieldVisitor;

+import org.objectweb.asm.Type;

+import org.objectweb.asm.commons.EmptyVisitor;

+

+/**

+ * Collect field annotations. 

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

+ */

+public class FieldCollector extends EmptyVisitor implements FieldVisitor {

+    

+    /**

+     * Collected element.

+     */

+    private MetadataCollector m_collector;

+    

+    /**

+     * Field name. 

+     */

+    private String m_field;

+    

+    /**

+     * Constructor.

+     * @param fieldName : field name

+     * @param collector : metadata collector.

+     */

+    public FieldCollector(String fieldName, MetadataCollector collector) {

+        m_collector = collector;

+        m_field = fieldName;

+    }

+

+    /**

+     * Visit annotations on the current field.

+     * @param arg0 : annotation name

+     * @param arg1 : is the annotation a runtime annotation.

+     * @return the annotation visitor visiting the annotation

+     * @see org.objectweb.asm.FieldVisitor#visitAnnotation(java.lang.String, boolean)

+     */

+    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {

+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Requires;")) {

+            return new RequiresAnnotationParser(m_field);

+        }

+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Controller;")) {

+            Element elem = new Element("controller", "");

+            elem.addAttribute(new Attribute("field", m_field));

+            m_collector.getElements().put(elem, null);

+            return null;

+        }

+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/ServiceProperty;")) {

+            if (! m_collector.getIds().containsKey("provides")) { // The provides annotation is already computed.

+                System.err.println("The component does not provide services, skip ServiceProperty for " + m_field);

+                return null;

+            } else {

+                // Get the provides element

+                Element parent = (Element) m_collector.getIds().get("provides");

+                return new PropertyAnnotationParser(m_field, parent);

+            } 

+        }

+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/ServiceController;")) {

+            if (! m_collector.getIds().containsKey("provides")) { // The provides annotation is already computed.

+                System.err.println("The component does not provide services, skip ServiceController for " + m_field);

+                return null;

+            } else {

+                // Get the provides element

+                Element parent = (Element) m_collector.getIds().get("provides");

+                return new ServiceControllerAnnotationParser(m_field, parent);

+            } 

+        }

+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {

+            Element parent = null;

+            if (! m_collector.getIds().containsKey("properties")) {

+                parent = new Element("Properties", "");

+                m_collector.getIds().put("properties", parent);

+                m_collector.getElements().put(parent, null);

+            } else {

+                parent = (Element) m_collector.getIds().get("properties");

+            }

+            return new PropertyAnnotationParser(m_field, parent);

+        }

+        

+        if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {

+            Element elem = CustomAnnotationVisitor.buildElement(arg0);

+            elem.addAttribute(new Attribute("field", m_field)); // Add a field attribute

+            return new CustomAnnotationVisitor(elem, m_collector, true, false);

+        }

+        

+        return null;

+       

+    }

+    

+    /**

+     * AnnotationVisitor parsing the @requires annotation.

+     */

+    private final class RequiresAnnotationParser extends EmptyVisitor implements AnnotationVisitor {

+        

+        /**

+         * Dependency field.

+         */

+        private String m_field;

+        

+        /**

+         * Dependency filter.

+         */

+        private String m_filter;

+        

+        /**

+         * Is the dependency optional ?

+         */

+        private String m_optional;

+        

+        /**

+         * Dependency specification.

+         */

+        private String m_specification;

+        

+        /**

+         * Dependency id.

+         */

+        private String m_id;

+        

+        /**

+         * Binding policy.

+         */

+        private String m_policy;

+        

+        /**

+         * Default-Implementation attribute.

+         */

+        private String m_defaultImplementation;

+        

+        /**

+         * Enable or Disable Nullable pattern. 

+         */

+        private String m_nullable;

+        

+        /**

+         * Comparator.

+         */

+        private String m_comparator;

+        

+        /**

+         * From attribute.

+         */

+        private String m_from;

+        

+        /**

+         * Proxy attribute.

+         */

+        private String m_proxy;

+        

+        /**

+         * Constructor.

+         * @param name : field name.

+         */

+        private RequiresAnnotationParser(String name) {

+            m_field = name;

+        }

+

+        /**

+         * Visit one "simple" annotation.

+         * @param arg0 : annotation name

+         * @param arg1 : annotation value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            if (arg0.equals("filter")) {

+                m_filter = arg1.toString();

+                return;

+            }

+            if (arg0.equals("optional")) {

+                m_optional = arg1.toString();

+                return;

+            }

+            if (arg0.equals("nullable")) {

+                m_nullable = arg1.toString();

+                return;

+            }

+            if (arg0.equals("policy")) {

+                m_policy = arg1.toString();

+                return;

+            }

+            if (arg0.equals("defaultimplementation")) {

+                Type type = Type.getType(arg1.toString());

+                m_defaultImplementation = type.getClassName();

+                return;

+            }

+            if (arg0.equals("specification")) {

+                m_specification = arg1.toString();

+                return;

+            }

+            if (arg0.equals("id")) {

+                m_id = arg1.toString();

+                return;

+            }

+            if (arg0.equals("comparator")) {

+                Type type = Type.getType(arg1.toString());

+                m_comparator = type.getClassName();

+                return;

+            }

+            if (arg0.equals("from")) {

+                m_from = arg1.toString();

+                return;

+            }

+            if (arg0.equals("proxy")) {

+                m_proxy = arg1.toString();

+                return;

+            }

+        }

+

+        /**

+         * End of the annotation.

+         * Create a "requires" element

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() {

+            Element req = null;

+            if (m_id == null) {

+                req = (Element) m_collector.getIds().get(m_field);

+            } else {

+                req = (Element) m_collector.getIds().get(m_id);

+            }

+

+            if (req == null) {

+                req = new Element("requires", "");

+            }

+

+            req.addAttribute(new Attribute("field", m_field));

+            if (m_specification != null) {

+                req.addAttribute(new Attribute("specification", m_specification));

+            }

+            if (m_filter != null) {

+                req.addAttribute(new Attribute("filter", m_filter));

+            }

+            if (m_optional != null) {

+                req.addAttribute(new Attribute("optional", m_optional));

+            }

+            if (m_nullable != null) {

+                req.addAttribute(new Attribute("nullable", m_nullable));

+            }

+            if (m_defaultImplementation != null) {

+                req.addAttribute(new Attribute("default-implementation", m_defaultImplementation));

+            }

+            if (m_policy != null) {

+                req.addAttribute(new Attribute("policy", m_policy));

+            }

+            if (m_id != null) {

+                req.addAttribute(new Attribute("id", m_id));

+            }

+            if (m_comparator != null) {

+                req.addAttribute(new Attribute("comparator", m_comparator));

+            }

+            if (m_from != null) {

+                req.addAttribute(new Attribute("from", m_from));

+            }

+            if (m_proxy != null) {

+                req.addAttribute(new Attribute("proxy", m_proxy));

+            }

+            

+            if (m_id != null) { 

+                m_collector.getIds().put(m_id, req);

+            } else {

+                m_collector.getIds().put(m_field, req);

+            }

+            

+            m_collector.getElements().put(req, null);

+                

+            return;

+        }

+    }

+    

+    /**

+     * Parses a ServiceController annotation.

+     */

+    private static final class ServiceControllerAnnotationParser extends EmptyVisitor implements AnnotationVisitor {

+        

+        /**

+         * Parent element element.

+         */

+        private Element m_parent;

+        

+        /**

+         * Field name. 

+         */

+        private String m_field;

+        

+        /**

+         * Property value.  

+         */

+        private String m_value;

+        

+        /**

+         * Specification value.  

+         */

+        private String m_spec;   

+        

+        /**

+         * Constructor.

+         * @param parent : parent element.

+         * @param field : field name.

+         */

+        private ServiceControllerAnnotationParser(String field, Element parent) {

+            m_parent = parent;

+            m_field = field;

+        }

+

+        /**

+         * Visit one "simple" annotation.

+         * @param arg0 : annotation name

+         * @param arg1 : annotation value

+         * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)

+         */

+        public void visit(String arg0, Object arg1) {

+            if (arg0.equals("value")) {

+                m_value = arg1.toString();

+                return;

+            }

+            if (arg0.equals("specification")) {

+                m_spec = ((Type) arg1).getClassName();

+                return;

+            } 

+        }

+

+        /**

+         * End of the annotation.

+         * Create a "controller" element

+         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()

+         */

+        public void visitEnd() {

+            Element controller = new Element("controller", "");

+            m_parent.addElement(controller);

+            

+            controller.addAttribute(new Attribute("field", m_field));

+            if (m_value != null) {

+                controller.addAttribute(new Attribute("value", m_value));

+            }

+            if (m_spec != null) {

+                controller.addAttribute(new Attribute("specification", m_spec));

+            }

+        }

+    }

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
new file mode 100644
index 0000000..62fe47d
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
@@ -0,0 +1,669 @@
+/*
+ * 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.annotations;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+/**
+ * Collect metadata from classes by parsing annotation.
+ * This class collects type (i.e.) annotations and create method & field collectors.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MetadataCollector extends EmptyVisitor implements Opcodes {
+
+    /**
+     * Class name.
+     */
+    private String m_className;
+
+    /**
+     * Root element of computed metadata.
+     */
+    private Element m_elem = null;
+
+    /**
+     * True if the visited class is a component type declaration (i.e. contains the @component annotation).
+     */
+    private boolean m_containsComponentAnnotation = false;
+
+    /**
+     * True if the visited class does not have the @Component annotation.
+     */
+    private boolean m_ignoredBecauseOfMissingComponent = false;
+
+    /**
+     * Map of [element ids, element].
+     * This map is used to easily get an already created element.
+     */
+    private Map<String, Element> m_ids = new TreeMap<String, Element>();
+
+    /**
+     * Map of [element, referto].
+     * This map is used to recreate the element hierarchy.
+     * Stored element are added under referred element.
+     */
+    private Map<Element, String> m_elements = new LinkedHashMap<Element, String>();
+
+    /**
+     * Instance declaration.
+     */
+    private Element m_instance;
+
+    /**
+     * XML document parser.
+     */
+    private DocumentBuilder m_builder;
+
+
+    public Element getComponentTypeDeclaration() {
+        return m_elem;
+    }
+
+    public Element getInstanceDeclaration() {
+        return m_instance;
+    }
+
+    public boolean isComponentType() {
+        return m_containsComponentAnnotation;
+    }
+
+    public boolean isIgnoredBecauseOfMissingComponent() {
+        return m_ignoredBecauseOfMissingComponent;
+    }
+
+    public String getClassName() {
+        return m_className;
+    }
+
+    /**
+     * Start visiting a class.
+     * Initialize the getter/setter generator, add the _cm field, add the pojo interface.
+     * @param version : class version
+     * @param access : class access
+     * @param name : class name
+     * @param signature : class signature
+     * @param superName : class super class
+     * @param interfaces : implemented interfaces
+     * @see org.objectweb.asm.ClassAdapter#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+     */
+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+        m_ids = new TreeMap<String, Element>();
+        m_elements = new LinkedHashMap<Element, String>();
+        m_className = name;
+    }
+
+
+    /**
+     * Visit class annotations.
+     * This method detects @component and @provides annotations.
+     * @param desc : annotation descriptor.
+     * @param visible : is the annotation visible at runtime.
+     * @return the annotation visitor.
+     * @see org.objectweb.asm.ClassAdapter#visitAnnotation(java.lang.String, boolean)
+     */
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        // @Component
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Component;")) {
+            // It is a component
+            m_elem =  new Element("component", "");
+            m_containsComponentAnnotation = true;
+            m_elem.addAttribute(new Attribute("className", m_className.replace('/', '.')));
+            return new ComponentVisitor();
+        }
+
+        // @Handler
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Handler;")) {
+            // It is a handler, change the root element
+            m_elem = new Element("handler", "");
+            m_containsComponentAnnotation = true;
+            m_elem.addAttribute(new Attribute("classname", m_className.replace('/', '.')));
+            return new HandlerVisitor();
+        }
+
+        // @Provides
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Provides;")) {
+            return new ProvidesVisitor();
+        }
+
+        // @HandlerDeclaration
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/HandlerDeclaration;")) {
+            return new HandlerDeclarationVisitor();
+        }
+
+        // @Instantiate
+        if (desc.equals("Lorg/apache/felix/ipojo/annotations/Instantiate;")) {
+            return new InstantiateVisitor();
+        }
+
+        if (CustomAnnotationVisitor.isCustomAnnotation(desc)) {
+            Element elem = CustomAnnotationVisitor.buildElement(desc);
+            return new CustomAnnotationVisitor(elem, this, true, true);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Visit a field.
+     * Call the field collector visitor.
+     * @param access : field access.
+     * @param name : field name
+     * @param desc : field descriptor
+     * @param signature : field signature
+     * @param value : field value (static field only)
+     * @return the field visitor.
+     * @see org.objectweb.asm.ClassAdapter#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
+     */
+    public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+        return new FieldCollector(name, this);
+    }
+
+    /**
+     * Visit a method.
+     * Call the method collector visitor.
+     * @param access : method access
+     * @param name : method name
+     * @param desc : method descriptor
+     * @param signature : method signature
+     * @param exceptions : method exceptions
+     * @return the Method Visitor.
+     * @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
+     */
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        return new MethodCollector(name, desc, this);
+    }
+
+    /**
+     * End of the visit : compute final elements.
+     * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+     */
+    public void visitEnd() {
+        // If m_elem (Component) is null, print a warning and ignore.
+        if (m_elem == null  &&  ! m_elements.isEmpty()) {
+            m_ignoredBecauseOfMissingComponent = true;
+            return;
+        }
+
+        if (! m_containsComponentAnnotation) {
+            m_ignoredBecauseOfMissingComponent = true;
+            return;
+        }
+
+        // Recompute the tree
+        Set<Element> elems = getElements().keySet();
+        Iterator<Element> it = elems.iterator();
+        while (it.hasNext()) {
+            Element current = it.next();
+            String reference = getElements().get(current);
+            if (reference == null) {
+                m_elem.addElement(current);
+            } else {
+                Element ref = (Element) getIds().get(reference);
+                if (ref == null) {
+                    // Add to the root
+                    m_elem.addElement(current);
+                } else {
+                    ref.addElement(current);
+                }
+            }
+        }
+    }
+
+    protected Map<String, Element> getIds() {
+        return m_ids;
+    }
+
+    protected Map<Element, String> getElements() {
+        return m_elements;
+    }
+
+    /**
+     * Creates a 'fresh' document builder.
+     * @return a new document builder is not already created, else reset
+     * the created one, and return it.
+     */
+    protected DocumentBuilder getFreshDocumentBuilder() {
+        if (m_builder == null) {
+
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            try {
+                m_builder = factory.newDocumentBuilder();
+            } catch (ParserConfigurationException e) {
+                // TODO GSA is this acceptable to throw a RuntimeException here ?
+                e.printStackTrace();
+            }
+
+            return m_builder;
+        }
+
+        // The builder has to be reseted
+        m_builder.reset();
+
+        return m_builder;
+    }
+
+    /**
+     * Parse the @provides annotation.
+     */
+    private class ProvidesVisitor extends EmptyVisitor implements AnnotationVisitor {
+        /**
+         * Provides element.
+         */
+        Element m_prov = new Element("provides", "");
+
+        /**
+         * Visit @provides annotation attributes.
+         * @param arg0 : annotation attribute name
+         * @param arg1 : annotation attribute value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("factory")) { // Should be deprecated
+                m_prov.addAttribute(new Attribute("factory", arg1.toString()));
+            }
+            if (arg0.equals("strategy")) {
+                m_prov.addAttribute(new Attribute("strategy", arg1.toString()));
+            }
+        }
+
+        /**
+         * Visit specifications array.
+         * @param arg0 : attribute name
+         * @return a visitor visiting each element of the array.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(java.lang.String)
+         */
+        public AnnotationVisitor visitArray(String arg0) {
+            if (arg0.equals("specifications")) {
+                return new InterfaceArrayVisitor();
+            } else if (arg0.equals("properties")) {
+                // Create a new simple visitor to visit the nested ServiceProperty annotations
+                // Collected properties are collected in m_prov
+                return new EmptyVisitor() {
+                    public AnnotationVisitor visitAnnotation(String ignored, String desc) {
+                        return new PropertyAnnotationParser(m_prov);
+                    }
+                };
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * End of the visit.
+         * Append to the parent element the computed "provides" element.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            getIds().put("provides", m_prov);
+            getElements().put(m_prov, null);
+        }
+
+        private class InterfaceArrayVisitor extends EmptyVisitor {
+            /**
+             * List of parsed interface.
+             */
+            private String m_itfs;
+
+            /**
+             * Visit one element of the array.
+             * @param arg0 : null
+             * @param arg1 : element value.
+             * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+             */
+            public void visit(String arg0, Object arg1) {
+                if (m_itfs == null) {
+                    m_itfs = "{" + ((Type) arg1).getClassName();
+                } else {
+                    m_itfs += "," + ((Type) arg1).getClassName();
+                }
+            }
+
+            /**
+             * End of the array visit.
+             * Add the attribute to 'provides' element.
+             * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+             */
+            public void visitEnd() {
+                m_prov.addAttribute(new Attribute("specifications", m_itfs + "}"));
+            }
+
+        }
+
+
+    }
+
+    /**
+     * Parse the @Instantitate annotation.
+     */
+    private class InstantiateVisitor extends EmptyVisitor implements AnnotationVisitor {
+        /**
+         * Instance name.
+         */
+        private String m_name;
+
+        /**
+         * Visit an annotation attribute.
+         * @param arg0 the attribute name
+         * @param arg1 the attribute value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("name")) {
+                m_name = arg1.toString();
+                return;
+            }
+        }
+
+        /**
+         * End of the visit. Creates the instance element.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            m_instance = new Element("instance", "");
+            if (m_className != null) { // Should not be null.
+                m_instance.addAttribute(new Attribute("component", m_className.replace('/', '.')));
+            }
+            if (m_name != null) {
+                m_instance.addAttribute(new Attribute("name", m_name));
+            }
+        }
+    }
+
+
+    /**
+     * Parse the @component annotation.
+     */
+    private class ComponentVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+        /**
+         * Factory attribute.
+         */
+        private String m_factory;
+
+        /**
+         * Is the component an immediate component?
+         */
+        private String m_immediate;
+
+        /**
+         * Component name (cannot be null).
+         */
+        private String m_name;
+
+        /**
+         * Does the component exposes its architecture?
+         */
+        private String m_architecture;
+
+        /**
+         * Does the component propagate configuration to provided services?
+         */
+        private String m_propagation;
+
+        /**
+         * Managed Service PID.
+         */
+        private String m_managedservice;
+
+        /**
+         * Factory-Method.
+         */
+        private String m_method;
+
+        /**
+         * Version.
+         */
+        private String m_version;
+
+        /**
+         * Element properties.
+         */
+        private Element m_props;
+
+        /**
+         * Visit @component annotation attribute.
+         * @param arg0 : attribute name
+         * @param arg1 : attribute value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("public_factory")  || arg0.equals("publicFactory")) {
+                // public_factory is deprecated, but must sill be supported
+                m_factory = arg1.toString();
+                return;
+            }
+            if (arg0.equals("name")) {
+                m_name = arg1.toString();
+                return;
+            }
+            if (arg0.equals("immediate")) {
+                m_immediate = arg1.toString();
+                return;
+            }
+            if (arg0.equals("architecture")) {
+                m_architecture = arg1.toString();
+                return;
+            }
+            if (arg0.equals("propagation")) {
+                m_propagation = arg1.toString();
+                return;
+            }
+            if (arg0.equals("managedservice")) {
+                m_managedservice = arg1.toString();
+                return;
+            }
+            if (arg0.equals("factory_method")  || arg0.equals("factoryMethod")) {
+                // factory_method is deprecated, but must still be supported.
+                m_method = arg1.toString();
+                return;
+            }
+            if (arg0.equals("version")) {
+                m_version = arg1.toString();
+                return;
+            }
+        }
+
+        /**
+         * End of the visit.
+         * Append to the "component" element computed attribute.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            if (m_name == null) {
+                m_name = m_className.replace('/', '.');
+            }
+            m_elem.addAttribute(new Attribute("name", m_name));
+            if (m_factory != null && m_factory.equalsIgnoreCase("false")) {
+                m_elem.addAttribute(new Attribute("public", "false"));
+            } else {
+                m_elem.addAttribute(new Attribute("public", "true"));
+            }
+            if (m_architecture != null) {
+                m_elem.addAttribute(new Attribute("architecture", m_architecture));
+            }
+            if (m_immediate != null) {
+                m_elem.addAttribute(new Attribute("immediate", m_immediate));
+            }
+            if (m_method != null) {
+                m_elem.addAttribute(new Attribute("factory-method", m_method));
+            }
+            if (m_version != null) {
+                m_elem.addAttribute(new Attribute("version", m_version));
+            }
+            if (m_propagation != null) {
+                if (m_props == null) {
+                    m_props = new Element("properties", "");
+                    getElements().put(m_props, null);
+                    getIds().put("properties", m_props);
+                }
+                m_props.addAttribute(new Attribute("propagation", m_propagation));
+            }
+            if (m_managedservice != null) {
+                if (m_props == null) {
+                    m_props = new Element("properties", "");
+                    getElements().put(m_props, null);
+                    getIds().put("properties", m_props);
+                }
+                m_props.addAttribute(new Attribute("pid", m_managedservice));
+            }
+        }
+    }
+
+    /**
+     * Parses the @Handler annotation.
+     */
+    private class HandlerVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+        /**
+         * Visit @handler annotation attributes.
+         * @param arg0 : annotation attribute name
+         * @param arg1 : annotation attribute value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("name")) {
+                m_elem.addAttribute(new Attribute("name", arg1.toString()));
+                return;
+            }
+            if (arg0.equals("namespace")) {
+                m_elem.addAttribute(new Attribute("namespace", arg1.toString()));
+                return;
+            }
+            if (arg0.equals("level")) {
+                m_elem.addAttribute(new Attribute("level", arg1.toString()));
+                return;
+            }
+            if (arg0.equals("architecture")) {
+                m_elem.addAttribute(new Attribute("architecture", arg1.toString()));
+                return;
+            }
+        }
+    }
+
+    /**
+     * Parse the @HandlerDeclaration annotation.
+     */
+    private class HandlerDeclarationVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+        /**
+         * XML accepted by the handler.
+         */
+        private String m_value;
+
+        /**
+         * Parses the value attribute.
+         * @param arg0 'value'
+         * @param arg1 the value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            // there is only a 'value' attribute
+            this.m_value = (String) arg1;
+        }
+
+        /**
+         * End of the visit.
+         * Builds the XML document.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            // The value is an XML document
+            DocumentBuilder builder = getFreshDocumentBuilder();
+            InputStream is = new ByteArrayInputStream(m_value.getBytes());
+            Document document = null;
+            try {
+                document = builder.parse(is);
+                convertDOMElements(m_elem, document.getDocumentElement());
+            } catch (Exception e) {
+                // TODO GSA change this to a logger ?
+                System.err.println("[warning] Cannot convert " + m_value + " to iPOJO Elements.");
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    System.err.println("[warning] Cannot close correctly the value input stream");
+                }
+            }
+        }
+
+        /**
+         * Converts recursively the given XML Element into an iPOJO Element.
+         * @param root iPOJO root Element
+         * @param xmlElement DOM Element to be converted
+         */
+        private void convertDOMElements(final Element root,
+                                        final org.w3c.dom.Element xmlElement) {
+
+            // Create an equivalent iPOJO element
+            Element converted = new Element(xmlElement.getLocalName(), xmlElement.getNamespaceURI());
+
+            // Convert attributes if any
+            if (xmlElement.hasAttributes()) {
+                NamedNodeMap attributes = xmlElement.getAttributes();
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    Attr attr = (Attr) attributes.item(i);
+                    converted.addAttribute(new Attribute(attr.getName(),
+                                                         attr.getNamespaceURI(),
+                                                         attr.getValue()));
+                }
+            }
+
+            // Convert child elements if any
+            if (xmlElement.hasChildNodes()) {
+                NodeList childs = xmlElement.getChildNodes();
+                for (int i = 0; i < childs.getLength(); i++) {
+
+                    // Recursive call
+                    convertDOMElements(converted, (org.w3c.dom.Element) childs.item(i));
+                }
+            }
+
+            // Add converted element as a root's child
+            root.addElement(converted);
+        }
+    }
+
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
new file mode 100644
index 0000000..e7f18cd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
@@ -0,0 +1,618 @@
+/*
+ * 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.annotations;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * This class collects method annotations, and give them to the metadata collector.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class MethodCollector extends EmptyVisitor {
+
+    /**
+     * Parent collector.
+     */
+    private MetadataCollector m_collector;
+
+    /**
+     * Method name.
+     */
+    private String m_name;
+
+    /**
+     * Method Descriptor.
+     */
+    private String m_descriptor;
+
+    /**
+     * Constructor.
+     * @param name : name of the method.
+     * @param collector : parent collector.
+     */
+    public MethodCollector(String name, String descriptor, MetadataCollector collector) {
+        m_collector = collector;
+        m_name = name;
+        m_descriptor = descriptor;
+    }
+
+    /**
+     * Visit a parameter annotation.
+     * @see org.objectweb.asm.commons.EmptyVisitor#visitParameterAnnotation(int, java.lang.String, boolean)
+     */
+    public AnnotationVisitor visitParameterAnnotation(int index, String annotation,
+            boolean visible) {
+        if (m_name.equals("<init>")) {
+            if (annotation.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
+                return processProperty(true, index);
+            }
+            if (annotation.equals("Lorg/apache/felix/ipojo/annotations/Requires;")) {
+                return new BindAnnotationParser(index);
+            }
+
+            if (CustomAnnotationVisitor.isCustomAnnotation(annotation)) {
+                Element elem = CustomAnnotationVisitor.buildElement(annotation);
+                elem.addAttribute(new Attribute("index", "" + index));
+                return new CustomAnnotationVisitor(elem, m_collector, true, false, index, m_descriptor);
+            }
+        }
+        return super.visitParameterAnnotation(index, annotation, visible);
+    }
+
+
+
+    /**
+     * Visit method annotations.
+     * @param arg0 : annotation name.
+     * @param arg1 : is the annotation visible at runtime.
+     * @return the visitor paring the visited annotation.
+     * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)
+     */
+    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
+            return processProperty(false, -1);
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Validate;")) {
+            return processValidate();
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Invalidate;")) {
+            return processInvalidate();
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Updated;")) {
+            return processUpdated();
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Bind;")) {
+            return processBind("bind");
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Modified;")) {
+            return processBind("modified");
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Unbind;")) {
+            return processBind("unbind");
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/PostRegistration;")) {
+            return processPostRegistration();
+        }
+        if (arg0.equals("Lorg/apache/felix/ipojo/annotations/PostUnregistration;")) {
+            return processPostUnregistration();
+        }
+
+        if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {
+            Element elem = CustomAnnotationVisitor.buildElement(arg0);
+            elem.addAttribute(new Attribute("method", m_name));
+            return new CustomAnnotationVisitor(elem, m_collector, true, false);
+        }
+
+        return null;
+    }
+
+    /**
+     * Process @Updated annotation.
+     * @return null.
+     */
+    private AnnotationVisitor processUpdated() {
+        Element parent = null;
+        if (! m_collector.getIds().containsKey("properties")) {
+            parent = new Element("Properties", "");
+            m_collector.getIds().put("properties", parent);
+            m_collector.getElements().put(parent, null);
+        } else {
+            parent = (Element) m_collector.getIds().get("properties");
+        }
+
+        parent.addAttribute(new Attribute("updated", m_name));
+
+        return null;
+    }
+
+    /**
+     * Process @PostRegistration annotation.
+     * @return null.
+     */
+    private AnnotationVisitor processPostRegistration() {
+        Element parent = null;
+        if (m_collector.getIds().containsKey("provides")) {
+            parent = (Element) m_collector.getIds().get("provides");
+            parent.addAttribute(new Attribute("post-registration", m_name));
+        } else {
+            // Ignore annotation...
+        }
+
+        return null;
+    }
+
+    /**
+     * Process @PostRegistration annotation.
+     * @return null.
+     */
+    private AnnotationVisitor processPostUnregistration() {
+        Element parent = null;
+        if (m_collector.getIds().containsKey("provides")) {
+            parent = (Element) m_collector.getIds().get("provides");
+            parent.addAttribute(new Attribute("post-unregistration", m_name));
+        } else {
+            // Ignore annotation...
+        }
+
+        return null;
+    }
+
+    /**
+     * Process @bind, @modified, @unbind.
+     * @param type : bind or unbind
+     * @return the visitor parsing @bind & @unbind annotations.
+     */
+    private AnnotationVisitor processBind(String type) {
+        return new BindAnnotationParser(m_name, type);
+    }
+
+    /**
+     * Process @validate annotation.
+     * @return null.
+     */
+    private AnnotationVisitor processValidate() {
+        Element cb = new Element("callback", "");
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "validate"));
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
+        m_collector.getElements().put(cb, null);
+        return null;
+    }
+
+    /**
+     * Process @invalidate annotation.
+     * @return null.
+     */
+    private AnnotationVisitor processInvalidate() {
+        Element cb = new Element("callback", "");
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "invalidate"));
+        cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
+        m_collector.getElements().put(cb, null);
+        return null;
+    }
+
+    /**
+     * Process @property annotation.
+     * @param parameter true if we're processing a parameter
+     * @param index the index, meaningful only if parameter is true
+     * @return the visitor parsing the visited annotation.
+     */
+    private AnnotationVisitor processProperty(boolean parameter, int index) {
+        Element prop = null;
+        if (! m_collector.getIds().containsKey("properties")) {
+            prop = new Element("Properties", "");
+            m_collector.getIds().put("properties", prop);
+            m_collector.getElements().put(prop, null);
+        } else {
+            prop = (Element) m_collector.getIds().get("properties");
+        }
+        return new PropertyAnnotationParser(prop, m_name, parameter, index);
+    }
+
+    /**
+     * Parse @bind & @unbind annotations.
+     */
+    private final class BindAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
+
+        /**
+         * Method name.
+         */
+        private String m_name;
+
+        /**
+         * Requirement filter.
+         */
+        private String m_filter;
+
+        /**
+         * Is the requirement optional?
+         */
+        private String m_optional;
+
+        /**
+         * Is the requirement aggregate?
+         */
+        private String m_aggregate;
+
+        /**
+         * Required specification.
+         */
+        private String m_specification;
+
+        /**
+         * Requirement id.
+         */
+        private String m_id;
+
+        /**
+         * Bind, Modify or Unbind method?
+         */
+        private String m_type;
+
+        /**
+         * Binding policy.
+         */
+        private String m_policy;
+
+        /**
+         * Comparator.
+         */
+        private String m_comparator;
+
+        /**
+         * From attribute.
+         */
+        private String m_from;
+
+        /**
+         * For annotation parameter,
+         * the parameter index.
+         */
+        private int m_index = -1;
+
+        /**
+         * Constructor.
+         * @param bind : method name.
+         * @param type : is the callback a bind or an unbind method.
+         */
+        private BindAnnotationParser(String bind, String type) {
+            m_name = bind;
+            m_type = type;
+        }
+
+        private BindAnnotationParser(int index) {
+            m_index = index;
+        }
+
+        /**
+         * Visit annotation attribute.
+         * @param arg0 : annotation name
+         * @param arg1 : annotation value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("filter")) {
+                m_filter = arg1.toString();
+                return;
+            }
+            if (arg0.equals("optional")) {
+                m_optional = arg1.toString();
+                return;
+            }
+            if (arg0.equals("aggregate")) {
+                m_aggregate = arg1.toString();
+                return;
+            }
+            if (arg0.equals("specification")) {
+                m_specification = arg1.toString();
+                return;
+            }
+            if (arg0.equals("policy")) {
+                m_policy = arg1.toString();
+                return;
+            }
+            if (arg0.equals("id")) {
+                m_id = arg1.toString();
+                return;
+            }
+            if (arg0.equals("comparator")) {
+                Type type = Type.getType(arg1.toString());
+                m_comparator = type.getClassName();
+                return;
+            }
+            if (arg0.equals("from")) {
+                m_from = arg1.toString();
+                return;
+            }
+
+        }
+
+        /**
+         * End of the visit.
+         * Create or append the requirement info to a created or already existing "requires" element.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            if (m_id == null) {
+                if (m_name != null  && m_name.startsWith("bind")) {
+                    m_id = m_name.substring("bind".length());
+                } else if (m_name != null  && m_name.startsWith("unbind")) {
+                    m_id = m_name.substring("unbind".length());
+                } else if (m_name != null  && m_name.startsWith("modified")) {
+                    m_id = m_name.substring("modified".length());
+                } else if (m_index != -1) {
+                    m_id = "" + m_index;
+                } else {
+                    System.err.println("Cannot determine the id of the " + m_type + " method : " + m_name);
+                    return;
+                }
+            }
+
+            // Check if it is a full-determined requirement
+            Element req = (Element) m_collector.getIds().get(m_id);
+            if (req == null) {
+                // Add the complete requires
+                req = new Element("requires", "");
+                if (m_specification != null) {
+                    req.addAttribute(new Attribute("specification", m_specification));
+                }
+                if (m_aggregate != null) {
+                    req.addAttribute(new Attribute("aggregate", m_aggregate));
+                }
+                if (m_filter != null) {
+                    req.addAttribute(new Attribute("filter", m_filter));
+                }
+                if (m_optional != null) {
+                    req.addAttribute(new Attribute("optional", m_optional));
+                }
+                if (m_policy != null) {
+                    req.addAttribute(new Attribute("policy", m_policy));
+                }
+                if (m_id != null) {
+                    req.addAttribute(new Attribute("id", m_id));
+                }
+                if (m_comparator != null) {
+                    req.addAttribute(new Attribute("comparator", m_comparator));
+                }
+                if (m_from != null) {
+                    req.addAttribute(new Attribute("from", m_from));
+                }
+            } else {
+                String itf = req.getAttribute("specification");
+                String aggregate = req.getAttribute("aggregate");
+                String optional = req.getAttribute("optional");
+                String filter = req.getAttribute("filter");
+                String policy = req.getAttribute("policy");
+                String comparator = req.getAttribute("comparator");
+                String from = req.getAttribute("from");
+                if (m_specification != null) {
+                    if (itf == null) {
+                        req.addAttribute(new Attribute("specification", m_specification));
+                    } else if (! m_specification.equals(itf)) {
+                        System.err.println("The required specification is not the same as previouly : " + m_specification + " & " + itf);
+                        return;
+                    }
+                }
+
+                if (m_optional != null) {
+                    if (optional == null) {
+                        req.addAttribute(new Attribute("optional", m_optional));
+                    } else if (! m_optional.equals(optional)) {
+                        System.err.println("The optional attribute is not always the same");
+                        return;
+                    }
+                }
+
+                if (m_aggregate != null) {
+                    if (aggregate == null) {
+                        req.addAttribute(new Attribute("aggregate", m_aggregate));
+                    } else if (! m_aggregate.equals(aggregate)) {
+                        System.err.println("The aggregate attribute is not always the same");
+                        return;
+                    }
+                }
+
+                if (m_filter != null) {
+                    if (filter == null) {
+                        req.addAttribute(new Attribute("filter", m_filter));
+                    } else if (! m_filter.equals(filter)) {
+                        System.err.println("The filter attribute is not always the same");
+                        return;
+                    }
+                }
+
+                if (m_policy != null) {
+                    if (policy == null) {
+                        req.addAttribute(new Attribute("policy", m_policy));
+                    } else if (! m_policy.equals(policy)) {
+                        System.err.println("The policy attribute is not always the same");
+                        return;
+                    }
+                }
+
+                if (m_comparator != null) {
+                    if (comparator == null) {
+                        req.addAttribute(new Attribute("comparator", m_comparator));
+                    } else if (! m_comparator.equals(comparator)) {
+                        System.err.println("The comparator attribute is not always the same");
+                        return;
+                    }
+                }
+
+                if (m_from != null) {
+                    if (from == null) {
+                        req.addAttribute(new Attribute("from", m_from));
+                    } else if (! m_from.equals(from)) {
+                        System.err.println("The from attribute is not always the same");
+                        return;
+                    }
+                }
+
+            }
+            if (m_name != null) {
+                Element method = new Element("callback", "");
+                method.addAttribute(new Attribute("method", m_name));
+                method.addAttribute(new Attribute("type", m_type));
+                req.addElement(method);
+            } else {
+                req.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+            }
+
+            m_collector.getIds().put(m_id, req);
+            m_collector.getElements().put(req, null);
+            return;
+        }
+    }
+
+    private final class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
+
+        /**
+         * Parent element.
+         */
+        private Element m_parent;
+
+        /**
+         * Attached method.
+         */
+        private String m_method;
+
+        /**
+         * Property name.
+         */
+        private String m_name;
+
+        /**
+         * Property id.
+         */
+        private String m_id;
+
+        /**
+         * Property value.
+         */
+        private String m_value;
+
+        /**
+         * Property mandatory aspect.
+         */
+        private String m_mandatory;
+
+        /**
+         * Flag set to true if we're processing an annotation parameter.
+         */
+        private boolean m_isParameterAnnotation = false;
+
+        /**
+         * If this is a parameter annotation, the index of the parameter.
+         */
+        private int m_index = -1;
+
+        /**
+         * Constructor.
+         * @param parent : parent element.
+         * @param method : attached method.
+         * @param param : we're processing a parameter
+         * @param index : the parameter index
+         */
+        private PropertyAnnotationParser(Element parent, String method, boolean param, int index) {
+            m_parent = parent;
+            m_method = method;
+            m_isParameterAnnotation = param;
+            m_index = index;
+        }
+
+        /**
+         * Visit annotation attributes.
+         * @param arg0 : annotation name
+         * @param arg1 : annotation value
+         * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+         */
+        public void visit(String arg0, Object arg1) {
+            if (arg0.equals("name")) {
+                m_name = arg1.toString();
+                return;
+            }
+            if (arg0.equals("value")) {
+                m_value = arg1.toString();
+                return;
+            }
+            if (arg0.equals("mandatory")) {
+                m_mandatory = arg1.toString();
+                return;
+            }
+            if (arg0.equals("id")) {
+                m_id = arg1.toString();
+                return;
+            }
+        }
+
+        /**
+         * End of the visit.
+         * Append the computed element to the parent element.
+         * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+         */
+        public void visitEnd() {
+            // If neither name not id, try to extract the name
+            if (m_name == null && m_id == null  && m_method.startsWith("set")) {
+                m_name = m_method.substring("set".length());
+                m_id = m_name;
+            // Else align the two values
+            } else if (m_name != null  && m_id == null) {
+                m_id = m_name;
+            } else if (m_id != null  && m_name == null) {
+                m_name = m_id;
+            }
+
+            Element[] props = m_parent.getElements("Property");
+            Element prop = null;
+            for (int i = 0; props != null && prop == null && i < props.length; i++) {
+                String name = props[i].getAttribute("name");
+                if (name != null && name.equals(m_name)) {
+                    prop = props[i];
+                }
+            }
+
+            if (prop == null) {
+                prop = new Element("property", "");
+                m_parent.addElement(prop);
+                if (m_name != null) {
+                    prop.addAttribute(new Attribute("name", m_name));
+                }
+            }
+
+            if (m_value != null) {
+                prop.addAttribute(new Attribute("value", m_value));
+            }
+            if (m_mandatory != null) {
+                prop.addAttribute(new Attribute("mandatory", m_mandatory));
+            }
+
+            if (m_isParameterAnnotation) {
+                String t = Type.getArgumentTypes(m_descriptor)[m_index].getClassName();
+                prop.addAttribute(new Attribute("type", t));
+                prop.addAttribute(new Attribute("constructor-parameter", Integer.toString(m_index)));
+            } else {
+                prop.addAttribute(new Attribute("method", m_method));
+            }
+
+        }
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/PropertyAnnotationParser.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/PropertyAnnotationParser.java
new file mode 100644
index 0000000..548fd23
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/PropertyAnnotationParser.java
@@ -0,0 +1,150 @@
+/*
+ * 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.annotations;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Parses a Property or ServiceProperty annotation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
+
+    /**
+     * Parent element element.
+     */
+    private Element m_parent;
+
+    /**
+     * Field name.
+     */
+    private String m_field;
+
+    /**
+     * Property name.
+     */
+    private String m_name;
+
+    /**
+     * Property value.
+     */
+    private String m_value;
+
+    /**
+     * Property mandatory aspect.
+     */
+    private String m_mandatory;
+
+    /**
+     * Property type.
+     */
+    private String m_type;
+
+
+    /**
+     * Constructor.
+     * @param parent : parent element.
+     * @param field : field name.
+     */
+    PropertyAnnotationParser(String field, Element parent) {
+        m_parent = parent;
+        m_field = field;
+    }
+
+    /**
+     * Constructor without field
+     * @param parent : parent element..
+     */
+    PropertyAnnotationParser(Element parent) {
+        m_parent = parent;
+        m_field = null;
+    }
+
+    /**
+     * Visit one "simple" annotation.
+     * @param arg0 : annotation name
+     * @param arg1 : annotation value
+     * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
+     */
+    public void visit(String arg0, Object arg1) {
+        if (arg0.equals("name")) {
+            m_name = arg1.toString();
+            return;
+        }
+        if (arg0.equals("value")) {
+            m_value = arg1.toString();
+            return;
+        }
+        if (arg0.equals("mandatory")) {
+            m_mandatory = arg1.toString();
+            return;
+        }
+        if (arg0.equals("type")) {
+        	m_type = arg1.toString();
+        	return;
+        }
+    }
+
+    /**
+     * End of the annotation.
+     * Create a "property" element
+     * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
+     */
+    public void visitEnd() {
+        if (m_field != null  && m_name == null) {
+            m_name = m_field;
+        }
+
+
+        Element[] props = m_parent.getElements("Property");
+        Element prop = null;
+        for (int i = 0; prop == null && props != null && i < props.length; i++) {
+            String name = props[i].getAttribute("name");
+            if (name != null && name.equals(m_name)) {
+                prop = props[i];
+            }
+        }
+
+        if (prop == null) {
+            prop = new Element("property", "");
+            m_parent.addElement(prop);
+            if (m_name != null) {
+                prop.addAttribute(new Attribute("name", m_name));
+            }
+        }
+
+        if (m_field != null) {
+        	prop.addAttribute(new Attribute("field", m_field));
+        }
+        if (m_type != null) {
+        	prop.addAttribute(new Attribute("type", m_type));
+        }
+
+        if (m_value != null) {
+            prop.addAttribute(new Attribute("value", m_value));
+        }
+        if (m_mandatory != null) {
+            prop.addAttribute(new Attribute("mandatory", m_mandatory));
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.java
new file mode 100644
index 0000000..7fc0c6e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestAttributeFilter.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;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+
+/**
+ * Defines a filter to be tested against Attribute contained
+ * in the Manifest.
+ * If one filter accept the attribute, others are ignored.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ManifestAttributeFilter {
+
+    /**
+     * Tests if the given Attribute is recognized by the filter
+     * @param attribute the tested attribute.
+     * @return <code>true</code> if the filter accept the
+     * value, <code>false</code> otherwise.
+     */
+    public boolean accept(final Attribute attribute);
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManifestProvider.java
new file mode 100644
index 0000000..77596a7
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
new file mode 100644
index 0000000..aa5eb2f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationEngine.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+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> m_manipulationUnits = new ArrayList<ManipulationUnit>();
+
+    /**
+     * Error reporting.
+     */
+    private Reporter m_reporter;
+
+    /**
+     * Bytecode store.
+     */
+    private ResourceStore m_store;
+
+    /**
+     * The visitor handling output result.
+     */
+    private ManipulationVisitor m_manipulationVisitor;
+
+    /**
+     * Add information related to a discovered component that will be manipulated.
+     * @param component additional component
+     */
+    public void addManipulationUnit(ManipulationUnit component) {
+        m_manipulationUnits.add(component);
+    }
+
+    public void setManipulationVisitor(ManipulationVisitor manipulationVisitor) {
+        m_manipulationVisitor = manipulationVisitor;
+    }
+
+    /**
+     * @param reporter Feedback reporter.
+     */
+    public void setReporter(Reporter reporter) {
+        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) {
+        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 : m_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 = m_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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationResultVisitor.java
new file mode 100644
index 0000000..702abfd
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
new file mode 100644
index 0000000..d25391e
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationUnit.java
@@ -0,0 +1,69 @@
+/*
+ * 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.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) {
+        m_resourcePath = resourcePath;
+        m_componentMetadata = meta;
+        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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ManipulationVisitor.java
new file mode 100644
index 0000000..c04bd57
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/MetadataProvider.java
new file mode 100644
index 0000000..b6aecd0
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
new file mode 100644
index 0000000..5fcee7b
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Pojoization.java
@@ -0,0 +1,319 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.jar.JarFile;
+
+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.SchemaResolver;
+
+/**
+ * Pojoization allows creating an iPOJO bundle from a "normal" bundle.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Pojoization {
+
+    /**
+     * iPOJO Imported Package Version.
+     */
+    public static final String IPOJO_PACKAGE_VERSION = " 1.8.0";
+
+    /**
+     * Flag describing if we need or not compute annotations.
+     * By default, compute the annotations.
+     */
+    private boolean m_ignoreAnnotations;
+
+    /**
+     * 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 used (default to {@literal false}).
+     */
+    private boolean m_useLocalXSD = false;
+
+    /**
+     * Reporter for error reporting.
+     */
+    private Reporter m_reporter;
+
+    public Pojoization() {
+        this(new SystemReporter());
+    }
+
+    public Pojoization(Reporter reporter) {
+        m_reporter = reporter;
+    }
+
+    /**
+     * Activates annotation processing.
+     */
+    public void disableAnnotationProcessing() {
+        m_ignoreAnnotations = true;
+    }
+
+    /**
+     * Activates the entity resolver loading
+     * XSD files from the classloader.
+     */
+    public void setUseLocalXSD() {
+        m_useLocalXSD = true;
+    }
+
+    /**
+     * @return all the errors (fatal) reported by the manipulation process.
+     */
+    public List<String> getErrors() {
+        // Simple delegation for backward compatibility
+        return m_reporter.getErrors();
+    }
+
+    /**
+     * @return all the warnings (non fatal) reported by the manipulation process.
+     */
+    public List<String> 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.
+     * @param in the original bundle.
+     * @param out the final bundle.
+     * @param metadata the iPOJO metadata input stream.
+     */
+    public void pojoization(File in, File out, InputStream metadata) {
+
+        StreamMetadataProvider provider = new StreamMetadataProvider(metadata, m_reporter);
+        provider.setValidateUsingLocalSchemas(m_useLocalXSD);
+
+        ResourceStore store;
+        try {
+            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) {
+            m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+            return;
+        }
+
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+        pojoization(store, provider, visitor);
+    }
+
+    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;
+    }
+
+    /**
+     * Manipulates an input bundle.
+     * This method creates an iPOJO bundle based on the given metadata file.
+     * The original and final bundles must be different.
+     * @param in the original bundle.
+     * @param out the final bundle.
+     * @param metadataFile the iPOJO metadata file (XML).
+     */
+    public void pojoization(File in, File out, File metadataFile) {
+
+        MetadataProvider provider = new EmptyMetadataProvider();
+        if (metadataFile != null) {
+            FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+            fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+            provider = fileMetadataProvider;
+        }
+
+        ResourceStore store;
+        try {
+            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) {
+            m_reporter.error("The input file " + in.getAbsolutePath() + " is not a Jar file");
+            return;
+        }
+
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+        pojoization(store, provider, visitor);
+    }
+
+    /**
+     * Manipulates an expanded bundles.
+     * Classes are in the specified directory.
+     * this method allows to update a customized manifest.
+     * @param directory the directory containing classes
+     * @param metadataFile the metadata file
+     * @param manifestFile the manifest file. <code>null</code> to use directory/META-INF/MANIFEST.mf
+     */
+    public void directoryPojoization(File directory, File metadataFile, File manifestFile) {
+        // Get the metadata.xml location if not null
+        MetadataProvider provider = new EmptyMetadataProvider();
+        if (metadataFile != null) {
+            FileMetadataProvider fileMetadataProvider = new FileMetadataProvider(metadataFile, m_reporter);
+            fileMetadataProvider.setValidateUsingLocalSchemas(m_useLocalXSD);
+            provider = fileMetadataProvider;
+        }
+
+        ManifestProvider manifestProvider;
+        if (manifestFile != null) {
+            if (manifestFile.isFile()) {
+                try {
+                    manifestProvider = new FileManifestProvider(manifestFile);
+                } catch (IOException e) {
+                    m_reporter.error("Cannot read Manifest from '" + manifestFile.getAbsolutePath() + "'");
+                    return;
+                }
+            } else {
+                m_reporter.error("The manifest file " + manifestFile.getAbsolutePath() + " does not exist");
+                return;
+            }
+        } else {
+            // 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;
+                }
+            } else {
+                m_reporter.error("The manifest file " + original.getAbsolutePath() + " does not exist");
+                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());
+            }
+            store.setManifest(manifestProvider.getManifest());
+            DefaultManifestBuilder dmb = new DefaultManifestBuilder();
+            dmb.setMetadataRenderer(new MetadataRenderer());
+            store.setManifestBuilder(dmb);
+        } else {
+            m_reporter.error("The directory " + directory.getAbsolutePath() + " does not exist or is not a directory.");
+            return;
+        }
+
+        ManipulationVisitor visitor = createDefaultVisitorChain(store);
+
+        pojoization(store, provider, visitor);
+
+    }
+
+    public void pojoization(final ResourceStore store,
+                            final MetadataProvider metadata,
+                            final ManipulationVisitor visitor) {
+
+        ManipulationEngine engine = new ManipulationEngine();
+        engine.setResourceStore(store);
+        engine.setReporter(m_reporter);
+        engine.setManipulationVisitor(visitor);
+
+        try {
+
+            // Creates a composite to store multiple metadata providers
+            CompositeMetadataProvider composite = new CompositeMetadataProvider(m_reporter);
+            composite.addMetadataProvider(metadata);
+
+            if (!m_ignoreAnnotations) {
+                composite.addMetadataProvider(new AnnotationMetadataProvider(store, m_reporter));
+            }
+
+            // Get metadata
+            List<Element> metadatas = composite.getMetadatas();
+
+            // 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 {
+                    visitor.visitMetadata(meta);
+                }
+            }
+
+        } catch (IOException e) {
+            m_reporter.error("Cannot load metadata " + e.getMessage());
+            return;
+        }
+
+        // Start the manipulation
+        engine.generate();
+
+        // Tell the visitor that we have finished
+        visitor.visitEnd();
+
+    }
+}
+
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
new file mode 100644
index 0000000..f9054c6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/QuotedTokenizer.java
@@ -0,0 +1,199 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *   http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+package org.apache.felix.ipojo.manipulator;

+

+import java.util.ArrayList;

+import java.util.List;

+

+/**

+ * Parse on OSGi Manifest clause.

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

+ */

+public class QuotedTokenizer {

+    /**

+     * String to parse.

+     */

+    String m_string;

+

+    /**

+     * Index.

+     */

+    int m_index = 0;

+

+    /**

+     * Default separator to use.

+     */

+    String m_separators;

+

+    /**

+     * Does the tokenizer returns token.

+     */

+    boolean m_returnTokens;

+

+    /**

+     * Peek.

+     */

+    String m_peek;

+

+    /**

+     * Separator.

+     */

+    char m_separator;

+

+    /**

+     * Constructors.

+     * @param string : input String.

+     * @param separators : separators.

+     * @param returnTokens : should the tokenizer return tokens ?

+     */

+    public QuotedTokenizer(String string, String separators, boolean returnTokens) {

+        if (string == null) {

+            throw new IllegalArgumentException("string argument must be not null");

+        }

+        this.m_string = string;

+        this.m_separators = separators;

+        this.m_returnTokens = returnTokens;

+    }

+

+    /**

+     * Constructors.

+     * Set returnTokens to false.

+     * @param string : input String.

+     * @param separators : separators

+     */

+    public QuotedTokenizer(String string, String separators) {

+        this(string, separators, false);

+    }

+

+    /**

+     * Get the next token.

+     * @param separators : separators to used.

+     * @return : the next token.

+     */

+    public String nextToken(String separators) {

+        m_separator = 0;

+        if (m_peek != null) {

+            String tmp = m_peek;

+            m_peek = null;

+            return tmp;

+        }

+

+        if (m_index == m_string.length()) { return null; }

+

+        StringBuffer sb = new StringBuffer();

+

+        while (m_index < m_string.length()) {

+            char c = m_string.charAt(m_index++);

+

+            if (Character.isWhitespace(c)) {

+                if (m_index == m_string.length()) {

+                    break;

+                } else {

+                    continue;

+                }

+            }

+

+            if (separators.indexOf(c) >= 0) {

+                if (m_returnTokens) {

+                    m_peek = Character.toString(c);

+                } else {

+                    m_separator = c;

+                }

+                break;

+            }

+

+            switch (c) {

+                case '"':

+                case '\'':

+                    quotedString(sb, c);

+                    break;

+

+                default:

+                    sb.append(c);

+            }

+        }

+        String result = sb.toString().trim();

+        if (result.length() == 0 && m_index == m_string.length()) { return null; }

+        return result;

+    }

+

+    /**

+     * Get the next token.

+     * Used the defined separators.

+     * @return the next token.

+     */

+    public String nextToken() {

+        return nextToken(m_separators);

+    }

+

+    /**

+     * Append the next quote to the given String Buffer.

+     * @param sb : accumulator.

+     * @param c : quote.

+     */

+    private void quotedString(StringBuffer sb, char c) {

+        char quote = c;

+        while (m_index < m_string.length()) {

+            c = m_string.charAt(m_index++);

+            if (c == quote) { break; }

+            if (c == '\\' && m_index < m_string.length() && m_string.charAt(m_index + 1) == quote) {

+                c = m_string.charAt(m_index++);

+            }

+            sb.append(c);

+        }

+    }

+

+    public String[] getTokens() {

+        return getTokens(0);

+    }

+

+    /**

+     * Get the list of tokens.

+     * @param cnt : array length.

+     * @return : the array of token.

+     */

+    private String[] getTokens(int cnt) {

+        String token = nextToken();

+        if (token == null) {

+            return new String[cnt];

+        }

+

+        String[] result = getTokens(cnt + 1);

+        result[cnt] = token;

+        return result;

+    }

+

+    public char getSeparator() {

+        return m_separator;

+    }

+

+    /**

+     * Get token list.

+     * @return the list of token.

+     */

+    public List<String> getTokenSet() {

+        List<String> list = new ArrayList<String>();

+        String token = nextToken();

+        while (token != null) {

+            list.add(token);

+            token = nextToken();

+        }

+        return list;

+    }

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/Reporter.java
new file mode 100644
index 0000000..33445f0
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
new file mode 100644
index 0000000..82abde6
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceStore.java
@@ -0,0 +1,76 @@
+/**
+ * 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 org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * 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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/ResourceVisitor.java
new file mode 100644
index 0000000..00d75d3
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProvider.java
new file mode 100644
index 0000000..e4dc187
--- /dev/null
+++ b/ipojo/manipulator/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 m_manifest;
+
+    /**
+     * Construct a provider servicing the given manifest.
+     * @param manifest Manifest to be serviced
+     */
+    public DirectManifestProvider(Manifest manifest) {
+        m_manifest = manifest;
+    }
+
+    public Manifest getManifest() {
+        return m_manifest;
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProvider.java
new file mode 100644
index 0000000..81e723e
--- /dev/null
+++ b/ipojo/manipulator/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 m_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 {
+        m_manifest = new Manifest();
+        InputStream is = null;
+        try {
+            is = new FileInputStream(resource);
+            m_manifest.read(is);
+        } finally {
+            Streams.close(is);
+        }
+    }
+
+    public Manifest getManifest() {
+        return m_manifest;
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProvider.java
new file mode 100644
index 0000000..398f0d7
--- /dev/null
+++ b/ipojo/manipulator/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 m_store;
+
+    private Reporter m_reporter;
+
+    public AnnotationMetadataProvider(final ResourceStore store,
+                                      final Reporter reporter) {
+        this.m_store = store;
+        this.m_reporter = reporter;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        final List<Element> metadata = new ArrayList<Element>();
+
+
+        m_store.accept(new ResourceVisitor() {
+            public void visit(String name) {
+                if (name.endsWith(".class")) {
+
+                    // Read file's content
+                    byte[] data = null;
+                    try {
+                        data = m_store.read(name);
+                    } catch (IOException e) {
+                        m_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 {
+                        m_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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProvider.java
new file mode 100644
index 0000000..f6affff
--- /dev/null
+++ b/ipojo/manipulator/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 m_delegate;
+
+    /**
+     * Cached elements.
+     */
+    private List<Element> m_cached;
+
+    public CacheableMetadataProvider(MetadataProvider delegate) {
+        m_delegate = delegate;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        // Only ask the delegate if cache is empty
+        if (m_cached == null) {
+            m_cached = new ArrayList<Element>();
+            m_cached.addAll(m_delegate.getMetadatas());
+        }
+        return m_cached;
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProvider.java
new file mode 100644
index 0000000..9661aed
--- /dev/null
+++ b/ipojo/manipulator/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> m_providers = new ArrayList<MetadataProvider>();
+    private Reporter m_reporter;
+
+    public CompositeMetadataProvider(Reporter reporter) {
+        m_reporter = reporter;
+    }
+
+    public void addMetadataProvider(MetadataProvider provider) {
+        m_providers.add(provider);
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+        List<Element> metadata = new ArrayList<Element>();
+        for (MetadataProvider provider : m_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 ?
+                            m_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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProvider.java
new file mode 100644
index 0000000..b7b99ad
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProvider.java
new file mode 100644
index 0000000..4873bcc
--- /dev/null
+++ b/ipojo/manipulator/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 m_source;
+
+    /**
+     * Feedback reporter.
+     */
+    private Reporter m_reporter;
+
+    /**
+     * Validate using local schemas or not ?
+     */
+    private boolean m_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) {
+        m_source = source;
+        m_reporter = reporter;
+    }
+
+    public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+        m_validateUsingLocalSchemas = validateUsingLocalSchemas;
+    }
+
+    public List<Element> getMetadatas() throws IOException {
+
+        List<Element> metadata = new ArrayList<Element>();
+        traverse(m_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) {
+                m_reporter.warn("Cannot find the metadata file : " + m_source.getAbsolutePath());
+            } else {
+                stream = url.openStream();
+                StreamMetadataProvider provider = new StreamMetadataProvider(stream, m_reporter);
+                provider.setValidateUsingLocalSchemas(m_validateUsingLocalSchemas);
+                metadata.addAll(provider.getMetadatas());
+            }
+        } catch (MalformedURLException e) {
+            m_reporter.error("Cannot open the metadata input stream from " + m_source.getAbsolutePath() + ": " + e.getMessage());
+        } catch (IOException e) {
+            m_reporter.error("Cannot open the metadata input stream: " + m_source.getAbsolutePath() + ": " + e.getMessage());
+        }
+
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProvider.java
new file mode 100644
index 0000000..dd2d891
--- /dev/null
+++ b/ipojo/manipulator/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 m_stream;
+
+    private Reporter m_reporter;
+
+    private boolean m_validateUsingLocalSchemas = false;
+
+    public StreamMetadataProvider(InputStream stream, Reporter reporter) {
+        m_stream = stream;
+        m_reporter = reporter;
+    }
+
+    /**
+     * Force XML schemas resolution to be performed locally
+     */
+    public void setValidateUsingLocalSchemas(boolean validateUsingLocalSchemas) {
+        m_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 (m_validateUsingLocalSchemas) {
+                parser.setEntityResolver(new SchemaResolver());
+            }
+
+            // Parse the XML
+            InputSource is = new InputSource(m_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) {
+                m_reporter.warn("Neither component types, nor instances in the XML metadata");
+            }
+
+        } catch (IOException e) {
+            m_reporter.error("Cannot open the metadata input stream: " + e.getMessage());
+        } catch (ParseException e) {
+            m_reporter.error("Parsing error when parsing the XML file: " + e.getMessage());
+        } catch (SAXParseException e) {
+            m_reporter.error("Error during metadata parsing at line " + e.getLineNumber() + " : " + e.getMessage());
+        } catch (SAXException e) {
+            m_reporter.error("Parsing error when parsing (Sax Error) the XML file: " + e.getMessage());
+        } finally {
+            Streams.close(m_stream);
+        }
+
+        return metadata;
+
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.java
new file mode 100644
index 0000000..1e262ab
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilter.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.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}
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataFilter.java
new file mode 100644
index 0000000..3bfc2a5
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/render/MetadataRenderer.java
new file mode 100644
index 0000000..f44c36f
--- /dev/null
+++ b/ipojo/manipulator/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> m_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) {
+        m_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 : m_filters) {
+            if (filter.accept(element)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/EmptyReporter.java
new file mode 100644
index 0000000..28c4e03
--- /dev/null
+++ b/ipojo/manipulator/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> m_warnings = new ArrayList<String>();
+
+    /**
+     * List of errors
+     */
+    private List<String> m_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 m_errors;
+    }
+
+    public List<String> getWarnings() {
+        return m_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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/reporter/SystemReporter.java
new file mode 100644
index 0000000..18e9310
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
new file mode 100644
index 0000000..b1af78f
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStore.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.store;
+
+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;
+
+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.metadata.Element;
+
+/**
+ * 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 m_source;
+
+    /**
+     * Target directory.
+     */
+    private File m_target;
+
+    /**
+     * The builder of the updated manifest.
+     */
+    private ManifestBuilder m_manifestBuilder;
+
+    /**
+     * Original manifest to be updated.
+     */
+    private Manifest m_manifest;
+
+    /**
+     * Resource Mapper.
+     */
+    private ResourceMapper m_mapper = new FileSystemResourceMapper(new IdentityResourceMapper());
+
+    public DirectoryResourceStore(File source) {
+        this(source, source);
+    }
+
+    public DirectoryResourceStore(File source, File target) {
+        m_source = source;
+        m_target = target;
+    }
+
+    public void setResourceMapper(ResourceMapper mapper) {
+        m_mapper = new FileSystemResourceMapper(mapper);
+    }
+
+    public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+        m_manifestBuilder = manifestBuilder;
+    }
+
+    public void setManifest(Manifest manifest) {
+        m_manifest = manifest;
+    }
+
+    public byte[] read(String path) throws IOException {
+        File resource = new File(m_source, m_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(m_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(m_source.getPath().length());
+        return m_mapper.externalize(relative);
+    }
+
+    public void open() throws IOException {
+
+        // Update the manifest
+        Manifest updated = m_manifestBuilder.build(m_manifest);
+
+        // Write it on disk
+        File metaInf = new File(m_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) {
+        m_manifestBuilder.addMetada(Collections.singletonList(metadata));
+        m_manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+    }
+
+    public void write(String resourcePath, byte[] bytecode) throws IOException {
+
+        // Internalize the name
+        File resource = new File(m_target, m_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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStore.java
new file mode 100644
index 0000000..ba1a18a
--- /dev/null
+++ b/ipojo/manipulator/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 m_source;
+
+    /**
+     * Target File.
+     */
+    private File m_target;
+
+    /**
+     * Modified resources.
+     */
+    private Map<String, byte[]> m_content;
+
+    /**
+     * Resource Mapper.
+     */
+    private ResourceMapper m_mapper = new IdentityResourceMapper();
+
+    /**
+     * The builder of the updated manifest.
+     */
+    private ManifestBuilder m_manifestBuilder;
+
+    /**
+     * Original manifest to be updated.
+     */
+    private Manifest m_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 {
+        m_source = source;
+        m_target = target;
+
+        // TODO ensure File is not null and not an existing file/directory
+        this.m_target = target;
+        if (source != null) {
+            m_manifest = source.getManifest();
+        } else {
+            m_manifest = new Manifest();
+        }
+        m_content = new TreeMap<String, byte[]>();
+    }
+
+    public void setResourceMapper(ResourceMapper mapper) {
+        this.m_mapper = mapper;
+    }
+
+    public void setManifestBuilder(ManifestBuilder manifestBuilder) {
+        this.m_manifestBuilder = manifestBuilder;
+    }
+
+    public void setManifest(Manifest manifest) {
+        this.m_manifest = manifest;
+    }
+
+    public byte[] read(String path) throws IOException {
+        ZipEntry entry = m_source.getEntry(getInternalPath(path));
+        if (entry == null) {
+            throw new IOException("Jar Entry is not found for class " + path + ".");
+        }
+        return Streams.readBytes(m_source.getInputStream(entry));
+    }
+
+    private String getInternalPath(String path) {
+        return m_mapper.internalize(path);
+    }
+
+    public void accept(ResourceVisitor visitor) {
+        List<JarEntry> entries = Collections.list(m_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 m_mapper.externalize(path);
+    }
+
+    public void open() throws IOException {
+        // Nothing to do
+    }
+
+    public void writeMetadata(Element metadata) {
+        m_manifestBuilder.addMetada(Collections.singletonList(metadata));
+        m_manifestBuilder.addReferredPackage(Metadatas.findReferredPackages(metadata));
+    }
+
+    public void write(String resourcePath, byte[] resource) throws IOException {
+        this.m_content.put(resourcePath, resource);
+    }
+
+    public void close() throws IOException {
+
+        // Update the manifest
+        Manifest updated = m_manifestBuilder.build(m_manifest);
+
+        // Create a new Jar file
+        FileOutputStream fos = new FileOutputStream(m_target);
+        JarOutputStream jos = new JarOutputStream(fos, updated);
+
+        try {
+            // Copy classes and resources
+            List<JarEntry> entries = Collections.list(m_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 = m_content.get(getInternalPath(entry.getName()));
+                    jos.putNextEntry(je);
+                    jos.write(data);
+                    jos.closeEntry();
+                } else {
+                    // Copy the resource as-is
+
+                    jos.putNextEntry(entry);
+                    InputStream is = m_source.getInputStream(entry);
+                    try {
+                        Streams.transfer(is, jos);
+                    } finally {
+                        Streams.close(is);
+                    }
+
+                    jos.closeEntry();
+
+                }
+            }
+        } finally {
+            try {
+                m_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 m_content.containsKey(cleaned);
+        } else {
+            return false;
+        }
+    }
+
+    private boolean isIgnored(JarEntry entry) {
+        return "META-INF/MANIFEST.MF".equals(entry.getName());
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.java
new file mode 100644
index 0000000..4e5e081
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ManifestBuilder.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.store;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.jar.Manifest;
+
+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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/ResourceMapper.java
new file mode 100644
index 0000000..3003ba8
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilder.java
new file mode 100644
index 0000000..3cf7b92
--- /dev/null
+++ b/ipojo/manipulator/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 m_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) {
+        m_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<String, Map<String, String>> imports = parseHeader(att.getValue("Import-Package"));
+        Map<String, String> ver = new TreeMap<String, String>();
+        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<String, String> verCM = new TreeMap<String, String>();
+            verCM.put("version", "1.2");
+            imports.put("org.osgi.service.cm", verCM);
+        }
+        if (!imports.containsKey("org.osgi.service.log")) {
+            Map<String, String> verCM = new TreeMap<String, String>();
+            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<String, String>());
+        }
+
+        // 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(m_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.
+     */
+    protected Map<String, Map<String, String>> parseHeader(String value) {
+        if (value == null || value.trim().length() == 0) {
+            return new HashMap<String, Map<String, String>>();
+        }
+
+        Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+        QuotedTokenizer qt = new QuotedTokenizer(value, ";=,");
+        char del;
+        do {
+            boolean hadAttribute = false;
+            Map<String, String> clause = new HashMap<String, String>();
+            List<String> aliases = new ArrayList<String>();
+            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<String> 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<String, Map<String, String>> 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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
new file mode 100644
index 0000000..120ccfa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapper.java
@@ -0,0 +1,74 @@
+/*
+ * 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 java.io.File;
+
+import org.apache.felix.ipojo.manipulator.store.ResourceMapper;
+
+/**
+ * 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 m_delegate;
+    private char m_separator;
+
+    public FileSystemResourceMapper(ResourceMapper delegate) {
+        this(delegate, File.separatorChar);
+    }
+
+    public FileSystemResourceMapper(ResourceMapper delegate, char separator) {
+        m_delegate = delegate;
+        m_separator = separator;
+    }
+
+    public String internalize(String name) {
+        // transform as system path the result of the internalization operation
+        return systemPath(m_delegate.internalize(name));
+    }
+
+    public String externalize(String name) {
+        // normalize he path before giving it to the delegate mapper
+        return m_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(m_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('/', m_separator);
+    }
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapper.java b/ipojo/manipulator/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/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapper.java b/ipojo/manipulator/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/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
new file mode 100644
index 0000000..84f5084
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Collections5.java
@@ -0,0 +1,85 @@
+/*
+ * 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
+     */
+    @SuppressWarnings("unchecked")
+    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) {
+        @SuppressWarnings("unchecked")
+        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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
new file mode 100644
index 0000000..ce072fc
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Metadatas.java
@@ -0,0 +1,119 @@
+/*
+ * 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.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * {@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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Streams.java
new file mode 100644
index 0000000..0edb0ce
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java
new file mode 100644
index 0000000..597903a
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/util/Strings.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulator.util;
+
+
+/**
+ * {@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/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationAdapter.java
new file mode 100644
index 0000000..a377bc5
--- /dev/null
+++ b/ipojo/manipulator/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 m_delegate;
+
+    public ManipulationAdapter(ManipulationVisitor delegate) {
+        m_delegate = delegate;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        return new ManipulationResultAdapter(m_delegate.visitManipulationResult(metadata));
+    }
+
+    public void visitMetadata(Element metadata) {
+        m_delegate.visitMetadata(metadata);
+    }
+
+    public void visitEnd() {
+        m_delegate.visitEnd();
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/ManipulationResultAdapter.java
new file mode 100644
index 0000000..4ae494e
--- /dev/null
+++ b/ipojo/manipulator/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 m_delegate;
+
+    public ManipulationResultAdapter(ManipulationResultVisitor delegate) {
+        m_delegate = delegate;
+    }
+
+    public void visitClassStructure(Element structure) {
+        m_delegate.visitClassStructure(structure);
+    }
+
+    public void visitManipulatedResource(String type, byte[] resource) {
+        m_delegate.visitManipulatedResource(type, resource);
+    }
+
+    public void visitEnd() {
+        m_delegate.visitEnd();
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitor.java
new file mode 100644
index 0000000..008505c
--- /dev/null
+++ b/ipojo/manipulator/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 m_metadata;
+
+    /**
+     * Reporter for errors.
+     */
+    private Reporter m_reporter;
+
+    public CheckFieldConsistencyResultVisitor(ManipulationResultVisitor visitor) {
+        super(visitor);
+    }
+
+    public void setMetadata(Element metadata) {
+        this.m_metadata = metadata;
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.m_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, m_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)) {
+                m_reporter.error("The field " + fieldName + " is referenced in the "
+                        + "metadata but does not exist in the " + Metadatas.getComponentType(m_metadata)
+                        + " class");
+            }
+        }
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyVisitor.java
new file mode 100644
index 0000000..5d3f635
--- /dev/null
+++ b/ipojo/manipulator/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 m_reporter;
+
+    public CheckFieldConsistencyVisitor(ManipulationVisitor visitor) {
+        super(visitor);
+    }
+
+    public void setReporter(Reporter reporter) {
+        this.m_reporter = reporter;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        CheckFieldConsistencyResultVisitor rv = new CheckFieldConsistencyResultVisitor(super.visitManipulationResult(metadata));
+        rv.setMetadata(metadata);
+        rv.setReporter(m_reporter);
+        return rv;
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriter.java
new file mode 100644
index 0000000..de285c1
--- /dev/null
+++ b/ipojo/manipulator/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 m_resourceStore;
+    private Reporter m_reporter;
+    private List<ManipulatedResultWriter> m_writers;
+
+    public ManipulatedResourcesWriter() {
+        m_writers = new ArrayList<ManipulatedResultWriter>();
+    }
+
+    public void setResourceStore(ResourceStore resourceStore) {
+        m_resourceStore = resourceStore;
+    }
+
+    public void setReporter(Reporter reporter) {
+        m_reporter = reporter;
+    }
+
+    public ManipulationResultVisitor visitManipulationResult(Element metadata) {
+        m_resourceStore.writeMetadata(metadata);
+        ManipulatedResultWriter writer = new ManipulatedResultWriter(metadata);
+        m_writers.add(writer);
+        return writer;
+    }
+
+    public void visitMetadata(Element metadata) {
+        m_resourceStore.writeMetadata(metadata);
+    }
+
+    public void visitEnd() {
+
+        try {
+            m_resourceStore.open();
+            for (ManipulatedResultWriter writer : m_writers) {
+                for (Map.Entry<String, byte[]> entry : writer.getResources().entrySet()) {
+                    m_resourceStore.write(entry.getKey(), entry.getValue());
+                }
+            }
+            m_resourceStore.close();
+        } catch (IOException e) {
+            m_reporter.error("Cannot store manipulation result: " + e.getMessage());
+        }
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriter.java
new file mode 100644
index 0000000..b0619bd
--- /dev/null
+++ b/ipojo/manipulator/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[]> m_resources;
+
+    private Element m_component;
+
+    public ManipulatedResultWriter(Element component) {
+        m_component = component;
+        m_resources = new HashMap<String, byte[]>();
+    }
+
+    public void visitClassStructure(Element structure) {
+        // Insert the manipulation structure in the component's metadata
+        m_component.addElement(structure);
+    }
+
+    public void visitManipulatedResource(String type, byte[] resource) {
+        m_resources.put(type, resource);
+    }
+
+    public void visitEnd() {
+        // nothing to do
+    }
+
+    public Map<String, byte[]> getResources() {
+        return m_resources;
+    }
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
new file mode 100644
index 0000000..d10a4bd
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/ParseException.java
@@ -0,0 +1,40 @@
+/* 

+ * 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.xml.parser;

+

+/**

+ * Exceptions thrown by parsers.

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

+ */

+public class ParseException extends Exception {

+

+    /**

+     * serialVersionUID.

+     */

+    private static final long serialVersionUID = 1L;

+

+    /**

+     * Parsing error.

+     * @param msg : the error message.

+     */

+    public ParseException(String msg) {

+        super(msg);

+    }

+

+}

diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.java
new file mode 100644
index 0000000..0cdc653
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/SchemaResolver.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.xml.parser;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Entity Resolver loading embedded XML Schemas.
+ * This resolver avoid using a network connection to get schemas as they
+ * are loaded from the manipulator jar file.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SchemaResolver implements EntityResolver {
+    
+    /**
+     * Directory where embedded schemas are copied.
+     */
+    public static final String XSD_PATH = "xsd";
+
+    /**
+     * Resolves systemIds to use embedded schemas. The schemas are loaded from
+     * the {@link SchemaResolver#XSD_PATH} directory with the current classloader.
+     * @param publicId the publicId
+     * @param systemId the systemId (Schema URL)
+     * @return the InputSource to load the schemas or <code>null</code> if the schema
+     * cannot be loaded (not embedded)
+     * @throws SAXException cannot happen 
+     * @throws IOException when the embedded resource cannot be read correctly
+     * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
+     */
+    public InputSource resolveEntity(String publicId, String systemId)
+        throws SAXException, IOException {
+        
+        URL url = getURL(systemId);
+        if (url == null) {
+            // Cannot found the resource
+            return null;
+        } else {
+            return new InputSource(url.openStream());
+        }
+        
+    }
+    
+    /**
+     * Computes the local URL of the given system Id.
+     * This URL is computed by trying to load the resource from
+     * the current classloader. First, the last fragment (file name) of the system id
+     * url is extracted and the file is loaded from the {@link SchemaResolver#XSD_PATH}
+     * directory ('xsd/extracted') 
+     * @param id the systemId to load
+     * @return the URL to the resources or <code>null</code> if the resource cannot be found.
+     */
+    private URL getURL(String id) {
+        int index = id.lastIndexOf('/');
+        String fragment = id.substring(index);
+        return this.getClass().getClassLoader().getResource(XSD_PATH + fragment);
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
new file mode 100644
index 0000000..2f46217
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/xml/parser/XMLMetadataParser.java
@@ -0,0 +1,293 @@
+/*
+ * 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.xml.parser;

+

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

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

+import org.xml.sax.Attributes;

+import org.xml.sax.ContentHandler;

+import org.xml.sax.ErrorHandler;

+import org.xml.sax.Locator;

+import org.xml.sax.SAXException;

+import org.xml.sax.SAXParseException;

+

+/**

+ * XML Metadata parser.

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

+ */

+public class XMLMetadataParser implements ContentHandler, ErrorHandler {

+

+    /**

+     * Element of the metadata.

+     */

+    private Element[] m_elements = new Element[0];

+

+    /**

+     * Get parsed metadata.

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

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

+     */

+    public Element[] getMetadata() throws ParseException {

+        return m_elements[0].getElements();

+    }

+

+

+    /**

+     * Characters.

+     * @param ch : character

+     * @param start : start

+     * @param length : length

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#characters(char[], int, int)

+     */

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

+        // NOTHING TO DO

+

+    }

+

+

+    /**

+     * End the document.

+     * @throws SAXException : can never occrus.

+     * @see org.xml.sax.ContentHandler#endDocument()

+     */

+    public void endDocument() throws SAXException {

+    }

+

+

+    /**

+     * End of an element.

+     * @param namespaceURI : element namespace

+     * @param localName : local name

+     * @param qName : qualified name

+     * @throws SAXException : occurs when the element is malformed

+     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)

+     */

+    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {

+        // Get the last element of the list

+        Element lastElement = removeLastElement();

+

+        // The name is consistent

+        // Add this element last element with if it is not the root

+        if (m_elements.length != 0) {

+            Element newQueue = m_elements[m_elements.length - 1];

+            newQueue.addElement(lastElement);

+        } else {

+            // It is the last element

+            addElement(lastElement);

+        }

+

+    }

+

+    /**

+     * End prefix mapping.

+     * @param prefix : ended prefix

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)

+     */

+    public void endPrefixMapping(String prefix) throws SAXException {

+        // NOTHING TO DO

+    }

+

+

+    /**

+     * Ignore whitespace.

+     * @param ch : character

+     * @param start : start

+     * @param length : length

+     * @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 {

+        // NOTHING TO DO

+    }

+

+    /**

+     * Process an instruction.

+     * @param target : target

+     * @param data : data

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)

+     */

+    public void processingInstruction(String target, String data) throws SAXException {

+        // DO NOTHING

+    }

+

+    /**

+     * Set Document locator.

+     * @param locator : new locator.

+     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)

+     */

+    public void setDocumentLocator(Locator locator) {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Skipped entity.

+     * @param name : name.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)

+     */

+    public void skippedEntity(String name) throws SAXException {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Start a document.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#startDocument()

+     */

+    public void startDocument() throws SAXException {

+    }

+

+

+    /**

+     * Start an element.

+     * @param namespaceURI : element namespace.

+     * @param localName : local element.

+     * @param qName : qualified name.

+     * @param atts : attribute

+     * @throws SAXException : occurs if the element cannot be parsed correctly.

+     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)

+     */

+    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {

+        String namespace = namespaceURI;

+        if (namespaceURI != null

+                && (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);

+            String ns = (String) atts.getURI(i);

+            String value = (String) atts.getValue(i);

+            Attribute att = new Attribute(name, ns, value);

+            elem.addAttribute(att);

+        }

+

+        addElement(elem);

+

+    }

+

+    /**

+     * Start a prefix mapping.

+     * @param prefix : prefix.

+     * @param uri : uri.

+     * @throws SAXException : can never occurs.

+     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)

+     */

+    public void startPrefixMapping(String prefix, String uri) throws SAXException {

+        // NOTHING TO DO

+

+    }

+

+    /**

+     * Add an element.

+     * @param elem : the element to add

+     */

+    private void addElement(Element elem) {

+        for (int i = 0; (m_elements != null) && (i < m_elements.length); i++) {

+            if (m_elements[i] == elem) {

+                return;

+            }

+        }

+

+        if (m_elements != null) {

+            Element[] newElementsList = new Element[m_elements.length + 1];

+            System.arraycopy(m_elements, 0, newElementsList, 0, m_elements.length);

+            newElementsList[m_elements.length] = elem;

+            m_elements = newElementsList;

+        } else {

+            m_elements = new Element[] { elem };

+        }

+    }

+

+    /**

+     * Remove an element.

+     * @return : the removed element.

+     */

+    private Element removeLastElement() {

+        int idx = -1;

+        idx = m_elements.length - 1;

+        Element last = m_elements[idx];

+        if (idx >= 0) {

+            if ((m_elements.length - 1) == 0) {

+                // It is the last element of the list;

+                m_elements = new Element[0];

+            } else {

+                // Remove the last element of the list :

+                Element[] newElementsList = new Element[m_elements.length - 1];

+                System.arraycopy(m_elements, 0, newElementsList, 0, idx);

+                m_elements = newElementsList;

+            }

+        }

+        return last;

+    }

+

+

+    /**

+     * An error occurs during the XML-Schema checking.

+     * This method propagates the error except if the error concerns

+     * no XML-Schemas are used   (<code>cvc-elt.1</code>).

+     * @param saxparseexception the checking error

+     * @throws SAXException the propagated exception

+     * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)

+     */

+    public void error(SAXParseException saxparseexception) throws SAXException {

+        if (saxparseexception.getMessage().indexOf("cvc-elt.1") != -1) {

+            return; // Do not throw an exception when no schema defined.

+        }

+        throw saxparseexception;

+    }

+

+

+    /**

+     * A fatal error occurs during the XML-Schema checking.

+     * This method always propagates the error.

+     * @param saxparseexception the checking error

+     * @throws SAXException the propagated exception

+     * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)

+     */

+    public void fatalError(SAXParseException saxparseexception)

+        throws SAXException {

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

+        throw saxparseexception;

+    }

+

+    /**

+     * A warning was detected during the XML-Schema checking.

+     * This method always propagate the warning message to

+     * {@link System#out}.

+     * @param saxparseexception the checking error

+     * @throws SAXException nothing.

+     * @see org.xml.sax.ErrorHandler#warning(SAXParseException)

+     */

+    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/manipulator/src/main/resources/xsd/composite.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/composite.xsd
new file mode 100644
index 0000000..6a95fb8
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/resources/xsd/core.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
new file mode 100644
index 0000000..66cb2d5
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/resources/xsd/event-admin.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/event-admin.xsd
new file mode 100644
index 0000000..b9c8271
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/resources/xsd/extender-pattern.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/extender-pattern.xsd
new file mode 100644
index 0000000..0e2ed9f
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/resources/xsd/jmx.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/jmx.xsd
new file mode 100644
index 0000000..80152e9
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/main/resources/xsd/temporal.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/temporal.xsd
new file mode 100644
index 0000000..4ba6292
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/temporal.xsd
@@ -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.
+-->
+<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="id" type="xs:string" use="optional">
+        	<xs:annotation>
+        		<xs:documentation>The dependency id</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/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/whiteboard-pattern.xsd
new file mode 100644
index 0000000..f02afde
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
new file mode 100644
index 0000000..a81dea8
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/ComponentInstance.java
@@ -0,0 +1,12 @@
+package org.apache.felix.ipojo;
+
+
+/**
+ * Component Instance Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface ComponentInstance {
+
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
new file mode 100644
index 0000000..04281df
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/InstanceManager.java
@@ -0,0 +1,20 @@
+package org.apache.felix.ipojo;
+
+import java.util.Set;
+
+/**
+ * Instance Manager Fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public class InstanceManager {
+
+    public Set getRegistredFields() {
+        return null;
+    }
+
+    public Set getRegistredMethods() {
+        return null;
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
new file mode 100644
index 0000000..c7bcb59
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/Pojo.java
@@ -0,0 +1,10 @@
+package org.apache.felix.ipojo;
+
+/**
+ * POJO Interface fake.
+ * We're using a fake to avoid the cyclic build dependency:
+ * manipulator -> ipojo -> maven-ipojo-plugin -> manipulator
+ */
+public interface Pojo {
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
new file mode 100644
index 0000000..cbf6769
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/ManipulatorTest.java
@@ -0,0 +1,370 @@
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.Pojo;
+import org.apache.felix.ipojo.manipulation.annotations.MetadataCollector;
+import org.mockito.Mockito;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.util.CheckClassAdapter;
+
+public class ManipulatorTest extends TestCase {
+
+    public void testClusterDaemon() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")));
+        TestClassLoader classloader = new TestClassLoader("test.ClusterDaemon", clazz);
+
+        //Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        //System.out.println(manipulator.getManipulationMetadata());
+
+
+        ClassReader reader = new ClassReader(clazz);
+        CheckClassAdapter.verify(reader, false, new PrintWriter(new File("/tmp/class_dump")));
+
+        Class cl = classloader.findClass("test.ClusterDaemon");
+        //Assert.assertNotNull(cl);
+
+        // The manipulation add stuff to the class.
+        //Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/ClusterDaemon.class")).length);
+
+        //Assert.assertNotNull(cl.newInstance());
+
+    }
+
+    public void testManipulatingTheSimplePojo() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")));
+        TestClassLoader classloader = new TestClassLoader("test.SimplePojo", clazz);
+        Class cl = classloader.findClass("test.SimplePojo");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        System.out.println(manipulator.getManipulationMetadata());
+
+        // The manipulation add stuff to the class.
+        Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/SimplePojo.class")).length);
+
+
+        boolean found = false;
+        Constructor cst = null;
+        Constructor[] csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 1  &&
+                    csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+                found = true;
+                cst = csts[i];
+            }
+        }
+        Assert.assertTrue(found);
+
+        // We still have the empty constructor
+        found = false;
+        csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 0) {
+                found = true;
+            }
+        }
+        Assert.assertTrue(found);
+
+        // Check the POJO interface
+        Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+        cst.setAccessible(true);
+        Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+        Method method = cl.getMethod("doSomething", new Class[0]);
+        Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+    }
+
+    public void testManipulatingChild() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
+        TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+        Class cl = classloader.findClass("test.Child");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        boolean found = false;
+        Constructor cst = null;
+        Constructor[] csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 1  &&
+                    csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+                found = true;
+                cst = csts[i];
+            }
+        }
+        Assert.assertTrue(found);
+
+        // We still have the regular constructor
+        found = false;
+        csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 2) {
+                found = true;
+            }
+        }
+        Assert.assertTrue(found);
+
+        // Check the POJO interface
+        Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+        InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+        cst.setAccessible(true);
+        Object pojo = cst.newInstance(new Object[] {im});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+        Method method = cl.getMethod("doSomething", new Class[0]);
+        Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+    }
+
+    //TODO CE - 19/10/2011 Why do we have a classloader issue in this test
+    public void _testManipulatingTheInner() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/PojoWithInner.class")));
+        TestClassLoader classloader = new TestClassLoader("test.PojoWithInner", clazz);
+        Class cl = classloader.findClass("test.PojoWithInner");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+        Assert.assertFalse(manipulator.getInnerClasses().isEmpty());
+
+
+        System.out.println(manipulator.getManipulationMetadata());
+
+        // The manipulation add stuff to the class.
+        Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/PojoWithInner.class")).length);
+
+
+        boolean found = false;
+        Constructor cst = null;
+        Constructor[] csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 1  &&
+                    csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+                found = true;
+                cst = csts[i];
+            }
+        }
+        Assert.assertTrue(found);
+
+        // We still have the empty constructor
+        found = false;
+        csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 0) {
+                found = true;
+            }
+        }
+        Assert.assertTrue(found);
+
+        // Check the POJO interface
+        Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+        InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+        cst.setAccessible(true);
+        Object pojo = cst.newInstance(new Object[] {im});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+        Method method = cl.getMethod("doSomething", new Class[0]);
+        Assert.assertTrue(((Boolean) method.invoke(pojo, new Object[0])).booleanValue());
+
+    }
+
+    public void testManipulatingWithConstructorModification() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/Child.class")));
+        TestClassLoader classloader = new TestClassLoader("test.Child", clazz);
+        Class cl = classloader.findClass("test.Child");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        boolean found = false;
+        Constructor cst = null;
+        Constructor[] csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 1  &&
+                    csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+                found = true;
+                cst = csts[i];
+            }
+        }
+        Assert.assertTrue(found);
+
+        // We still have the regular constructor
+        found = false;
+        csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 2) {
+                found = true;
+            }
+        }
+        Assert.assertTrue(found);
+
+        // Check that we have the IM, Integer, String constructor too
+        Constructor cst2 = cl.getDeclaredConstructor(new Class[] { InstanceManager.class, Integer.TYPE, String.class });
+        Assert.assertNotNull(cst2);
+
+        // Check the POJO interface
+        Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+
+        // Creation using cst
+        InstanceManager im = (InstanceManager) Mockito.mock(InstanceManager.class);
+        cst.setAccessible(true);
+        Object pojo = cst.newInstance(new Object[] {im});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+        Method method = cl.getMethod("doSomething", new Class[0]);
+        Assert.assertEquals(9, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+        // Try to create using cst2
+        im = (InstanceManager) Mockito.mock(InstanceManager.class);
+        cst2.setAccessible(true);
+        pojo = cst2.newInstance(new Object[] {im, new Integer(2), "bariton"});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+        method = cl.getMethod("doSomething", new Class[0]);
+        Assert.assertEquals(10, ((Integer) method.invoke(pojo, new Object[0])).intValue());
+
+
+
+    }
+
+
+    public void testManipulatingWithNoValidConstructor() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")));
+        TestClassLoader classloader = new TestClassLoader("test.NoValidConstructor", clazz);
+        Class cl = classloader.findClass("test.NoValidConstructor");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        System.out.println(manipulator.getManipulationMetadata());
+
+        // The manipulation add stuff to the class.
+        Assert.assertTrue(clazz.length > getBytesFromFile(new File("target/test-classes/test/NoValidConstructor.class")).length);
+
+
+        boolean found = false;
+        Constructor cst = null;
+        Constructor[] csts = cl.getDeclaredConstructors();
+        for (int i = 0; i < csts.length; i++) {
+            System.out.println(Arrays.asList(csts[i].getParameterTypes()));
+            if (csts[i].getParameterTypes().length == 1  &&
+                    csts[i].getParameterTypes()[0].equals(InstanceManager.class)) {
+                found = true;
+                cst = csts[i];
+            }
+        }
+        Assert.assertTrue(found);
+
+        // Check the POJO interface
+        Assert.assertTrue(Arrays.asList(cl.getInterfaces()).contains(Pojo.class));
+
+        cst.setAccessible(true);
+        Object pojo = cst.newInstance(new Object[] {new InstanceManager()});
+        Assert.assertNotNull(pojo);
+        Assert.assertTrue(pojo instanceof Pojo);
+
+    }
+
+     public void testConstructor() throws Exception {
+        Manipulator manipulator = new Manipulator();
+        byte[] clazz = manipulator.manipulate(getBytesFromFile(new File("target/test-classes/test/ConstructorCheck.class")));
+
+//        File out = new File("target/ManipulatedConstructorCheck.class");
+//        FileOutputStream fos = new FileOutputStream(out);
+//        fos.write(clazz);
+//        fos.close();
+
+        TestClassLoader classloader = new TestClassLoader("test.ConstructorCheck", clazz);
+        Class cl = classloader.findClass("test.ConstructorCheck");
+        Assert.assertNotNull(cl);
+        Assert.assertNotNull(manipulator.getManipulationMetadata());
+
+        System.out.println(manipulator.getManipulationMetadata());
+
+        Constructor c = cl.getConstructor(new Class[] {String.class });
+        Assert.assertNotNull(c);
+
+        Object o = c.newInstance("toto");
+        Field f = o.getClass().getField("m_foo");
+        Assert.assertEquals("toto", f.get(o));
+     }
+
+    public static byte[] getBytesFromFile(File file) throws IOException {
+        InputStream is = new FileInputStream(file);
+        long length = file.length();
+        byte[] bytes = new byte[(int)length];
+
+        // Read in the bytes
+        int offset = 0;
+        int numRead = 0;
+        while (offset < bytes.length
+               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+            offset += numRead;
+        }
+
+        // Ensure all the bytes have been read in
+        if (offset < bytes.length) {
+            throw new IOException("Could not completely read file "+file.getName());
+        }
+
+        // Close the input stream and return bytes
+        is.close();
+        return bytes;
+    }
+
+    class TestClassLoader extends ClassLoader {
+
+        private String name;
+        private byte[] clazz;
+
+        public TestClassLoader(String name, byte[] clazz) {
+            this.name = name;
+            this.clazz = clazz;
+        }
+
+        public Class findClass(String name) throws ClassNotFoundException {
+            if (name.equals(this.name)) {
+                return defineClass(name, clazz, 0, clazz.length);
+            }
+            return super.findClass(name);
+        }
+
+        public Class loadClass(String arg0) throws ClassNotFoundException {
+            return super.loadClass(arg0);
+        }
+
+
+
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
new file mode 100644
index 0000000..387dfca
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulation/PojoizationTest.java
@@ -0,0 +1,46 @@
+package org.apache.felix.ipojo.manipulation;
+
+import java.io.File;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.felix.ipojo.manipulator.Pojoization;
+
+public class PojoizationTest extends TestCase {
+
+	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();
+		File metadata = new File("target/test-classes/metadata.xml");
+		pojoization.pojoization(in, out, metadata);
+
+		Assert.assertTrue(out.exists());
+	}
+
+	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();
+		pojoization.pojoization(in, out, (File) null);
+
+		Assert.assertTrue(out.exists());
+	}
+
+	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();
+		pojoization.pojoization(in, out, (File) null);
+
+		Assert.assertTrue(out.exists());
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/ManipulationEngineTestCase.java
new file mode 100644
index 0000000..b282b11
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/DirectManifestProviderTestCase.java
new file mode 100644
index 0000000..46cf8ae
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/manifest/FileManifestProviderTestCase.java
new file mode 100644
index 0000000..dc8abcc
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/AnnotationMetadataProviderTestCase.java
new file mode 100644
index 0000000..3d9e287
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CacheableMetadataProviderTestCase.java
new file mode 100644
index 0000000..5c29fb9
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/CompositeMetadataProviderTestCase.java
new file mode 100644
index 0000000..bdd8338
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/EmptyMetadataProviderTestCase.java
new file mode 100644
index 0000000..2698a67
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/FileMetadataProviderTestCase.java
new file mode 100644
index 0000000..db851c8
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/metadata/StreamMetadataProviderTestCase.java
new file mode 100644
index 0000000..9fa4f45
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/ManipulatedMetadataFilterTestCase.java
new file mode 100644
index 0000000..7f8bbf6
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/render/MetadataRendererTestCase.java
new file mode 100644
index 0000000..a9b0e2c
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/DirectoryResourceStoreTestCase.java
new file mode 100644
index 0000000..1179700
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/JarFileResourceStoreTestCase.java
new file mode 100644
index 0000000..ed74c75
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/builder/DefaultManifestBuilderTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/FileSystemResourceMapperTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/IdentityResourceMapperTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/store/mapper/WABResourceMapperTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StreamsTestCase.java
new file mode 100644
index 0000000..b3f2902
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java b/ipojo/manipulator/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/util/StringsTestCase.java
new file mode 100644
index 0000000..44c7dd4
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/check/CheckFieldConsistencyResultVisitorTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResourcesWriterTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/org/apache/felix/ipojo/manipulator/visitor/writer/ManipulatedResultWriterTestCase.java b/ipojo/manipulator/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/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/manipulator/src/test/java/test/AnnotatedComponent.java b/ipojo/manipulator/manipulator/src/test/java/test/AnnotatedComponent.java
new file mode 100644
index 0000000..186d4bb
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/java/test/Child.java b/ipojo/manipulator/manipulator/src/test/java/test/Child.java
new file mode 100644
index 0000000..1eda305
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/Child.java
@@ -0,0 +1,17 @@
+package test;
+
+public class Child extends Parent {
+
+	Child(int i, String f) {
+		super(i, f);
+	}
+
+	Child() {
+		super(5, "foo");
+	}
+
+	public int doSomething() {
+		return getIndex() + 1; // 9
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java b/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java
new file mode 100755
index 0000000..d0b24da
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/ClusterDaemon.java
@@ -0,0 +1,23 @@
+package test;
+
+import java.util.ArrayList;
+
+public class ClusterDaemon {
+
+
+    /**
+     * Controled servers url list.
+     */
+    private ArrayList ControlledServersNames;
+
+    /**
+     * Controlled servers.
+     * @return cluster daemon controlled server names.
+     * @throws ClusterDaemonException any.
+     */
+    public ArrayList getControlledServersNames() {
+        return null;
+    }
+
+
+}
\ No newline at end of file
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java b/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java
new file mode 100644
index 0000000..4492ca4
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/ConstructorCheck.java
@@ -0,0 +1,12 @@
+package test;
+
+
+public class ConstructorCheck {
+
+    public String m_foo;
+
+    public ConstructorCheck(String foo) {
+        m_foo = foo;
+    }
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java b/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java
new file mode 100644
index 0000000..45d52cb
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/NoValidConstructor.java
@@ -0,0 +1,15 @@
+package test;
+
+public class NoValidConstructor {
+
+	String m_s;
+
+	public NoValidConstructor(String s) {
+		m_s = s;
+	}
+
+	public String getS() {
+		return m_s;
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/Parent.java b/ipojo/manipulator/manipulator/src/test/java/test/Parent.java
new file mode 100644
index 0000000..51ac622
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/Parent.java
@@ -0,0 +1,15 @@
+package test;
+
+public class Parent {
+
+	private int m_index = 0;
+
+	public Parent(int i, String s) {
+		m_index = i + s.length();
+	}
+
+	public int getIndex() {
+		return m_index;
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java b/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java
new file mode 100644
index 0000000..ac5a052
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/PojoWithInner.java
@@ -0,0 +1,21 @@
+package test;
+
+public class PojoWithInner {
+
+	private MyInner m_result = new MyInner();
+
+	// This is a simple POJO
+
+	public boolean doSomething() {
+		return m_result.getInner();
+	}
+
+	public class MyInner {
+
+		public boolean getInner() {
+			return true;
+		}
+
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java b/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java
new file mode 100644
index 0000000..3c1d6fa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/java/test/SimplePojo.java
@@ -0,0 +1,13 @@
+package test;
+
+public class SimplePojo {
+
+	private boolean m_result = true;
+
+	// This is a simple POJO
+
+	public boolean doSomething() {
+		return m_result;
+	}
+
+}
diff --git a/ipojo/manipulator/manipulator/src/test/resources/MANIFEST.MF b/ipojo/manipulator/manipulator/src/test/resources/MANIFEST.MF
new file mode 100644
index 0000000..8bb4036
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/src/test/resources/empty-metadata.xml b/ipojo/manipulator/manipulator/src/test/resources/empty-metadata.xml
new file mode 100644
index 0000000..7308bd1
--- /dev/null
+++ b/ipojo/manipulator/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/manipulator/manipulator/src/test/resources/metadata.xml b/ipojo/manipulator/manipulator/src/test/resources/metadata.xml
new file mode 100644
index 0000000..b3e0262
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/metadata.xml
@@ -0,0 +1,37 @@
+<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"

+>

+	<!-- Simple provider  used for manipulation analysis -->

+	<component

+		classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

+		name="Manipulation-FooProviderType-1" architecture="true">

+		<provides />

+	</component>

+	

+	<!-- Non lazzy service provider, to check instantiation -->

+	<component

+		classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

+		name="Manipulation-ImmediateFooProviderType" immediate="true"

+		architecture="true">

+		<provides />

+	</component>

+	

+	<!-- Nested & Inner classes -->

+	<component name="inners" classname="org.apache.felix.ipojo.test.scenarios.component.InnerClasses">

+		<provides>

+			<property field="privateObject"/>

+			<property field="privateInt"/>

+			

+			<property field="protectedObject"/>

+			<property field="protectedInt"/>

+			

+			<property field="packageObject"/>

+			<property field="packageInt"/>

+			

+			<property field="publicObject"/>

+			<property field="publicInt"/>

+		</provides>

+	</component>

+</ipojo>

diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
new file mode 100644
index 0000000..a701fc0
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation-no-annotations.jar
Binary files differ
diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar
new file mode 100644
index 0000000..456e356
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulation.java5.jar
Binary files differ
diff --git a/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar
new file mode 100644
index 0000000..45322aa
--- /dev/null
+++ b/ipojo/manipulator/manipulator/src/test/resources/tests.manipulator-annotations.jar
Binary files differ