/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.antx.util.configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
/**
* This class has a bunch of utility methods to work with configuration objects.
*
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
*/
public class ConfigurationUtil {
/** Private constructor to block instantiation. */
private ConfigurationUtil() {
}
/**
* Convert a configuration tree into a DOM Element tree.
*
* @param configuration the configuration object
* @return the DOM Element
*/
public static Element toElement(final Configuration configuration) {
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document document = builder.newDocument();
return createElement(document, configuration);
} catch (final ParserConfigurationException pce) {
throw new IllegalStateException(pce.toString());
}
}
/**
* Test to see if two Configuration's can be considered the same. Name,
* value, attributes and children are test. The <b>order</b> of children is
* not taken into consideration for equality.
*
* @param c1 Configuration to test
* @param c2 Configuration to test
* @return true if the configurations can be considered equals
*/
public static boolean equals(final Configuration c1, final Configuration c2) {
return c1.getName().equals(c2.getName()) && areValuesEqual(c1, c2) && areAttributesEqual(c1, c2)
&& areChildrenEqual(c1, c2);
}
/**
* Return true if the children of both configurations are equal.
*
* @param c1 configuration1
* @param c2 configuration2
* @return true if the children of both configurations are equal.
*/
private static boolean areChildrenEqual(final Configuration c1, final Configuration c2) {
final Configuration[] kids1 = c1.getChildren();
final ArrayList kids2 = new ArrayList(Arrays.asList(c2.getChildren()));
if (kids1.length != kids2.size()) {
return false;
}
for (int i = 0; i < kids1.length; i++) {
if (!findMatchingChild(kids1[i], kids2)) {
return false;
}
}
return kids2.isEmpty() ? true : false;
}
/**
* Return true if find a matching child and remove child from list.
*
* @param c the configuration
* @param matchAgainst the list of items to match against
* @return true if the found.
*/
private static boolean findMatchingChild(final Configuration c, final ArrayList matchAgainst) {
final Iterator i = matchAgainst.iterator();
while (i.hasNext()) {
if (equals(c, (Configuration) i.next())) {
i.remove();
return true;
}
}
return false;
}
/**
* Return true if the attributes of both configurations are equal.
*
* @param c1 configuration1
* @param c2 configuration2
* @return true if the attributes of both configurations are equal.
*/
private static boolean areAttributesEqual(final Configuration c1, final Configuration c2) {
final String[] names1 = c1.getAttributeNames();
final String[] names2 = c2.getAttributeNames();
if (names1.length != names2.length) {
return false;
}
for (final String name : names1) {
final String value1 = c1.getAttribute(name, null);
final String value2 = c2.getAttribute(name, null);
if (!value1.equals(value2)) {
return false;
}
}
return true;
}
/**
* Return true if the values of two configurations are equal.
*
* @param c1 configuration1
* @param c2 configuration2
* @return true if the values of two configurations are equal.
*/
private static boolean areValuesEqual(final Configuration c1, final Configuration c2) {
final String value1 = c1.getValue(null);
final String value2 = c2.getValue(null);
return value1 == null && value2 == null || value1 != null && value1.equals(value2);
}
/**
* Create an DOM {@link Element} from a {@link Configuration} object.
*
* @param document the DOM document
* @param configuration the configuration to convert
* @return the DOM Element
*/
private static Element createElement(final Document document, final Configuration configuration) {
final Element element = document.createElement(configuration.getName());
final String content = configuration.getValue(null);
if (null != content) {
final Text child = document.createTextNode(content);
element.appendChild(child);
}
final String[] names = configuration.getAttributeNames();
for (final String name : names) {
final String value = configuration.getAttribute(name, null);
element.setAttribute(name, value);
}
final Configuration[] children = configuration.getChildren();
for (Configuration element2 : children) {
final Element child = createElement(document, element2);
element.appendChild(child);
}
return element;
}
}