build: Remove unused dependencies and modules (#141)
parent
c95c0d56ea
commit
f000ed5aa6
|
|
@ -1,56 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
This program and the accompanying materials are made
|
||||
available under the terms of the Eclipse Public License 2.0
|
||||
which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
|
||||
SPDX-License-Identifier: EPL-2.0
|
||||
|
||||
Contributors:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>che-core-commons-parent</artifactId>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<version>7.37.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>che-core-commons-xml</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Che Core :: Commons :: XML</name>
|
||||
<properties>
|
||||
<findbugs.failonerror>false</findbugs.failonerror>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mycila</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/test-xml-files/**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
/** @author Eugene Voevodin */
|
||||
public final class Attribute {
|
||||
|
||||
private final Element container;
|
||||
private final QName name;
|
||||
private String value;
|
||||
|
||||
Attribute(Element container, String name, String value) {
|
||||
this.name = new QName(name);
|
||||
this.container = container;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name.getName();
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return name.getPrefix();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Element getElement() {
|
||||
return container;
|
||||
}
|
||||
|
||||
public boolean hasPrefix() {
|
||||
return name.hasPrefix();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
container.removeAttribute(name.getName());
|
||||
}
|
||||
|
||||
public Attribute setValue(String value) {
|
||||
this.value = value;
|
||||
container.setAttributeValue(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (hasPrefix()) {
|
||||
sb.append(getPrefix()).append(':');
|
||||
}
|
||||
return sb.append(name).append('=').append('"').append(value).append('"').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,830 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2021 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE;
|
||||
import static javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.asElement;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.asElements;
|
||||
import static org.w3c.dom.Node.DOCUMENT_NODE;
|
||||
import static org.w3c.dom.Node.ELEMENT_NODE;
|
||||
import static org.w3c.dom.Node.TEXT_NODE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import org.eclipse.che.commons.xml.XMLTree.Segment;
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* XMLTree element which provides abilities to fetch and update xml document data.
|
||||
*
|
||||
* <p>Delegates for related {@link org.w3c.dom.Element}
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public final class Element {
|
||||
|
||||
private final XMLTree xmlTree;
|
||||
|
||||
Segment start;
|
||||
Segment end;
|
||||
List<Segment> text;
|
||||
|
||||
org.w3c.dom.Element delegate;
|
||||
|
||||
Element(XMLTree xmlTree) {
|
||||
this.xmlTree = xmlTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns name of element as <i>prefix:name</i>. If element doesn't have prefix only local name
|
||||
* will be returned
|
||||
*
|
||||
* @return name of element tag as <i>prefix:name</i>
|
||||
* @throws XMLTreeException when {@link #remove()} has been invoked on this element instance
|
||||
* @see org.w3c.dom.Element#getTagName()
|
||||
*/
|
||||
public String getName() {
|
||||
checkNotRemoved();
|
||||
return delegate.getTagName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns local name of element
|
||||
*
|
||||
* @return element local name
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @see org.w3c.dom.Element#getLocalName()
|
||||
*/
|
||||
public String getLocalName() {
|
||||
checkNotRemoved();
|
||||
return delegate.getLocalName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element name prefix or {@code null} if element name is not prefixed
|
||||
*
|
||||
* @return element name prefix
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @see org.w3c.dom.Element#getPrefix()
|
||||
*/
|
||||
public String getPrefix() {
|
||||
checkNotRemoved();
|
||||
return delegate.getPrefix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element parent or {@code null} if element doesn't have parent.
|
||||
*
|
||||
* @return element parent or {@code null} if element is xml root
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element getParent() {
|
||||
checkNotRemoved();
|
||||
return asElement(delegate.getParentNode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for element sibling with given name. If more than one sibling was found throws {@link
|
||||
* XMLTreeException}. If sibling with given name doesn't exist returns {@code null}.
|
||||
*
|
||||
* <p>Note that {@link #getName} method used to compare element names.
|
||||
*
|
||||
* @param name sibling name to search
|
||||
* @return element sibling with given name or {@code null} if sibling with given <i>name</i> was
|
||||
* not found
|
||||
* @throws XMLTreeException when element has more than one sibling with given <i>name</i> or this
|
||||
* element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public Element getSingleSibling(String name) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(name, "Non-null sibling name required.");
|
||||
Element target = null;
|
||||
for (Element sibling : asElements(delegate.getParentNode().getChildNodes())) {
|
||||
if (this != sibling && sibling.getName().equals(name)) {
|
||||
if (target != null) {
|
||||
throw new XMLTreeException(
|
||||
"Element " + name + " has more than one sibling with name " + name);
|
||||
}
|
||||
target = sibling;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for element child with given name. If element has more then only child with given name
|
||||
* then {@link XMLTreeException} will be thrown. If child with given name doesn't exist returns
|
||||
* {@code null}
|
||||
*
|
||||
* <p>Note that {@link #getName} method used to compare element names.
|
||||
*
|
||||
* @param name name to search child
|
||||
* @return child element with given name or {@code null} if element with given name was not found
|
||||
* @throws XMLTreeException when element has more than one child with given <i>name</i> or this
|
||||
* element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public Element getSingleChild(String name) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(name, "Non-null child name required.");
|
||||
for (Element child : asElements(delegate.getChildNodes())) {
|
||||
if (name.equals(child.getName())) {
|
||||
if (child.hasSibling(name)) {
|
||||
throw new XMLTreeException(
|
||||
"Element " + name + " has more than one child with the name " + name);
|
||||
}
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last element child or {@code null} if element doesn't have children
|
||||
*
|
||||
* @return last child element or {@code null} if this element doesn't have children
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element getLastChild() {
|
||||
checkNotRemoved();
|
||||
final Node lastChild = delegate.getLastChild();
|
||||
if (lastChild != null && lastChild.getNodeType() != ELEMENT_NODE) {
|
||||
return asElement(previousElementNode(lastChild));
|
||||
}
|
||||
return asElement(lastChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first element child or {@code null} if element doesn't have children
|
||||
*
|
||||
* @return first child element or {@code null} if this element doesn't have children
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element getFirstChild() {
|
||||
checkNotRemoved();
|
||||
final Node firstChild = delegate.getFirstChild();
|
||||
if (firstChild.getNodeType() != ELEMENT_NODE) {
|
||||
return asElement(nextElementNode(firstChild));
|
||||
}
|
||||
return asElement(firstChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element children or empty list when element doesn't have children
|
||||
*
|
||||
* @return list of element children
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public List<Element> getChildren() {
|
||||
checkNotRemoved();
|
||||
return asElements(delegate.getChildNodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns children mapped with given mapper or empty list when element doesn't have children
|
||||
*
|
||||
* @param mapper function which will be applied on each child element
|
||||
* @param <R> mapper result type
|
||||
* @return list of element children which are mapped with given mapper
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public <R> List<R> getChildren(ElementMapper<? extends R> mapper) {
|
||||
checkNotRemoved();
|
||||
return asElements(delegate.getChildNodes(), mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element text content.
|
||||
*
|
||||
* <p>Note that only element text going to be fetched, no CDATA or children text content.
|
||||
*
|
||||
* @return element text content
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public String getText() {
|
||||
checkNotRemoved();
|
||||
return fetchText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element has at least one sibling with given name, otherwise returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @return {@code true} if element has at least one singling with given name, otherwise {@code
|
||||
* false}.
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public boolean hasSibling(String name) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(name, "Non-null sibling name required.");
|
||||
final NodeList nodes = delegate.getParentNode().getChildNodes();
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
if (nodes.item(i) != delegate && name.equals(nodes.item(i).getNodeName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this element instance is xml root element, otherwise returns {@code
|
||||
* false}
|
||||
*
|
||||
* @return {@code true} if element has parent, otherwise {@code false}
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public boolean hasParent() {
|
||||
checkNotRemoved();
|
||||
return delegate.getParentNode() != null
|
||||
&& delegate.getParentNode().getNodeType() != DOCUMENT_NODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns previous element sibling or {@code null} when element doesn't have previous sibling
|
||||
*
|
||||
* @return previous element sibling or {@code null} when element doesn't have previous sibling
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element getPreviousSibling() {
|
||||
checkNotRemoved();
|
||||
return asElement(previousElementNode(delegate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next element sibling or {@code null} if element doesn't have next sibling
|
||||
*
|
||||
* @return next element sibling or {@code null} if element doesn't have next sibling
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element getNextSibling() {
|
||||
checkNotRemoved();
|
||||
return asElement(nextElementNode(delegate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element attributes or empty list if element doesn't have attributes.
|
||||
*
|
||||
* <p>When element doesn't have attributes returns {@link java.util.Collections#emptyList()} which
|
||||
* is unmodifiable, so clients should not use list 'update' methods.
|
||||
*
|
||||
* @return list of element attributes or empty list if element doesn't have attributes
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public List<Attribute> getAttributes() {
|
||||
checkNotRemoved();
|
||||
if (delegate != null && delegate.hasAttributes()) {
|
||||
final NamedNodeMap attributes = delegate.getAttributes();
|
||||
final List<Attribute> copy = new ArrayList<>(attributes.getLength());
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
final Node item = attributes.item(i);
|
||||
copy.add(asAttribute(item));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of element sibling or empty list if element doesn't have siblings.
|
||||
*
|
||||
* @return list of element sibling
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public List<Element> getSiblings() {
|
||||
checkNotRemoved();
|
||||
final List<Element> siblings = asElements(delegate.getParentNode().getChildNodes());
|
||||
siblings.remove(asElement(delegate));
|
||||
return siblings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element has at least one child with given name, otherwise returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @param name child name to check
|
||||
* @return {@code true} if element has at least one child with given name, otherwise {@code false}
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public boolean hasChild(String name) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(name, "Non-null child name required.");
|
||||
final NodeList nodes = delegate.getChildNodes();
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
if (name.equals(nodes.item(i).getNodeName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element has at least one child or {@code false} if doesn't
|
||||
*
|
||||
* @return {@code true} if element has at least one child or {@code false} if doesn't
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public boolean hasChildren() {
|
||||
checkNotRemoved();
|
||||
final NodeList childNodes = delegate.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
if (childNodes.item(i).getNodeType() == ELEMENT_NODE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new text content to element
|
||||
*
|
||||
* @param newText new text content
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when newText parameter is {@code null}
|
||||
*/
|
||||
public Element setText(String newText) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(newText, "Non-null new text required.");
|
||||
if (!newText.equals(getText())) {
|
||||
removeTextNodes();
|
||||
delegate.appendChild(document().createTextNode(newText));
|
||||
// let tree do dirty job
|
||||
xmlTree.updateText(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text content of child with given name.
|
||||
*
|
||||
* @param childName child name to fetch text content
|
||||
* @return child text or {@code null} if child doesn't exist or element has more then only child
|
||||
* with given name
|
||||
*/
|
||||
public String getChildText(String childName) {
|
||||
return getChildTextOrDefault(childName, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns text content of child with given name or default value if child doesn't exist or it has
|
||||
* sibling with same name
|
||||
*
|
||||
* @param childName name of child
|
||||
* @param defaultValue value which will be returned if child doesn't exist or it has sibling with
|
||||
* same name
|
||||
* @return child text
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when childName parameter is {@code null}
|
||||
*/
|
||||
public String getChildTextOrDefault(String childName, String defaultValue) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(childName, "Non-null child name required.");
|
||||
return hasSingleChild(childName) ? getSingleChild(childName).getText() : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element has only sibling with given name or {@code false} if element
|
||||
* has more then 1 or 0 siblings with given name
|
||||
*
|
||||
* @param childName name of sibling
|
||||
* @return {@code true} if element has only sibling with given name otherwise {@code false}
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when childName parameter is {@code null}
|
||||
*/
|
||||
public boolean hasSingleChild(String childName) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(childName, "Non-null child name required.");
|
||||
for (Element child : asElements(delegate.getChildNodes())) {
|
||||
if (childName.equals(child.getName())) {
|
||||
return !child.hasSibling(childName);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes single element child. If child does not exist nothing will be done
|
||||
*
|
||||
* @param name child name to removeElement
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element removeChild(String name) {
|
||||
checkNotRemoved();
|
||||
final Element child = getSingleChild(name);
|
||||
if (child != null) {
|
||||
child.remove();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes current element and related children from xml
|
||||
*
|
||||
* @throws XMLTreeException when this element has been removed from xml tree or this element is
|
||||
* root element
|
||||
*/
|
||||
public void remove() {
|
||||
checkNotRemoved();
|
||||
notPermittedOnRootElement();
|
||||
if (hasChildren()) {
|
||||
for (Element element : getChildren()) {
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
// let tree do dirty job
|
||||
xmlTree.removeElement(this);
|
||||
// remove self from document
|
||||
delegate.getParentNode().removeChild(delegate);
|
||||
// if references to 'this' element exist
|
||||
// we should disallow ability to use delegate
|
||||
delegate = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes children which names equal to given name
|
||||
*
|
||||
* @param name name to remove children
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element removeChildren(String name) {
|
||||
checkNotRemoved();
|
||||
final List<Node> matched = new LinkedList<>();
|
||||
final NodeList nodes = delegate.getChildNodes();
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
if (name.equals(nodes.item(i).getNodeName())) {
|
||||
matched.add(nodes.item(i));
|
||||
}
|
||||
}
|
||||
for (Node node : matched) {
|
||||
asElement(node).remove();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new attribute to element. If element has attribute with given name attribute value will be
|
||||
* replaced with new value
|
||||
*
|
||||
* @param name attribute name
|
||||
* @param value attribute value
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element setAttribute(String name, String value) {
|
||||
return setAttribute(new NewAttribute(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets new attribute to element. If element has attribute with {@code newAttribute#name} then
|
||||
* existing attribute value will be replaced with {@code newAttribute#value}.
|
||||
*
|
||||
* @param newAttribute attribute that should be added to element
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public Element setAttribute(NewAttribute newAttribute) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(newAttribute, "Required not null new attribute");
|
||||
// if tree already contains element replace value
|
||||
if (hasAttribute(newAttribute.getName())) {
|
||||
final Attribute attr = getAttribute(newAttribute.getName());
|
||||
attr.setValue(newAttribute.getValue());
|
||||
return this;
|
||||
}
|
||||
//
|
||||
if (newAttribute.hasPrefix()) {
|
||||
delegate.setAttributeNodeNS(createAttrNSNode(newAttribute));
|
||||
} else {
|
||||
delegate.setAttributeNode(createAttrNode(newAttribute));
|
||||
}
|
||||
// let tree do dirty job
|
||||
xmlTree.insertAttribute(newAttribute, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes attribute with given name. If element doesn't have attribute with given name nothing
|
||||
* will be done.
|
||||
*
|
||||
* @param name name of attribute which should be removed from element
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public Element removeAttribute(String name) {
|
||||
checkNotRemoved();
|
||||
final Attribute attribute = getAttribute(name);
|
||||
if (attribute != null) {
|
||||
xmlTree.removeAttribute(attribute);
|
||||
delegate.getAttributes().removeNamedItem(name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element has attribute with given name
|
||||
*
|
||||
* @param name name of attribute to check
|
||||
* @return {@code true} if element has attribute with {@code name} otherwise {@code false}
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
*/
|
||||
public boolean hasAttribute(String name) {
|
||||
checkNotRemoved();
|
||||
return delegate.hasAttribute(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if element doesn't have closing tag i.e {@literal <element
|
||||
* attr="value"/>}, otherwise {@code false}
|
||||
*/
|
||||
public boolean isVoid() {
|
||||
return start.equals(end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns attribute with given name or {@code null} if element doesn't have such attribute
|
||||
*
|
||||
* @param name name to search attribute
|
||||
* @return attribute with {@code name} or {@code null} if nothing found
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when name parameter is {@code null}
|
||||
*/
|
||||
public Attribute getAttribute(String name) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(name, "Non-null new attribute name required.");
|
||||
if (delegate.hasAttributes()) {
|
||||
return asAttribute(getAttributeNode(name));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this element with new one.
|
||||
*
|
||||
* @param newElement new element which is replacement for current element
|
||||
* @return newly created element
|
||||
* @throws XMLTreeException when this element has been removed from xml tree or this element is
|
||||
* root element
|
||||
* @throws NullPointerException when newElement parameter is {@code null}
|
||||
*/
|
||||
public Element replaceWith(NewElement newElement) {
|
||||
checkNotRemoved();
|
||||
notPermittedOnRootElement();
|
||||
requireNonNull(newElement, "Required not null new element");
|
||||
insertAfter(newElement);
|
||||
final Element inserted = getNextSibling();
|
||||
remove();
|
||||
return inserted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends new element to the end of children list
|
||||
*
|
||||
* @param newElement element which will be inserted to the end of children list
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree
|
||||
* @throws NullPointerException when newElement parameter is {@code null}
|
||||
*/
|
||||
public Element appendChild(NewElement newElement) {
|
||||
checkNotRemoved();
|
||||
requireNonNull(newElement, "Required not null new element");
|
||||
if (isVoid()) {
|
||||
throw new XMLTreeException("Append child is not permitted on void elements");
|
||||
}
|
||||
final Node newNode = createNode(newElement);
|
||||
final Element element = createElement(newNode);
|
||||
// append new node into document
|
||||
delegate.appendChild(newNode);
|
||||
// let tree do dirty job
|
||||
xmlTree.appendChild(newElement, element, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new element after current
|
||||
*
|
||||
* @param newElement element which will be inserted after current
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree or this element is
|
||||
* root element
|
||||
* @throws NullPointerException when newElement parameter is {@code null}
|
||||
*/
|
||||
public Element insertAfter(NewElement newElement) {
|
||||
checkNotRemoved();
|
||||
notPermittedOnRootElement();
|
||||
requireNonNull(newElement, "Required not null new element");
|
||||
final Node newNode = createNode(newElement);
|
||||
final Element element = createElement(newNode);
|
||||
// if element has next sibling append child to parent
|
||||
// else insert before next sibling
|
||||
final Node nextNode = nextElementNode(delegate);
|
||||
if (nextNode != null) {
|
||||
delegate.getParentNode().insertBefore(newNode, nextNode);
|
||||
} else {
|
||||
delegate.getParentNode().appendChild(newNode);
|
||||
}
|
||||
// let tree do dirty job
|
||||
xmlTree.insertAfter(newElement, element, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new element before current element
|
||||
*
|
||||
* @param newElement element which will be inserted before current
|
||||
* @return this element instance
|
||||
* @throws XMLTreeException when this element has been removed from xml tree or this element is
|
||||
* root element
|
||||
* @throws NullPointerException when newElement parameter is {@code null}
|
||||
*/
|
||||
public Element insertBefore(NewElement newElement) {
|
||||
checkNotRemoved();
|
||||
notPermittedOnRootElement();
|
||||
requireNonNull(newElement, "Required not null new element");
|
||||
// if element has previous sibling insert new element after it
|
||||
// inserting before this element to let existing comments
|
||||
// or whatever over referenced element
|
||||
if (previousElementNode(delegate) != null) {
|
||||
getPreviousSibling().insertAfter(newElement);
|
||||
return this;
|
||||
}
|
||||
final Node newNode = createNode(newElement);
|
||||
final Element element = createElement(newNode);
|
||||
delegate.getParentNode().insertBefore(newNode, delegate);
|
||||
// let tree do dirty job
|
||||
xmlTree.insertAfterParent(newElement, element, getParent());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new element as child to the specified by {@link XMLTreeLocation} location.
|
||||
*
|
||||
* <p>If it is not possible to insert element in specified location then {@link XMLTreeException}
|
||||
* will be thrown
|
||||
*
|
||||
* @param child new child
|
||||
*/
|
||||
public Element insertChild(NewElement child, XMLTreeLocation place) {
|
||||
place.evalInsert(this, child);
|
||||
return this;
|
||||
}
|
||||
|
||||
void setAttributeValue(Attribute attribute) {
|
||||
checkNotRemoved();
|
||||
final Node attributeNode = getAttributeNode(attribute.getName());
|
||||
xmlTree.updateAttributeValue(attribute, attributeNode.getNodeValue());
|
||||
getAttributeNode(attribute.getName()).setNodeValue(attribute.getValue());
|
||||
}
|
||||
|
||||
private void removeTextNodes() {
|
||||
final NodeList childNodes = delegate.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
if (childNodes.item(i).getNodeType() == TEXT_NODE) {
|
||||
delegate.removeChild(childNodes.item(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Attribute asAttribute(Node node) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
return new Attribute(this, node.getNodeName(), node.getNodeValue());
|
||||
}
|
||||
|
||||
private String fetchText() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final NodeList childNodes = delegate.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
if (childNodes.item(i).getNodeType() == TEXT_NODE) {
|
||||
sb.append(childNodes.item(i).getTextContent());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Attr createAttrNode(NewAttribute newAttribute) {
|
||||
final Attr attr = document().createAttribute(newAttribute.getName());
|
||||
attr.setValue(newAttribute.getValue());
|
||||
return attr;
|
||||
}
|
||||
|
||||
private Attr createAttrNSNode(NewAttribute attribute) {
|
||||
if (attribute.getPrefix().equals(XMLNS_ATTRIBUTE)) {
|
||||
final Attr attr = document().createAttributeNS(XMLNS_ATTRIBUTE_NS_URI, attribute.getName());
|
||||
attr.setValue(attribute.getValue());
|
||||
// save uri
|
||||
xmlTree.putNamespace(attribute.getLocalName(), attribute.getValue());
|
||||
return attr;
|
||||
} else {
|
||||
// retrieve namespace
|
||||
final String uri = xmlTree.getNamespaceUri(attribute.getPrefix());
|
||||
final Attr attr = document().createAttributeNS(uri, attribute.getName());
|
||||
attr.setValue(attribute.getValue());
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
|
||||
private Node nextElementNode(Node node) {
|
||||
node = node.getNextSibling();
|
||||
while (node != null && node.getNodeType() != ELEMENT_NODE) {
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private Node previousElementNode(Node node) {
|
||||
node = node.getPreviousSibling();
|
||||
while (node != null && node.getNodeType() != ELEMENT_NODE) {
|
||||
node = node.getPreviousSibling();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private void notPermittedOnRootElement() {
|
||||
if (!hasParent()) {
|
||||
throw new XMLTreeException("Operation not permitted for root element");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkNotRemoved() {
|
||||
if (delegate == null) {
|
||||
throw new XMLTreeException(
|
||||
"Operation not permitted for element which has been removed from XMLTree");
|
||||
}
|
||||
}
|
||||
|
||||
private Element createElement(Node node) {
|
||||
final Element element = new Element(xmlTree);
|
||||
element.delegate = (org.w3c.dom.Element) node;
|
||||
node.setUserData("element", element, null);
|
||||
if (node.hasChildNodes()) {
|
||||
final NodeList children = node.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
if (children.item(i).getNodeType() == ELEMENT_NODE) {
|
||||
createElement(children.item(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
private Node createNode(NewElement newElement) {
|
||||
final org.w3c.dom.Element newNode;
|
||||
if (newElement.hasPrefix()) {
|
||||
final String uri = xmlTree.getNamespaceUri(newElement.getPrefix());
|
||||
newNode = document().createElementNS(uri, newElement.getName());
|
||||
} else {
|
||||
newNode = document().createElement(newElement.getLocalName());
|
||||
}
|
||||
newNode.setTextContent(newElement.getText());
|
||||
// creating all related children
|
||||
for (NewElement child : newElement.getChildren()) {
|
||||
newNode.appendChild(createNode(child));
|
||||
}
|
||||
// creating all related attributes
|
||||
for (NewAttribute attribute : newElement.getAttributes()) {
|
||||
if (attribute.hasPrefix()) {
|
||||
newNode.setAttributeNodeNS(createAttrNSNode(attribute));
|
||||
} else {
|
||||
newNode.setAttributeNode(createAttrNode(attribute));
|
||||
}
|
||||
}
|
||||
return newNode;
|
||||
}
|
||||
|
||||
private Document document() {
|
||||
return delegate.getOwnerDocument();
|
||||
}
|
||||
|
||||
private Node getAttributeNode(String name) {
|
||||
final NamedNodeMap attributes = delegate.getAttributes();
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
if (attributes.item(i).getNodeName().equals(name)) {
|
||||
return attributes.item(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
/** @author Eugene Voevodin */
|
||||
public interface ElementMapper<T> {
|
||||
|
||||
T map(Element element);
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
/**
|
||||
* Describes new attribute. Should be used to insert new attribute into existing tree element or may
|
||||
* be a part of {@link NewElement}.
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public final class NewAttribute extends QName {
|
||||
|
||||
private String value;
|
||||
|
||||
public NewAttribute(String qName, String value) {
|
||||
super(qName);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
return getName() + '=' + '"' + value + '"';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.tabulate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to add new element to {@link XMLTree}.
|
||||
*
|
||||
* <p>This class is really convenient for complex tree updates. To do it you need to make hierarchy
|
||||
* from NewElement instances which can contain NewAttribute instances or text as well. When {@link
|
||||
* NewElement} instance is ready tree uses {@link NewElement#asString()} to get view of new element.
|
||||
*
|
||||
* <p>Why don't we just create {@link Element} instead of using {@link NewElement} class?
|
||||
*
|
||||
* <ul>
|
||||
* <li>First reason - is performance! Each time when you need to insert element tree bytes should
|
||||
* be rewrote, but with {@link NewElement} tree bytes will be updated only time
|
||||
* <li>Second reason is - data redundancy! Element should keep values such as children,
|
||||
* attributes, name, text for each element instance which will be added to tree and after tree
|
||||
* update this values must be dropped because element delegates for {@link org.w3c.dom.Node}
|
||||
* and doesn't need it anymore.
|
||||
* <li>Third reason is - tree integrity! Element instance created with tree should be inserted
|
||||
* into same tree, so each time when update is going we need to make a lot of checks to save
|
||||
* tree elements integrity
|
||||
* </ul>
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public final class NewElement extends QName {
|
||||
|
||||
public static NewElement createElement(String name) {
|
||||
return new NewElement(name, null);
|
||||
}
|
||||
|
||||
public static NewElement createElement(String name, String text) {
|
||||
return new NewElement(name, text);
|
||||
}
|
||||
|
||||
public static NewElement createElement(String name, NewElement... children) {
|
||||
final NewElement newElement = createElement(name);
|
||||
newElement.children = new ArrayList<>(asList(children));
|
||||
return newElement;
|
||||
}
|
||||
|
||||
private String text;
|
||||
private List<NewAttribute> attributes;
|
||||
private List<NewElement> children;
|
||||
|
||||
private NewElement(String name, String text) {
|
||||
super(name);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public NewElement setText(String text) {
|
||||
this.text = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NewElement setAttributes(List<NewAttribute> attributes) {
|
||||
this.attributes = attributes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NewElement setChildren(List<NewElement> children) {
|
||||
this.children = children;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NewElement appendChild(NewElement child) {
|
||||
getChildren().add(child);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NewElement setAttribute(String name, String value) {
|
||||
getAttributes().add(new NewAttribute(name, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text == null ? "" : text;
|
||||
}
|
||||
|
||||
public List<NewAttribute> getAttributes() {
|
||||
if (attributes == null) {
|
||||
attributes = new LinkedList<>();
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public List<NewElement> getChildren() {
|
||||
if (children == null) {
|
||||
children = new LinkedList<>();
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
public boolean hasChildren() {
|
||||
return children != null && !children.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isVoid() {
|
||||
return text == null && !hasChildren();
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append('<').append(getName());
|
||||
if (attributes != null) {
|
||||
for (NewAttribute attribute : attributes) {
|
||||
builder.append(' ').append(attribute.asString());
|
||||
}
|
||||
}
|
||||
// if it is void element such as <tag attr="value"/>
|
||||
if (isVoid()) {
|
||||
return builder.append('/').append('>').toString();
|
||||
}
|
||||
builder.append('>').append(getText());
|
||||
if (hasChildren()) {
|
||||
builder.append('\n');
|
||||
for (NewElement child : children) {
|
||||
builder.append(tabulate(child.asString(), 1)).append('\n');
|
||||
}
|
||||
}
|
||||
builder.append('<').append('/').append(getName()).append('>');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return asString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
/**
|
||||
* Describes qualified name
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public class QName {
|
||||
|
||||
private String prefix;
|
||||
private String localName;
|
||||
|
||||
public QName(String name) {
|
||||
applyName(name);
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public String getLocalName() {
|
||||
return localName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return hasPrefix() ? prefix + ':' + localName : localName;
|
||||
}
|
||||
|
||||
public boolean hasPrefix() {
|
||||
return prefix != null && !prefix.isEmpty();
|
||||
}
|
||||
|
||||
private void applyName(String newName) {
|
||||
final int separator = newName.indexOf(':');
|
||||
if (separator != -1) {
|
||||
localName = newName.substring(separator + 1);
|
||||
prefix = newName.substring(0, separator);
|
||||
} else {
|
||||
localName = newName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/**
|
||||
* The handler is designed for using at xml document parsing and logs messages at the DEBUG level
|
||||
* only.
|
||||
*
|
||||
* @author Roman Nikitenko
|
||||
*/
|
||||
public class QuietXmlErrorHandler implements ErrorHandler {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QuietXmlErrorHandler.class);
|
||||
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
LOG.debug("Warning at parsing xml document: " + exception.getLocalizedMessage(), exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
LOG.debug("Error at parsing xml document: " + exception.getLocalizedMessage(), exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
LOG.debug("Fatal error at parsing xml document: " + exception.getLocalizedMessage(), exception);
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,958 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
|
||||
import static com.google.common.io.ByteStreams.toByteArray;
|
||||
import static java.nio.file.Files.readAllBytes;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING;
|
||||
import static javax.xml.XMLConstants.XML_NS_URI;
|
||||
import static javax.xml.stream.XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES;
|
||||
import static javax.xml.stream.XMLInputFactory.SUPPORT_DTD;
|
||||
import static javax.xml.stream.XMLStreamConstants.CHARACTERS;
|
||||
import static javax.xml.stream.XMLStreamConstants.COMMENT;
|
||||
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
|
||||
import static javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION;
|
||||
import static javax.xml.stream.XMLStreamConstants.SPACE;
|
||||
import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
|
||||
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
|
||||
import static javax.xml.xpath.XPathConstants.NODESET;
|
||||
import static javax.xml.xpath.XPathConstants.STRING;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.SPACES_IN_TAB;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.UTF_8;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.asElement;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.asElements;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.closeTagLength;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.indexOf;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.indexOfAttributeName;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.insertBetween;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.insertInto;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.lastIndexOf;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.level;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.openTagLength;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.replaceAll;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.rootStart;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.single;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.tabulate;
|
||||
import static org.w3c.dom.Node.CDATA_SECTION_NODE;
|
||||
import static org.w3c.dom.Node.TEXT_NODE;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.stream.XMLInputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import javax.xml.xpath.XPathFactoryConfigurationException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* XML tool which provides abilities to modify and search information in xml document without
|
||||
* affecting of existing formatting, comments.
|
||||
*
|
||||
* <p>XMLTree delegates out of the box implementation of org.w3c.dom and provides a lot of
|
||||
* functionality such as XPath selection. How does the XMLTree let content in required state? The
|
||||
* main idea is simple: know XML elements positions! If we know elements positions and source bytes
|
||||
* we can easily manipulate content as we want. So each time when client updates tree, tree rewrites
|
||||
* source bytes with new information, indexes new elements, updates delegated document, shifts
|
||||
* needed existed elements positions. As you may see there are a lot of data manipulations when
|
||||
* update is going, so <b>you should not use this tool for parsing huge xml documents or for often
|
||||
* complex updates.</b>
|
||||
*
|
||||
* <p>XPath is embedded to XMLTree so each query to tree is xpath query. You will be able to
|
||||
* select/update content provided with XMLTree elements or attributes without working with xpath
|
||||
* directly.
|
||||
*
|
||||
* <p>XMLTree provides methods which do the same as model methods but sometimes they are more
|
||||
* convenient, you can use tree methods as well as model methods.
|
||||
*
|
||||
* <p>XMLTree disallows using of {@code DOCTYPE} definition in security reasons(XML Entity Expansion
|
||||
* injection, XML External Entity Injection).
|
||||
*
|
||||
* <pre>
|
||||
* For example:
|
||||
*
|
||||
* XMLTree tree = XMLTree.from(...)
|
||||
*
|
||||
* //tree call
|
||||
* tree.updateText("/project/name", "new name");
|
||||
*
|
||||
* //model call
|
||||
* tree.getSingleElement("/project/name")
|
||||
* .setText("new name");
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <b>NOTE: XMLTree is not thread-safe!</b>
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public final class XMLTree {
|
||||
|
||||
/** Creates XMLTree from input stream. Doesn't close the stream */
|
||||
public static XMLTree from(InputStream is) throws IOException {
|
||||
return new XMLTree(toByteArray(is));
|
||||
}
|
||||
|
||||
/** Creates XMLTree from file */
|
||||
public static XMLTree from(java.io.File file) throws IOException {
|
||||
return from(file.toPath());
|
||||
}
|
||||
|
||||
/** Creates XMLTree from path */
|
||||
public static XMLTree from(Path path) throws IOException {
|
||||
return new XMLTree(readAllBytes(path));
|
||||
}
|
||||
|
||||
/** Creates XMLTree from string */
|
||||
public static XMLTree from(String xml) {
|
||||
return new XMLTree(xml.getBytes(UTF_8));
|
||||
}
|
||||
|
||||
/** Creates XMLTree from byte array */
|
||||
public static XMLTree from(byte[] xml) {
|
||||
requireNonNull(xml, "Required not null bytes");
|
||||
return new XMLTree(Arrays.copyOf(xml, xml.length));
|
||||
}
|
||||
|
||||
/** Creates XMLTree with given root element */
|
||||
public static XMLTree create(String rootName) {
|
||||
return from(String.format(ROOT_TEMPLATE, rootName, rootName));
|
||||
}
|
||||
|
||||
private static final XMLInputFactory XML_INPUT_FACTORY = XMLInputFactory.newFactory();
|
||||
private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY =
|
||||
DocumentBuilderFactory.newInstance();
|
||||
private static final XPathFactory XPATH_FACTORY = XPathFactory.newInstance();
|
||||
private static final String ROOT_TEMPLATE =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<%s>\n</%s>";
|
||||
private static final int EXPECTED_NAMESPACES_SIZE = 2;
|
||||
|
||||
/** Factories configuration. */
|
||||
static {
|
||||
try {
|
||||
// Disable doctype declaration to avoid: XML Entity Expansion injection, XML External Entity
|
||||
// Injection
|
||||
DOCUMENT_BUILDER_FACTORY.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||
// Force parser to use secure settings
|
||||
DOCUMENT_BUILDER_FACTORY.setFeature(FEATURE_SECURE_PROCESSING, true);
|
||||
// Disable usage of entity references to avoid: XML External Entity Injection
|
||||
// It is not needed as long as doctype is disabled, but when doctype is enabled
|
||||
// this adjustment guarantees avoiding of entity references expansion
|
||||
DOCUMENT_BUILDER_FACTORY.setExpandEntityReferences(false);
|
||||
|
||||
// Force xpath factory to use secure settings
|
||||
XPATH_FACTORY.setFeature(FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
// Disable DTD support at all to avoid: XML Entity Expansion injection, XML External Entity
|
||||
// Injection
|
||||
XML_INPUT_FACTORY.setProperty(SUPPORT_DTD, false);
|
||||
// Disable usage of external entities to avoid: XML External Entity Injection
|
||||
XML_INPUT_FACTORY.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false);
|
||||
} catch (ParserConfigurationException | XPathFactoryConfigurationException confEx) {
|
||||
throw XMLTreeException.wrap(confEx);
|
||||
}
|
||||
}
|
||||
|
||||
private Document document;
|
||||
private Map<String, String> namespaces;
|
||||
private List<Element> elements;
|
||||
private byte[] xml;
|
||||
|
||||
private XMLTree(byte[] xml) {
|
||||
if (xml.length == 0) {
|
||||
throw new XMLTreeException("Source content is empty");
|
||||
}
|
||||
elements = new LinkedList<>();
|
||||
namespaces = newHashMapWithExpectedSize(EXPECTED_NAMESPACES_SIZE);
|
||||
this.xml = normalizeLineEndings(xml);
|
||||
// reason: parser is going to replace all '\r\n' sequences with single '\n'
|
||||
// which will affect elements position in source xml and produce incorrect XMLTree behaviour
|
||||
// it comes from spec http://www.w3.org/TR/2004/REC-xml11-20040204/
|
||||
document = parseQuietly(this.xml);
|
||||
constructTreeQuietly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for requested element text. If there are more then only element were found {@link
|
||||
* XMLTreeException} will be thrown
|
||||
*
|
||||
* @param expression xpath expression to search element
|
||||
* @return requested element text
|
||||
* @see Element#getText()
|
||||
*/
|
||||
public String getSingleText(String expression) {
|
||||
return (String) evaluateXPath(expression, STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for requested elements text. If there are no elements were found empty list will be
|
||||
* returned.
|
||||
*
|
||||
* <p>You can use this method to request not only elements text but for selecting attributes
|
||||
* values or whatever text information which is able to be selected with xpath
|
||||
*
|
||||
* @param expression xpath expression to search elements
|
||||
* @return list of elements text or empty list if nothing found
|
||||
*/
|
||||
public List<String> getText(String expression) {
|
||||
return retrieveText(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for requested elements.
|
||||
*
|
||||
* @param expression xpath expression to search elements
|
||||
* @return list of found elements or empty list if elements were not found
|
||||
*/
|
||||
public List<Element> getElements(String expression) {
|
||||
final NodeList nodes = (NodeList) evaluateXPath(expression, NODESET);
|
||||
return asElements(nodes);
|
||||
}
|
||||
|
||||
public <R> List<R> getElements(String expression, ElementMapper<? extends R> mapper) {
|
||||
final NodeList nodes = (NodeList) evaluateXPath(expression, NODESET);
|
||||
return asElements(nodes, mapper);
|
||||
}
|
||||
|
||||
/** Returns root element for current tree */
|
||||
public Element getRoot() {
|
||||
return asElement(document.getDocumentElement());
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are more then only element or nothing were found {@link XMLTreeException} will be
|
||||
* thrown
|
||||
*
|
||||
* @param expression xpath expression to search element
|
||||
* @return found element
|
||||
*/
|
||||
public Element getSingleElement(String expression) {
|
||||
return single(getElements(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates requested element text. XPath expression should be used only for element not for
|
||||
* attribute or something else. If there are more then only element were found {@link
|
||||
* XMLTreeException} will be thrown
|
||||
*
|
||||
* @param expression xpath expression to search element
|
||||
* @param newContent new element text content
|
||||
* @see Element#setText(String)
|
||||
*/
|
||||
public void updateText(String expression, String newContent) {
|
||||
getSingleElement(expression).setText(newContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds element to the end of the list of existed children or adds it as only child.
|
||||
*
|
||||
* <p>If there are more then only parent element were found {@link XMLTreeException} will be
|
||||
* thrown
|
||||
*
|
||||
* @param expression xpath expression to search parent
|
||||
* @param newElement new element which will be inserted. It should be created with same tree
|
||||
* instance
|
||||
*/
|
||||
public void appendChild(String expression, NewElement newElement) {
|
||||
single(getElements(expression)).appendChild(newElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts element before referenced one. All comments related before referenced element going to
|
||||
* have same positions like they had before.
|
||||
*
|
||||
* <p>If there are more then only referenced element were found {@link XMLTreeException} will be
|
||||
* thrown
|
||||
*
|
||||
* @param expression xpath expression to search referenced element
|
||||
* @param newElement new element which will be inserted. It should be created with same tree
|
||||
* instance
|
||||
*/
|
||||
public void insertBefore(String expression, NewElement newElement) {
|
||||
single(getElements(expression)).insertBefore(newElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts element after referenced one.
|
||||
*
|
||||
* <p>If there are more then only referenced elements were found {@link XMLTreeException} will be
|
||||
* thrown
|
||||
*
|
||||
* @param expression xpath expression to search referenced element
|
||||
* @param newElement new element which will be inserted. It should be created with same tree
|
||||
* instance
|
||||
*/
|
||||
public void insertAfter(String expression, NewElement newElement) {
|
||||
single(getElements(expression)).insertAfter(newElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes requested element. If there are was any <b>text</b> before removal element it will be
|
||||
* removed as well. It is important when we need to keep formatting pretty - if it was pretty. It
|
||||
* is really strange when parent element contains not only whitespaces but another text content.
|
||||
*
|
||||
* <p>If there are more then only referenced element were found {@link XMLTreeException} will be
|
||||
* thrown
|
||||
*
|
||||
* @param expression xpath expression to remove element
|
||||
*/
|
||||
public void removeElement(String expression) {
|
||||
single(getElements(expression)).remove();
|
||||
}
|
||||
|
||||
/** Returns copy of source bytes. TODO: write replacement explanation */
|
||||
public byte[] getBytes() {
|
||||
final String separator = System.getProperty("line.separator");
|
||||
if (!"\n".equals(separator)) {
|
||||
return replaceAll(xml, "\n".getBytes(), separator.getBytes());
|
||||
}
|
||||
return Arrays.copyOf(xml, xml.length);
|
||||
}
|
||||
|
||||
/** Writes copy of source bytes to output stream. Doesn't close the stream */
|
||||
public void writeTo(OutputStream outputStream) throws IOException {
|
||||
outputStream.write(getBytes());
|
||||
}
|
||||
|
||||
/** Writes source bytes to path */
|
||||
public void writeTo(Path path) throws IOException {
|
||||
Files.write(path, getBytes());
|
||||
}
|
||||
|
||||
/** Writes source bytes to file */
|
||||
public void writeTo(java.io.File file) throws IOException {
|
||||
Files.write(file.toPath(), getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates xpath expression with given return type. Rethrows all exceptions as {@link
|
||||
* XMLTreeException}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object evaluateXPath(String expression, QName returnType) {
|
||||
final XPath xpath = XPATH_FACTORY.newXPath();
|
||||
try {
|
||||
return xpath.evaluate(expression, document, returnType);
|
||||
} catch (XPathExpressionException xpathEx) {
|
||||
throw XMLTreeException.wrap(xpathEx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses document using {@link DocumentBuilder} Rethrows all exceptions as {@link
|
||||
* XMLTreeException}
|
||||
*/
|
||||
private Document parseQuietly(byte[] xml) {
|
||||
try {
|
||||
final DocumentBuilder db = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
|
||||
db.setErrorHandler(new QuietXmlErrorHandler());
|
||||
return db.parse(new ByteArrayInputStream(xml));
|
||||
} catch (Exception ex) {
|
||||
throw XMLTreeException.wrap(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates xpath expression and maps result as list of strings using {@link
|
||||
* Node#getTextContent()} method
|
||||
*/
|
||||
private List<String> retrieveText(String expression) {
|
||||
final NodeList nodeList = (NodeList) evaluateXPath(expression, NODESET);
|
||||
final List<String> elementsText = new ArrayList<>(nodeList.getLength());
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
elementsText.add(nodeList.item(i).getTextContent());
|
||||
}
|
||||
return elementsText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs tree based on segments which are supplied by {@link XMLStreamReader}. Before this
|
||||
* method is invoked {@link #document} should be initialized first. For START_ELEMENT,
|
||||
* END_ELEMENT, CHARACTERS reader provides offset from start of source array bytes, so we can
|
||||
* fetch position of elements and text. Each created element associated with related {@link Node}
|
||||
* and vise-versa.
|
||||
*/
|
||||
private void constructTree() throws XMLStreamException {
|
||||
final XMLStreamReader reader = newXMLStreamReader();
|
||||
final LinkedList<Element> stack = new LinkedList<>();
|
||||
// before element open tag index
|
||||
int beforeStart = rootStart(xml) - 1;
|
||||
// used to associate each element with document node
|
||||
Node node = document.getDocumentElement();
|
||||
// used to hold previous reader event
|
||||
int prevEvent = START_DOCUMENT;
|
||||
while (reader.hasNext()) {
|
||||
switch (reader.next()) {
|
||||
case START_ELEMENT:
|
||||
final Element newElement = new Element(this);
|
||||
newElement.start = new Segment(beforeStart + 1, elementRight(beforeStart + 1, reader));
|
||||
// if new node is not xml root - set up relationships
|
||||
if (!stack.isEmpty()) {
|
||||
node = deepNext(node, true);
|
||||
}
|
||||
// connect node with element
|
||||
node.setUserData("element", newElement, null);
|
||||
|
||||
newElement.delegate = safeCast(node);
|
||||
// let next event know about its start
|
||||
beforeStart = newElement.start.right;
|
||||
// if element has declared namespaces register it
|
||||
putNamespaces(reader);
|
||||
stack.push(newElement);
|
||||
break;
|
||||
case END_ELEMENT:
|
||||
final Element element = stack.pop();
|
||||
element.end = new Segment(beforeStart + 1, elementRight(beforeStart + 1, reader));
|
||||
elements.add(element);
|
||||
beforeStart = element.end.right;
|
||||
break;
|
||||
case CHARACTERS:
|
||||
// characters event may be invoked 2 or more times
|
||||
// on the element text, but related node is single text node
|
||||
// so the only segment should be created for it
|
||||
if (prevEvent == CHARACTERS) continue;
|
||||
|
||||
final Element current = stack.peek();
|
||||
if (current.text == null) {
|
||||
// TODO replace with array list as we know current node 'text nodes' count
|
||||
current.text = new LinkedList<>();
|
||||
}
|
||||
|
||||
final Node nextNode = deepNext(node, true);
|
||||
|
||||
final int left = beforeStart + 1;
|
||||
final int right = left + textLength(nextNode) - 1;
|
||||
|
||||
current.text.add(new Segment(left, right));
|
||||
beforeStart = right;
|
||||
node = skipTextNodes(nextNode);
|
||||
break;
|
||||
case COMMENT:
|
||||
case SPACE:
|
||||
case PROCESSING_INSTRUCTION:
|
||||
if (!stack.isEmpty()) {
|
||||
node = deepNext(node, true);
|
||||
beforeStart = lastIndexOf(xml, '>', reader.getLocation().getCharacterOffset());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// DO NOTHING
|
||||
}
|
||||
prevEvent = reader.getEventType();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns length of cdata and text nodes chain. */
|
||||
private int textLength(Node node) {
|
||||
int length = node.getTextContent().length();
|
||||
node = node.getNextSibling();
|
||||
while (node != null
|
||||
&& (node.getNodeType() == TEXT_NODE || node.getNodeType() == CDATA_SECTION_NODE)) {
|
||||
length += node.getTextContent().length();
|
||||
if (node.getNodeType() == CDATA_SECTION_NODE) {
|
||||
length += 12; // <![CDATA[]]> - 12
|
||||
}
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns safe Element instance for node or throws exception if it is not possible to cast {@code
|
||||
* node} to {@link org.w3c.dom.Element}.
|
||||
*/
|
||||
private org.w3c.dom.Element safeCast(Node node) {
|
||||
if (!(node instanceof org.w3c.dom.Element)) {
|
||||
throw new XMLTreeException("It is not possible to associate xml elements");
|
||||
}
|
||||
return (org.w3c.dom.Element) node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last text or cdata node in the chain of cdata and text nodes.
|
||||
*
|
||||
* <p>i.e. node1 is text <i>node</i> and <i>node1</i> has next sibling <i>node2</i> as cdata node
|
||||
* and <i>node2</i> has next sibling <i>node3</i> as text node and node3 has next sibling
|
||||
* <i>node4</i> as element node, then <i>node3</i> will be returned as last text node in the
|
||||
* chain. Consider following examples:
|
||||
*
|
||||
* <pre>
|
||||
* 1.
|
||||
* node3 - last text node
|
||||
*
|
||||
* text cdata text element
|
||||
* node1 -> node2 -> node3 -> node4
|
||||
*
|
||||
* 2.
|
||||
* node2 - last text result
|
||||
*
|
||||
* text cdata
|
||||
* node1 -> node2 -> null
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
private Node skipTextNodes(Node node) {
|
||||
final Node next = node.getNextSibling();
|
||||
if (next != null
|
||||
&& (next.getNodeType() == CDATA_SECTION_NODE || next.getNodeType() == TEXT_NODE)) {
|
||||
return skipTextNodes(next);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the element start right bound index. TODO respect element attributes text content
|
||||
* while checking '<'
|
||||
*/
|
||||
private int elementRight(int left, XMLStreamReader reader) {
|
||||
int rightIdx = lastIndexOf(xml, '>', reader.getLocation().getCharacterOffset());
|
||||
int leftIdx = lastIndexOf(xml, '<', rightIdx);
|
||||
while (leftIdx > left) {
|
||||
rightIdx = lastIndexOf(xml, '>', rightIdx - 1);
|
||||
leftIdx = lastIndexOf(xml, '<', rightIdx);
|
||||
}
|
||||
return rightIdx;
|
||||
}
|
||||
|
||||
private Node deepNext(Node node, boolean deep) {
|
||||
if (deep && node.getChildNodes().getLength() != 0) {
|
||||
return node.getFirstChild();
|
||||
}
|
||||
final Node next = node.getNextSibling();
|
||||
if (next != null) {
|
||||
return next;
|
||||
} else if (node == document.getDocumentElement()) {
|
||||
return node;
|
||||
}
|
||||
return deepNext(node.getParentNode(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #constructTree()}, only difference that it wraps {@link XMLStreamException} to
|
||||
* {@link XMLTreeException}
|
||||
*/
|
||||
private void constructTreeQuietly() {
|
||||
try {
|
||||
constructTree();
|
||||
} catch (XMLStreamException xmlEx) {
|
||||
throw XMLTreeException.wrap(xmlEx);
|
||||
}
|
||||
}
|
||||
|
||||
/** Should be invoked on ELEMENT_START event */
|
||||
private void putNamespaces(XMLStreamReader reader) {
|
||||
for (int i = 0; i < reader.getNamespaceCount(); i++) {
|
||||
final String prefix = reader.getNamespacePrefix(i);
|
||||
if (prefix != null) {
|
||||
putNamespace(prefix, reader.getNamespaceURI(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates new stream reader instance */
|
||||
private XMLStreamReader newXMLStreamReader() {
|
||||
try {
|
||||
return XML_INPUT_FACTORY.createXMLStreamReader(new ByteArrayInputStream(xml), "UTF-8");
|
||||
} catch (Exception xmlEx) {
|
||||
throw XMLTreeException.wrap(xmlEx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates element text content. Update based on element text segments. If element doesn't have
|
||||
* any text segment then new segment will be created which positions based on container bounds,
|
||||
* otherwise only first text segment will be used for update, other text segments will be removed.
|
||||
*/
|
||||
void updateText(Element target) {
|
||||
// it may be null when target element doesn't contain
|
||||
// text <element></element> so CHARACTERS event was not processed
|
||||
if (target.text == null) {
|
||||
target.text = new LinkedList<>();
|
||||
// updateSegmentContent will set up right bound
|
||||
target.text.add(new Segment(target.start.right + 1, target.start.right));
|
||||
}
|
||||
final Iterator<Segment> segIt = target.text.iterator();
|
||||
final Segment first = segIt.next();
|
||||
// removing all segments instead of first
|
||||
while (segIt.hasNext()) {
|
||||
final Segment removal = segIt.next();
|
||||
segIt.remove();
|
||||
removeSegment(removal);
|
||||
}
|
||||
updateSegmentContent(first, target.getText());
|
||||
}
|
||||
|
||||
void updateAttributeValue(Attribute attribute, String oldValue) {
|
||||
final Segment segment = valueSegment(attribute, oldValue);
|
||||
updateSegmentContent(segment, attribute.getValue());
|
||||
}
|
||||
|
||||
/** Adds new element to the end of children list with given parent. */
|
||||
void appendChild(NewElement newElement, Element relatedToNew, Element parent) {
|
||||
final int level = level(parent) + 1;
|
||||
final int lengthBefore = xml.length;
|
||||
final int insertHere = lastIndexOf(xml, '>', parent.end.left) + 1;
|
||||
// inserting new element bytes to tree bytes
|
||||
xml = insertInto(xml, insertHere, '\n' + tabulate(newElement.asString(), level));
|
||||
// shift existing segments which are after parent start
|
||||
shiftSegments(insertHere, xml.length - lengthBefore);
|
||||
// create and set up start, end, text segments to created element
|
||||
applySegments(newElement, relatedToNew, insertHere - 1, level);
|
||||
// let tree know about added element
|
||||
registerElement(relatedToNew);
|
||||
}
|
||||
|
||||
/** Inserts element after referenced one */
|
||||
void insertAfter(NewElement newElement, Element relatedToNew, Element refElement) {
|
||||
final int level = level(refElement);
|
||||
final int lengthBefore = xml.length;
|
||||
// inserting new element bytes to tree bytes
|
||||
xml = insertInto(xml, refElement.end.right + 1, '\n' + tabulate(newElement.asString(), level));
|
||||
// shift existing segments which are after parent start
|
||||
shiftSegments(refElement.end.right, xml.length - lengthBefore);
|
||||
// create and set up start, end, text segments to created element
|
||||
// +1 because of \n
|
||||
applySegments(newElement, relatedToNew, refElement.end.right, level);
|
||||
// let tree know about inserted element
|
||||
registerElement(relatedToNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts element before referenced one. It is important to let all related to {@code refElement}
|
||||
* comments on their places, so to avoid deformation we inserting new element after previous
|
||||
* sibling or after element parent if element doesn't have previous sibling
|
||||
*/
|
||||
void insertAfterParent(NewElement newElement, Element relatedToNew, Element parent) {
|
||||
final int level = level(parent) + 1;
|
||||
final int lengthBefore = xml.length;
|
||||
// inserting after parent
|
||||
xml = insertInto(xml, parent.start.right + 1, '\n' + tabulate(newElement.asString(), level));
|
||||
// shift existing segments which are after parent start
|
||||
shiftSegments(parent.start.right, xml.length - lengthBefore);
|
||||
// create and set up start, end, text segments to created element
|
||||
applySegments(newElement, relatedToNew, parent.start.right, level);
|
||||
// let tree know about inserted element
|
||||
registerElement(relatedToNew);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes element bytes from tree.
|
||||
*
|
||||
* <p>It is important to save xml tree pretty view, so element should be removed without of
|
||||
* destroying style of xml document.
|
||||
*
|
||||
* <pre>
|
||||
* e.g.
|
||||
*
|
||||
* {@literal <level1>}
|
||||
* {@literal <level2>} {@literal <level2>+\n}
|
||||
* {@literal <level2>} {@literal <level2+>\n}
|
||||
* {@literal <level1>}
|
||||
*
|
||||
* first + is before left border
|
||||
* last + is before right border
|
||||
*
|
||||
* segment [first, last] - will be removed
|
||||
* </pre>
|
||||
*
|
||||
* So after removing - formatting will be the same. We can't remove just element from start to end
|
||||
* because it will produce not pretty formatting for good and pretty formatted before document.
|
||||
*/
|
||||
void removeElement(Element element) {
|
||||
final int leftBound = lastIndexOf(xml, '>', element.start.left) + 1;
|
||||
final int lengthBefore = xml.length;
|
||||
// if text segment before removal element
|
||||
// exists it should go to hell with removal
|
||||
if (leftBound != element.start.left - 1) {
|
||||
removeSegmentFromElement(element.getParent(), leftBound);
|
||||
}
|
||||
// replacing content with nothing
|
||||
xml = insertBetween(xml, leftBound, element.end.right, "");
|
||||
// shift all elements which are right from removed element
|
||||
shiftSegments(element.end.right, xml.length - lengthBefore);
|
||||
// let tree know that element is not a family member
|
||||
unregisterElement(element);
|
||||
}
|
||||
|
||||
/** Inserts new attribute value content to tree bytes */
|
||||
void insertAttribute(NewAttribute attribute, Element owner) {
|
||||
final int len = xml.length;
|
||||
// inserting new attribute content
|
||||
xml = insertInto(xml, owner.start.right, ' ' + attribute.asString());
|
||||
// shift all elements which are right from removed element
|
||||
shiftSegments(owner.start.left - 1, xml.length - len);
|
||||
}
|
||||
|
||||
/** Removes element bytes from tree */
|
||||
void removeAttribute(Attribute attribute) {
|
||||
final Element element = attribute.getElement();
|
||||
final int lengthBefore = xml.length;
|
||||
final Segment segment = attributeSegment(attribute);
|
||||
// replacing attribute segment with nothing
|
||||
xml = insertBetween(xml, segment.left - 1, segment.right, "");
|
||||
// shift all elements which are left from owner left
|
||||
shiftSegments(element.start.left, xml.length - lengthBefore);
|
||||
}
|
||||
|
||||
// TODO should it be public?
|
||||
void putNamespace(String prefix, String uri) {
|
||||
namespaces.put(prefix, uri);
|
||||
}
|
||||
|
||||
// TODO should it be public?
|
||||
String getNamespaceUri(String prefix) {
|
||||
final String uri = namespaces.get(prefix);
|
||||
return uri == null ? XML_NS_URI : uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift given segment on offset if it is righter then idx
|
||||
*
|
||||
* @param segment segment to shift
|
||||
* @param leftBound left bound
|
||||
* @param offset offset to shift on, it can be negative
|
||||
*/
|
||||
private void shiftSegment(Segment segment, int leftBound, int offset) {
|
||||
if (segment.left > leftBound) {
|
||||
segment.left += offset;
|
||||
segment.right += offset;
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes segment which left bound equal to {@param left} from element */
|
||||
private void removeSegmentFromElement(Element element, int left) {
|
||||
for (Iterator<Segment> segIt = element.text.iterator(); segIt.hasNext(); ) {
|
||||
if (segIt.next().left == left) {
|
||||
segIt.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Iterates all existed elements and shifts their segments if needed */
|
||||
private void shiftSegments(int fromIdx, int offset) {
|
||||
for (Element element : elements) {
|
||||
if (element.end.left > fromIdx) {
|
||||
shiftSegment(element.start, fromIdx, offset);
|
||||
shiftSegment(element.end, fromIdx, offset);
|
||||
if (element.text != null) {
|
||||
for (Segment textSegment : element.text) {
|
||||
shiftSegment(textSegment, fromIdx, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given segment from source bytes and shifts segments left on offset equal to removal
|
||||
* segment length
|
||||
*/
|
||||
private void removeSegment(Segment segment) {
|
||||
final int lengthBefore = xml.length;
|
||||
xml = insertBetween(xml, segment.left, segment.right, "");
|
||||
shiftSegments(segment.left, xml.length - lengthBefore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts content bytes between left and right segment bounds and shifts segments on offset equal
|
||||
* to difference between new and old source bytes length
|
||||
*/
|
||||
private void updateSegmentContent(Segment segment, String content) {
|
||||
final int lengthBefore = xml.length;
|
||||
xml = insertBetween(xml, segment.left, segment.right, content);
|
||||
shiftSegments(segment.left, xml.length - lengthBefore);
|
||||
segment.right = segment.left + content.length() - 1;
|
||||
}
|
||||
|
||||
/** Adds element and it children to tree */
|
||||
private void registerElement(Element element) {
|
||||
elements.add(element);
|
||||
for (Element child : element.getChildren()) {
|
||||
registerElement(child);
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes element and children from tree */
|
||||
private void unregisterElement(Element element) {
|
||||
elements.remove(element);
|
||||
for (Element child : element.getChildren()) {
|
||||
unregisterElement(child);
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieves attribute segment */
|
||||
private Segment attributeSegment(Attribute attribute) {
|
||||
final Element owner = attribute.getElement();
|
||||
|
||||
final byte[] name = attribute.getName().getBytes();
|
||||
final byte[] value = attribute.getValue().getBytes();
|
||||
|
||||
final int attrLeft =
|
||||
indexOfAttributeName(xml, name, owner.start.left + owner.getName().length());
|
||||
final int valueLeft = indexOf(xml, value, attrLeft + name.length);
|
||||
|
||||
return new Segment(attrLeft, valueLeft + value.length);
|
||||
}
|
||||
|
||||
/** Retrieves attribute value segment */
|
||||
private Segment valueSegment(Attribute attribute, String oldValue) {
|
||||
final Element owner = attribute.getElement();
|
||||
|
||||
final byte[] name = attribute.getName().getBytes();
|
||||
final byte[] value = oldValue.getBytes();
|
||||
|
||||
final int attrLeft =
|
||||
indexOfAttributeName(xml, name, owner.start.left + owner.getName().length());
|
||||
final int valueLeft = indexOf(xml, value, attrLeft + name.length);
|
||||
|
||||
return new Segment(valueLeft, valueLeft + value.length - 1);
|
||||
}
|
||||
|
||||
/** Creates segments for newly created element and related children */
|
||||
private int applySegments(
|
||||
NewElement newElement, Element relatedToNew, int prevElementCloseRight, int level) {
|
||||
// text length before element
|
||||
// child - new element
|
||||
// '+' - text before element
|
||||
//
|
||||
// <parent>\n
|
||||
// ++++<child>...
|
||||
final int levelTextLength = level * SPACES_IN_TAB;
|
||||
|
||||
// '*' - before element open tag pos
|
||||
//
|
||||
// | prevElementCloseRight
|
||||
// v
|
||||
// <parent>\n *<child>...
|
||||
// +1 because of '\n'
|
||||
final int beforeOpenLeft = 1 + prevElementCloseRight + levelTextLength;
|
||||
|
||||
// we should add text segment which
|
||||
// is before new element to the parent text segments and start to track it
|
||||
final Element parent = relatedToNew.getParent();
|
||||
if (parent.text == null) {
|
||||
parent.text = new LinkedList<>();
|
||||
}
|
||||
parent.text.add(new Segment(prevElementCloseRight + 1, beforeOpenLeft));
|
||||
|
||||
// pos of open tag right '>'
|
||||
final int openRight = beforeOpenLeft + openTagLength(newElement);
|
||||
|
||||
relatedToNew.start = new Segment(beforeOpenLeft + 1, openRight);
|
||||
// if element is void it doesn't have children and text
|
||||
// and it has same start and end so we can initialize
|
||||
// only start and end segments
|
||||
if (relatedToNew.isVoid()) {
|
||||
relatedToNew.end = relatedToNew.start;
|
||||
return openRight;
|
||||
}
|
||||
// if element has children it doesn't have text instead of
|
||||
// whitespaces, so all what we need - detect element close tag segment
|
||||
// to do so we need to map segments for all children first
|
||||
int childRight = openRight;
|
||||
if (newElement.hasChildren()) {
|
||||
|
||||
final Iterator<NewElement> newChIt = newElement.getChildren().iterator();
|
||||
final Iterator<Element> chIt = relatedToNew.getChildren().iterator();
|
||||
|
||||
while (newChIt.hasNext()) {
|
||||
childRight = applySegments(newChIt.next(), chIt.next(), childRight, level + 1);
|
||||
}
|
||||
} else {
|
||||
relatedToNew.text = new LinkedList<>();
|
||||
}
|
||||
// before element close tag pos
|
||||
// +
|
||||
// <parent>\n <child>text</child>
|
||||
int beforeCloseLeft;
|
||||
if (newElement.hasChildren()) {
|
||||
beforeCloseLeft = childRight + levelTextLength + 1;
|
||||
} else {
|
||||
beforeCloseLeft = childRight + newElement.getText().length();
|
||||
}
|
||||
relatedToNew.text.add(new Segment(childRight + 1, beforeCloseLeft));
|
||||
relatedToNew.end =
|
||||
new Segment(beforeCloseLeft + 1, beforeCloseLeft + closeTagLength(newElement));
|
||||
return relatedToNew.end.right;
|
||||
}
|
||||
|
||||
private byte[] normalizeLineEndings(byte[] src) {
|
||||
final String separator = System.getProperty("line.separator");
|
||||
// replacing all \r\n with \n
|
||||
if (separator.equals("\r\n")) {
|
||||
src = replaceAll(src, "\r\n".getBytes(), "\n".getBytes());
|
||||
}
|
||||
// replacing all \r with \n to prevent combination of \r\n which was created after
|
||||
// \r\n replacement, i.e. content \r\r\n after first replacement will be \r\n which is not okay
|
||||
return replaceAll(src, "\r".getBytes(), "\n".getBytes());
|
||||
}
|
||||
|
||||
/** Describes element, attribute or text position in the source array of bytes. */
|
||||
static class Segment {
|
||||
int left;
|
||||
int right;
|
||||
|
||||
Segment(int left, int right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Segment)) {
|
||||
return false;
|
||||
}
|
||||
final Segment other = (Segment) obj;
|
||||
return other.left == left && other.right == right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * left ^ 31 * right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "left: " + left + ", right: " + right;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(getBytes(), UTF_8);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
/** @author Eugene Voevodin */
|
||||
public class XMLTreeException extends RuntimeException {
|
||||
|
||||
public static XMLTreeException wrap(Exception ex) {
|
||||
return new XMLTreeException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
public XMLTreeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public XMLTreeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Helps to add new tree elements in specified places
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public class XMLTreeLocation {
|
||||
|
||||
/** Location which indicates position after element with given name */
|
||||
public static XMLTreeLocation after(String name) {
|
||||
return new XMLTreeLocation(LocationType.AFTER, name);
|
||||
}
|
||||
|
||||
/** Location which indicates position before element with given name */
|
||||
public static XMLTreeLocation before(String name) {
|
||||
return new XMLTreeLocation(LocationType.BEFORE, name);
|
||||
}
|
||||
|
||||
/** Location which indicates after last element position */
|
||||
public static XMLTreeLocation inTheEnd() {
|
||||
return new XMLTreeLocation(LocationType.END, "");
|
||||
}
|
||||
|
||||
/** Location which indicates before first element position */
|
||||
public static XMLTreeLocation inTheBegin() {
|
||||
return new XMLTreeLocation(LocationType.BEGIN, "");
|
||||
}
|
||||
|
||||
/** Indicates position after any of elements with given names */
|
||||
public static XMLTreeLocation afterAnyOf(String... names) {
|
||||
if (names.length == 0) {
|
||||
throw new IllegalArgumentException("Required not empty elements names");
|
||||
}
|
||||
return disjunctionChain(LocationType.AFTER, names);
|
||||
}
|
||||
|
||||
/** Indicates position before any of elements with given names */
|
||||
public static XMLTreeLocation beforeAnyOf(String... names) {
|
||||
if (names.length == 0) {
|
||||
throw new IllegalArgumentException("Required not empty elements names");
|
||||
}
|
||||
return disjunctionChain(LocationType.BEFORE, names);
|
||||
}
|
||||
|
||||
/** Connects locations with same type by {@link #or} connector */
|
||||
private static XMLTreeLocation disjunctionChain(LocationType location, String[] names) {
|
||||
final XMLTreeLocation treeLocation = new XMLTreeLocation(location, names[0]);
|
||||
for (int i = 1; i < names.length; i++) {
|
||||
treeLocation.or(new XMLTreeLocation(location, names[i]));
|
||||
}
|
||||
return treeLocation;
|
||||
}
|
||||
|
||||
private LinkedList<XMLTreeLocation> locations;
|
||||
private LocationType location;
|
||||
private String name;
|
||||
|
||||
private XMLTreeLocation(LocationType location, String name) {
|
||||
this.location = location;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public XMLTreeLocation or(XMLTreeLocation location) {
|
||||
locations().add(location);
|
||||
return this;
|
||||
}
|
||||
|
||||
void evalInsert(Element parent, NewElement newElement) {
|
||||
locations().addFirst(this);
|
||||
for (XMLTreeLocation location : locations) {
|
||||
switch (location.location) {
|
||||
case AFTER:
|
||||
if (parent.hasSingleChild(location.name)) {
|
||||
parent.getSingleChild(location.name).insertAfter(newElement);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case BEFORE:
|
||||
if (parent.hasSingleChild(location.name)) {
|
||||
parent.getSingleChild(location.name).insertBefore(newElement);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case BEGIN:
|
||||
final Element first = parent.getFirstChild();
|
||||
if (first != null) {
|
||||
first.insertBefore(newElement);
|
||||
} else {
|
||||
parent.appendChild(newElement);
|
||||
}
|
||||
return;
|
||||
case END:
|
||||
parent.appendChild(newElement);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new XMLTreeException("It is not possible to insert element in specified location");
|
||||
}
|
||||
|
||||
private LinkedList<XMLTreeLocation> locations() {
|
||||
return locations == null ? locations = new LinkedList<>() : locations;
|
||||
}
|
||||
|
||||
private enum LocationType {
|
||||
AFTER,
|
||||
BEFORE,
|
||||
BEGIN,
|
||||
END
|
||||
}
|
||||
}
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import static java.lang.Character.isWhitespace;
|
||||
import static java.lang.Math.min;
|
||||
import static java.lang.System.arraycopy;
|
||||
import static java.util.Arrays.fill;
|
||||
import static org.w3c.dom.Node.ELEMENT_NODE;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* Utils for xml tree
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public final class XMLTreeUtil {
|
||||
|
||||
public static final Charset UTF_8 = Charset.forName("utf-8");
|
||||
public static final int SPACES_IN_TAB = 4;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* New content schema:
|
||||
*
|
||||
* [0 - left) + content + (right, src.elementLength)
|
||||
* </pre>
|
||||
*
|
||||
* @param src source array
|
||||
* @param left left anchor - not included to result
|
||||
* @param right right anchor - not included to result
|
||||
* @param content content which will be inserted between left and right
|
||||
* @return new content
|
||||
*/
|
||||
public static byte[] insertBetween(byte[] src, int left, int right, String content) {
|
||||
final byte[] contentSrc = content.getBytes(UTF_8);
|
||||
final byte[] newSrc = new byte[left + src.length - right + contentSrc.length - 1];
|
||||
arraycopy(src, 0, newSrc, 0, left);
|
||||
arraycopy(contentSrc, 0, newSrc, left, contentSrc.length);
|
||||
arraycopy(src, right + 1, newSrc, left + contentSrc.length, src.length - right - 1);
|
||||
return newSrc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* New content schema:
|
||||
*
|
||||
* [0 - pos) + content + [pos, src.elementLength)
|
||||
* </pre>
|
||||
*
|
||||
* @param src source array
|
||||
* @param pos start position for content insertion
|
||||
* @param content content which will be inserted from {@param anchor}
|
||||
* @return new content
|
||||
*/
|
||||
public static byte[] insertInto(byte[] src, int pos, String content) {
|
||||
final byte[] contentSrc = content.getBytes(UTF_8);
|
||||
final byte[] newSrc = new byte[src.length + contentSrc.length];
|
||||
arraycopy(src, 0, newSrc, 0, pos);
|
||||
arraycopy(contentSrc, 0, newSrc, pos, contentSrc.length);
|
||||
arraycopy(src, pos, newSrc, pos + contentSrc.length, src.length - pos);
|
||||
return newSrc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check given list contains only element and return it. If list size is not 1 {@link
|
||||
* XMLTreeException} will be thrown.
|
||||
*
|
||||
* @param target list to check
|
||||
* @return list only element
|
||||
*/
|
||||
public static <T> T single(List<T> target) {
|
||||
if (target.size() != 1) {
|
||||
throw new XMLTreeException("Required list with one element");
|
||||
}
|
||||
return target.get(0);
|
||||
}
|
||||
|
||||
public static int lastIndexOf(byte[] src, char c, int fromIdx) {
|
||||
for (int i = min(fromIdx, src.length - 1); i >= 0; i--) {
|
||||
if (src[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates how deep is the element in tree. First level is tree root and it is equal to 0.
|
||||
*
|
||||
* @param element target element
|
||||
* @return how deep is the element
|
||||
*/
|
||||
public static int level(Element element) {
|
||||
int level = 0;
|
||||
while (element.hasParent()) {
|
||||
element = element.getParent();
|
||||
level++;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
public static int openTagLength(NewElement element) {
|
||||
int len = 2; // '<' + '>'
|
||||
len += element.getName().length(); // 'name' or 'prefix:name'
|
||||
for (NewAttribute attribute : element.getAttributes()) {
|
||||
len += 1 + attributeLength(attribute); // ' ' + 'attr="value"' or 'pref:attr="value"'
|
||||
}
|
||||
// if is void add +1 '/'
|
||||
return element.isVoid() ? len + 1 : len;
|
||||
}
|
||||
|
||||
public static int closeTagLength(NewElement element) {
|
||||
return 3 + element.getLocalName().length(); // '<' + '/' + 'name' + '>'
|
||||
}
|
||||
|
||||
public static int attributeLength(NewAttribute attribute) {
|
||||
int len = 0;
|
||||
if (attribute.hasPrefix()) {
|
||||
len += attribute.getPrefix().length() + 1; // prefix + ':'
|
||||
}
|
||||
len += attribute.getName().length() + attribute.getValue().length() + 3;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts given number of tabs to each line of given source.
|
||||
*
|
||||
* @param src source which going to be tabulated
|
||||
* @param tabsCount how many tabs should be added before each line
|
||||
* @return tabulated source
|
||||
*/
|
||||
public static String tabulate(String src, int tabsCount) {
|
||||
char[] tabs = new char[SPACES_IN_TAB * tabsCount];
|
||||
fill(tabs, ' ');
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final String[] lines = src.split("\n");
|
||||
for (int i = 0; i < lines.length - 1; i++) {
|
||||
builder.append(tabs).append(lines[i]).append('\n');
|
||||
}
|
||||
builder.append(tabs).append(lines[lines.length - 1]);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches {@link Element} from {@link Node} using {@link Node#getUserData(String)}
|
||||
*
|
||||
* @param node node to fetch from
|
||||
* @return {@code null} if {@param node} is null or {@link Element} associated with given node
|
||||
*/
|
||||
public static Element asElement(Node node) {
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
return (Element) node.getUserData("element");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@link NodeList} to list of elements. Only nodes with type {@link Node#ELEMENT_NODE}
|
||||
* will be fetched other will be skipped
|
||||
*
|
||||
* @param list list of nodes to fetch elements from
|
||||
* @return list of fetched elements or empty list if node list doesn't contain any element node
|
||||
*/
|
||||
public static List<Element> asElements(NodeList list) {
|
||||
final List<Element> elements = new ArrayList<>(list.getLength());
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
if (list.item(i).getNodeType() == ELEMENT_NODE) {
|
||||
elements.add(asElement(list.item(i)));
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
public static <R> List<R> asElements(NodeList list, ElementMapper<? extends R> mapper) {
|
||||
final List<R> elements = new ArrayList<>(list.getLength());
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
if (list.item(i).getNodeType() == ELEMENT_NODE) {
|
||||
elements.add(mapper.map(asElement(list.item(i))));
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for target bytes in the source bytes.
|
||||
*
|
||||
* @param src where to search
|
||||
* @param target what to search
|
||||
* @param fromIdx source index to search from
|
||||
* @return index of the first occurrence or -1 if nothing was found
|
||||
*/
|
||||
public static int indexOf(byte[] src, byte[] target, int fromIdx) {
|
||||
final int to = src.length - target.length + 1;
|
||||
for (int i = fromIdx; i < to; i++) {
|
||||
if (src[i] == target[0]) {
|
||||
boolean equals = true;
|
||||
for (int j = 1, k = i + 1; j < target.length && equals; j++, k++) {
|
||||
if (src[k] != target[j]) {
|
||||
equals = false;
|
||||
}
|
||||
}
|
||||
if (equals) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for attribute name bytes in the source bytes. The main difference with {@link #indexOf}
|
||||
* is that if occurrence was found then we need to check next byte as character, if it is
|
||||
* whitespace character or it equals to '=' attribute name was found otherwise continue searching
|
||||
*
|
||||
* @param src where to search
|
||||
* @param target attribute name bytes to search
|
||||
* @param fromIdx source index to search from
|
||||
* @return index of the first attribute name occurrence or -1 if nothing was found
|
||||
*/
|
||||
public static int indexOfAttributeName(byte[] src, byte[] target, int fromIdx) {
|
||||
final int idx = indexOf(src, target, fromIdx);
|
||||
if (idx == -1) {
|
||||
return -1;
|
||||
}
|
||||
final int next = idx + target.length;
|
||||
if (next == src.length || isWhitespace(src[next]) || src[next] == '=') {
|
||||
return idx;
|
||||
}
|
||||
return indexOfAttributeName(src, target, idx + 1);
|
||||
}
|
||||
|
||||
public static byte[] replaceAll(byte[] src, byte[] target, byte[] replacement) {
|
||||
final ByteArrayOutputStream result = new ByteArrayOutputStream(src.length);
|
||||
int i = 0;
|
||||
int wrote = 0;
|
||||
while ((i = indexOf(src, target, i)) != -1) {
|
||||
int len = i - wrote;
|
||||
result.write(src, wrote, len);
|
||||
result.write(replacement, 0, replacement.length);
|
||||
wrote += len + target.length;
|
||||
i += target.length;
|
||||
}
|
||||
result.write(src, wrote, src.length - wrote);
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
public static int rootStart(byte[] xml) {
|
||||
final byte[] open = {'<'};
|
||||
int pos = indexOf(xml, open, 0);
|
||||
while (xml[pos + 1] == '?' || xml[pos + 1] == '!') {
|
||||
if (xml[pos + 1] == '!' && xml[pos + 2] == '-' && xml[pos + 3] == '-') {
|
||||
pos = indexOf(xml, new byte[] {'-', '-', '>'}, pos + 1);
|
||||
}
|
||||
pos = indexOf(xml, open, pos + 1);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
private XMLTreeUtil() {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2018 Red Hat, Inc.
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.commons.xml;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.closeTagLength;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.indexOf;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.indexOfAttributeName;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.insertBetween;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.insertInto;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.lastIndexOf;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.openTagLength;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.replaceAll;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.rootStart;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.single;
|
||||
import static org.eclipse.che.commons.xml.XMLTreeUtil.tabulate;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link XMLTreeUtil}
|
||||
*
|
||||
* @author Eugene Voevodin
|
||||
*/
|
||||
public class XMLTreeUtilTest {
|
||||
|
||||
@Test
|
||||
public void shouldTabulateOneLineString() {
|
||||
final String src = "text here";
|
||||
|
||||
assertEquals(tabulate(src, 2), " " + src);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTabulateMultilineString() {
|
||||
final String src = "first line\nsecond line";
|
||||
|
||||
assertEquals(tabulate(src, 1), " first line\n second line");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFirstElement() {
|
||||
assertEquals(single(asList("first")), "first");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = XMLTreeException.class)
|
||||
public void shouldThrowExceptionWhenListContainsNotOnlyElement() {
|
||||
single(asList("first", "second"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInsertContentBetweenTwoAnchors() {
|
||||
// 6 12
|
||||
final byte[] src = "<name>content</name>".getBytes();
|
||||
|
||||
final byte[] newSrc = insertBetween(src, 6, 12, "new content");
|
||||
|
||||
assertEquals(newSrc, "<name>new content</name>".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInsertContentToCharArrayInSelectedPlace() {
|
||||
// 6
|
||||
final byte[] src = "<name></name>".getBytes();
|
||||
|
||||
final byte[] newSrc = insertInto(src, 6, "new content");
|
||||
|
||||
assertEquals(new String(newSrc).intern(), "<name>new content</name>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToFindLastIndexOf() {
|
||||
// 11 20 28
|
||||
final byte[] src = "...</before>\n <current>...".getBytes();
|
||||
|
||||
assertEquals(lastIndexOf(src, '>', 20), 11);
|
||||
assertEquals(lastIndexOf(src, '>', src.length - 1), 28);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToGetElementOpenTagLength() {
|
||||
// <test>test</test>
|
||||
final NewElement newElement = NewElement.createElement("test", "test");
|
||||
|
||||
assertEquals(openTagLength(newElement), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToGetElementCloseTagLength() {
|
||||
// <test>test</test>
|
||||
final NewElement newElement = NewElement.createElement("test", "test");
|
||||
|
||||
assertEquals(closeTagLength(newElement), 7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToGetIndexOf() {
|
||||
final String src =
|
||||
"<element attribute1=\"value1\" attribute2=\"value2\" attribute3=\"value3\">text</element>";
|
||||
final byte[] byteSrc = src.getBytes();
|
||||
|
||||
assertEquals(indexOf(byteSrc, "attribute1".getBytes(), 0), src.indexOf("attribute1"));
|
||||
assertEquals(indexOf(byteSrc, "attribute2".getBytes(), 0), src.indexOf("attribute2"));
|
||||
assertEquals(indexOf(byteSrc, "attribute3".getBytes(), 0), src.indexOf("attribute3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMinusOneIfTargetBytesWereNotFound() {
|
||||
final String src = "source string";
|
||||
final byte[] byteSrc = src.getBytes();
|
||||
|
||||
assertNotEquals(indexOf(byteSrc, "string".getBytes(), 0), -1);
|
||||
assertEquals(indexOf(byteSrc, "strings".getBytes(), 0), -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToFindIndexOfAttributeNameBytes() {
|
||||
final String src =
|
||||
"<element attribute1=\"value1\" attribute2=\"value2\" attribute3=\"value3\">text</element>";
|
||||
final byte[] byteSrc = src.getBytes();
|
||||
|
||||
assertEquals(
|
||||
indexOfAttributeName(byteSrc, "attribute1".getBytes(), 0), src.indexOf("attribute1"));
|
||||
assertEquals(
|
||||
indexOfAttributeName(byteSrc, "attribute2".getBytes(), 0), src.indexOf("attribute2"));
|
||||
assertEquals(
|
||||
indexOfAttributeName(byteSrc, "attribute3".getBytes(), 0), src.indexOf("attribute3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMinusOneIfAttributeNameBytesWereNotFound() {
|
||||
final String src = "<element attribute12=\"value1\"/>";
|
||||
final byte[] byteSrc = src.getBytes();
|
||||
|
||||
assertEquals(indexOfAttributeName(byteSrc, "attribute1".getBytes(), 0), -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToReplaceMoreBytesWithLessBytes() {
|
||||
final byte[] src = "\r\n\r\n text \r\n\r\n".getBytes();
|
||||
|
||||
final byte[] newSrc = replaceAll(src, "\r\n".getBytes(), "\n".getBytes());
|
||||
|
||||
assertEquals(newSrc, "\n\n text \n\n".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToReplaceLessBytesWithMoreBytes() {
|
||||
final byte[] src = "\n\n text \n\n text".getBytes();
|
||||
|
||||
final byte[] newSrc = replaceAll(src, "\n".getBytes(), "\r\n".getBytes());
|
||||
|
||||
assertEquals(newSrc, "\r\n\r\n text \r\n\r\n text".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToReplaceBytes() {
|
||||
final byte[] src = "\r\r text \r\r text \r\r text \r\r".getBytes();
|
||||
|
||||
final byte[] newSrc = replaceAll(src, "\r".getBytes(), "\n".getBytes());
|
||||
|
||||
assertEquals(newSrc, "\n\n text \n\n text \n\n text \n\n".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotReplaceBytesIfTargetBytesWereNotFound() {
|
||||
final byte[] src = "\n\n text \n\n text".getBytes();
|
||||
|
||||
final byte[] newSrc = replaceAll(src, "\r\n".getBytes(), "\n".getBytes());
|
||||
|
||||
assertEquals(newSrc, "\n\n text \n\n text".getBytes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindRootStart() {
|
||||
final String src =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<!-- Comment -->"
|
||||
+ "<!-- Another comment -->"
|
||||
+ "<root></root>";
|
||||
|
||||
int start = rootStart(src.getBytes());
|
||||
|
||||
assertEquals(start, src.indexOf("<root>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindRootStartEvenIfCommentContainsStartCharacter() {
|
||||
final String src =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<!-- Comment < < -->"
|
||||
+ "<!-- Another < < comment -->"
|
||||
+ "<root></root>";
|
||||
|
||||
int start = rootStart(src.getBytes());
|
||||
|
||||
assertEquals(start, src.indexOf("<root>"));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2015 Red Hat, Inc.
|
||||
This program and the accompanying materials are made
|
||||
available under the terms of the Eclipse Public License 2.0
|
||||
which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
|
||||
SPDX-License-Identifier: EPL-2.0
|
||||
|
||||
Contributors:
|
||||
Red Hat, Inc. - initial API and implementation
|
||||
|
||||
-->
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
<book id="bk102">
|
||||
<author>Ralls, Kim</author>
|
||||
<title>Midnight Rain</title>
|
||||
<genre>Fantasy</genre>
|
||||
<price>5.95</price>
|
||||
<publish_date>2000-12-16</publish_date>
|
||||
<description>A former architect battles corporate zombies,
|
||||
an evil sorceress, and her own childhood to become queen
|
||||
of the world.</description>
|
||||
</book>
|
||||
<book id="bk103">
|
||||
<author>Corets, Eva</author>
|
||||
<title>Maeve Ascendant</title>
|
||||
<genre>Fantasy</genre>
|
||||
<price>5.95</price>
|
||||
<publish_date>2000-11-17</publish_date>
|
||||
<description>After the collapse of a nanotechnology
|
||||
society in England, the young survivors lay the
|
||||
foundation for a new society.</description>
|
||||
</book>
|
||||
<book id="bk104">
|
||||
<author>Corets, Eva</author>
|
||||
<title>Oberon's Legacy</title>
|
||||
<genre>Fantasy</genre>
|
||||
<price>5.95</price>
|
||||
<publish_date>2001-03-10</publish_date>
|
||||
<description>In post-apocalypse England, the mysterious
|
||||
agent known only as Oberon helps to create a new life
|
||||
for the inhabitants of London. Sequel to Maeve
|
||||
Ascendant.</description>
|
||||
</book>
|
||||
<book id="bk105">
|
||||
<author>Corets, Eva</author>
|
||||
<title>The Sundered Grail</title>
|
||||
<genre>Fantasy</genre>
|
||||
<price>5.95</price>
|
||||
<publish_date>2001-09-10</publish_date>
|
||||
<description>The two daughters of Maeve, half-sisters,
|
||||
battle one another for control of England. Sequel to
|
||||
Oberon's Legacy.</description>
|
||||
</book>
|
||||
<book id="bk106">
|
||||
<author>Randall, Cynthia</author>
|
||||
<title>Lover Birds</title>
|
||||
<genre>Romance</genre>
|
||||
<price>4.95</price>
|
||||
<publish_date>2000-09-02</publish_date>
|
||||
<description>When Carla meets Paul at an ornithology
|
||||
conference, tempers fly as feathers get ruffled.</description>
|
||||
</book>
|
||||
<book id="bk107">
|
||||
<author>Thurman, Paula</author>
|
||||
<title>Splish Splash</title>
|
||||
<genre>Romance</genre>
|
||||
<price>4.95</price>
|
||||
<publish_date>2000-11-02</publish_date>
|
||||
<description>A deep sea diver finds true love twenty
|
||||
thousand leagues beneath the sea.</description>
|
||||
</book>
|
||||
<book id="bk108">
|
||||
<author>Knorr, Stefan</author>
|
||||
<title>Creepy Crawlies</title>
|
||||
<genre>Horror</genre>
|
||||
<price>4.95</price>
|
||||
<publish_date>2000-12-06</publish_date>
|
||||
<description>An anthology of horror stories about roaches,
|
||||
centipedes, scorpions and other insects.</description>
|
||||
</book>
|
||||
<book id="bk109">
|
||||
<author>Kress, Peter</author>
|
||||
<title>Paradox Lost</title>
|
||||
<genre>Science Fiction</genre>
|
||||
<price>6.95</price>
|
||||
<publish_date>2000-11-02</publish_date>
|
||||
<description>After an inadvertant trip through a Heisenberg
|
||||
Uncertainty Device, James Salway discovers the problems
|
||||
of being quantum.</description>
|
||||
</book>
|
||||
<book id="bk110">
|
||||
<author>O'Brien, Tim</author>
|
||||
<title>Microsoft .NET: The Programming Bible</title>
|
||||
<genre>Computer</genre>
|
||||
<price>36.95</price>
|
||||
<publish_date>2000-12-09</publish_date>
|
||||
<description>Microsoft's .NET initiative is explored in
|
||||
detail in this deep programmer's reference.</description>
|
||||
</book>
|
||||
<book id="bk111">
|
||||
<author>O'Brien, Tim</author>
|
||||
<title>MSXML3: A Comprehensive Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>36.95</price>
|
||||
<publish_date>2000-12-01</publish_date>
|
||||
<description>The Microsoft MSXML3 parser is covered in
|
||||
detail, with attention to XML DOM interfaces, XSLT processing,
|
||||
SAX and more.</description>
|
||||
</book>
|
||||
<book id="bk112">
|
||||
<author>Galos, Mike</author>
|
||||
<title>Visual Studio 7: A Comprehensive Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>49.95</price>
|
||||
<publish_date>2001-04-16</publish_date>
|
||||
<description>Microsoft Visual Studio 7 is explored in depth,
|
||||
looking at how Visual Basic, Visual C++, C#, and ASP+ are
|
||||
integrated into a comprehensive development
|
||||
environment.</description>
|
||||
</book>
|
||||
</catalog>
|
||||
|
|
@ -1,305 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<project name="mr4c" default="build" xmlns:ac="antlib:net.sf.antcontrib"
|
||||
xmlns:jacoco="antlib:org.jacoco.ant"
|
||||
xmlns:ivy="antlib:org.apache.ivy.ant">
|
||||
|
||||
<description>Build, test and package the MR4C project.</description>
|
||||
|
||||
<property file="build.local.properties" />
|
||||
|
||||
<property file="build.properties" />
|
||||
|
||||
|
||||
|
||||
<propertyset id="mr4c.properties">
|
||||
<propertyref prefix="mr4c" />
|
||||
</propertyset>
|
||||
|
||||
<path id="compile.classpath">
|
||||
<fileset dir="${lib.dir}" />
|
||||
</path>
|
||||
|
||||
<path id="compile.classpath.test">
|
||||
<fileset dir="${lib.dir.test}" />
|
||||
</path>
|
||||
|
||||
<path id="run.classpath" >
|
||||
<pathelement location="${conf.dir}" />
|
||||
<pathelement location="${src.classes.dir}" />
|
||||
<path refid="compile.classpath" />
|
||||
</path>
|
||||
|
||||
<path id="test.classpath" >
|
||||
<pathelement location="${test.classes.dir}" />
|
||||
<path refid="compile.classpath.test" />
|
||||
<path refid="run.classpath" />
|
||||
</path>
|
||||
|
||||
<!-- Validate hadoop binding -->
|
||||
<fail message="Property hadoop.binding = [${hadoop.binding}]; must be 'mrv1' or 'yarn'" >
|
||||
<condition><not><or>
|
||||
<equals arg1="${hadoop.binding}" arg2="mrv1" />
|
||||
<equals arg1="${hadoop.binding}" arg2="yarn" />
|
||||
</or></not></condition>
|
||||
</fail>
|
||||
|
||||
<!-- Specifying which Hadoop binding classes not to compile -->
|
||||
<condition property="hadoop.binding.excludes" value="${hadoop.pkg.path}/yarn/**" >
|
||||
<equals arg1="${hadoop.binding}" arg2="mrv1" />
|
||||
</condition>
|
||||
<condition property="hadoop.binding.excludes" value="${hadoop.pkg.path}/mrv1/**" >
|
||||
<equals arg1="${hadoop.binding}" arg2="yarn" />
|
||||
</condition>
|
||||
|
||||
<!--
|
||||
NOTE: All targets with dependencies and tasks should follow the following pattern:
|
||||
Target do-XXX has no dependencies and all the tasks
|
||||
Target XXX has all the dependencies and no tasks, and also depends on do-XXX
|
||||
This allows externally calling pieces of the build without continuously executing dependent targets
|
||||
-->
|
||||
|
||||
<!-- TARGET: build -->
|
||||
<target name="build" depends="clean, test, dist" />
|
||||
|
||||
<!-- TARGET: clean -->
|
||||
<target name="clean" >
|
||||
<delete dir="${dist.dir}" />
|
||||
<delete dir="${lib.dir}" />
|
||||
<delete dir="${lib.dir.test}" />
|
||||
<delete dir="${src.classes.dir}" />
|
||||
<delete dir="${test.classes.dir}" />
|
||||
<delete dir="${reports.dir}" />
|
||||
<delete dir="${output.dir}" />
|
||||
<delete dir="${jna.gen.dir}" />
|
||||
<delete file="${hadoop.static.binder}" />
|
||||
<delete file="${hadoop.static.test.binder}" />
|
||||
<delete file="${hadoop.ivy}" />
|
||||
</target>
|
||||
|
||||
<!-- TARGET: init -->
|
||||
<target name="init" depends="make-dirs, select-hadoop-ivy, select-hadoop-binding" />
|
||||
|
||||
<!-- TARGET: make-dirs -->
|
||||
<target name="make-dirs" >
|
||||
<mkdir dir="${dist.dir}" />
|
||||
<mkdir dir="${lib.dir}" />
|
||||
<mkdir dir="${lib.dir.test}" />
|
||||
<mkdir dir="${src.classes.dir}" />
|
||||
<mkdir dir="${test.classes.dir}" />
|
||||
<mkdir dir="${reports.dir}" />
|
||||
<mkdir dir="${output.dir}" />
|
||||
</target>
|
||||
|
||||
<!-- TARGET: select-hadoop-ivy -->
|
||||
<target name="select-hadoop-ivy" >
|
||||
<copy file="${hadoop.ivy.src}" tofile="${hadoop.ivy}" />
|
||||
</target>
|
||||
|
||||
<!-- TARGET: select-hadoop-binding -->
|
||||
<target name="select-hadoop-binding" >
|
||||
<copy file="${hadoop.static.binder.src}" tofile="${hadoop.static.binder}" />
|
||||
<copy file="${hadoop.static.test.binder.src}" tofile="${hadoop.static.test.binder}" />
|
||||
</target>
|
||||
|
||||
|
||||
<!-- TARGET: resolve -->
|
||||
<target name="resolve" depends = "init, do-resolve" />
|
||||
|
||||
<!-- TARGET: do-resolve -->
|
||||
<target name="do-resolve" depends= "select-hadoop-ivy, retrieve" />
|
||||
|
||||
<!-- TARGET: retrieve -->
|
||||
<target name="retrieve" >
|
||||
<taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar}" />
|
||||
<ivy:retrieve/>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: compile -->
|
||||
<target name="compile" depends="init, resolve, do-compile" />
|
||||
|
||||
<!-- TARGET: do-compile -->
|
||||
<target name="do-compile" depends="jnaerate, comp-src, comp-test" />
|
||||
|
||||
<!-- TARGET: jnaerate -->
|
||||
<target name="jnaerate" description="--> run JNAerator on native lib">
|
||||
<java classname="com.ochafik.lang.jnaerator.JNAerator" fork="false" failonerror="true" >
|
||||
<arg value="-library" />
|
||||
<arg value="mr4c" />
|
||||
<arg value="-o" />
|
||||
<arg value="${src.dir}" />
|
||||
<arg value="-package" />
|
||||
<arg value="com.google.mr4c.nativec.jna.lib" />
|
||||
<arg value="-f" />
|
||||
<arg value="-mode" />
|
||||
<arg value="Directory" />
|
||||
<arg value="-runtime" />
|
||||
<arg value="JNAerator" />
|
||||
<arg value="-I${mr4c.api.dir}" />
|
||||
<!--arg value="-I/usr/lib/gcc/x86_64-linux-gnu/4.4/include" /--> <!-- for stdbool.h -->
|
||||
<arg value="${mr4c.api.dir}/external_capi.h" />
|
||||
<classpath refid="compile.classpath" />
|
||||
</java>
|
||||
<fail message="Jnaerator failed to produce a java file" >
|
||||
<condition>
|
||||
<not>
|
||||
<available file="${jna.gen.dir}/Mr4cLibrary.java" />
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: fix-library-load -->
|
||||
<target name="fix-library-load" description="--> fix the arguments to getLibraryPath">
|
||||
|
||||
<exec executable="sed" dir="${jna.gen.dir}" output="${jna.gen.dir}/Mr4cLibrary.java" logError="true" input="${jna.gen.dir}/Mr4cLibrary.java" failonerror="true" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/\(getLibraryPath.*\)true\(.*\)/\1false\2/" />
|
||||
</exec>
|
||||
<fail message="Couldn't fix the Mr4cLibrary file" >
|
||||
<condition>
|
||||
<not>
|
||||
<available file="${jna.gen.dir}/Mr4cLibrary.java" />
|
||||
</not>
|
||||
</condition>
|
||||
</fail>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: comp-src -->
|
||||
<target name="comp-src" >
|
||||
<copy todir="${src.classes.dir}">
|
||||
<fileset dir="${basedir}/src/resources" />
|
||||
</copy>
|
||||
<javac
|
||||
destdir="${src.classes.dir}"
|
||||
failonerror="true"
|
||||
source="1.6"
|
||||
target="1.6"
|
||||
debug="on"
|
||||
includeantruntime="false"
|
||||
excludes="${hadoop.binding.excludes}"
|
||||
>
|
||||
<src path="${src.dir}" />
|
||||
<src path="${third.dir}/etsy/src/java" />
|
||||
<src path="${third.dir}/stack_overflow/src/java" />
|
||||
<classpath refid="compile.classpath" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: comp-test -->
|
||||
<target name="comp-test" >
|
||||
<copy todir="${test.classes.dir}">
|
||||
<fileset dir="${basedir}/test/resources" />
|
||||
</copy>
|
||||
<javac
|
||||
destdir="${test.classes.dir}"
|
||||
failonerror="true"
|
||||
source="1.6"
|
||||
target="1.6"
|
||||
debug="on"
|
||||
includeantruntime="false"
|
||||
excludes="${hadoop.binding.excludes}"
|
||||
>
|
||||
<src path="${test.dir}" />
|
||||
<src path="${third.dir}/hadoop/test/java" />
|
||||
<classpath location="${src.classes.dir}" />
|
||||
<classpath refid="compile.classpath" />
|
||||
<classpath refid="compile.classpath.test" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: test -->
|
||||
<target name="test" depends="init, compile, do-test" />
|
||||
|
||||
<!-- TARGET: do-test -->
|
||||
<target name="do-test" >
|
||||
<junit fork="true" printsummary="no" haltonfailure="no" forkmode="perBatch" dir="${basedir}">
|
||||
<syspropertyset refid="mr4c.properties"/>
|
||||
<classpath refid="test.classpath" />
|
||||
|
||||
<formatter type="xml" />
|
||||
<!--formatter type="plain" usefile="false" /-->
|
||||
|
||||
<batchtest failureproperty="test.failed" todir="${reports.dir}">
|
||||
<fileset dir="${test.dir}">
|
||||
<include name="**/*Test.java" />
|
||||
</fileset>
|
||||
</batchtest>
|
||||
<env key="LD_LIBRARY_PATH" path="${jna.library.path}" />
|
||||
<env key="MR4C_LOG4CXX_CONFIG" path="${mr4c.log4cxx}" />
|
||||
<env key="MR4C_UNIT_TEST" path="${mr4c.unit.test}" />
|
||||
</junit>
|
||||
<fail if="${test.failed}" />
|
||||
</target>
|
||||
|
||||
<!-- TARGET: test-class -->
|
||||
<target name="test-class" >
|
||||
<junit fork="true" printsummary="no" haltonfailure="no" forkmode="perTest" dir="${basedir}">
|
||||
<syspropertyset refid="mr4c.properties"/>
|
||||
<classpath refid="test.classpath" />
|
||||
<formatter type="plain" usefile="false" />
|
||||
<test name="${test-class.base}${test-class.class}" failureproperty="test.failed" />
|
||||
<env key="LD_LIBRARY_PATH" path="${jna.library.path}" />
|
||||
<env key="MR4C_LOG4CXX_CONFIG" path="${mr4c.log4cxx}" />
|
||||
<env key="MR4C_UNIT_TEST" path="${mr4c.unit.test}" />
|
||||
</junit>
|
||||
<fail if="${test.failed}" />
|
||||
</target>
|
||||
|
||||
<!-- TARGET: dist -->
|
||||
<target name="dist" depends="init, compile, do-dist" />
|
||||
|
||||
<!-- TARGET: do-dist -->
|
||||
<target name="do-dist" depends="jar, jar-test, jar-with-libs" />
|
||||
|
||||
<!-- TARGET: jar -->
|
||||
<target name="jar" >
|
||||
<jar destfile="${dist.dir}/${product.name}.jar">
|
||||
<fileset dir="${src.classes.dir}" />
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: jar-test -->
|
||||
<target name="jar-test" >
|
||||
<jar destfile="${dist.dir}/${product.name}-test.jar">
|
||||
<fileset dir="${test.classes.dir}" />
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="jar-with-libs" >
|
||||
<echo>${lib.dir}</echo>
|
||||
<jar destfile="${dist.dir}/${product.name}-with-libs.jar">
|
||||
<fileset dir="${src.classes.dir}" />
|
||||
<fileset dir="${basedir}" includes="lib/**" />
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: deploy -->
|
||||
<target name="deploy" >
|
||||
<mkdir dir="${deploy.dir}" />
|
||||
<copy todir="${deploy.dir}/bin" >
|
||||
<fileset dir="${bin.dir}" includes="**/*" />
|
||||
</copy>
|
||||
<chmod perm="+x" >
|
||||
<fileset dir="${deploy.dir}/bin" includes="**/*" />
|
||||
</chmod>
|
||||
<copy todir="${deploy.dir}/conf" >
|
||||
<fileset dir="${conf.dir}" includes="**/*" />
|
||||
</copy>
|
||||
<copy todir="${deploy.dir}/dist" >
|
||||
<fileset dir="${dist.dir}" includes="**/*" />
|
||||
</copy>
|
||||
<copy todir="${deploy.dir}/lib" >
|
||||
<fileset dir="${lib.dir}" includes="**/*" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<!-- TARGET: remove -->
|
||||
<target name="remove" >
|
||||
<delete dir="${deploy.dir}" />
|
||||
</target>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</project>
|
||||
|
|
@ -1,449 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.samples</groupId>
|
||||
<artifactId>spring-petclinic</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<name>petclinic</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
|
||||
<!-- Generic properties -->
|
||||
<java.version>1.6</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
|
||||
<!-- Spring -->
|
||||
<spring-framework.version>4.1.4.RELEASE</spring-framework.version>
|
||||
<spring-data-jpa.version>1.7.1.RELEASE</spring-data-jpa.version>
|
||||
|
||||
|
||||
<!-- Java EE / Java SE dependencies -->
|
||||
<jsp.version>2.2</jsp.version>
|
||||
<jstl.version>1.2</jstl.version>
|
||||
<tomcat.servlet.version>7.0.30</tomcat.servlet.version>
|
||||
<jaxb-impl.version>2.2.7</jaxb-impl.version>
|
||||
|
||||
<!-- Hibernate / JPA -->
|
||||
<hibernate.version>4.3.8.Final</hibernate.version>
|
||||
|
||||
<!-- Bean validation -->
|
||||
<hibernate-validator.version>4.3.1.Final</hibernate-validator.version>
|
||||
|
||||
<!-- Database access -->
|
||||
<tomcat-jdbc.version>7.0.42</tomcat-jdbc.version>
|
||||
<ehcache.version>2.6.10</ehcache.version>
|
||||
<hsqldb.version>2.3.2</hsqldb.version>
|
||||
|
||||
<!-- AOP -->
|
||||
<aspectj.version>1.8.4</aspectj.version>
|
||||
|
||||
<!-- Logging -->
|
||||
<logback.version>1.1.2</logback.version>
|
||||
<slf4j.version>1.7.10</slf4j.version>
|
||||
|
||||
<!-- RSS -->
|
||||
<rome.version>1.5.0</rome.version>
|
||||
|
||||
<!-- Test -->
|
||||
<junit.version>4.12</junit.version>
|
||||
<assertj.version>1.7.1</assertj.version>
|
||||
|
||||
<!-- Dates -->
|
||||
<jodatime-hibernate.version>1.3</jodatime-hibernate.version>
|
||||
<jodatime-jsptags.version>1.1.1</jodatime-jsptags.version>
|
||||
<jodatime.version>2.7</jodatime.version>
|
||||
<jadira-usertype-core.version>3.2.0.GA</jadira-usertype-core.version>
|
||||
|
||||
|
||||
<!-- Web dependencies -->
|
||||
<webjars-bootstrap.version>2.3.0</webjars-bootstrap.version>
|
||||
<webjars-jquery-ui.version>1.10.3</webjars-jquery-ui.version>
|
||||
<webjars-jquery.version>2.0.3-1</webjars-jquery.version>
|
||||
<dandelion.version>0.10.1</dandelion.version>
|
||||
|
||||
<mysql.version>5.1.22</mysql.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jadira.usertype</groupId>
|
||||
<artifactId>usertype.core</artifactId>
|
||||
<version>${jadira-usertype-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-servlet-api</artifactId>
|
||||
<version>${tomcat.servlet.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet.jsp</groupId>
|
||||
<artifactId>jsp-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.web</groupId>
|
||||
<artifactId>jstl-impl</artifactId>
|
||||
<version>1.2</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>${jaxb-impl.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- SPRING, SPRING, SPRINGITY SPRING -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jpa</artifactId>
|
||||
<version>${spring-data-jpa.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<!-- used for EhCacheCacheManager -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-oxm</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Database connection pool
|
||||
See here for more details on commons-dbcp versus tomcat-jdbc:
|
||||
http://blog.ippon.fr/2013/03/13/improving-the-performance-of-the-spring-petclinic-sample-application-part-3-of-5/
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-jdbc</artifactId>
|
||||
<version>${tomcat-jdbc.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging with SLF4J & LogBack -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- used for Atom -->
|
||||
<dependency>
|
||||
<groupId>com.rometools</groupId>
|
||||
<artifactId>rome</artifactId>
|
||||
<version>${rome.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Date and Time -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${jodatime.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time-hibernate</artifactId>
|
||||
<version>${jodatime-hibernate.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time-jsptags</artifactId>
|
||||
<version>${jodatime-jsptags.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Databases - Uses HSQL by default -->
|
||||
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>${hsqldb.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- For MySql only -->
|
||||
<!-- <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> -->
|
||||
<!-- HIBERNATE -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>${hibernate.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>${hibernate-validator.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-ehcache</artifactId>
|
||||
<version>${hibernate.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
<version>${ehcache.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- Webjars (static dependencies distributed as JAR files) -->
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<version>${webjars-bootstrap.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery-ui</artifactId>
|
||||
<version>${webjars-jquery-ui.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
<version>${webjars-jquery.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test Artifacts -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>${aspectj.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Dandelion -->
|
||||
<dependency>
|
||||
<groupId>com.github.dandelion</groupId>
|
||||
<artifactId>datatables-jsp</artifactId>
|
||||
<version>${dandelion.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.dandelion</groupId>
|
||||
<artifactId>datatables-export-itext</artifactId>
|
||||
<version>${dandelion.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!--
|
||||
Force the version of all the spring jars (core, beans, context, ...)
|
||||
pulled by spring-data-jpa:1.3.4.RELEASE to 3.2.x when spring-data pulls
|
||||
the 3.1.x versions to prevent some misbehaviors of maven which sometimes
|
||||
pulls both 3.2.x and 3.1.x versions of spring-core, spring-beans and spring-context
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
<version>${spring-framework.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<!-- Maven plugin versions are mentioned in order to guarantee the build reproducibility in the long term -->
|
||||
<build>
|
||||
<defaultGoal>install</defaultGoal>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<!-- declared explicitly so Spring config files can be placed next to their corresponding JUnit test class
|
||||
(see example with ValidatorTests) -->
|
||||
<directory>${project.basedir}/src/test/java</directory>
|
||||
</testResource>
|
||||
<testResource>
|
||||
<directory>${project.basedir}/src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<compilerArguments>
|
||||
<Xlint />
|
||||
</compilerArguments>
|
||||
<verbose>true</verbose>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<showWarnings>true</showWarnings>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.13</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Tests.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<configuration>
|
||||
<warName>petclinic</warName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<version>2.9</version>
|
||||
<configuration>
|
||||
<downloadSources>true</downloadSources>
|
||||
<downloadJavadocs>true</downloadJavadocs>
|
||||
<wtpversion>2.0</wtpversion>
|
||||
<sourceIncludes>
|
||||
<sourceInclude>**/*.*</sourceInclude>
|
||||
</sourceIncludes>
|
||||
<additionalBuildcommands>
|
||||
<buildCommand>
|
||||
<name>org.springframework.ide.eclipse.core.springbuilder</name>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
</buildCommand>
|
||||
</additionalBuildcommands>
|
||||
<additionalProjectnatures>
|
||||
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
|
||||
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
|
||||
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
|
||||
</additionalProjectnatures>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.tomcat.maven</groupId>
|
||||
<artifactId>tomcat7-maven-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<configuration>
|
||||
<server>tomcat-development-server</server>
|
||||
<port>9966</port>
|
||||
<path>/petclinic</path>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<url>demopetclinic</url>
|
||||
</project>
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
<module>che-core-commons-lang</module>
|
||||
<module>che-core-commons-inject</module>
|
||||
<module>che-core-commons-json</module>
|
||||
<module>che-core-commons-xml</module>
|
||||
<module>che-core-commons-schedule</module>
|
||||
<module>che-core-commons-test</module>
|
||||
<module>che-core-commons-j2ee</module>
|
||||
|
|
|
|||
11
pom.xml
11
pom.xml
|
|
@ -97,7 +97,6 @@
|
|||
<jakarta.ws.rs.version>3.0.0</jakarta.ws.rs.version>
|
||||
<java.target.version>11</java.target.version>
|
||||
<jdk.min.version>${java.target.version}</jdk.min.version>
|
||||
<junit.version>4.13.1</junit.version>
|
||||
<license_contributor>Red Hat, Inc. - initial API and implementation</license_contributor>
|
||||
<?SORTPOM IGNORE?>
|
||||
<build.info>${project.version}</build.info>
|
||||
|
|
@ -501,11 +500,6 @@
|
|||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
<version>${jakarta.ws.rs.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
|
|
@ -915,11 +909,6 @@
|
|||
<artifactId>che-core-commons-tracing</artifactId>
|
||||
<version>${che.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-commons-xml</artifactId>
|
||||
<version>${che.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.che.core</groupId>
|
||||
<artifactId>che-core-db</artifactId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue