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.Element;
008: import org.w3c.dom.Node;
009:
010: import java.util.Set;
011: import java.util.Map;
012: import java.util.HashSet;
013: import java.util.Iterator;
014:
015: import com.sun.portal.desktop.context.DPContext;
016:
017: import com.sun.portal.desktop.dp.DPError;
018: import com.sun.portal.desktop.dp.DPNode;
019: import com.sun.portal.desktop.dp.DPChannel;
020: import com.sun.portal.desktop.dp.DPContainerChannel;
021: import com.sun.portal.desktop.dp.DPProvider;
022: import com.sun.portal.desktop.dp.DPTypes;
023: import com.sun.portal.desktop.dp.DPRoot;
024: import com.sun.portal.desktop.dp.DPPropertyHolder;
025:
026: public abstract class XMLDPNode extends XMLDPPropertyHolder implements
027: DPNode, DPTypes, XMLDPTags, XMLDPAttrs {
028: private Map channelsTable = null;
029: private Element channelsElement = null;
030: private Element parentNodeElement = null;
031:
032: XMLDPNode(DPContext dpc, DPRoot r, Element e) {
033: super (dpc, r, e);
034: Element channelsElement = getChannelsElement(getElement());
035: if (channelsElement != null) {
036: channelsTable = createElementTable(channelsElement);
037: }
038: }
039:
040: public DPPropertyHolder getParentPropertyHolder() {
041: return getParentNode();
042: }
043:
044: Element getParentNodeElement() {
045: if (parentNodeElement == null) {
046: Node n = getElement().getParentNode();
047: if (n == null) {
048: return null;
049: }
050: n = n.getParentNode();
051: if (n == null) {
052: return null;
053: }
054:
055: if (!(n.getNodeType() == Node.ELEMENT_NODE)) {
056: throw new DPError(
057: "XMLDPNode.getParentElement(): parent was not an element!");
058: }
059:
060: parentNodeElement = (Element) n;
061: }
062:
063: return parentNodeElement;
064: }
065:
066: public DPNode getParentNodeFromThis() {
067: Element e = getParentNodeElement();
068: DPNode dpn = null;
069:
070: if (e != null) {
071: dpn = (DPNode) getObject(e);
072: if (dpn == null) {
073: dpn = XMLDPFactory.getInstance().getNode(getContext(),
074: getRoot(), e);
075: putObject(dpn);
076: }
077: }
078:
079: return dpn;
080: }
081:
082: public DPNode getParentNode() {
083: DPNode dp = getParentNodeFromThis();
084:
085: if (dp != null && dp.isMerged()) {
086: // nothing
087: } else {
088: for (int i = 0; i < getMergers().size(); i++) {
089: DPNode dpn = (DPNode) getMergers().get(i);
090:
091: if (getType() != dpn.getType()) {
092: throw new DPError(
093: "XMLDPNode.getParentNode(): type mismatch");
094: }
095:
096: DPNode parentDPN = ((XMLDPNode) dpn)
097: .getParentNodeFromThis();
098:
099: if (parentDPN != null) {
100: dp.addMerger(parentDPN);
101: }
102: }
103: }
104:
105: return dp;
106: }
107:
108: /*
109: * Add a channel object to the node object.
110: */
111:
112: //
113: // TBD(jtb):
114: //
115: // the problem here is that XMLDPChannel extends from XMLDPNode,
116: // and it doesn't make
117: // sense to call addChannel() on a DPChannel.
118: // in fact, i think you'll get an exception if you do.
119: // perhaps i can change the semantics such that calling
120: // addChannel() on a DPChannel adds it to the root object.
121: //
122: public DPChannel addChannel(DPChannel dpc) {
123: return addChannel(dpc, true, true, false);
124: }
125:
126: public DPChannel addChannel(DPChannel dpc, boolean copy,
127: boolean deep, boolean dummy) {
128: removeObject(dpc);
129:
130: XMLDPChannel xmldpc = null;
131: if (copy) {
132: xmldpc = (XMLDPChannel) dpc.copy(getRoot(), deep);
133: } else {
134: xmldpc = (XMLDPChannel) dpc;
135: }
136: Element e = xmldpc.getElement();
137: //
138: // get channelName before adding the actual element in order to
139: // get the single-qualified name
140: //
141: String channelName = xmldpc.getName();
142: addChannelElement(getElement(), e);
143: channelsTable.put(channelName, e);
144: putObject(xmldpc);
145: xmldpc.setDummy(dummy);
146:
147: return xmldpc;
148: }
149:
150: DPChannel addChannelHierarchy(DPNode pn, String name, DPNode n) {
151: //
152: // the basic alg here is: step down the base and merger
153: // trees in unison until we find the parent of the node to be
154: // added. when we find a node in the merger that is not in the
155: // base, we copy it from the merger and add it to the base.
156: // when we find the parent of the node to be added, we add
157: // the new channel there.
158: //
159: // this method is recursive.
160: //
161:
162: int i = name.indexOf(CHANNEL_NAME_SEPARATOR);
163:
164: String parentName = null;
165: String subName = null;
166:
167: if (i != -1) {
168: parentName = name.substring(0, i);
169: subName = name.substring(i + 1);
170: } else {
171: subName = name;
172: }
173:
174: //getContext().debugError("XMLDPNode.addChannelHierarchy(): parentName=" + parentName);
175: //getContext().debugError("XMLDPNode.addChannelHierarchy(): subName=" + subName);
176:
177: if (parentName == null) {
178: //getContext().debugError("XMLDPNode.addChannel(): parent name was null, adding here");
179: DPChannel dpc = addChannel((DPChannel) n, true, false, true);
180: //
181: // reset merge/lock attributes only
182: // (i.e. advanced/propagate attributes inherited)
183: //
184: ((XMLDPChannel) dpc).setMergeDefaults();
185: return dpc;
186: } else {
187: // recurse
188: //getContext().debugError("XMLDPNode.addChannel(): parent name was non-null, recursing");
189: DPChannel pc = pn.getChannel(parentName);
190: if (pc == null) {
191: //
192: // this should never happen
193: //
194: throw new DPError(
195: "XMLDPNode.addChannelHierarchy(): error traversing source hierarchy: could not find next descendent in merger");
196: }
197:
198: //
199: // now, either the channel exists in this or not
200: //
201: DPChannel this PC = getChannelFromThis(parentName);
202: if (this PC == null) {
203: //
204: // doesn't exist, add it
205: //
206: this PC = addChannel(pc, true, false, true);
207:
208: //
209: // reset merge/lock attributes only
210: // (i.e. advanced/propagate attributes inherited)
211: //
212: ((XMLDPChannel) this PC).setMergeDefaults();
213: }
214:
215: return ((XMLDPNode) this PC).addChannelHierarchy(pc,
216: subName, n);
217: }
218: }
219:
220: DPChannel getChannelFromMergers(String key) {
221: DPChannel dpChannel = null;
222:
223: for (int i = 0; i < getMergers().size(); i++) {
224: DPNode dpn = (DPNode) getMergers().get(i);
225: DPChannel dpc = ((XMLDPNode) dpn).getChannelFromThis(key);
226:
227: if (dpc != null) {
228: dpChannel = dpc;
229: break;
230: }
231: }
232:
233: return dpChannel;
234: }
235:
236: public DPChannel removeChannel(String key) {
237: DPChannel removedDPC = null;
238:
239: DPChannel dpcFromThis = getChannelFromThis(key);
240:
241: if (dpcFromThis != null) {
242: //
243: // is in this, remove
244: // from this
245: //
246: removeChannelElement(dpcFromThis);
247: channelsTable.remove(key);
248:
249: removeObject(dpcFromThis);
250: removedDPC = dpcFromThis;
251:
252: setDummy(false);
253: }
254:
255: //
256: // check to see if in mergers
257: //
258:
259: DPChannel dpcFromMerger = getChannelFromMergers(key);
260:
261: if (dpcFromMerger != null) {
262: //
263: // exists in mergers.
264: // add to this and set to merge remove
265: //
266: DPChannel dpc = addChannel(dpcFromMerger, true, false,
267: false);
268: dpc.setMergeType(MERGE_REMOVE);
269: if (removedDPC == null) {
270: removedDPC = dpc;
271: }
272: }
273:
274: return removedDPC;
275: }
276:
277: void removeChannelElement(DPChannel dpc) {
278: XMLDPChannel xmldpc = (XMLDPChannel) dpc;
279: Element childElement = xmldpc.getElement();
280: Element parentElement = (Element) childElement.getParentNode();
281: parentElement.removeChild(childElement);
282: }
283:
284: public DPProvider addProvider(DPProvider dpp) {
285: return getRoot().addProvider(dpp);
286: }
287:
288: /*
289: * Add a channel element to the node object.
290: *
291: * This method modifies the underlying root DOM fragement appending
292: * a channel element.
293: */
294: static void addChannelElement(Element parentNodeElement,
295: Element channelElement) {
296: Element channelsElement = getChildElement(parentNodeElement,
297: CHANNELS_TAG);
298:
299: if (channelsElement == null) {
300: throw new DPError(
301: "XMLDPRoot.addChannelElement(): could not find child channels element");
302: }
303:
304: channelsElement.appendChild(channelElement);
305: }
306:
307: public DPProvider removeProvider(String name) {
308: return getRoot().removeProvider(name);
309: }
310:
311: Set getChannelNamesFromMergers() {
312: Set names = new HashSet();
313: Set locked = new HashSet();
314:
315: for (int i = 0; i < getMergers().size(); i++) {
316: XMLDPNode dpn = (XMLDPNode) getMergers().get(i);
317:
318: if (dpn.isRemove()) {
319: names = clearChannelNames(names, locked);
320: } else if (dpn.getMergeType() == MERGE_REPLACE) {
321: names = clearChannelNames(names, locked);
322: names = dpn.mergeChannelNamesFromThis(names, locked);
323: } else {
324: names = dpn.mergeChannelNamesFromThis(names, locked);
325: }
326:
327: if (dpn.isLocked()) {
328: return names;
329: }
330: }
331:
332: return names;
333: }
334:
335: public Set getChannelNames() {
336: //
337: // this is the list of names we will return
338: //
339: Set names = new HashSet();
340:
341: //
342: // this keeps track of names whose properties were locked
343: //
344: Set locked = new HashSet();
345:
346: for (int i = 0; i < getMergers().size(); i++) {
347: DPNode dpn = (DPNode) getMergers().get(i);
348:
349: if (dpn.isRemove()) {
350: names = clearChannelNames(names, locked);
351: } else if (dpn.getMergeType() == MERGE_REPLACE) {
352: names = clearChannelNames(names, locked);
353: names = ((XMLDPNode) dpn).mergeChannelNamesFromThis(
354: names, locked);
355: } else {
356: names = ((XMLDPNode) dpn).mergeChannelNamesFromThis(
357: names, locked);
358: }
359:
360: if (dpn.isLocked()) {
361: return names;
362: }
363: }
364:
365: // merge == fuse, add names from this
366:
367: if (!isDummy()) {
368: if (isReplace()) {
369: names = clearChannelNames(names, locked);
370: }
371: names = mergeChannelNamesFromThis(names, locked);
372: }
373:
374: return names;
375: }
376:
377: public Set getChannelNamesFromThis() {
378: Set names = channelsTable.keySet();
379: return names;
380: }
381:
382: protected Set mergeChannelNamesFromThis(Set names, Set locked) {
383: Set namesFromThis = getChannelNamesFromThis();
384:
385: for (Iterator i = namesFromThis.iterator(); i.hasNext();) {
386: String name = (String) i.next();
387:
388: DPChannel dpc = getChannelFromThis(name);
389:
390: if (dpc == null) {
391: throw new DPError(
392: "XMLDPNode.mergeChanelNamesFromThis(): mismatch, could not get object from this for name from this, name="
393: + name
394: + ", namesFromThis="
395: + namesFromThis);
396: }
397:
398: if (dpc.isDummy()) {
399: continue;
400: }
401:
402: //
403: // if the property by this name was locked, then we don't
404: // touch it's existing state. this will prevent us
405: // from removing a names whose property was "locked"
406: //
407: if (locked.contains(name)) {
408: continue;
409: }
410:
411: if (dpc.isLocked()) {
412: locked.add(name);
413: }
414:
415: if (dpc.getMergeType() == MERGE_REMOVE) {
416: names.remove(name);
417: continue;
418: }
419:
420: //
421: // if the merge type is fuse or replace, we just add it to the
422: // set of names
423: //
424: names.add(name);
425:
426: }
427:
428: return names;
429: }
430:
431: public Set getProviderNames() {
432: return getRoot().getProviderNames();
433: }
434:
435: Element getChannelsElement(Element e) {
436: if (channelsElement == null) {
437: channelsElement = getChildElement(e, CHANNELS_TAG, null);
438: }
439:
440: return channelsElement;
441: }
442:
443: Element getChannelElement(String name) {
444: Element channelElement = (Element) channelsTable.get(name);
445: return channelElement;
446: }
447:
448: /*
449: protected DPChannel getDescendentChannelFromThis(String name) {
450: return getDescendentChannelFromThis(name, true);
451: }
452:
453: protected DPChannel getDescendentChannelFromThis(String name, boolean recurse) {
454: DPChannel dpc = null;
455: Element e = getChannelElement(name);
456:
457: if (e != null) {
458: dpc = (DPChannel)getObject(e);
459: if (dpc == null) {
460: dpc = XMLDPFactory.getInstance().getChannel(getContext(), getRoot(), e);
461: putObject(dpc);
462: }
463: }
464:
465: if (dpc == null && recurse) {
466: //
467: // look recursively in all child container channels
468: //
469: for (Iterator i = channelsTable.keySet().iterator(); i.hasNext(); ) {
470: String childName = (String)i.next();
471: DPChannel dpcChild = getDescendentChannelFromThis(childName, false);
472: if (dpcChild == null) {
473: throw new DPError("XMLDPNode.getDescendentChannel(): corrupted channel table, channel name=" + name + " not found in this=\n" + toDebugString());
474: }
475: if (dpcChild.getType() != CONTAINER_DP) {
476: continue;
477: }
478: dpc = ((XMLDPNode)dpcChild).getDescendentChannelFromThis(name);
479: if (dpc != null) {
480: break;
481: }
482: }
483: }
484:
485: return dpc;
486: }
487: */
488:
489: public DPChannel getChannelFromThis(String name) {
490: //getContext().debugError("XMLDPNode.getChannelFromThis(): name=" + name);
491: int type = getType();
492: if (type != CONTAINER_DP && type != ROOT_DP) {
493: //
494: // only a container or the root can contain channels
495: // i.e. if type == CHANNEL_DP, return null
496: //
497: return null;
498: }
499:
500: String subName = null;
501: String lastName = null;
502:
503: int i = name.indexOf(CHANNEL_NAME_SEPARATOR);
504:
505: if (i != -1) {
506: subName = name.substring(0, i);
507: lastName = name.substring(i + 1);
508:
509: } else {
510: subName = name;
511: }
512:
513: //getContext().debugError("XMLDPNode.getChannelFromThis(): subName=" + subName);
514: //getContext().debugError("XMLDPNode.getChannelFromThis(): lastName=" + lastName);
515:
516: Element e = getChannelElement(subName);
517: DPChannel dpc = null;
518:
519: if (e != null) {
520: dpc = (DPChannel) getObject(e);
521: if (dpc == null) {
522: dpc = XMLDPFactory.getInstance().getChannel(
523: getContext(), getRoot(), e);
524: putObject(dpc);
525: }
526: }
527:
528: if (dpc == null) {
529: return null;
530: }
531:
532: if (lastName == null) {
533: //
534: // leaf channel found. return it.
535: //
536: return dpc;
537: } else {
538: //
539: // not at end yet, recurse on what's
540: // left of the name
541: //
542: return ((XMLDPChannel) dpc).getChannelFromThis(lastName);
543: }
544: }
545:
546: public DPChannel getChannel(String name) {
547: boolean replace = false;
548:
549: DPChannel dpChannel = getChannelFromThis(name);
550:
551: if (dpChannel != null && dpChannel.isMerged()) {
552: // nothing
553: } else {
554: for (int i = 0; i < getMergers().size(); i++) {
555: DPNode dpn = (DPNode) getMergers().get(i);
556: DPChannel dpc = ((XMLDPNode) dpn)
557: .getChannelFromThis(name);
558:
559: if (dpc != null) {
560: if (dpChannel == null) {
561: dpChannel = ((XMLDPRoot) getRoot())
562: .addChannelHierarchy(dpc);
563: if (!dpc.isLocked() && dpChannel.isDummy()
564: && this .isReplace()) {
565: replace = true;
566: }
567: }
568:
569: if (!dpChannel.isMergeLocked()) {
570: if (dpc.isLocked() && dpc.isRemove()) {
571: dpChannel = null;
572: }
573: }
574: dpChannel.addMerger(dpc);
575: }
576: }
577: }
578:
579: //
580: // if the merge is locked and the merge is remove, return null
581: // else, if we are merge remove, return null
582: //
583: if (dpChannel != null) {
584: if (!dpChannel.isMergeLocked() && dpChannel.isRemove()) {
585: dpChannel = null;
586: }
587: }
588: if (replace) {
589: dpChannel = null;
590: }
591: return dpChannel;
592: }
593:
594: public boolean channelExists(String name) {
595: if (getChannel(name) == null) {
596: return false;
597: }
598:
599: return true;
600: }
601:
602: public boolean providerExists(String name) {
603: return getRoot().providerExists(name);
604: }
605:
606: public DPChannel createChannel(String name, String providerName) {
607: int i = name.lastIndexOf(CHANNEL_NAME_SEPARATOR);
608:
609: if (i == -1) {
610: DPChannel dpc = XMLDPFactory.getInstance().createChannel(
611: getContext(), getRoot(), getDocument(), name,
612: providerName);
613: //
614: // careful, return the copy we added
615: //
616: dpc = addChannel(dpc, false, true, false);
617:
618: return dpc;
619: }
620:
621: String containerName = name.substring(0, i);
622: String channelName = name.substring(i + 1);
623:
624: //getContext().debugError("XMLDPNode.createChannel(): containerName=" + containerName);
625: //getContext().debugError("XMLDPNode.createChannel(): channelName=" + channelName);
626:
627: DPChannel dpc = getChannel(containerName);
628: if (dpc == null) {
629: throw new DPError(
630: "XMLDPNode.createChannel(): could not find in path containerName="
631: + containerName);
632: }
633:
634: return dpc.createChannel(channelName, providerName);
635: }
636:
637: public DPContainerChannel createContainerChannel(String name,
638: String providerName) {
639: //getContext().debugError("XMLDPNode.createContainerChannel() name=" + name + ", providerName=" + providerName);
640: int i = name.lastIndexOf(CHANNEL_NAME_SEPARATOR);
641: DPContainerChannel dpcc = null;
642: //getContext().debugError("XMLDPNode.createContainer(): i=" + i);
643:
644: if (i == -1) {
645: dpcc = XMLDPFactory.getInstance().createContainerChannel(
646: getContext(), getRoot(), getDocument(), name,
647: providerName);
648: //
649: // careful, return the copy we added
650: //
651: dpcc = (DPContainerChannel) addChannel(dpcc, false, true,
652: false);
653: //getContext().debugError("XMLDPNode.createContainerChannel(): channelsTable.keySet()=" + channelsTable.keySet() + ", this root=" + getRoot().toString());
654: } else {
655: String containerName = name.substring(0, i);
656: String channelName = name.substring(i + 1);
657: //getContext().debugError("XMLDPNode.createContainer(): containerName=" + containerName);
658: //getContext().debugError("XMLDPNode.createContainer(): channelName=" + channelName);
659:
660: DPChannel dpc = getChannel(containerName);
661: if (dpc == null) {
662: throw new DPError(
663: "XMLDPNode.createContainerChannel(): could not find in path containerName="
664: + containerName);
665: }
666:
667: //
668: // check to make sure it's a container
669: //
670: if (dpc.getType() != CONTAINER_DP) {
671: throw new DPError(
672: "XMLDPNode.createContainerChannel(): trying to add a channel to a non-container="
673: + containerName);
674: }
675: dpcc = dpc
676: .createContainerChannel(channelName, providerName);
677: }
678: return dpcc;
679: }
680:
681: public DPChannel copyChannel(String src, String dst) {
682: //
683: // this method calls itself recursively until it finds where
684: // the new channel should be copied into. this is essentially
685: // calling getChannel() on the first path element in
686: // dst, and then resursively calling copyChannel() with
687: // dst=the tail path elements of dst.
688: //
689: // dst can be considered a relative path. no matter where
690: // "this" node is, you can copy a channel from here to there.
691: // dst must be relative to where "this" node is, that's all.
692: // if you call this method with this=root, then dst
693: // is an absolute path.
694: //
695:
696: //
697: // is there a head container that we need to recurse
698: // farther into?
699: //
700: int i = dst.lastIndexOf(CHANNEL_NAME_SEPARATOR);
701:
702: if (i == -1) {
703: //
704: // recursion is done.
705: // we have successfully navigated down path of
706: // dst channel name, and we are ready to copy the
707: // src channel into place here
708: //
709:
710: //
711: // get a handle to the src channel
712: //
713: DPChannel dpcSrc = getRoot().getChannel(src);
714:
715: //
716: // add the src channel into the tree where we are at,
717: // copying it at the same time
718: //
719: DPChannel dpcDst = dpcSrc.copy(getRoot(), true, dst);
720: dpcDst = addChannel(dpcDst, false, false, false);
721:
722: return dpcDst;
723: }
724:
725: //
726: // we have not found the branch where we are going to
727: // copy the channel to
728: //
729:
730: //
731: // get the head of the dst
732: String containerName = dst.substring(0, i);
733: //
734: // get tail of dst
735: String channelName = dst.substring(i + 1);
736:
737: //
738: // get a handle to the head of dst, a container
739: //
740: DPChannel dpc = getChannel(containerName);
741: if (dpc == null) {
742: throw new DPError(
743: "XMLDPNode.copyChannel(): could not find in path containerName="
744: + containerName);
745: }
746: if (dpc.getType() != CONTAINER_DP) {
747: throw new DPError(
748: "XMLDPNode.copyChannel(): trying to copy a channel into a non-container, containerName="
749: + containerName);
750: }
751:
752: //
753: // call recursively to navigate done the path of
754: // containers
755: //
756: return dpc.copyChannel(src, channelName);
757: }
758:
759: Set clearChannelNames(Set names, Set locked) {
760: for (Iterator i = names.iterator(); i.hasNext();) {
761: String name = (String) i.next();
762: if (!locked.contains(name)) {
763: i.remove();
764: }
765: }
766:
767: return names;
768: }
769:
770: public void appendChannels(StringBuffer b, int indent) {
771: b.append("<" + CHANNELS_TAG + ">\n");
772: for (Iterator i = getChannelNamesFromThis().iterator(); i
773: .hasNext();) {
774: String channelName = (String) i.next();
775: DPChannel channel = getChannelFromThis(channelName);
776: channel.toXML(b, indent + 2);
777: }
778: indentBuffer(b, indent + 1);
779: b.append("</" + CHANNELS_TAG + ">\n");
780: }
781:
782: }
|