build: Remove unused dependencies and modules (#141)

pull/147/head
Sergii Kabashniuk 2021-09-27 09:25:55 +03:00 committed by GitHub
parent c95c0d56ea
commit f000ed5aa6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 0 additions and 5696 deletions

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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() {}
}

View File

@ -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>"));
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
View File

@ -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>