/* Copyright (c) 2008 Google Inc.
*
* 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.google.gdata.model;
import com.google.gdata.util.common.base.Preconditions;
import com.google.gdata.util.common.xml.XmlNamespace;
/**
* Qualified name of a data model element or attribute. A qname instance is
* immutable.
*/
public final class QName implements Comparable<QName> {
/**
* Special value for the QName namespace that will match any namespace.
*/
public static final XmlNamespace ANY_NAMESPACE = new XmlNamespace("*", "*");
/**
* Special value for the QName local name that will match any local name.
*/
public static final String ANY_LOCALNAME = "*";
private final XmlNamespace namespace;
private final String localName;
public QName(String localName) {
this(null, localName);
}
public QName(XmlNamespace namespace, String localName) {
Preconditions.checkNotNull(localName, "localName");
this.namespace = namespace;
this.localName = localName;
}
public XmlNamespace getNs() { return namespace; }
public String getLocalName() { return localName; }
/**
* Returns {@code true} if this qname has a namespace value that will match
* any namespace.
*
* @see ANY_NAMESPACE
*/
public boolean matchesAnyNamespace() {
return ANY_NAMESPACE.equals(namespace);
}
/**
* Returns {@code true} if this qname has a local name that will
* match any local name.
*
* @see ANY_LOCALNAME
*/
public boolean matchesAnyLocalName() {
return ANY_LOCALNAME.equals(localName);
}
/**
* Checks if this QName is a match for the other QName. A QName is a match
* if it is null and if 1) the local namespace is {@link ANY_NAMESPACE} or
* the two namespaces are both null or have a matching uri and 2) the local
* name is {@link ANY_LOCALNAME} or the two local names are equal.
*/
public boolean matches(QName o) {
if (o == null) {
return false;
}
if (!matchesAnyNamespace()) {
XmlNamespace otherNs = o.getNs();
String idUri = (namespace == null) ? null : namespace.getUri();
String otherUri = (otherNs == null) ? null : otherNs.getUri();
// Check namespace uris.
if (idUri == null) {
if (otherUri != null) {
return false;
}
} else if (!idUri.equals(otherUri)) {
return false;
}
}
// Check the local names.
if (matchesAnyLocalName()) {
return true;
}
return localName.equals(o.getLocalName());
}
@Override
public boolean equals(Object other) {
if (!(other instanceof QName)) {
return false;
}
QName otherQName = (QName) other;
if (this.getNs() == null && otherQName.getNs() == null) {
return getLocalName().equals(otherQName.getLocalName());
}
if (this.getNs() != null && otherQName.getNs() != null) {
return this.getNs().getUri().equals(otherQName.getNs().getUri())
&& getLocalName().equals(otherQName.getLocalName());
}
return false;
}
@Override
public int hashCode() {
if (getNs() == null) {
return getLocalName().hashCode();
}
return getNs().getUri().hashCode() * 13 + getLocalName().hashCode();
}
@Override
public String toString() {
if (getNs() == null || "".equals(getNs().getAlias())) {
return getLocalName();
}
return getNs().getAlias() + ":" + getLocalName();
}
public int compareTo(QName o) {
if (getNs() == null) {
if (o.getNs() != null) {
return -1;
}
} else {
if (o.getNs() == null) {
return 1;
}
int result = getNs().getUri().compareTo(o.getNs().getUri());
if (result != 0) {
if (ANY_NAMESPACE.equals(o.getNs())) {
return -1;
}
return result;
}
}
String localName = getLocalName();
int compare = localName.compareTo(o.getLocalName());
if (compare != 0 && ANY_LOCALNAME.equals(localName)) {
return -1;
}
return compare;
}
}