ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1304039 [1/2] - in /ace/trunk/ace-deployment-provider-repositorybased/src: main/java/org/apache/ace/deployment/provider/repositorybased/ test/java/org/apache/ace/deployment/provider/repositorybased/
Date Thu, 22 Mar 2012 20:33:24 GMT
Author: marrs
Date: Thu Mar 22 20:33:24 2012
New Revision: 1304039

URL: http://svn.apache.org/viewvc?rev=1304039&view=rev
Log:
ACE-218 applied the provided patch

Added:
    ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java   (with props)
    ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java   (with props)
    ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java   (with props)
    ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java   (with props)
    ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java   (with props)
Modified:
    ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java
    ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderTest.java

Added: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java?rev=1304039&view=auto
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java (added)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java Thu Mar 22 20:33:24 2012
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.provider.repositorybased;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Provides a SAX-based push parser for obtaining all versions of the deployment packages of a certain target.
+ */
+class BaseRepositoryHandler extends DefaultHandler {
+
+    private final String m_targetID;
+
+    /** Denotes the current tag in the XML structure. */
+    private XmlTag m_currentTag;
+    /** Denotes the current version of the found target. */
+    private Version m_currentVersion;
+    /** Denotes whether or not the requested target is found. */
+    private boolean m_targetFound;
+    /** Denotes the current deployment artifact. */
+    private XmlDeploymentArtifact m_currentArtifact;
+    /** Denotes the directive key of the current deployment artifact. */
+    private String m_currentDirectiveKey;
+
+    /**
+     * Creates a new {@link BaseRepositoryHandler} instance.
+     * 
+     * @param targetID the target ID to search for, cannot be <code>null</code>.
+     */
+    public BaseRepositoryHandler(String targetID) {
+        m_targetID = targetID;
+        m_currentTag = XmlTag.unknown;
+    }
+
+    /**
+     * Parses the given text as {@link Version}.
+     * 
+     * @param text the text to parse as version, can not be <code>null</code>.
+     * @return a {@link Version} if the given text represent a correct version, never <code>null</code>.
+     */
+    static final Version parseVersion(String text) {
+        try {
+            if (text != null) {
+                return Version.parseVersion(text);
+            }
+        }
+        catch (Exception e) {
+            // Ignore; simply return an empty version to denote this invalid version...
+        }
+        return Version.emptyVersion;
+    }
+
+    @Override
+    public void startDocument() throws SAXException {
+        m_currentTag = XmlTag.unknown;
+        m_currentVersion = null;
+        m_targetFound = false;
+        m_currentArtifact = null;
+        m_currentDirectiveKey = null;
+    }
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException {
+        if (XmlTag.targetID.equals(m_currentTag)) {
+            // verify whether we're in the DP for the requested target...
+            m_targetFound = m_targetID.equals(new String(ch, start, length));
+        }
+        else if (XmlTag.version.equals(m_currentTag)) {
+            // Don't assume we've got the desired version (yet)...
+            m_currentVersion = null;
+
+            if (m_targetFound) {
+                m_currentVersion = parseAsVersion(new String(ch, start, length));
+            }
+        }
+        else if (XmlTag.url.equals(m_currentTag)) {
+            try {
+                URL artifactUrl = new URL(new String(ch, start, length));
+                m_currentArtifact = new XmlDeploymentArtifact(artifactUrl);
+            }
+            catch (MalformedURLException e) {
+                throw new SAXException("Unexpected URL!", e);
+            }
+        }
+        else if (XmlTag.directives.equals(m_currentTag)) {
+            if (m_currentArtifact == null) {
+                throw new SAXException("Unexpected directive tag!");
+            }
+            m_currentArtifact.m_directives.put(m_currentDirectiveKey, new String(ch, start, length));
+        }
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+        XmlTag tag = XmlTag.asXmlTag(qName);
+        // If the given element is an expected child of the current tag, we
+        // traverse deeper into the XML-hierarchy; otherwise, consider it an
+        // "unknown"/uninteresting child and keep the current tag as-is...
+        if (m_currentTag.isExpectedChild(tag)) {
+            m_currentTag = tag;
+        }
+
+        m_currentDirectiveKey = null;
+        // If we're parsing the directives of an artifact, take the name for
+        // later use (the literal text in this tag will be used as value)...
+        if (XmlTag.directives.equals(m_currentTag)) {
+            m_currentDirectiveKey = qName;
+        }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) throws SAXException {
+        XmlTag tag = XmlTag.asXmlTag(qName);
+        // When we're ending the current tag, traverse up to its parent...
+        if (!XmlTag.unknown.equals(tag) && (m_currentTag == tag)) {
+            m_currentTag = tag.getParent();
+        }
+
+        // Invoke the callbacks for events we're interested in...
+        if (XmlTag.version.equals(tag)) {
+            if (m_currentVersion != null && !Version.emptyVersion.equals(m_currentVersion)) {
+                // Let the version be handled (if needed)...
+                handleVersion(m_currentVersion);
+            }
+
+            // Let the currentVersion field as-is! We want to reuse it for the artifacts...
+        }
+        else if (XmlTag.deploymentArtifact.equals(tag)) {
+            if (m_currentArtifact != null) {
+                // push out the current deployment artifact...
+                handleArtifact(m_currentVersion, m_currentArtifact);
+            }
+
+            m_currentArtifact = null;
+        }
+    }
+
+    /**
+     * Allows subclasses to handle the given version of a target's deployment package.
+     * <p>By default, this method does nothing.</p>
+     * 
+     * @param version the version found, never <code>null</code>.
+     */
+    protected void handleVersion(Version version) {
+        // NO-op
+    }
+
+    /**
+     * Allows subclasses to handle the given deployment artifact for the given version of the deployment package.
+     * <p>By default, this method does nothing.</p>
+     * 
+     * @param version the version of the deployment package;
+     * @param artifact the deployment artifact itself.
+     */
+    protected void handleArtifact(Version version, XmlDeploymentArtifact artifact) {
+        // NO-op
+    }
+
+    /**
+     * Parses the given text as {@link Version}.
+     * 
+     * @param text the text to parse as version, can not be <code>null</code>.
+     * @return a {@link Version} if the given text represent a correct version,
+     *         can be <code>null</code> in case of an incorrect/empty version..
+     */
+    protected final Version parseAsVersion(String text) {
+        Version result = parseVersion(text);
+        if (Version.emptyVersion.equals(result)) {
+            return null;
+        }
+        return result;
+    }
+
+    /**
+     * Helper class to store a pair of URL and directive, in which the directive may be empty.
+     */
+    public static class XmlDeploymentArtifact {
+        final private URL m_url;
+        final private Map<String, String> m_directives;
+
+        private XmlDeploymentArtifact(URL url) {
+            m_url = url;
+            m_directives = new HashMap<String, String>();
+        }
+
+        public URL getUrl() {
+            return m_url;
+        }
+
+        public Map<String, String> getDirective() {
+            return m_directives;
+        }
+    }
+
+    /**
+     * Defines the structure of our XML (only the parts we're interested in).
+     */
+    public static enum XmlTag {
+        targetID,
+        version,
+        attributes(targetID, version),
+        url,
+        directives,
+        deploymentArtifact(url, directives),
+        artifacts(deploymentArtifact),
+        tags,
+        deploymentversion(attributes, tags, artifacts),
+        deploymentversions(deploymentversion),
+        repository(deploymentversions),
+        unknown(repository);
+
+        private final XmlTag[] m_children;
+        private XmlTag m_parent;
+
+        private XmlTag(XmlTag... possibleChildren) {
+            m_children = possibleChildren;
+            // Update the children's parent...
+            for (int i = 0; i < m_children.length; i++) {
+                m_children[i].m_parent = this;
+            }
+        }
+
+        /**
+         * Returns the parent tag of this tag.
+         * 
+         * @return a parent tag, can be <code>null</code>.
+         */
+        public XmlTag getParent() {
+            return m_parent;
+        }
+
+        /**
+         * Returns whether the given XML tag is an expected child of this tag.
+         * 
+         * @param xmlTag the XML tag to test, cannot be <code>null</code>.
+         * @return <code>true</code> if the given tag is an expected child of this tag, <code>false</code> otherwise.
+         */
+        public boolean isExpectedChild(XmlTag xmlTag) {
+            for (int i = 0; i < m_children.length; i++) {
+                if (xmlTag.equals(m_children[i])) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Provides a "safe" way of representing the given tag name as instance of this enum. If the given name does not represent a defined tag, "unknown" will be returned.
+         * 
+         * @param name the XML tag-name to represent as enum value, cannot be <code>null</code>.
+         * @return a {@link XmlTag} representation of the given tag-name, never <code>null</code>.
+         */
+        public static XmlTag asXmlTag(String name) {
+            try {
+                return valueOf(name);
+            }
+            catch (Exception e) {
+                return XmlTag.unknown;
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandler.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java?rev=1304039&view=auto
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java (added)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java Thu Mar 22 20:33:24 2012
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.provider.repositorybased;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Version;
+
+/**
+ * Provides {@link BaseRepositoryHandler} implementation that gathers all deployment
+ * artifacts of deployment packages for a specific target with a specific version.
+ */
+public class DeploymentArtifactCollector extends BaseRepositoryHandler {
+
+    private final List<Version> m_expectedVersions;
+    private final Map<Version, List<XmlDeploymentArtifact>> m_artifacts;
+
+    /**
+     * @param targetID the identification of the target to gather all artifacts for;
+     * @param versions the version of the deployment package to gather all artifacts for.
+     */
+    public DeploymentArtifactCollector(String targetID, String... versions) {
+        super(targetID);
+
+        m_artifacts = new HashMap<Version, List<XmlDeploymentArtifact>>();
+
+        m_expectedVersions = new ArrayList<Version>(versions.length);
+        for (int i = 0; i < versions.length; i++) {
+            Version v = parseVersion(versions[i]);
+            if (Version.emptyVersion.equals(v)) {
+                throw new IllegalArgumentException("Expected real version for " + versions[i]);
+            }
+            m_expectedVersions.add(v);
+        }
+    }
+
+    /**
+     * Returns all deployment artifacts of the requested target's deployment package.
+     * 
+     * @return an array with lists of all found deployment artifacts, never <code>null</code>.
+     *         The array contains the deployment artifacts per requested version, in the same
+     *         order as given in the class constructor.
+     */
+    public List<XmlDeploymentArtifact>[] getArtifacts() {
+        List<XmlDeploymentArtifact>[] result = new List[m_expectedVersions.size()];
+        int i = 0;
+        for (Version version : m_expectedVersions) {
+            List<XmlDeploymentArtifact> list = m_artifacts.get(version);
+            if (list == null) {
+                throw new IllegalArgumentException("No artifacts found for version " + version);
+            }
+            result[i++] = list;
+        }
+        return result;
+    }
+
+    @Override
+    protected void handleVersion(Version version) {
+        if (m_expectedVersions.contains(version)) {
+            List<XmlDeploymentArtifact> artifacts = m_artifacts.get(version);
+            if (artifacts == null) {
+                artifacts = new ArrayList<XmlDeploymentArtifact>();
+                m_artifacts.put(version, artifacts);
+            }
+        }
+    }
+
+    @Override
+    protected void handleArtifact(Version version, XmlDeploymentArtifact artifact) {
+        if (m_expectedVersions.contains(version)) {
+            m_artifacts.get(version).add(artifact);
+        }
+    }
+}

Propchange: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentArtifactCollector.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java?rev=1304039&view=auto
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java (added)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java Thu Mar 22 20:33:24 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.provider.repositorybased;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.Version;
+
+/**
+ * Provides {@link BaseRepositoryHandler} implementation that gathers all versions of deployment packages for a specific target.
+ */
+public class DeploymentPackageVersionCollector extends BaseRepositoryHandler {
+
+    private final List<Version> m_versions;
+
+    /**
+     * @param targetID the target to gather all deployment package versions for.
+     */
+    public DeploymentPackageVersionCollector(String targetID) {
+        super(targetID);
+
+        m_versions = new ArrayList<Version>();
+    }
+
+    /**
+     * Returns a list of all found deployment package versions.
+     * 
+     * @return a list of {@link Version}s, never <code>null</code>.
+     */
+    public List<Version> getVersions() {
+        return m_versions;
+    }
+
+    @Override
+    protected void handleVersion(Version version) {
+        m_versions.add(version);
+    }
+}

Propchange: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/DeploymentPackageVersionCollector.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java?rev=1304039&r1=1304038&r2=1304039&view=diff
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java (original)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/main/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProvider.java Thu Mar 22 20:33:24 2012
@@ -21,31 +21,24 @@ package org.apache.ace.deployment.provid
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.ref.SoftReference;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Dictionary;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import javax.xml.namespace.QName;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-import javax.xml.xpath.XPathVariableResolver;
+import javax.xml.parsers.SAXParserFactory;
 
 import org.apache.ace.client.repository.helper.bundle.BundleHelper;
 import org.apache.ace.client.repository.object.DeploymentArtifact;
 import org.apache.ace.deployment.provider.ArtifactData;
 import org.apache.ace.deployment.provider.DeploymentProvider;
 import org.apache.ace.deployment.provider.impl.ArtifactDataImpl;
+import org.apache.ace.deployment.provider.repositorybased.BaseRepositoryHandler.XmlDeploymentArtifact;
 import org.apache.ace.range.RangeIterator;
 import org.apache.ace.repository.Repository;
 import org.apache.ace.repository.ext.BackupRepository;
@@ -57,9 +50,6 @@ import org.osgi.framework.Version;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogService;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
 
 /**
  * The RepositoryBasedProvider provides version information and bundle data by the DeploymentProvider interface. It uses a
@@ -79,6 +69,11 @@ public class RepositoryBasedProvider imp
      * custom repository in the integration test.
      */
     private volatile Repository m_directRepository;
+    private final SAXParserFactory m_saxParserFactory;
+
+    public RepositoryBasedProvider() {
+        m_saxParserFactory = SAXParserFactory.newInstance();
+    }
 
     public List<ArtifactData> getBundleData(String targetId, String version) throws IllegalArgumentException, IOException {
         return getBundleData(targetId, null, version);
@@ -99,14 +94,14 @@ public class RepositoryBasedProvider imp
         List<ArtifactData> dataVersionTo = null;
         List<ArtifactData> dataVersionFrom = null;
 
-        List<URLDirectivePair>[] pairs = null;
+        List<XmlDeploymentArtifact>[] pairs = null;
         try {
             input = getRepositoryStream();
             if (versionFrom == null) {
-                pairs = getURLDirectivePairs(input, targetId, new String[] { versionTo });
+                pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionTo });
             }
             else {
-                pairs = getURLDirectivePairs(input, targetId, new String[] { versionFrom, versionTo });
+                pairs = getDeploymentArtifactPairs(input, targetId, new String[] { versionFrom, versionTo });
             }
         }
         catch (IOException ioe) {
@@ -125,24 +120,24 @@ public class RepositoryBasedProvider imp
         }
 
         if ((pairs != null) && (pairs.length > 1)) {
-            dataVersionFrom = getBundleDataByDocument(pairs[0]);
-            dataVersionTo = getBundleDataByDocument(pairs[1]);
+            dataVersionFrom = getAllArtifactData(pairs[0]);
+            dataVersionTo = getAllArtifactData(pairs[1]);
             Iterator<ArtifactData> it = dataVersionTo.iterator();
             while (it.hasNext()) {
                 ArtifactDataImpl bundleDataVersionTo = (ArtifactDataImpl) it.next();
                 // see if there was previously a version of this bundle, and update the 'changed' property accordingly.
                 if (bundleDataVersionTo.isBundle()) {
-                    ArtifactData bundleDataVersionFrom = getBundleData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
+                    ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getSymbolicName(), dataVersionFrom);
                     bundleDataVersionTo.setChanged(!bundleDataVersionTo.equals(bundleDataVersionFrom));
                 }
                 else {
-                    ArtifactData bundleDataVersionFrom = getBundleData(bundleDataVersionTo.getUrl(), dataVersionFrom);
+                    ArtifactData bundleDataVersionFrom = getArtifactData(bundleDataVersionTo.getUrl(), dataVersionFrom);
                     bundleDataVersionTo.setChanged(bundleDataVersionFrom == null);
                 }
             }
         }
         else {
-            dataVersionTo = getBundleDataByDocument(pairs[0]);
+            dataVersionTo = getAllArtifactData(pairs[0]);
         }
 
         return dataVersionTo != null ? dataVersionTo : new ArrayList<ArtifactData>();
@@ -196,17 +191,17 @@ public class RepositoryBasedProvider imp
      * @param input An input stream to the XML data to be parsed.
      * @return A list of ArtifactData object representing this version.
      */
-    private List<ArtifactData> getBundleDataByDocument(List<URLDirectivePair> urlDirectivePairs) throws IllegalArgumentException {
+    private List<ArtifactData> getAllArtifactData(List<XmlDeploymentArtifact> deploymentArtifacts) throws IllegalArgumentException {
         List<ArtifactData> result = new ArrayList<ArtifactData>();
 
         // get the bundledata for each URL
-        for (URLDirectivePair pair : urlDirectivePairs) {
+        for (XmlDeploymentArtifact pair : deploymentArtifacts) {
             Map<String, String> directives = pair.getDirective();
 
             if (directives.get(DeploymentArtifact.DIRECTIVE_KEY_PROCESSORID) == null) {
                 // this is a bundle.
-                String symbolicName = directives.remove(BundleHelper.KEY_SYMBOLICNAME);
-                String bundleVersion = directives.remove(BundleHelper.KEY_VERSION);
+                String symbolicName = directives.get(BundleHelper.KEY_SYMBOLICNAME);
+                String bundleVersion = directives.get(BundleHelper.KEY_VERSION);
                 if (symbolicName != null) {
                     // it is the right symbolic name
                     if (symbolicName.trim().equals("")) {
@@ -219,7 +214,7 @@ public class RepositoryBasedProvider imp
             }
             else {
                 // it is an artifact.
-                String filename = directives.remove(DeploymentArtifact.DIRECTIVE_KEY_RESOURCE_ID);
+                String filename = directives.get(DeploymentArtifact.DIRECTIVE_KEY_RESOURCE_ID);
                 result.add(new ArtifactDataImpl(filename, pair.getUrl(), directives, true));
             }
 
@@ -234,7 +229,7 @@ public class RepositoryBasedProvider imp
      * @return The <code>ArtifactData</code> object that has this <code>url</code>, or <code>null</code> if none can be
      *         found.
      */
-    private ArtifactData getBundleData(URL url, Collection<ArtifactData> data) {
+    private ArtifactData getArtifactData(URL url, Collection<ArtifactData> data) {
         ArtifactData bundle = null;
         Iterator<ArtifactData> it = data.iterator();
         while (it.hasNext()) {
@@ -253,7 +248,7 @@ public class RepositoryBasedProvider imp
      * @return The <code>ArtifactData</code> object that has this <code>symbolicName</code>, or <code>null</code> if none
      *         can be found.
      */
-    private ArtifactData getBundleData(String symbolicName, Collection<ArtifactData> data) {
+    private ArtifactData getArtifactData(String symbolicName, Collection<ArtifactData> data) {
         ArtifactData bundle = null;
         Iterator<ArtifactData> it = data.iterator();
         while (it.hasNext()) {
@@ -273,191 +268,15 @@ public class RepositoryBasedProvider imp
      * @return A list of available versions
      */
     private List<Version> getAvailableVersions(InputStream input, String targetId) throws IllegalArgumentException {
-        //result list
-        List<Version> versionList = new ArrayList<Version>();
-        XPathContext context = XPathContext.getInstance();
-
+        DeploymentPackageVersionCollector collector = new DeploymentPackageVersionCollector(targetId);
+        
         try {
-            NodeList versions = context.getVersions(targetId, input);
-            if (versions != null) {
-                for (int j = 0; j < versions.getLength(); j++) {
-                    Node n = versions.item(j);
-                    String versionValue = n.getTextContent();
-                    try {
-                        Version version = Version.parseVersion(versionValue);
-                        // no exception, but is could still be an empty version
-                        if (!version.equals(Version.emptyVersion)) {
-                            versionList.add(version);
-                        }
-                    }
-                    catch (NumberFormatException nfe) {
-                        // Ignore this version
-                        m_log.log(LogService.LOG_WARNING, "Deploymentversion ignored: ", nfe);
-                    }
-                }
-            }
-
-            return versionList;
+            m_saxParserFactory.newSAXParser().parse(input, collector);
+            
+            return collector.getVersions();
         }
-        catch (XPathExpressionException xee) {
-            throw new IllegalArgumentException(xee);
-        }
-        finally {
-            context.destroy();
-        }
-    }
-
-    /*
-     * This class is used to cache compiled xpath expression for the queries we need on a per thread basis. In order
-     * to do this a thread local is used to cache an instance of this class per calling thread. The reference to this
-     * instance is wrapped in a soft reference to make it possible to GC the instance in case memory is low.
-     * <p>
-     * Example Usage:
-     * <pre>
-     * XPathContext context = XPathContext.getInstance();
-     *
-     * try
-     * {
-     *     // to get all artifacts of a number of versions:
-     *     context.init(targetId, versions, input);
-     *
-     *     for (int i = 0; i < versions.length; i++)
-     *     {
-     *         Node version = context.getVersion(i);
-     *         // Do work with version
-     *     }
-     *     // to get all versions of a number of a target:
-     *     NodeList versions = context.getVersions(targetId, input);
-     *     // Do work with versions
-     * }
-     * finally
-     * {
-     *     context.destory();
-     * }
-     * </pre>
-     */
-    private static final class XPathContext implements XPathVariableResolver {
-        private static final ThreadLocal<SoftReference<XPathContext>> m_cache = new ThreadLocal<SoftReference<XPathContext>>();
-
-        private final XPath m_xPath = XPathFactory.newInstance().newXPath();
-
-        private final XPathExpression m_attributesExpression;
-
-        private final XPathExpression m_versionsExpression;
-
-        private final Map<Integer, XPathExpression> m_expressions = new HashMap<Integer, XPathExpression>();
-
-        private String m_targetId;
-
-        private String[] m_versions;
-
-        private Node m_node;
-
-        private String m_version;
-
-        private XPathContext() {
-            m_xPath.setXPathVariableResolver(this);
-            try {
-                m_attributesExpression = m_xPath.compile("//deploymentversions/deploymentversion/attributes/child::targetID[text()=$id]/../child::version[text()=$version]/../../artifacts");
-                m_versionsExpression = m_xPath.compile("//deploymentversions/deploymentversion/attributes/child::targetID[text()=$id]/parent::attributes/version/text()");
-            }
-            catch (XPathExpressionException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        /**
-         * @return A thread local instance from the cache.
-         */
-        public static XPathContext getInstance() {
-            SoftReference<XPathContext> ref = m_cache.get();
-            XPathContext instance = null;
-            if (ref != null) {
-                instance = ref.get();
-            }
-
-            if (instance == null) {
-                ref = null;
-                instance = new XPathContext();
-            }
-
-            if (ref == null) {
-                m_cache.set(new SoftReference<XPathContext>(instance));
-            }
-
-            return instance;
-        }
-
-        /**
-         * @param targetId the id of the target
-         * @param input the stream to read repository from
-         * @return  the versions in the repo for the given targetId or null if none
-         * @throws javax.xml.xpath.XPathExpressionException in case something goes wrong
-         */
-        public NodeList getVersions(String targetId, InputStream input) throws XPathExpressionException {
-            m_targetId = targetId;
-            return (NodeList) m_versionsExpression.evaluate(new InputSource(input), XPathConstants.NODESET);
-        }
-
-        /**
-         * @param targetId the id of the target
-         * @param versions the versions to return
-         * @param input the stream to read repository from
-         * @return true if versions can be found, otherwise false
-         * @throws javax.xml.xpath.XPathExpressionException if something goes wrong
-         */
-        @SuppressWarnings("boxing")
-        public boolean init(String targetId, String[] versions, InputStream input) throws XPathExpressionException {
-            XPathExpression expression = m_expressions.get(versions.length);
-            if (expression == null) {
-                StringBuilder versionStatement = new StringBuilder("//deploymentversions/deploymentversion/attributes/child::targetID[text()=$id]/following::version[text()=$0");
-                for (int i = 1; i < versions.length; i++) {
-                    versionStatement.append(" or ").append(".=$").append(i);
-                }
-                versionStatement.append("]/../../..");
-                expression = m_xPath.compile(versionStatement.toString());
-                m_expressions.put(versions.length, expression);
-            }
-            m_targetId = targetId;
-            m_versions = versions;
-
-            m_node = (Node) expression.evaluate(new InputSource(input), XPathConstants.NODE);
-            return (m_node != null);
-        }
-
-        /**
-         *  @param i the index into the versions form init
-         *  @return the version at index i
-         * @throws javax.xml.xpath.XPathExpressionException if something goes wrong
-         */
-        public Node getVersion(int i) throws XPathExpressionException {
-            m_version = m_versions[i];
-            return (Node) m_attributesExpression.evaluate(m_node, XPathConstants.NODE);
-        }
-
-        /**
-         * reset this thread local instance
-         */
-        public void destroy() {
-            m_node = null;
-            m_version = null;
-            m_targetId = null;
-            m_versions = null;
-        }
-
-        /**
-         * @param name id|version|<version-index>
-         * @return id->targetId | version->version | version-index -> versions[version-index]
-         */
-        public Object resolveVariable(QName name) {
-            String localPart = name.getLocalPart();
-            if ("id".equals(localPart)) {
-                return m_targetId;
-            }
-            else if ("version".equals(localPart)) {
-                return m_version;
-            }
-            return m_versions[Integer.parseInt(localPart)];
+        catch (Exception e) {
+            throw new IllegalArgumentException(e);
         }
     }
 
@@ -473,76 +292,16 @@ public class RepositoryBasedProvider imp
      * @throws IllegalArgumentException if the targetId or versions cannot be found in the input stream, or if
      *         <code>input</code> does not contain an XML stream.
      */
-    @SuppressWarnings("unchecked")
-    private List<URLDirectivePair>[] getURLDirectivePairs(InputStream input, String targetId, String[] versions) throws IllegalArgumentException {
-
-        XPathContext context = XPathContext.getInstance();
-        List<URLDirectivePair>[] result = new List[versions.length]; //unfortunately, we cannot use a typed list array.
-
+    private List<XmlDeploymentArtifact>[] getDeploymentArtifactPairs(InputStream input, String targetId, String[] versions) throws IllegalArgumentException {
+        final DeploymentArtifactCollector collector = new DeploymentArtifactCollector(targetId, versions);
+        
         try {
-            if (!context.init(targetId, versions, input)) {
-                m_log.log(LogService.LOG_WARNING, "Versions not found for target: " + targetId);
-                throw new IllegalArgumentException("Versions not found.");
-            }
-            for (int i = 0; i < versions.length; i++) {
-                result[i] = new ArrayList<URLDirectivePair>();
+            m_saxParserFactory.newSAXParser().parse(input, collector);
 
-                // find all artifacts for the version we're currently working on.
-                Node artifactNode = null;
-                try {
-                    artifactNode = context.getVersion(i);
-                }
-                catch (XPathExpressionException e) {
-                    m_log.log(LogService.LOG_WARNING, "Version " + versions[i] + " not found for target: " + targetId);
-                    continue;
-                }
-                NodeList artifacts = artifactNode.getChildNodes();
-                // Read the artifacts
-                for (int artifactNumber = 0; artifactNumber < artifacts.getLength(); artifactNumber++) {
-                    Node artifact = artifacts.item(artifactNumber);
-
-                    NodeList artifactElements = artifact.getChildNodes();
-
-                    String url = null;
-                    Map<String, String> directives = new HashMap<String, String>();
-
-                    for (int elementNumber = 0; elementNumber < artifactElements.getLength(); elementNumber++) {
-                        // find the attributes of this artifact we are interested in.
-                        Node element = artifactElements.item(elementNumber);
-
-                        if (element.getNodeName().equals("url")) {
-                            url = element.getTextContent();
-                        }
-                        else if (element.getNodeName().equals("directives")) {
-                            // we found the directives? put all of them into our map.
-                            NodeList directivesElements = element.getChildNodes();
-                            for (int nDirective = 0; nDirective < directivesElements.getLength(); nDirective++) {
-                                Node directivesElement = directivesElements.item(nDirective);
-                                if (!"#text".equals(directivesElement.getNodeName())) {
-                                    directives.put(directivesElement.getNodeName(), directivesElement.getTextContent());
-                                }
-                            }
-                        }
-                    }
-
-                    if (url != null) {
-                        try {
-                            result[i].add(new URLDirectivePair(new URL(url), directives));
-                        }
-                        catch (MalformedURLException mue) {
-                            m_log.log(LogService.LOG_WARNING, "The BundleUrl is malformed: ", mue);
-                        }
-                    }
-                }
-            }
-
-            return result;
+            return collector.getArtifacts();
         }
-        catch (XPathExpressionException ex) {
-            throw new IllegalArgumentException(ex);
-        }
-        finally {
-            context.destroy();
+        catch (Exception e) {
+            throw new IllegalArgumentException(e);
         }
     }
 
@@ -603,10 +362,8 @@ public class RepositoryBasedProvider imp
                 // We always create the remote repository. If we can create a backup repository, we will wrap a CachedRepository
                 // around it.
                 m_directRepository = new RemoteRepository(new URL(url), customer, name);
-                if (backup == null) {
-                    m_cachedRepository = null;
-                }
-                else {
+                m_cachedRepository = null;
+                if (backup != null) {
                     m_cachedRepository = new CachedRepositoryImpl(null, m_directRepository, backup, CachedRepositoryImpl.UNCOMMITTED_VERSION);
                 }
             }
@@ -626,26 +383,4 @@ public class RepositoryBasedProvider imp
         }
         return result;
     }
-
-    /**
-     * Helper class to store a pair of URL and directive, in which the directive may be empty.
-     */
-    private class URLDirectivePair {
-        final private URL m_url;
-
-        final private Map<String, String> m_directives;
-
-        URLDirectivePair(URL url, Map<String, String> directives) {
-            m_url = url;
-            m_directives = directives;
-        }
-
-        public URL getUrl() {
-            return m_url;
-        }
-
-        public Map<String, String> getDirective() {
-            return m_directives;
-        }
-    }
 }
\ No newline at end of file

Added: ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java?rev=1304039&view=auto
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java (added)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java Thu Mar 22 20:33:24 2012
@@ -0,0 +1,362 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.provider.repositorybased;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.deployment.provider.repositorybased.BaseRepositoryHandler.XmlDeploymentArtifact;
+import org.osgi.framework.Version;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Test cases for {@link BaseRepositoryHandler}.
+ */
+public class BaseRepositoryHandlerTest {
+
+    private static final String TAGS_TAG = "tags";
+    private static final String VERSION_TAG = "version";
+    private static final String TARGETID_TAG = "targetID";
+    private static final String ARTIFACTS_TAG = "artifacts";
+    private static final String ARTIFACT_TAG = "deploymentArtifact";
+    private static final String URL_TAG = "url";
+    private static final String DIRECTIVES_TAG = "directives";
+    private static final String ATTRIBUTES_TAG = "attributes";
+    private static final String DEPLOYMENTVERSION_TAG = "deploymentversion";
+
+    private static final String TARGET = "target";
+    private static final String MULTIPLEVERSIONTARGET = "multi-version-target";
+    private static final String EMPTYVERSIONTARGET = "empty-version-target";
+
+    private static final String VERSION1 = "1.0.0";
+    private static final String VERSION2 = "2.0.0";
+    private static final String VERSION3 = "3.0.0";
+    private static final String VERSION3_2 = "3.2.0";
+    private static final String VERSION4 = "4.0.0";
+    private static final String VERSION4_1 = "4.1.0";
+    private static final String VERSION4_2 = "4.2.0";
+    private static final String VERSION5 = "5.0.0";
+
+    private InputStream m_inputStream;
+    private SAXParser m_parser;
+
+    @BeforeMethod(alwaysRun = true)
+    protected void setUp() throws Exception {
+        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+        m_parser = saxParserFactory.newSAXParser();
+
+        String xml = generateValidTestXml();
+        m_inputStream = new ByteArrayInputStream(xml.getBytes());
+    }
+
+    /**
+     * Tests that a deployment package with a single version can be parsed & found.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherSingleVersionOk() throws Exception {
+        DeploymentPackageVersionCollector handler = new DeploymentPackageVersionCollector(TARGET);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<Version> versions = handler.getVersions();
+        assert versions.size() == 1 : "Expected a single version to be found!";
+
+        assert Version.parseVersion(VERSION1).equals(versions.get(0)) : "Expected version1 to be found!";
+    }
+
+    /**
+     * Tests that the single artifact of a deployment package with a single version can be parsed & found.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherSingleArtifactOk() throws Exception {
+        DeploymentArtifactCollector handler = new DeploymentArtifactCollector(TARGET, VERSION1);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<XmlDeploymentArtifact>[] artifacts = handler.getArtifacts();
+        assert artifacts.length == 1 : "Expected a single artifact to be found!";
+        assert artifacts[0].size() == 1 : "Expected a single artifact to be found!";
+
+        XmlDeploymentArtifact artifact1 = artifacts[0].get(0);
+        assert new URL("file:///bundle1").equals(artifact1.getUrl()) : "Expected 'file:///bundle1' URL to be found!";
+        assert artifact1.getDirective().size() == 2 : "Expected two directives to be found!";
+        assert "bundle1".equals(artifact1.getDirective().get(BundleHelper.KEY_SYMBOLICNAME)) : "Expected correct symbolic name to be found!";
+        assert "1.0.0".equals(artifact1.getDirective().get(BundleHelper.KEY_VERSION)) : "Expected correct bundle version to be found!";
+    }
+
+    /**
+     * Tests that a deployment package with multiple versions can be parsed & found.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherMultipleVersionOk() throws Exception {
+        DeploymentPackageVersionCollector handler = new DeploymentPackageVersionCollector(MULTIPLEVERSIONTARGET);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<Version> versions = handler.getVersions();
+        assert versions.size() == 4 : "Expected four versions to be found!";
+
+        assert Version.parseVersion(VERSION1).equals(versions.get(0)) : "Expected version1 to be found!";
+        assert Version.parseVersion(VERSION2).equals(versions.get(1)) : "Expected version2 to be found!";
+        assert Version.parseVersion(VERSION3).equals(versions.get(2)) : "Expected version3 to be found!";
+        assert Version.parseVersion(VERSION4).equals(versions.get(3)) : "Expected version4 to be found!";
+    }
+
+    /**
+     * Tests that multiple artifacts of a deployment package with a single version can be parsed & found.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherMultipleArtifactsOfMultipleVersionTargetOk() throws Exception {
+        DeploymentArtifactCollector handler = new DeploymentArtifactCollector(MULTIPLEVERSIONTARGET, VERSION2);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<XmlDeploymentArtifact>[] artifacts = handler.getArtifacts();
+        assert artifacts.length == 1 : "Expected two artifacts to be found!";
+        assert artifacts[0].size() == 2 : "Expected two artifacts to be found!";
+
+        XmlDeploymentArtifact artifact1 = artifacts[0].get(0);
+        assert new URL("file:///bundle4.1").equals(artifact1.getUrl()) : "Expected 'file:///bundle4.1' URL to be found!";
+        assert artifact1.getDirective().size() == 2 : "Expected two directives to be found!";
+        assert "bundle4.1".equals(artifact1.getDirective().get(BundleHelper.KEY_SYMBOLICNAME)) : "Expected correct symbolic name to be found!";
+        assert "4.1.0".equals(artifact1.getDirective().get(BundleHelper.KEY_VERSION)) : "Expected correct bundle version to be found!";
+
+        XmlDeploymentArtifact artifact2 = artifacts[0].get(1);
+        assert new URL("file:///bundle5").equals(artifact2.getUrl()) : "Expected 'file:///bundle5' URL to be found!";
+        assert artifact2.getDirective().size() == 2 : "Expected two directives to be found!";
+        assert "bundle5".equals(artifact2.getDirective().get(BundleHelper.KEY_SYMBOLICNAME)) : "Expected correct symbolic name to be found!";
+        assert "5.0.0".equals(artifact2.getDirective().get(BundleHelper.KEY_VERSION)) : "Expected correct bundle version to be found!";
+    }
+
+    /**
+     * Tests that single artifact of a deployment package with multiple versions can be parsed & found.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherSingleArtifactsOfMultipleVersionTargetOk() throws Exception {
+        DeploymentArtifactCollector handler = new DeploymentArtifactCollector(MULTIPLEVERSIONTARGET, VERSION3);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<XmlDeploymentArtifact>[] artifacts = handler.getArtifacts();
+        assert artifacts.length == 1 : "Expected a single artifact to be found!";
+        assert artifacts[0].size() == 1 : "Expected a single artifact to be found!";
+
+        XmlDeploymentArtifact artifact1 = artifacts[0].get(0);
+        assert new URL("file:///bundle4").equals(artifact1.getUrl()) : "Expected 'file:///bundle4' URL to be found!";
+        assert artifact1.getDirective().size() == 2 : "Expected two directives to be found!";
+        assert "bundle4".equals(artifact1.getDirective().get(BundleHelper.KEY_SYMBOLICNAME)) : "Expected correct symbolic name to be found!";
+        assert "4.0.0".equals(artifact1.getDirective().get(BundleHelper.KEY_VERSION)) : "Expected correct bundle version to be found!";
+    }
+
+    /**
+     * Tests that non existing artifacts of a deployment package with multiple versions can be parsed.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherNonExistingArtifactsOfMultipleVersionTargetOk() throws Exception {
+        DeploymentArtifactCollector handler = new DeploymentArtifactCollector(EMPTYVERSIONTARGET, VERSION2);
+
+        m_parser.parse(m_inputStream, handler);
+
+        List<XmlDeploymentArtifact>[] artifacts = handler.getArtifacts();
+        assert artifacts.length == 1 : "Expected a single artifact to be found!";
+        assert artifacts[0].isEmpty() : "Expected no deployment artifacts to be found!";
+    }
+
+    /**
+     * Tests that requesting the artifacts of a deployment package with an invalid version can be done.
+     * 
+     * @throws Exception not part of this test case.
+     */
+    @Test(groups = { UNIT })
+    public void testGatherArtifactsOfMultipleVersionTargetWithInvalidVersionOk() throws Exception {
+        DeploymentArtifactCollector handler = new DeploymentArtifactCollector(EMPTYVERSIONTARGET, VERSION3);
+        
+        m_parser.parse(m_inputStream, handler);
+        
+        try {
+            handler.getArtifacts();
+            
+            assert false : "Expected no deployment artifacts to be found!";
+        }
+        catch (IllegalArgumentException e) {
+            // Ok; expected...
+        }
+    }
+
+    /**
+     * @return a valid repository XML; never <code>null</code>.
+     */
+    private String generateValidTestXml() {
+        Document doc = null;
+        try {
+            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+            doc = docBuilder.newDocument();
+        }
+        catch (ParserConfigurationException e) {
+            // Should not happen
+            e.printStackTrace();
+        }
+
+        // create the root element
+        Element root = doc.createElement("repository");
+        doc.appendChild(root);
+
+        // create the versions element
+        Element versions = doc.createElement("deploymentversions");
+        root.appendChild(versions);
+
+        // create deployment versions
+        versions.appendChild(generateDeploymentVersion(doc, TARGET, VERSION1, new String[] { "file:///bundle1",
+            BundleHelper.KEY_SYMBOLICNAME, "bundle1", BundleHelper.KEY_VERSION, VERSION1 }));
+
+        versions.appendChild(generateDeploymentVersion(doc, MULTIPLEVERSIONTARGET, VERSION1, new String[] {
+            "file:///bundle3", BundleHelper.KEY_SYMBOLICNAME, "bundle3", BundleHelper.KEY_VERSION, VERSION3 },
+            new String[] { "file:///bundle4", BundleHelper.KEY_SYMBOLICNAME, "bundle4", BundleHelper.KEY_VERSION,
+                VERSION4 }));
+        versions.appendChild(generateDeploymentVersion(doc, MULTIPLEVERSIONTARGET, VERSION2, new String[] {
+            "file:///bundle4.1", BundleHelper.KEY_SYMBOLICNAME, "bundle4.1", BundleHelper.KEY_VERSION, VERSION4_1 },
+            new String[] { "file:///bundle5", BundleHelper.KEY_SYMBOLICNAME, "bundle5", BundleHelper.KEY_VERSION,
+                VERSION5 }));
+        versions.appendChild(generateDeploymentVersion(doc, MULTIPLEVERSIONTARGET, VERSION3, new String[] {
+            "file:///bundle4", BundleHelper.KEY_SYMBOLICNAME, "bundle4", BundleHelper.KEY_VERSION, VERSION4 }));
+        versions.appendChild(generateDeploymentVersion(doc, MULTIPLEVERSIONTARGET, VERSION4, new String[] {
+            "file:///bundle3.2", BundleHelper.KEY_SYMBOLICNAME, "bundle3.2", BundleHelper.KEY_VERSION, VERSION3_2 },
+            new String[] { "file:///bundle4.2", BundleHelper.KEY_SYMBOLICNAME, "bundle4.2", BundleHelper.KEY_VERSION,
+                VERSION4_2 }));
+
+        // Add a valid deployment version (5.0.0) with no bundle urls (empty package)
+        versions.appendChild(generateDeploymentVersion(doc, EMPTYVERSIONTARGET, VERSION1, new String[] {
+            "file:///bundle1", BundleHelper.KEY_SYMBOLICNAME, "bundle1", BundleHelper.KEY_VERSION, VERSION1 }));
+        versions.appendChild(generateDeploymentVersion(doc, EMPTYVERSIONTARGET, VERSION2));
+
+        // transform the document to string
+        TransformerFactory tFactory = TransformerFactory.newInstance();
+        Transformer transformer = null;
+        StringWriter sw = null;
+        try {
+            transformer = tFactory.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.setOutputProperty(OutputKeys.INDENT, "no");
+            DOMSource source = new DOMSource(doc);
+            sw = new StringWriter();
+            StreamResult result = new StreamResult(sw);
+            transformer.transform(source, result);
+        }
+        catch (TransformerConfigurationException e) {
+            // Should not happen
+            e.printStackTrace();
+        }
+        catch (TransformerException e) {
+            // Should not happen
+            e.printStackTrace();
+        }
+
+        return sw.toString();
+    }
+
+    /**
+     * Helper method to create the description of a deploymentpacakge with given data.
+     * 
+     * @param doc The document to add the version to.
+     * @param targetText The targetId in the deploymentversion.
+     * @param versionText The version in the deploymentversion.
+     * @param data An array of data for the deployment artifact. [0] is the url, and each following item is
+     *        first a directive key, and a directive value. For example,<br>
+     *        <code>new String[] { "http://mybundle", "somedirective", "somevalue" }</code>
+     * @return
+     */
+    private Node generateDeploymentVersion(Document doc, String targetText, String versionText, String[]... data) {
+        Element deploymentversion = doc.createElement(DEPLOYMENTVERSION_TAG);
+        Element attr = doc.createElement(ATTRIBUTES_TAG);
+        deploymentversion.appendChild(attr);
+
+        // Create and add targetId Tag
+        Element elem = null;
+        elem = doc.createElement(TARGETID_TAG);
+        elem.setTextContent(targetText);
+        attr.appendChild(elem);
+
+        // Create and add versionTag
+        elem = doc.createElement(VERSION_TAG);
+        elem.setTextContent(versionText);
+        attr.appendChild(elem);
+
+        // Create and add empty tagsTag to deploymentversion
+        elem = doc.createElement(TAGS_TAG);
+        deploymentversion.appendChild(elem);
+
+        // create and add bundlesTag
+        elem = doc.createElement(ARTIFACTS_TAG);
+        for (String[] s : data) {
+            Element artifact = doc.createElement(ARTIFACT_TAG);
+            Element url = doc.createElement(URL_TAG);
+            url.setTextContent(s[0]);
+            artifact.appendChild(url);
+            Element directives = doc.createElement(DIRECTIVES_TAG);
+            for (int i = 1; i < s.length; i += 2) {
+                Element directive = doc.createElement(s[i]);
+                directive.setTextContent(s[i + 1]);
+                directives.appendChild(directive);
+            }
+            artifact.appendChild(directives);
+            elem.appendChild(artifact);
+        }
+
+        deploymentversion.appendChild(elem);
+
+        return deploymentversion;
+    }
+
+}

Propchange: ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/BaseRepositoryHandlerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java?rev=1304039&view=auto
==============================================================================
--- ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java (added)
+++ ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java Thu Mar 22 20:33:24 2012
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.provider.repositorybased;
+
+import static org.apache.ace.test.utils.TestUtils.*;
+
+import java.io.StringWriter;
+import java.util.Collection;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.client.repository.object.DeploymentArtifact;
+import org.apache.ace.deployment.provider.ArtifactData;
+import org.apache.ace.repository.Repository;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.framework.Version;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class RepositoryBasedProviderPerformanceTest {
+
+    private static final String TAGS_TAG = "tags";
+    private static final String VERSION_TAG = "version";
+    private static final String TARGETID_TAG = "targetID";
+    private static final String ARTIFACTS_TAG = "artifacts";
+    private static final String ARTIFACT_TAG = "deploymentArtifact";
+    private static final String URL_TAG = "url";
+    private static final String DIRECTIVES_TAG = "directives";
+    private static final String ATTRIBUTES_TAG = "attributes";
+    private static final String DEPLOYMENTVERSION_TAG = "deploymentversion";
+
+    private static final String TARGET = "target";
+    private static final String RESOURCETARGET = "resource-target";
+
+    private RepositoryBasedProvider m_backend;
+
+    /**
+     * Sets up for the test cases.
+     */
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        // setup mock repository
+        String range = "1-100000";
+        Repository mock = new MockDeploymentRepository(range, generateHugeTestXml());
+        m_backend = new RepositoryBasedProvider();
+        TestUtils.configureObject(m_backend, Repository.class, mock);
+        TestUtils.configureObject(m_backend, LogService.class);
+    }
+    
+    /**
+     * Test the getBundleData for a single version, returning a single bundle, for a huge XML.
+     */
+    @Test(groups = { PERFORMANCE }, timeOut = 2000 /* millis */)
+    public void testSingleBundleSingleVersionBundleDataFromHugeXml() throws Exception {
+        // will parse the entire XML structure;
+        // with XPath queries, it takes about 115 seconds of time;
+        // with a SAX parser, it takes about 0.9(!) seconds of time.
+        Collection<ArtifactData> bundleData = m_backend.getBundleData(TARGET, "44.0.0");
+        assert bundleData.size() == 1 : "Expected one bundle to be found, but found " + bundleData.size();
+    }
+
+    /**
+     * Test the getBundleData for a single version, returning a single bundle, for a huge XML.
+     */
+    @Test(groups = { PERFORMANCE }, timeOut = 3000 /* millis */)
+    public void testSingleBundleMultipleVersionBundleDataFromHugeXml() throws Exception {
+        // will parse the entire XML structure;
+        // with XPath queries, it takes about 115 seconds of time;
+        // with a SAX parser, it takes about 0.9(!) seconds of time.
+        Collection<ArtifactData> bundleData = m_backend.getBundleData(TARGET, "40.0.0", "44.6.0");
+        assert bundleData.size() == 1 : "Expected one bundle to be found, but found " + bundleData.size();
+    }
+
+    /**
+     * @return a "huge" XML repository, with lots of deployment versions (approx. 10000) for a single target.
+     */
+    private String generateHugeTestXml() throws Exception {
+        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+        Document doc = docBuilder.newDocument();
+
+        // create the root element
+        Element root = doc.createElement("repository");
+        doc.appendChild(root);
+
+        // create the versions element
+        Element versions = doc.createElement("deploymentversions");
+        root.appendChild(versions);
+
+        String bundleUrl = "file:///path/to/bundle1";
+        String symName = "my-test-bundle1";
+
+        // create deployment versions
+        for (int i = 0; i < 10000; i++) {
+            Version dpVersion = new Version(i / 100, i % 100, 0);
+            Version bundleVersion = new Version(i / 100, i % 100, 1);
+            versions.appendChild(generateDeploymentVersion(doc, TARGET, dpVersion.toString(),
+                new String[] { bundleUrl, BundleHelper.KEY_SYMBOLICNAME, symName, BundleHelper.KEY_VERSION,
+                    bundleVersion.toString() }));
+        }
+
+        String rpUrl = "file:///path/to/rp";
+        String artUrl = "file:///path/to/artifact";
+        String rpSymName = "my-test-rp1";
+
+        versions.appendChild(generateDeploymentVersion(doc, RESOURCETARGET, "1.0.0",
+            new String[] { bundleUrl, BundleHelper.KEY_SYMBOLICNAME, symName, BundleHelper.KEY_VERSION, "1.0.1" },
+            new String[] { rpUrl, DeploymentArtifact.DIRECTIVE_ISCUSTOMIZER, "true", BundleHelper.KEY_SYMBOLICNAME, rpSymName, BundleHelper.KEY_VERSION, "1.0.2" },
+            new String[] { artUrl, DeploymentArtifact.DIRECTIVE_KEY_PROCESSORID, "my.processor.pid" },
+            new String[] { artUrl, DeploymentArtifact.DIRECTIVE_KEY_RESOURCE_ID, "Artifact2", DeploymentArtifact.DIRECTIVE_KEY_PROCESSORID, "my.processor.pid" }));
+
+        // transform the document to string
+        TransformerFactory tFactory = TransformerFactory.newInstance();
+        Transformer transformer = tFactory.newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        transformer.setOutputProperty(OutputKeys.INDENT, "no");
+        DOMSource source = new DOMSource(doc);
+
+        StringWriter sw = new StringWriter();
+        StreamResult result = new StreamResult(sw);
+        transformer.transform(source, result);
+
+        return sw.toString();
+    }
+
+    /**
+     * Helper method to create the description of a deploymentpacakge with given data.
+     * 
+     * @param doc The document to add the version to.
+     * @param targetText The targetId in the deploymentversion.
+     * @param versionText The version in the deploymentversion.
+     * @param data An array of data for the deployment artifact. [0] is the url, and each following item is
+     *        first a directive key, and a directive value. For example,<br>
+     *        <code>new String[] { "http://mybundle", "somedirective", "somevalue" }</code>
+     * @return
+     */
+    private Node generateDeploymentVersion(Document doc, String targetText, String versionText, String[]... data) {
+        Element deploymentversion = doc.createElement(DEPLOYMENTVERSION_TAG);
+        Element attr = doc.createElement(ATTRIBUTES_TAG);
+        deploymentversion.appendChild(attr);
+
+        // Create and add targetId Tag
+        Element elem = null;
+        elem = doc.createElement(TARGETID_TAG);
+        elem.setTextContent(targetText);
+        attr.appendChild(elem);
+
+        // Create and add versionTag
+        elem = doc.createElement(VERSION_TAG);
+        elem.setTextContent(versionText);
+        attr.appendChild(elem);
+
+        // Create and add empty tagsTag to deploymentversion
+        elem = doc.createElement(TAGS_TAG);
+        deploymentversion.appendChild(elem);
+
+        // create and add bundlesTag
+        elem = doc.createElement(ARTIFACTS_TAG);
+        for (String[] s : data) {
+            Element artifact = doc.createElement(ARTIFACT_TAG);
+            Element url = doc.createElement(URL_TAG);
+            url.setTextContent(s[0]);
+            artifact.appendChild(url);
+            Element directives = doc.createElement(DIRECTIVES_TAG);
+            for (int i = 1; i < s.length; i += 2) {
+                Element directive = doc.createElement(s[i]);
+                directive.setTextContent(s[i + 1]);
+                directives.appendChild(directive);
+            }
+            artifact.appendChild(directives);
+            elem.appendChild(artifact);
+        }
+
+        deploymentversion.appendChild(elem);
+
+        return deploymentversion;
+    }
+}

Propchange: ace/trunk/ace-deployment-provider-repositorybased/src/test/java/org/apache/ace/deployment/provider/repositorybased/RepositoryBasedProviderPerformanceTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Mime
View raw message