You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2009/10/07 12:24:47 UTC

svn commit: r822645 - in /incubator/aries/trunk/blueprint: ./ blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/ blueprint-core/ blueprint-core/src/main/java/org/apache/aries/blueprint/ blueprint-core/src/main/java/org/apache/aries/bl...

Author: gnodet
Date: Wed Oct  7 10:24:46 2009
New Revision: 822645

URL: http://svn.apache.org/viewvc?rev=822645&view=rev
Log:
ARIES-5: Support for multiple namespace handlers for the same schema and use a compatible one wrt class loaders

Modified:
    incubator/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java
    incubator/aries/trunk/blueprint/blueprint-core/pom.xml
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/Parser.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java
    incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java
    incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java
    incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/ParserTest.java
    incubator/aries/trunk/blueprint/pom.xml

Modified: incubator/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-cm/src/main/java/org/apache/aries/blueprint/compendium/cm/CmNamespaceHandler.java Wed Oct  7 10:24:46 2009
@@ -20,8 +20,11 @@
 
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.w3c.dom.CharacterData;
 import org.w3c.dom.Comment;
@@ -138,6 +141,15 @@
         return getClass().getResource("blueprint-cm.xsd");
     }
 
+    public Set<Class> getManagedClasses() {
+        return new HashSet<Class>(Arrays.asList(
+                CmPropertyPlaceholder.class,
+                CmManagedServiceFactory.class,
+                CmManagedProperties.class,
+                CmProperties.class
+        ));
+    }
+
     public Metadata parse(Element element, ParserContext context) {
         LOGGER.debug("Parsing element {{}}{}", element.getNamespaceURI(), element.getLocalName());
         ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry();

Modified: incubator/aries/trunk/blueprint/blueprint-core/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/pom.xml?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/pom.xml (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/pom.xml Wed Oct  7 10:24:46 2009
@@ -37,10 +37,9 @@
           <groupId>org.apache.aries.blueprint</groupId>
           <artifactId>aries-blueprint-api</artifactId>
       </dependency>
-      <!-- We should use the org.osgi:org.osgi.core:1.5 jar, but it has not been released yet -->
       <dependency>
-          <groupId>org.eclipse</groupId>
-          <artifactId>osgi</artifactId>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>org.osgi.core</artifactId>
           <scope>provided</scope>
       </dependency>
       <dependency>

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/NamespaceHandler.java Wed Oct  7 10:24:46 2009
@@ -17,6 +17,7 @@
 package org.apache.aries.blueprint;
 
 import java.net.URL;
+import java.util.Set;
 
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -27,6 +28,8 @@
 public interface NamespaceHandler  {
     
     URL getSchemaLocation(String namespace);
+
+    Set<Class> getManagedClasses();
     
     Metadata parse(Element element, ParserContext context);
     

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BeanRecipe.java Wed Oct  7 10:24:46 2009
@@ -513,7 +513,7 @@
         // call init method
         if (initMethod != null) {
             try {
-                invoke(initMethod, obj, null);
+                invoke(initMethod, obj, (Object[]) null);
             } catch (Throwable t) {
                 throw new ComponentDefinitionException("Unable to intialize bean " + getName(), getRealCause(t));
             }
@@ -529,7 +529,7 @@
         try {
             Method method = getDestroyMethod(obj);
             if (method != null) {
-                invoke(method, obj, null);
+                invoke(method, obj, (Object[]) null);
             }
         } catch (Exception e) {
             LOGGER.info("Error invoking destroy method", getRealCause(e));
@@ -544,7 +544,7 @@
         Method method = getDestroyMethod(instance);
         if (method != null) {
             try {
-                invoke(method, instance, null);
+                invoke(method, instance, (Object[]) null);
             } catch (Throwable e) {
                 LOGGER.info("Error destroying bean " + getName(), getRealCause(e));
             }
@@ -584,7 +584,7 @@
             Method getter = getPropertyDescriptor(clazz, names[i]).getGetter();
             if (getter != null) {
                 try {
-                    instance = invoke(getter, instance, null);
+                    instance = invoke(getter, instance, (Object[]) null);
                 } catch (Exception e) {
                     throw new ComponentDefinitionException("Error getting property: " + names[i] + " on bean " + getName() + " when setting property " + propertyName + " on class " + clazz.getName(), getRealCause(e));
                 }

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/BlueprintContainerImpl.java Wed Oct  7 10:24:46 2009
@@ -121,6 +121,7 @@
     private final ScheduledExecutorService executors;
     private Set<URI> namespaces;
     private State state = State.Unknown;
+    private NamespaceHandlerRegistry.NamespaceHandlerSet handlerSet;
     private boolean destroyed;
     private Parser parser;
     private BlueprintRepository repository;
@@ -231,19 +232,17 @@
                         checkDirectives();
                         eventDispatcher.blueprintEvent(new BlueprintEvent(BlueprintEvent.CREATING, getBundleContext().getBundle(), getExtenderBundle()));
                         parser = new Parser();
-                        parser.setValidation(xmlValidation);
                         parser.parse(getResources());
                         namespaces = parser.getNamespaces();
-                        if (namespaces.size() > 0) {
-                            handlers.addListener(this);
-                        }
+                        handlerSet = handlers.getNamespaceHandlers(namespaces, getBundleContext().getBundle());
+                        handlerSet.addListener(this);
                         state = State.WaitForNamespaceHandlers;
                         break;
                     case WaitForNamespaceHandlers:
                     {
                         List<String> missing = new ArrayList<String>();
                         for (URI ns : namespaces) {
-                            if (handlers.getNamespaceHandler(ns) == null) {
+                            if (handlerSet.getNamespaceHandler(ns) == null) {
                                 missing.add("(&(" + Constants.OBJECTCLASS + "=" + NamespaceHandler.class.getName() + ")(" + NamespaceHandlerRegistryImpl.NAMESPACE + "=" + ns + "))");
                             }
                         }
@@ -255,7 +254,10 @@
                         componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintBundle", bundleContext.getBundle()));
                         componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintBundleContext", bundleContext));
                         componentDefinitionRegistry.registerComponentDefinition(new PassThroughMetadataImpl("blueprintConverter", converter));
-                        parser.populate(handlers, componentDefinitionRegistry);
+                        if (xmlValidation) {
+                            parser.validate(handlerSet.getSchema());
+                        }
+                        parser.populate(handlerSet, componentDefinitionRegistry);
                         state = State.Populated;
                         break;
                     }
@@ -777,7 +779,10 @@
         if (registration != null) {
             registration.unregister();
         }
-        handlers.removeListener(this);
+        if (handlerSet != null) {
+            handlerSet.removeListener(this);
+            handlerSet.destroy();
+        }
         unregisterServices();
         untrackServiceReferences();
 

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/NamespaceHandlerRegistry.java Wed Oct  7 10:24:46 2009
@@ -25,6 +25,8 @@
 import javax.xml.validation.Schema;
 
 import org.apache.aries.blueprint.NamespaceHandler;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.xml.sax.SAXException;
 
 /**
@@ -38,42 +40,65 @@
      * Retrieve the <code>NamespaceHandler</code> for the specified URI
      *
      * @param uri the namespace identifying the namespace handler
-     * @return the registered <code>NamespaceHandler</code> or <code>null</code> if none has been registered for the given namespace
-     */
-    NamespaceHandler getNamespaceHandler(URI uri);
-
-    /**
-     * Add a new Listener to be called when namespace handlers are registerd or unregistered
+     * @param bundle the blueprint bundle to be checked for class space consistency
      *
-     * @param listener the listener to register
+     * @return a set of registered <code>NamespaceHandler</code>s compatible with the class space of the given bundle
      */
-    void addListener(Listener listener);
+    NamespaceHandlerSet getNamespaceHandlers(Set<URI> uri, Bundle bundle);
 
     /**
-     * Remove a previously registered Listener
-     *
-     * @param listener the listener to unregister
+     * Destroy this registry
      */
-    void removeListener(Listener listener);
+    void destroy();
 
     /**
-     * Obtain a schema to validate the XML for the given list of namespaces
-     *
-     * @param namespaces
-     * @return
+     * Interface used to managed a set of namespace handlers
      */
-    Schema getSchema(Set<URI> namespaces) throws SAXException, IOException;
+    public interface NamespaceHandlerSet {
 
-    /**
-     * Destroy this registry
-     */
-    void destroy();
+        Set<URI> getNamespaces();
+
+        boolean isComplete();
+
+        /**
+         * Retrieve the NamespaceHandler to use for the given namespace
+         *
+         * @return the NamespaceHandler to use or <code>null</code> if none is available at this time
+         */
+        NamespaceHandler getNamespaceHandler(URI namespace);
+
+        /**
+         * Obtain a schema to validate the XML for the given list of namespaces
+         *
+         * @return the schema to use to validate the XML
+         */
+        Schema getSchema() throws SAXException, IOException;
+
+        /**
+         * Add a new Listener to be called when namespace handlers are registerd or unregistered
+         *
+         * @param listener the listener to register
+         */
+        void addListener(Listener listener);
+
+        /**
+         * Remove a previously registered Listener
+         *
+         * @param listener the listener to unregister
+         */
+        void removeListener(Listener listener);
+
+        /**
+         * Destroy this handler set
+         */
+        void destroy();
+    }
 
     /**
      * Interface used to listen to registered or unregistered namespace handlers.
      *
-     * @see NamespaceHandlerRegistry#addListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener)
-     * @see NamespaceHandlerRegistry#removeListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener) 
+     * @see NamespaceHandlerSet#addListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener)
+     * @see NamespaceHandlerSet#removeListener(org.apache.aries.blueprint.container.NamespaceHandlerRegistry.Listener) 
      */
     public interface Listener {
 

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/Parser.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/Parser.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/Parser.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/container/Parser.java Wed Oct  7 10:24:46 2009
@@ -183,7 +183,7 @@
 
     private List<Document> documents;
     private ComponentDefinitionRegistry registry;
-    private NamespaceHandlerRegistry namespaceHandlerRegistry;
+    private NamespaceHandlerRegistry.NamespaceHandlerSet handlers;
     private String idPrefix = "component-";
     private Set<String> ids = new HashSet<String>();
     private int idCounter;
@@ -191,8 +191,6 @@
     private String defaultAvailability;
     private String defaultActivation;
     private Set<URI> namespaces;
-    private boolean validation;
-    private boolean validated;
 
     public Parser() {
     }
@@ -201,10 +199,6 @@
         this.idPrefix = idPrefix;
     }
 
-    public void setValidation(boolean validation) {
-        this.validation = validation;
-    }
-
     public void parse(List<URL> urls) throws Exception {
         List<Document> documents = new ArrayList<Document>();
         // Create document builder factory
@@ -250,28 +244,21 @@
         }
     }
 
-    public void populate(NamespaceHandlerRegistry handlers,
+    public void populate(NamespaceHandlerRegistry.NamespaceHandlerSet handlers,
                          ComponentDefinitionRegistry registry) {
-        this.namespaceHandlerRegistry = handlers;
+        this.handlers = handlers;
         this.registry = registry;
         if (this.documents == null) {
             throw new IllegalStateException("Documents should be parsed before populating the registry");
         }
-        // Validate xmls
-        if (!this.validated && validation) {
-            validate();
-            this.validated = true;
-        }
         // Parse components
         for (Document doc : this.documents) {
             loadComponents(doc);
         }
     }
 
-    private void validate() {
-        // Use a LinkedHashSet to ensure that the blueprint schema is loaded first
+    public void validate(Schema schema) {
         try {
-            Schema schema = this.namespaceHandlerRegistry.getSchema(getNamespaces());
             Validator validator = schema.newValidator();
             for (Document doc : this.documents) {
                 validator.validate(new DOMSource(doc));
@@ -1163,11 +1150,11 @@
     }
 
     private NamespaceHandler getNamespaceHandler(Node node) {
-        if (namespaceHandlerRegistry == null) {
+        if (handlers == null) {
             throw new ComponentDefinitionException("Unsupported node (namespace handler registry is not set): " + node);
         }
         URI ns = URI.create(node.getNamespaceURI());
-        NamespaceHandler handler = this.namespaceHandlerRegistry.getNamespaceHandler(ns);
+        NamespaceHandler handler = this.handlers.getNamespaceHandler(ns);
         if (handler == null) {
             throw new ComponentDefinitionException("Unsupported node namespace: " + node.getNamespaceURI());
         }

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/ext/ExtNamespaceHandler.java Wed Oct  7 10:24:46 2009
@@ -20,7 +20,10 @@
 
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.w3c.dom.Attr;
 import org.w3c.dom.CharacterData;
@@ -97,6 +100,12 @@
         return getClass().getResource("blueprint-ext.xsd");
     }
 
+    public Set<Class> getManagedClasses() {
+        return new HashSet<Class>(Arrays.asList(
+                PropertyPlaceholder.class
+        ));
+    }
+
     public Metadata parse(Element element, ParserContext context) {
         LOGGER.debug("Parsing element {{}}{}", element.getNamespaceURI(), element.getLocalName());
         if (nodeNameEquals(element, PROPERTY_PLACEHOLDER_ELEMENT)) {

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java Wed Oct  7 10:24:46 2009
@@ -18,24 +18,24 @@
  */
 package org.apache.aries.blueprint.namespace;
 
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
 import java.net.URI;
 import java.net.URL;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.AbstractMap;
-import java.util.LinkedList;
-import java.util.AbstractSet;
-import java.util.Iterator;
 import java.util.HashSet;
 import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.lang.ref.Reference;
 
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
@@ -45,6 +45,7 @@
 
 import org.apache.aries.blueprint.NamespaceHandler;
 import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.ServiceTracker;
@@ -70,18 +71,18 @@
     private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceHandlerRegistryImpl.class);
 
     private final BundleContext bundleContext;
-    private final Map<URI, NamespaceHandler> handlers;
+    private final Map<URI, Set<NamespaceHandler>> handlers;
     private final ServiceTracker tracker;
-    private final Map<Listener, Boolean> listeners;
-    private final Map<Set<URI>, Reference<Schema>> schemas = new LRUMap<Set<URI>, Reference<Schema>>(10);
+    private final Map<Map<URI, NamespaceHandler>, Reference<Schema>> schemas = new LRUMap<Map<URI, NamespaceHandler>, Reference<Schema>>(10);
     private SchemaFactory schemaFactory;
+    private List<NamespaceHandlerSetImpl> sets;
 
     public NamespaceHandlerRegistryImpl(BundleContext bundleContext) {
         this.bundleContext = bundleContext;
-        handlers = new HashMap<URI, NamespaceHandler>();
+        handlers = new HashMap<URI, Set<NamespaceHandler>>();
+        sets = new ArrayList<NamespaceHandlerSetImpl>();
         tracker = new ServiceTracker(bundleContext, NamespaceHandler.class.getName(), this);
         tracker.open();
-        listeners = new HashMap<Listener, Boolean>();
     }
 
     public Object addingService(ServiceReference reference) {
@@ -119,11 +120,15 @@
     public synchronized void registerHandler(NamespaceHandler handler, Map properties) {
         List<URI> namespaces = getNamespaces(properties);
         for (URI uri : namespaces) {
-            if (handlers.containsKey(uri)) {
-                LOGGER.warn("Ignoring NamespaceHandler for namespace {}, as another handler has already been registered for the same namespace", uri);
-            } else {
-                handlers.put(uri, handler);
-                callListeners(uri, true);
+            Set<NamespaceHandler> h = handlers.get(uri);
+            if (h == null) {
+                h = new HashSet<NamespaceHandler>();
+                handlers.put(uri, h);
+            }
+            if (h.add(handler)) {
+                for (NamespaceHandlerSetImpl s : sets) {
+                    s.registerHandler(uri, handler);
+                }
             }
         }
     }
@@ -131,27 +136,15 @@
     public synchronized void unregisterHandler(NamespaceHandler handler, Map properties) {
         List<URI> namespaces = getNamespaces(properties);
         for (URI uri : namespaces) {
-            if (handlers.get(uri) != handler) {
+            Set<NamespaceHandler> h = handlers.get(uri);
+            if (h == null || !h.remove(handler)) {
                 continue;
             }
-            handlers.remove(uri);
-            callListeners(uri, false);
-        }
-        removeSchemasFor(namespaces);
-    }
-
-    private void callListeners(URI uri, boolean registered) {
-        for (Listener listener : listeners.keySet()) {
-            try {
-                if (registered) {
-                    listener.namespaceHandlerRegistered(uri);
-                } else {
-                    listener.namespaceHandlerUnregistered(uri);
-                }
-            } catch (Throwable t) {
-                LOGGER.debug("Unexpected exception when notifying a NamespaceHandler listener", t);
+            for (NamespaceHandlerSetImpl s : sets) {
+                s.unregisterHandler(uri, handler);
             }
         }
+        removeSchemasFor(handler);
     }
 
     private static List<URI> getNamespaces(Map properties) {
@@ -200,29 +193,23 @@
         }
     }
     
-    public synchronized NamespaceHandler getNamespaceHandler(URI uri) {
-        return handlers.get(uri);
+    public synchronized NamespaceHandlerSet getNamespaceHandlers(Set<URI> uris, Bundle bundle) {
+        NamespaceHandlerSetImpl s = new NamespaceHandlerSetImpl(uris, bundle);
+        sets.add(s);
+        return s;
     }
 
     public void destroy() {
         tracker.close();
     }
 
-    public synchronized void addListener(Listener listener) {
-        listeners.put(listener, Boolean.TRUE);
-    }
-
-    public synchronized void removeListener(Listener listener) {
-        listeners.remove(listener);
-    }
-
-    public synchronized Schema getSchema(Set<URI> namespaces) throws IOException, SAXException {
+    public synchronized Schema getSchema(Map<URI, NamespaceHandler> handlers) throws IOException, SAXException {
         Schema schema = null;
         // Find a schema that can handle all the requested namespaces
         // If it contains additional namespaces, it should not be a problem since
         // they won't be used at all
-        for (Set<URI> key : schemas.keySet()) {
-            if (key.containsAll(namespaces)) {
+        for (Map<URI, NamespaceHandler> key : schemas.keySet()) {
+            if (key.equals(handlers)) {
                 schema = schemas.get(key).get();
                 break;
             }
@@ -233,24 +220,16 @@
                 schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/aries/blueprint/blueprint.xsd")));
                 // Create a schema for all namespaces known at this point
                 // It will speed things as it can be reused for all other blueprint containers
-                namespaces = new HashSet<URI>(handlers.keySet());
-                namespaces.add(BLUEPRINT_NAMESPACE);
-                for (URI ns : namespaces) {
-                    if (!BLUEPRINT_NAMESPACE.equals(ns)) {
-                        NamespaceHandler handler = getNamespaceHandler(ns);
-                        if (handler == null) {
-                            throw new IllegalArgumentException("No namespace handler has been registered for " + ns);
-                        }
-                        URL url = handler.getSchemaLocation(ns.toString());
-                        if (url == null) {
-                            LOGGER.warn("No URL is defined for schema " + ns + ". This schema will not be validated");
-                        } else {
-                            schemaSources.add(new StreamSource(url.openStream()));
-                        }
+                for (URI ns : handlers.keySet()) {
+                    URL url = handlers.get(ns).getSchemaLocation(ns.toString());
+                    if (url == null) {
+                        LOGGER.warn("No URL is defined for schema " + ns + ". This schema will not be validated");
+                    } else {
+                        schemaSources.add(new StreamSource(url.openStream()));
                     }
                 }
                 schema = getSchemaFactory().newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
-                schemas.put(namespaces, new SoftReference<Schema>(schema));
+                schemas.put(handlers, new SoftReference<Schema>(schema));
             } finally {
                 for (StreamSource s : schemaSources) {
                     try {
@@ -264,27 +243,202 @@
         return schema;
     }
 
-    protected synchronized void removeSchemasFor(List<URI> namespaces) {
-        List<Set<URI>> keys = new ArrayList<Set<URI>>();
-        for (URI ns : namespaces) {
-            for (Set<URI> key : schemas.keySet()) {
-                if (key.contains(ns)) {
-                    keys.add(key);
-                }
+    protected synchronized void removeSchemasFor(NamespaceHandler handler) {
+        List<Map<URI, NamespaceHandler>> keys = new ArrayList<Map<URI, NamespaceHandler>>();
+        for (Map<URI, NamespaceHandler> key : schemas.keySet()) {
+            if (key.values().contains(handler)) {
+                keys.add(key);
             }
         }
-        for (Set<URI> key : keys) {
+        for (Map<URI, NamespaceHandler> key : keys) {
             schemas.remove(key);
         }
     }
 
     private SchemaFactory getSchemaFactory() {
+        SchemaFactory schemaFactory = null;
         if (schemaFactory == null) {
             schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
         }
         return schemaFactory;
     }
 
+    protected class NamespaceHandlerSetImpl implements NamespaceHandlerSet {
+
+        private final Map<Listener, Boolean> listeners;
+        private final Bundle bundle;
+        private final Set<URI> namespaces;
+        private final Map<URI, NamespaceHandler> handlers;
+        private Schema schema;
+
+        public NamespaceHandlerSetImpl(Set<URI> namespaces, Bundle bundle) {
+            this.listeners = new HashMap<Listener, Boolean>();
+            this.namespaces = namespaces;
+            this.bundle = bundle;
+            handlers = new HashMap<URI, NamespaceHandler>();
+            for (URI ns : namespaces) {
+                findCompatibleNamespaceHandler(ns);
+            }
+        }
+
+        public boolean isComplete() {
+            return handlers.size() == namespaces.size();
+        }
+
+        public Set<URI> getNamespaces() {
+            return namespaces;
+        }
+
+        public NamespaceHandler getNamespaceHandler(URI namespace) {
+            return handlers.get(namespace);
+        }
+
+        public Schema getSchema() throws SAXException, IOException {
+            if (!isComplete()) {
+                throw new IllegalStateException("NamespaceHandlerSet is not complete");
+            }
+            if (schema == null) {
+                schema = NamespaceHandlerRegistryImpl.this.getSchema(handlers);
+            }
+            return schema;
+        }
+
+        public synchronized void addListener(Listener listener) {
+            listeners.put(listener, Boolean.TRUE);
+        }
+
+        public synchronized void removeListener(Listener listener) {
+            listeners.remove(listener);
+        }
+
+        public void destroy() {
+            NamespaceHandlerRegistryImpl.this.sets.remove(this);
+        }
+
+        public void registerHandler(URI uri, NamespaceHandler handler) {
+            if (namespaces.contains(uri) && handlers.get(uri) == null) {
+                if (findCompatibleNamespaceHandler(uri) !=  null) {
+                    for (Listener listener : listeners.keySet()) {
+                        try {
+                            listener.namespaceHandlerRegistered(uri);
+                        } catch (Throwable t) {
+                            LOGGER.debug("Unexpected exception when notifying a NamespaceHandler listener", t);
+                        }
+                    }
+                }
+            }
+        }
+
+        public void unregisterHandler(URI uri, NamespaceHandler handler) {
+            if (handlers.get(uri) == handler) {
+                handlers.remove(uri);
+                for (Listener listener : listeners.keySet()) {
+                    try {
+                        listener.namespaceHandlerUnregistered(uri);
+                    } catch (Throwable t) {
+                        LOGGER.debug("Unexpected exception when notifying a NamespaceHandler listener", t);
+                    }
+                }
+            }
+        }
+
+        private NamespaceHandler findCompatibleNamespaceHandler(URI ns) {
+            Set<NamespaceHandler> candidates = NamespaceHandlerRegistryImpl.this.handlers.get(ns);
+            if (candidates != null) {
+                for (NamespaceHandler h : candidates) {
+                    Set<Class> classes = h.getManagedClasses();
+                    boolean compat = true;
+                    if (classes != null) {
+                        Set<Class> allClasses = new HashSet<Class>();
+                        for (Class cl : classes) {
+                            for (Class c = cl; c != null; c = c.getSuperclass()) {
+                                allClasses.add(c);
+                                for (Class i : c.getInterfaces()) {
+                                    allClasses.add(i);
+                                }
+                            }
+                        }
+                        for (Class cl : allClasses) {
+                            Class clb;
+                            try {
+                                clb = bundle.loadClass(cl.getName());
+                                if (clb != cl) {
+                                    compat = false;
+                                    break;
+                                }
+                            } catch (ClassNotFoundException e) {
+                                // Ignore
+                            }
+                        }
+                    }
+                    if (compat) {
+                        handlers.put(ns, h);
+                        return h;
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    protected static Map<URI, NamespaceHandler> findHandlers(Map<URI, Set<NamespaceHandler>> allHandlers,
+                                                             Set<URI> namespaces,
+                                                             Bundle bundle) {
+        Map<URI, NamespaceHandler> handlers = new HashMap<URI, NamespaceHandler>();
+        Map<URI, Set<NamespaceHandler>> candidates = new HashMap<URI, Set<NamespaceHandler>>();
+        // Populate initial candidates
+        for (URI ns : namespaces) {
+            Set<NamespaceHandler> h = new HashSet<NamespaceHandler>();
+            if (allHandlers.get(ns) != null) {
+                h.addAll(allHandlers.get(ns));
+            }
+            candidates.put(ns, h);
+        }
+        // Exclude directly incompatible handlers
+        for (URI ns : namespaces) {
+            for (Iterator<NamespaceHandler> it = candidates.get(ns).iterator(); it.hasNext();) {
+                NamespaceHandler h = it.next();
+                Set<Class> classes = h.getManagedClasses();
+                boolean compat = true;
+                if (classes != null) {
+                    Set<Class> allClasses = new HashSet<Class>();
+                    for (Class cl : classes) {
+                        for (Class c = cl; c != null; c = c.getSuperclass()) {
+                            allClasses.add(c);
+                            for (Class i : c.getInterfaces()) {
+                                allClasses.add(i);
+                            }
+                        }
+                    }
+                    for (Class cl : allClasses) {
+                        Class clb;
+                        try {
+                            clb = bundle.loadClass(cl.getName());
+                        } catch (Throwable t) {
+                            clb = null;
+                        }
+                        if (clb != cl) {
+                            compat = false;
+                            break;
+                        }
+                    }
+                }
+                if (!compat) {
+                    it.remove();
+                }
+            }
+        }
+        // TODO: do we need to check if there are incompatibilities between namespaces?
+        // Pick the first ones
+        for (URI ns : namespaces) {
+            Set<NamespaceHandler> h = candidates.get(ns);
+            if (!h.isEmpty()) {
+                handlers.put(ns, h.iterator().next());
+            }
+        }
+        return handlers;
+    }
+
     public static class LRUMap<K,V> extends AbstractMap<K,V> {
 
         private final int bound;

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/AbstractBlueprintTest.java Wed Oct  7 10:24:46 2009
@@ -29,31 +29,36 @@
 import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
 import org.apache.aries.blueprint.container.Parser;
 import org.apache.aries.blueprint.namespace.ComponentDefinitionRegistryImpl;
+import org.osgi.framework.Bundle;
 import org.xml.sax.SAXException;
 
 public abstract class AbstractBlueprintTest extends TestCase {
 
     protected ComponentDefinitionRegistryImpl parse(String name) throws Exception {
-        NamespaceHandlerRegistry handlers = new NamespaceHandlerRegistry() {
-            public NamespaceHandler getNamespaceHandler(URI uri) {
+        NamespaceHandlerRegistry.NamespaceHandlerSet handlers = new NamespaceHandlerRegistry.NamespaceHandlerSet() {
+            public Set<URI> getNamespaces() {
                 return null;
             }
-            public void addCallback(Runnable runnable) {
+            public NamespaceHandler getNamespaceHandler(URI namespace) {
+                return null;
             }
-            public void destroy() {
+            public void removeListener(NamespaceHandlerRegistry.Listener listener) {
+            }
+            public Schema getSchema() throws SAXException, IOException {
+                return null;
             }
-            public void addListener(Listener listener) {
+            public boolean isComplete() {
+                return false;
             }
-            public void removeListener(Listener listener) {
+            public void addListener(NamespaceHandlerRegistry.Listener listener) {
             }
-            public Schema getSchema(Set<URI> namespaces) throws SAXException, IOException {
-                return null;
+            public void destroy() {
             }
         };
         return parse(name, handlers);
     }
 
-    protected ComponentDefinitionRegistryImpl parse(String name, NamespaceHandlerRegistry handlers) throws Exception {
+    protected ComponentDefinitionRegistryImpl parse(String name, NamespaceHandlerRegistry.NamespaceHandlerSet handlers) throws Exception {
         ComponentDefinitionRegistryImpl registry = new ComponentDefinitionRegistryImpl();
         Parser parser = new Parser();
         parser.parse(Collections.singletonList(getClass().getResource(name)));

Modified: incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/ParserTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/ParserTest.java?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/ParserTest.java (original)
+++ incubator/aries/trunk/blueprint/blueprint-core/src/test/java/org/apache/aries/blueprint/ParserTest.java Wed Oct  7 10:24:46 2009
@@ -20,6 +20,9 @@
 
 import java.net.URI;
 import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.io.IOException;
@@ -32,6 +35,7 @@
 
 import org.apache.aries.blueprint.container.NamespaceHandlerRegistry;
 import org.apache.aries.blueprint.reflect.BeanMetadataImpl;
+import org.osgi.framework.Bundle;
 import org.osgi.service.blueprint.reflect.BeanArgument;
 import org.osgi.service.blueprint.reflect.BeanMetadata;
 import org.osgi.service.blueprint.reflect.BeanProperty;
@@ -150,7 +154,7 @@
 
 
     public void testCustomNodes() throws Exception {
-        ComponentDefinitionRegistry registry = parse("/test-custom-nodes.xml", new TestNamespaceHandlerRegistry());
+        ComponentDefinitionRegistry registry = parse("/test-custom-nodes.xml", new TestNamespaceHandlerSet());
         
         ComponentMetadata metadata;
         
@@ -180,33 +184,52 @@
         assertEquals("org.apache.aries.Cache", comp3.getClassName());         
     }
 
-    private static class TestNamespaceHandlerRegistry implements NamespaceHandlerRegistry {
-        
-        public void destroy() {
+    private static class TestNamespaceHandlerSet implements NamespaceHandlerRegistry.NamespaceHandlerSet {
+
+        private TestNamespaceHandlerSet() {
         }
-        
-        public NamespaceHandler getNamespaceHandler(URI uri) {
+
+        public Set<URI> getNamespaces() {
+            return Collections.singleton(URI.create("http://cache.org"));
+        }
+
+        public boolean isComplete() {
+            return true;
+        }
+
+        public NamespaceHandler getNamespaceHandler(URI namespace) {
             URI u = URI.create("http://cache.org");
-            if (u.equals(uri)) {
+            if (u.equals(namespace)) {
                 return new TestNamespaceHandler();
             } else {
                 return null;
-            }        
+            }
         }
 
-        public void addListener(Listener listener) {
+        public Schema getSchema() throws SAXException, IOException {
+            return null;
         }
 
-        public void removeListener(Listener listener) {
+        public void addListener(NamespaceHandlerRegistry.Listener listener) {
         }
 
-        public Schema getSchema(Set<URI> namespaces) throws SAXException, IOException {
-            return null;
+        public void removeListener(NamespaceHandlerRegistry.Listener listener) {
+        }
+
+        public void destroy() {
         }
     }
-    
+
     private static class TestNamespaceHandler implements NamespaceHandler {
 
+        public URL getSchemaLocation(String namespace) {
+            return getClass().getResource("/cache.xsd");
+        }
+
+        public Set<Class> getManagedClasses() {
+            return new HashSet<Class>();
+        }
+
         public ComponentMetadata decorate(Node node,
                                           ComponentMetadata component,
                                           ParserContext context) {
@@ -227,10 +250,6 @@
             }
         }
 
-        public URL getSchemaLocation(String namespace) {
-            return getClass().getResource("/cache.xsd");
-        }
-
         public Metadata parse(Element element, ParserContext context) {
             String comp = (context.getEnclosingComponent() == null) ? null : context.getEnclosingComponent().getId();
             //System.out.println("parse: " + element.getLocalName() + " " + comp);

Modified: incubator/aries/trunk/blueprint/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/blueprint/pom.xml?rev=822645&r1=822644&r2=822645&view=diff
==============================================================================
--- incubator/aries/trunk/blueprint/pom.xml (original)
+++ incubator/aries/trunk/blueprint/pom.xml Wed Oct  7 10:24:46 2009
@@ -89,6 +89,17 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.felix</groupId>
+                <artifactId>org.osgi.core</artifactId>
+                <version>1.4.0</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.apache.felix</groupId>
+                        <artifactId>org.osgi.foundation</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.felix</groupId>
                 <artifactId>org.osgi.compendium</artifactId>
                 <version>1.2.0</version>
                 <exclusions>
@@ -199,7 +210,7 @@
                 <plugin>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>maven-bundle-plugin</artifactId>
-                    <version>2.0.0</version>
+                    <version>2.0.1</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>