![JAR search and dependency download from the Maven repository](/logo.png)
org.xins.client.DataElement Maven / Gradle / Ivy
/*
* $Id: DataElement.java,v 1.41 2006/10/25 09:39:34 agoubard Exp $
*
* Copyright 2003-2006 Orange Nederland Breedband B.V.
* See the COPYRIGHT file for redistribution and use restrictions.
*/
package org.xins.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.xins.common.MandatoryArgumentChecker;
import org.xins.common.Utils;
import org.xins.common.text.TextUtils;
import org.xins.common.xml.Element;
import org.xins.common.xml.ElementBuilder;
/**
* Element in a XINS result data section.
*
* Note that this class is not thread-safe. It should not be used from
* different threads at the same time. This applies even to read operations.
*
*
Note that the namespace URIs and local names are not checked for
* validity in this class.
*
* @version $Revision: 1.41 $ $Date: 2006/10/25 09:39:34 $
* @author Anthony Goubard
* @author Ernst de Haan
*
* @since XINS 1.0.0
*/
public class DataElement implements Cloneable {
// NOTE: The behavior of this class has been slightly redefined in XINS
// 1.1. In XINS 1.0, the name for a DataElement was a combination of
// the namespace prefix and the local name. In XINS 1.1, the name is
// just the local name. Since XINS 1.0 did not support XML Namespaces
// yet, this is not considered an incompatibility.
//-------------------------------------------------------------------------
// Class fields
//-------------------------------------------------------------------------
/**
* Fully-qualified name of this class.
*/
private static final String CLASSNAME = DataElement.class.getName();
//-------------------------------------------------------------------------
// Constructors
//-------------------------------------------------------------------------
/**
* Creates a new DataElement
.
*
* @param namespaceURI
* the namespace URI for the element, can be null
; an empty
* string is equivalent to null
.
*
* @param localName
* the local name of the element, cannot be null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*/
DataElement(String namespaceURI, String localName)
throws IllegalArgumentException {
// Check preconditions
MandatoryArgumentChecker.check("localName", localName);
// An empty namespace URI is equivalent to null
if (namespaceURI != null && namespaceURI.length() < 1) {
namespaceURI = null;
}
// Store namespace URI and local name
_namespaceURI = namespaceURI;
_localName = localName;
}
//-------------------------------------------------------------------------
// Fields
//-------------------------------------------------------------------------
/**
* The namespace URI. This field can be null
, but it can never
* be an empty string.
*/
private final String _namespaceURI;
/**
* The local name. This field is never null
.
*/
private final String _localName;
/**
* The child elements. This field is lazily initialized is initially
* null
.
*/
private ArrayList _children;
/**
* The attributes. This field is lazily initialized and is initially
* null
.
*/
private HashMap _attributes;
/**
* The character content for this element. Can be null
.
*/
private String _text;
//-------------------------------------------------------------------------
// Methods
//-------------------------------------------------------------------------
/**
* Gets the namespace URI.
*
* @return
* the namespace URI for this element, or null
if there is
* none, but never an empty string.
*
* @since XINS 1.1.0
*/
public String getNamespaceURI() {
return _namespaceURI;
}
/**
* Gets the local name.
*
* @return
* the local name of this element, cannot be null
.
*
* @since XINS 1.1.0
*/
public String getLocalName() {
return _localName;
}
/**
* Gets the local name.
*
* @return
* the local name of this element, cannot be null
.
*
* @deprecated
* Deprecated since XINS 1.1.0. Use {@link #getLocalName()} instead,
* which has the same functionality and behavior. This method has been
* deprecated since it returned a combination of the namespace prefix
* and the local name in XINS 1.0. This method is guaranteed not to be
* removed before XINS 2.0.0.
*/
public String getName() {
return getLocalName();
}
/**
* Sets the specified attribute. If the value for the specified
* attribute is already set, then the previous value is replaced.
*
* @param namespaceURI
* the namespace URI for the attribute, can be null
; an
* empty string is equivalent to null
.
*
* @param localName
* the local name for the attribute, cannot be null
.
*
* @param value
* the value for the attribute, can be null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*
* @since XINS 1.1.0
*/
void setAttribute(String namespaceURI, String localName, String value)
throws IllegalArgumentException {
final String THIS_METHOD = "setAttribute(String,String,String)";
// Construct a QualifiedName object. This will check the preconditions.
QualifiedName qn = new QualifiedName(namespaceURI, localName);
if (_attributes == null) {
if (value == null) {
return;
}
// Lazily initialize
_attributes = new HashMap();
}
// Set or reset the attribute
_attributes.put(qn, value);
// Check postconditions
String getValue = getAttribute(namespaceURI, localName);
if ((value != null && getValue == null)
|| (value == null && getValue != null)
|| (value != null && !value.equals(getValue))) {
String message = "Postcondition failed"
+ "; namespaceURI=" + TextUtils.quote(namespaceURI)
+ "; qn.namespaceURI=" + TextUtils.quote(qn.getNamespaceURI())
+ "; localName=" + TextUtils.quote(localName)
+ "; qn.localName=" + TextUtils.quote(qn.getLocalName())
+ "; value=" + TextUtils.quote(value)
+ "; getAttribute(...)=" + TextUtils.quote(getValue)
+ '.';
throw Utils.logProgrammingError(CLASSNAME, THIS_METHOD,
CLASSNAME, THIS_METHOD,
message, null);
}
}
/**
* Gets an unmodifiable view of all attributes.
*
* @return
* an unmodifiable {@link Map} (never null
) which is a view
* on all the attributes; each key in the Map
is a
* {@link QualifiedName} instance (not null
) and each value
* in it is a String
instance (not null
).
*
* @since XINS 1.1.0
*/
public Map getAttributeMap() {
if (_attributes == null) {
return Collections.EMPTY_MAP;
} else {
return Collections.unmodifiableMap(_attributes);
}
}
/**
* Gets the names of all attributes that do not have a namespace defined.
*
* @return
* an {@link Iterator} returning each attribute name as a
* {@link String}; or null
, which indicates the
* DataElement
has no elements.
*
* @deprecated
* Deprecated since XINS 1.1.0. Use {@link #getAttributeMap()}
* instead, which returns all attributes names and values and which
* supports XML Namespaces. This method has been deprecated since it
* does not support namespaces and since it returned a combination of
* the namespace prefix and the local name in XINS 1.0, although XML
* Namespaces were not supported yet. This method is guaranteed not to
* be removed before XINS 2.0.0.
*/
public Iterator getAttributes() {
Set set = null;
// Find all matches and put them in a lazily-initialized Set
if (_attributes != null) {
Iterator it = _attributes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
QualifiedName qn = (QualifiedName) entry.getKey();
if (qn.getNamespaceURI() == null) {
if (set == null) {
set = new HashSet();
}
set.add(qn.getLocalName());
}
}
}
if (set == null) {
return null;
} else {
return set.iterator();
}
}
/**
* Gets the value of the attribute with the qualified name. If the
* qualified name does not specify a namespace, then only an attribute that
* does not have a namespace will match.
*
* @param qn
* a combination of an optional namespace and a mandatory local name, or
* null
.
*
* @return
* the value of the attribute that matches the specified namespace and
* local name, or null
if such an attribute is either not
* set or set to null
.
*
* @throws IllegalArgumentException
* if qn == null
.
*
* @since XINS 1.1.0
*/
public String getAttribute(QualifiedName qn)
throws IllegalArgumentException {
// Check preconditions
MandatoryArgumentChecker.check("qn", qn);
if (_attributes == null) {
return null;
} else {
return (String) _attributes.get(qn);
}
}
/**
* Gets the value of the attribute with the specified namespace and local
* name. The namespace is optional. If the namespace is not given, then only
* an attribute that does not have a namespace will match.
*
* @param namespaceURI
* the namespace URI for the attribute, can be null
; an
* empty string is equivalent to null
; if specified this
* string must be a valid namespace URI.
*
* @param localName
* the local name of the attribute, cannot be null
.
*
* @return
* the value of the attribute that matches the specified namespace and
* local name, or null
if such an attribute is either not
* set or set to null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*
* @since XINS 1.1.0
*/
public String getAttribute(String namespaceURI, String localName)
throws IllegalArgumentException {
QualifiedName qn = new QualifiedName(namespaceURI, localName);
return getAttribute(qn);
}
/**
* Gets the value of an attribute that has no namespace.
*
* @param localName
* the local name of the attribute, cannot be null
.
*
* @return
* the value of the attribute that matches the specified local name and
* has no namespace defined, or null
if the attribute is
* either not set or set to null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*
* @since XINS 1.1.0
*/
public String getAttribute(String localName)
throws IllegalArgumentException {
return getAttribute(null, localName);
}
/**
* Gets the value of an attribute that has no namespace.
*
* @param localName
* the local name of the attribute, cannot be null
.
*
* @return
* the value of the attribute that matches the specified local name and
* has no namespace defined, or null
if the attribute is
* either not set or set to null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*
* @deprecated
* Deprecated since XINS 1.1.0. Use {@link #getAttribute(String)}
* instead. This method has been deprecated since it used to
* expect/accept a combination of the namespace prefix and the local
* name in XINS 1.0, although that XML Namespaces were not supported
* yet. This method is guaranteed not to be removed before XINS 2.0.0.
*/
public String get(String localName) throws IllegalArgumentException {
return getAttribute(null, localName);
}
/**
* Adds a new child element.
*
* @param child
* the new child to add to this element, cannot be null
.
*
* @throws IllegalArgumentException
* if child == null || child == this
.
*/
void addChild(DataElement child) throws IllegalArgumentException {
final String THIS_METHOD = "addChild(DataElement)";
// Check preconditions
MandatoryArgumentChecker.check("child", child);
if (child == this) {
final String SUBJECT_CLASS = Utils.getCallingClass();
final String SUBJECT_METHOD = Utils.getCallingMethod();
final String DETAIL = "child == this";
Utils.logProgrammingError(CLASSNAME, THIS_METHOD,
SUBJECT_CLASS, SUBJECT_METHOD,
DETAIL);
throw new IllegalArgumentException(DETAIL);
}
// Lazily initialize
if (_children == null) {
_children = new ArrayList();
}
_children.add(child);
}
/**
* Gets the list of all child elements.
*
* @return
* an unmodifiable {@link List} containing all child elements; each
* element in the list is another DataElement
instance;
* never null
.
*/
public List getChildElements() {
List children;
// If there are no children, then return an immutable empty List
if (_children == null || _children.size() == 0) {
children = Collections.EMPTY_LIST;
// Otherwise return an immutable view of the list of children
} else {
children = Collections.unmodifiableList(_children);
}
return children;
}
/**
* Gets the list of child elements that match the specified name.
*
* @param name
* the name for the child elements to match, cannot be
* null
.
*
* @return
* a {@link List} containing each child element that matches the
* specified name as another DataElement
instance;
* never null
.
*
* @throws IllegalArgumentException
* if name == null
.
*/
public List getChildElements(String name)
throws IllegalArgumentException {
// TODO: Support namespaces
// Check preconditions
MandatoryArgumentChecker.check("name", name);
List matches;
// If there are no children, then return null
if (_children.size() == 0) {
matches = Collections.EMPTY_LIST;
// There are children, find all matching ones
} else {
matches = new ArrayList();
Iterator it = _children.iterator();
while (it.hasNext()) {
DataElement child = (DataElement) it.next();
if (name.equals(child.getLocalName())) {
matches.add(child);
}
}
// If there are no matching children, then return null
if (matches.size() == 0) {
matches = Collections.EMPTY_LIST;
// Otherwise return an immutable list with all matches
} else {
matches = Collections.unmodifiableList(matches);
}
}
return matches;
}
/**
* Sets the character content. The existing character content, if any, is
* replaced
*
* @param text
* the character content for this element, or null
.
*/
void setText(String text) {
_text = text;
}
/**
* Gets the character content, if any.
*
* @return
* the character content of this element, or null
if no
* text has been specified for this element.
*/
public String getText() {
return _text;
}
/**
* Converts this DataElement to a {@link org.xins.common.xml.Element} object.
*
* @return
* the converted object, never null
.
*
* @since XINS 1.3.0
*/
public Element toXMLElement() {
return toXMLElement(this);
}
/**
* Converts the given DataElement to a
* {@link org.xins.common.xml.Element} object.
*
* @param dataElement
* the input element to convert, cannot be null
*
* @return
* the converted object, never null
.
*
* @throws IllegalArgumentException
* if dataElement == null
.
*/
private Element toXMLElement(DataElement dataElement)
throws IllegalArgumentException {
// Check preconditions
MandatoryArgumentChecker.check("dataElement", dataElement);
String elementName = dataElement.getLocalName();
String elementNameSpaceURI = dataElement.getNamespaceURI();
Map elementAttributes = dataElement.getAttributeMap();
String elementText = dataElement.getText();
List elementChildren = dataElement.getChildElements();
ElementBuilder builder = new ElementBuilder(elementNameSpaceURI, elementName);
builder.setText(elementText);
// Go through the attributes
Iterator itAttributes = elementAttributes.entrySet().iterator();
while (itAttributes.hasNext()) {
Map.Entry entry = (Map.Entry) itAttributes.next();
DataElement.QualifiedName attributeName = (DataElement.QualifiedName) entry.getKey();
String attributeValue = (String) entry.getValue();
builder.setAttribute(attributeName.getNamespaceURI(), attributeName.getLocalName(), attributeValue);
}
// Add the children of this element
Iterator itChildren = elementChildren.iterator();
while (itChildren.hasNext()) {
DataElement nextChild = (DataElement) itChildren.next();
Element transformedChild = toXMLElement(nextChild);
builder.addChild(transformedChild);
}
return builder.createElement();
}
/**
* Clones this object. The clone will have the same namespace URI and local
* name and equivalent attributes, children and character content.
*
* @return
* a new clone of this object, never null
.
*/
public Object clone() {
// Construct a new DataElement, copy all field values (shallow copy)
DataElement clone;
try {
clone = (DataElement) super.clone();
} catch (CloneNotSupportedException exception) {
String detail = null;
throw Utils.logProgrammingError(DataElement.class.getName(),
"clone()",
"java.lang.Object",
"clone()",
detail,
exception);
}
// Deep copy the children
if (_children != null) {
clone._children = (ArrayList) _children.clone();
}
// Deep copy the attributes
if (_attributes != null) {
clone._attributes = (HashMap) _attributes.clone();
}
return clone;
}
//-------------------------------------------------------------------------
// Inner classes
//-------------------------------------------------------------------------
/**
* Qualified name for an element or attribute. This is a combination of an
* optional namespace URI and a mandatory local name.
*
* @author Ernst de Haan
*
* @since XINS 1.1.0
*/
public static final class QualifiedName extends Object {
//----------------------------------------------------------------------
// Constructors
//----------------------------------------------------------------------
/**
* Constructs a new QualifiedName
with the specified
* namespace and local name.
*
* @param namespaceURI
* the namespace URI for the element, can be null
; an
* empty string is equivalent to null
.
*
* @param localName
* the local name of the element, cannot be null
.
*
* @throws IllegalArgumentException
* if localName == null
.
*/
public QualifiedName(String namespaceURI, String localName)
throws IllegalArgumentException {
// Check preconditions
MandatoryArgumentChecker.check("localName", localName);
// An empty namespace URI is equivalent to null
if (namespaceURI != null && namespaceURI.length() < 1) {
namespaceURI = null;
}
// Initialize fields
_hashCode = localName.hashCode();
_namespaceURI = namespaceURI;
_localName = localName;
}
//----------------------------------------------------------------------
// Fields
//----------------------------------------------------------------------
/**
* The hash code for this object.
*/
private final int _hashCode;
/**
* The namespace URI. Can be null
.
*/
private final String _namespaceURI;
/**
* The local name. Cannot be null
.
*/
private final String _localName;
//----------------------------------------------------------------------
// Methods
//----------------------------------------------------------------------
/**
* Returns the hash code value for this object.
*
* @return
* the hash code value.
*/
public int hashCode() {
return _hashCode;
}
/**
* Compares this object with the specified object for equality.
*
* @param obj
* the object to compare with, or null
.
*
* @return
* true
if this object and the argument are considered
* equal, false
otherwise.
*/
public boolean equals(Object obj) {
if (! (obj instanceof QualifiedName)) {
return false;
}
QualifiedName qn = (QualifiedName) obj;
return ((_namespaceURI == null && qn._namespaceURI == null) ||
(_namespaceURI != null && _namespaceURI.equals(qn._namespaceURI))) &&
_localName.equals(qn._localName);
}
/**
* Gets the namespace URI.
*
* @return
* the namespace URI, can be null
.
*/
public String getNamespaceURI() {
return _namespaceURI;
}
/**
* Gets the local name.
*
* @return
* the local name, never null
.
*/
public String getLocalName() {
return _localName;
}
}
}