001/**
002 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
003 *   This file is part of the LDP4j Project:
004 *     http://www.ldp4j.org/
005 *
006 *   Center for Open Middleware
007 *     http://www.centeropenmiddleware.com/
008 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
009 *   Copyright (C) 2014-2016 Center for Open Middleware.
010 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
011 *   Licensed under the Apache License, Version 2.0 (the "License");
012 *   you may not use this file except in compliance with the License.
013 *   You may obtain a copy of the License at
014 *
015 *             http://www.apache.org/licenses/LICENSE-2.0
016 *
017 *   Unless required by applicable law or agreed to in writing, software
018 *   distributed under the License is distributed on an "AS IS" BASIS,
019 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020 *   See the License for the specific language governing permissions and
021 *   limitations under the License.
022 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
023 *   Artifact    : org.ldp4j.framework:ldp4j-application-api:0.2.2
024 *   Bundle      : ldp4j-application-api-0.2.2.jar
025 * #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
026 */
027package org.ldp4j.application.vocabulary;
028
029import java.util.Objects;
030
031
032/**
033 * A term implementation that enforces the creation of immutable terms defined
034 * for an {@code AbstractImmutableVocabulary}, which behave as {@code Enum} constants.
035 *
036 * @version 1.0
037 * @since 1.0.0
038 * @author Miguel Esteban Gutiérrez
039 * @see AbstractImmutableVocabulary
040 */
041public class ImmutableTerm implements Term {
042
043  private static final long serialVersionUID = 6842492155071877731L;
044
045  private static final int HASH_CODE_SALT = 19;
046  private final int ordinal;
047  private final String name;
048  private final AbstractImmutableVocabulary<? extends ImmutableTerm> vocabulary;
049  private final String entityName;
050
051  /**
052   * Create a new term for a vocabulary and entity.
053   *
054   * @param vocabulary
055   *            the vocabulary to which the term will belong to.
056   * @param entityName
057   *            the entity name of the term.
058   * @throws NullPointerException
059   *             if any of the vocabulary is {@code null}.
060   * @throws IllegalArgumentException
061   *             if the entity name is not valid.
062   */
063  public ImmutableTerm(AbstractImmutableVocabulary<? extends ImmutableTerm> vocabulary, String entityName) {
064    this.vocabulary = Objects.requireNonNull(vocabulary,"Vocabulary cannot be null");
065    this.entityName = entityName;
066    this.name = TermUtils.toTermName(entityName);
067    this.ordinal = vocabulary.reserveTermName(this.name);
068    vocabulary.registerTerm(this);
069  }
070
071  /**
072   * {@inheritDoc}
073   */
074  @Override
075  public final int ordinal() {
076    return ordinal;
077  }
078
079  /**
080   * {@inheritDoc}
081   */
082  @Override
083  public final String name() {
084    return name;
085  }
086
087  /**
088   * {@inheritDoc}
089   */
090  @Override
091  public final String entityName() {
092    return entityName;
093  }
094
095  /**
096   * {@inheritDoc}
097   */
098  @Override
099  public final String qualifiedEntityName() {
100    return vocabulary.getNamespace() + entityName;
101  }
102
103  /**
104   * {@inheritDoc}
105   */
106  @Override
107  public final Vocabulary getDeclaringVocabulary() {
108    return vocabulary;
109  }
110
111  /**
112   * {@inheritDoc} <br>
113   * This method may be overridden, though it typically isn't necessary or
114   * desirable. An term type should override this method when a more specific
115   * value types are supported.
116   */
117  @Override
118  public <V> V as(Class<? extends V> valueClass) {
119    try {
120      return TypeAdapter.adapt(this, valueClass);
121    } catch (CannotAdaptClassesException e) {
122      throw new UnsupportedOperationException("Class '"+getClass().getCanonicalName()+" cannot be transformed to '"+valueClass.getCanonicalName()+"'",e);
123    }
124  }
125
126  /**
127   * Returns true if the specified object is equal to this term constant.
128   *
129   * @param other
130   *            the object to be compared for equality with this object.
131   * @return true if the specified object is equal to this term constant.
132   */
133  @Override
134  public final boolean equals(Object other) {
135    return this == other;
136  }
137
138  /**
139   * Returns a hash code for this term constant.
140   *
141   * @return a hash code for this term constant.
142   */
143  @Override
144  public final int hashCode() {
145    return super.hashCode()*HASH_CODE_SALT;
146  }
147
148  /**
149   * Throws CloneNotSupportedException. This guarantees that terms are never
150   * cloned, which is necessary to preserve their "singleton" status.
151   *
152   * @return (never returns)
153   */
154  @Override
155  protected final Object clone() throws CloneNotSupportedException { // NOSONAR
156    throw new CloneNotSupportedException();
157  }
158
159  /**
160   * Returns the qualified entity name of this term constant.
161   * This method may be overridden, though it typically isn't necessary or
162   * desirable. An term type should override this method when a more
163   * "programmer-friendly" string form exists.
164   *
165   * @return the name of this term constant
166   */
167  @Override
168  public String toString() {
169    return qualifiedEntityName();
170  }
171
172  /**
173   * Compares this term with the specified object for order. Returns a
174   * negative integer, zero, or a positive integer as this object is less
175   * than, equal to, or greater than the specified object.
176   *
177   * Term constants are only comparable to other term constants of the same
178   * vocabulary. The natural order implemented by this method is the order in
179   * which the constants are declared.
180   */
181  @Override
182  public int compareTo(Term other) {
183    ImmutableTerm self = this;
184    if(self.getDeclaringVocabulary() != other.getDeclaringVocabulary()) {
185      throw new ClassCastException();
186    }
187    return self.ordinal - other.ordinal();
188  }
189
190}