001: /*
002: * ParManager.java
003: *
004: * Created on October 24, 2001, 3:39 PM
005: */
006:
007: package com.sun.portal.desktop.deployment;
008:
009: import java.util.StringTokenizer;
010: import java.util.Locale;
011: import java.util.ResourceBundle;
012: import java.util.PropertyResourceBundle;
013: import java.util.MissingResourceException;
014:
015: import java.text.MessageFormat;
016:
017: import java.io.PrintStream;
018: import java.io.InputStream;
019: import java.io.StringWriter;
020: import java.io.ByteArrayInputStream;
021: import java.io.File;
022:
023: import java.util.logging.Level;
024: import java.util.logging.Logger;
025:
026: import org.w3c.dom.Document;
027: import org.w3c.dom.Element;
028: import org.w3c.dom.Attr;
029: import org.w3c.dom.NodeList;
030: import org.w3c.dom.Node;
031: import org.w3c.dom.Text;
032: import org.w3c.dom.NamedNodeMap;
033:
034: import org.xml.sax.InputSource;
035:
036: import javax.xml.parsers.DocumentBuilder;
037: import javax.xml.parsers.DocumentBuilderFactory;
038:
039: import javax.xml.transform.Transformer;
040: import javax.xml.transform.TransformerFactory;
041:
042: import javax.xml.transform.dom.DOMSource;
043:
044: import javax.xml.transform.stream.StreamResult;
045:
046: import com.sun.portal.desktop.dp.xml.XMLDPTags;
047:
048: /**
049: * Utility switchboard class for Par files.
050: *
051: * @author yabob
052: * @version
053: */
054: public class Par implements XMLDPTags {
055:
056: public static void setLogger(Logger logger) {
057: m_Logger = logger;
058: }
059:
060: public static String classToFile(String pkg, String classname) {
061:
062: if (pkg != null && pkg.length() > 0) {
063: return classToFile(pkg + "." + classname);
064: }
065: return classname + ".class";
066: }
067:
068: public static String classToFile(String fullclassname) {
069:
070: StringTokenizer tok = new StringTokenizer(fullclassname, ".");
071: StringBuffer buf = new StringBuffer();
072: String pfx = "";
073:
074: while (tok.hasMoreTokens()) {
075: buf.append(pfx);
076: buf.append(tok.nextToken());
077: pfx = "/";
078: }
079:
080: buf.append(".class");
081:
082: return buf.toString();
083: }
084:
085: // Obtain the correct name to go with a psdp:parentry document
086:
087: public static String findDPEntryName(Document doc)
088: throws ParFileException {
089:
090: Element e = getDPDocElement(doc);
091:
092: Attr a = e.getAttributeNode("name");
093:
094: if (a == null) {
095: Object tok[] = { "document" };
096: throw new ParFileException("errorXMLNoName", tok);
097: }
098:
099: return a.getValue();
100: }
101:
102: // Obtain the applicable types and description from DP document. Optionally streams description out
103: // to an output stream.
104:
105: public static int applicableDocTypes(Document doc)
106: throws ParFileException {
107: return describeDPDoc(doc, null);
108: }
109:
110: public static int describeDPDoc(Document doc, PrintStream dout)
111: throws ParFileException {
112:
113: Element e = getDPDocElement(doc);
114: if (dout != null) {
115: dout.println("DP Document:");
116: }
117:
118: int types = 0;
119:
120: NodeList kids = e.getChildNodes();
121: for (int i = 0; i < kids.getLength(); ++i) {
122: Node child = kids.item(i);
123:
124: if (!(child instanceof Element)) {
125: continue;
126: }
127:
128: String nm = child.getNodeName();
129: Element chelt = (Element) child;
130:
131: if (nm.equals(CHANNEL_TAG)) {
132: types |= ExtractOp.TYPE_CHANNEL;
133: if (dout != null) {
134: Attr a = chelt.getAttributeNode("name");
135:
136: if (a == null) {
137: Object tok[] = { "channel" };
138: throw new ParFileException("errorXMLNoName",
139: tok);
140: }
141:
142: dout.println("\tChannel: " + a.getValue());
143: }
144: continue;
145: }
146:
147: if (nm.equals(PROVIDER_TAG)) {
148: types |= ExtractOp.TYPE_PROVIDER;
149: if (dout != null) {
150: Attr a = chelt.getAttributeNode("name");
151:
152: if (a == null) {
153: Object tok[] = { "provider" };
154: throw new ParFileException("errorXMLNoName",
155: tok);
156: }
157:
158: dout.println("\tProvider: " + a.getValue());
159: }
160: continue;
161: }
162:
163: if (nm.equals(DESCRIPTION_TAG) && dout != null) {
164: NodeList dkids = child.getChildNodes();
165: StringBuffer buf = new StringBuffer();
166:
167: for (int j = 0; j < dkids.getLength(); ++j) {
168: Node dchild = dkids.item(j);
169: if (dchild instanceof Text) {
170: buf.append(dchild.getNodeValue());
171: }
172: }
173:
174: StringTokenizer tok = new StringTokenizer(buf
175: .toString(), "\n\r");
176: while (tok.hasMoreTokens()) {
177: dout.println("\t" + tok.nextToken());
178: }
179: }
180: }
181:
182: return types;
183: }
184:
185: public static InputStream domToStream(Document doc)
186: throws ParFileException {
187:
188: try {
189:
190: // FIXME - this works, but the output is exceptionally ugly
191: // (no formatting at all - just a stream of tags with no whitespace).
192: // We kludge in our own indenting so that the result is at least semi-legible.
193:
194: TransformerFactory tf = TransformerFactory.newInstance();
195: Transformer t = tf.newTransformer();
196:
197: DOMSource ds = new DOMSource(doc);
198: StringWriter sw = new StringWriter();
199: StreamResult sr = new StreamResult(sw);
200:
201: t.transform(ds, sr);
202:
203: return new ByteArrayInputStream(indentTags(
204: sw.getBuffer().toString()).getBytes("UTF-8"));
205: } catch (Exception ex) {
206: throw new ParFileException("errorXMLWrite", ex);
207: }
208: }
209:
210: private static String indentTags(String str) {
211:
212: StringBuffer out = new StringBuffer();
213:
214: // NOTE - transform escapes "<" and ">" in attributes and
215: // text, so we may safely look for them.
216:
217: int indent = 0;
218: for (;;) {
219: int idx = str.indexOf("<");
220:
221: // No more tags? break
222: if (idx < 0) {
223: break;
224: }
225:
226: // handle leading non-tag text and strip off
227: if (idx > 0) {
228: out.append(str.substring(0, idx));
229: if (str.charAt(idx - 1) != '\n') {
230: out.append("\n");
231: }
232: str = str.substring(idx);
233: }
234:
235: // tag is now at beginning of string - find end.
236:
237: idx = str.indexOf(">");
238: if (idx <= 0) {
239: break; // shouldn't happen - give up.
240: }
241:
242: // if it's a "/>", decrement indent count.
243: if (str.charAt(1) == '/' && indent > 0) {
244: --indent;
245: }
246:
247: // indent
248: for (int ic = 0; ic < indent; ++ic) {
249: out.append(" ");
250: }
251:
252: // if this terminates the string, output, make string empty and break
253: if ((idx + 1) == str.length()) {
254: out.append(str);
255: str = "";
256: break;
257: }
258:
259: // spit out tag.
260: out.append(str.substring(0, idx + 1));
261: if (str.charAt(idx + 1) != '\n') {
262: out.append("\n");
263: }
264:
265: // if not a terminator or self-contained tag, up indent.
266: if (str.charAt(1) != '/' && str.charAt(idx - 1) != '/') {
267: ++indent;
268: }
269:
270: // strip off tag and continue
271: str = str.substring(idx + 1);
272: }
273:
274: out.append(str);
275: out.append("\n");
276:
277: return out.toString();
278: }
279:
280: public static Document streamToDom(InputStream str)
281: throws ParFileException {
282: try {
283: DocumentBuilderFactory dbf = DocumentBuilderFactory
284: .newInstance();
285: DocumentBuilder db = dbf.newDocumentBuilder();
286: return db.parse(str);
287: } catch (Exception ex) {
288: throw new ParFileException("errorXMLRead", ex);
289: }
290: }
291:
292: /*
293: * Makes a par entry based on a dp document.
294: */
295: public static Document makeParEntry(String name, String desc,
296: Element dp) throws ParFileException {
297:
298: Document doc = null;
299: try {
300: DocumentBuilderFactory dbf = DocumentBuilderFactory
301: .newInstance();
302: DocumentBuilder db = dbf.newDocumentBuilder();
303: doc = db.newDocument();
304: } catch (Exception ex) {
305: throw new ParFileException("errorXMLConstruct", ex);
306: }
307:
308: Element root = doc.createElement(PARENTRY_TAG);
309: root.setAttribute("name", name);
310: doc.appendChild(root);
311:
312: if (desc != null) {
313: Element delt = doc.createElement(DESCRIPTION_TAG);
314: delt.appendChild(doc.createTextNode(desc));
315: root.appendChild(delt);
316: }
317:
318: if (dp != null) {
319: root.appendChild(cloneElement(doc, dp));
320: }
321:
322: return doc;
323: }
324:
325: public static Document makeParEntry(String name, String desc,
326: Element provider, Element channel) throws ParFileException {
327:
328: Document doc = null;
329: try {
330: DocumentBuilderFactory dbf = DocumentBuilderFactory
331: .newInstance();
332: DocumentBuilder db = dbf.newDocumentBuilder();
333: doc = db.newDocument();
334: } catch (Exception ex) {
335: throw new ParFileException("errorXMLConstruct", ex);
336: }
337:
338: Element root = doc.createElement(PARENTRY_TAG);
339: root.setAttribute("name", name);
340: doc.appendChild(root);
341:
342: if (desc != null) {
343: Element delt = doc.createElement(DESCRIPTION_TAG);
344: delt.appendChild(doc.createTextNode(desc));
345: root.appendChild(delt);
346: }
347:
348: if (provider != null) {
349: root.appendChild(cloneElement(doc, provider));
350: }
351:
352: if (channel != null) {
353: root.appendChild(cloneElement(doc, channel));
354: }
355:
356: return doc;
357: }
358:
359: // getProviderNameFromChannel is optional and may return null. Other document descenders
360: // throw exceptions if the required tag is not present.
361:
362: public static String getProviderNameFromChannel(Document doc)
363: throws ParFileException {
364:
365: Element chan = findElement(doc, CHANNEL_TAG, false);
366: if (chan == null) {
367: return null;
368: }
369:
370: Attr a = chan.getAttributeNode("provider");
371: if (a == null) {
372: Object tok[] = { "channel", "provider" };
373: throw new ParFileException("errorXMLAttr", tok);
374: }
375:
376: return a.getValue();
377: }
378:
379: public static String getProviderName(Document doc)
380: throws ParFileException {
381:
382: Element p = findElement(doc, PROVIDER_TAG, true);
383: Attr a = p.getAttributeNode("name");
384: if (a == null) {
385: Object tok[] = { "provider", "name" };
386: throw new ParFileException("errorXMLAttr", tok);
387: }
388:
389: return a.getValue();
390: }
391:
392: public static String getChannelName(Document doc)
393: throws ParFileException {
394:
395: Element chan = findElement(doc, CHANNEL_TAG, true);
396: Attr a = chan.getAttributeNode("name");
397: if (a == null) {
398: Object tok[] = { "channel", "name" };
399: throw new ParFileException("errorXMLAttr", tok);
400: }
401:
402: return a.getValue();
403: }
404:
405: public static String getProviderClass(Document doc)
406: throws ParFileException {
407:
408: Element p = findElement(doc, PROVIDER_TAG, true);
409: Attr a = p.getAttributeNode("class");
410: if (a == null) {
411: Object tok[] = { "provider", "class" };
412: throw new ParFileException("errorXMLAttr", tok);
413: }
414:
415: return a.getValue();
416: }
417:
418: public static int getProviderVersion(Document doc)
419: throws ParFileException {
420:
421: Element p = findElement(doc, PROVIDER_TAG, true);
422: Attr a = p.getAttributeNode("version");
423: if (a == null) {
424: Object tok[] = { "provider", "version" };
425: throw new ParFileException("errorXMLAttr", tok);
426: }
427:
428: int version = -1;
429: String versionStr = a.getValue();
430: try {
431: version = Integer.parseInt(versionStr);
432: } catch (NumberFormatException nfe) {
433: throw new ParFileException("errorXMLProviderVersion", nfe);
434: }
435:
436: return version;
437: }
438:
439: public static Element getProviderProperties(Document doc)
440: throws ParFileException {
441: return findProperties(findElement(doc, PROVIDER_TAG, true));
442: }
443:
444: public static Element getChannelProperties(Document doc)
445: throws ParFileException {
446: return findProperties(findElement(doc, CHANNEL_TAG, true));
447: }
448:
449: public static void replaceProps(Element elt, Element props)
450: throws ParFileException {
451:
452: NodeList kids = elt.getChildNodes();
453: for (int i = 0; i < kids.getLength(); ++i) {
454: Node child = kids.item(i);
455: if (child instanceof Element
456: && child.getNodeName().equals(PROPERTIES_TAG)) {
457: elt.removeChild(child);
458: break;
459: }
460: }
461:
462: elt.appendChild(cloneElement(elt.getOwnerDocument(), props));
463: }
464:
465: public static void setLocale(java.util.Locale locale) {
466: // load resource bundle based on locale
467: m_RB = PropertyResourceBundle.getBundle(RESOURCE_BASE, locale);
468: }
469:
470: /**
471: * given a string representation of the locale (i.e. en_US)
472: * create a Locale obj.
473: */
474: public static Locale getLocale(String stringformat) {
475:
476: if (stringformat == null)
477: return Locale.getDefault();
478: StringTokenizer tk = new StringTokenizer(stringformat, "_");
479: String lang = "";
480: String country = "";
481: String variant = "";
482: if (tk.hasMoreTokens())
483: lang = tk.nextToken();
484: if (tk.hasMoreTokens())
485: country = tk.nextToken();
486: if (tk.hasMoreTokens())
487: variant = tk.nextToken();
488: return new java.util.Locale(lang, country, variant);
489:
490: }
491:
492: public static String getLocalizedString(String key) {
493: try {
494: return m_RB.getString(key);
495: } catch (MissingResourceException mrex) {
496: return "Missing PAR resource string: " + key;
497: }
498: }
499:
500: public static String getLocalizedString(String key, Object[] objs) {
501: try {
502: if (objs != null && objs.length > 0) {
503: MessageFormat mf = new MessageFormat("");
504: mf.setLocale(m_RB.getLocale());
505: mf.applyPattern(m_RB.getString(key));
506: return mf.format(objs);
507: } else {
508: return m_RB.getString(key);
509: }
510: } catch (MissingResourceException mrex) {
511: return "Missing PAR resource string: " + key;
512: }
513: }
514:
515: private static Element findElement(Document doc, String tag,
516: boolean required) throws ParFileException {
517:
518: Element elt = getDPDocElement(doc);
519:
520: NodeList kids = elt.getChildNodes();
521: for (int i = 0; i < kids.getLength(); ++i) {
522: Node child = kids.item(i);
523: if (child instanceof Element
524: && child.getNodeName().equals(tag)) {
525: return (Element) child;
526: }
527: }
528:
529: if (required) {
530: Object tok[] = { tag };
531: throw new ParFileException("errorXMLMissing", tok);
532: }
533:
534: return null;
535: }
536:
537: private static Element cloneElement(Document doc, Element elt)
538: throws ParFileException {
539: Element copy = doc.createElement(elt.getNodeName());
540:
541: NamedNodeMap attrs = elt.getAttributes();
542: if (attrs != null) {
543: for (int i = 0; i < attrs.getLength(); ++i) {
544: Node n = attrs.item(i);
545: if (n instanceof Attr) {
546: copy
547: .setAttribute(n.getNodeName(), n
548: .getNodeValue());
549: }
550: }
551: }
552:
553: NodeList kids = elt.getChildNodes();
554: for (int j = 0; j < kids.getLength(); j++) {
555: Node n = kids.item(j);
556: if (n instanceof Element) {
557: copy.appendChild(cloneElement(doc, (Element) n));
558: }
559: }
560:
561: return copy;
562: }
563:
564: private static Element findProperties(Element elt)
565: throws ParFileException {
566:
567: NodeList kids = elt.getChildNodes();
568: for (int i = 0; i < kids.getLength(); ++i) {
569: Node child = kids.item(i);
570: if (child instanceof Element
571: && child.getNodeName().equals(PROPERTIES_TAG)) {
572: return (Element) child;
573: }
574: }
575:
576: throw new ParFileException("errorXMLMissingProperties");
577: }
578:
579: private static Element getDPDocElement(Document doc)
580: throws ParFileException {
581: Element e = doc.getDocumentElement();
582:
583: if (e == null) {
584: throw new ParFileException("errorXMLNoRoot");
585: }
586:
587: if (!e.getNodeName().equals(PARENTRY_TAG)) {
588: throw new ParFileException("errorXMLNoRoot");
589: }
590:
591: return e;
592: }
593:
594: public static final String RESOURCE_BASE = "desktopPAR";
595:
596: public static ResourceBundle m_RB = PropertyResourceBundle
597: .getBundle(RESOURCE_BASE, Locale.getDefault());
598: public static Logger m_Logger = null;
599: }
|