001: /*
002: * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
003: * NETSCAPE COMMUNICATIONS CORPORATION
004: *
005: * Copyright (c) 1996 Netscape Communications Corporation.
006: * All Rights Reserved.
007: * Use of this Source Code is subject to the terms of the applicable
008: * license agreement from Netscape Communications Corporation.
009: */
010:
011: package soif;
012:
013: import util.AltSTokenizer;
014:
015: /**
016: Package RDM headers.
017: <p>
018: This class package RDM Header information for easy management,
019: validation and passing to other classes.
020: It also manages RDM return header checking for errors.
021: <p>
022: The many of the descriptions included in this document have been
023: copied from the RDM spec.
024: See the RDM spec for more information.
025: *
026: * @version 1.01
027: */
028: public class RDMHeader {
029: private boolean valid;
030:
031: private String RDM_Version;
032: private int RDM_Type;
033: private int RDM_Query_Language;
034: private CSID Compass_Service_ID;
035: private String RDM_Response_Interpret;
036: private String RDM_Error_Message;
037:
038: private int RDM_Results; // number of results for this response
039: private int RDM_Hits; // number of matching hits
040: private int RDM_Documents; // across this many 'documents'
041:
042: private AVPairs list;
043:
044: /**
045: * Base RDM query language constant.
046: */
047: private final static int RDM_QL = 200;
048: /**
049: * RDM Query Language: Verity.
050: * Query follows the conventions of the Verity IR query language.
051: */
052: public final static int QL_VERITY = RDM_QL + 1;
053:
054: /**
055: * Base RDM-Type constant.
056: */
057: private final static int RDM_TYPE_BASE = 100;
058: /**
059: * RDM-Type: RD-Request.
060: * Request to send RD's based on given query.
061: */
062: public final static int RD_REQUEST = RDM_TYPE_BASE + 1;
063: /**
064: * RDM-Type: RD-Request-Deleted.
065: * Request to send RD's have been deleted based on given query.
066: */
067: public final static int RD_REQUEST_DELETED = RDM_TYPE_BASE + 2;
068: /**
069: * RDM-Type: RD-Response
070: * Contains RD's.
071: */
072: public final static int RD_RESPONSE = RDM_TYPE_BASE + 3;
073: /**
074: * RDM-Type: RD-Response-Deleted.
075: * Contains RD's which should be deleted.
076: */
077: public final static int RD_RESPONSE_DELETED = RDM_TYPE_BASE + 4;
078: /**
079: * RDM-Type: Schema-Description-Request.
080: * Request to send the schema definition.
081: */
082: public final static int SCHEMA_DESCRIPTION_REQUEST = RDM_TYPE_BASE + 5;
083: /**
084: * RDM-Type: Schema-Description-Response.
085: * Contains the schema definition.
086: */
087: public final static int SCHEMA_DESCRIPTION_RESPONSE = RDM_TYPE_BASE + 6;
088: /**
089: * RDM-Type: Server-Description-Request.
090: * Request to send the server description.
091: */
092: public final static int SERVER_DESCRIPTION_REQUEST = RDM_TYPE_BASE + 7;
093: /**
094: * RDM-Type: Sever-Description-Response.
095: * Contains the server description.
096: */
097: public final static int SERVER_DESCRIPTION_RESPONSE = RDM_TYPE_BASE + 8;
098: /**
099: * RDM-Type: Taxonomy-Description-Request.
100: * Request to send the taxonomy description.
101: */
102: public final static int TAXONOMY_DESCRIPTION_REQUEST = RDM_TYPE_BASE + 9;
103: /**
104: * RDM-Type: Taxonomy-Description-Response.
105: * Contains the taxonomy description.
106: */
107: public final static int TAXONOMY_DESCRIPTION_RESPONSE = RDM_TYPE_BASE + 10;
108: /**
109: * RDM-Type: Status-Request.
110: * Request to send status message - used to test existence.
111: */
112: public final static int STATUS_REQUEST = RDM_TYPE_BASE + 11;
113: /**
114: * RDM-Type: Status-Response.
115: * Contains general status information about the result of the request.
116: */
117: public final static int STATUS_RESPONSE = RDM_TYPE_BASE + 12;
118:
119: /* The rdm type header strings */
120: private static String str_types[] = { "RD-Request",
121: "RD-Request-Deleted", "RD-Response", "RD-Response-Deleted",
122: "Schema-Description-Request",
123: "Schema-Description-Response",
124: "Server-Description-Request",
125: "Server-Description-Response",
126: "Taxonomy-Description-Request",
127: "Taxonomy-Description-Response", "Status-Request",
128: "Status-Response" };
129:
130: /**
131: * Constructor for required attributes only.
132: * @param RDM_Version RDM version string
133: * @param RDM_Type RDM type
134: * @param RDM_Query_Language RDM query language
135: */
136: public RDMHeader(String RDM_Version, int RDM_Type,
137: int RDM_Query_Language) {
138: this .RDM_Version = RDM_Version;
139: this .RDM_Type = stringToType(typeToString(RDM_Type));
140: this .RDM_Query_Language = stringToQL(qlToString(RDM_Query_Language));
141:
142: valid = simpleValidate();
143: }
144:
145: /**
146: * Constructor for required and optinal attributes.
147: * @param RDM_Version RDM version string
148: * @param RDM_Type RDM type
149: * @param RDM_Query_Language RDM query language
150: * @param Compass_Service_ID CSID
151: * @param RDM_Response_Interpret RDM response interpret
152: * @param RDM_Error_Message RDM error message
153: */
154: public RDMHeader(String RDM_Version, int RDM_Type,
155: int RDM_Query_Language, CSID Compass_Service_ID,
156: String RDM_Response_Interpret, String RDM_Error_Message) {
157: this (RDM_Version, RDM_Type, RDM_Query_Language);
158:
159: this .Compass_Service_ID = Compass_Service_ID;
160: this .RDM_Response_Interpret = RDM_Response_Interpret;
161: this .RDM_Error_Message = RDM_Error_Message;
162: }
163:
164: /**
165: * Constructor for RDM Header received as SOIF.
166: * @param soif SOIF chunk
167: */
168: public RDMHeader(SOIF soif) {
169: String s;
170:
171: if (soif.schemaName == null
172: || soif.schemaName.compareTo("RDMHEADER") != 0) {
173: valid = false;
174: return;
175: }
176:
177: RDM_Version = soif.getValue("RDM-Version");
178:
179: s = soif.getValue("RDM-Type");
180: if (s != null)
181: RDM_Type = stringToType(s);
182:
183: s = soif.getValue("RDM-Query-Language");
184: if (s != null)
185: RDM_Query_Language = stringToQL(s);
186:
187: s = soif.getValue("RDM-Catalog-Service-ID");
188: if (s != null)
189: Compass_Service_ID = new CSID(s);
190:
191: RDM_Response_Interpret = soif
192: .getValue("RDM-Response-Interpret");
193: if (RDM_Response_Interpret != null)
194: parseResponse();
195:
196: RDM_Error_Message = soif.getValue("RDM-Error-Message");
197:
198: }
199:
200: /**
201: * Other validation checks are performed, depending on
202: * how the instance is created but this is common to all.
203: */
204: private boolean simpleValidate() {
205: if ((RDM_Version.length() == 0) || (RDM_Type == RDM_TYPE_BASE)
206: || (RDM_Query_Language == RDM_QL)) {
207: return false;
208: }
209:
210: return true;
211: }
212:
213: /**
214: * Parses the rdm response interpret attribute.
215: *
216: * NB: Currently only makes sense for RD, taxonomy and url responses
217: */
218: private void parseResponse() {
219: RDM_Results = 0;
220: RDM_Hits = 0;
221: RDM_Documents = 0;
222:
223: if (RDM_Response_Interpret == null)
224: return;
225:
226: // RD and TAX responses looks like
227: // "3 results out of 10 hits across 157 documents"
228: // Some other responses, eg url, look like
229: // "3 results"
230: //
231: // Here we look for "[n result] [... n hit] [... n document]"
232: //
233: String resp = RDM_Response_Interpret;
234: try {
235: RDM_Results = getKeyedInt(resp, "result");
236: } catch (Exception e) {
237: }
238:
239: try {
240: RDM_Hits = getKeyedInt(resp, "hit");
241: } catch (Exception e) {
242: }
243:
244: try {
245: RDM_Documents = getKeyedInt(resp, "document");
246: } catch (Exception e) {
247: }
248: }
249:
250: /**
251: * Parses a keyed int out of a string, ie, "... nnn key ..."
252: * throws NumberFormatException on failure
253: */
254: private int getKeyedInt(String str, String rawkey)
255: throws NumberFormatException {
256: int res = 0;
257: try {
258: int i, n1, n2;
259: String key = " " + rawkey; // need space(s) before key
260: if ((i = str.indexOf(key)) <= 0)
261: throw (new Exception());
262: for (--i; i >= 0 && str.charAt(i) == ' '; --i)
263: ;
264: n2 = i + 1;
265: for (; i >= 0 && str.charAt(i) != ' '; --i)
266: ;
267: n1 = i + 1;
268: String s1 = str.substring(n1, n2);
269: //System.out.println("dbg: " + s1 + " " + n1 + " " + n2);
270: res = Integer.parseInt(s1);
271: } catch (Exception e) {
272: throw new NumberFormatException();
273: }
274: return res;
275: }
276:
277: /** The number of results in this response. */
278: public int resultCount() {
279: return RDM_Results;
280: }
281:
282: /** The number of matching hits. */
283: public int hitCount() {
284: return RDM_Hits;
285: }
286:
287: /** The total number of documents. */
288: public int documentCount() {
289: return RDM_Documents;
290: }
291:
292: /**
293: * Is this a valid RDM header?
294: */
295: public boolean isValid() {
296: return valid;
297: }
298:
299: /**
300: * Return the RDM Error Message (null if there is none).
301: */
302: public String getRDMErrorMessage() {
303: return RDM_Error_Message;
304: }
305:
306: /**
307: * Add an attribute value pair beyond the standard set.
308: * @param attribute attribute
309: * @param value value
310: */
311: public void addAVPair(String attribute, String value) {
312: AVPairs avp = new AVPairs(attribute, value);
313:
314: if (list == null) {
315: list = avp;
316: } else {
317: list.insertAfter(avp);
318: }
319: }
320:
321: /**
322: * Delete all attribute value pairs beyond the standard set.
323: */
324: public void deleteAVPairs() {
325: list = null;
326: }
327:
328: /**
329: * Translate query language constant to string.
330: * @param i query language constant
331: */
332: public static String qlToString(int i) {
333: switch (i) {
334: case QL_VERITY:
335: return "verity-ql";
336: default:
337: return "Unknown QL";
338: }
339: }
340:
341: /**
342: * Translate string to query language constant.
343: * @param s string
344: */
345: public static int stringToQL(String s) {
346: if (s.compareTo("verity-ql") == 0) {
347: return QL_VERITY;
348: }
349:
350: return RDM_QL;
351: }
352:
353: /**
354: * Translate rdm type to string.
355: * @param i type constant
356: */
357: public static String typeToString(int i) {
358: int idx = i - RDM_TYPE_BASE - 1;
359: if (i >= 0 && i < str_types.length)
360: return str_types[i];
361: else
362: return "Unknown Type";
363: }
364:
365: /**
366: * Translate string to rdm type.
367: * @param s string
368: */
369: public static int stringToType(String s) {
370: int i;
371: for (i = 0; i < str_types.length; ++i) {
372: if (s.equalsIgnoreCase(str_types[i]))
373: return RDM_TYPE_BASE + 1 + i;
374: }
375: return RDM_TYPE_BASE;
376: }
377:
378: /**
379: * Return string in CGI argument format.
380: */
381: public String toCGIString() {
382: StringBuffer sb = new StringBuffer();
383:
384: if (list != null) {
385: if (sb.length() != 0) {
386: sb.append("&");
387: }
388: sb.append(list.toCGIEqualStringList(false));
389: }
390:
391: if (RDM_Type != RDM_TYPE_BASE) {
392: if (sb.length() != 0) {
393: sb.append("&");
394: }
395: sb.append("type=" + typeToString(RDM_Type));
396: }
397:
398: if (RDM_Query_Language != RDM_QL) {
399: if (sb.length() != 0) {
400: sb.append("&");
401: }
402: sb.append("ql=" + qlToString(RDM_Query_Language));
403: }
404:
405: if (Compass_Service_ID.isValid()) {
406: if (sb.length() != 0) {
407: sb.append("&");
408: }
409: sb.append("csid=" + Compass_Service_ID.toString());
410: }
411:
412: return sb.toString();
413: }
414:
415: public String toString() {
416: return "RDMHeader instance:\n" + "\tvalid = ["
417: + valid
418: + "]\n"
419: + "\tRDM_Version = ["
420: + RDM_Version
421: + "]\n"
422: + "\tRDM_Type = ["
423: + typeToString(RDM_Type)
424: + "]\n"
425: + "\tRDM_Query_Language = ["
426: + qlToString(RDM_Query_Language)
427: + "]\n"
428: + "\tRDM_Response_Interpret = ["
429: + RDM_Response_Interpret
430: + "]\n"
431: + "\tRDM_Error_Message = ["
432: + RDM_Error_Message
433: + "]\n"
434: + "\tCompass_Service_ID = ["
435: + ((Compass_Service_ID == null) ? "null"
436: : Compass_Service_ID.toString()) + "]\n"
437: + "\tlist = ["
438: + ((list == null) ? "null" : list.toString()) + "]\n";
439: }
440: }
|