001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file ../GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.vdl.classes;
016:
017: import org.griphyn.common.util.Separator;
018: import java.util.*;
019: import java.io.IOException;
020: import java.io.Writer;
021: import java.io.Serializable;
022:
023: /**
024: * This is a base class which collects attributes that belong to
025: * <code>Transformation</code> and <code>Derivation</code>.<p>
026: *
027: * Note: this class has a natural ordering that may be inconsistent with
028: * equals due to differing implementations. The equal method will take
029: * object type and primary key triple into consideration, making extensive
030: * null checks. The compareTo method compares the type and short ids of
031: * the Definitions.
032: *
033: * @author Jens-S. Vöckler
034: * @author Yong Zhao
035: * @version $Revision: 50 $
036: *
037: * @see Transformation
038: * @see Derivation */
039: public abstract class Definition extends VDL implements Comparable,
040: Serializable {
041: // common constants for quick type access
042: /**
043: * This is the return value for {@link #getType()} from a
044: * {@link Transformation}.
045: */
046: public static final int TRANSFORMATION = 0x71077345; // shell oil
047:
048: /**
049: * This is the return value for {@link #getType()} from a
050: * {@link Derivation}.
051: */
052: public static final int DERIVATION = 0xCAFEBABE;
053:
054: /**
055: * This is an abstract function that must be implemented by
056: * instantiable children, of which currently only exist
057: * {@link Transformation} and {@link Derivation} siblings and derivatives.
058: *
059: * @return the integer representing the concrete definition type of a
060: * instance. The value of -1 *might* be used to indicate an unknown
061: * type.
062: */
063: abstract public int getType();
064:
065: // common attributes from child elements
066: /**
067: * Each transformation and derivation resides in a namespace. Mind
068: * that namespaces are currently flat. If you need to impose any kind
069: * of hierarchy, please do so yourself, e.g. use periods between
070: * hierarchy intifiers. The namespace is part of the key identifying
071: * a logical transformation. The default is <code>null</code>.
072: *
073: * @see Transformation
074: * @see Derivation
075: */
076: private String m_namespace;
077:
078: /**
079: * Each transformation and derivation can be identified by a name.
080: * For a transformation, this is part of the logical transformation
081: * name. Derivations can no longer be anonymous.
082: *
083: * @see Transformation
084: * @see Derivation
085: */
086: private String m_name;
087:
088: /**
089: * Each transformation and derivation has a version associated with
090: * their definition. While a version number is highly recommended for
091: * transformation, being part of the primary key triple into the
092: * (future) transformation catalog, a derivation can remain without
093: * version. The default is <code>null</code>.
094: *
095: * @see Transformation
096: * @see Derivation
097: */
098: private String m_version;
099:
100: // AttributeGroup "DefinitionsAG"
101: /**
102: * Yong's knowledgebase approach needs this.
103: */
104: private String m_description;
105: /**
106: * Yong's knowledgebase approach needs this.
107: */
108: private String m_title;
109: /**
110: * Yong's knowledgebase approach needs this.
111: */
112: private String m_keyword;
113: /**
114: * Yong's knowledgebase approach needs this.
115: */
116: private String m_url;
117:
118: /**
119: * ctor: empty
120: */
121: public Definition() {
122: this .m_namespace = null;
123: this .m_version = null;
124: }
125:
126: /**
127: * Convenience ctor: name the definition. The name is part of a
128: * logical {@link Transformation}. Note that a {@link Derivation} may
129: * remain anonymous. The namespace will be the default namespace, or
130: * taken from the {@link Definitions}. The version remains unset.
131: *
132: * @param name is the name to be used for the defintion.
133: */
134: public Definition(String name) {
135: this .m_namespace = null;
136: this .m_version = null;
137: this .m_name = name;
138: }
139:
140: /**
141: * Convenience ctor: name the definition. The name is part of a
142: * logical {@link Transformation}. Note that a {@link Derivation} may
143: * remain anonymous. The version remains unset.
144: *
145: * @param namespace is the namespace the name resides in.
146: * @param name is the name to be used for the defintion.
147: */
148: public Definition(String namespace, String name) {
149: this .m_name = name;
150: this .m_namespace = namespace;
151: this .m_version = null;
152: }
153:
154: /**
155: * Convenience ctor: name the definition. The name is part of a
156: * logical {@link Transformation}. Note that a {@link Derivation} may
157: * remain anonymous.
158: *
159: * @param namespace is the namespace the name resides in.
160: * @param name is the name to be used for the defintion.
161: * @param version is the version of this definition.
162: */
163: public Definition(String namespace, String name, String version) {
164: this .m_name = name;
165: this .m_namespace = namespace;
166: this .m_version = version;
167: }
168:
169: /**
170: * Implementation of the {@link java.lang.Comparable} interface.
171: * Compares this object with the specified object for order. Returns a
172: * negative integer, zero, or a positive integer as this object is
173: * less than, equal to, or greater than the specified object. The
174: * definitions are compared by their type, and by their short ids.
175: *
176: * @param o is the object to be compared
177: * @return a negative number, zero, or a positive number, if the
178: * object compared against is less than, equals or greater than
179: * this object.
180: * @exception ClassCastException if the specified object's type
181: * prevents it from being compared to this Object.
182: */
183: public int compareTo(Object o) {
184: if (o instanceof Definition) {
185: Definition d = (Definition) o;
186: int diff = d.getType() - getType(); // order is important
187: return (diff != 0 ? diff : d.shortID().compareTo(
188: this .shortID()));
189: } else {
190: throw new ClassCastException("object is not a Definition");
191: }
192: }
193:
194: /**
195: * Calculate a hash code value for the object to support hash tables.
196: *
197: * @return a hash code value for the object.
198: */
199: public int hashCode() {
200: int result = m_namespace == null ? 0 : m_namespace.hashCode();
201: result = (result << 8)
202: ^ (m_name == null ? 0 : m_name.hashCode());
203: result = (result << 8)
204: ^ (m_version == null ? 0 : m_version.hashCode());
205: return (result ^ getType());
206: }
207:
208: /**
209: * Accessor: match the primary key of a definition.
210: * Note, this match is not wildcard capable. The type of the definitions
211: * will also be checked. The primary key of a definition is the triple
212: * namespace, name and version. This function is null-capable.
213: *
214: * @param type is the type identifier TRANSFORMATION or DERIVATION
215: * @param namespace is the namespace
216: * @param name is the name
217: * @param version is the version
218: *
219: * @return true, if the primary keys match, false otherwise.
220: */
221: public boolean match(int type, String namespace, String name,
222: String version) {
223: return ( // check type
224: type == this .getType() &&
225: // check namespace
226: (m_namespace == null && namespace == null || m_namespace != null
227: && namespace != null
228: && namespace.equals(m_namespace)) &&
229: // check name
230: (m_name != null && name != null && name.equals(m_name)) &&
231: // check version string
232: (m_version == null && version == null || m_version != null
233: && version != null && version.equals(m_version)));
234: }
235:
236: /**
237: * Accessor: match primary keys of two Definitions.
238: * Note, this match is not wildcard capable. The type of the definitions
239: * will also be checked. The primary key of a definition is the triple
240: * namespace, name and version. The equals function is null-capable.
241: *
242: * @param obj the reference object with which to compare.
243: * @return true, if the primary keys match, false otherwise.
244: */
245: public boolean equals(Object obj) {
246: // ward against null
247: if (obj == null)
248: return false;
249:
250: // shortcut
251: if (obj == this )
252: return true;
253:
254: // don't compare apples with oranges
255: if (!(obj instanceof Definition))
256: return false;
257:
258: // now we can safely cast
259: Definition d = (Definition) obj;
260: return match(d.getType(), d.getNamespace(), d.getName(), d
261: .getVersion());
262: }
263:
264: /**
265: * Accessor: Obtains the current description state.
266: *
267: * @return a string containing a descriptive remark on the definition,
268: * or null for no description.
269: * @see #setDescription(java.lang.String)
270: */
271: public String getDescription() {
272: return this .m_description;
273: }
274:
275: /**
276: * Accessor: Obtains the current keyword state.
277: *
278: * @return a string containing a collection of keywords describing the
279: * definition, or null for no keywords.
280: * @see #setKeyword(java.lang.String)
281: */
282: public String getKeyword() {
283: return this .m_keyword;
284: }
285:
286: /**
287: * Accessor: Obtains the current name of the definition. Note that
288: * a name is mandatory for any {@link Transformation}, but a
289: * {@link Derivation} may remain anonymous.
290: *
291: * @return the current name used for the definition. Note that derivations
292: * may be anonymous. Returns null, if no name exists.
293: * @see #setName(java.lang.String)
294: */
295: public String getName() {
296: return this .m_name;
297: }
298:
299: /**
300: * Accessor: Obtains the current namespace that is used for the
301: * definition. Note that a namespace is part of the key for any
302: * {@link Transformation}.
303: *
304: * @return the namespace the definition resides in, or null, if
305: * no namespace was defined.
306: * @see #setNamespace(java.lang.String)
307: */
308: public String getNamespace() {
309: return this .m_namespace;
310: }
311:
312: /**
313: * Accessor: Obtains the current title state.
314: *
315: * @return the title given to this definition, or null, if there
316: * was no title defined.
317: * @see #setTitle(java.lang.String)
318: */
319: public String getTitle() {
320: return this .m_title;
321: }
322:
323: /**
324: * Accessor: Obtains the current URI definition.
325: *
326: * @return the URL pointing to related information or a project, or
327: * null, if no URL was registered.
328: * @see #setUrl(java.lang.String)
329: */
330: public String getUrl() {
331: return this .m_url;
332: }
333:
334: /**
335: * Accessor: Obtains the current version of the definition. A version
336: * is an integral part of a logical {@link Transformation}.
337: *
338: * @return the version number of this definition, or null, if no
339: * version number was defined.
340: * @see #setVersion(java.lang.String)
341: */
342: public String getVersion() {
343: return this .m_version;
344: }
345:
346: /**
347: * Accessor: Sets the description.
348: *
349: * @param description
350: * @see #getDescription()
351: */
352: public void setDescription(String description) {
353: this .m_description = description;
354: }
355:
356: /**
357: * Accessor: Sets or overwrites the keyword list.
358: *
359: * @param keyword
360: * @see #getKeyword()
361: */
362: public void setKeyword(String keyword) {
363: this .m_keyword = keyword;
364: }
365:
366: /**
367: * Accessor: Sets or overwrite the currently given name.
368: *
369: * @param name
370: * @see #getName()
371: */
372: public void setName(String name) {
373: this .m_name = name;
374: }
375:
376: /**
377: * Accessor: Sets or overwrites the namespace identifier.
378: *
379: * @param namespace
380: * @see #getNamespace()
381: */
382: public void setNamespace(String namespace) {
383: this .m_namespace = namespace;
384: }
385:
386: /**
387: * Accessor: Sets the current title for the definition.
388: *
389: * @param title
390: * @see #getTitle()
391: */
392: public void setTitle(String title) {
393: this .m_title = title;
394: }
395:
396: /**
397: * Accessor: Sets the project reference.
398: *
399: * @param url
400: * @see #getUrl()
401: */
402: public void setUrl(String url) {
403: this .m_url = url;
404: }
405:
406: /**
407: * Accessor: Sets the version of the definition.
408: *
409: * @param version
410: * @see #getVersion()
411: */
412: public void setVersion(String version) {
413: this .m_version = version;
414: }
415:
416: /**
417: * Identify the transformation or derivation by its name.
418: */
419: public abstract String identify();
420:
421: /**
422: * Create the short id from ns:id:version.
423: * @param d is a Definition, or null for non-siblings
424: * @param namespace is the namespace to use, may be null.
425: * @param name is the name to produce the id for, should not be null.
426: * @param version is a version string, may be null.
427: * @return A string which textually identifies a Definition.
428: * @exception RuntimeException, if the name and definition are both null.
429: */
430: public static String shortID(Definition d, String namespace,
431: String name, String version) {
432: if (name != null)
433: return Separator.combine(namespace, name, version);
434: else if (d != null)
435: return Separator.combine(namespace, Integer.toHexString(d
436: .hashCode()), version);
437: else
438: throw new RuntimeException(
439: "Definitions require valid identifiers");
440: }
441:
442: /**
443: * Constructs dynamically a short descriptive, hopefully unique
444: * identifier for this derivation w/o referring to any transformation.
445: * FIXME: Anonymous derivations get their hash code, which is well
446: * for the first versions working without database. Later versions
447: * with database must use some unique sequence mechanism instead.
448: *
449: * @return a string describing the derivation
450: * @see Object#hashCode()
451: */
452: public String shortID() {
453: return shortID(this , this .m_namespace, this .m_name,
454: this .m_version);
455: }
456:
457: /**
458: * The toXML method is a partial method, to be incorporated/called
459: * by its sibling class method of the same name. For this reason,
460: * it does not fit the {@link VDL} interface.
461: *
462: * @return a string containing the attributes collected in the base class.
463: */
464: public String toXML() {
465: StringBuffer result = new StringBuffer();
466:
467: if (this .m_namespace != null)
468: result.append(" namespace=\"").append(
469: quote(this .m_namespace, true)).append("\"");
470:
471: if (this .m_name != null)
472: result.append(" name=\"").append(quote(this .m_name, true))
473: .append("\"");
474:
475: if (this .m_version != null)
476: result.append(" version=\"").append(
477: quote(this .m_version, true)).append("\"");
478:
479: if (this .m_description != null)
480: result.append(" description=\"").append(
481: quote(this .m_description, true)).append("\"");
482:
483: if (this .m_title != null)
484: result.append(" title=\"")
485: .append(quote(this .m_title, true)).append("\"");
486:
487: if (this .m_keyword != null)
488: result.append(" keyword=\"").append(
489: quote(this .m_keyword, true)).append("\"");
490:
491: if (this .m_url != null)
492: result.append(" url=\"").append(quote(this .m_url, true))
493: .append("\"");
494:
495: return result.toString();
496: }
497:
498: /**
499: * The toXML method is a partial method, to be incorporated/called
500: * by its sibling class method of the same name. For this reason,
501: * it does not fit the {@link VDL} interface.
502: *
503: * @param stream is a stream opened and ready for writing. This can also
504: * be a string stream for efficient output.
505: * @exception IOException if something fishy happens to the stream.
506: */
507: public void toXML(Writer stream) throws IOException {
508: writeAttribute(stream, " namespace=\"", this .m_namespace);
509: writeAttribute(stream, " name=\"", this .m_name);
510: writeAttribute(stream, " version=\"", this .m_version);
511: writeAttribute(stream, " description=\"", this .m_description);
512: writeAttribute(stream, " title=\"", this .m_title);
513: writeAttribute(stream, " keyword=\"", this .m_keyword);
514: writeAttribute(stream, " url=\"", this.m_url);
515: }
516: }
|