001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.vishnu.client;
028:
029: import org.cougaar.planning.ldm.measure.Latitude;
030: import org.cougaar.planning.ldm.measure.Longitude;
031: import org.cougaar.planning.ldm.plan.Schedule;
032: import org.cougaar.planning.ldm.plan.RoleSchedule;
033: import org.cougaar.planning.ldm.plan.ScheduleElement;
034:
035: import org.cougaar.core.util.PropertyNameValue;
036: import org.cougaar.util.TimeSpan;
037: import org.cougaar.core.util.UID;
038: import org.cougaar.core.util.UniqueObject;
039:
040: import java.util.*;
041: import java.text.SimpleDateFormat;
042: import java.lang.NumberFormatException;
043: import org.apache.xerces.dom.DocumentImpl;
044:
045: import org.w3c.dom.Document;
046: import org.w3c.dom.Element;
047: import org.w3c.dom.NodeList;
048:
049: import org.cougaar.util.log.Logger;
050:
051: import org.cougaar.lib.vishnu.client.XMLProcessor.ObjectDescrip;
052:
053: /**
054: * Create XML document in the Vishnu Data format, directly from ALP objects.
055: * <p>
056: * Create and return xml for first class log plan objects.
057: * <p>
058: * Element name is extracted from object class, by taking the
059: * last field of the object class, and dropping a trailing "Impl",
060: * if it exists.
061: */
062:
063: public class DataXMLize extends FormatXMLize {
064: protected Class roleScheduleImplClass;
065: protected Class uniqueObjectClass;
066: protected Map nameToDescrip;
067: protected String resourceName;
068: protected Map globalToNode = new HashMap(); // global object -> DOM node mapping
069: protected Set globalsToSend = new HashSet(); // globals to send with this batch of objects
070: protected Map globalToName = new HashMap(); // global object -> global name mapping
071: protected Map classToInstances = new HashMap();
072:
073: public DataXMLize(Logger logger) {
074: super (logger);
075: try {
076: roleScheduleImplClass = Class
077: .forName("org.cougaar.planning.ldm.plan.RoleScheduleImpl");
078: uniqueObjectClass = Class
079: .forName("org.cougaar.core.util.UniqueObject");
080: } catch (ClassNotFoundException cnfe) {
081: }
082: }
083:
084: public void setNameToDescrip(Map nameToDescrip) {
085: this .nameToDescrip = nameToDescrip;
086: }
087:
088: public void setResourceName(String resourceName) {
089: this .resourceName = resourceName;
090: }
091:
092: int numAddNodes = 0;
093: protected boolean printedDataWarning = false;
094:
095: /**
096: * <b>Recursively</b> introspect and add nodes to the XML document.
097: * <p>
098: * Keeps a Set of objects (as these can be circular) and stops
099: * when it tries to introspect over an object a second time.
100: * <p>
101: * Also keeps a depth counter, decrements for each call to addNodes,
102: * and stops when the counter is zero. Use Integer.MAX_VALUE to
103: * indicate an unlimited search.
104: */
105:
106: Map unique = new HashMap();
107:
108: protected void addNodes(Document doc, Object obj,
109: Element parentElement, int searchDepth,
110: Collection createdNodes) {
111: if (obj == null) {
112: return;
113: }
114:
115: if (ignoreClass(obj.getClass())) {
116: if (logger.isDebugEnabled())
117: logger.debug("----> ignored " + obj.getClass());
118: return;
119: }
120:
121: if (logger.isDebugEnabled()) {
122: if (unique.containsKey(obj))
123: unique.put(obj, new Integer(((Integer) unique.get(obj))
124: .intValue() + 1));
125: else
126: unique.put(obj, new Integer(1));
127: }
128:
129: //debug ("DataXMLize.addNodes - Search depth " + searchDepth);
130: if (logger.isDebugEnabled() && ((numAddNodes++ % 100) == 0))
131: logger.debug("addNodes called " + numAddNodes + " times");
132:
133: String parentType = parentElement.getAttribute("type");
134: if (logger.isDebugEnabled())
135: logger.debug("parentType - " + parentType);
136: ObjectDescrip od = (ObjectDescrip) nameToDescrip.get(parentType
137: .toLowerCase());
138: if (od == null && !printedDataWarning
139: && !parentType.toLowerCase().startsWith("string")) {
140: printWarning(parentType);
141: printedDataWarning = true;
142: }
143:
144: if (searchDepth <= 0) {
145: generateElementReachedMaxDepth(doc, parentElement, obj, od);
146: return;
147: }
148:
149: Map listProps = new HashMap();
150: List propertyNameValues = getProperties(obj, listProps);
151: // debug ("getProps for parentType - " + parentType + " listProps = " + listProps);
152:
153: if (listProps.isEmpty())
154: noListProcessProperties(propertyNameValues, doc,
155: parentElement, searchDepth, od, createdNodes);
156: else {
157: // add the nodes for the properties and values
158: boolean foundDateAspect = false;
159: PropertyNameValue[] currentLatLong = new PropertyNameValue[2];
160:
161: for (int i = 0; i < propertyNameValues.size();) {
162: PropertyNameValue pnv = (PropertyNameValue) propertyNameValues
163: .get(i);
164: if (checkForLatLong(doc, parentElement, pnv,
165: currentLatLong)) {
166: i++;
167: continue;
168: }
169:
170: foundDateAspect = checkForDateAspect(pnv,
171: foundDateAspect);
172:
173: boolean isFirst = false;
174: Integer numListElems = (Integer) listProps
175: .get(pnv.name);
176: // debug ("for " + pnv.name + " numListElems = " + numListElems);
177:
178: boolean isList = (numListElems != null);
179: if (isList) {
180: //debug ("found list for " + pnv.name + " with " + numListElems + " elems.");
181:
182: isFirst = true;
183: Element field = createField(doc, pnv.name,
184: pnv.value, true, od);
185: parentElement.appendChild(field);
186: Element list = createList(doc);
187: field.appendChild(list);
188: for (int j = 0; j < numListElems.intValue(); j++) {
189: Element value = createValue(doc);
190: list.appendChild(value);
191: pnv = (PropertyNameValue) propertyNameValues
192: .get(i++);
193: generateNonLeaf(doc, value, pnv.name,
194: pnv.value, searchDepth, isList,
195: isFirst, od, createdNodes);
196: if (value.getFirstChild() != null) {
197: Element objectNode = (Element) value
198: .getFirstChild().getFirstChild();
199: value.removeChild(value.getFirstChild());
200: if (objectNode != null)
201: value.appendChild(objectNode);
202: }
203: isFirst = false;
204: }
205: } else {
206: generateElem(doc, parentElement, pnv.name,
207: pnv.value, searchDepth, isList, isFirst,
208: od, createdNodes);
209: i++;
210: }
211: }
212: }
213:
214: }
215:
216: protected void printWarning(String parentType) {
217: logger
218: .debug("\n-----------------------------------------------\n"
219: + "DataXMLize.addNodes - descrip was null for "
220: + parentType.toLowerCase()
221: + "."
222: + "\nThis means that the default code in VishnuPlugin.getTemplateTasks, which only\n"
223: + "looks at the first few tasks to define the problem format should be subclassed, or the\n"
224: + "firstTemplateTasks parameter increased to close to the number of tasks expected.\n"
225: + "(It's OK if it's larger than the number of tasks.)\n"
226: + "Basically what this means is that many different kinds of tasks are being sent to Vishnu\n"
227: + "and when the task format is being created, more tasks have to be sampled to generate a\n"
228: + "a format that represents all these different tasks. For more info, call Gordon Vidaver\n"
229: + "at BBN - 617 873 3558 or email gvidaver@bbn.com.\n"
230: + "-----------------------------------------------");
231: }
232:
233: protected void noListProcessProperties(List propertyNameValues,
234: Document doc, Element parentElement, int searchDepth,
235: ObjectDescrip od, Collection createdNodes) {
236: boolean foundDateAspect = false;
237: PropertyNameValue[] currentLatLong = new PropertyNameValue[2];
238: for (int i = 0; i < propertyNameValues.size();) {
239: PropertyNameValue pnv = (PropertyNameValue) propertyNameValues
240: .get(i);
241: if (checkForLatLong(doc, parentElement, pnv, currentLatLong)) {
242: i++;
243: continue;
244: }
245:
246: foundDateAspect = checkForDateAspect(pnv, foundDateAspect);
247:
248: generateElem(doc, parentElement, pnv.name, pnv.value,
249: searchDepth, false, false, od, createdNodes);
250: i++;
251: }
252: }
253:
254: protected void generateElem(Document doc, Element parentElement,
255: String propertyName, Object propertyValue, int searchDepth,
256: boolean isList, boolean isFirst, ObjectDescrip od,
257: Collection createdNodes) {
258: // check if this should be a leaf
259: boolean isLeaf = !isList
260: && (stringClass.isInstance(propertyValue) || classClass
261: .isInstance(propertyValue));
262:
263: if (isLeaf)
264: generateLeaf(doc, parentElement, propertyName,
265: propertyValue, od);
266: else {
267: generateNonLeaf(doc, parentElement, propertyName,
268: propertyValue, searchDepth, isList, isFirst, od,
269: createdNodes);
270: }
271: }
272:
273: /** subclass to generate different tag */
274: protected Element createRootNode(Document doc, String tag,
275: boolean isTask, boolean isResource, Object obj,
276: String resourceClassName) {
277: return createObject(doc, tag, obj, isTask, isResource);
278: }
279:
280: /**
281: * Already seen this object or reached maximum depth.
282: * Write the UID if possible, otherwise write the "toString".
283: */
284: protected void generateElementReachedMaxDepth(Document doc,
285: Element parentElement, Object obj, ObjectDescrip od) {
286: if (logger.isDebugEnabled())
287: logger.debug("Object traversed already/max depth: "
288: + obj.getClass().toString() + " " + obj);
289: if (isUniqueObject(obj)) {
290: Element item = createField(doc, "UID", "string(40)", false,
291: od);
292: if (logger.isDebugEnabled())
293: logger.debug("maxDepth - " + "UID" + " - "
294: + "string(40)");
295:
296: parentElement.appendChild(item);
297: } else {
298: parentElement.appendChild(createField(doc, obj.toString(),
299: obj, false, od));
300: if (logger.isDebugEnabled())
301: logger.debug("maxDepth - " + obj);
302: }
303: }
304:
305: protected boolean checkForLatLong(Document doc, Element parentElem,
306: PropertyNameValue pnv, PropertyNameValue[] currentLatLong) {
307: boolean skip = false;
308:
309: if (pnv.name.charAt(0) == 'l') {
310: if (pnv.name.equals("latitude")) {
311: currentLatLong[0] = pnv;
312: skip = true;
313: } else if (pnv.name.equals("longitude")) {
314: currentLatLong[1] = pnv;
315: skip = true;
316: }
317: }
318:
319: if (currentLatLong[0] != null && currentLatLong[1] != null) {
320: Element latlong = createLatlong(doc,
321: ""
322: + ((Latitude) currentLatLong[0].value)
323: .getDegrees(), ""
324: + ((Longitude) currentLatLong[1].value)
325: .getDegrees());
326: parentElem.appendChild(latlong);
327: }
328: return skip;
329: }
330:
331: protected void generateLeaf(Document doc, Element parentElement,
332: String propertyName, Object propertyValue, ObjectDescrip od) {
333: Element item = createField(doc, propertyName, propertyValue,
334: false, od);
335: parentElement.appendChild(item);
336:
337: if (logger.isDebugEnabled())
338: logger.debug("isLeaf - field " + propertyName + " - "
339: + propertyValue + " to parent "
340: + parentElement.getTagName());
341: }
342:
343: /**
344: * Create a <FIELD> with an <OBJECT> underneath it.
345: *
346: * The object that is the OBJECT is propertyValue.
347: *
348: * Keeps track of global objects, and sets the field values to properly reference them.
349: *
350: * Ignores longitude objects since they are handled with latitudes.
351: * Also skips creating an object tag for dates, latitudes, longitudes, and uids.
352: * Object tags are created for non globals and for the first instance of a global.
353: * Role Schedules get interval tags added to them.
354: *
355: * Globals get entered into two maps : one mapping object to DOM node, and one
356: * mapping object to the global's name. Also, a class to instance map maps
357: * types to instances, so we can rename the globals properly. I.e. the fifth
358: * TypeIdentificationPG becomes TypeIdentificationPG5.
359: *
360: * Subsequent encounters of the same object generate a value tag with that global's
361: * name.
362: *
363: * Recurses on propertyValue using addNodes.
364: *
365: * @see #addNodes
366: * @param doc the document to add nodes to
367: * @param parentElement append new nodes here
368: * @param propertyName classname of the propertyValue object
369: * @param propertyValue object that we're translating into XML
370: * @param searchDepth how deep in the tree we can still go
371: * @param isList is the object part of a list - IGNORED (used in Format)
372: * @param isFirst is the object the first elem in a list - IGNORED (used in Format)
373: * @param od object description - structure of object created in format xmlize,
374: * used in field renaming
375: * @param od createdNodes - IGNORED
376: */
377: protected void generateNonLeaf(Document doc, Element parentElement,
378: String propertyName, Object propertyValue, int searchDepth,
379: boolean isList, boolean isFirst, ObjectDescrip od,
380: Collection createdNodes) {
381: // this removes the class name following the $ for Locked classes
382: int index = propertyName.indexOf('$');
383: if (index > 0) {
384: propertyName = propertyName.substring(0, index);
385: }
386:
387: Element fieldNode = null;
388: if (!ignoreObject(propertyValue)) {
389: fieldNode = createField(doc, propertyName, propertyValue,
390: true, od);
391: parentElement.appendChild(fieldNode);
392: }
393:
394: if (logger.isDebugEnabled())
395: logger.debug("DataXMLize.nonLeaf - " + propertyName + " - "
396: + propertyValue);
397: if (!skipObject(propertyValue)) {
398: boolean isGlobal = isGlobal(propertyValue);
399: boolean seenGlobalBefore = false;
400: boolean removedObjectNode = false;
401: if (isGlobal) {
402: seenGlobalBefore = globalToNode
403: .containsKey(propertyValue);
404: if (logger.isDebugEnabled())
405: logger.debug("DataXMLize.nonLeaf - "
406: + propertyValue + " is global");
407: if (logger.isDebugEnabled() && seenGlobalBefore)
408: logger
409: .debug("DataXMLize.nonLeaf - "
410: + propertyValue
411: + " saw before. Skipping.");
412: }
413: Element objectNode = null;
414: if (!isGlobal || !seenGlobalBefore) {
415: objectNode = createObject(doc, propertyName,
416: propertyValue, false, false);
417: fieldNode.appendChild(objectNode);
418: if (logger.isDebugEnabled())
419: logger
420: .debug("DataXMLize.nonLeaf - adding object to field.");
421: removedObjectNode = false;
422: addNodes(doc, propertyValue, objectNode,
423: (searchDepth - 1), createdNodes);
424:
425: // check to see if it's a role schedule, in which case, we need to append plan elem info
426: // yes, this is a hack -- we remove the needless roleSchedule field and the scheduleElements
427: // these are useless
428: if (roleScheduleImplClass.isInstance(propertyValue)) {
429: if (logger.isDebugEnabled())
430: logger
431: .debug("DataXMLize.nonLeaf - found role schedule");
432: removeChildNamed(objectNode, "roleSchedule");
433: removeChildNamed(objectNode, "scheduleElements");
434: removeChildNamed(objectNode, "availableSchedule");
435: objectNode.appendChild(createIntervalNamed(
436: "scheduleElements", doc,
437: (Schedule) propertyValue));
438: objectNode.appendChild(createIntervalNamed(
439: "availableSchedule", doc,
440: ((RoleSchedule) propertyValue)
441: .getAvailableSchedule()));
442: }
443: // if there are no fields in the object
444: if (objectNode.getChildNodes().getLength() == 0) {
445: fieldNode.removeChild(objectNode);
446: parentElement.removeChild(fieldNode);
447: if (logger.isDebugEnabled())
448: logger
449: .debug("DataXMLize : nonLeaf - REMOVING - "
450: + propertyName
451: + " - "
452: + propertyValue);
453: removedObjectNode = true;
454: }
455: }
456:
457: if (isGlobal) {
458: if (!removedObjectNode && !seenGlobalBefore) {
459: fieldNode.removeChild(objectNode);
460:
461: if (logger.isDebugEnabled())
462: logger.debug("DataXMLize.nonLeaf - mapping "
463: + propertyValue.getClass() + " to "
464: + objectNode);
465:
466: // store the node for later
467: globalToNode.put(propertyValue, objectNode);
468: globalsToSend.add(propertyValue);
469:
470: // get the type
471: String typeName = getTypeName(propertyValue, true);
472: List instances = (List) classToInstances
473: .get(typeName);
474: if (instances == null)
475: classToInstances.put(typeName,
476: instances = new ArrayList());
477: if (instances.contains(propertyValue))
478: logger
479: .debug("DataXMLize.nonLeaf - Huh? found second occurence of instance?");
480: else
481: instances.add(propertyValue);
482:
483: String name = (instances.size() > 1) ? typeName
484: + instances.indexOf(propertyValue)
485: : typeName;
486: if (logger.isDebugEnabled())
487: logger.debug("DataXMLize.nonLeaf - "
488: + propertyValue.getClass() + " "
489: + instances.size() + " instances, "
490: + " name " + name);
491:
492: // store the object's global name
493: globalToName.put(propertyValue, name);
494: fieldNode.setAttribute("value", name);
495: } else
496: fieldNode.setAttribute("value",
497: (String) globalToName.get(propertyValue));
498: }
499: }
500: }
501:
502: /**
503: * <pre>
504: * Converts a collection of ALP objects into a Vishnu Data DOM document
505: * Format is :
506: * <PROBLEM>
507: * <DATA>
508: * <WINDOW starttime=xxx endtime=yyy>
509: * <NEWOBJECTS>
510: * <OBJECT>
511: * </OBJECT>
512: * ...
513: *
514: * Where each <OBJECT> tag corresponds to each item.
515: * </pre>
516: * @param items collection of items to translate
517: * @return result document
518: */
519: public synchronized Document createDoc(Collection items,
520: Collection changedAssets, String assetClassName) {
521: Document doc = new DocumentImpl();
522: Element root = doc.createElement("PROBLEM");
523: doc.appendChild(root);
524: Element df = doc.createElement("DATA");
525: root.appendChild(df);
526: Element window = doc.createElement("WINDOW");
527: window.setAttribute("starttime", "2000-01-01 00:00:00");
528: window.setAttribute("endtime", "2002-01-01 00:00:00");
529: df.appendChild(window);
530:
531: Element newobjects = doc.createElement("NEWOBJECTS");
532: df.appendChild(newobjects);
533:
534: Element changedobjects = doc.createElement("CHANGEDOBJECTS");
535: df.appendChild(changedobjects);
536:
537: Element element = null;
538: Date start = new Date();
539: for (Iterator iter = items.iterator(); iter.hasNext();) {
540: Object obj = iter.next();
541: boolean changed = changedAssets.contains(obj);
542: Collection nodes = getPlanObjectXMLNodes(obj, doc,
543: RECURSION_DEPTH, assetClassName);
544: Element placeToAdd = (changed) ? changedobjects
545: : newobjects;
546: for (Iterator iter2 = nodes.iterator(); iter2.hasNext();)
547: placeToAdd.appendChild((Element) iter2.next());
548: }
549: if (logger.isDebugEnabled())
550: reportTime("DataXMLize.createDoc - did addNodes in ", start);
551:
552: if (logger.isDebugEnabled()) {
553: int i = 0;
554: for (Iterator iter = unique.keySet().iterator(); iter
555: .hasNext();) {
556: Object obj = iter.next();
557: logger
558: .debug(""
559: + i++
560: + " - "
561: + obj.getClass()
562: + " - "
563: + unique.get(obj)
564: + " - "
565: + ((obj instanceof org.cougaar.planning.ldm.asset.PropertyGroup) ? " PG "
566: : ""));
567: }
568: }
569:
570: // only send those globals not sent since last set
571: for (Iterator iter = globalsToSend.iterator(); iter.hasNext();) {
572: Object global = iter.next();
573: Element globalElem = doc.createElement("GLOBAL");
574: String globalName = (String) globalToName.get(global);
575: if (logger.isDebugEnabled())
576: logger.debug("DataXMLize - global " + global.getClass()
577: + " name " + globalName);
578:
579: globalElem.setAttribute("name", globalName);
580: Element node = (Element) globalToNode.get(global);
581: if (node == null)
582: logger.debug("no node for global?");
583:
584: globalElem.appendChild(node);
585: newobjects.appendChild(globalElem);
586: }
587:
588: globalsToSend.clear();
589:
590: return doc;
591: }
592:
593: protected Element createObject(Document doc, String name,
594: Object theObj, boolean isTask, boolean isResource) {
595: Element elem = doc.createElement("OBJECT");
596: String cn;
597:
598: if (isResource) {
599: cn = resourceName;
600:
601: if (logger.isDebugEnabled())
602: logger
603: .debug("DataXMLize.createObject - Using resource name "
604: + resourceName);
605: } else {
606: cn = theObj.getClass().toString();
607: cn = cn.substring(cn.lastIndexOf('.') + 1);
608: cn = cn.substring(cn.lastIndexOf('$') + 1);
609: }
610:
611: elem.setAttribute("type", (isTask) ? name : cn);
612:
613: return elem;
614: }
615:
616: private final SimpleDateFormat format = new SimpleDateFormat(
617: "yyyy-MM-dd HH:mm:ss");
618:
619: /**
620: * <pre>
621: *
622: * Creates an element, field, of the form:
623: * <FIELD name=xxx> OR
624: * <FIELD name=xxx value=yyy>
625: * </pre><p>
626: * Uses the type of <code>theObj</code> to format the value properly. <p>
627: *
628: * Renames the field with the <code>od</code> ObjectDescrip. This <br>
629: * object holds the mapping of oldname to newname. It is created in the <br>
630: * VishnuPlugin. The general problem that some fields can have multiple <br>
631: * types of objects, and each needs a distinct name.
632: *
633: * @param doc needed to create new elements
634: * @param name the name of the field
635: * @param theObj the value for the field
636: * @param hasObject is there an object inside of this field
637: * @param od ObjectDescrip, used to figure out how to rename the field
638: * @return the field element that is created
639: */
640: protected Element createField(Document doc, String name,
641: Object theObj, boolean hasObject, ObjectDescrip od) {
642: Element elem = doc.createElement("FIELD");
643: Set nameTypePairs = null;
644:
645: if (od == null)
646: elem.setAttribute("name", name);
647: else
648: nameTypePairs = od.getNameTypePairs(name);
649:
650: if (nameTypePairs != null) {
651: String typeName = getTypeName(theObj, hasObject);
652: if (logger.isDebugEnabled())
653: logger.debug("type " + typeName + " hasObject = "
654: + hasObject);
655: for (Iterator iter = nameTypePairs.iterator(); iter
656: .hasNext();) {
657: String[] nameTypePair = (String[]) iter.next();
658: if (typeName.equals(nameTypePair[1])
659: || ((typeName.charAt(0) == 's') && (typeName
660: .startsWith("string(") && nameTypePair[1]
661: .startsWith("string(")))) {
662: name = nameTypePair[0];
663: if (logger.isDebugEnabled())
664: logger.debug("\tFOUND MATCH! new name " + name);
665: break;
666: }
667: }
668: }
669: elem.setAttribute("name", name);
670:
671: if (dateClass.isInstance(theObj)) {
672: try {
673: String dateAsString = format.format((Date) theObj);
674: elem.setAttribute("value", dateAsString);
675: } catch (NumberFormatException nfe) {
676: }
677: } else if (uniqueObjectClass.isInstance(theObj)) {
678: UniqueObject unique = (UniqueObject) theObj;
679: UID uniqueUID = unique.getUID();
680: String UIDString = "ERROR_novalue";
681: try {
682: UIDString = uniqueUID.toString();
683: } catch (NullPointerException npe) {
684: logger.debug("DataXMLize - null pointer on " + unique
685: + " - no UID set?");
686: }
687:
688: if (UIDString.indexOf('<') != -1)
689: UIDString = UIDString.replace('<', '_');
690: if (UIDString.indexOf('>') != -1)
691: UIDString = UIDString.replace('>', '_');
692:
693: elem.setAttribute("value", UIDString);
694: } else if (UIDClass.isInstance(theObj)) {
695: elem.setAttribute("value", ((UID) theObj).toString());
696: } else if (isPrimitiveFloat(theObj.getClass()))
697: elem
698: .setAttribute("value",
699: getValueOfPrimitiveFloat(theObj));
700: else if (!hasObject) {
701: String valueString = theObj.toString();
702: if (valueString.indexOf('\"') != -1) {
703: valueString = valueString.replace('\"', '\'');
704: }
705: if (valueString.indexOf('&') != -1) {
706: valueString = valueString.replace('&', '+');
707: }
708: if (valueString.indexOf('<') != -1)
709: valueString = valueString.replace('<', '_');
710: if (valueString.indexOf('>') != -1)
711: valueString = valueString.replace('>', '_');
712:
713: elem.setAttribute("value", valueString);
714: }
715:
716: return elem;
717: }
718:
719: protected String getTypeName(Object theObj, boolean hasObject) {
720: if (dateClass.isInstance(theObj))
721: return dateString;
722: if (hasObject) {
723: String cn = theObj.getClass().toString();
724: cn = cn.substring(cn.lastIndexOf('.') + 1);
725: cn = cn.substring(cn.lastIndexOf('$') + 1);
726: return cn;
727: } else
728: return getTypeFor(theObj);
729: }
730:
731: protected Element createLatlong(Document doc, String latitude,
732: String longitude) {
733: Element elem = doc.createElement("FIELD");
734: elem.setAttribute("name", "latitude");
735: Element obj = doc.createElement("OBJECT");
736: obj.setAttribute("type", "latlong");
737: elem.appendChild(obj);
738: Element field = doc.createElement("FIELD");
739: field.setAttribute("name", "latitude");
740: field.setAttribute("value", latitude);
741: obj.appendChild(field);
742: field = doc.createElement("FIELD");
743: field.setAttribute("name", "longitude");
744: field.setAttribute("value", longitude);
745: obj.appendChild(field);
746:
747: return elem;
748: }
749:
750: /**
751: * need to have special code to add plan element intervals to role schedule data, since
752: * bean properties don't include them
753: */
754: protected Element createIntervalNamed(String name, Document doc,
755: Schedule rs) {
756: Element fieldElem = doc.createElement("FIELD");
757: fieldElem.setAttribute("name", name);
758: Element listTag = createList(doc);
759: fieldElem.appendChild(listTag);
760:
761: // Must get a copy first, even though I know there will be no concurrent modification
762: try {
763: List copy = new ArrayList(rs);
764:
765: for (Iterator iter = copy.iterator(); iter.hasNext();) {
766: TimeSpan elem = (TimeSpan) iter.next();
767: Element value = createValue(doc);
768: listTag.appendChild(value);
769: value.appendChild(createLittleInterval(doc, new Date(
770: elem.getStartTime()), new Date(elem
771: .getEndTime())));
772: }
773: } catch (Exception e) {
774: }
775: return fieldElem;
776: }
777:
778: protected Element createLittleInterval(Document doc, Date start,
779: Date end) {
780: Element obj = doc.createElement("OBJECT");
781: obj.setAttribute("type", "interval");
782:
783: Element field = doc.createElement("FIELD");
784: field.setAttribute("name", "start");
785: field.setAttribute("value", format.format(start));
786: obj.appendChild(field);
787:
788: field = doc.createElement("FIELD");
789: field.setAttribute("name", "end");
790: field.setAttribute("value", format.format(end));
791: obj.appendChild(field);
792:
793: return obj;
794: }
795:
796: protected Element createList(Document doc) {
797: Element elem = doc.createElement("LIST");
798: return elem;
799: }
800:
801: protected Element createValue(Document doc) {
802: Element elem = doc.createElement("VALUE");
803: return elem;
804: }
805: }
|