You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by gn...@apache.org on 2009/07/10 13:28:10 UTC
svn commit: r792887 - in /geronimo/sandbox/blueprint:
blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/
blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/
blueprint-core/src/main/java/org/apache/geronimo/bl...
Author: gnodet
Date: Fri Jul 10 11:28:10 2009
New Revision: 792887
URL: http://svn.apache.org/viewvc?rev=792887&view=rev
Log:
Boost performance of schema validation by maintaining a cache of schemas
Modified:
geronimo/sandbox/blueprint/blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/blueprint-cm.xsd
geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/NamespaceHandlerRegistry.java
geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/Parser.java
geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/namespace/NamespaceHandlerRegistryImpl.java
Modified: geronimo/sandbox/blueprint/blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/blueprint-cm.xsd
URL: http://svn.apache.org/viewvc/geronimo/sandbox/blueprint/blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/blueprint-cm.xsd?rev=792887&r1=792886&r2=792887&view=diff
==============================================================================
--- geronimo/sandbox/blueprint/blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/blueprint-cm.xsd (original)
+++ geronimo/sandbox/blueprint/blueprint-cm/src/main/resources/org/apache/geronimo/blueprint/compendium/cm/blueprint-cm.xsd Fri Jul 10 11:28:10 2009
@@ -26,7 +26,7 @@
attributeFormDefault="unqualified"
version="1.0.0">
- <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0" schemaLocation="../../blueprint/v1.0.0/blueprint.xsd"/>
+ <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0" />
<!-- property placeholder -->
Modified: geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/NamespaceHandlerRegistry.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/NamespaceHandlerRegistry.java?rev=792887&r1=792886&r2=792887&view=diff
==============================================================================
--- geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/NamespaceHandlerRegistry.java (original)
+++ geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/NamespaceHandlerRegistry.java Fri Jul 10 11:28:10 2009
@@ -19,8 +19,13 @@
package org.apache.geronimo.blueprint.container;
import java.net.URI;
+import java.util.Set;
+import java.io.IOException;
+
+import javax.xml.validation.Schema;
import org.apache.geronimo.blueprint.NamespaceHandler;
+import org.xml.sax.SAXException;
/**
* Registry of NamespaceHandler.
@@ -53,6 +58,14 @@
void removeListener(Listener listener);
/**
+ * Obtain a schema to validate the XML for the given list of namespaces
+ *
+ * @param namespaces
+ * @return
+ */
+ Schema getSchema(Set<URI> namespaces) throws SAXException, IOException;
+
+ /**
* Destroy this registry
*/
void destroy();
Modified: geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/Parser.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/Parser.java?rev=792887&r1=792886&r2=792887&view=diff
==============================================================================
--- geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/Parser.java (original)
+++ geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/container/Parser.java Fri Jul 10 11:28:10 2009
@@ -18,7 +18,6 @@
*/
package org.apache.geronimo.blueprint.container;
-import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
@@ -26,17 +25,15 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.w3c.dom.Attr;
@@ -60,15 +57,14 @@
import org.apache.geronimo.blueprint.reflect.MapMetadataImpl;
import org.apache.geronimo.blueprint.reflect.MetadataUtil;
import org.apache.geronimo.blueprint.reflect.PropsMetadataImpl;
-import org.apache.geronimo.blueprint.reflect.ReferenceListMetadataImpl;
import org.apache.geronimo.blueprint.reflect.RefMetadataImpl;
+import org.apache.geronimo.blueprint.reflect.ReferenceListMetadataImpl;
import org.apache.geronimo.blueprint.reflect.ReferenceListenerImpl;
import org.apache.geronimo.blueprint.reflect.ReferenceMetadataImpl;
import org.apache.geronimo.blueprint.reflect.RegistrationListenerImpl;
import org.apache.geronimo.blueprint.reflect.ServiceMetadataImpl;
import org.apache.geronimo.blueprint.reflect.ServiceReferenceMetadataImpl;
import org.apache.geronimo.blueprint.reflect.ValueMetadataImpl;
-import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.service.blueprint.container.ComponentDefinitionException;
import org.osgi.service.blueprint.reflect.BeanArgument;
import org.osgi.service.blueprint.reflect.BeanMetadata;
@@ -82,8 +78,8 @@
import org.osgi.service.blueprint.reflect.NonNullMetadata;
import org.osgi.service.blueprint.reflect.NullMetadata;
import org.osgi.service.blueprint.reflect.PropsMetadata;
-import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
import org.osgi.service.blueprint.reflect.ReferenceListener;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.blueprint.reflect.RegistrationListener;
@@ -185,7 +181,6 @@
private static final Logger LOGGER = LoggerFactory.getLogger(Parser.class);
private static DocumentBuilderFactory documentBuilderFactory;
- private static SchemaFactory schemaFactory;
private List<Document> documents;
private ComponentDefinitionRegistry registry;
@@ -234,7 +229,7 @@
if (documents == null) {
throw new IllegalStateException("Documents should be parsed before retrieving required namespaces");
}
- Set<URI> namespaces = new HashSet<URI>();
+ Set<URI> namespaces = new LinkedHashSet<URI>();
for (Document doc : documents) {
findNamespaces(namespaces, doc);
}
@@ -246,7 +241,7 @@
private void findNamespaces(Set<URI> namespaces, Node node) {
if (node instanceof Element || node instanceof Attr) {
String ns = node.getNamespaceURI();
- if (ns != null && !isBlueprintNamespace(ns)) {
+ if (ns != null) {
namespaces.add(URI.create(ns));
}
}
@@ -275,36 +270,15 @@
}
private void validate() {
- List<StreamSource> schemaSources = new ArrayList<StreamSource>();
+ // Use a LinkedHashSet to ensure that the blueprint schema is loaded first
try {
- schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/geronimo/blueprint/blueprint.xsd")));
- for (URI uri : getNamespaces()) {
- NamespaceHandler handler = this.namespaceHandlerRegistry.getNamespaceHandler(uri);
- if (handler == null) {
- throw new ComponentDefinitionException("Unsupported node namespace: " + uri);
- }
- URL url = handler.getSchemaLocation(uri.toString());
- if (url != null) {
- schemaSources.add(new StreamSource(url.openStream()));
- } else {
- LOGGER.warn("No URL is defined for schema " + uri + ". This schema will not be validated");
- }
- }
- Schema schema = getSchemaFactory().newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
+ Schema schema = this.namespaceHandlerRegistry.getSchema(getNamespaces());
Validator validator = schema.newValidator();
for (Document doc : this.documents) {
validator.validate(new DOMSource(doc));
}
} catch (Exception e) {
throw new ComponentDefinitionException("Unable to validate xml", e);
- } finally {
- for (StreamSource s : schemaSources) {
- try {
- s.getInputStream().close();
- } catch (IOException e) {
- // Ignore
- }
- }
}
}
@@ -1225,11 +1199,4 @@
return documentBuilderFactory;
}
- private static SchemaFactory getSchemaFactory() {
- if (schemaFactory == null) {
- schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- }
- return schemaFactory;
- }
-
}
Modified: geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/namespace/NamespaceHandlerRegistryImpl.java
URL: http://svn.apache.org/viewvc/geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/namespace/NamespaceHandlerRegistryImpl.java?rev=792887&r1=792886&r2=792887&view=diff
==============================================================================
--- geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/namespace/NamespaceHandlerRegistryImpl.java (original)
+++ geronimo/sandbox/blueprint/blueprint-core/src/main/java/org/apache/geronimo/blueprint/namespace/NamespaceHandlerRegistryImpl.java Fri Jul 10 11:28:10 2009
@@ -19,6 +19,7 @@
package org.apache.geronimo.blueprint.namespace;
import java.net.URI;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -26,6 +27,19 @@
import java.util.HashMap;
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 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.apache.geronimo.blueprint.NamespaceHandler;
import org.apache.geronimo.blueprint.container.NamespaceHandlerRegistry;
@@ -35,6 +49,7 @@
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
/**
* Default implementation of the NamespaceHandlerRegistry.
@@ -47,6 +62,8 @@
*/
public class NamespaceHandlerRegistryImpl implements NamespaceHandlerRegistry, ServiceTrackerCustomizer {
+ public static final URI BLUEPRINT_NAMESPACE = URI.create("http://www.osgi.org/xmlns/blueprint/v1.0.0");
+
public static final String NAMESPACE = "osgi.service.blueprint.namespace";
private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceHandlerRegistryImpl.class);
@@ -55,6 +72,8 @@
private final Map<URI, NamespaceHandler> handlers;
private final ServiceTracker tracker;
private final Map<Listener, Boolean> listeners;
+ private final Map<Set<URI>, Schema> schemas = new LRUMap<Set<URI>, Schema>(10);
+ private SchemaFactory schemaFactory;
public NamespaceHandlerRegistryImpl(BundleContext bundleContext) {
this.bundleContext = bundleContext;
@@ -117,6 +136,7 @@
handlers.remove(uri);
callListeners(uri, false);
}
+ removeSchemasFor(namespaces);
}
private void callListeners(URI uri, boolean registered) {
@@ -194,4 +214,149 @@
public synchronized void removeListener(Listener listener) {
listeners.remove(listener);
}
+
+ public synchronized Schema getSchema(Set<URI> namespaces) 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)) {
+ schema = schemas.get(key);
+ break;
+ }
+ }
+ if (schema == null) {
+ List<StreamSource> schemaSources = new ArrayList<StreamSource>();
+ try {
+ schemaSources.add(new StreamSource(getClass().getResourceAsStream("/org/apache/geronimo/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()));
+ }
+ }
+ }
+ schema = getSchemaFactory().newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
+ schemas.put(namespaces, schema);
+ } finally {
+ for (StreamSource s : schemaSources) {
+ try {
+ s.getInputStream().close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ return schema;
+ }
+
+ protected synchronized void removeSchemasFor(List<URI> namespaces) {
+ for (URI ns : namespaces) {
+ for (Set<URI> key : schemas.keySet()) {
+ if (key.contains(ns)) {
+ schemas.remove(key);
+ }
+ }
+ }
+ }
+
+ private SchemaFactory getSchemaFactory() {
+ if (schemaFactory == null) {
+ schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ }
+ return schemaFactory;
+ }
+
+ private static class LRUMap<K,V> extends AbstractMap<K,V> {
+
+ private final int bound;
+ private final LinkedList<Entry<K,V>> entries = new LinkedList<Entry<K,V>>();
+
+ private static class LRUEntry<K,V> implements Entry<K,V> {
+ private final K key;
+ private final V value;
+
+ private LRUEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private LRUMap(int bound) {
+ this.bound = bound;
+ }
+
+ public V get(Object key) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+ for (Entry<K,V> e : entries) {
+ if (e.getKey().equals(key)) {
+ entries.remove(e);
+ entries.addFirst(e);
+ return e.getValue();
+ }
+ }
+ return null;
+ }
+
+ public V put(K key, V value) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+ V old = null;
+ for (Entry<K,V> e : entries) {
+ if (e.getKey().equals(key)) {
+ entries.remove(e);
+ old = e.getValue();
+ break;
+ }
+ }
+ if (value != null) {
+ entries.addFirst(new LRUEntry<K,V>(key, value));
+ while (entries.size() > bound) {
+ entries.removeLast();
+ }
+ }
+ return old;
+ }
+
+ public Set<Entry<K, V>> entrySet() {
+ return new AbstractSet<Entry<K,V>>() {
+ public Iterator<Entry<K, V>> iterator() {
+ return entries.iterator();
+ }
+
+ public int size() {
+ return entries.size();
+ }
+ };
+ }
+ }
+
}