/* * This file or a portion of this file is licensed under the terms of * the Globus Toolkit Public License, found in file ../GTPL, or at * http://www.globus.org/toolkit/download/license.html. This notice must * appear in redistributions of this file, with or without modification. * * Redistributions of this Software, with or without modification, must * reproduce the GTPL in: (1) the Software, or (2) the Documentation or * some other similar material which is provided with the Software (if * any). * * Copyright 1999-2004 University of Chicago and The University of * Southern California. All rights reserved. */ package org.griphyn.vdl.classes; import edu.isi.pegasus.common.util.Separator; import java.util.*; import java.io.IOException; import java.io.Writer; import java.io.Serializable; /** * This is a base class which collects attributes that belong to * <code>Transformation</code> and <code>Derivation</code>.<p> * * Note: this class has a natural ordering that may be inconsistent with * equals due to differing implementations. The equal method will take * object type and primary key triple into consideration, making extensive * null checks. The compareTo method compares the type and short ids of * the Definitions. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * * @see Transformation * @see Derivation */ public abstract class Definition extends VDL implements Comparable, Serializable { // common constants for quick type access /** * This is the return value for {@link #getType()} from a * {@link Transformation}. */ public static final int TRANSFORMATION = 0x71077345; // shell oil /** * This is the return value for {@link #getType()} from a * {@link Derivation}. */ public static final int DERIVATION = 0xCAFEBABE; /** * This is an abstract function that must be implemented by * instantiable children, of which currently only exist * {@link Transformation} and {@link Derivation} siblings and derivatives. * * @return the integer representing the concrete definition type of a * instance. The value of -1 *might* be used to indicate an unknown * type. */ abstract public int getType(); // common attributes from child elements /** * Each transformation and derivation resides in a namespace. Mind * that namespaces are currently flat. If you need to impose any kind * of hierarchy, please do so yourself, e.g. use periods between * hierarchy intifiers. The namespace is part of the key identifying * a logical transformation. The default is <code>null</code>. * * @see Transformation * @see Derivation */ private String m_namespace; /** * Each transformation and derivation can be identified by a name. * For a transformation, this is part of the logical transformation * name. Derivations can no longer be anonymous. * * @see Transformation * @see Derivation */ private String m_name; /** * Each transformation and derivation has a version associated with * their definition. While a version number is highly recommended for * transformation, being part of the primary key triple into the * (future) transformation catalog, a derivation can remain without * version. The default is <code>null</code>. * * @see Transformation * @see Derivation */ private String m_version; // AttributeGroup "DefinitionsAG" /** * Yong's knowledgebase approach needs this. */ private String m_description; /** * Yong's knowledgebase approach needs this. */ private String m_title; /** * Yong's knowledgebase approach needs this. */ private String m_keyword; /** * Yong's knowledgebase approach needs this. */ private String m_url; /** * ctor: empty */ public Definition() { this.m_namespace = null; this.m_version = null; } /** * Convenience ctor: name the definition. The name is part of a * logical {@link Transformation}. Note that a {@link Derivation} may * remain anonymous. The namespace will be the default namespace, or * taken from the {@link Definitions}. The version remains unset. * * @param name is the name to be used for the defintion. */ public Definition( String name ) { this.m_namespace = null; this.m_version = null; this.m_name = name; } /** * Convenience ctor: name the definition. The name is part of a * logical {@link Transformation}. Note that a {@link Derivation} may * remain anonymous. The version remains unset. * * @param namespace is the namespace the name resides in. * @param name is the name to be used for the defintion. */ public Definition( String namespace, String name ) { this.m_name = name; this.m_namespace = namespace; this.m_version = null; } /** * Convenience ctor: name the definition. The name is part of a * logical {@link Transformation}. Note that a {@link Derivation} may * remain anonymous. * * @param namespace is the namespace the name resides in. * @param name is the name to be used for the defintion. * @param version is the version of this definition. */ public Definition( String namespace, String name, String version ) { this.m_name = name; this.m_namespace = namespace; this.m_version = version; } /** * Implementation of the {@link java.lang.Comparable} interface. * Compares this object with the specified object for order. Returns a * negative integer, zero, or a positive integer as this object is * less than, equal to, or greater than the specified object. The * definitions are compared by their type, and by their short ids. * * @param o is the object to be compared * @return a negative number, zero, or a positive number, if the * object compared against is less than, equals or greater than * this object. * @exception ClassCastException if the specified object's type * prevents it from being compared to this Object. */ public int compareTo( Object o ) { if ( o instanceof Definition ) { Definition d = (Definition) o; int diff = d.getType() - getType(); // order is important return ( diff != 0 ? diff : d.shortID().compareTo(this.shortID()) ); } else { throw new ClassCastException( "object is not a Definition" ); } } /** * Calculate a hash code value for the object to support hash tables. * * @return a hash code value for the object. */ public int hashCode() { int result = m_namespace == null ? 0 : m_namespace.hashCode(); result = ( result << 8 ) ^ ( m_name == null ? 0 : m_name.hashCode() ); result = ( result << 8 ) ^ ( m_version == null ? 0 : m_version.hashCode() ); return ( result ^ getType() ); } /** * Accessor: match the primary key of a definition. * Note, this match is not wildcard capable. The type of the definitions * will also be checked. The primary key of a definition is the triple * namespace, name and version. This function is null-capable. * * @param type is the type identifier TRANSFORMATION or DERIVATION * @param namespace is the namespace * @param name is the name * @param version is the version * * @return true, if the primary keys match, false otherwise. */ public boolean match( int type, String namespace, String name, String version ) { return ( // check type type == this.getType() && // check namespace ( m_namespace == null && namespace == null || m_namespace != null && namespace != null && namespace.equals(m_namespace) ) && // check name ( m_name != null && name != null && name.equals(m_name) ) && // check version string ( m_version == null && version == null || m_version != null && version != null && version.equals(m_version) ) ); } /** * Accessor: match primary keys of two Definitions. * Note, this match is not wildcard capable. The type of the definitions * will also be checked. The primary key of a definition is the triple * namespace, name and version. The equals function is null-capable. * * @param obj the reference object with which to compare. * @return true, if the primary keys match, false otherwise. */ public boolean equals( Object obj ) { // ward against null if ( obj == null ) return false; // shortcut if ( obj == this ) return true; // don't compare apples with oranges if ( ! (obj instanceof Definition) ) return false; // now we can safely cast Definition d = (Definition) obj; return match( d.getType(), d.getNamespace(), d.getName(), d.getVersion() ); } /** * Accessor: Obtains the current description state. * * @return a string containing a descriptive remark on the definition, * or null for no description. * @see #setDescription(java.lang.String) */ public String getDescription() { return this.m_description; } /** * Accessor: Obtains the current keyword state. * * @return a string containing a collection of keywords describing the * definition, or null for no keywords. * @see #setKeyword(java.lang.String) */ public String getKeyword() { return this.m_keyword; } /** * Accessor: Obtains the current name of the definition. Note that * a name is mandatory for any {@link Transformation}, but a * {@link Derivation} may remain anonymous. * * @return the current name used for the definition. Note that derivations * may be anonymous. Returns null, if no name exists. * @see #setName(java.lang.String) */ public String getName() { return this.m_name; } /** * Accessor: Obtains the current namespace that is used for the * definition. Note that a namespace is part of the key for any * {@link Transformation}. * * @return the namespace the definition resides in, or null, if * no namespace was defined. * @see #setNamespace(java.lang.String) */ public String getNamespace() { return this.m_namespace; } /** * Accessor: Obtains the current title state. * * @return the title given to this definition, or null, if there * was no title defined. * @see #setTitle(java.lang.String) */ public String getTitle() { return this.m_title; } /** * Accessor: Obtains the current URI definition. * * @return the URL pointing to related information or a project, or * null, if no URL was registered. * @see #setUrl(java.lang.String) */ public String getUrl() { return this.m_url; } /** * Accessor: Obtains the current version of the definition. A version * is an integral part of a logical {@link Transformation}. * * @return the version number of this definition, or null, if no * version number was defined. * @see #setVersion(java.lang.String) */ public String getVersion() { return this.m_version; } /** * Accessor: Sets the description. * * @param description * @see #getDescription() */ public void setDescription(String description) { this.m_description = description; } /** * Accessor: Sets or overwrites the keyword list. * * @param keyword * @see #getKeyword() */ public void setKeyword(String keyword) { this.m_keyword = keyword; } /** * Accessor: Sets or overwrite the currently given name. * * @param name * @see #getName() */ public void setName(String name) { this.m_name = name; } /** * Accessor: Sets or overwrites the namespace identifier. * * @param namespace * @see #getNamespace() */ public void setNamespace(String namespace) { this.m_namespace = namespace; } /** * Accessor: Sets the current title for the definition. * * @param title * @see #getTitle() */ public void setTitle(String title) { this.m_title = title; } /** * Accessor: Sets the project reference. * * @param url * @see #getUrl() */ public void setUrl(String url) { this.m_url = url; } /** * Accessor: Sets the version of the definition. * * @param version * @see #getVersion() */ public void setVersion(String version) { this.m_version = version; } /** * Identify the transformation or derivation by its name. */ public abstract String identify(); /** * Create the short id from ns:id:version. * @param d is a Definition, or null for non-siblings * @param namespace is the namespace to use, may be null. * @param name is the name to produce the id for, should not be null. * @param version is a version string, may be null. * @return A string which textually identifies a Definition. * @exception RuntimeException, if the name and definition are both null. */ public static String shortID( Definition d, String namespace, String name, String version ) { if ( name != null ) return Separator.combine( namespace, name, version ); else if ( d != null ) return Separator.combine( namespace, Integer.toHexString(d.hashCode()), version ); else throw new RuntimeException("Definitions require valid identifiers" ); } /** * Constructs dynamically a short descriptive, hopefully unique * identifier for this derivation w/o referring to any transformation. * FIXME: Anonymous derivations get their hash code, which is well * for the first versions working without database. Later versions * with database must use some unique sequence mechanism instead. * * @return a string describing the derivation * @see Object#hashCode() */ public String shortID() { return shortID( this, this.m_namespace, this.m_name, this.m_version ); } /** * The toXML method is a partial method, to be incorporated/called * by its sibling class method of the same name. For this reason, * it does not fit the {@link VDL} interface. * * @return a string containing the attributes collected in the base class. */ public String toXML() { StringBuffer result = new StringBuffer(); if ( this.m_namespace != null ) result.append(" namespace=\"").append(quote(this.m_namespace,true)).append("\""); if ( this.m_name != null ) result.append(" name=\"").append(quote(this.m_name,true)).append("\""); if ( this.m_version != null ) result.append(" version=\"").append(quote(this.m_version,true)).append("\""); if ( this.m_description != null ) result.append(" description=\"").append(quote(this.m_description,true)).append("\""); if ( this.m_title != null ) result.append(" title=\"").append(quote(this.m_title,true)).append("\""); if ( this.m_keyword != null ) result.append(" keyword=\"").append(quote(this.m_keyword,true)).append("\""); if ( this.m_url != null ) result.append(" url=\"").append(quote(this.m_url,true)).append("\""); return result.toString(); } /** * The toXML method is a partial method, to be incorporated/called * by its sibling class method of the same name. For this reason, * it does not fit the {@link VDL} interface. * * @param stream is a stream opened and ready for writing. This can also * be a string stream for efficient output. * @exception IOException if something fishy happens to the stream. */ public void toXML( Writer stream ) throws IOException { writeAttribute( stream, " namespace=\"", this.m_namespace ); writeAttribute( stream, " name=\"", this.m_name ); writeAttribute( stream, " version=\"", this.m_version ); writeAttribute( stream, " description=\"", this.m_description ); writeAttribute( stream, " title=\"", this.m_title ); writeAttribute( stream, " keyword=\"", this.m_keyword ); writeAttribute( stream, " url=\"", this.m_url ); } }