Author: gnodet Date: Tue Aug 28 12:55:03 2012 New Revision: 1378113 URL: http://svn.apache.org/viewvc?rev=1378113&view=rev Log: [ARIES-899] Another peek at improving concurrency on the namespace handler registry
Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java Modified: aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java URL: http://svn.apache.org/viewvc/aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java?rev=1378113&r1=1378112&r2=1378113&view=diff ============================================================================== --- aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java (original) +++ aries/trunk/blueprint/blueprint-core/src/main/java/org/apache/aries/blueprint/namespace/NamespaceHandlerRegistryImpl.java Tue Aug 28 12:55:03 2012 @@ -18,6 +18,10 @@ */ package org.apache.aries.blueprint.namespace; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.net.URI; @@ -30,30 +34,27 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.HashSet; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; - +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.xml.XMLConstants; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; -import javax.xml.transform.stream.StreamSource; -import javax.xml.transform.Source; -import javax.xml.XMLConstants; - -import org.w3c.dom.ls.LSInput; -import org.w3c.dom.ls.LSResourceResolver; import org.apache.aries.blueprint.NamespaceHandler; import org.apache.aries.blueprint.container.NamespaceHandlerRegistry; import org.apache.aries.blueprint.parser.NamespaceHandlerSet; -import org.apache.aries.blueprint.parser.NamespaceHandlerSet.Listener; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -61,9 +62,9 @@ import org.osgi.util.tracker.ServiceTrac import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; /** * Default implementation of the NamespaceHandlerRegistry. @@ -81,25 +82,41 @@ public class NamespaceHandlerRegistryImp private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceHandlerRegistryImpl.class); + // The bundle context is thread safe private final BundleContext bundleContext; - private final Map<URI, Set<NamespaceHandler>> handlers; + + // The service tracker is thread safe private final ServiceTracker tracker; - private final Map<Map<URI, NamespaceHandler>, Reference<Schema>> schemas = new LRUMap<Map<URI, NamespaceHandler>, Reference<Schema>>(10); - private SchemaFactory schemaFactory; - private List<NamespaceHandlerSetImpl> sets; + + // The handlers map is concurrent + private final ConcurrentHashMap<URI, CopyOnWriteArraySet<NamespaceHandler>> handlers = + new ConcurrentHashMap<URI, CopyOnWriteArraySet<NamespaceHandler>>(); + + // Access to the LRU schemas map is synchronized on the lock object + private final Map<Map<URI, NamespaceHandler>, Reference<Schema>> schemas = + new LRUMap<Map<URI, NamespaceHandler>, Reference<Schema>>(10); + + // Lock to protect access to the schema list + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + // Access to this factory is synchronized on itself + private final SchemaFactory schemaFactory = + SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + + // Access to this variable is not synchronized. The list itself is concurrent + private final CopyOnWriteArrayList<NamespaceHandlerSetImpl> sets = + new CopyOnWriteArrayList<NamespaceHandlerSetImpl>(); public NamespaceHandlerRegistryImpl(BundleContext bundleContext) { this.bundleContext = bundleContext; - handlers = new HashMap<URI, Set<NamespaceHandler>>(); - sets = new ArrayList<NamespaceHandlerSetImpl>(); tracker = new ServiceTracker(bundleContext, NamespaceHandler.class.getName(), this); tracker.open(); } public Object addingService(ServiceReference reference) { - LOGGER.debug("Adding NamespaceHandler "+reference.toString()); + LOGGER.debug("Adding NamespaceHandler " + reference.toString()); NamespaceHandler handler = (NamespaceHandler) bundleContext.getService(reference); - if(handler!=null){ + if (handler != null) { try { Map<String, Object> props = new HashMap<String, Object>(); for (String name : reference.getPropertyKeys()) { @@ -109,8 +126,9 @@ public class NamespaceHandlerRegistryImp } catch (Exception e) { LOGGER.warn("Error registering NamespaceHandler", e); } - }else{ - LOGGER.warn("Error resolving NamespaceHandler, null Service obtained from tracked ServiceReference {} for bundle {}, ver {}", new Object[]{reference.toString(), reference.getBundle().getSymbolicName(), reference.getBundle().getVersion()}); + } else { + LOGGER.warn("Error resolving NamespaceHandler, null Service obtained from tracked ServiceReference {} for bundle {}, ver {}", + new Object[] { reference.toString(), reference.getBundle().getSymbolicName(), reference.getBundle().getVersion() }); } return handler; } @@ -122,6 +140,7 @@ public class NamespaceHandlerRegistryImp public void removedService(ServiceReference reference, Object service) { try { + LOGGER.debug("Removing NamespaceHandler " + reference.toString()); NamespaceHandler handler = (NamespaceHandler) service; Map<String, Object> props = new HashMap<String, Object>(); for (String name : reference.getPropertyKeys()) { @@ -133,13 +152,12 @@ public class NamespaceHandlerRegistryImp } } - public synchronized void registerHandler(NamespaceHandler handler, Map properties) { + public void registerHandler(NamespaceHandler handler, Map properties) { List<URI> namespaces = getNamespaces(properties); for (URI uri : namespaces) { - Set<NamespaceHandler> h = handlers.get(uri); + CopyOnWriteArraySet<NamespaceHandler> h = handlers.putIfAbsent(uri, new CopyOnWriteArraySet<NamespaceHandler>()); if (h == null) { - h = new HashSet<NamespaceHandler>(); - handlers.put(uri, h); + h = handlers.get(uri); } if (h.add(handler)) { for (NamespaceHandlerSetImpl s : sets) { @@ -149,11 +167,11 @@ public class NamespaceHandlerRegistryImp } } - public synchronized void unregisterHandler(NamespaceHandler handler, Map properties) { + public void unregisterHandler(NamespaceHandler handler, Map properties) { List<URI> namespaces = getNamespaces(properties); for (URI uri : namespaces) { - Set<NamespaceHandler> h = handlers.get(uri); - if (h == null || !h.remove(handler)) { + CopyOnWriteArraySet<NamespaceHandler> h = handlers.get(uri); + if (!h.remove(handler)) { continue; } for (NamespaceHandlerSetImpl s : sets) { @@ -166,7 +184,8 @@ public class NamespaceHandlerRegistryImp private static List<URI> getNamespaces(Map properties) { Object ns = properties != null ? properties.get(NAMESPACE) : null; if (ns == null) { - throw new IllegalArgumentException("NamespaceHandler service does not have an associated " + NAMESPACE + " property defined"); + throw new IllegalArgumentException("NamespaceHandler service does not have an associated " + + NAMESPACE + " property defined"); } else if (ns instanceof URI[]) { return Arrays.asList((URI[]) ns); } else if (ns instanceof URI) { @@ -195,7 +214,8 @@ public class NamespaceHandlerRegistryImp } return namespaces; } else { - throw new IllegalArgumentException("NamespaceHandler service has an associated " + NAMESPACE + " property defined which can not be converted to an array of URI"); + throw new IllegalArgumentException("NamespaceHandler service has an associated " + + NAMESPACE + " property defined which can not be converted to an array of URI"); } } @@ -205,11 +225,12 @@ public class NamespaceHandlerRegistryImp } else if (o instanceof String) { return URI.create((String) o); } else { - throw new IllegalArgumentException("NamespaceHandler service has an associated " + NAMESPACE + " property defined which can not be converted to an array of URI"); + throw new IllegalArgumentException("NamespaceHandler service has an associated " + + NAMESPACE + " property defined which can not be converted to an array of URI"); } } - public synchronized NamespaceHandlerSet getNamespaceHandlers(Set<URI> uris, Bundle bundle) { + public NamespaceHandlerSet getNamespaceHandlers(Set<URI> uris, Bundle bundle) { NamespaceHandlerSetImpl s = new NamespaceHandlerSetImpl(uris, bundle); sets.add(s); return s; @@ -218,222 +239,282 @@ public class NamespaceHandlerRegistryImp public void destroy() { tracker.close(); } - public synchronized Schema getSchema(Map<URI, NamespaceHandler> handlers) - throws IOException, SAXException { - return getSchema(handlers, null, new Properties()); - } - private synchronized Schema getSchema(Map<URI, NamespaceHandler> handlers, - final Bundle bundle, - final Properties schemaMap) throws IOException, SAXException { - Schema schema = null; + + private Schema getSchema(Map<URI, NamespaceHandler> handlers, + final Bundle bundle, + final Properties schemaMap) throws IOException, SAXException { + if (schemaMap != null && !schemaMap.isEmpty()) { + return createSchema(handlers, bundle, schemaMap); + } // 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 - if (schemaMap == null || schemaMap.isEmpty()) { + lock.readLock().lock(); + try { + Schema schema = getExistingSchema(handlers); + if (schema != null) { + return schema; + } + } finally { + lock.readLock().unlock(); + } + // Create schema + lock.writeLock().lock(); + try { + Schema schema = getExistingSchema(handlers); + if (schema == null) { + schema = createSchema(handlers, bundle, schemaMap); + cacheSchema(handlers, schema); + } + return schema; + } finally { + lock.writeLock().unlock(); + } + } + + private Schema getExistingSchema(Map<URI, NamespaceHandler> handlers) { + for (Map<URI, NamespaceHandler> key : schemas.keySet()) { + boolean found = true; + for (URI uri : handlers.keySet()) { + if (!handlers.get(uri).equals(key.get(uri))) { + found = false; + break; + } + } + if (found) { + return schemas.get(key).get(); + } + } + return null; + } + + private void removeSchemasFor(NamespaceHandler handler) { + List<Map<URI, NamespaceHandler>> keys = new ArrayList<Map<URI, NamespaceHandler>>(); + lock.readLock().lock(); + try { for (Map<URI, NamespaceHandler> key : schemas.keySet()) { - boolean found = true; - for (URI uri : handlers.keySet()) { - if (!handlers.get(uri).equals(key.get(uri))) { - found = false; - break; - } + if (key.values().contains(handler)) { + keys.add(key); } - if (found) { - schema = schemas.get(key).get(); + } + } finally { + lock.readLock().unlock(); + } + if (!keys.isEmpty()) { + lock.writeLock().lock(); + try { + for (Map<URI, NamespaceHandler> key : keys) { + schemas.remove(key); + } + } finally { + lock.writeLock().unlock(); + } + } + } + + private void cacheSchema(Map<URI, NamespaceHandler> handlers, Schema schema) { + // Remove schemas that are fully included + for (Iterator<Map<URI, NamespaceHandler>> iterator = schemas.keySet().iterator(); iterator.hasNext();) { + Map<URI, NamespaceHandler> key = iterator.next(); + boolean found = true; + for (URI uri : key.keySet()) { + if (!key.get(uri).equals(handlers.get(uri))) { + found = false; break; } } + if (found) { + iterator.remove(); + break; + } } - if (schema == null) { - final List<StreamSource> schemaSources = new ArrayList<StreamSource>(); - try { - 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 - 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(), url.toExternalForm())); - } + // Add our new schema + schemas.put(handlers, new SoftReference<Schema>(schema)); + } + + private Schema createSchema(Map<URI, NamespaceHandler> handlers, + Bundle bundle, + Properties schemaMap) throws IOException, SAXException { + final List<StreamSource> schemaSources = new ArrayList<StreamSource>(); + try { + 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 + 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(), url.toExternalForm())); } - for (Object ns : schemaMap.values()) { - URL url = bundle.getResource(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(), url.toExternalForm())); - } + } + for (Object ns : schemaMap.values()) { + URL url = bundle.getResource(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(), url.toExternalForm())); } - SchemaFactory factory = getSchemaFactory(); - factory.setResourceResolver(new LSResourceResolver() { - public LSInput resolveResource(String type, - final String namespaceURI, - final String publicId, - String systemId, String baseURI) { - String loc = null; - if (namespaceURI != null) { - loc = schemaMap.getProperty(namespaceURI); - } - if (loc == null && publicId != null) { - loc = schemaMap.getProperty(publicId); - } - if (loc == null && systemId != null) { - loc = schemaMap.getProperty(systemId); - } - if (loc != null) { - URL url = bundle.getResource(loc); - if (url != null) { - try { - StreamSource source - = new StreamSource(url.openStream(), url.toExternalForm()); - schemaSources.add(source); - return new SourceLSInput(source, publicId, url); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - URI uri = URI.create((String) namespaceURI); - Set<NamespaceHandler> hs = NamespaceHandlerRegistryImpl.this.handlers.get(uri); - if (hs == null) { - return null; - } - for (NamespaceHandler h : hs) { - URL url = h.getSchemaLocation(namespaceURI); - if (url != null) { - // handling include-relative-path case - if (systemId != null && !systemId.matches("^[a-z][-+.0-9a-z]*:.*")) { - try { - url = new URL(url, systemId); - } catch (Exception e) { - // ignore and use the given systemId - } - } - - - try { - final StreamSource source - = new StreamSource(url.openStream(), url.toExternalForm()); - schemaSources.add(source); - return new SourceLSInput(source, publicId, url); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - return null; + } + synchronized (schemaFactory) { + schemaFactory.setResourceResolver(new BundleResourceResolver(schemaMap, bundle, schemaSources)); + return schemaFactory.newSchema(schemaSources.toArray(new Source[schemaSources.size()])); + } + } finally { + for (StreamSource s : schemaSources) { + closeQuietly(s.getInputStream()); + } + } + } + + private static void closeQuietly(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (IOException e) { + // Ignore + } + } + + private class BundleResourceResolver implements LSResourceResolver { + private final Properties schemaMap; + private final Bundle bundle; + private final List<StreamSource> schemaSources; + + public BundleResourceResolver(Properties schemaMap, Bundle bundle, List<StreamSource> schemaSources) { + this.schemaMap = schemaMap; + this.bundle = bundle; + this.schemaSources = schemaSources; + } + + public LSInput resolveResource(String type, + final String namespaceURI, + final String publicId, + String systemId, String baseURI) { + String loc = null; + if (namespaceURI != null) { + loc = schemaMap.getProperty(namespaceURI); + } + if (loc == null && publicId != null) { + loc = schemaMap.getProperty(publicId); + } + if (loc == null && systemId != null) { + loc = schemaMap.getProperty(systemId); + } + if (loc != null) { + URL url = bundle.getResource(loc); + if (url != null) { + try { + StreamSource source + = new StreamSource(url.openStream(), url.toExternalForm()); + schemaSources.add(source); + return new SourceLSInput(source, publicId, url); + } catch (IOException e) { + throw new RuntimeException(e); } - - }); - schema = factory.newSchema(schemaSources.toArray(new Source[schemaSources.size()])); - // Remove schemas that are fully included - for (Iterator<Map<URI, NamespaceHandler>> iterator = schemas.keySet().iterator(); iterator.hasNext();) { - Map<URI, NamespaceHandler> key = iterator.next(); - boolean found = true; - for (URI uri : key.keySet()) { - if (!key.get(uri).equals(handlers.get(uri))) { - found = false; - break; + } + } + URI uri = URI.create(namespaceURI); + Set<NamespaceHandler> hs = NamespaceHandlerRegistryImpl.this.handlers.get(uri); + if (hs == null) { + return null; + } + for (NamespaceHandler h : hs) { + URL url = h.getSchemaLocation(namespaceURI); + if (url != null) { + // handling include-relative-path case + if (systemId != null && !systemId.matches("^[a-z][-+.0-9a-z]*:.*")) { + try { + url = new URL(url, systemId); + } catch (Exception e) { + // ignore and use the given systemId } } - if (found) { - iterator.remove(); - break; - } - } - // Add our new schema - if (schemaMap.isEmpty()) { - //only cache non-custom schemas - schemas.put(handlers, new SoftReference<Schema>(schema)); - } - } finally { - for (StreamSource s : schemaSources) { try { - s.getInputStream().close(); + final StreamSource source = new StreamSource(url.openStream(), url.toExternalForm()); + schemaSources.add(source); + return new SourceLSInput(source, publicId, url); } catch (IOException e) { - // Ignore + throw new RuntimeException(e); } } } + return null; } - return schema; } - + private class SourceLSInput implements LSInput { - StreamSource source; - URL systemId; - String publicId; - public SourceLSInput(StreamSource src, String pid, URL sys) { - source = src; - publicId = pid; - systemId = sys; + private final StreamSource source; + private final URL systemId; + private final String publicId; + + public SourceLSInput(StreamSource source, String publicId, URL systemId) { + this.source = source; + this.publicId = publicId; + this.systemId = systemId; } + public Reader getCharacterStream() { return null; } + public void setCharacterStream(Reader characterStream) { } + public InputStream getByteStream() { return source.getInputStream(); } + public void setByteStream(InputStream byteStream) { } + public String getStringData() { return null; } + public void setStringData(String stringData) { } + public String getSystemId() { return systemId.toExternalForm(); } + public void setSystemId(String systemId) { } + public String getPublicId() { return publicId; } + public void setPublicId(String publicId) { } + public String getBaseURI() { return null; } + public void setBaseURI(String baseURI) { } + public String getEncoding() { return null; } + public void setEncoding(String encoding) { } + public boolean getCertifiedText() { return false; } - public void setCertifiedText(boolean certifiedText) { - } - }; - 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 (Map<URI, NamespaceHandler> key : keys) { - schemas.remove(key); - } - } - - private SchemaFactory getSchemaFactory() { - if (schemaFactory == null) { - schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + public void setCertifiedText(boolean certifiedText) { } - return schemaFactory; } protected class NamespaceHandlerSetImpl implements NamespaceHandlerSet { - private final Map<Listener, Boolean> listeners; + private final List<Listener> listeners; private final Bundle bundle; private final Set<URI> namespaces; private final Map<URI, NamespaceHandler> handlers; @@ -441,7 +522,7 @@ public class NamespaceHandlerRegistryImp private Schema schema; public NamespaceHandlerSetImpl(Set<URI> namespaces, Bundle bundle) { - this.listeners = new HashMap<Listener, Boolean>(); + this.listeners = new CopyOnWriteArrayList<Listener>(); this.namespaces = namespaces; this.bundle = bundle; handlers = new HashMap<URI, NamespaceHandler>(); @@ -458,13 +539,7 @@ public class NamespaceHandlerRegistryImp ex.printStackTrace(); //ignore } finally { - if (ins != null) { - try { - ins.close(); - } catch (IOException e) { - //ignore - } - } + closeQuietly(ins); } } for (Object ns : schemaMap.keySet()) { @@ -498,11 +573,11 @@ public class NamespaceHandlerRegistryImp return schema; } - public synchronized void addListener(Listener listener) { - listeners.put(listener, Boolean.TRUE); + public void addListener(Listener listener) { + listeners.add(listener); } - public synchronized void removeListener(Listener listener) { + public void removeListener(Listener listener) { listeners.remove(listener); } @@ -513,7 +588,7 @@ public class NamespaceHandlerRegistryImp public void registerHandler(URI uri, NamespaceHandler handler) { if (namespaces.contains(uri) && handlers.get(uri) == null) { if (findCompatibleNamespaceHandler(uri) != null) { - for (Listener listener : listeners.keySet()) { + for (Listener listener : listeners) { try { listener.namespaceHandlerRegistered(uri); } catch (Throwable t) { @@ -527,7 +602,7 @@ public class NamespaceHandlerRegistryImp public void unregisterHandler(URI uri, NamespaceHandler handler) { if (handlers.get(uri) == handler) { handlers.remove(uri); - for (Listener listener : listeners.keySet()) { + for (Listener listener : listeners) { try { listener.namespaceHandlerUnregistered(uri); } catch (Throwable t) { @@ -578,64 +653,6 @@ public class NamespaceHandlerRegistryImp } } - 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;