diff --git a/src/main/java/com/versionone/apiclient/AssetType.java b/src/main/java/com/versionone/apiclient/AssetType.java index 51521ea1..6d0755c3 100644 --- a/src/main/java/com/versionone/apiclient/AssetType.java +++ b/src/main/java/com/versionone/apiclient/AssetType.java @@ -1,18 +1,16 @@ package com.versionone.apiclient; -import java.util.Map; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Element; - import com.versionone.apiclient.exceptions.MetaException; import com.versionone.apiclient.interfaces.IAssetType; import com.versionone.apiclient.interfaces.IAttributeDefinition; import com.versionone.apiclient.interfaces.IMetaModel; import com.versionone.apiclient.interfaces.IOperation; +import com.versionone.util.XPathFactoryInstanceHolder; +import org.w3c.dom.Element; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import java.util.Map; /** * Represents information about an asset type @@ -51,7 +49,7 @@ public AssetType(IMetaModel meta, Element element, Map map) throws Exception { _displayname = element.getAttribute("displayname"); _token = element.getAttribute("token"); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); Element baseelement = (Element)xpath.evaluate("Base", element, XPathConstants.NODE); if (baseelement != null) _basetoken = baseelement.getAttribute("nameref"); diff --git a/src/main/java/com/versionone/apiclient/AttributeDefinition.java b/src/main/java/com/versionone/apiclient/AttributeDefinition.java index 1ae03c70..50aab8d7 100644 --- a/src/main/java/com/versionone/apiclient/AttributeDefinition.java +++ b/src/main/java/com/versionone/apiclient/AttributeDefinition.java @@ -1,11 +1,5 @@ package com.versionone.apiclient; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Element; - import com.versionone.DB; import com.versionone.Duration; import com.versionone.Oid; @@ -18,6 +12,11 @@ import com.versionone.apiclient.interfaces.IAttributeDefinition; import com.versionone.apiclient.interfaces.IMetaModel; import com.versionone.apiclient.services.TextBuilder; +import com.versionone.util.XPathFactoryInstanceHolder; +import org.w3c.dom.Element; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; /** * Represents the definition of an Attribute @@ -61,7 +60,7 @@ public AttributeDefinition(IMetaModel meta, Element element) throws Exception { _isrequired = new DB.Bit(element.getAttribute("isrequired")).booleanValue(); _ismultivalue = new DB.Bit(element.getAttribute("ismultivalue")).booleanValue(); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); Element baseelement = (Element)xpath.evaluate("Base", element, XPathConstants.NODE); if (baseelement != null) _basetoken = baseelement.getAttribute("tokenref"); diff --git a/src/main/java/com/versionone/apiclient/MetaModel.java b/src/main/java/com/versionone/apiclient/MetaModel.java index be70b263..ea3f90cf 100644 --- a/src/main/java/com/versionone/apiclient/MetaModel.java +++ b/src/main/java/com/versionone/apiclient/MetaModel.java @@ -1,34 +1,28 @@ package com.versionone.apiclient; -import java.io.IOException; -import java.io.Reader; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - import com.versionone.apiclient.exceptions.ConnectionException; import com.versionone.apiclient.exceptions.MetaException; import com.versionone.apiclient.exceptions.V1Exception; -import com.versionone.apiclient.interfaces.IAPIConnector; -import com.versionone.apiclient.interfaces.IAssetType; -import com.versionone.apiclient.interfaces.IAttributeDefinition; -import com.versionone.apiclient.interfaces.IMetaModel; -import com.versionone.apiclient.interfaces.IOperation; +import com.versionone.apiclient.interfaces.*; import com.versionone.apiclient.services.TextBuilder; +import com.versionone.util.XPathFactoryInstanceHolder; import com.versionone.utils.Version; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import java.io.IOException; +import java.io.Reader; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Concrete class for obtaining metadata from the VersionOne server */ public class MetaModel implements IMetaModel { - private Map _map = new HashMap(); + private Map _map = new ConcurrentHashMap<>(); private IAPIConnector _connector; private Version _version; private String _versionString = null; @@ -189,7 +183,7 @@ private IAssetType hookupAssetType(String token) throws Exception { AssetType assetType = new AssetType(this, doc.getDocumentElement(), _map); saveAssetType(assetType); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); NodeList attribnodes = (NodeList) xpath.evaluate("AttributeDefinition", doc.getDocumentElement(), XPathConstants.NODESET); for (int attrIndex = 0; attrIndex < attribnodes.getLength(); ++attrIndex) saveAttributeDefinition(new AttributeDefinition(this, (Element) attribnodes.item(attrIndex))); @@ -219,7 +213,7 @@ private void hookup() { try { Document doc = this.createDocument(""); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); NodeList assetnodes = (NodeList) xpath.evaluate("//AssetType", doc.getDocumentElement(), XPathConstants.NODESET); for (int assetIndex = 0; assetIndex < assetnodes.getLength(); ++assetIndex) { Element element = (Element) assetnodes.item(assetIndex); diff --git a/src/main/java/com/versionone/apiclient/Services.java b/src/main/java/com/versionone/apiclient/Services.java index f1b97ec8..57b033b6 100644 --- a/src/main/java/com/versionone/apiclient/Services.java +++ b/src/main/java/com/versionone/apiclient/Services.java @@ -1,27 +1,14 @@ package com.versionone.apiclient; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -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 com.versionone.DB; +import com.versionone.Oid; +import com.versionone.apiclient.exceptions.*; +import com.versionone.apiclient.filters.FilterTerm; +import com.versionone.apiclient.interfaces.*; +import com.versionone.apiclient.services.QueryResult; +import com.versionone.apiclient.services.QueryURLBuilder; +import com.versionone.util.XPathFactoryInstanceHolder; +import com.versionone.utils.V1Util; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.NullArgumentException; import org.apache.commons.lang.StringUtils; @@ -31,24 +18,10 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import com.versionone.DB; -import com.versionone.Oid; -import com.versionone.apiclient.exceptions.APIException; -import com.versionone.apiclient.exceptions.ConnectionException; -import com.versionone.apiclient.exceptions.MetaException; -import com.versionone.apiclient.exceptions.NotImplementedException; -import com.versionone.apiclient.exceptions.OidException; -import com.versionone.apiclient.exceptions.V1Exception; -import com.versionone.apiclient.filters.FilterTerm; -import com.versionone.apiclient.interfaces.IAPIConnector; -import com.versionone.apiclient.interfaces.IAssetType; -import com.versionone.apiclient.interfaces.IAttributeDefinition; -import com.versionone.apiclient.interfaces.IMetaModel; -import com.versionone.apiclient.interfaces.IOperation; -import com.versionone.apiclient.interfaces.IServices; -import com.versionone.apiclient.services.QueryResult; -import com.versionone.apiclient.services.QueryURLBuilder; -import com.versionone.utils.V1Util; +import javax.xml.xpath.*; +import java.io.*; +import java.net.URLEncoder; +import java.util.*; /** * Wraps the services available in the VersionOne API @@ -483,7 +456,7 @@ private QueryResult parseAssetListQueryResult(Element element, Query query) thro int total = Integer.parseInt(element.getAttribute("total")); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); NodeList nodes; try { removeEmptyTextNodes(element); diff --git a/src/main/java/com/versionone/apiclient/V1Configuration.java b/src/main/java/com/versionone/apiclient/V1Configuration.java index ce7491eb..563fd02b 100644 --- a/src/main/java/com/versionone/apiclient/V1Configuration.java +++ b/src/main/java/com/versionone/apiclient/V1Configuration.java @@ -1,20 +1,15 @@ package com.versionone.apiclient; -import java.io.Reader; - -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 org.apache.commons.lang.NullArgumentException; -import org.w3c.dom.Document; - import com.versionone.apiclient.exceptions.APIException; import com.versionone.apiclient.exceptions.ConnectionException; import com.versionone.apiclient.interfaces.IAPIConnector; import com.versionone.apiclient.interfaces.IV1Configuration; +import com.versionone.util.XPathFactoryInstanceHolder; +import org.apache.commons.lang.NullArgumentException; +import org.w3c.dom.Document; + +import javax.xml.xpath.*; +import java.io.Reader; /** * Class to access to VersionOne server configuration @@ -130,7 +125,7 @@ public String getCapacityPlanning() throws ConnectionException, APIException { private String getSetting(String keyToFind) throws ConnectionException, APIException { try { - XPathFactory factory = XPathFactory.newInstance(); + XPathFactory factory = XPathFactoryInstanceHolder.get(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//Configuration/Setting[@key=\"" + keyToFind + "\"]/@value"); diff --git a/src/main/java/com/versionone/util/XPathFactoryInstanceHolder.java b/src/main/java/com/versionone/util/XPathFactoryInstanceHolder.java new file mode 100644 index 00000000..14d3606c --- /dev/null +++ b/src/main/java/com/versionone/util/XPathFactoryInstanceHolder.java @@ -0,0 +1,30 @@ +package com.versionone.util; + +import javax.xml.xpath.XPathFactory; + +/** + * Holding a XmlFactory instance using ThreadLocal. + *

+ * This approach to fix issues that VersionOne always call {@link XPathFactory#newInstance()} whenever they use it. + * + * @author tuanle + * + */ +public class XPathFactoryInstanceHolder { + private static final ThreadLocal xpathFactoryInstanceHolder = new ThreadLocal(); + + /** + * Get or create new instance of XPathFactory. + * + * @return + */ + public static XPathFactory get() { + XPathFactory factory = xpathFactoryInstanceHolder.get(); + if (null == factory) { + factory = XPathFactory.newInstance(); + xpathFactoryInstanceHolder.set(factory); + } + return factory; + } + +} diff --git a/src/test/java/com/versionone/sdk/unit/tests/ResponseConnector.java b/src/test/java/com/versionone/sdk/unit/tests/ResponseConnector.java index 70e09338..f0bddfc1 100644 --- a/src/test/java/com/versionone/sdk/unit/tests/ResponseConnector.java +++ b/src/test/java/com/versionone/sdk/unit/tests/ResponseConnector.java @@ -1,13 +1,11 @@ package com.versionone.sdk.unit.tests; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.StringReader; -import java.util.HashMap; -import java.util.Map; +import com.versionone.apiclient.exceptions.ConnectionException; +import com.versionone.apiclient.exceptions.NotImplementedException; +import com.versionone.apiclient.interfaces.IAPIConnector; +import com.versionone.util.XPathFactoryInstanceHolder; +import org.w3c.dom.*; +import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -15,20 +13,9 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; -import org.xml.sax.SAXException; - -import com.versionone.apiclient.exceptions.ConnectionException; -import com.versionone.apiclient.exceptions.NotImplementedException; -import com.versionone.apiclient.interfaces.IAPIConnector; +import java.io.*; +import java.util.HashMap; +import java.util.Map; public class ResponseConnector implements IAPIConnector { @@ -58,7 +45,7 @@ public ResponseConnector(String datafile, String prefix, String keys, IResolveCo String[] parts = keys.split(";"); - XPath xpath = XPathFactory.newInstance().newXPath(); + XPath xpath = XPathFactoryInstanceHolder.get().newXPath(); for(String part : parts) { NodeList nodes = (NodeList)xpath.evaluate("Test[@name='" + part + "']", doc.getDocumentElement(), XPathConstants.NODESET);