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 com.sun.portal.desktop.context.DPContext;
008: import com.sun.portal.desktop.dp.DPChannel;
009: import com.sun.portal.desktop.dp.DPError;
010: import com.sun.portal.desktop.dp.DPNode;
011: import com.sun.portal.desktop.dp.DPObject;
012: import com.sun.portal.desktop.dp.DPProvider;
013: import com.sun.portal.desktop.dp.DPRoot;
014: import com.sun.portal.desktop.dp.DPTypes;
015: import org.w3c.dom.Document;
016: import org.w3c.dom.Element;
017: import org.xml.sax.InputSource;
018: import org.xml.sax.SAXException;
019: import org.xml.sax.SAXParseException;
020:
021: import javax.xml.parsers.DocumentBuilder;
022: import java.io.ByteArrayInputStream;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.Map;
029: import java.util.Set;
030:
031: public class XMLDPRoot extends XMLDPNode implements DPRoot, DPTypes,
032: XMLDPTags, XMLDPAttrs {
033: static long ccount = 0;
034: private Map objects = null;
035: protected Map providersTable = null;
036: private Element providersElement = null;
037:
038: //
039: // when the cached priority is modified via setPriority, the merge order for the current dproot does not get
040: // affected. It gets affected only if the DPRoot is recreated.
041: //
042: private Integer priority = null;
043:
044: /**
045: * This constructor can be used only if the encoding in the xml
046: * header is "UTF-8".
047: *
048: * @param dpc The DPContext
049: * @param doc String containing xml data.
050: */
051: public XMLDPRoot(DPContext dpc, String doc) {
052: this (dpc, createElement(dpc, doc));
053: }
054:
055: public XMLDPRoot(DPContext dpc, InputStream xmlByteStream) {
056: this (dpc, createElement(dpc, xmlByteStream));
057: }
058:
059: public XMLDPRoot(DPContext dpc) {
060: this (dpc, createElement(dpc));
061: }
062:
063: XMLDPRoot(DPContext dpc, Element e) {
064: super (dpc, null, e);
065: putObject(this );
066:
067: providersTable = createElementTable(getProvidersElement(getElement()));
068: }
069:
070: public Map getObjects() {
071: if (objects == null) {
072: objects = new HashMap();
073: }
074:
075: return objects;
076: }
077:
078: public DPObject getObject(Element e) {
079: DPObject dpo = (DPObject) getObjects().get(e);
080: return dpo;
081: }
082:
083: public void putObject(DPObject dpo) {
084: XMLDPObject xmldpo = (XMLDPObject) dpo;
085: Element e = xmldpo.getElement();
086:
087: /*
088: if (getObjects().containsKey(e)) {
089: //
090: // danger, danger will robinson! we are
091: // caching the same object
092: // twice! this indicates a logic error somewhere
093: // else in the code
094: //
095: String name = dpo.getName();
096: getContext().debugError("XMLDPRoot.putObject(): contained object name=" + dpo.getName());
097: trace();
098: }
099: */
100:
101: getObjects().put(e, dpo);
102: }
103:
104: public void removeObject(DPObject dpo) {
105: XMLDPObject xmldpo = (XMLDPObject) dpo;
106: Element e = xmldpo.getElement();
107: removeObject(e);
108: }
109:
110: public void removeObject(Element e) {
111: getObjects().remove(e);
112: }
113:
114: public DPRoot getRoot() {
115: //
116: // root member declared in XMLDPObject is null for XMLDPRoot objects
117: // no one should ever reference it directly
118: //
119: return this ;
120: }
121:
122: public boolean isDirty() {
123: if (getElement().hasAttribute(DIRTY_KEY)
124: && getElement().getAttribute(DIRTY_KEY).equals(
125: TRUE_ATTR)) {
126: return true;
127: }
128:
129: return false;
130: }
131:
132: public void setDirty(boolean state) {
133: if (!state) {
134: getElement().removeAttribute(DIRTY_KEY);
135: } else {
136: getElement().setAttribute(DIRTY_KEY, TRUE_ATTR);
137: }
138: }
139:
140: Element getRootElement() {
141: return getElement();
142: }
143:
144: public int getPriority() {
145: if (priority == null) {
146: String p = getElement().getAttribute(PRIORITY_KEY);
147:
148: if (p.equals(USER_PRIORITY_ATTR)) {
149: priority = new Integer(Integer.MAX_VALUE);
150: } else {
151: try {
152: priority = new Integer(p);
153: } catch (NumberFormatException nfe) {
154: throw new DPError(
155: "XMLDPRoot.getPriority(): invalid value priority="
156: + p);
157: }
158: }
159: }
160:
161: return priority.intValue();
162: }
163:
164: public void setPriority(int priority) {
165: getElement().setAttribute(PRIORITY_KEY,
166: Integer.toString(priority));
167: this .priority = new Integer(priority);
168: }
169:
170: public String getVersion() {
171: return getElement().getAttribute(VERSION_KEY);
172: }
173:
174: public void setVersion(String version) {
175: getElement().setAttribute(VERSION_KEY, version);
176: }
177:
178: public String getTag() {
179: return DISPLAYPROFILE_TAG;
180: }
181:
182: public short getType() {
183: return ROOT_DP;
184: }
185:
186: Element getProvidersElement(Element e) {
187: if (providersElement == null) {
188: providersElement = getChildElement(e, PROVIDERS_TAG, null);
189:
190: if (providersElement == null) {
191: //
192: // this is okay, some nodes won't have a providers bag. this is an
193: // inidcation that the caller should look in the parent for the
194: // provider
195: //
196: throw new DPError(
197: "XMLDPNode.getProviderElement(): could not find child "
198: + PROVIDERS_TAG + " element");
199: }
200: }
201:
202: return providersElement;
203: }
204:
205: Element getProviderElement(String name) {
206: Element providerElement = (Element) providersTable.get(name);
207: return providerElement;
208: }
209:
210: public DPProvider getProviderFromThis(String name) {
211: Element e = getProviderElement(name);
212: DPProvider dpp = null;
213:
214: if (e != null) {
215: dpp = (DPProvider) getObject(e);
216: if (dpp == null) {
217: dpp = XMLDPFactory.getInstance().getProvider(
218: getContext(), getRoot(), e);
219: putObject(dpp);
220: }
221: }
222:
223: return dpp;
224: }
225:
226: public DPProvider getProvider(String name) {
227: boolean replace = false;
228: DPProvider dpProvider = getProviderFromThis(name);
229:
230: if (dpProvider != null && dpProvider.isMerged()) {
231: // nothing
232: } else {
233: for (int i = 0; i < getMergers().size(); i++) {
234: DPRoot dpr = (DPRoot) getMergers().get(i);
235: DPProvider dpp = ((XMLDPRoot) dpr)
236: .getProviderFromThis(name);
237:
238: if (dpp != null) {
239: if (dpProvider == null) {
240: DPProvider ddpp = ((XMLDPProvider) dpp)
241: .createDummy(getRoot());
242: dpProvider = addProvider(ddpp, false, false,
243: true);
244: if (!dpp.isLocked() && dpProvider.isDummy()
245: && this .isReplace()) {
246: replace = true;
247: }
248: }
249:
250: if (!dpProvider.isMergeLocked()) {
251: if (dpp.isLocked() && dpp.isRemove()) {
252: dpProvider = null;
253: break;
254: }
255: }
256: dpProvider.addMerger(dpp);
257: }
258:
259: }
260: }
261:
262: //
263: // if the merge is locked and the merge is remove, return null
264: // else, if we are merge remove, return null
265: //
266: if (dpProvider != null) {
267: if (!dpProvider.isMergeLocked() && dpProvider.isRemove()) {
268: dpProvider = null;
269: }
270: }
271:
272: if (replace) {
273: dpProvider = null;
274: }
275: return dpProvider;
276: }
277:
278: public DPProvider addProvider(DPProvider dpp) {
279: return addProvider(dpp, true, true, false);
280: }
281:
282: DPProvider addProvider(DPProvider dpp, boolean copy, boolean deep,
283: boolean dummy) {
284: removeObject(dpp);
285: XMLDPProvider xmldpp = null;
286: if (copy) {
287: xmldpp = (XMLDPProvider) dpp.copy(getRoot(), deep);
288: } else {
289: xmldpp = (XMLDPProvider) dpp;
290: }
291: Element e = xmldpp.getElement();
292: providersTable.put(xmldpp.getName(), e);
293: addProviderElement(getElement(), e);
294: putObject(xmldpp);
295:
296: xmldpp.setDummy(dummy);
297:
298: return xmldpp;
299: }
300:
301: void addProviderElement(Element parentNodeElement,
302: Element providerElement) {
303: Element providersElement = getProvidersElement(parentNodeElement);
304: providersElement.appendChild(providerElement);
305: }
306:
307: DPProvider getProviderFromMergers(String key) {
308: DPProvider dpProvider = null;
309:
310: for (int i = 0; i < getMergers().size(); i++) {
311: DPRoot dpr = (DPRoot) getMergers().get(i);
312: DPProvider dpp = ((XMLDPRoot) dpr).getProviderFromThis(key);
313:
314: if (dpp != null) {
315: dpProvider = dpp;
316: break;
317: }
318: }
319:
320: return dpProvider;
321: }
322:
323: public DPProvider removeProvider(String key) {
324: DPProvider removedDPP = null;
325:
326: DPProvider dppFromThis = getProviderFromThis(key);
327:
328: if (dppFromThis != null) {
329: //
330: // is in this, remove
331: // from this
332: //
333: removeProviderElement(dppFromThis);
334: providersTable.remove(key);
335:
336: removeObject(dppFromThis);
337: removedDPP = dppFromThis;
338:
339: setDummy(false);
340: }
341:
342: //
343: // check to see if in mergers
344: //
345:
346: DPProvider dppFromMerger = getProviderFromMergers(key);
347:
348: if (dppFromMerger != null) {
349: //
350: // exists in mergers.
351: // add to this and set to merge remove
352: //
353: DPProvider dpp = addProvider(dppFromMerger, true, false,
354: false);
355: dpp.setMergeType(MERGE_REMOVE);
356: if (removedDPP == null) {
357: removedDPP = dpp;
358: }
359: }
360:
361: return removedDPP;
362: }
363:
364: void removeProviderElement(DPProvider dpp) {
365: XMLDPProvider xmldpp = (XMLDPProvider) dpp;
366: Element childElement = xmldpp.getElement();
367: Element parentElement = (Element) childElement.getParentNode();
368: parentElement.removeChild(childElement);
369: }
370:
371: Set getProviderNamesFromMergers() {
372: Set names = new HashSet();
373: Set locked = new HashSet();
374:
375: for (int i = 0; i < getMergers().size(); i++) {
376: DPRoot dpr = (DPRoot) getMergers().get(i);
377:
378: if (dpr.isRemove()) {
379: names = clearProviderNames(names, locked);
380: } else if (dpr.getMergeType() == MERGE_REPLACE) {
381: names = clearProviderNames(names, locked);
382: names = ((XMLDPRoot) dpr).mergeProviderNamesFromThis(
383: names, locked);
384: } else {
385: names = ((XMLDPRoot) dpr).mergeProviderNamesFromThis(
386: names, locked);
387: }
388:
389: if (dpr.isLocked()) {
390: return names;
391: }
392: }
393:
394: return names;
395: }
396:
397: public Set getProviderNames() {
398: //
399: // this is the list of names we will return
400: //
401: Set names = new HashSet();
402:
403: //
404: // this keeps track of names whose properties were locked
405: //
406: Set locked = new HashSet();
407:
408: for (int i = 0; i < getMergers().size(); i++) {
409: DPRoot dpr = (DPRoot) getMergers().get(i);
410:
411: if (dpr.isRemove()) {
412: names = clearProviderNames(names, locked);
413: } else if (dpr.getMergeType() == MERGE_REPLACE) {
414: names = clearProviderNames(names, locked);
415: names = ((XMLDPRoot) dpr).mergeProviderNamesFromThis(
416: names, locked);
417: } else {
418: names = ((XMLDPRoot) dpr).mergeProviderNamesFromThis(
419: names, locked);
420: }
421:
422: if (dpr.isLocked()) {
423: return names;
424: }
425: }
426:
427: // merge == fuse, add names from this
428:
429: if (!isDummy()) {
430: if (isReplace()) {
431: names = clearProviderNames(names, locked);
432: }
433: names = mergeProviderNamesFromThis(names, locked);
434: }
435:
436: return names;
437: }
438:
439: public Set getProviderNamesFromThis() {
440: return providersTable.keySet();
441: }
442:
443: Set mergeProviderNamesFromThis(Set names, Set locked) {
444: Set namesFromThis = getProviderNamesFromThis();
445:
446: for (Iterator i = namesFromThis.iterator(); i.hasNext();) {
447: String name = (String) i.next();
448:
449: DPProvider dpp = getProviderFromThis(name);
450:
451: if (dpp == null) {
452: throw new DPError(
453: "XMLDPRoot.mergeProviderNamesFromThis(): mismatch, could not get object from this for name from this, name="
454: + name
455: + ", namesFromThis="
456: + namesFromThis);
457: }
458:
459: if (dpp.isDummy()) {
460: continue;
461: }
462:
463: //
464: // if the property by this name was locked, then we don't
465: // touch it's existing state. this will prevent us
466: // from removing a names whose property was "locked"
467: //
468: if (locked.contains(name)) {
469: continue;
470: }
471:
472: if (dpp.isLocked()) {
473: locked.add(name);
474: }
475:
476: if (dpp.getMergeType() == MERGE_REMOVE) {
477: names.remove(name);
478: continue;
479: }
480:
481: //
482: // if the merge type is fuse or replace, we just add it to the
483: // set of names
484: //
485: names.add(name);
486:
487: }
488:
489: return names;
490: }
491:
492: DPChannel addChannelHierarchy(DPNode n) {
493: //
494: // call recursive version, assuming we are starting
495: // at the root. the recursive version is implemented
496: // in XMLDPNode.
497: //
498:
499: DPChannel dpc = addChannelHierarchy(n.getRoot(), n.getName(), n);
500: return dpc;
501: }
502:
503: public DPChannel addChannelHierarchy(DPChannel dpc) {
504: return addChannelHierarchy((DPNode) dpc);
505: }
506:
507: public static StringBuffer getXMLHeader() {
508: //
509: // TBD(jtb): is this okay? we're hardcoding the XML document "header"
510: // here. would anyone want to change this? AKAI can tell, there's
511: // no way to generate this from the Document.you CAN get a "doc type"
512: // node, but that does not generate the <?xml ... > header.
513: //
514: // another option here is to get the various pieces of the header
515: // from the DPContext (encoding, dtd path, etc). or, we could
516: // just get the whole "header" from the DPContext.
517: //
518:
519: /* (Prashant): DSAME always writes the DP in utf-8 format. So hardcoding
520: * this should be ok.
521: */
522:
523: StringBuffer b = new StringBuffer(128);
524: b
525: .append("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n");
526: b
527: .append("<!DOCTYPE DisplayProfile SYSTEM \"jar://resources/psdp.dtd\">\n\n");
528:
529: return b;
530: }
531:
532: public String toString() {
533: StringBuffer b = new StringBuffer(256);
534: b.append(getXMLHeader());
535: toStringBuffer(getElement(), b, true, 0);
536: return b.toString();
537: }
538:
539: public String toString(boolean prune) {
540: StringBuffer b = new StringBuffer(256);
541: b.append(getXMLHeader());
542: toStringBuffer(getElement(), b, prune, 0);
543: return b.toString();
544: }
545:
546: public String toMergedXML() {
547: StringBuffer b = new StringBuffer(256);
548: b.append(getXMLHeader());
549: toStringBuffer(getMergedElement(), b, true, 0);
550: return b.toString();
551: }
552:
553: static Element createElement(DPContext dpc) {
554: return createElement(dpc, (InputStream) null);
555: }
556:
557: public DPRoot copy(boolean deep) {
558: DocumentBuilder db = getDocBuilder(getContext());
559: Document ownerDocument = db.newDocument();
560:
561: Element copyElement = (Element) ownerDocument.importNode(
562: getElement(), deep);
563:
564: if (!deep) {
565: //
566: // we're not copying deep, so copy empty versions of the
567: // required sub elements
568: //
569: copyElement.appendChild(ownerDocument
570: .importNode(getChildElement(getElement(),
571: PROPERTIES_TAG, null), false));
572: copyElement.appendChild(ownerDocument.importNode(
573: getChildElement(getElement(), CHANNELS_TAG, null),
574: false));
575: copyElement.appendChild(ownerDocument.importNode(
576: getProvidersElement(getElement()), false));
577: }
578:
579: return XMLDPFactory.getInstance().getRoot(getContext(),
580: copyElement);
581: }
582:
583: protected Element getMergedElement() {
584: Element e = createElement(getContext(), getDocument());
585: e.removeAttribute(DUMMY_KEY);
586:
587: //
588: // add properties
589: //
590: Element pse = getChildElement(e, PROPERTIES_TAG);
591: XMLDPProperties xp = (XMLDPProperties) getProperties();
592: e.replaceChild(xp.getMergedElement(), pse);
593:
594: //
595: // add channels
596: //
597: Element cse = getChildElement(e, CHANNELS_TAG);
598: Set names = getChannelNames();
599: for (Iterator i = names.iterator(); i.hasNext();) {
600: String name = (String) i.next();
601: XMLDPChannel xc = (XMLDPChannel) getChannel(name);
602: Element ce = xc.getMergedElement();
603: cse.appendChild(ce);
604: }
605:
606: //
607: // add providers
608: //
609: Element pvse = getChildElement(e, PROVIDERS_TAG);
610: names = getProviderNames();
611: for (Iterator i = names.iterator(); i.hasNext();) {
612: String name = (String) i.next();
613: XMLDPProvider xpv = (XMLDPProvider) getProvider(name);
614: Element pe = xpv.getMergedElement();
615: pvse.appendChild(pe);
616: }
617:
618: //
619: // reset priority
620: //
621: int priority = getPriority();
622: e.setAttribute(PRIORITY_KEY, Integer.toString(priority));
623:
624: return e;
625: }
626:
627: /**
628: * This method can be called only if the encoding in the xml header is "UTF-8"
629: * This method is not called during dpadmin. Thus it is ok to hardcode
630: * the getBytes to read utf-8 because the dp has been stored in that format.
631: *
632: * @param dpc The DPContext
633: * @param dpXML String containing xml data.
634: */
635: static Element createElement(DPContext dpc, String dpXML) {
636: Element elem = null;
637: if (dpXML != null) {
638: try {
639: ByteArrayInputStream byteIS = null;
640: byte[] bytes = dpXML.getBytes("UTF-8");
641: byteIS = new ByteArrayInputStream(bytes);
642: elem = createElement(dpc, byteIS);
643: byteIS.close();
644: } catch (java.io.IOException ioe) {
645: throw new DPError("XMLDPRoot.createElement(): ", ioe);
646: }
647: }
648: return elem;
649: }
650:
651: /**
652: * This method is called in both cases, (read/write) and (write via dpadmin).
653: * Hence it passes on the byte stream to the parser as is. It is
654: * upto the parser to read the header and figure out the encoding.
655: */
656: static Element createElement(DPContext dpc,
657: InputStream xmlByteStream) {
658: if (dpc == null) {
659: throw new DPError(
660: "XMLDPRoot.createElement(): DP context was null");
661: }
662:
663: DocumentBuilder db = getDocBuilder(dpc);
664: Document d = null;
665:
666: if (xmlByteStream == null) {
667: //
668: // user document is null. create a skeleton.
669: //
670: d = db.newDocument();
671: Element documentElement = createElement(dpc, d);
672: d.appendChild(documentElement);
673: } else {
674: try {
675: xmlByteStream.reset();
676: InputSource is = new InputSource(xmlByteStream);
677: d = db.parse(is);
678: } catch (SAXParseException spe) {
679: throw new DPError("XMLDPRoot.createElement(): line="
680: + spe.getLineNumber() + ". ", spe);
681: } catch (SAXException se) {
682: throw new DPError("XMLDPRoot.createElement(): ", se);
683: } catch (IOException ioe) {
684: throw new DPError("XMLDPRoot.createElement(): ", ioe);
685: }
686: }
687:
688: return d.getDocumentElement();
689: }
690:
691: static Element createElement(DPContext dpc, Document d) {
692: //
693: // create the psdp tag
694: //
695: Element documentElement = d.createElement(DISPLAYPROFILE_TAG);
696:
697: //
698: // create empty properties element, and add it to the doc element
699: //
700: Element propertiesElement = XMLDPProperties.createElement(dpc,
701: d);
702: documentElement.appendChild(propertiesElement);
703:
704: //
705: // create empty channels element, and add it to the doc element
706: //
707: Element channelsElement = d.createElement(CHANNELS_TAG);
708: documentElement.appendChild(channelsElement);
709:
710: //
711: // create empty providers element, and add it to the doc element
712: //
713: Element providersElement = d.createElement(PROVIDERS_TAG);
714: documentElement.appendChild(providersElement);
715:
716: setDefaultsElement(documentElement);
717:
718: documentElement.setAttribute(VERSION_KEY, DEFAULT_VERSION_ATTR);
719: documentElement.setAttribute(PRIORITY_KEY, USER_PRIORITY_ATTR);
720: documentElement.setAttribute(DUMMY_KEY, TRUE_ATTR);
721:
722: return documentElement;
723: }
724:
725: public boolean providerExists(String name) {
726: if (getProvider(name) == null) {
727: return false;
728: }
729:
730: return true;
731: }
732:
733: protected Set clearProviderNames(Set names, Set locked) {
734: for (Iterator i = names.iterator(); i.hasNext();) {
735: String name = (String) i.next();
736: if (!locked.contains(name)) {
737: i.remove();
738: }
739: }
740:
741: return names;
742: }
743:
744: public void toXML(StringBuffer b, int indent) {
745:
746: // string buffer cannot be null, and only in the root we will
747: // do the check and from here on, it will always be assumed that
748: // the buffer is not null.
749: if (b == null) {
750: b = new StringBuffer(256);
751: }
752:
753: // Add XML Header
754: b.append(getXMLHeader());
755:
756: // Add Display Profile Tag
757: appendStartTag(b);
758:
759: b.append(" " + VERSION_KEY + "=\"").append(
760: getElement().getAttribute(VERSION_KEY)).append(
761: "\" " + PRIORITY_KEY + "=\"").append(
762: getElement().getAttribute(PRIORITY_KEY)).append("\"");
763:
764: appendMergeAttr(b);
765: appendLockAttr(b);
766: appendAdvancedAttr(b);
767: b.append(">\n");
768:
769: // Add Properties
770: indentBuffer(b, indent);
771: getPropertiesFromThis().toXML(b, indent + 1);
772:
773: // Add Channels
774: indentBuffer(b, indent + 1);
775: appendChannels(b, indent);
776:
777: // Add Providers
778: indentBuffer(b, indent + 1);
779: b.append("<").append(PROVIDERS_TAG).append(">\n");
780: for (Iterator i = getProviderNamesFromThis().iterator(); i
781: .hasNext();) {
782: String providerName = (String) i.next();
783: DPProvider provider = getProviderFromThis(providerName);
784: provider.toXML(b, indent + 2);
785: }
786: indentBuffer(b, indent + 1);
787: b.append("</").append(PROVIDERS_TAG).append(">\n");
788:
789: appendEndTag(b);
790:
791: }
792:
793: }
|