001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
003: * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
004: */
005: package com.sun.portal.desktop.dp.xml;
006:
007: import org.w3c.dom.*;
008:
009: import java.util.Map;
010: import java.util.Set;
011: import java.util.Iterator;
012: import java.util.List;
013:
014: import com.sun.portal.desktop.util.OrderedSet;
015: import com.sun.portal.desktop.util.OrderedMap;
016:
017: import com.sun.portal.desktop.context.DPContext;
018: import com.sun.portal.desktop.encode.Encoder;
019:
020: import com.sun.portal.desktop.dp.DPError;
021: import com.sun.portal.desktop.dp.DPCollection;
022: import com.sun.portal.desktop.dp.DPTypes;
023: import com.sun.portal.desktop.dp.DPRoot;
024: import com.sun.portal.desktop.dp.DPProperty;
025:
026: public class XMLDPCollection extends XMLDPProperty implements
027: DPCollection, DPTypes, XMLDPTags {
028: protected Map propertiesTable = null;
029:
030: /**
031: * Construct a DP collection and initialize.
032: */
033:
034: XMLDPCollection(DPContext dpc, DPRoot r, Document d, String name,
035: Map val) {
036: this (dpc, r, createElement(dpc, r, d, name, val));
037: }
038:
039: /**
040: * Construct a DP collection and initialize.
041: */
042:
043: XMLDPCollection(DPContext dpc, DPRoot r, Document d, String name,
044: List val) {
045: this (dpc, r, createElement(dpc, r, d, name, val));
046: }
047:
048: /**
049: * Construct an empty DP collection.
050: */
051:
052: XMLDPCollection(DPContext dpc, DPRoot r, Document d, String name) {
053: this (dpc, r, createElement(dpc, d, name));
054: }
055:
056: XMLDPCollection(DPContext dpc, DPRoot r, Element e) {
057: super (dpc, r, e);
058: propertiesTable = createElementTable(getElement());
059: }
060:
061: public void checkType() {
062: if ((!getElement().getTagName().equals(PROPERTIES_TAG))
063: && (!getElement().getTagName().equals(
064: CONDITIONALPROPERTIES_TAG))
065: && (!getElement().getTagName().equals(LOCALE_TAG))
066: && (!getElement().getTagName().equals(COLLECTION_TAG))) {
067: throw new DPError(
068: "XMLDPCollection.checkType(): wrong type tagName="
069: + getElement().getTagName());
070: }
071: }
072:
073: public Object setValue(Object o) {
074: Object old = getValue();
075:
076: if (o instanceof Map) {
077: setCollectionValue((Map) o);
078: } else if (o instanceof List) {
079: setCollectionValue((List) o);
080: } else {
081: throw new DPError(
082: "XMLDPCollection.setValue(): object was not a List or Map");
083: }
084:
085: return old;
086: }
087:
088: public short getType() {
089: return COLLECTION_DP;
090: }
091:
092: public String getTag() {
093: return COLLECTION_TAG;
094: }
095:
096: /**
097: * Gets a DP property from the base document, if it exists.
098: * This method will only fetch the object if it exists in this.
099: * Mergers will not be considered.
100: * The returned DP object may or may not be merged.
101: */
102: public DPProperty getFromThis(String key) {
103: Element e = getElementFromThis(key);
104: DPProperty dpProperty = null;
105:
106: if (e != null) {
107: dpProperty = (DPProperty) getObject(e);
108: if (dpProperty == null) {
109: dpProperty = XMLDPFactory.getInstance().getProperty(
110: getContext(), getRoot(), e);
111: putObject(dpProperty);
112: }
113: }
114:
115: return dpProperty;
116: }
117:
118: Element getElementFromThis(String key) {
119: Element e = (Element) propertiesTable.get(key);
120: return e;
121: }
122:
123: DPProperty getFromMergers(String key) {
124: long start = System.currentTimeMillis();
125:
126: DPProperty dpProperty = null;
127:
128: for (int i = 0; i < getMergers().size(); i++) {
129: DPCollection dpc = (DPCollection) getMergers().get(i);
130: DPProperty dpp = ((XMLDPCollection) dpc).getFromThis(key);
131:
132: if (dpp != null) {
133: dpProperty = dpp;
134: break;
135: }
136: }
137:
138: return dpProperty;
139: }
140:
141: public DPProperty get(String key) {
142: boolean replace = false;
143: DPProperty dpProperty = getFromThis(key);
144:
145: if (dpProperty != null && dpProperty.isMerged()) {
146: // nothing
147: } else {
148: for (int i = 0; i < getMergers().size(); i++) {
149: DPCollection dpc = (DPCollection) getMergers().get(i);
150:
151: DPProperty dpp = ((XMLDPCollection) dpc)
152: .getFromThis(key);
153:
154: if (dpp != null) {
155: if (dpProperty != null) {
156: if (dpp.getType() != dpProperty.getType()) {
157: throw new DPError(
158: "XMLDPCollection.get(): conflicting types found for key="
159: + key);
160: }
161: } else {
162: DPProperty ddpp = ((XMLDPProperty) dpp)
163: .createDummy(getRoot());
164: dpProperty = add(ddpp, false, false, true);
165: if (!dpp.isLocked() && dpProperty.isDummy()
166: && this .isReplace()) {
167: replace = true;
168: }
169: }
170:
171: if (!dpProperty.isMergeLocked()) {
172: if (dpp.isLocked() && dpp.isRemove()) {
173: dpProperty = null;
174: break;
175: }
176: }
177:
178: dpProperty.addMerger(dpp);
179: }
180: }
181: }
182:
183: if (dpProperty != null) {
184: if (!dpProperty.isMergeLocked() && dpProperty.isRemove()) {
185: dpProperty = null;
186: }
187: }
188:
189: if (replace) {
190: dpProperty = null;
191: }
192:
193: return dpProperty;
194: }
195:
196: public void addAll(Set props) {
197: if (props == null) {
198: return;
199: }
200:
201: for (Iterator i = props.iterator(); i.hasNext();) {
202: XMLDPProperty dpp = (XMLDPProperty) i.next();
203: add(dpp);
204: }
205: }
206:
207: public DPProperty add(DPProperty dpp) {
208: return add(dpp, true, true, false);
209: }
210:
211: DPProperty add(DPProperty dpp, boolean copy, boolean deep,
212: boolean dummy) {
213: //
214: // here, we are removing because since we've added a new value,
215: // that means that the cached value is probably not correct
216: // anymore. we want to force the code to fetch the new value
217: // and re-cache.
218: //
219: // the reason we are not caching here is that cached values are
220: // expected to have had merges added. however, this is not required
221: // for adding a property --- we don't want to cache a non-merged
222: // property
223: //
224: removeObject(dpp);
225:
226: XMLDPProperty xmldpp = null;
227: if (copy) {
228: xmldpp = (XMLDPProperty) dpp.copy(getRoot(), deep);
229: } else {
230: xmldpp = (XMLDPProperty) dpp;
231: }
232: Element e = xmldpp.getElement();
233: getElement().appendChild(e);
234: propertiesTable.put(xmldpp.getName(), e);
235: putObject(xmldpp);
236:
237: xmldpp.setDummy(dummy);
238:
239: return xmldpp;
240: }
241:
242: public void removeAll() {
243: Set names = getNamesFromThis();
244:
245: for (Iterator i = names.iterator(); i.hasNext();) {
246: String name = (String) i.next();
247: remove(name, false);
248: }
249: propertiesTable.clear();
250: }
251:
252: /**
253: * Deletes a property.
254: *
255: * note: you CANNOT delete a property from a channel if that property was
256: * inherited from the provider definition or from the container definiton.
257: * see bug #4695542
258: */
259:
260: public DPProperty remove(String key) {
261: return remove(key, true);
262: }
263:
264: protected DPProperty remove(String key, boolean updateTable) {
265: DPProperty removedDPP = null;
266:
267: DPProperty dppFromThis = getFromThis(key);
268:
269: if (dppFromThis != null) {
270: //getContext().debugError("XMLDPCollection.remove(): dppFromThis was non-null");
271: //
272: // property is in this, remove
273: // from this
274: //
275: removeElement(dppFromThis);
276: if (updateTable) {
277: propertiesTable.remove(key);
278: }
279: removeObject(dppFromThis);
280: removedDPP = dppFromThis;
281:
282: setDummy(false);
283: }
284:
285: //
286: // check to see if the property is in mergers
287: //
288:
289: DPProperty dppFromMerger = getFromMergers(key);
290:
291: if (dppFromMerger != null) {
292: //getContext().debugError("XMLDPCollection.remove(): dppFromMerger was non-null");
293:
294: //
295: // prop exists in mergers.
296: // add to this and set to merge remove
297: //
298: DPProperty dpp = add(dppFromMerger, true, false, false);
299: dpp.setMergeType(MERGE_REMOVE);
300: if (removedDPP == null) {
301: removedDPP = dpp;
302: }
303: }
304:
305: //getContext().debugError("XMLDPCollection.remove(): done, this=" + toDebugString());
306:
307: return removedDPP;
308: }
309:
310: void removeElement(DPProperty dpp) {
311: XMLDPProperty xmlDPP = (XMLDPProperty) dpp;
312: Element childElement = xmlDPP.getElement();
313: Element parentElement = getElement();
314: parentElement.removeChild(childElement);
315: }
316:
317: void removeChildElements() {
318: List childElements = getChildElements(getElement(), null);
319:
320: for (int i = 0; i < childElements.size(); i++) {
321: Element childElement = (Element) childElements.get(i);
322: getElement().removeChild(childElement);
323: removeObject(childElement);
324: }
325: propertiesTable.clear();
326: }
327:
328: private void removeElement(String key) {
329: Element childElement = getElementFromThis(key);
330: if (childElement == null) {
331: return;
332: }
333: getElement().removeChild(childElement);
334: removeObject(childElement);
335: propertiesTable.remove(key);
336: }
337:
338: public void setCollectionValue(Map m) {
339: Set mergerNames = getNamesFromMergers();
340: Set names = getNames();
341:
342: for (Iterator i = mergerNames.iterator(); i.hasNext();) {
343: String name = (String) i.next();
344:
345: if (!m.containsKey(name)) {
346: //
347: // the new maps does not contain the name from
348: // the merger. this means we must add the property
349: // from the merger as merge=remove
350: //
351:
352: //
353: // get the property from the merger. we'll use this to
354: // add to this removed
355: //
356: DPProperty mergerDPP = getFromMergers(name);
357:
358: //
359: // if the item also existed in this, remove it from this
360: //
361: removeElement(name);
362:
363: //
364: // we dealt with this one, remove it
365: // from the items to process
366: //
367: if (names.contains(name)) {
368: names.remove(name);
369: }
370:
371: //
372: // add the merger property, removed
373: //
374: DPProperty dpp = add(mergerDPP, true, false, false);
375: dpp.setMergeType(MERGE_REMOVE);
376: }
377: }
378:
379: //
380: // now we must add the objects in the new collection plus the removed
381: // objects discovered above
382: //
383:
384: //
385: // add objects from new collection
386: //
387: for (Iterator i = m.keySet().iterator(); i.hasNext();) {
388: String name = (String) i.next();
389: Object o = m.get(name);
390:
391: // To preserve the namedness, get the property from the merger
392: DPProperty dpProp = get(name);
393: // If the property previously existed remove it.
394: if (names.contains(name)) {
395: removeElement(name);
396: names.remove(name);
397: }
398:
399: if (dpProp != null) {
400: // Set the new value and add to the collection
401:
402: DPProperty dpp = add(dpProp, true, false, false);
403: dpp.setValue(o);
404: } else {
405: // New property hence create it
406: DPProperty dpp = createProperty(name, o);
407: add(dpp);
408: }
409: }
410:
411: // Properties (not found in the mergers) which are deleted will not be
412: // in the map m, delete those elements
413: if (names.size() > 0) {
414: for (Iterator i = names.iterator(); i.hasNext();) {
415: removeElement((String) i.next());
416: }
417: }
418:
419: setDummy(false);
420: }
421:
422: DPProperty createProperty(String name, Object o) {
423: DPProperty dpp = XMLDPFactory.getInstance().createProperty(
424: getContext(), getRoot(), getDocument(), name, o);
425: return dpp;
426: }
427:
428: public void setCollectionValue(List l) {
429: Map m = new OrderedMap();
430:
431: for (int i = 0; i < l.size(); i++) {
432: String s = (String) l.get(i);
433: m.put(s, s);
434: }
435:
436: setCollectionValue(m);
437: }
438:
439: public Map getCollectionValue() {
440: return (Map) getValue();
441: }
442:
443: public Object getValue() {
444: return getValue(getNames());
445: }
446:
447: Object getValue(Set names) {
448: Map objs = new OrderedMap();
449:
450: for (Iterator i = names.iterator(); i.hasNext();) {
451: String name = (String) i.next();
452: DPProperty dpProperty = get(name);
453:
454: if (dpProperty == null) {
455: throw new DPError(
456: "XMLDPCollection.getValue(): couldn't get value for name="
457: + name);
458: }
459:
460: Object v = dpProperty.getValue();
461: objs.put(name, v);
462: }
463:
464: return objs;
465: }
466:
467: public Set getNamesFromThis() {
468: return propertiesTable.keySet();
469: }
470:
471: Set mergeNamesFromThis(Set names, Set locked) {
472: Set namesFromThis = getNamesFromThis();
473:
474: for (Iterator i = namesFromThis.iterator(); i.hasNext();) {
475: String name = (String) i.next();
476: DPProperty dpp = getFromThis(name);
477:
478: if (dpp == null) {
479: throw new DPError(
480: "XMLDPCollection.mergeNamesFromThis(): mismatch, could not get object from this for name from this, name="
481: + name
482: + ", namesFromThis="
483: + namesFromThis);
484: }
485:
486: if (dpp.isDummy()) {
487: continue;
488: }
489:
490: //
491: // if the property by this name was locked, then we don't
492: // touch it's existing state. this will prevent us
493: // from removing a names whose property was "locked"
494: //
495: if (locked.contains(name)) {
496: continue;
497: }
498:
499: if (dpp.isLocked()) {
500: locked.add(name);
501: }
502:
503: if (dpp.getMergeType() == MERGE_REMOVE) {
504: names.remove(name);
505: continue;
506: }
507:
508: //
509: // if the merge type is fuse or replace, we just add it to the
510: // set of names
511: //
512: names.add(name);
513:
514: }
515:
516: return names;
517: }
518:
519: Set getNamesFromMergers() {
520: Set names = new OrderedSet();
521: Set locked = new OrderedSet();
522:
523: for (int i = 0; i < getMergers().size(); i++) {
524: XMLDPCollection dpc = (XMLDPCollection) getMergers().get(i);
525:
526: if (dpc.isRemove()) {
527: names = clearElements(names, locked);
528: } else if (!dpc.isDummy() && !dpc.isMergeLocked()
529: && dpc.isReplace()) {
530: names = clearElements(names, locked);
531: names = dpc.mergeNamesFromThis(names, locked);
532: } else {
533: names = dpc.mergeNamesFromThis(names, locked);
534: }
535:
536: if (dpc.isLocked()) {
537: return names;
538: }
539: }
540:
541: return names;
542: }
543:
544: public Set getValues() {
545: Set names = getNames();
546: Set values = new OrderedSet();
547:
548: for (Iterator i = names.iterator(); i.hasNext();) {
549: String key = (String) i.next();
550: DPProperty dpp = get(key);
551: values.add(dpp.getValue());
552: }
553:
554: return values;
555: }
556:
557: public Set getNames() {
558: //
559: // this is the list of names we will return
560: //
561: Set names = new OrderedSet();
562:
563: //
564: // this keeps track of names whose properties were locked
565: //
566: Set locked = new OrderedSet();
567:
568: for (int i = 0; i < getMergers().size(); i++) {
569: DPCollection dpc = (DPCollection) getMergers().get(i);
570:
571: if (dpc.isRemove()) {
572: names = clearElements(names, locked);
573: } else if (!dpc.isDummy() && !dpc.isMergeLocked()
574: && dpc.isReplace()) {
575:
576: names = clearElements(names, locked);
577: names = ((XMLDPCollection) dpc).mergeNamesFromThis(
578: names, locked);
579: } else {
580: names = ((XMLDPCollection) dpc).mergeNamesFromThis(
581: names, locked);
582: }
583:
584: if (dpc.isLocked()) {
585: return names;
586: }
587: }
588:
589: // merge == fuse, add names from this
590:
591: if (!isDummy()) {
592: if (isReplace()) {
593: names = clearElements(names, locked);
594: }
595: names = mergeNamesFromThis(names, locked);
596: } else {
597: }
598:
599: return names;
600: }
601:
602: protected Element getMergedElement() {
603: Map map = getCollectionValue();
604: Element e = createElement(getContext(), getRoot(),
605: getDocument(), getTag(), getName(), map);
606: return e;
607: }
608:
609: public static Element createElement(DPContext dpc, DPRoot r,
610: Document d, String n, Map m) {
611: Element e = createElement(dpc, r, d, COLLECTION_TAG, n, m);
612:
613: return e;
614: }
615:
616: public static Element createElement(DPContext dpc, DPRoot r,
617: Document d, String n, List l) {
618: Element e = createElement(dpc, r, d, COLLECTION_TAG, n, l);
619:
620: return e;
621: }
622:
623: protected static Element createElement(DPContext dpc, DPRoot r,
624: Document d, String tagName, String n, List l) {
625: Map m = new OrderedMap();
626:
627: for (int i = 0; i < l.size(); i++) {
628: Object o = l.get(i);
629: m.put(o.toString(), o);
630: }
631:
632: return createElement(dpc, r, d, tagName, n, m);
633: }
634:
635: private static Element createElement(DPContext dpc, DPRoot r,
636: Document d, String tagName, String n, Map m) {
637: Element e = createElement(dpc, d, tagName, n);
638:
639: for (Iterator i = m.keySet().iterator(); i.hasNext();) {
640: String name = (String) i.next();
641: Object o = m.get(name);
642: DPProperty dpp = XMLDPFactory.getInstance().createProperty(
643: dpc, r, d, name, o);
644: XMLDPProperty xmlDPP = (XMLDPProperty) dpp;
645: Element newElement = xmlDPP.getElement();
646: e.appendChild(newElement);
647: }
648:
649: setDefaultsElement(e);
650:
651: return e;
652: }
653:
654: public int getDefaultMergeType() {
655: return staticGetDefaultMergeType();
656: }
657:
658: static int staticGetDefaultMergeType() {
659: return MERGE_FUSE;
660: }
661:
662: public void setMergeDefaults() {
663: setMergeDefaultsElement(getElement());
664: }
665:
666: public void setDefaults() {
667: setDefaultsElement(getElement());
668: }
669:
670: static void setMergeDefaultsElement(Element e) {
671: setMergeTypeElement(e, staticGetDefaultMergeType());
672: e.setAttribute(LOCK_KEY, FALSE_ATTR);
673: }
674:
675: static void setDefaultsElement(Element e) {
676: setMergeDefaultsElement(e);
677: e.setAttribute(PROPAGATE_KEY, TRUE_ATTR);
678: e.setAttribute(ADVANCED_KEY, FALSE_ATTR);
679: }
680:
681: Set clearElements(Set names, Set locked) {
682: for (Iterator i = names.iterator(); i.hasNext();) {
683: String name = (String) i.next();
684: if (!locked.contains(name)) {
685: i.remove();
686: }
687: }
688:
689: return names;
690: }
691:
692: public void appendChildProperty(StringBuffer b, int indent) {
693: for (Iterator i = getNamesFromThis().iterator(); i.hasNext();) {
694: String name = (String) i.next();
695: DPProperty prop = getFromThis(name);
696: prop.toXML(b, indent + 1);
697: }
698: }
699:
700: public void toXML(StringBuffer b, int indent) {
701: if (isDummy()) {
702: return;
703: }
704:
705: indentBuffer(b, indent);
706: appendStartTag(b);
707: b.append(" " + NAME_KEY + "=\"").append(
708: Encoder.XML_ENCODER.encode(getName())).append("\"");
709: appendMergeAttr(b);
710: appendLockAttr(b);
711: appendAdvancedAttr(b);
712: appendPropagateAttr(b);
713: b.append(">\n");
714: appendChildProperty(b, indent);
715: indentBuffer(b, indent);
716: appendEndTag(b);
717: }
718:
719: }
|