@@ -19,25 +19,23 @@ package org.apache.archiva.repository.metadata; | |||
* under the License. | |||
*/ | |||
import org.apache.archiva.common.utils.FileUtils; | |||
import org.apache.archiva.model.ArchivaRepositoryMetadata; | |||
import org.apache.archiva.model.Plugin; | |||
import org.apache.archiva.repository.storage.StorageAsset; | |||
import org.apache.archiva.xml.XMLException; | |||
import org.apache.archiva.xml.XMLWriter; | |||
import org.apache.archiva.xml.XmlUtil; | |||
import org.apache.commons.collections4.CollectionUtils; | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.dom4j.Document; | |||
import org.dom4j.DocumentHelper; | |||
import org.dom4j.Element; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import java.io.FileWriter; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import java.io.IOException; | |||
import java.io.OutputStreamWriter; | |||
import java.io.Writer; | |||
import java.nio.file.Path; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.Iterator; | |||
@@ -81,10 +79,15 @@ public class RepositoryMetadataWriter | |||
public static void write( ArchivaRepositoryMetadata metadata, Writer writer ) | |||
throws RepositoryMetadataException | |||
{ | |||
Document doc = DocumentHelper.createDocument(); | |||
Document doc = null; | |||
try { | |||
doc = XmlUtil.createDocument(); | |||
} catch (ParserConfigurationException e) { | |||
throw new RepositoryMetadataException("Could not create xml doc " + e.getMessage(), e); | |||
} | |||
Element root = DocumentHelper.createElement( "metadata" ); | |||
doc.setRootElement( root ); | |||
Element root = doc.createElement( "metadata" ); | |||
doc.appendChild(root); | |||
addOptionalElementText( root, "groupId", metadata.getGroupId() ); | |||
addOptionalElementText( root, "artifactId", metadata.getArtifactId() ); | |||
@@ -92,16 +95,16 @@ public class RepositoryMetadataWriter | |||
if ( CollectionUtils.isNotEmpty( metadata.getPlugins() ) ) | |||
{ | |||
Element plugins = root.addElement( "plugins" ); | |||
Element plugins = XmlUtil.addChild(root, "plugins" ); | |||
List<Plugin> pluginList = metadata.getPlugins(); | |||
Collections.sort( pluginList, PluginComparator.INSTANCE ); | |||
for ( Plugin plugin : metadata.getPlugins() ) | |||
{ | |||
Element p = plugins.addElement( "plugin" ); | |||
p.addElement( "prefix" ).setText( plugin.getPrefix() ); | |||
p.addElement( "artifactId" ).setText( plugin.getArtifactId() ); | |||
Element p = XmlUtil.addChild(plugins, "plugin" ); | |||
XmlUtil.addChild(doc, p, "prefix" ).setTextContent( plugin.getPrefix() ); | |||
XmlUtil.addChild(doc, p, "artifactId" ).setTextContent( plugin.getArtifactId() ); | |||
addOptionalElementText( p, "name", plugin.getName() ); | |||
} | |||
} | |||
@@ -112,14 +115,14 @@ public class RepositoryMetadataWriter | |||
|| StringUtils.isNotBlank( metadata.getLastUpdated() ) // | |||
|| ( metadata.getSnapshotVersion() != null ) ) | |||
{ | |||
Element versioning = root.addElement( "versioning" ); | |||
Element versioning = XmlUtil.addChild(root, "versioning" ); | |||
addOptionalElementText( versioning, "latest", metadata.getLatestVersion() ); | |||
addOptionalElementText( versioning, "release", metadata.getReleasedVersion() ); | |||
if ( metadata.getSnapshotVersion() != null ) | |||
{ | |||
Element snapshot = versioning.addElement( "snapshot" ); | |||
Element snapshot = XmlUtil.addChild(versioning, "snapshot" ); | |||
String bnum = String.valueOf( metadata.getSnapshotVersion().getBuildNumber() ); | |||
addOptionalElementText( snapshot, "buildNumber", bnum ); | |||
addOptionalElementText( snapshot, "timestamp", metadata.getSnapshotVersion().getTimestamp() ); | |||
@@ -127,12 +130,12 @@ public class RepositoryMetadataWriter | |||
if ( CollectionUtils.isNotEmpty( metadata.getAvailableVersions() ) ) | |||
{ | |||
Element versions = versioning.addElement( "versions" ); | |||
Element versions = XmlUtil.addChild(versioning, "versions" ); | |||
Iterator<String> it = metadata.getAvailableVersions().iterator(); | |||
while ( it.hasNext() ) | |||
{ | |||
String version = it.next(); | |||
versions.addElement( "version" ).setText( version ); | |||
XmlUtil.addChild(versions, "version" ).setTextContent( version ); | |||
} | |||
} | |||
@@ -156,7 +159,7 @@ public class RepositoryMetadataWriter | |||
return; | |||
} | |||
elem.addElement( elemName ).setText( text ); | |||
XmlUtil.addChild(elem, elemName ).setTextContent( text ); | |||
} | |||
private static class PluginComparator |
@@ -42,22 +42,11 @@ | |||
<artifactId>commons-collections4</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>commons-io</groupId> | |||
<artifactId>commons-io</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>dom4j</groupId> | |||
<artifactId>dom4j</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>jaxen</groupId> | |||
<artifactId>jaxen</artifactId> | |||
<groupId>org.apache.commons</groupId> | |||
<artifactId>commons-lang3</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.codehaus.plexus</groupId> | |||
<artifactId>plexus-utils</artifactId> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.apache.archiva</groupId> | |||
<artifactId>archiva-test-utils</artifactId> | |||
<version>${project.version}</version> |
@@ -1,52 +0,0 @@ | |||
package org.apache.archiva.xml; | |||
/* | |||
* 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. | |||
*/ | |||
import org.apache.commons.collections4.Closure; | |||
import org.dom4j.Element; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* Gather the text from a collection of {@link Element}'s into a {@link List} | |||
* | |||
* | |||
*/ | |||
public class ElementTextListClosure | |||
implements Closure | |||
{ | |||
private List<String> list = new ArrayList<>(); | |||
@Override | |||
public void execute( Object input ) | |||
{ | |||
if ( input instanceof Element ) | |||
{ | |||
Element elem = (Element) input; | |||
list.add( elem.getTextTrim() ); | |||
} | |||
} | |||
public List<String> getList() | |||
{ | |||
return list; | |||
} | |||
} |
@@ -20,29 +20,28 @@ package org.apache.archiva.xml; | |||
*/ | |||
import org.apache.commons.lang3.StringUtils; | |||
import org.dom4j.Attribute; | |||
import org.dom4j.Document; | |||
import org.dom4j.DocumentException; | |||
import org.dom4j.Element; | |||
import org.dom4j.Namespace; | |||
import org.dom4j.Node; | |||
import org.dom4j.QName; | |||
import org.dom4j.XPath; | |||
import org.dom4j.io.SAXReader; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import org.w3c.dom.Node; | |||
import org.w3c.dom.NodeList; | |||
import org.xml.sax.ErrorHandler; | |||
import org.xml.sax.InputSource; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.SAXParseException; | |||
import javax.xml.XMLConstants; | |||
import javax.xml.namespace.NamespaceContext; | |||
import javax.xml.parsers.DocumentBuilder; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
import javax.xml.xpath.*; | |||
import java.io.*; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.nio.charset.Charset; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.*; | |||
import java.util.stream.Collectors; | |||
/** | |||
* XMLReader - a set of common xml utility methods for reading content out of an xml file. | |||
@@ -56,6 +55,25 @@ public class XMLReader | |||
private Document document; | |||
private Map<String, String> namespaceMap = new HashMap<>(); | |||
private Map<String, String> reverseNamespaceMap = new HashMap<>(); | |||
private class NamespaceCtx implements NamespaceContext { | |||
@Override | |||
public String getNamespaceURI(String prefix) { | |||
return namespaceMap.get(prefix); | |||
} | |||
@Override | |||
public String getPrefix(String namespaceURI) { | |||
return reverseNamespaceMap.get(namespaceURI); | |||
} | |||
@Override | |||
public Iterator getPrefixes(String namespaceURI) { | |||
return namespaceMap.keySet().iterator(); | |||
} | |||
} | |||
public XMLReader( String type, Path file ) | |||
throws XMLException | |||
@@ -97,41 +115,69 @@ public class XMLReader | |||
this.documentType = type; | |||
this.xmlUrl = url; | |||
SAXReader reader = new SAXReader(); | |||
// SAXReader reader = new SAXReader(); | |||
try (InputStream in = url.openStream()) | |||
{ | |||
InputStreamReader inReader = new InputStreamReader( in, Charset.forName( "UTF-8" ) ); | |||
LatinEntityResolutionReader latinReader = new LatinEntityResolutionReader( inReader ); | |||
this.document = reader.read( latinReader ); | |||
} | |||
catch ( DocumentException e ) | |||
try (InputStream in = url.openStream(); Reader reader = new LatinEntityResolutionReader(new BufferedReader(new InputStreamReader(in, "UTF-8")))) | |||
{ | |||
throw new XMLException( "Unable to parse " + documentType + " xml " + xmlUrl + ": " + e.getMessage(), e ); | |||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); | |||
dbf.setNamespaceAware(true); | |||
dbf.setExpandEntityReferences(false); | |||
dbf.setValidating(false); | |||
// dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD,"false"); | |||
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,true); | |||
// dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); | |||
DocumentBuilder db = dbf.newDocumentBuilder(); | |||
// To suppress error output at System.err | |||
db.setErrorHandler(new ErrorHandler() { | |||
@Override | |||
public void warning(SAXParseException exception) throws SAXException { | |||
} | |||
@Override | |||
public void error(SAXParseException exception) throws SAXException { | |||
throw exception; | |||
} | |||
@Override | |||
public void fatalError(SAXParseException exception) throws SAXException { | |||
throw exception; | |||
} | |||
}); | |||
this.document = db.parse(new InputSource(reader)); | |||
} | |||
catch ( IOException e ) | |||
{ | |||
throw new XMLException( "Unable to open stream to " + url + ": " + e.getMessage(), e ); | |||
} catch (ParserConfigurationException e) { | |||
throw new XMLException("Unable to start parser "+e.getMessage()); | |||
} catch (SAXException e) { | |||
throw new XMLException("Unable to parse file "+e.getMessage()); | |||
} | |||
Element root = this.document.getRootElement(); | |||
Element root = this.document.getDocumentElement(); | |||
if ( root == null ) | |||
{ | |||
throw new XMLException( "Invalid " + documentType + " xml: root element is null." ); | |||
} | |||
if ( !StringUtils.equals( root.getName(), documentType ) ) | |||
if ( !StringUtils.equals( root.getLocalName(), documentType ) ) | |||
{ | |||
throw new XMLException( | |||
"Invalid " + documentType + " xml: Unexpected root element <" + root.getName() + ">, expected <" | |||
+ documentType + ">" ); | |||
"Invalid " + documentType + " xml: Unexpected root element <" + root.getLocalName() + ">, expected <" | |||
+ documentType + ">" + root.getNodeName() ); | |||
} | |||
} | |||
public String getDefaultNamespaceURI() | |||
{ | |||
Namespace namespace = this.document.getRootElement().getNamespace(); | |||
return namespace.getURI(); | |||
String namespace = this.document.getNamespaceURI(); | |||
return namespace; | |||
} | |||
public void addNamespaceMapping( String elementName, String uri ) | |||
@@ -142,48 +188,55 @@ public class XMLReader | |||
public Element getElement( String xpathExpr ) | |||
throws XMLException | |||
{ | |||
XPath xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.selectSingleNode( document ); | |||
XPathExpression xpath = null; | |||
try { | |||
xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.evaluate( document, XPathConstants.NODE); | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated instanceof Element ) | |||
{ | |||
return (Element) evaluated; | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElement( Expr: " + xpathExpr + " ) resulted in non-Element type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
if ( evaluated instanceof Element ) | |||
{ | |||
return (Element) evaluated; | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElement( Expr: " + xpathExpr + " ) resulted in non-Element type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
} | |||
} catch (XPathExpressionException e) { | |||
throw new XMLException("Could not parse xpath expression"); | |||
} | |||
} | |||
private XPath createXPath( String xpathExpr ) | |||
{ | |||
XPath xpath = document.createXPath( xpathExpr ); | |||
private XPathExpression createXPath(String xpathExpr ) throws XPathExpressionException { | |||
XPath xpath = XPathFactory.newInstance().newXPath(); | |||
if ( !this.namespaceMap.isEmpty() ) | |||
{ | |||
xpath.setNamespaceURIs( this.namespaceMap ); | |||
xpath.setNamespaceContext(new NamespaceCtx()); | |||
} | |||
return xpath; | |||
return xpath.compile(xpathExpr); | |||
} | |||
public boolean hasElement( String xpathExpr ) | |||
throws XMLException | |||
{ | |||
XPath xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.selectSingleNode( document ); | |||
if ( evaluated == null ) | |||
{ | |||
return false; | |||
XPathExpression xpath = null; | |||
try { | |||
xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.evaluate( document, XPathConstants.NODE ); | |||
if ( evaluated == null ) | |||
{ | |||
return false; | |||
} | |||
return true; | |||
} catch (XPathExpressionException e) { | |||
throw new XMLException("Could not create xpath expression"); | |||
} | |||
return true; | |||
} | |||
/** | |||
@@ -191,32 +244,26 @@ public class XMLReader | |||
*/ | |||
public void removeNamespaces() | |||
{ | |||
removeNamespaces( this.document.getRootElement() ); | |||
removeNamespaces( this.document.getDocumentElement() ); | |||
} | |||
/** | |||
* Remove namespaces from element recursively. | |||
*/ | |||
@SuppressWarnings("unchecked") | |||
public void removeNamespaces( Element elem ) | |||
public void removeNamespaces( Node elem ) | |||
{ | |||
elem.setQName( QName.get( elem.getName(), Namespace.NO_NAMESPACE, elem.getQualifiedName() ) ); | |||
if (elem.getNodeType() == Node.ELEMENT_NODE || elem.getNodeType() == Node.ATTRIBUTE_NODE) { | |||
document.renameNode(elem, null, elem.getLocalName()); | |||
Node n; | |||
Node n; | |||
Iterator<Node> it = elem.elementIterator(); | |||
while ( it.hasNext() ) | |||
{ | |||
n = it.next(); | |||
NodeList nodeList = elem.getChildNodes(); | |||
switch ( n.getNodeType() ) | |||
{ | |||
case Node.ATTRIBUTE_NODE: | |||
( (Attribute) n ).setNamespace( Namespace.NO_NAMESPACE ); | |||
break; | |||
case Node.ELEMENT_NODE: | |||
removeNamespaces( (Element) n ); | |||
break; | |||
for (int i = 0; i < nodeList.getLength(); i++) { | |||
n = nodeList.item(i); | |||
removeNamespaces(n); | |||
} | |||
} | |||
} | |||
@@ -224,102 +271,74 @@ public class XMLReader | |||
public String getElementText( Node context, String xpathExpr ) | |||
throws XMLException | |||
{ | |||
XPath xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.selectSingleNode( context ); | |||
XPathExpression xpath = null; | |||
try { | |||
xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.evaluate( context, XPathConstants.NODE ); | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated instanceof Element ) | |||
{ | |||
Element evalElem = (Element) evaluated; | |||
return evalElem.getTextTrim(); | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElementText( Node, Expr: " + xpathExpr + " ) resulted in non-Element type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
if ( evaluated instanceof Element ) | |||
{ | |||
Element evalElem = (Element) evaluated; | |||
return XmlUtil.getText(evalElem); | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElementText( Node, Expr: " + xpathExpr + " ) resulted in non-Element type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
} | |||
} catch (XPathExpressionException e) { | |||
throw new XMLException("Could not parse xpath expression"); | |||
} | |||
} | |||
public String getElementText( String xpathExpr ) | |||
throws XMLException | |||
{ | |||
XPath xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.selectSingleNode( document ); | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated instanceof Element ) | |||
{ | |||
Element evalElem = (Element) evaluated; | |||
return evalElem.getTextTrim(); | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElementText( Expr: " + xpathExpr + " ) resulted in non-Element type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
} | |||
return getElementText(document, xpathExpr); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public List<Element> getElementList( String xpathExpr ) | |||
public List<Node> getElementList( String xpathExpr ) | |||
throws XMLException | |||
{ | |||
XPath xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.evaluate( document ); | |||
XPathExpression xpath = null; | |||
try { | |||
xpath = createXPath( xpathExpr ); | |||
Object evaluated = xpath.evaluate( document, XPathConstants.NODESET); | |||
if ( evaluated == null ) | |||
{ | |||
return null; | |||
} | |||
if ( evaluated == null ) | |||
{ | |||
return Collections.emptyList(); | |||
} | |||
/* The xpath.evaluate(Context) method can return: | |||
* 1) A Collection or List of dom4j Nodes. | |||
* 2) A single dom4j Node. | |||
*/ | |||
NodeList nl = (NodeList) evaluated; | |||
List<Node> nodeList = new ArrayList<>(); | |||
for (int i = 0 ; i<nl.getLength(); i++) { | |||
nodeList.add(nl.item(i)); | |||
} | |||
return nodeList; | |||
if ( evaluated instanceof List ) | |||
{ | |||
return (List<Element>) evaluated; | |||
} | |||
else if ( evaluated instanceof Node ) | |||
{ | |||
List<Element> ret = new ArrayList<>(); | |||
ret.add( (Element) evaluated ); | |||
return ret; | |||
} | |||
else | |||
{ | |||
// Unknown evaluated type. | |||
throw new XMLException( ".getElementList( Expr: " + xpathExpr + " ) resulted in non-List type -> (" | |||
+ evaluated.getClass().getName() + ") " + evaluated ); | |||
} catch (XPathExpressionException e) { | |||
throw new XMLException("Could not parse xpath expression"); | |||
} | |||
} | |||
public List<String> getElementListText( String xpathExpr ) | |||
throws XMLException | |||
{ | |||
List<Element> elemList = getElementList( xpathExpr ); | |||
List<Node> elemList = getElementList( xpathExpr ); | |||
if ( elemList == null ) | |||
{ | |||
return null; | |||
} | |||
List<String> ret = new ArrayList<>(); | |||
for ( Iterator<Element> iter = elemList.iterator(); iter.hasNext(); ) | |||
{ | |||
Element listelem = iter.next(); | |||
ret.add( listelem.getTextTrim() ); | |||
} | |||
return ret; | |||
return elemList.stream().filter(n -> n instanceof Element).map(n -> XmlUtil.getText(n)).collect(Collectors.toList()); | |||
} | |||
} |
@@ -19,67 +19,78 @@ package org.apache.archiva.xml; | |||
* under the License. | |||
*/ | |||
import org.dom4j.Document; | |||
import org.dom4j.io.OutputFormat; | |||
import org.w3c.dom.Document; | |||
import javax.xml.transform.OutputKeys; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.dom.DOMSource; | |||
import javax.xml.transform.stream.StreamResult; | |||
import java.io.IOException; | |||
import java.io.Writer; | |||
/** | |||
* XMLWriter - Making writing XML files easier. | |||
* | |||
* | |||
* XMLWriter - Making writing XML files easier. | |||
*/ | |||
public class XMLWriter | |||
{ | |||
public class XMLWriter { | |||
/** | |||
* Write the Document to the provided Writer, leaving the Writer open. | |||
* | |||
* @param doc the document to write. | |||
* | |||
* @param doc the document to write. | |||
* @param writer the writer to write to. | |||
* @throws XMLException if there was a problem writing the xml to the writer. | |||
*/ | |||
public static void write( Document doc, Writer writer ) | |||
throws XMLException | |||
{ | |||
write( doc, writer, false ); | |||
public static void write(Document doc, Writer writer) | |||
throws XMLException { | |||
write(doc, writer, false); | |||
} | |||
/** | |||
* Write the Document to the provided Writer, with an option to close the writer upon completion. | |||
* | |||
* @param doc the document to write. | |||
* | |||
* @param doc the document to write. | |||
* @param writer the writer to write to. | |||
* @param close true to close the writer on completion. | |||
* @param close true to close the writer on completion. | |||
* @throws XMLException if there was a problem writing the xml to the writer. | |||
*/ | |||
public static void write( Document doc, Writer writer, boolean close ) | |||
throws XMLException | |||
{ | |||
org.dom4j.io.XMLWriter xmlwriter = null; | |||
public static void write(Document doc, Writer writer, boolean close) | |||
throws XMLException { | |||
try | |||
{ | |||
OutputFormat outputFormat = OutputFormat.createPrettyPrint(); | |||
xmlwriter = new org.dom4j.io.XMLWriter( writer, outputFormat ); | |||
xmlwriter.write( doc ); | |||
xmlwriter.flush(); | |||
} | |||
catch ( IOException e ) | |||
{ | |||
throw new XMLException( "Unable to write xml contents to writer: " + e.getMessage(), e ); | |||
} | |||
finally | |||
{ | |||
if ( close && ( xmlwriter != null ) ) | |||
{ | |||
try | |||
{ | |||
xmlwriter.close(); | |||
} | |||
catch ( IOException e ) | |||
{ | |||
/* quietly ignore */ | |||
try { | |||
TransformerFactory transformerFactory = TransformerFactory.newInstance(); | |||
Transformer transformer = transformerFactory.newTransformer(); | |||
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); | |||
try { | |||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); | |||
} catch (IllegalArgumentException ex) { | |||
// Indent not supported | |||
} | |||
// Writing the XML declaration, because the JDK implementation does not create a newline | |||
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); | |||
StreamResult result = new StreamResult(writer); | |||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); | |||
DOMSource source = new DOMSource(doc); | |||
transformer.transform(source, result); | |||
} catch (TransformerException e) { | |||
throw new XMLException("Could not create the xml transformer: " + e.getMessage(), e); | |||
} catch (IOException e) { | |||
throw new XMLException("Could not write to xml output: " + e.getMessage(), e); | |||
} finally { | |||
if (writer!=null) { | |||
if (close) { | |||
try { | |||
writer.flush(); | |||
} catch (IOException e) { | |||
/* quietly ignore */ | |||
} | |||
try { | |||
writer.close(); | |||
} catch (IOException e) { | |||
/* quietly ignore */ | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
package org.apache.archiva.xml; | |||
/* | |||
* 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. | |||
*/ | |||
import org.w3c.dom.*; | |||
import javax.xml.parsers.DocumentBuilder; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import javax.xml.parsers.ParserConfigurationException; | |||
public class XmlUtil { | |||
public static Document createDocument() throws ParserConfigurationException { | |||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | |||
DocumentBuilder builder = factory.newDocumentBuilder(); | |||
return builder.newDocument(); | |||
} | |||
public static Element addChild(Document doc, Element parent, String name) { | |||
Element el = doc.createElement(name); | |||
parent.appendChild(el); | |||
return el; | |||
} | |||
public static Element addChild(Element parent, String name) { | |||
Document doc = parent.getOwnerDocument(); | |||
Element el = doc.createElement(name); | |||
parent.appendChild(el); | |||
return el; | |||
} | |||
public static String getText(Node element) { | |||
if (element!=null) { | |||
element.normalize(); | |||
try { | |||
String txt = element.getTextContent(); | |||
if (txt!=null) { | |||
return txt.trim(); | |||
} | |||
} catch (DOMException e) { | |||
return ""; | |||
} | |||
} | |||
return ""; | |||
} | |||
public static Node getChild(Element parent, String name) { | |||
NodeList elList = parent.getElementsByTagName(name); | |||
if (elList.getLength()>0) { | |||
return elList.item(0); | |||
} else { | |||
return null; | |||
} | |||
} | |||
public static String getChildText(Element parent, String name) { | |||
return getText(getChild(parent, name)); | |||
} | |||
} |
@@ -19,8 +19,6 @@ package org.apache.archiva.xml; | |||
* under the License. | |||
*/ | |||
import org.dom4j.DocumentException; | |||
import org.dom4j.io.SAXReader; | |||
import org.junit.Assert; | |||
import org.junit.Test; | |||
@@ -204,30 +202,6 @@ public class LatinEntityResolutionReaderTest | |||
assertProperRead( expected, "no-prolog-with-entities.xml", 409600 ); | |||
} | |||
@Test | |||
public void testReaderLeftOver() | |||
throws IOException | |||
{ | |||
Path inputFile = getExampleXml( "maven-metadata-leftover.xml" ); | |||
//Bits from RepositoryMetadataReader.read | |||
InputStream in = null; | |||
SAXReader reader = new SAXReader(); | |||
URL url = inputFile.toUri().toURL(); | |||
in = url.openStream(); | |||
InputStreamReader inReader = new InputStreamReader( in, Charset.forName( "UTF-8" ) ); | |||
LatinEntityResolutionReader latinReader = new LatinEntityResolutionReader( inReader ); | |||
try | |||
{ | |||
reader.read( latinReader ); | |||
} | |||
catch ( DocumentException e ) | |||
{ | |||
Assert.fail( "Should not have failed here." + e ); | |||
IOException ioe = new IOException(); | |||
ioe.initCause( e ); | |||
throw ioe; | |||
} | |||
} | |||
@Test | |||
public void testNoLatinEntitiesHugeLine() |
@@ -19,8 +19,9 @@ package org.apache.archiva.xml; | |||
* under the License. | |||
*/ | |||
import org.dom4j.Element; | |||
import org.junit.Test; | |||
import org.w3c.dom.Element; | |||
import org.w3c.dom.Node; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
@@ -34,14 +35,14 @@ import java.util.List; | |||
public class XMLReaderTest | |||
extends AbstractArchivaXmlTestCase | |||
{ | |||
private void assertElementTexts( List<Element> elementList, String[] expectedTexts ) | |||
private void assertElementTexts( List<Node> elementList, String[] expectedTexts ) | |||
{ | |||
assertEquals( "Element List Size", expectedTexts.length, elementList.size() ); | |||
List<String> texts = new ArrayList<>(); | |||
for ( Element element : elementList ) | |||
for ( Node element : elementList ) | |||
{ | |||
texts.add( element.getTextTrim() ); | |||
texts.add( element.getTextContent().trim()); | |||
} | |||
for ( int i = 0; i < expectedTexts.length; i++ ) | |||
@@ -58,7 +59,7 @@ public class XMLReaderTest | |||
Path xmlFile = getExampleXml( "no-prolog-basic.xml" ); | |||
XMLReader reader = new XMLReader( "basic", xmlFile ); | |||
List<Element> fruits = reader.getElementList( "//basic/fruits/fruit" ); | |||
List<Node> fruits = reader.getElementList( "//basic/fruits/fruit" ); | |||
assertElementTexts( fruits, new String[] { "apple", "cherry", "pear", "peach" } ); | |||
} | |||
@@ -69,7 +70,7 @@ public class XMLReaderTest | |||
Path xmlFile = getExampleXml( "no-prolog-with-entities.xml" ); | |||
XMLReader reader = new XMLReader( "basic", xmlFile ); | |||
List<Element> names = reader.getElementList( "//basic/names/name" ); | |||
List<Node> names = reader.getElementList( "//basic/names/name" ); | |||
assertElementTexts( names, new String[] { TRYGVIS, INFINITE_ARCHIVA } ); | |||
} | |||
@@ -80,7 +81,7 @@ public class XMLReaderTest | |||
Path xmlFile = getExampleXml( "no-prolog-with-utf8.xml" ); | |||
XMLReader reader = new XMLReader( "basic", xmlFile ); | |||
List<Element> names = reader.getElementList( "//basic/names/name" ); | |||
List<Node> names = reader.getElementList( "//basic/names/name" ); | |||
assertElementTexts( names, new String[] { TRYGVIS, INFINITE_ARCHIVA } ); | |||
} | |||
@@ -91,7 +92,7 @@ public class XMLReaderTest | |||
Path xmlFile = getExampleXml( "prolog-with-utf8.xml" ); | |||
XMLReader reader = new XMLReader( "basic", xmlFile ); | |||
List<Element> names = reader.getElementList( "//basic/names/name" ); | |||
List<Node> names = reader.getElementList( "//basic/names/name" ); | |||
assertElementTexts( names, new String[] { TRYGVIS, INFINITE_ARCHIVA } ); | |||
} | |||
@@ -104,9 +105,9 @@ public class XMLReaderTest | |||
XMLReader reader = new XMLReader( "metadata", xmlFile ); | |||
reader.removeNamespaces(); | |||
Element groupId = reader.getElement( "//metadata/groupId" ); | |||
Element groupId = (Element) reader.getElement( "//metadata/groupId" ); | |||
assertNotNull( groupId ); | |||
assertEquals( "org.codehaus.mojo", groupId.getTextTrim() ); | |||
assertEquals( "org.codehaus.mojo", groupId.getTextContent().trim() ); | |||
} | |||
} |
@@ -19,11 +19,12 @@ package org.apache.archiva.xml; | |||
* under the License. | |||
*/ | |||
import org.dom4j.Document; | |||
import org.dom4j.DocumentHelper; | |||
import org.dom4j.Element; | |||
import org.junit.Test; | |||
import org.w3c.dom.Document; | |||
import org.w3c.dom.Element; | |||
import javax.xml.parsers.DocumentBuilder; | |||
import javax.xml.parsers.DocumentBuilderFactory; | |||
import java.io.StringWriter; | |||
/** | |||
@@ -41,7 +42,6 @@ public class XMLWriterTest | |||
StringBuilder expected = new StringBuilder(); | |||
expected.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); | |||
expected.append( "\n" ); | |||
expected.append( "<basic>\n" ); | |||
expected.append( " <names>\n" ); | |||
expected.append( " <name>" ).append( TRYGVIS ).append( "</name>\n" ); | |||
@@ -49,12 +49,19 @@ public class XMLWriterTest | |||
expected.append( " </names>\n" ); | |||
expected.append( "</basic>\n" ); | |||
Element basic = DocumentHelper.createElement( "basic" ); | |||
Document doc = DocumentHelper.createDocument( basic ); | |||
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); | |||
Document doc = docBuilder.newDocument(); | |||
Element basic = doc.createElement("basic"); | |||
doc.appendChild(basic); | |||
Element names = doc.createElement( "names" ); | |||
basic.appendChild(names); | |||
Element name = doc.createElement("name"); | |||
name.setTextContent(TRYGVIS); | |||
names.appendChild(name); | |||
name = doc.createElement("name"); | |||
name.setTextContent(INFINITE_ARCHIVA); | |||
Element names = basic.addElement( "names" ); | |||
names.addElement( "name" ).setText( TRYGVIS ); | |||
names.addElement( "name" ).setText( INFINITE_ARCHIVA ); | |||
names.appendChild(name); | |||
StringWriter actual = new StringWriter(); | |||
XMLWriter.write( doc, actual ); |
@@ -24,10 +24,12 @@ import org.apache.archiva.model.SnapshotVersion; | |||
import org.apache.archiva.repository.storage.StorageAsset; | |||
import org.apache.archiva.xml.XMLException; | |||
import org.apache.archiva.xml.XMLReader; | |||
import org.apache.archiva.xml.XmlUtil; | |||
import org.apache.commons.lang3.math.NumberUtils; | |||
import org.dom4j.Element; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.w3c.dom.Element; | |||
import org.w3c.dom.Node; | |||
import java.io.IOException; | |||
import java.nio.file.Files; | |||
@@ -115,22 +117,28 @@ public class MavenMetadataReader | |||
if ( snapshotElem != null ) | |||
{ | |||
SnapshotVersion snapshot = new SnapshotVersion(); | |||
snapshot.setTimestamp( snapshotElem.elementTextTrim( "timestamp" ) ); | |||
String tmp = snapshotElem.elementTextTrim( "buildNumber" ); | |||
if ( NumberUtils.isNumber( tmp ) ) | |||
snapshot.setTimestamp(XmlUtil.getChildText(snapshotElem, "timestamp")); | |||
String buildNumber = XmlUtil.getChildText(snapshotElem, "buildNumber"); | |||
if ( NumberUtils.isCreatable( buildNumber ) ) | |||
{ | |||
snapshot.setBuildNumber( NumberUtils.toInt( tmp ) ); | |||
snapshot.setBuildNumber( NumberUtils.toInt( buildNumber ) ); | |||
} | |||
metadata.setSnapshotVersion( snapshot ); | |||
} | |||
for ( Element plugin : xml.getElementList( "//metadata/plugins/plugin" ) ) | |||
for ( Node node : xml.getElementList( "//metadata/plugins/plugin" ) ) | |||
{ | |||
Plugin p = new Plugin(); | |||
p.setPrefix( plugin.elementTextTrim( "prefix" ) ); | |||
p.setArtifactId( plugin.elementTextTrim( "artifactId" ) ); | |||
p.setName( plugin.elementTextTrim( "name" ) ); | |||
metadata.addPlugin( p ); | |||
if (node instanceof Element) { | |||
Element plugin = (Element) node; | |||
Plugin p = new Plugin(); | |||
String prefix = plugin.getElementsByTagName("prefix").item(0).getTextContent().trim(); | |||
p.setPrefix(prefix); | |||
String artifactId = plugin.getElementsByTagName("artifactId").item(0).getTextContent().trim(); | |||
p.setArtifactId(artifactId); | |||
String name = plugin.getElementsByTagName("name").item(0).getTextContent().trim(); | |||
p.setName(name); | |||
metadata.addPlugin(p); | |||
} | |||
} | |||
return metadata; |
@@ -258,7 +258,6 @@ public class RepositoryServletRepositoryGroupTest | |||
WebResponse response = getServletUnitClient().getResource( request ); | |||
Path returnedMetadata = getProjectBase().resolve( "target/test-classes/retrievedMetadataFile.xml" ); | |||
System.out.println( response.getContentAsString() ); | |||
org.apache.archiva.common.utils.FileUtils.writeStringToFile( returnedMetadata, Charset.defaultCharset(), response.getContentAsString() ); | |||
ArchivaRepositoryMetadata metadata = MavenMetadataReader.read( returnedMetadata ); | |||
@@ -285,7 +284,7 @@ public class RepositoryServletRepositoryGroupTest | |||
assertResponseOK( response ); | |||
assertThat( response.getContentAsString() ) | |||
.startsWith( "add113b0d7f8c6adb92a5015a7a3701081edf998" ); | |||
.startsWith( "f8a7a858a46887368adf0b30874de1f807d91453" ); | |||
// request the md5 checksum of the metadata | |||
request = new GetMethodWebRequest( "http://machine.com/repository/" + REPO_GROUP_WITH_VALID_REPOS + "/dummy/" | |||
@@ -295,7 +294,7 @@ public class RepositoryServletRepositoryGroupTest | |||
assertResponseOK( response ); | |||
assertThat( response.getContentAsString() ) | |||
.startsWith( "5b85ea4aa5f52bb76760041a52f98de8" ); | |||
.startsWith( "cec864b66849153dd45fddb7cdde12b2" ); | |||
} | |||
// MRM-901 |
@@ -800,9 +800,9 @@ | |||
<version>${derbyVersion}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>dom4j</groupId> | |||
<groupId>org.dom4j</groupId> | |||
<artifactId>dom4j</artifactId> | |||
<version>1.6.1</version> | |||
<version>2.1.1</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>org.hsqldb</groupId> |