| /* |
| * Copyright (c) 2009, Rickard Öberg. 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 org.apache.zest.api.common; |
| |
| import java.io.Serializable; |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Member; |
| import org.apache.zest.api.util.NullArgumentException; |
| |
| /** |
| * QualifiedName is a representation of Property names to their full declaration. |
| * <p> |
| * A QualifiedName is created by combining the name of a method and the name of the type that declares the method. |
| * This class also contains many static utility methods to manage QualifiedName instances. |
| * </p> |
| * <p> |
| * <strong>NOTE: Unless you do very generic libraries, entity stores and other extensions that is deeply coupled into |
| * the Zest runtime, it is very unlikely you will need to use this class directly.</strong> |
| * </p> |
| * <p> |
| * It is also important to notice that the QualifiedName needs to be long-term stable, as the names are written |
| * to persistent storage. So any changes in the formatting <strong>must be made in a backward-compatible manner |
| * </strong>. |
| * </p> |
| * <p> |
| * The QualifiedName has two intrinsic parts, one being the {@code type} and the other the {@code name}. The |
| * {@code type} comes from the class where the QualifiedName originates from and internally kept as a {@link TypeName} |
| * instance. The name is the name from the method name. When the QualifiedName instance is converted to an external |
| * string representation, via the offical and formal {@link #toString()} method, the {@code type} is normalized, i.e. |
| * any dollar characters ($) in the name are replaced by dashes (-), to make them URI friendly. |
| * </p> |
| * <p> |
| * QualifiedName instances are immutable, implements {@link #hashCode()} and {@link #equals(Object)} as a value |
| * object and can safely be used as keys in {@link java.util.Map}. |
| */ |
| public final class QualifiedName |
| implements Comparable<QualifiedName>, Serializable |
| { |
| private final TypeName typeName; |
| private final String name; |
| |
| /** |
| * Creates a QualifiedName from a method. |
| * <p> |
| * This factory method will create a QualifiedName from the Method itself. |
| * |
| * </p> |
| * |
| * @param method Type method that returns a Property, for which the QualifiedName will be representing. |
| * |
| * @return A QualifiedName representing this method. |
| * |
| * @throws NullArgumentException If the {@code method} argument passed is null. |
| */ |
| public static QualifiedName fromAccessor( AccessibleObject method ) |
| { |
| NullArgumentException.validateNotNull( "method", method ); |
| return fromClass( ( (Member) method ).getDeclaringClass(), ( (Member) method ).getName() ); |
| } |
| |
| /** |
| * Creates a QualifiedName instance from the Class and a given name. |
| * <p> |
| * This factory method converts the {@code type} to a {@link TypeName} and appends the given {@code name}. |
| * |
| * @param type The Class that is the base of the QualifiedName. |
| * @param name The qualifier name which will be appended to the base name derived from the {@code type} argument. |
| * |
| * @return A QualifiedName instance representing the {@code type} and {@code name} arguments. |
| * |
| * @throws NullArgumentException if any of the two arguments are {@code null}, or if the name string is empty. |
| */ |
| public static QualifiedName fromClass( Class type, String name ) |
| { |
| return new QualifiedName( TypeName.nameOf( type ), name ); |
| } |
| |
| /** |
| * Creates a Qualified name from a type as string and a name qualifier. |
| * |
| * @param type The type name as a a string, which must be properly formatted. No checks for correctly formatted |
| * type name is performed. |
| * @param name The qualifier name which will be appended to the base name derived from the {@code type} argument. |
| * |
| * @return A QualifiedName instance representing the {@code type} and {@code name} arguments. |
| * |
| * @throws NullArgumentException if any of the two arguments are {@code null} or either string is empty. |
| */ |
| public static QualifiedName fromName( String type, String name ) |
| { |
| return new QualifiedName( TypeName.nameOf( type ), name ); |
| } |
| |
| /** |
| * Creates a QualifiedName from the external string format of QualifiedName. |
| * <p> |
| * This factory method is the reverse of {@link QualifiedName#toString() } method, and creates a new QualifiedName |
| * instance from the string representation of the QualifiedName. |
| * </p> |
| * |
| * @param fullQualifiedName The QualifiedName external string representation to be converted back into a QualifiedName |
| * instance. |
| * |
| * @return The QualifiedName instance represented by the {@code qualifiedName} argument. |
| * |
| * @throws IllegalArgumentException If the {@code qualifiedName} argument has wrong format. |
| */ |
| public static QualifiedName fromFQN( String fullQualifiedName ) |
| { |
| NullArgumentException.validateNotEmpty( "qualifiedName", fullQualifiedName ); |
| int idx = fullQualifiedName.lastIndexOf( ":" ); |
| if( idx == -1 ) |
| { |
| throw new IllegalArgumentException( "Name '" + fullQualifiedName + "' is not a qualified name" ); |
| } |
| final String type = fullQualifiedName.substring( 0, idx ); |
| final String name = fullQualifiedName.substring( idx + 1 ); |
| return new QualifiedName( TypeName.nameOf( type ), name ); |
| } |
| |
| QualifiedName( TypeName typeName, String name ) |
| { |
| NullArgumentException.validateNotNull( "typeName", typeName ); |
| NullArgumentException.validateNotEmpty( "name", name ); |
| this.typeName = typeName; |
| this.name = name; |
| } |
| |
| /** |
| * Returns the normalized string of the type part of the QualifiedName. |
| * |
| * <p> |
| * The normalized type name means that all dollar ($) characters have been replaced by dashes (-). |
| * </p> |
| * |
| * @return the normalized string of the type part of the QualifiedName. |
| */ |
| public String type() |
| { |
| return typeName.normalized(); |
| } |
| |
| /** |
| * Returns the name component of the QualifiedName. |
| * |
| * @return the name component of the QualifiedName. |
| */ |
| public String name() |
| { |
| return name; |
| } |
| |
| /** |
| * Returns the URI of the QualifiedName. |
| * |
| * <p> |
| * The URI is the {@link #toNamespace()} followed by the {@code name} component. |
| * <p> |
| * |
| * @return the URI of the QualifiedName. |
| * |
| * @see #toNamespace() |
| */ |
| public String toURI() |
| { |
| return toNamespace() + name; |
| } |
| |
| /** |
| * Return the URI of the {@link TypeName} component of the QualifiedName. |
| * <p> |
| * The URI of the {@link TypeName} component is in the form of; |
| * </p> |
| * <pre> |
| * "urn:qi4j:type:" normalizedClassName |
| * </pre> |
| * <p> |
| * where {@code normalizedClassName} is the fully-qualified class name having had any dollar ($) characters replaced |
| * by URI friendly dashes (-), with a trailing hash (#). Examples; |
| * </p> |
| * <pre> |
| * urn:qi4j:type:org.qi4j.api.common.QualifiedName# |
| * urn:qi4j:type:org.qi4j.samples.MyClass-MyInnerClass# |
| * </pre> |
| * |
| * @return the URI of the {@link TypeName} component of the QualifiedName. |
| */ |
| public String toNamespace() |
| { |
| return typeName.toURI() + "#"; |
| } |
| |
| /** |
| * Return the formal and official, long-term stable, external string representation of a QualifiedName. |
| * <p> |
| * This returns the {@link org.apache.zest.api.common.TypeName#toString()} followed by the {@code name} component. |
| * </p> |
| * |
| * @return the formal and official, long-term stable, external string representation of a QualifiedName. |
| */ |
| @Override |
| public String toString() |
| { |
| return typeName + ":" + name; |
| } |
| |
| @Override |
| public boolean equals( Object o ) |
| { |
| if( this == o ) |
| { |
| return true; |
| } |
| if( o == null || getClass() != o.getClass() ) |
| { |
| return false; |
| } |
| |
| QualifiedName that = (QualifiedName) o; |
| |
| return name.equals( that.name ) && typeName.equals( that.typeName ); |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return 31 * typeName.hashCode() + name.hashCode(); |
| } |
| |
| @Override |
| public int compareTo( QualifiedName other ) |
| { |
| final int result = typeName.compareTo( other.typeName ); |
| if( result != 0 ) |
| { |
| return result; |
| } |
| return name.compareTo( other.name ); |
| } |
| } |