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 java.util.Vector;
014:
015: /**
016: * A class to handle attribute/value pairs.
017: * <p>
018: * A SOIF attribute name may be multi-valued. For example,
019: * attributes "author-1" and "author-2" are treated as seperate
020: * instances of a single attribute, allowing the attribute
021: * to have more than one value.
022: */
023: public class AVPairs implements Cloneable {
024: /**
025: * Attribute.
026: */
027: private String attribute;
028:
029: /**
030: * Value.
031: */
032: public String value;
033:
034: /**
035: * Next AVPair.
036: */
037: public AVPairs next;
038:
039: /**
040: * Multivalue SOIF base name.
041: */
042: private String attributeName;
043:
044: /**
045: * Multivalue SOIF numeric version of index.
046: */
047: private int attributeIndex;
048:
049: /**
050: * No multivalue value.
051: * This is the value that an AVPair which is not multivalue
052: * will return if asked for its multivalue index.
053: */
054: public static final int NOMULTIVALUE = -1;
055:
056: /**
057: * Constructs a new AVPairs instance.
058: * @param att the attribute
059: * @param val the value
060: */
061: public AVPairs(String att, String val) {
062: setAttribute(att);
063: value = val;
064: next = null;
065: }
066:
067: /**
068: * Set the attribute, do the multi-value parse.
069: * @param att the attribute
070: */
071: public void setAttribute(String att) {
072: String aIndex;
073:
074: attribute = att;
075: int i = attribute.lastIndexOf("-");
076:
077: if (i != -1) {
078: // this could be a MV attribute
079: try {
080: // try to parse "-NN"...
081: aIndex = attribute.substring(i + 1, attribute.length());
082: attributeIndex = Integer.parseInt(aIndex);
083: attributeName = attribute.substring(0, i);
084: } catch (NumberFormatException e) {
085: // ...nope, not MV
086: attributeIndex = NOMULTIVALUE;
087: attributeName = attribute;
088: }
089: } else {
090: attributeIndex = NOMULTIVALUE;
091: attributeName = attribute;
092: }
093: }
094:
095: /**
096: * Sets the index of a multivalue attribute value pair.
097: * @param index index >= 0 or == NOMULTIVALUE
098: * @exception IllegalArgumentException on bad index
099: */
100: public void setIndices(int index) {
101: if (index < 0 && index != NOMULTIVALUE)
102: throw new IllegalArgumentException("index [" + index
103: + "] must be >= 0 or == NOMULTIVALUE");
104:
105: for (AVPairs i = this ; i != null; i = i.next) {
106: i.attributeIndex = index;
107: i.attribute = (index == NOMULTIVALUE) ? i.attributeName
108: : i.attributeName + "-" + i.attributeIndex;
109: }
110: }
111:
112: /**
113: * Get the attribute for this AVPair.
114: */
115: public String getAttribute() {
116: return attribute;
117: }
118:
119: /**
120: * Get the attribute name for this AVPair.
121: */
122: public String getAttributeName() {
123: return attributeName;
124: }
125:
126: /**
127: * Get the attribute index for this AVPair. NOMULTIVALUE if no index.
128: */
129: public int getAttributeIndex() {
130: return attributeIndex;
131: }
132:
133: /**
134: * Is this avp multi-valued?
135: */
136: public boolean isMV() {
137: return attributeIndex != NOMULTIVALUE;
138: }
139:
140: /**
141: * Set the value of a non-multivalue attribute.
142: * Ignores case of attribute name.
143: * @param s the attribute
144: * @param v the value
145: */
146: public boolean setValue(String s, String v) {
147: return setValue(s, NOMULTIVALUE, v);
148: }
149:
150: /**
151: * Set the value of a multivalue attribute by index.
152: * Ignores case of attribute name.
153: * @param s the attribute
154: * @param n the index
155: * @param v the value
156: */
157: public boolean setValue(String s, int n, String v) {
158: boolean status = false;
159: for (AVPairs i = this ; i != null; i = i.next) {
160: if ((s.equalsIgnoreCase(i.attributeName))
161: && (n == i.attributeIndex)) {
162: i.value = v;
163: status = true;
164: }
165: }
166: return status;
167: }
168:
169: /**
170: * Return the value of a single AVPair (head of list).
171: * @param s the attribute
172: */
173: public String getValue() {
174: return value;
175: }
176:
177: /**
178: * Find the value of a non-multivalue attribute.
179: * Ignores case of attribute name.
180: * @param s the attribute
181: */
182: public String getValue(String s) {
183: return getValue(s, NOMULTIVALUE);
184: }
185:
186: /**
187: * Find the value of a multivalue attribute by index.
188: * Ignores case of attribute name.
189: * @param s the attribute
190: * @param n the index
191: */
192: public String getValue(String s, int n) {
193: for (AVPairs i = this ; i != null; i = i.next) {
194: if ((s.equalsIgnoreCase(i.attributeName))
195: && (n == i.attributeIndex))
196: return i.value;
197: }
198: return null;
199: }
200:
201: /**
202: * Find all values of an attribute. Return an array of strings for
203: * multiple values for an attribute, e.g., for Bob, return
204: * values for Bob-1 and Bob-2.
205: * Ignores case of attribute name.
206: * @param s the attribute
207: */
208: public String[] getValues(String s) {
209: String vals[] = new String[attributeValueCount(s)];
210: int i = 0;
211: for (AVPairs avp = this ; avp != null; avp = avp.next) {
212: if (s.equalsIgnoreCase(avp.attributeName)) {
213: vals[i] = avp.value;
214: i++;
215: }
216: }
217: return vals;
218: }
219:
220: /**
221: * Return a unique list of attributes w/out multi value,
222: * e.g. for Bob-1, Bob-2, Jim-1, return Bob, Jim.
223: * Ignores case of attribute name.
224: */
225: public String[] getAttributes() {
226: Vector v = new Vector(count());
227: for (AVPairs avp = this ; avp != null; avp = avp.next) {
228: if (!v.contains((String) avp.attributeName))
229: v.addElement((String) avp.attributeName);
230: }
231: v.trimToSize();
232: String atts[] = new String[v.size()];
233: v.copyInto((String[]) atts);
234: return atts;
235: }
236:
237: /**
238: * Return a unique list of attributes w/out multi value,
239: * e.g. for Bob-1, Bob-2, Jim-1, return Bob, Jim.
240: */
241: public int getAttributeCount() {
242: Vector v = new Vector(count());
243: for (AVPairs avp = this ; avp != null; avp = avp.next) {
244: if (!v.contains((String) avp.attributeName))
245: v.addElement((String) avp.attributeName);
246: }
247: v.trimToSize();
248: return v.size();
249: }
250:
251: /**
252: * Get number of values for an attribute, e.g. if Bob has
253: * Bob-1 and Bob-2, the answer is 2.
254: * Ignores case of attribute name.
255: * @param s the attribute
256: */
257: public int attributeValueCount(String s) {
258: int n = 0;
259: for (AVPairs i = this ; i != null; i = i.next) {
260: if ((s.equalsIgnoreCase(i.attributeName)))
261: n++;
262: }
263: return n;
264: }
265:
266: /**
267: * Get the maximum multivalue value.
268: */
269: public int getMaxAttributeIndex() {
270: int n = NOMULTIVALUE;
271: for (AVPairs i = this ; i != null; i = i.next)
272: n = Math.max(n, i.attributeIndex);
273: return n;
274: }
275:
276: /**
277: * Check to see if an attributeName exists on the list of
278: * AVPairs, regardless of multivalue: e.g. Bob == Bob-1.
279: * Ignores case of attribute name.
280: * @param s the attribute
281: */
282: public boolean attributeNameExists(String s) {
283: for (AVPairs i = this ; i != null; i = i.next) {
284: if ((s.equalsIgnoreCase(i.attributeName)))
285: return true;
286: }
287: return false;
288: }
289:
290: /**
291: * Get an avpair based on the attribute.
292: * @param att attribute
293: */
294: public AVPairs getAVPair(String s) {
295: for (AVPairs i = this ; i != null; i = i.next) {
296: if (i.attribute.equalsIgnoreCase(s))
297: return i;
298: }
299: return null;
300: }
301:
302: /**
303: * Clone the AVPairs w/ the specified MV.
304: * @param mv multivalue value
305: */
306: public AVPairs getAVPairsByMV(int mv) {
307: AVPairs newList = null;
308: AVPairs tmp = null;
309:
310: for (AVPairs i = this ; i != null; i = i.next) {
311: if (i.attributeIndex == mv) {
312: tmp = new AVPairs(i.attribute, i.value);
313: tmp.next = newList;
314: newList = tmp;
315: }
316: }
317:
318: return newList;
319: }
320:
321: /**
322: * Clone the AVPairs w/ the specified attribute.
323: * For Bob, return for Bob-1 and Bob-2.
324: * @param s attribute
325: */
326: public AVPairs getAVPairsByAttribute(String s) {
327: AVPairs newList = null;
328: AVPairs tmp = null;
329:
330: for (AVPairs i = this ; i != null; i = i.next) {
331: if (i.attributeName.equalsIgnoreCase(s)) {
332: tmp = new AVPairs(i.attribute, i.value);
333: tmp.next = newList;
334: newList = tmp;
335: }
336: }
337:
338: return newList;
339: }
340:
341: /**
342: * Unduplicate values on the AVPairs list.
343: */
344: public AVPairs unduplicateValues() {
345: AVPairs newList = null;
346: AVPairs tmp = null;
347:
348: for (AVPairs i = this ; i != null; i = i.next) {
349: AVPairs j;
350: for (j = newList; j != null; j = j.next) {
351: if (i.value.equalsIgnoreCase(j.value))
352: break;
353: }
354: if (j == null) {
355: tmp = new AVPairs(i.attribute, i.value);
356: tmp.next = newList;
357: newList = tmp;
358: }
359: }
360:
361: return newList;
362: }
363:
364: /**
365: * Return the pairs of the list that are not multivalue.
366: */
367: public AVPairs getSingleValuePairs() {
368: AVPairs newList = null;
369: AVPairs tmp = null;
370:
371: for (AVPairs i = this ; i != null; i = i.next) {
372: if (i.attributeIndex == NOMULTIVALUE) {
373: tmp = new AVPairs(i.attribute, i.value);
374: tmp.next = newList;
375: newList = tmp;
376: }
377: }
378:
379: return newList;
380: }
381:
382: /**
383: * Count AVPairs.
384: */
385: public int count() {
386: int n = 0;
387: for (AVPairs i = this ; i != null; i = i.next)
388: n++;
389: return n;
390: }
391:
392: /**
393: * Insert new AVPair after this instance.
394: * @param avPair the new instance
395: */
396: public void insertAfter(AVPairs avPair) {
397: avPair.next = next;
398: next = avPair;
399: }
400:
401: /**
402: * Insert new AVPair after this instance.
403: * @param att attribute
404: * @param val value
405: */
406: public void insertAfter(String att, String val) {
407: AVPairs avPair = new AVPairs(att, val);
408: insertAfter(avPair);
409: }
410:
411: /**
412: * Remove AVPairs instance from list.
413: * Return a pointer to corrected list.
414: * The method is silent if it finds
415: * nothing to remove.
416: * @param avp node to nuke
417: */
418: public AVPairs remove(AVPairs avp) {
419: if (this == avp)
420: return this .next;
421:
422: if (this .next == null)
423: return this ;
424:
425: for (AVPairs i = this ; i.next != null; i = i.next) {
426: if (avp == i.next) {
427: i.next = i.next.next;
428: return this ;
429: }
430: }
431:
432: return this ;
433: }
434:
435: /**
436: * Remove AVPairs instance from list.
437: * Return a pointer to corrected list.
438: * @param att attribute to nuke
439: */
440: public AVPairs remove(String att) {
441: return remove(getAVPair(att));
442: }
443:
444: /**
445: * A convenience method which bundles insert(),
446: * setValue() and remove().
447: * If the proposed value is length 0, remove() is called.
448: * Otherwise, setValue() is called.
449: * If setValue() fails, insertAfter() is called.
450: * @param att attribute
451: * @param val value
452: */
453: public AVPairs update(String att, String val) {
454: if (val.length() == 0)
455: return remove(att);
456: else {
457: if (!setValue(att, val))
458: insertAfter(att, val);
459: }
460: return this ;
461: }
462:
463: /**
464: * Return the base attribute name.
465: */
466: public String attributeValue() {
467: return attributeName;
468: }
469:
470: public String toString() {
471: return "AVPairs instance: (" + Header.VERSION + ")\n"
472: + "\tattribute = [" + attribute + "]\n"
473: + "\tvalue = [" + value + "]\n"
474: + "\tattributeName = [" + attributeName + "]\n"
475: + "\tattributeIndex = [" + attributeIndex + "]\n"
476: + "\tnext = ["
477: + ((next == null) ? "null" : "not null") + "]\n";
478: }
479:
480: /**
481: * Return SOIF string version of AVPairs instance list.
482: */
483: public String toStringList() {
484: StringBuffer sb = new StringBuffer();
485: AVPairs i;
486: for (i = this ; i != null; i = i.next)
487: sb.append(i.toString() + "\n");
488: return sb.toString().trim();
489: }
490:
491: /**
492: * Print out SOIF attribute value pair.
493: * @param a attribute
494: * @param v value
495: */
496: public static String toSOIF(String a, String v) {
497: if ((a.length() == 0) || (v.length() == 0))
498: return "";
499: return a + "{" + v.length() + "}:\t" + v + "\n";
500: }
501:
502: /**
503: * Print out SOIF attribute value pair.
504: */
505: public String toSOIF() {
506: if ((attribute.length() == 0) || (value.length() == 0))
507: return "";
508: return attribute + "{" + value.length() + "}:\t" + value + "\n";
509: }
510:
511: /**
512: * Print out SOIF attribute value pair.
513: * @param mv multi-value
514: */
515: public String toSOIF(int mv) {
516: if ((attribute.length() == 0) || (value.length() == 0))
517: return "";
518: return attributeName + "-" + mv + "{" + value.length() + "}:\t"
519: + value + "\n";
520: }
521:
522: /**
523: * Print out SOIF attribute value pair.
524: */
525: public String toSOIFList() {
526: StringBuffer sb = new StringBuffer();
527: for (AVPairs i = this ; i != null; i = i.next)
528: sb.append(i.toSOIF());
529: return sb.toString().trim();
530: }
531:
532: /**
533: * Print out SOIF attribute value pair.
534: * @param mv multi-value
535: */
536: public String toSOIFList(int mv) {
537: StringBuffer sb = new StringBuffer();
538: for (AVPairs i = this ; i != null; i = i.next)
539: sb.append(i.toSOIF(mv));
540: return sb.toString().trim();
541: }
542:
543: /**
544: * Return "a = v" string version of AVPairs instance.
545: * @param quoted doublequote the value if true
546: */
547: public String toEqualString(boolean quoted) {
548: if (quoted)
549: return attribute + "=\"" + value + "\"";
550: else
551: return attribute + "=" + value;
552: }
553:
554: /**
555: * Return "a = v" string version of AVPairs list, spaced.
556: * @param quoted doublequote the value if true
557: */
558: public String toSpacedEqualStringList(boolean quoted) {
559: StringBuffer sb = new StringBuffer();
560: for (AVPairs i = this ; i != null; i = i.next)
561: sb.append(i.toEqualString(quoted) + " ");
562: return sb.toString().trim();
563: }
564:
565: /**
566: * Return "a = v" string version of AVPairs list, spaced.
567: * @param quoted doublequote the value if true
568: */
569: public String toCGIEqualStringList(boolean quoted) {
570: StringBuffer sb = new StringBuffer();
571: for (AVPairs i = this ; i != null; i = i.next) {
572: sb.append(i.toEqualString(quoted) + " ");
573: if (i.next != null) {
574: sb.append("&");
575: }
576: }
577: return sb.toString().trim();
578: }
579:
580: }
|