You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/04/11 19:20:35 UTC

[13/33] git commit: [KARAF-2888] Refactor repository validation so that we use a single pass, cache the created Schema

[KARAF-2888] Refactor repository validation so that we use a single pass, cache the created Schema


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/1306af5f
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/1306af5f
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/1306af5f

Branch: refs/heads/master
Commit: 1306af5f222e8bf8925d0e42b0062ec3d367c1d3
Parents: a9b763f
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Apr 11 11:14:16 2014 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Fri Apr 11 19:20:03 2014 +0200

----------------------------------------------------------------------
 features/pom.xml                                |   4 +
 .../org/apache/karaf/features/Repository.java   |   3 +-
 .../karaf/features/internal/model/JaxbUtil.java | 149 ++++++++++++++-----
 .../internal/service/BootFeaturesInstaller.java |   2 +-
 .../internal/service/FeatureValidationUtil.java |  80 +---------
 .../internal/service/FeaturesServiceImpl.java   |   4 +-
 .../internal/service/RepositoryImpl.java        |  15 +-
 .../service/FeaturesValidationTest.java         |  49 +++++-
 .../karaf/tooling/features/CreateKarMojo.java   |  23 ++-
 .../features/GenerateDescriptorMojo.java        |   9 +-
 .../karaf/tooling/features/InstallKarsMojo.java |   9 +-
 .../features/GenerateDescriptorMojoTest.java    |   9 +-
 .../java/org/apache/karaf/util/XmlUtils.java    |  64 +++++---
 13 files changed, 231 insertions(+), 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/pom.xml
----------------------------------------------------------------------
diff --git a/features/pom.xml b/features/pom.xml
index 5013057..d722ada 100644
--- a/features/pom.xml
+++ b/features/pom.xml
@@ -129,12 +129,16 @@
                             org.apache.felix.resolver,
                             org.apache.felix.utils.version,
                             org.apache.felix.utils.manifest,
+                            org.apache.karaf.util,
                             org.apache.karaf.util.collections,
                             org.apache.karaf.util.json,
                             org.apache.karaf.util.tracker,
                             org.osgi.service.resolver,
                             org.osgi.service.repository
                         </Private-Package>
+                        <Embed-Dependency>
+                            org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class"
+                        </Embed-Dependency>
                         <Bundle-Activator>
                             org.apache.karaf.features.internal.osgi.Activator
                         </Bundle-Activator>

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/Repository.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/Repository.java b/features/src/main/java/org/apache/karaf/features/Repository.java
index 6ee96da..3ea12ec 100644
--- a/features/src/main/java/org/apache/karaf/features/Repository.java
+++ b/features/src/main/java/org/apache/karaf/features/Repository.java
@@ -16,6 +16,7 @@
  */
 package org.apache.karaf.features;
 
+import java.io.IOException;
 import java.net.URI;
 
 /**
@@ -23,7 +24,7 @@ import java.net.URI;
  */
 public interface Repository {
 
-    String getName();
+    String getName() throws IOException;
 
     URI getURI();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
index 39c057a..2036452 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/model/JaxbUtil.java
@@ -23,19 +23,27 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Writer;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.ValidationEvent;
-import javax.xml.bind.ValidationEventHandler;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.stream.XMLInputFactory;
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 
 import org.apache.karaf.features.FeaturesNamespaces;
+import org.apache.karaf.util.XmlUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -45,7 +53,6 @@ import org.xml.sax.helpers.XMLFilterImpl;
 
 public class JaxbUtil {
 
-    public static final XMLInputFactory XMLINPUT_FACTORY = XMLInputFactory.newInstance();
     private static final JAXBContext FEATURES_CONTEXT;
     static {
         try {
@@ -75,45 +82,113 @@ public class JaxbUtil {
     /**
      * Read in a Features from the input stream.
      *
-     * @param in       input stream to read
+     * @param uri      uri to read
      * @param validate whether to validate the input.
      * @return a Features read from the input stream
-     * @throws ParserConfigurationException is the SAX parser can not be configured
-     * @throws SAXException                 if there is an xml problem
-     * @throws JAXBException                if the xml cannot be marshalled into a T.
      */
-    public static Features unmarshal(InputStream in, boolean validate) {
-        InputSource inputSource = new InputSource(in);
+    public static Features unmarshal(String uri, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, null);
+        } else {
+            return unmarshalNoValidate(uri, null);
+        }
+    }
+
+    public static Features unmarshal(String uri, InputStream stream, boolean validate) {
+        if (validate) {
+            return unmarshalValidate(uri, stream);
+        } else {
+            return unmarshalNoValidate(uri, stream);
+        }
+    }
 
-        SAXParserFactory factory = SAXParserFactory.newInstance();
-        factory.setNamespaceAware(true);
-        factory.setValidating(validate);
-        SAXParser parser;
+    private static Features unmarshalValidate(String uri, InputStream stream) {
         try {
-            parser = factory.newSAXParser();
-        
-
-        Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
-        unmarshaller.setEventHandler(new ValidationEventHandler() {
-            public boolean handleEvent(ValidationEvent validationEvent) {
-                System.out.println(validationEvent);
-                return false;
+            Document doc;
+            if (stream != null) {
+                doc = XmlUtils.parse(stream);
+                doc.setDocumentURI(uri);
+            } else {
+                doc = XmlUtils.parse(uri);
             }
-        });
 
-        XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(parser.getXMLReader());
-        xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+            Schema schema = getSchema(doc.getDocumentElement().getNamespaceURI());
+            try {
+                schema.newValidator().validate(new DOMSource(doc));
+            } catch (SAXException e) {
+                throw new IllegalArgumentException("Unable to validate " + uri, e);
+            }
 
-        SAXSource source = new SAXSource(xmlFilter, inputSource);
+            fixDom(doc, doc.getDocumentElement());
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            return (Features) unmarshaller.unmarshal(new DOMSource(doc));
 
-        return (Features)unmarshaller.unmarshal(source);
-        
-        } catch (ParserConfigurationException e) {
-            throw new RuntimeException(e);
-        } catch (JAXBException e) {
-            throw new RuntimeException(e);
-        } catch (SAXException e) {
-            throw new RuntimeException(e);
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
+        }
+    }
+
+    private static Map<String, Schema> schemas = new ConcurrentHashMap<String, Schema>();
+    private static Schema getSchema(String namespace) throws SAXException {
+        Schema schema = schemas.get(namespace);
+        if (schema == null) {
+            String schemaLocation;
+            if (FeaturesNamespaces.URI_1_0_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.0.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_1_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.1.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_2_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.2.0.xsd";
+            } else if (FeaturesNamespaces.URI_1_3_0.equals(namespace)) {
+                schemaLocation = "/org/apache/karaf/features/karaf-features-1.3.0.xsd";
+            } else {
+                throw new IllegalArgumentException("Unsupported namespace: " + namespace);
+            }
+
+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            // root element has namespace - we can use schema validation
+            URL url = JaxbUtil.class.getResource(schemaLocation);
+            if (url == null) {
+                throw new IllegalStateException("Could not find resource: " + schemaLocation);
+            }
+            schema = factory.newSchema(new StreamSource(url.toExternalForm()));
+            schemas.put(namespace, schema);
+        }
+        return schema;
+    }
+
+
+    private static void fixDom(Document doc, Node node) {
+        if (node.getNamespaceURI() != null && !FeaturesNamespaces.URI_CURRENT.equals(node.getNamespaceURI())) {
+            doc.renameNode(node, FeaturesNamespaces.URI_CURRENT, node.getLocalName());
+        }
+        NodeList children = node.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            fixDom(doc, children.item(i));
+        }
+    }
+
+    private static Features unmarshalNoValidate(String uri, InputStream stream) {
+        try {
+            Unmarshaller unmarshaller = FEATURES_CONTEXT.createUnmarshaller();
+            XMLFilter xmlFilter = new NoSourceAndNamespaceFilter(XmlUtils.xmlReader());
+            xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
+
+
+            InputSource is = new InputSource(uri);
+            if (stream != null) {
+                is.setByteStream(stream);
+            }
+            SAXSource source = new SAXSource(xmlFilter, new InputSource(uri));
+            return (Features) unmarshaller.unmarshal(source);
+
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to load " + uri, e);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java b/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
index eaa9ba0..5b362b8 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/BootFeaturesInstaller.java
@@ -89,7 +89,7 @@ public class BootFeaturesInstaller {
                     try {
                         featuresService.addRepository(URI.create(repo));
                     } catch (Exception e) {
-                        LOGGER.error("Error installing boot feature repository " + repo);
+                        LOGGER.error("Error installing boot feature repository " + repo, e);
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
index 8fb161e..6903dc0 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeatureValidationUtil.java
@@ -15,38 +15,15 @@
  */
 package org.apache.karaf.features.internal.service;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.net.URI;
-import java.net.URLConnection;
 
-import javax.xml.XMLConstants;
-import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-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.apache.karaf.features.FeaturesNamespaces;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
+import org.apache.karaf.features.internal.model.JaxbUtil;
 
 /**
  * Utility class which fires XML Schema validation.
  */
 public class FeatureValidationUtil {
 
-    public static final QName FEATURES_0_0 = new QName("features");
-    public static final QName FEATURES_1_0 = new QName("http://karaf.apache.org/xmlns/features/v1.0.0", "features");
-    public static final QName FEATURES_1_1 = new QName("http://karaf.apache.org/xmlns/features/v1.1.0", "features");
-    public static final QName FEATURES_1_2 = new QName("http://karaf.apache.org/xmlns/features/v1.2.0", "features");
-    private static final Logger LOGGER = LoggerFactory.getLogger(FeatureValidationUtil.class);
-
     /**
      * Runs schema validation.
      * 
@@ -54,60 +31,7 @@ public class FeatureValidationUtil {
      * @throws Exception When validation fails.
      */
     public static void validate(URI uri) throws Exception {
-        Document doc = load(uri);
-
-        QName name = new QName(doc.getDocumentElement().getNamespaceURI(), doc.getDocumentElement().getLocalName());
-
-        if (FeaturesNamespaces.FEATURES_0_0_0.equals(name)) {
-            LOGGER.warn("Old style feature file without namespace found (URI: {}). This format is deprecated and support for it will soon be removed", uri);
-            return;
-        } else if (FeaturesNamespaces.FEATURES_1_0_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.0.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_1_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.1.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_2_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.2.0.xsd");
-        } else if (FeaturesNamespaces.FEATURES_1_3_0.equals(name)) {
-            validate(doc, "/org/apache/karaf/features/karaf-features-1.3.0.xsd");
-        }
-        else {
-            throw new IllegalArgumentException("Unrecognized root element: " + name);
-        }
-    }
-
-    private static Document load(URI uri) throws IOException, SAXException, ParserConfigurationException {
-        InputStream stream = null;
-        try {
-            URLConnection conn;
-            try {
-                conn = uri.toURL().openConnection();
-            } catch (IllegalArgumentException e) {
-                throw new IllegalArgumentException("invalid URI: " + uri, e);
-            }
-            conn.setDefaultUseCaches(false);
-            stream = conn.getInputStream();
-            // load document and check the root element for namespace declaration
-            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
-            dFactory.setNamespaceAware(true);
-            return dFactory.newDocumentBuilder().parse(stream);
-        } finally {
-            if (stream != null) {
-                stream.close();
-            }
-        }
-    }
-
-    private static void validate(Document doc, String schemaLocation) throws SAXException {
-        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        // root element has namespace - we can use schema validation
-        Schema schema = factory.newSchema(new StreamSource(FeatureValidationUtil.class.getResourceAsStream(schemaLocation)));
-        // create schema by reading it from an XSD file:
-        Validator validator = schema.newValidator();
-        try {
-            validator.validate(new DOMSource(doc));
-        } catch (Exception e) {
-            throw new IllegalArgumentException("Unable to validate " + doc.getDocumentURI(), e);
-        }
+        JaxbUtil.unmarshal(uri.toASCIIString(), true);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
index 0bd1e67..65223d5 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java
@@ -281,10 +281,8 @@ public class FeaturesServiceImpl implements FeaturesService {
     //
 
     public Repository loadRepository(URI uri) throws Exception {
-        // TODO: merge validation and loading by loading the DOM, validating, unmarshalling
-        FeatureValidationUtil.validate(uri);
         RepositoryImpl repo = new RepositoryImpl(uri);
-        repo.load();
+        repo.load(true);
         return repo;
     }
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
----------------------------------------------------------------------
diff --git a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java b/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
index 4bf1502..56e5102 100644
--- a/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
+++ b/features/src/main/java/org/apache/karaf/features/internal/service/RepositoryImpl.java
@@ -42,13 +42,8 @@ public class RepositoryImpl implements Repository {
         return uri;
     }
 
-    public String getName() {
-        // TODO: catching this exception is ugly
-        try {
-            load();
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to load repository", e);
-        }
+    public String getName() throws IOException {
+        load();
         return features.getName();
     }
 
@@ -70,6 +65,10 @@ public class RepositoryImpl implements Repository {
 
 
     public void load() throws IOException {
+        load(false);
+    }
+
+    public void load(boolean validate) throws IOException {
         if (features == null) {
             try {
                 InputStream inputStream = uri.toURL().openStream();
@@ -83,7 +82,7 @@ public class RepositoryImpl implements Repository {
     				}
     			};
                 try {
-                    features = JaxbUtil.unmarshal(inputStream, false);
+                    features = JaxbUtil.unmarshal(uri.toASCIIString(), inputStream, validate);
                 } finally {
                     inputStream.close();
                 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
----------------------------------------------------------------------
diff --git a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
index f3ca2e6..9e33ee3 100644
--- a/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
+++ b/features/src/test/java/org/apache/karaf/features/internal/service/FeaturesValidationTest.java
@@ -16,20 +16,29 @@
  */
 package org.apache.karaf.features.internal.service;
 
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.karaf.features.Repository;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
 import org.junit.Test;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
 public class FeaturesValidationTest {
 
     @Test
-    public void testNoNs() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f01.xml").toURI());
+    public void testNs10() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
     }
 
     @Test
-    public void testNs10() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f02.xml").toURI());
+    public void testNs10Unmarshall() throws Exception {
+        URL url = getClass().getResource("f02.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
     }
 
     @Test
@@ -38,13 +47,22 @@ public class FeaturesValidationTest {
     }
 
     @Test
+    public void testNs10NoNameUnmarshall() throws Exception {
+        URL url = getClass().getResource("f03.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
     public void testNs11() throws Exception {
         FeatureValidationUtil.validate(getClass().getResource("f04.xml").toURI());
     }
 
     @Test
-    public void testNs12() throws Exception {
-        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    public void testNs11Unmarshall() throws Exception {
+        URL url = getClass().getResource("f04.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
     }
 
     @Test
@@ -58,8 +76,27 @@ public class FeaturesValidationTest {
     }
 
     @Test
+    public void testNs12() throws Exception {
+        FeatureValidationUtil.validate(getClass().getResource("f06.xml").toURI());
+    }
+
+    @Test
+    public void testNs12Unmarshall() throws Exception {
+        URL url = getClass().getResource("f06.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
+    @Test
     public void testNs13() throws Exception {
         FeatureValidationUtil.validate(getClass().getResource("f07.xml").toURI());
     }
 
+    @Test
+    public void testNs13Unmarshall() throws Exception {
+        URL url = getClass().getResource("f07.xml");
+        Features features = JaxbUtil.unmarshal(url.toExternalForm(), true);
+        assertNotNull(features);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
index c30f7c0..71ff485 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/CreateKarMojo.java
@@ -212,23 +212,18 @@ public class CreateKarMojo extends MojoSupport {
     private List<Artifact> readResources(File featuresFile) throws MojoExecutionException {
         List<Artifact> resources = new ArrayList<Artifact>();
         try {
-            InputStream in = new FileInputStream(featuresFile);
-            try {
-                Features features = JaxbUtil.unmarshal(in, false);
-                for (Feature feature : features.getFeature()) {
-                    for (BundleInfo bundle : feature.getBundles()) {
-                        if (ignoreDependencyFlag || (!ignoreDependencyFlag && !bundle.isDependency())) {
-                            resources.add(resourceToArtifact(bundle.getLocation(), false));
-                        }
-                    }
-                    for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
-                        resources.add(resourceToArtifact(configFile.getLocation(), false));
+            Features features = JaxbUtil.unmarshal(featuresFile.toURI().toASCIIString(), false);
+            for (Feature feature : features.getFeature()) {
+                for (BundleInfo bundle : feature.getBundles()) {
+                    if (ignoreDependencyFlag || (!ignoreDependencyFlag && !bundle.isDependency())) {
+                        resources.add(resourceToArtifact(bundle.getLocation(), false));
                     }
                 }
-                return resources;
-            } finally {
-                in.close();
+                for (ConfigFileInfo configFile : feature.getConfigurationFiles()) {
+                    resources.add(resourceToArtifact(configFile.getLocation(), false));
+                }
             }
+            return resources;
         } catch (MojoExecutionException e) {
             throw e;
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
index 1aff2c6..3cdae4a 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/GenerateDescriptorMojo.java
@@ -401,14 +401,7 @@ public class GenerateDescriptorMojo extends AbstractLogEnabled implements Mojo {
     }
 
     private Features readFeaturesFile(File featuresFile) throws XMLStreamException, JAXBException, IOException {
-        Features features;
-        InputStream in = new FileInputStream(featuresFile);
-        try {
-            features = JaxbUtil.unmarshal(in, false);
-        } finally {
-            in.close();
-        }
-        return features;
+        return JaxbUtil.unmarshal(featuresFile.toURI().toASCIIString(), false);
     }
 
     public void setLog(Log log) {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
index c1a6c5f..f58ca37 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
@@ -425,14 +425,7 @@ public class InstallKarsMojo extends MojoSupport {
             } else {
                 repoFile = new File(uri);
             }
-            InputStream in = new FileInputStream(repoFile);
-            Features features;
-            try {
-                features = JaxbUtil.unmarshal(in, false);
-            } finally {
-                in.close();
-            }
-            return features;
+            return JaxbUtil.unmarshal(repoFile.toURI().toASCIIString(), false);
         }
 
         public void installFeature(org.apache.karaf.features.Feature feature) throws Exception {

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
index 4b12fda..0eecbd0 100644
--- a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
+++ b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/features/GenerateDescriptorMojoTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.*;
 
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.List;
 
 import javax.xml.bind.JAXBException;
@@ -41,9 +42,9 @@ public class GenerateDescriptorMojoTest {
     @Test
     public void testReadXml100() throws JAXBException, SAXException, ParserConfigurationException, XMLStreamException {
 
-        InputStream in = getClass().getClassLoader().getResourceAsStream("input-features-1.0.0.xml");
+        URL url = getClass().getClassLoader().getResource("input-features-1.0.0.xml");
 
-        Features featuresRoot = JaxbUtil.unmarshal(in, false);
+        Features featuresRoot = JaxbUtil.unmarshal(url.toExternalForm(), false);
 
         assertEquals(featuresRoot.getRepository().size(), 1);
 
@@ -61,9 +62,9 @@ public class GenerateDescriptorMojoTest {
     @Test
     public void testReadXml1() throws Exception {
 
-        InputStream in = getClass().getClassLoader().getResourceAsStream("input-features-1.1.0.xml");
+        URL url = getClass().getClassLoader().getResource("input-features-1.1.0.xml");
 
-        Features featuresRoot = JaxbUtil.unmarshal(in, false);
+        Features featuresRoot = JaxbUtil.unmarshal(url.toExternalForm(), false);
 
         List<Feature> featuresList = featuresRoot.getFeature();
 

http://git-wip-us.apache.org/repos/asf/karaf/blob/1306af5f/util/src/main/java/org/apache/karaf/util/XmlUtils.java
----------------------------------------------------------------------
diff --git a/util/src/main/java/org/apache/karaf/util/XmlUtils.java b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
index cbcb593..adfc2e6 100644
--- a/util/src/main/java/org/apache/karaf/util/XmlUtils.java
+++ b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
@@ -16,17 +16,25 @@
  */
 package org.apache.karaf.util;
 
-import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
-import org.w3c.dom.Document;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.*;
-import java.io.File;
-import java.io.IOException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
 
 /**
  * Utils class to manipulate XML document in a thread safe way.
@@ -35,6 +43,7 @@ public class XmlUtils {
 
     private static final ThreadLocal<DocumentBuilderFactory> DOCUMENT_BUILDER_FACTORY = new ThreadLocal<DocumentBuilderFactory>();
     private static final ThreadLocal<TransformerFactory> TRANSFORMER_FACTORY = new ThreadLocal<TransformerFactory>();
+    private static final ThreadLocal<SAXParserFactory> SAX_PARSER_FACTORY = new ThreadLocal<SAXParserFactory>();
 
     public static Document parse(String uri) throws TransformerException, IOException, SAXException, ParserConfigurationException {
         DocumentBuilder db = documentBuilder();
@@ -45,6 +54,15 @@ public class XmlUtils {
         }
     }
 
+    public static Document parse(InputStream stream) throws TransformerException, IOException, SAXException, ParserConfigurationException {
+        DocumentBuilder db = documentBuilder();
+        try {
+            return db.parse(stream);
+        } finally {
+            db.reset();
+        }
+    }
+
     public static Document parse(File f) throws TransformerException, IOException, SAXException, ParserConfigurationException {
         DocumentBuilder db = documentBuilder();
         try {
@@ -82,36 +100,40 @@ public class XmlUtils {
         }
     }
 
-    private static DocumentBuilder documentBuilder() throws ParserConfigurationException {
-        DocumentBuilderFactory dbf;
-        if (DOCUMENT_BUILDER_FACTORY.get() == null) {
+    public static XMLReader xmlReader() throws ParserConfigurationException, SAXException {
+        SAXParserFactory spf = SAX_PARSER_FACTORY.get();
+        if (spf == null) {
+            spf = SAXParserFactory.newInstance();
+            spf.setNamespaceAware(true);
+            SAX_PARSER_FACTORY.set(spf);
+        }
+        return spf.newSAXParser().getXMLReader();
+    }
+
+    public static DocumentBuilder documentBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory dbf = DOCUMENT_BUILDER_FACTORY.get();
+        if (dbf == null) {
             dbf = DocumentBuilderFactory.newInstance();
             dbf.setNamespaceAware(true);
             DOCUMENT_BUILDER_FACTORY.set(dbf);
-        } else {
-            dbf = DOCUMENT_BUILDER_FACTORY.get();
         }
         return dbf.newDocumentBuilder();
     }
 
-    private static Transformer transformer() throws TransformerConfigurationException {
-        TransformerFactory tf;
-        if (TRANSFORMER_FACTORY.get() == null) {
+    public static Transformer transformer() throws TransformerConfigurationException {
+        TransformerFactory tf = TRANSFORMER_FACTORY.get();
+        if (tf == null) {
             tf = TransformerFactory.newInstance();
             TRANSFORMER_FACTORY.set(tf);
-        } else {
-            tf = TRANSFORMER_FACTORY.get();
         }
         return tf.newTransformer();
     }
 
     private static Transformer transformer(Source xsltSource) throws TransformerConfigurationException {
-        TransformerFactory tf;
-        if (TRANSFORMER_FACTORY.get() == null) {
+        TransformerFactory tf = TRANSFORMER_FACTORY.get();
+        if (tf == null) {
             tf = TransformerFactory.newInstance();
             TRANSFORMER_FACTORY.set(tf);
-        } else {
-            tf = TRANSFORMER_FACTORY.get();
         }
         return tf.newTransformer(xsltSource);
     }