/* 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;
/**
* A key referring to a particular attribute. Holds the ID of the attribute
* and the expected datatype. Attribute keys support value-based equality,
* natural ordering, and matching.
* <ul>
* <li>An attribute key is {@link #equals(Object)} to another attribute key if
* their IDs are equal and the datatypes are the same.</li>
* <li>An attribute key's natural ordering is based first on name and then on
* datatype.</li>
* <li>An attribute key {@link #matches(MetadataKey)} another attribute key if
* the ID is a match for the ID of the other key, and the datatype is assignable
* from the other key's datatype.</li>
* </ul>
*
* @param <D> the datatype of the attribute
*
*/
public final class AttributeKey<D> extends MetadataKey<D> {
/**
* Construct and return a new attribute key with the default datatype of
* String. The id must not be {@code null}.
*/
public static AttributeKey<String> of(QName id) {
return of(id, String.class);
}
/**
* Construct and return a new attribute key with the given id and datatype.
* Both id and datatype must not be {@code null}, or a
* {@link NullPointerException} will be thrown.
*/
public static <T> AttributeKey<T> of(QName id,
Class<? extends T> datatype) {
return new AttributeKey<T>(id, datatype);
}
/**
* Construct a new attribute key. Both id and datatype must not be
* {@code null}.
*/
private AttributeKey(QName id, Class<? extends D> datatype) {
super(Preconditions.checkNotNull(id, "id"), datatype);
}
/**
* Returns {@code true} if this key is a match for the given key. This key
* is a match for the other key if the other key is also an attribute key and
* if its ID and datatype match.
*/
@Override
public boolean matches(MetadataKey<?> other) {
if (other == null) {
return false;
}
if (!(other instanceof AttributeKey<?>)) {
return false;
}
return matchIdAndDatatype(other);
}
/**
* Compares first on ID, then on datatype.
*/
public int compareTo(MetadataKey<?> other) {
if (other == this) {
return 0;
}
// If they aren't the same type, put attribute keys at the front.
if (!(other instanceof AttributeKey<?>)) {
return -1;
}
int compare = compareQName(id, other.id);
if (compare != 0) {
return compare;
}
return compareClass(datatype, other.datatype);
}
@Override
public int hashCode() {
int hashCode = datatype.hashCode();
hashCode *= 17;
if (id != null) {
hashCode += id.hashCode();
}
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != AttributeKey.class) {
return false;
}
AttributeKey<?> o = (AttributeKey<?>) obj;
return id.equals(o.id) && datatype == o.datatype;
}
@Override
public String toString() {
return "{AttributeKey " + id + ", D:" + datatype + "}";
}
}