001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005:
006: package com.sun.portal.search.rdm;
007:
008: import com.sun.portal.search.soif.*;
009:
010: import java.io.*;
011:
012: /**
013: * RDM Taxonomy
014: *
015: * Represents a hierarchy of Classifications (or Categories).
016: * The Taxonomy supports basic lookup and enumeration primitives
017: * for understanding the organization and content of the Classifications.
018: *
019: * To load a Taxonomy definition encoded in SOIF from a file or memory,
020: * use RDMTaxonomy_Parse().
021: *
022: * Example:
023: * SOIFStream *ss = SOIF_ParseInitFile(stdin);
024: * t = RDMTaxonomy_Parse(ss);
025: *
026: * To create a Taxonomy structure with no Classifications,
027: * use RDMTaxonomy_Create().
028: *
029: * To free an entire Taxonomy and all of its Classifications,
030: * use RDMTaxonomy_Free().
031: */
032: public class RDMTaxonomy {
033:
034: RDMClassification root; // Root of the Taxonomy Hierarchy
035: SOIF soif; // Direct access to SOIF object
036:
037: public final static String RDM_TAXONOMY_ROOT = "ROOT";
038:
039: /**
040: * RDMTaxonomy_Parse - Loads a taxonomy definition written in SOIF
041: * from the input SOIFStream. Returns null on error; otherwise,
042: * returns the RDMTaxonomy.
043: */
044: public RDMTaxonomy(SOIFInputStream ss) throws Exception {
045: this ((String) null);
046:
047: SOIF s;
048: RDMClassification c;
049: String p;
050:
051: while ((s = ss.readSOIF()) != null) { // until the End-Of-Stream
052:
053: if (false) {
054: // Print URL and Attribute Count for each SOIF
055: System.out.println("URL = %s" + s.getURL());
056: System.out.println("# of Attributes = "
057: + s.getAttributeCount());
058: }
059:
060: // If it's @TAXONOMY then get what we need from it
061: if (s.getSchemaName().equalsIgnoreCase(RDM.A_SN_RDM_TAX)) {
062: soif.merge(s);
063: // Assign Taxonomy-Id for ROOT
064: root.soif.insert(RDM.A_RDM_TAX, getId());
065: continue;
066: }
067:
068: // Require classification
069: if (!s.getSchemaName().equalsIgnoreCase(RDM.A_SN_RDM_CLASS))
070: throw new Exception("expected classification");
071:
072: // Does this classification belong in this taxonomy?
073: p = s.getValue(RDM.A_RDM_TAX);
074: if (p == null || !p.equalsIgnoreCase(getId()))
075: continue;
076:
077: c = new RDMClassification(s.getValue(RDM.A_RDM_ID));
078: c.soif.merge(s);
079: insert(c);
080: }
081: }
082:
083: public RDMTaxonomy(String id) {
084: root = new RDMClassification(RDM_TAXONOMY_ROOT);
085: soif = new SOIF(RDM.A_SN_RDM_TAX, null);
086: if (id != null) {
087: soif.insert(RDM.A_RDM_ID, id);
088: root.soif.insert(RDM.A_RDM_TAX, id);
089: }
090: }
091:
092: /** To lookup a Classification Id in the taxonomy, use find().
093: *
094: * Example:
095: * RDMClassification *musicp = (*t.find)(t, "Arts:Music");
096: */
097: public RDMClassification find(String cid) {
098: // XXX no security here...
099:
100: if (cid.equals(RDM_TAXONOMY_ROOT))
101: return root;
102:
103: /* Bug 71548
104: The previous check is insufficient to distinguish taxonomy root since the
105: Id attribute value is set by user of Taxonomy:Construction applet.
106: */
107: if (cid.equals(getId()))
108: return root;
109:
110: return root.find(cid);
111: }
112:
113: /** To insert a new classification, use insert().
114: * The given Classification object is inserted into the Taxonomy
115: * structure. Use delete() to release the classification object
116: * from the Taxonomy.
117: */
118: public void insert(RDMClassification c) {
119: String pid = c.getParentId();
120: if (pid != null) {
121: c.parent = find(pid);
122: if (c.parent != null)
123: c.parent.insertChild(c);
124: }
125: }
126:
127: protected void delete(RDMClassification c) {
128: //XXX assert(0);
129: }
130:
131: /** To traverse the Taxonomy in the given order, use apply()
132: * and give an explicit traversal policy:
133: * RDM_TAX_INORDER - node, then children (recommended)
134: * RDM_TAX_PREORDER - same as INORDER
135: * RDM_TAX_POSTORDER - children, then node
136: *
137: * Example:
138: * (*t.apply)(t, RDM_TAX_INORDER, MyFn, NULL);
139: * ...
140: * void MyFn(RDMClassification *c, void *unused)
141: * {
142: * printf("Classification = %s{n",
143: * RDMClassification_GetId(c));
144: * }
145: */
146: public void apply(int order, RDMCallback cb) throws Exception {
147: if (root != null)
148: root.apply(order, cb);
149: }
150:
151: /** To find the depth of this Classification from the Taxonomy root */
152: public int depth(RDMClassification c) {
153: int depth = 0;
154: RDMClassification walker = c;
155: while (walker != null) {
156: if (walker.getId().equals(RDM_TAXONOMY_ROOT))
157: break;
158: depth++;
159: walker = walker.parent;
160: }
161: return depth;
162: }
163:
164: /** Macros for accessing @TAXONOMY values
165: * Use prototype: char *RDMTaxonomy_GetXXX(RDMTaxonomy *t).
166: */
167: public String getId() {
168: return soif.getValue(RDM.A_RDM_ID);
169: }
170:
171: public String getDescription() {
172: return soif.getValue(RDM.A_RDM_DESC);
173: }
174:
175: public String getLMT() {
176: return soif.getValue(RDM.A_RDM_LMT);
177: }
178:
179: public String getMaintainer() {
180: return soif.getValue(RDM.A_RDM_MAINT);
181: }
182:
183: public SOIF getSOIF() {
184: return soif;
185: }
186:
187: /** Macros for defining @TAXONOMY values
188: * Use prototype: int RDMTaxonomy_SetXXX(RDMTaxonomy *t, char *newvalue).
189: */
190: public void setId(String s) {
191: soif.replace(RDM.A_RDM_ID, s);
192: }
193:
194: public void setDescription(String s) {
195: soif.replace(RDM.A_RDM_DESC, s);
196: }
197:
198: public void setLMT(String s) {
199: soif.replace(RDM.A_RDM_LMT, s);
200: }
201:
202: public void setMaintainer(String s) {
203: soif.replace(RDM.A_RDM_MAINT, s);
204: }
205:
206: }
|