Updated the metadata XML parser.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@396571 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.bundlerepository/pom.xml b/org.apache.felix.bundlerepository/pom.xml
index 18198be..9d62c0a 100644
--- a/org.apache.felix.bundlerepository/pom.xml
+++ b/org.apache.felix.bundlerepository/pom.xml
@@ -43,7 +43,7 @@
             <bundleUrl>http://oscar-osgi.sf.net/obr2/${pom.artifactId}/${pom.artifactId}-${pom.version}.jar</bundleUrl>
             <bundleSource>http://oscar-osgi.sf.net/obr2/${pom.artifactId}/${pom.artifactId}-${pom.version}-src.jar</bundleSource>
             <bundleSymbolicName>${pom.artifactId}</bundleSymbolicName>
-            <importPackage>org.osgi.framework</importPackage>
+            <importPackage>org.osgi.framework,org.xml.sax,javax.xml.parsers</importPackage>
             <dynamicImportPackage>org.apache.felix.shell</dynamicImportPackage>
             <exportPackage>org.osgi.service.obr</exportPackage>
             <exportService>org.osgi.service.obr.RepositoryAdmin</exportService>
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
index 1647cd2..2f45aad 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/CapabilityImpl.java
@@ -50,7 +50,7 @@
         return m_map;
     }
 
-    public void addP(PropertyImpl prop)
+    protected void addP(PropertyImpl prop)
     {
         m_map.put(prop.getN(), prop.getV());
     }
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
index c82b81e..c4ca31d 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/RepositoryImpl.java
@@ -17,6 +17,7 @@
 package org.apache.felix.bundlerepository;
 
 import java.io.*;
+import java.lang.reflect.Method;
 import java.net.*;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -59,7 +60,7 @@
     }
 
     // TODO: OBR - Wrong parameter type from metadata parser.
-    public void addResource(ResourceImpl resource)
+    public void addResource(Resource resource)
     {
         // Set resource's repository.
         ((ResourceImpl) resource).setRepository(this);
@@ -143,13 +144,19 @@
                         return RepositoryImpl.this;
                     }
                 };
-                handler.addType("repository", factory, Repository.class);
-                handler.addType("resource", ResourceImpl.class, Resource.class);
-                handler.addType("category", CategoryImpl.class, null);
-                handler.addType("require", RequirementImpl.class, Requirement.class);
-                handler.addType("capability", CapabilityImpl.class, Capability.class);
-                handler.addType("p", PropertyImpl.class, null);
-                handler.setDefaultType(String.class, null);
+
+                // Get default setter method for Resource.
+                Method resourceSetter = ResourceImpl.class.getDeclaredMethod(
+                    "put", new Class[] { Object.class, Object.class });
+
+                // Map XML tags to types.
+                handler.addType("repository", factory, Repository.class, null);
+                handler.addType("resource", ResourceImpl.class, Resource.class, resourceSetter);
+                handler.addType("category", CategoryImpl.class, null, null);
+                handler.addType("require", RequirementImpl.class, Requirement.class, null);
+                handler.addType("capability", CapabilityImpl.class, Capability.class, null);
+                handler.addType("p", PropertyImpl.class, null, null);
+                handler.setDefaultType(String.class, null, null);
             }
             catch (Exception ex)
             {
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
index 26ec16c..55fa422 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
@@ -23,7 +23,7 @@
 import org.osgi.framework.Version;
 import org.osgi.service.obr.*;
 
-public class ResourceImpl implements Resource, Map
+public class ResourceImpl implements Resource
 {
     private final String URI = "uri";
 
@@ -55,7 +55,7 @@
 
         if (resource != null)
         {
-            resource.putAll(resource.getProperties());
+            m_map.putAll(resource.getProperties());
             m_catList.addAll(resource.m_catList);
             m_capList.addAll(resource.m_capList);
             m_reqList.addAll(resource.m_reqList);
@@ -120,7 +120,7 @@
         return (Requirement[]) m_reqList.toArray(new Requirement[m_reqList.size()]);
     }
 
-    public void addRequire(Requirement req)
+    protected void addRequire(Requirement req)
     {
         m_reqList.add(req);
     }
@@ -130,8 +130,7 @@
         return (Capability[]) m_capList.toArray(new Capability[m_capList.size()]);
     }
 
-    // TODO: OBR - Should this be a property?
-    public void addCapability(Capability cap)
+    protected void addCapability(Capability cap)
     {
         m_capList.add(cap);
     }
@@ -141,7 +140,7 @@
         return (String[]) m_catList.toArray(new String[m_catList.size()]);
     }
 
-    public void addCategory(CategoryImpl cat)
+    protected void addCategory(CategoryImpl cat)
     {
         m_catList.add(cat.getId());
     }
@@ -156,66 +155,10 @@
         m_repo = repo;
     }
 
-    //
-    // Map interface methods.
-    //
-
-    public int size()
-    {
-        return m_map.size();
-    }
-
-    public void clear()
-    {
-        m_map.clear();
-    }
-
-    public boolean isEmpty()
-    {
-        return m_map.isEmpty();
-    }
-
-    public boolean containsKey(Object key)
-    {
-        return m_map.containsKey(key);
-    }
-
-    public boolean containsValue(Object value)
-    {
-        return m_map.containsValue(value);
-    }
-
-    public Collection values()
-    {
-        return m_map.values();
-    }
-
-    public void putAll(Map t)
-    {
-        m_map.putAll(t);
-    }
-
-    public Set entrySet()
-    {
-        return m_map.entrySet();
-    }
-
-    public Set keySet()
-    {
-        return m_map.keySet();
-    }
-
-    public Object get(Object key)
-    {
-        return m_map.get(key);
-    }
-
-    public Object remove(Object key)
-    {
-        return m_map.remove(key);
-    }
-
-    public Object put(Object key, Object value)
+    /**
+     * Default setter method when setting parsed data from the XML file. 
+    **/
+    protected Object put(Object key, Object value)
     {
         // Capture the URIs since they might be relative, so we
         // need to defer setting the actual URL value until they
@@ -247,22 +190,6 @@
             {
                 value = Long.valueOf(value.toString());
             }
-            // TODO: OBR - These should be handled by the "add" methods above.
-            else if (key.equals("require"))
-            {
-                m_reqList.add(value);
-                return null;
-            }
-            else if (key.equals("capability"))
-            {
-                m_capList.add(value);
-                return null;
-            }
-            else if (key.equals("category"))
-            {
-                m_catList.add(value);
-                return null;
-            }
     
             return m_map.put(key, value);
         }
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/KXml2MetadataHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/KXml2MetadataHandler.java
index ac2103a..16b909d 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/KXml2MetadataHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/KXml2MetadataHandler.java
@@ -23,8 +23,6 @@
 /**
  * handles the metadata in XML format
  * (use kXML (http://kxml.enhydra.org/) a open-source very light weight XML parser
- * @version 	1.00 11 Nov 2003
- * @author 	Didier Donsez
  */
 public class KXml2MetadataHandler extends MetadataHandler {
 
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MappingProcessingInstructionHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MappingProcessingInstructionHandler.java
index 51a019c..7f0963e 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MappingProcessingInstructionHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MappingProcessingInstructionHandler.java
@@ -19,8 +19,6 @@
 
 /**
  * this class adds type of elements to the parser
- *
- * @author Didier Donsez (didier.donsez@imag.fr)
  */
 public class MappingProcessingInstructionHandler {
 
@@ -39,7 +37,7 @@
 		if(classname==null) {
 			throw new Exception("class is missing");
 		}
-		handler.addType(name,this.getClass().getClassLoader().loadClass(classname),null);
+		handler.addType(name,this.getClass().getClassLoader().loadClass(classname),null,null);
 	}
 
 	public void setElement(String element) {
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MetadataHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MetadataHandler.java
index 3fc299a..53fccb1 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MetadataHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/MetadataHandler.java
@@ -17,16 +17,16 @@
 package org.apache.felix.bundlerepository.metadataparser;
 
 import java.io.InputStream;
+import java.lang.reflect.Method;
 
-
-/**
- * @version 	1.00 9 Jul 2004
- * @author 	Didier Donsez
- */
 public abstract class MetadataHandler {
 
 	protected XmlCommonHandler handler;
 
+	/**
+	 * constructor 
+	 *
+	 */
 	public MetadataHandler() {
 		handler = new XmlCommonHandler();
 	}
@@ -37,29 +37,80 @@
 	public abstract void parse(InputStream is) throws Exception;
 
 	/**
-	 * return the metadata
-	 * @return a Objet
+	 * return the metadata after the parsing
+	 * @return a Object. Its class is the returned type of instanceFactory newInstance method for the root element of the XML document.
 	 */
 	public final Object getMetadata() {
 		return handler.getRoot();
 	}
-
+	/**
+	 * Add a type for a element
+	 * @param qname the name of the element to process
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @throws Exception
+	 */
 	public final void addType(String qname, Object instanceFactory) throws Exception {
-		handler.addType(qname, instanceFactory, null);
+		handler.addType(qname, instanceFactory, null, null);
 	}
 
+	/**
+	 * Add a type for a element
+	 * @param qname the name of the element to process
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @param castClass the class used to introspect the adder/setter and parameters in parent adder/setter. if null the castClass is by default the class returned by the newInstance method of the instanceFactory.
+	 * @throws Exception
+	 */
 	public final void addType(String qname, Object instanceFactory, Class castClass) throws Exception {
-		handler.addType(qname, instanceFactory, castClass);
+		handler.addType(qname, instanceFactory, castClass, null);
+	}
+
+	/**
+	 * Add a type for a element
+	 * @param qname the name of the element to process
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @param castClass the class used to introspect the adder/setter and parameters in parent adder/setter. if null the castClass is by default the class returned by the newInstance method of the instanceFactory.
+	 * @param defaultAddMethod the method used to add the sub-elements and attributes if no adder/setter is founded. could be omitted.
+	 * @throws Exception
+	 */
+	public final void addType(String qname, Object instanceFactory, Class castClass, Method defaultAddMethod) throws Exception {
+		handler.addType(qname, instanceFactory, castClass, defaultAddMethod);
 	}
 	
+	/**
+	 * Add a type for the default element
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @throws Exception
+	 */
 	public final void setDefaultType(Object instanceFactory) throws Exception {
-		handler.setDefaultType(instanceFactory,null);
+		handler.setDefaultType(instanceFactory,null,null);
 	}
 
+	/**
+	 * Add a type for the default element
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @param castClass the class used to introspect the adder/setter and parameters in parent adder/setter. if null the castClass is by default the class returned by the newInstance method of the instanceFactory.
+	 * @throws Exception
+	 */
 	public final void setDefaultType(Object instanceFactory, Class castClass) throws Exception {
-		handler.setDefaultType(instanceFactory, castClass);
+		handler.setDefaultType(instanceFactory, castClass,null);
 	}
 
+	/**
+	 * Add a type for the default element
+	 * @param instanceFactory the factory of objects representing an element. Must have a newInstance method. could be a class.
+	 * @param castClass the class used to introspect the adder/setter and parameters in parent adder/setter. if null the castClass is by default the class returned by the newInstance method of the instanceFactory.
+	 * @param defaultAddMethod the method used to add the sub-elements and attributes if no adder/setter is founded. could be omitted.
+	 * @throws Exception
+	 */
+	public final void setDefaultType(Object instanceFactory, Class castClass, Method defaultAddMethod) throws Exception {
+		handler.setDefaultType(instanceFactory,castClass,defaultAddMethod);
+	}
+
+	/**
+	 * Add a type to process the processing instruction
+	 * @param piname
+	 * @param clazz
+	 */
 	public final void addPI(String piname, Class clazz) {
 		handler.addPI(piname, clazz);
 	}
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlCommonHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlCommonHandler.java
index 0dc6dc1..639eac3 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlCommonHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlCommonHandler.java
@@ -26,8 +26,6 @@
 
 /**
  * SAX handler for the XML file
- * 
- * @author Didier Donsez (didier.donsez@imag.fr)
  */
 public class XmlCommonHandler implements KXml2SAXHandler {
 
@@ -35,7 +33,7 @@
 
 	public static final String METADATAPARSER_PIS = "METADATAPARSER_PIS";
 
-	public static final String METADATAPARSER_INSTANCEFACTORY = "METADATAPARSER_INSTANCEFACTORY";
+	public static final String METADATAPARSER_TYPES = "METADATAPARSER_TYPES";
 
 	private int columnNumber;
 
@@ -49,43 +47,116 @@
 	// Data
 	//
 
-	private Object root;
+	private XmlStackElement root;
 
-	private Stack objectStack;
-
-	private Stack qnameStack;
-
+	private Stack elementStack;
+	
 	private Map pis;
 
 	private boolean missingPIExceptionFlag;
 
-	private Map instanceFactories;
+	private Map types;
 
-	private Map instanceClasses;
-
-	private Map castClasses;
-
-	private Map context;
-
-	private Object defaultInstanceFactory;
-
-	private Class defaultInstanceClass;
-
-	private Class defaultCastClass;
+	private TypeEntry defaultType;
 
 	private StringBuffer currentText;
 
+	private Map context;
+
+	private class XmlStackElement {
+		
+		public final String qname;
+		public Object object;
+		
+		public XmlStackElement(String qname, Object object) {
+			super();
+			this.qname = qname;
+			this.object = object;
+		};
+	}
+
+	public class TypeEntry {
+		public final Object instanceFactory;
+		public final Class instanceClass;
+		public final Method newInstanceMethod;
+		public final Class castClass;
+		public final Method defaultAddMethod;
+		
+		public TypeEntry(Object instanceFactory, Class castClass, Method defaultAddMethod) throws Exception {
+			super();
+			this.instanceFactory = instanceFactory;
+						
+			try {
+				if (instanceFactory instanceof Class) {
+					newInstanceMethod = instanceFactory.getClass()
+						.getDeclaredMethod("newInstance", null);
+					if (castClass == null) {
+						this.castClass = (Class) instanceFactory;
+					} else {
+						if (!castClass.isAssignableFrom((Class) instanceFactory)) {
+							throw new Exception(
+											"instanceFactory "
+											+ instanceFactory.getClass().getName()
+											+ " could not instanciate objects assignable to "
+											+ castClass.getName());
+						}
+						this.castClass=castClass;
+					}
+					instanceClass = (Class) instanceFactory;
+				} else {
+					newInstanceMethod = instanceFactory.getClass()
+						.getDeclaredMethod("newInstance", null);
+					Class returnType = newInstanceMethod.getReturnType();
+					if (castClass == null) {
+						this.castClass = returnType;
+					} else if (!castClass.isAssignableFrom(returnType)) {
+						throw new Exception(
+								"instanceFactory "
+								+ instanceFactory.getClass().getName()
+								+ " could not instanciate objects assignable to "
+								+ castClass.getName());
+					} else 
+						this.castClass=castClass;
+					instanceClass = returnType;
+				}
+			} catch (NoSuchMethodException e) {
+				throw new Exception(
+						"instanceFactory " + instanceFactory.getClass().getName()
+						+ " should have a newInstance method");
+			}
+			
+			// TODO check method
+			this.defaultAddMethod = defaultAddMethod;
+            if (this.defaultAddMethod != null)
+            {
+                this.defaultAddMethod.setAccessible(true);
+            }
+		}
+		
+		public String toString(){
+			StringBuffer sb=new StringBuffer();
+			sb.append("[");
+			if(instanceFactory instanceof Class)
+				sb.append("instanceFactory=").append(((Class)instanceFactory).getName());
+			else
+				sb.append("instanceFactory=").append(instanceFactory.getClass().getName());
+			sb.append(",instanceClass=").append(instanceClass.getName());
+			sb.append(",castClass=").append(castClass.getName());
+			sb.append(",defaultAddMethod=");
+			if(defaultAddMethod==null) sb.append(""); else sb.append(defaultAddMethod.getName());
+			sb.append("]");
+			return sb.toString();
+		}
+	}
+	
 	public XmlCommonHandler() {
-		objectStack = new Stack();
-		qnameStack = new Stack();
+		elementStack = new Stack();
 		pis = new HashMap();
 		missingPIExceptionFlag = false;
-		instanceFactories = new HashMap();
-		instanceClasses = new HashMap();
-		castClasses = new HashMap();
+		types = new HashMap();
 		context = new HashMap();
 		context.put(METADATAPARSER_PIS, pis);
-		context.put(METADATAPARSER_INSTANCEFACTORY, instanceFactories);
+		context.put(METADATAPARSER_TYPES, types);
 	}
 
 	public void addPI(String piname, Class clazz) {
@@ -102,79 +173,41 @@
 	public void setMissingPIExceptionFlag(boolean flag) {
 		missingPIExceptionFlag = flag;
 	}
+	
+	public void addType(String qname, Object instanceFactory, Class castClass, Method defaultAddMethod)
+	throws Exception {
 
-	private Class checkAndGetInstanceClass(String qname,
-			Object instanceFactory, Class castClass) throws Exception {
-		String typeMsg = (qname == null) ? " for default type "
-				: (" for type " + qname);
+		TypeEntry typeEntry;
 		try {
-			if (instanceFactory instanceof Class) {
-				if (castClass == null) {
-					castClass = (Class) instanceFactory;
-				} else {
-					if (!castClass.isAssignableFrom((Class) instanceFactory)) {
-						throw new Exception(
-								lineNumber
-										+ ","
-										+ columnNumber
-										+ ":"
-										+ "instanceFactory "
-										+ instanceFactory.getClass().getName()
-										+ typeMsg
-										+ " could not instanciate objects assignable to "
-										+ castClass.getName());
-					}
-				}
-				return (Class) instanceFactory;
-			} else {
-				Method newInstanceMethod = instanceFactory.getClass()
-						.getDeclaredMethod("newInstance", null);
-				Class returnType = newInstanceMethod.getReturnType();
-				if (castClass == null) {
-					castClass = returnType;
-				} else if (!castClass.isAssignableFrom(returnType)) {
-					throw new Exception(lineNumber + "," + columnNumber + ":"
-							+ "instanceFactory "
-							+ instanceFactory.getClass().getName() + typeMsg
-							+ " could not instanciate objects assignable to "
-							+ castClass.getName());
-				}
-				return returnType;
-			}
-		} catch (NoSuchMethodException e) {
-			throw new Exception(lineNumber + "," + columnNumber + ":"
-					+ "instanceFactory " + instanceFactory.getClass().getName()
-					+ " for type " + qname
-					+ " should have a newInstance method");
+			typeEntry = new TypeEntry(
+					instanceFactory,
+					castClass,
+					defaultAddMethod
+				);
+		} catch (Exception e) {
+			throw new Exception(lineNumber + "," + columnNumber + ":" + qname + " : " + e.getMessage());
 		}
-	}
-
-	public void addType(String qname, Object instanceFactory, Class castClass)
-			throws Exception {
-		Class instanceClass = checkAndGetInstanceClass(qname, instanceFactory,
-				castClass);
-		instanceClasses.put(qname, instanceClass);
-		instanceFactories.put(qname, instanceFactory);
-		castClasses.put(qname, castClass != null ? castClass : instanceClass);
+		types.put(qname,typeEntry);		
 		trace("element "
 				+ qname
-				+ " : instanceFactory="
-				+ (instanceFactory instanceof Class ? ((Class) instanceFactory)
-						.getName() : instanceFactory.getClass().getName())
-				+ " castClass="
-				+ (castClass != null ? castClass : instanceClass).getName());
+				+ " : " + typeEntry.toString());
 	}
-
-	public void setDefaultType(Object instanceFactory, Class castClass)
+		
+	public void setDefaultType(Object instanceFactory, Class castClass, Method defaultAddMethod)
 			throws Exception {
-		defaultInstanceClass = checkAndGetInstanceClass(null, instanceFactory,
-				castClass);
-		defaultInstanceFactory = instanceFactory;
-		defaultCastClass = castClass != null ? castClass : defaultInstanceClass;
-		trace("defaut type : instanceFactory="
-				+ (instanceFactory instanceof Class ? ((Class) instanceFactory)
-						.getName() : instanceFactory.getClass().getName())
-				+ " castClass=" + defaultCastClass.getName());
+		TypeEntry typeEntry;
+		try {
+			typeEntry = new TypeEntry(
+					instanceFactory,
+					castClass,
+					defaultAddMethod
+				);
+		} catch (Exception e) {
+			throw new Exception(lineNumber + "," + columnNumber + ": default element : " + e.getMessage());
+		}
+		defaultType=typeEntry;		
+		trace("default element "
+				+ " : " + typeEntry.toString());
 	}
 
 	public void setContext(Map context) {
@@ -186,7 +219,7 @@
 	}
 
 	public Object getRoot() {
-		return root;
+		return root.object;
 	}
 
 	/* for PCDATA */
@@ -224,7 +257,7 @@
 		Method method = null;
 		try {
 			// TODO setContext from castClass or object.getClass() ?
-			method = object.getClass().getMethod("setContext",
+			method = object.getClass().getDeclaredMethod("setContext",
 					new Class[] { Map.class });
 		} catch (NoSuchMethodException e) {
 			// do nothing
@@ -249,7 +282,7 @@
 		Method method = null;
 		try {
 			// TODO process from castClass or object.getClass() ?
-			method = object.getClass().getMethod("process", null);
+			method = object.getClass().getDeclaredMethod("process", null);
 		} catch (NoSuchMethodException e) {
 			// do nothing
 		}
@@ -274,7 +307,7 @@
 		Method method = null;
 		try {
 			// TODO setParent from castClass or object.getClass() ?
-			method = object.getClass().getMethod("setParent",
+			method = object.getClass().getDeclaredMethod("setParent",
 					new Class[] { parent.getClass() });
 		} catch (NoSuchMethodException e) {
 			// do nothing
@@ -306,53 +339,26 @@
 				+ qName);
 
 		// TODO: should add uri in the qname in the future
-		Object instanceFactory = instanceFactories.get(qName); // instanceFactory
-		// can be a
-		// java.lang.Class
-		// or a object
-		// with a
-		// newInstance()
-		// method
-		Class castClass = null;
-		Class instanceClass = null;
-
-		if (instanceFactory == null) {
-			if (defaultInstanceFactory != null) {
-				instanceFactory = defaultInstanceFactory;
-				castClass = defaultCastClass;
-				instanceClass = defaultInstanceClass;
-			}
-		} else {
-			castClass = (Class) castClasses.get(qName);
-			instanceClass = (Class) instanceClasses.get(qName);
+		TypeEntry type=(TypeEntry) types.get(qName);
+		if(type==null) {
+			type=defaultType;
 		}
 
 		Object obj = null;
-		if (instanceFactory != null) {
-			Method newInstanceMethod = null;
-			try {
-				newInstanceMethod = instanceFactory.getClass().getMethod(
-						"newInstance", null);
-			} catch (NoSuchMethodException e) {
-				// never catch since checked by addType and setDefaultType
-				throw new Exception(lineNumber + "," + columnNumber + ":"
-						+ "instanceFactory "
-						+ instanceFactory.getClass().getName()
-						+ " for element " + qName
-						+ " should have a newInstance method");
-			}
+		if (type != null) {
 
 			try {
-                newInstanceMethod.setAccessible(true);
-				obj = newInstanceMethod.invoke(instanceFactory, null);
+				// enables to access to "unmuttable" method
+				type.newInstanceMethod.setAccessible(true);
+				obj = type.newInstanceMethod.invoke(type.instanceFactory, null);
 			} catch (Exception e) {
 				// do nothing
 			}
 
 			// set parent
-			if (!objectStack.isEmpty()) {
-				Object parent = objectStack.peek();
-				setObjectParent(obj, parent);
+			if (!elementStack.isEmpty()) {
+				XmlStackElement parent = (XmlStackElement) elementStack.peek();
+				setObjectParent(obj, parent.object);
 			}
 
 			// set the parser context
@@ -374,16 +380,16 @@
 				Method method = null;
 				if (!(obj instanceof String)) {
 					try {
-						// method = castClass.getMethod(setterOf(key),new
+						// method = castClass.getDeclaredMethod(setterOf(key),new
 						// Class[] { String.class });
-						method = instanceClass.getMethod(setterOf(key),
+						method = type.instanceClass.getDeclaredMethod(setterOf(key),
 								new Class[] { String.class });
 					} catch (NoSuchMethodException e) {
 						// do nothing
 					}
 					if (method == null)
 						try {
-							method = instanceClass.getMethod(adderOf(key),
+							method = type.instanceClass.getDeclaredMethod(adderOf(key),
 									new Class[] { String.class });
 
 						} catch (NoSuchMethodException e) {
@@ -395,6 +401,7 @@
 						}
 
 				}
+				
 				if (method != null) {
 					trace(method.getName());
 					try {
@@ -404,19 +411,9 @@
 						throw e;
 					}
 				} else {
-					// Secondly, test if object if a map, a dictionary, a
-					// collection, or a string
-
-					if (obj instanceof Map) {
-						((Map) obj).put(key, value);
-					} else if (obj instanceof Dictionary) {
-						((Dictionary) obj).put(key, value);
-					} else if (obj instanceof Collection) {
-						throw new Exception(lineNumber + "," + columnNumber
-								+ ":" + "List element " + qName
-								+ " cannot have any attribute");
-					} else if (obj instanceof String) {
-						if (key.equals("value")) {
+					
+					if (obj instanceof String) {
+						if (key.equals(VALUE)) {
 							obj = value;
 						} else {
 							throw new Exception(lineNumber + "," + columnNumber
@@ -424,12 +421,32 @@
 									+ " cannot have other attribute than value");
 						}
 					} else {
-						throw new Exception(lineNumber + "," + columnNumber
+						if (type.defaultAddMethod != null) {
+							Class[] parameterTypes=type.defaultAddMethod.getParameterTypes();
+							if(parameterTypes.length==2
+								&& parameterTypes[0].isAssignableFrom(String.class)
+								&& parameterTypes[1].isAssignableFrom(String.class)
+							){
+								type.defaultAddMethod.invoke(obj,new String[]{key, value});
+							} else if(parameterTypes.length==1
+										&& parameterTypes[0].isAssignableFrom(String.class)
+									){
+										type.defaultAddMethod.invoke(obj,new String[]{value});
+							} else 
+								throw new Exception(lineNumber + "," + columnNumber
+										+ ":" + "class "
+										+ type.instanceFactory.getClass().getName()
+										+ " for element " + qName
+										+ " does not support the attribute " + key
+										);							
+						} else {
+							throw new Exception(lineNumber + "," + columnNumber
 								+ ":" + "class "
-								+ instanceFactory.getClass().getName()
+								+ type.instanceFactory.getClass().getName()
 								+ " for element " + qName
 								+ " does not support the attribute " + key
-								+ "or List.add or Map.put");
+								);
+						}
 
 					}
 				}
@@ -440,11 +457,10 @@
 			throw new Exception(lineNumber + "," + columnNumber + ":"
 					+ "this element " + qName + " has not corresponding class");
 		}
-
+		XmlStackElement element=new XmlStackElement(qName,obj);
 		if (root == null)
-			root = obj;
-		objectStack.push(obj);
-		qnameStack.push(qName);
+			root = element;
+		elementStack.push(element);
 		currentText = new StringBuffer();
 
 		trace("START/ (" + lineNumber + "," + columnNumber + "):" + uri + ":"
@@ -465,9 +481,12 @@
 		trace("END (" + lineNumber + "," + columnNumber + "):" + uri + ":"
 				+ qName);
 
-		Object obj = objectStack.pop();
-		Class objClass = obj.getClass();
-
+		XmlStackElement element = (XmlStackElement) elementStack.pop();
+		TypeEntry elementType=(TypeEntry) types.get(element.qname);
+		if(elementType==null) {
+			elementType=defaultType;
+		}		
+		
 		if (currentText != null && currentText.length() != 0) {
 
 			String currentStr = ReplaceUtility.replace(currentText.toString(),
@@ -477,11 +496,11 @@
 
 			Method method = null;
 			try {
-				method = objClass.getMethod("addText",
+				method = elementType.castClass.getDeclaredMethod("addText",
 						new Class[] { String.class });
 			} catch (NoSuchMethodException e) {
 				try {
-					method = objClass.getMethod("setText",
+					method = elementType.castClass.getDeclaredMethod("setText",
 							new Class[] { String.class });
 				} catch (NoSuchMethodException e2) {
 					// do nothing
@@ -490,21 +509,14 @@
 			if (method != null) {
 				trace(method.getName());
 				try {
-					method.invoke(obj, new String[] { currentStr });
+					method.invoke(element.object, new String[] { currentStr });
 				} catch (InvocationTargetException e) {
 					e.getTargetException().printStackTrace(System.err);
 					throw e;
 				}
 			} else {
-				if (Map.class.isAssignableFrom(objClass)) {
-					((Map) obj).put(qName, currentStr);
-				} else if (Dictionary.class.isAssignableFrom(objClass)) {
-					((Dictionary) obj).put(qName, currentStr);
-				} else if (Collection.class.isAssignableFrom(objClass)) {
-					throw new Exception(lineNumber + "," + columnNumber + ":"
-							+ "List element " + qName + " cannot have PCDATAs");
-				} else if (String.class.isAssignableFrom(objClass)) {
-					String str = (String) obj;
+				if (String.class.isAssignableFrom(elementType.castClass)) {
+					String str = (String) element.object;
 					if (str.length() != 0) {
 						throw new Exception(
 								lineNumber
@@ -515,7 +527,7 @@
 										+ qName
 										+ " cannot have both PCDATA and an attribute value");
 					} else {
-						obj = currentStr;
+						element.object = currentStr;
 					}
 				}
 			}
@@ -524,69 +536,87 @@
 
 		currentText = null;
 
-		if (!objectStack.isEmpty()) {
+		if (!elementStack.isEmpty()) {
 
-			Object parent = objectStack.peek();
-			String parentName = (String) qnameStack.peek();
-			// TODO Class parentClass = (castClasses(parentName)).getClass() ????
-			Class parentClass = parent.getClass();
+			XmlStackElement parent = (XmlStackElement) elementStack.peek();
+			TypeEntry parentType = (TypeEntry) types.get(parent.qname);
+			if(parentType==null) {
+				parentType=defaultType;
+			}		
 
+			String capqName=ClassUtility.capitalize(qName);
 			Method method = null;
 			try {
-				method = parentClass.getMethod(adderOf(ClassUtility
-						.capitalize(qName)), new Class[] { objClass });  // instanceClass
+// TODO: OBR PARSER: We should also check for instance class as a parameter.
+				method = parentType.instanceClass.getDeclaredMethod(
+						adderOf(capqName),
+						new Class[] { elementType.castClass });  // instanceClass
 			} catch (NoSuchMethodException e) {
 				trace("NoSuchMethodException: "
-						+ adderOf(ClassUtility.capitalize(qName)));
+						+ adderOf(capqName) + "("+elementType.castClass.getName()+")");
 				// do nothing
 			}
 			if (method == null)
-				try {
-					method = parent.getClass().getMethod(
-							setterOf(ClassUtility.capitalize(qName)),
-							new Class[] { objClass });
+                try {
+					method = parentType.instanceClass.getDeclaredMethod(
+						setterOf(capqName),
+						new Class[] { elementType.castClass });
 				} catch (NoSuchMethodException e) {
 					trace("NoSuchMethodException: "
-							+ setterOf(ClassUtility.capitalize(qName)));
+							+ setterOf(capqName) + "("+elementType.castClass.getName()+")");
+					// do nothing
+				}
+			/*if (method == null)
+				try {
+					method = parentType.castClass.getDeclaredMethod(
+							adderOf(type.castClass),
+							new Class[] { type.castClass });
+				} catch (NoSuchMethodException e) {
+					trace("NoSuchMethodException: " + adderOf(type.castClass)+ "("+type.castClass.getName()+")");
 					// do nothing
 				}
 			if (method == null)
 				try {
-					method = parent.getClass().getMethod(adderOf(objClass),
-							new Class[] { objClass });
+					method = parentType.castClass.getDeclaredMethod(
+							setterOf(type.castClass),
+							new Class[] { type.castClass });
 				} catch (NoSuchMethodException e) {
-					trace("NoSuchMethodException: " + adderOf(objClass));
+					trace("NoSuchMethodException: " + setterOf(type.castClass)+ "("+type.castClass.getName()+")");
 					// do nothing
 				}
-			if (method == null)
-				try {
-					method = parent.getClass().getMethod(setterOf(objClass),
-							new Class[] { objClass });
-				} catch (NoSuchMethodException e) {
-					trace("NoSuchMethodException: " + setterOf(objClass));
-					// do nothing
-				}
-
+				*/
 			if (method != null) {
 				trace(method.getName());
 				try {
-					method.invoke(parent, new Object[] { obj });
+                    method.setAccessible(true);
+					method.invoke(parent.object, new Object[] { element.object });
 				} catch (InvocationTargetException e) {
 					e.getTargetException().printStackTrace(System.err);
 					throw e;
 				}
 			} else {
-				if (Map.class.isAssignableFrom(parentClass)) {
-					((Map) parent).put(qName, obj);
-				} else if (Dictionary.class.isAssignableFrom(parentClass)) {
-					((Dictionary) parent).put(qName, obj);
-				} else if (Collection.class.isAssignableFrom(parentClass)) {
-					((Collection) parent).add(obj);
+				if (parentType.defaultAddMethod != null) {
+					Class[] parameterTypes=parentType.defaultAddMethod.getParameterTypes();
+					if(parameterTypes.length==2
+						&& parameterTypes[0].isAssignableFrom(String.class)
+						&& parameterTypes[1].isAssignableFrom(elementType.castClass)
+					){
+						parentType.defaultAddMethod.invoke(parent.object,new Object[]{qName, element.object});
+					} else 	if(parameterTypes.length==1
+							&& parameterTypes[0].isAssignableFrom(elementType.castClass)
+						){
+							parentType.defaultAddMethod.invoke(parent.object,new Object[]{element.object});
+					} else {
+						throw new Exception(lineNumber + "," + columnNumber + ":"
+								+ " element " + parent.qname
+								+ " cannot have an attribute " + qName
+								+ " of type " + elementType.castClass);						
+					}
 				} else {
 					throw new Exception(lineNumber + "," + columnNumber + ":"
-							+ " element " + parentName
+							+ " element " + parent.qname
 							+ " cannot have an attribute " + qName
-							+ " of type " + objClass);
+							+ " of type " + elementType.castClass);
 				}
 			}
 
@@ -594,7 +624,7 @@
 
 		// invoke the process method
 		try {
-			invokeProcess(obj);
+			invokeProcess(element);
 		} catch (Throwable e) {
 			e.printStackTrace();
 			throw new Exception(e);
@@ -704,7 +734,7 @@
 					context);
 			Method method = null;
 			try {
-				method = clazz.getMethod(setterOf(key),
+				method = clazz.getDeclaredMethod(setterOf(key),
 						new Class[] { String.class });
 			} catch (NoSuchMethodException e) {
 				// do nothing
@@ -762,7 +792,10 @@
 						+ " cannot found class " + classname
 						+ " for \"mapping\" PI");
 			}
-			setDefaultType(clazz, null);
+
+			//			 TODO Add method
+			Method defaultdefaultAddMethod=null;
+			setDefaultType(clazz, null,defaultdefaultAddMethod);
 			return;
 		}
 
@@ -824,6 +857,9 @@
 						+ " for \"mapping\" PI");
 			}
 
-		addType(element, clazz, castClazz);
+		// TODO Add method
+		Method defaultAddMethod=null;
+			
+		addType(element, clazz, castClazz, defaultAddMethod);
 	}
 }
\ No newline at end of file
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlMetadataHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlMetadataHandler.java
index aef14de..bab5b94 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlMetadataHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/XmlMetadataHandler.java
@@ -25,9 +25,6 @@
 
 /**
  * handles the metadata in XML format
- *
- * @version 1.00 18 May 2003
- * @author 	Didier Donsez
  */
 public class XmlMetadataHandler extends MetadataHandler {
 
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXHandler.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXHandler.java
index 0014c51..2ba350c 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXHandler.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXHandler.java
@@ -20,8 +20,6 @@
 
 /**
  * Interface for SAX handler with kXML
- *
- * @author Didier Donsez (didier.donsez@imag.fr)
  */
 public interface KXml2SAXHandler {
 
diff --git a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXParser.java b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXParser.java
index 3bc3b83..907a65e 100644
--- a/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXParser.java
+++ b/org.apache.felix.bundlerepository/src/main/java/org/apache/felix/bundlerepository/metadataparser/kxmlsax/KXml2SAXParser.java
@@ -24,19 +24,12 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 /**
- * The KXml2SAXParser extends the XmlParser from kxml. This is a very
- * simple parser that does not take into account the DTD
- *
- * @version 	1.0 08 Nov 2002
- * @version 	1.1 24 Apr 2004
- * @author 	Humberto Cervantes, Didier Donsez
+ * The KXml2SAXParser extends the XmlParser from kxml2 (which  does not take into account the DTD).
  */
 public class KXml2SAXParser extends KXmlParser {
 	
 	public String uri="uri";
 
-	private Reader reader;
-	
 	/**
 	* The constructor for a parser, it receives a java.io.Reader.
 	*
@@ -45,15 +38,14 @@
 	*/
 	public KXml2SAXParser(Reader reader) throws XmlPullParserException {
 		super();
-		this.reader=reader;
 	    setInput(reader);
 	}
 	
 	/**
-	* Parser from the reader provided in the constructor, and call
-	* the startElement and endElement in a KxmlHandler
+	* parse from the reader provided in the constructor, and call
+	* the startElement and endElement in the handler
 	*
-	* @param   reader  The reader
+	* @param   handler  The handler
 	* @exception   Exception thrown by the superclass
 	*/
 	public void parseXML(KXml2SAXHandler handler) throws Exception {