0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 2001-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026: package org.cougaar.lib.vishnu.client;
0027:
0028: import java.io.IOException;
0029: import java.io.FileNotFoundException;
0030: import java.text.SimpleDateFormat;
0031:
0032: import java.util.Collection;
0033: import java.util.Map;
0034: import java.util.Enumeration;
0035: import java.util.Iterator;
0036: import java.util.List;
0037: import java.util.Set;
0038: import java.util.ArrayList;
0039: import java.util.Comparator;
0040: import java.util.Date;
0041: import java.util.HashMap;
0042: import java.util.HashSet;
0043: import java.util.Iterator;
0044: import java.util.List;
0045: import java.util.Set;
0046: import java.util.Stack;
0047: import java.util.TreeSet;
0048:
0049: import org.w3c.dom.Document;
0050: import org.w3c.dom.Node;
0051: import org.w3c.dom.Element;
0052: import org.w3c.dom.NodeList;
0053: import org.apache.xerces.dom.DocumentImpl;
0054:
0055: import org.cougaar.lib.vishnu.client.VishnuComm;
0056: import org.cougaar.lib.vishnu.client.VishnuDomUtil;
0057:
0058: import org.cougaar.lib.param.ParamMap;
0059: import org.cougaar.util.ConfigFinder;
0060: import org.cougaar.planning.ldm.plan.Task;
0061: import org.cougaar.util.log.Logger;
0062:
0063: /**
0064: * Handles XML interaction...
0065: *
0066: * <!--
0067: * (When printed, any longer line will wrap...)
0068: *345678901234567890123456789012345678901234567890123456789012345678901234567890
0069: * 1 2 3 4 5 6 7 8
0070: * -->
0071: */
0072: public class XMLProcessor {
0073: private final SimpleDateFormat format = new SimpleDateFormat(
0074: "yyyy-MM-dd HH:mm:ss");
0075: private static String SEPARATOR = "_";
0076:
0077: public XMLProcessor(ParamMap myParamTable, String name,
0078: String clusterName, VishnuDomUtil domUtil, VishnuComm comm,
0079: ConfigFinder configFinder, Logger logger,
0080: Logger dataXMLizeLogger, Logger formatXMLizeLogger) {
0081: this .myParamTable = myParamTable;
0082:
0083: localSetup();
0084: this .name = name;
0085: this .clusterName = clusterName;
0086: this .configFinder = configFinder;
0087: this .domUtil = domUtil;
0088: this .comm = comm;
0089: this .logger = logger;
0090: this .dataXMLizeLogger = dataXMLizeLogger;
0091: this .formatXMLizeLogger = formatXMLizeLogger;
0092: }
0093:
0094: protected ParamMap getMyParams() {
0095: return myParamTable;
0096: }
0097:
0098: protected String getName() {
0099: return name;
0100: }
0101:
0102: protected String getClusterName() {
0103: return clusterName;
0104: }
0105:
0106: /**
0107: * Here all the various runtime parameters get set. See documentation for details.
0108: */
0109: public void localSetup() {
0110: try {
0111: showDataXML = getMyParams().getBooleanParam("showDataXML");
0112: } catch (Exception e) {
0113: showDataXML = false;
0114: }
0115:
0116: try {
0117: debugFormatXMLizer = getMyParams().getBooleanParam(
0118: "debugFormatXMLizer");
0119: } catch (Exception e) {
0120: debugFormatXMLizer = false;
0121: }
0122:
0123: try {
0124: debugDataXMLizer = getMyParams().getBooleanParam(
0125: "debugDataXMLizer");
0126: } catch (Exception e) {
0127: debugDataXMLizer = false;
0128: }
0129:
0130: // controls the time period that Vishnu uses - assumes world starts at this time
0131: // has large effect on scaling of gantt chart displays
0132: try {
0133: vishnuEpochStartTime = getMyParams().getStringParam(
0134: "vishnuEpochStartTime");
0135: } catch (Exception e) {
0136: vishnuEpochStartTime = "2000-01-01 00:00:00";
0137: }
0138:
0139: // controls the time period that Vishnu uses - assumes world ends at this time
0140: // has large effect on scaling of gantt chart displays
0141: try {
0142: vishnuEpochEndTime = getMyParams().getStringParam(
0143: "vishnuEpochEndTime");
0144: } catch (Exception e) {
0145: vishnuEpochEndTime = "2002-01-01 00:00:00";
0146: }
0147: }
0148:
0149: public void createDataXMLizer(Map nameToDescrip,
0150: String assetClassName) {
0151: setDataXMLizer(new DataXMLize(dataXMLizeLogger));
0152: ((DataXMLize) dataXMLizer).setNameToDescrip(nameToDescrip);
0153: ((DataXMLize) dataXMLizer).setResourceName(assetClassName);
0154: }
0155:
0156: protected void setDataXMLizer(XMLizer xmlizer) {
0157: dataXMLizer = xmlizer;
0158: }
0159:
0160: public XMLizer getDataXMLizer() {
0161: if (dataXMLizer == null)
0162: logger
0163: .error("XMLProcessor.getDataXMLizer - ERROR - dataxmlizer not set!");
0164:
0165: return dataXMLizer;
0166: }
0167:
0168: /** uses formatXMLizer to generate XML for Vishnu */
0169: protected Document getFormatDoc(Collection taskAndAssets,
0170: String assetClassName) {
0171: FormatXMLize formatXMLizer = new FormatXMLize(
0172: formatXMLizeLogger);
0173: return formatXMLizer.createDoc(taskAndAssets, null,
0174: assetClassName);
0175: }
0176:
0177: /**
0178: * Uses dataXMLizer to generate XML for Vishnu
0179: *
0180: * Passes nameToDescrip Map to dataXMLizer so can rename fields to be unique.
0181: *
0182: * @param taskAndAssets what to send
0183: * @param nameToDescrip mapping of object type to object description (field names, etc.)
0184: */
0185: protected Document getDataDoc(Collection taskAndAssets,
0186: Collection changedAssets, XMLizer dataXMLizer,
0187: String assetClassName) {
0188: return dataXMLizer.createDoc(taskAndAssets, changedAssets,
0189: assetClassName);
0190: }
0191:
0192: public Document getFormatDocWithoutDuplicates(Collection templates,
0193: String assetClassName, List returnedMap) {
0194: Document problemFormatDoc = getFormatDoc(templates,
0195: assetClassName);
0196:
0197: if (showFormatXML)
0198: logger.debug(domUtil.getDocAsString(problemFormatDoc));
0199:
0200: // must remove duplicate OBJECTFORMATS
0201:
0202: Node root = problemFormatDoc.getDocumentElement();
0203: if (logger.isInfoEnabled())
0204: logger.info(getName() + "- root "
0205: + ((Element) root).getTagName() + " has "
0206: + root.getChildNodes().getLength() + " children");
0207:
0208: NodeList nlist = root.getChildNodes();
0209: Node dataformat = nlist.item(0); // assumes first child is dataformat
0210:
0211: if (logger.isInfoEnabled())
0212: logger.info(getName() + "- dataformat "
0213: + ((Element) dataformat).getTagName() + " has "
0214: + dataformat.getChildNodes().getLength()
0215: + " children");
0216:
0217: Map nameInfo = removeDuplicates(dataformat, problemFormatDoc);
0218:
0219: // label the problem with the name of the problem
0220: ((Element) root).setAttribute("NAME", comm.getProblem());
0221:
0222: if (logger.isInfoEnabled())
0223: logger.info(getName() + ".sendFormat - problem is "
0224: + comm.getProblem());
0225:
0226: returnedMap.add(nameInfo);
0227:
0228: return problemFormatDoc;
0229: }
0230:
0231: /**
0232: * Looks at all the object format nodes in the document
0233: * and removes duplicates (two object formats with the same name and
0234: * same fields).
0235: *
0236: * Object formats that have the same name but with different fields are
0237: * renamed to make them distinct.
0238: *
0239: * addFieldsForDifferentTypes adds fields to refer to the new
0240: * unique names, and setObjectNames renames the object formats.
0241: *
0242: * The returned maps are needed for the object data phase, so we
0243: * can figure out what the unique type should be for a data object
0244: * with an ambiguous type.
0245: *
0246: * @param root - where to start in document
0247: * @param doc - doc to remove the duplicates from
0248: * @return Map [] containing two maps - name to object description
0249: * and name to node
0250: */
0251: protected Map removeDuplicates(Node root, Document doc) {
0252: Set children = new HashSet();
0253:
0254: NodeList nlist = root.getChildNodes();
0255:
0256: Map nameToNodes = new HashMap();
0257: Map nameToDescrip = new HashMap();
0258:
0259: Set potentialDuplicates = new HashSet();
0260:
0261: for (int i = 0; i < nlist.getLength(); i++) {
0262: Node child = nlist.item(i);
0263: String attr = child.getAttributes().getNamedItem("name")
0264: .getNodeValue().toLowerCase();
0265:
0266: boolean duplicate = false;
0267: List nodes = (List) nameToNodes.get(attr);
0268: if (nodes == null)
0269: nameToNodes.put(attr, (nodes = new ArrayList()));
0270: nodes.add(child);
0271:
0272: if (nodes.size() > 1)
0273: potentialDuplicates.add(attr);
0274:
0275: ObjectDescrip descrip = (ObjectDescrip) nameToDescrip
0276: .get(attr);
0277: if (descrip == null) {
0278: if (logger.isDebugEnabled())
0279: logger.debug("creating object descrip for - "
0280: + attr);
0281:
0282: descrip = new ObjectDescrip();
0283: nameToDescrip.put(attr, descrip);
0284: }
0285: descrip.addFields(child);
0286: }
0287:
0288: processObjectFormats(root, nameToNodes, potentialDuplicates,
0289: new DuplicateProcessor());
0290: processObjectFormats(root, nameToNodes, potentialDuplicates,
0291: new MergeProcessor());
0292:
0293: addFieldsForDifferentTypes(root, doc, nameToNodes,
0294: nameToDescrip);
0295:
0296: // possibly unnecessary
0297: processObjectFormats(root, nameToNodes, potentialDuplicates,
0298: new MergeProcessor());
0299: processObjectFormats(root, nameToNodes, potentialDuplicates,
0300: new DuplicateProcessor());
0301:
0302: return nameToDescrip;
0303: }
0304:
0305: /**
0306: * Given a set of potential duplicate types, removes those that are duplicates
0307: * from the set of DOM Node OBJECTFORMATs sent to Vishnu.
0308: *
0309: * Removes duplicate OBJECTFORMATs from <code>root</code>.
0310: *
0311: * If there is only one remaining Node for a type in potentialDuplicates, the type
0312: * is removed from the list of potential duplicates.
0313: *
0314: * First finds those nodes that should be removed and then removes them in a separate
0315: * step.
0316: *
0317: * @param potentialDuplicates set of type names of potential duplicates
0318: * @param nameToNodes list of DOM Nodes for type
0319: * @param root DATAFORMAT tag which is the parent of all OBJECTFORMATs
0320: */
0321: protected void processObjectFormats(Node root, Map nameToNodes,
0322: Set potentialDuplicates, FormatProcessor formatProcessor) {
0323: Set toRemove = new HashSet();
0324: Set dupsToRemove = new HashSet();
0325: for (Iterator iter = potentialDuplicates.iterator(); iter
0326: .hasNext();) {
0327: String type = (String) iter.next();
0328:
0329: if (logger.isDebugEnabled())
0330: logger.debug(getName() + ".pruneObjectFormat - type "
0331: + type);
0332:
0333: List nodesForType = (List) nameToNodes.get(type);
0334: List copyOfNodesForType = new ArrayList(nodesForType);
0335: if (logger.isDebugEnabled())
0336: logger.debug("nodes for type " + nodesForType);
0337:
0338: Set nameToNodeToRemove = new HashSet();
0339: for (Iterator iter2 = copyOfNodesForType.iterator(); iter2
0340: .hasNext();) {
0341: Node objectFormat = (Node) iter2.next();
0342: formatProcessor.examineObjectFormat(objectFormat,
0343: nodesForType, iter2, toRemove);
0344: }
0345: if (nodesForType.size() == 1) {
0346: if (logger.isDebugEnabled())
0347: logger.debug("\tremoving " + type);
0348: dupsToRemove.add(type);
0349: }
0350: }
0351: if (logger.isDebugEnabled())
0352: logger.debug(getName() + ".pruneObjectFormat - removing "
0353: + dupsToRemove + " from " + potentialDuplicates);
0354: potentialDuplicates.removeAll(dupsToRemove);
0355: if (logger.isDebugEnabled())
0356: logger.debug(getName() + ".pruneObjectFormat - "
0357: + potentialDuplicates.size()
0358: + " potential dups remain.");
0359:
0360: for (Iterator iter = toRemove.iterator(); iter.hasNext();)
0361: root.removeChild((Node) iter.next());
0362: }
0363:
0364: class FormatProcessor {
0365: protected void examineObjectFormat(Node objectFormat,
0366: List nodesForType, Iterator iter, Set toRemove) {
0367: };
0368: }
0369:
0370: class MergeProcessor extends FormatProcessor {
0371: protected void examineObjectFormat(Node objectFormat,
0372: List nodesForType, Iterator iter, Set toRemove) {
0373: mergeNode(objectFormat, nodesForType, iter);
0374: }
0375: }
0376:
0377: class DuplicateProcessor extends FormatProcessor {
0378: protected void examineObjectFormat(Node objectFormat,
0379: List nodesForType, Iterator iter, Set toRemove) {
0380: if (duplicateNode(objectFormat, nodesForType)) {
0381: if (logger.isDebugEnabled())
0382: logger.debug("\tfound dup");
0383: toRemove.add(objectFormat);
0384: }
0385: }
0386: }
0387:
0388: /**
0389: * Checks to see if first is an object format that has already been
0390: * seen when iterating over the document.
0391: *
0392: * Duplicates can be subsets -- i.e. have some subset of the fields
0393: * of another object with this name.
0394: *
0395: * NOTE : if <code>first</code> is a duplicate of another of the Nodes in
0396: * <code>nodes</code>, first is removed from the nodes list.
0397: *
0398: * If something is a resource, it should not be seen as a duplicate of
0399: * another object that is not a resource!
0400: *
0401: * @param first - the node itself
0402: * @param nameToNodes - hash that records name -> object format node mappings
0403: * @return true if it's a duplicate of one already seen
0404: */
0405: protected boolean duplicateNode(Node first, List nodes) {
0406: if (nodes.size() == 1)
0407: return false; // if no others to compare against, it's not a duplicate
0408:
0409: NodeList firstChildNodes = first.getChildNodes();
0410:
0411: for (int i = 0; i < nodes.size(); i++) {
0412: Node other = (Node) nodes.get(i);
0413: if (first == other)
0414: continue; // ignore self to tell if duplicate
0415:
0416: NodeList otherChildNodes = other.getChildNodes();
0417:
0418: if (firstChildNodes.getLength() > otherChildNodes
0419: .getLength())
0420: continue; // can't be a subset if more fields
0421:
0422: // create name->type mapping for other node
0423: Map otherFieldToType = new HashMap();
0424:
0425: for (int k = 0; k < otherChildNodes.getLength(); k++) {
0426: String field = otherChildNodes.item(k).getAttributes()
0427: .getNamedItem("name").getNodeValue();
0428: String type = otherChildNodes.item(k).getAttributes()
0429: .getNamedItem("datatype").getNodeValue();
0430: otherFieldToType.put(field, type);
0431: }
0432:
0433: boolean allFound = true;
0434: // go through fields of node we're checking
0435: for (int k = 0; k < firstChildNodes.getLength(); k++) {
0436: String firstChildName = firstChildNodes.item(k)
0437: .getAttributes().getNamedItem("name")
0438: .getNodeValue();
0439: String otherType = (String) otherFieldToType
0440: .get(firstChildName);
0441:
0442: if (otherType == null) {
0443: allFound = false;
0444: break;
0445: } else {
0446: String firstChildType = firstChildNodes.item(k)
0447: .getAttributes().getNamedItem("datatype")
0448: .getNodeValue();
0449:
0450: if (!firstChildType.equals(otherType)) {
0451: allFound = false;
0452: break;
0453: }
0454: }
0455: }
0456:
0457: // we found all the fields of the first node in the fields of another ->
0458: // it's a subset node...
0459: if (allFound) {
0460: if (logger.isDebugEnabled()) {
0461: String name = first.getAttributes().getNamedItem(
0462: "name").getNodeValue();
0463: logger
0464: .debug("VishnuPlugin.duplicateNode - Found a duplicate "
0465: + first.getNodeName() + " " + name);
0466: }
0467: setResourceAttributes(first, other);
0468:
0469: nodes.remove(first);
0470: return true;
0471: }
0472: }
0473: return false;
0474: }
0475:
0476: protected void mergeNode(Node first, List nodes,
0477: Iterator nodeListIter) {
0478: if (logger.isInfoEnabled()) {
0479: String name = first.getAttributes().getNamedItem("name")
0480: .getNodeValue();
0481: logger.info(getName() + ".mergeNode - examining "
0482: + first.getNodeName() + " " + name);
0483: }
0484:
0485: if (nodes.size() == 1)
0486: return; // if no others to compare against, it's not a duplicate
0487:
0488: NodeList firstChildNodes = first.getChildNodes();
0489:
0490: Map firstFieldToType = new HashMap();
0491:
0492: for (int k = 0; k < firstChildNodes.getLength(); k++) {
0493: String firstChildName = firstChildNodes.item(k)
0494: .getAttributes().getNamedItem("name")
0495: .getNodeValue();
0496: String type = firstChildNodes.item(k).getAttributes()
0497: .getNamedItem("datatype").getNodeValue();
0498: firstFieldToType.put(firstChildName, type);
0499: }
0500:
0501: for (int i = 0; i < nodes.size(); i++) {
0502: Node other = (Node) nodes.get(i);
0503: if (first == other)
0504: continue; // ignore self to tell if duplicate
0505:
0506: NodeList otherChildNodes = other.getChildNodes();
0507:
0508: // if (firstChildNodes.getLength () > otherChildNodes.getLength ())
0509: // continue; // can't be a subset if more fields
0510:
0511: // create name->type mapping for other node
0512: Map otherFieldToType = new HashMap();
0513: Map otherNameToNode = new HashMap();
0514:
0515: boolean hasTypeCollision = false;
0516: for (int k = 0; k < otherChildNodes.getLength(); k++) {
0517: String field = otherChildNodes.item(k).getAttributes()
0518: .getNamedItem("name").getNodeValue();
0519: String type = otherChildNodes.item(k).getAttributes()
0520: .getNamedItem("datatype").getNodeValue();
0521: if (logger.isInfoEnabled())
0522: logger.info(getName()
0523: + ".mergeNodes - other field " + field
0524: + " - type " + type);
0525:
0526: if (firstFieldToType.containsKey(field)
0527: && !firstFieldToType.get(field).equals(type)) {
0528: if (logger.isInfoEnabled())
0529: logger
0530: .info(getName()
0531: + ".mergeNodes - found type collision at "
0532: + field + " - "
0533: + firstFieldToType.get(field)
0534: + " vs " + type);
0535: hasTypeCollision = true;
0536: break;
0537: }
0538:
0539: otherFieldToType.put(field, type);
0540: otherNameToNode.put(field, otherChildNodes.item(k));
0541: }
0542:
0543: if (hasTypeCollision)
0544: continue; // can't merge
0545:
0546: Map namesInOther = new HashMap(otherFieldToType);
0547: namesInOther.entrySet().removeAll(
0548: firstFieldToType.entrySet());
0549:
0550: for (Iterator iter = namesInOther.keySet().iterator(); iter
0551: .hasNext();) {
0552: Object fieldName = iter.next();
0553: Node otherNode = (Node) otherNameToNode.get(fieldName);
0554: // add new fields
0555: first.appendChild(otherNode);
0556: firstFieldToType.put(fieldName, namesInOther
0557: .get(fieldName));
0558: }
0559:
0560: if (logger.isInfoEnabled()) {
0561: String name = first.getAttributes()
0562: .getNamedItem("name").getNodeValue();
0563: logger.info(getName()
0564: + ".mergeNode - Found a mergable node "
0565: + first.getNodeName() + " " + name);
0566: }
0567: setResourceAttributes(first, other);
0568:
0569: nodeListIter.remove();
0570: nodeListIter.next();
0571: }
0572: }
0573:
0574: protected void setResourceAttributes(Node first, Node other) {
0575: boolean this IsResource = first.getAttributes().getNamedItem(
0576: "is_resource").getNodeValue().equals("true");
0577: boolean otherIsNotResource = other.getAttributes()
0578: .getNamedItem("is_resource").getNodeValue().equals(
0579: "false");
0580: if (this IsResource && otherIsNotResource) {
0581: if (logger.isDebugEnabled()) {
0582: String name = first.getAttributes()
0583: .getNamedItem("name").getNodeValue();
0584: logger
0585: .debug(getName()
0586: + ".mergeNode - Found a mergable node - setting resource attribute for duplicate "
0587: + name);
0588: }
0589:
0590: other.getAttributes().getNamedItem("is_resource")
0591: .setNodeValue("true");
0592:
0593: // set is_key attribute on other object format
0594: NodeList otherChildNodes = other.getChildNodes();
0595: for (int k = 0; k < otherChildNodes.getLength(); k++) {
0596: String field = otherChildNodes.item(k).getAttributes()
0597: .getNamedItem("name").getNodeValue();
0598: if (field.equals("UID")) {
0599: otherChildNodes.item(k).getAttributes()
0600: .getNamedItem("is_key")
0601: .setNodeValue("true");
0602: break;
0603: }
0604: }
0605: }
0606: }
0607:
0608: /**
0609: * Add new fields
0610: *
0611: * Where there was :
0612: * FIELDFORMAT datatype="indirectObject" ... is_subobject="true" name="indirectObject"
0613: *
0614: * now have :
0615: *
0616: * FIELDFORMAT datatype="indirectObject_0" ... is_subobject="true" name="indirectObject_0"
0617: * FIELDFORMAT datatype="indirectObject_1" ... is_subobject="true" name="indirectObject_1"
0618: * FIELDFORMAT datatype="string(128)" ... is_subobject="true" name="indirectObject_2"
0619: *
0620: * for as many duplicates as there are in the nameToNode map.
0621: *
0622: * nameToDescrip is used to lookup the object description for a type. Then for each
0623: * field in the object description, if there is more than one known type for that field,
0624: * adds new fields with unique names for each type.
0625: *
0626: * nameToDescrip is created in removeDuplicates
0627: *
0628: * @see #removeDuplicates
0629: * @param root - of the document
0630: * @param doc - needed so can manufacture new nodes (fields), gets altered through addition of
0631: * new fields
0632: * @param nameToNodes -- per field name, holds all the different possible object formats
0633: * @param nameToDescrip -- contents are altered to record new name->type pairs
0634: */
0635: protected void addFieldsForDifferentTypes(Node root, Document doc,
0636: Map nameToNodes, Map nameToDescrip) {
0637: NodeList nlist = root.getChildNodes();
0638:
0639: Map nodeToNewFields = new HashMap();
0640: Map nodeToRemoveFields = new HashMap();
0641:
0642: for (int i = 0; i < nlist.getLength(); i++) {
0643: Node objectFormat = nlist.item(i);
0644: NodeList objectFormatNodeList = objectFormat
0645: .getChildNodes();
0646: Set fieldsToAdd = new TreeSet(new Comparator() {
0647: public int compare(Object o1, Object o2) {
0648: String n1 = ((Node) o1).getAttributes()
0649: .getNamedItem("name").getNodeValue();
0650: String n2 = ((Node) o2).getAttributes()
0651: .getNamedItem("name").getNodeValue();
0652: return n1.compareTo(n2);
0653: }
0654: });
0655: Set fieldsToRemove = new HashSet();
0656: nodeToNewFields.put(objectFormat, fieldsToAdd);
0657: nodeToRemoveFields.put(objectFormat, fieldsToRemove);
0658:
0659: String name = objectFormat.getAttributes().getNamedItem(
0660: "name").getNodeValue().toLowerCase();
0661: ObjectDescrip descrip = (ObjectDescrip) nameToDescrip
0662: .get(name);
0663:
0664: if (logger.isInfoEnabled())
0665: logger.info(getName()
0666: + ".addFieldsForDifferentTypes - " + name
0667: + " has " + objectFormatNodeList.getLength()
0668: + " children");
0669:
0670: for (int j = 0; j < objectFormatNodeList.getLength(); j++) {
0671: Node fieldFormat = objectFormatNodeList.item(j);
0672: String fieldName = fieldFormat.getAttributes()
0673: .getNamedItem("name").getNodeValue();
0674: String datatype = fieldFormat.getAttributes()
0675: .getNamedItem("datatype").getNodeValue();
0676: if (logger.isInfoEnabled())
0677: logger.info(getName()
0678: + ".addFieldsForDifferentTypes - "
0679: + datatype + "-" + fieldName);
0680:
0681: if (descrip == null) {
0682: logger.info(getName()
0683: + ".addFieldsForDifferentTypes - huh? no "
0684: + name);
0685: continue;
0686: }
0687:
0688: Set knownTypes = descrip.typesForField(fieldName);
0689:
0690: int distinctNames = 0;
0691:
0692: if (knownTypes.size() > 1) {
0693: fieldsToRemove.add(fieldFormat);
0694: if (logger.isInfoEnabled())
0695: logger
0696: .info(getName()
0697: + ".addFieldsForDifferentTypes - will remove "
0698: + fieldName + "-" + datatype);
0699: for (Iterator iter = knownTypes.iterator(); iter
0700: .hasNext();) {
0701: String newtype = (String) iter.next();
0702: /* if (newtype.equals (datatype) ||
0703: (newtype.startsWith ("string(") && (datatype.startsWith ("string(")))) {
0704: if (logger.isInfoEnabled())
0705: debug (getName () + ".addFieldsForDifferentTypes - skipping field " +
0706: newtype + "-" +
0707: name);
0708: continue;
0709: }
0710: */
0711:
0712: Node clone = domUtil.createClone(fieldFormat,
0713: doc);
0714: String newname = fieldName + SEPARATOR
0715: + distinctNames++;
0716:
0717: descrip.addNewNameType(fieldName, newname,
0718: newtype);
0719:
0720: clone.getAttributes().getNamedItem("name")
0721: .setNodeValue(newname);
0722: clone.getAttributes().getNamedItem("datatype")
0723: .setNodeValue(newtype);
0724: clone.getAttributes().getNamedItem(
0725: "is_subobject").setNodeValue(
0726: isObject(newtype) ? "true" : "false");
0727: boolean result = fieldsToAdd.add(clone);
0728: if (logger.isInfoEnabled() && result)
0729: logger
0730: .info(getName()
0731: + ".addFieldsForDifferentTypes - storing new field "
0732: + newtype + "-" + newname);
0733: }
0734: }
0735: }
0736: }
0737:
0738: // go through each OBJECTFORMAT node and add any new fields
0739: for (Iterator iter = nodeToNewFields.keySet().iterator(); iter
0740: .hasNext();) {
0741: Node objectFormatNode = (Node) iter.next();
0742: Set removeFields = (Set) nodeToRemoveFields
0743: .get(objectFormatNode);
0744: for (Iterator iter2 = removeFields.iterator(); iter2
0745: .hasNext();)
0746: objectFormatNode.removeChild((Node) iter2.next());
0747:
0748: Set newFields = (Set) nodeToNewFields.get(objectFormatNode);
0749:
0750: if (!newFields.isEmpty()) {
0751: for (Iterator iter2 = newFields.iterator(); iter2
0752: .hasNext();) {
0753: Node newNode = (Node) iter2.next();
0754: if (logger.isInfoEnabled()) {
0755: String type = newNode.getAttributes()
0756: .getNamedItem("datatype")
0757: .getNodeValue();
0758: String name = newNode.getAttributes()
0759: .getNamedItem("name").getNodeValue();
0760:
0761: String ofName = objectFormatNode
0762: .getAttributes().getNamedItem("name")
0763: .getNodeValue();
0764: logger
0765: .info(getName()
0766: + ".addFieldsForDifferentTypes - to node "
0767: + objectFormatNode
0768: .getNodeName() + "/"
0769: + ofName + " adding new field "
0770: + newNode.getNodeName() + " - "
0771: + type + " : " + name);
0772: }
0773:
0774: objectFormatNode.appendChild(newNode);
0775: }
0776: }
0777: }
0778: }
0779:
0780: /** check type and see if it is not a primitive = object */
0781: protected boolean isObject(String type) {
0782: return (!type.equals("number") && !type.equals("datetime")
0783: && !type.equals("latlong") && !type.equals("boolean")
0784: && !type.startsWith("string") && !type.equals("list")
0785: && !type.equals("interval") && !type.equals("matrix"));
0786: }
0787:
0788: /**
0789: * get the document from the data xmlizer, set some attributes on the header,
0790: * and then do any post-processing
0791: **/
0792: public Document prepareDocument(Collection tasks,
0793: Collection changed, XMLizer dataXMLizer,
0794: boolean clearDatabase, boolean sendingChangedObjects,
0795: String assetClassName) {
0796: Document dataDoc = getDataDoc(tasks, changed, dataXMLizer,
0797: assetClassName);
0798:
0799: if (showDataXML)
0800: logger.info(domUtil.getDocAsString(dataDoc));
0801:
0802: Node dataNode = setDocHeader(dataDoc, clearDatabase);
0803:
0804: // really just change newobjects tag to changedobjects tag if sendingChangedObjects is true
0805: postProcessData(dataDoc, dataNode, sendingChangedObjects);
0806:
0807: return dataDoc;
0808: }
0809:
0810: protected Document getVanillaHeader() {
0811: Document doc = new DocumentImpl();
0812: Element root = doc.createElement("PROBLEM");
0813: root.setAttribute("NAME", comm.getProblem());
0814: doc.appendChild(root);
0815: Element df = doc.createElement("DATA");
0816: root.appendChild(df);
0817: Element window = doc.createElement("WINDOW");
0818: df.appendChild(window);
0819:
0820: setDocHeader(doc, false);
0821:
0822: return doc;
0823: }
0824:
0825: /**
0826: * Sets the vishnu epoch start and end time and the proper problem name.
0827: * If clearDatabase is true, appends CLEARDATABASE tag.
0828: **/
0829: protected Node setDocHeader(Document dataDoc, boolean clearDatabase) {
0830: Node root = dataDoc.getDocumentElement();
0831: ((Element) root).setAttribute("NAME", comm.getProblem());
0832:
0833: Node dataNode = root.getFirstChild();
0834: Node windowNode = dataNode.getFirstChild();
0835:
0836: ((Element) windowNode).setAttribute("starttime",
0837: vishnuEpochStartTime);
0838: ((Element) windowNode).setAttribute("endtime",
0839: vishnuEpochEndTime);
0840:
0841: NodeList nlist = dataNode.getChildNodes();
0842:
0843: if (clearDatabase)
0844: root.getFirstChild().insertBefore(
0845: dataDoc.createElement("CLEARDATABASE"),
0846: root.getFirstChild().getFirstChild());
0847:
0848: return dataNode;
0849: }
0850:
0851: /** changes newobjects tag to changedobjects tag if sendingChangedObjects is true; */
0852: protected void postProcessData(Document dataDoc, Node dataNode,
0853: boolean sendingChangedObjects) {
0854: if (!sendingChangedObjects)
0855: return;
0856:
0857: NodeList nlist = dataNode.getChildNodes();
0858:
0859: for (int i = 0; i < nlist.getLength(); i++) {
0860: if (nlist.item(i).getNodeName().equals("NEWOBJECTS")) {
0861:
0862: Node newobject = nlist.item(i);
0863: NodeList objects = newobject.getChildNodes();
0864: String was = newobject.getNodeName();
0865: Node changedObjects = dataDoc
0866: .createElement("CHANGEDOBJECTS");
0867: dataNode.insertBefore(changedObjects, newobject);
0868: dataNode.removeChild(newobject);
0869: for (int j = 0; j < objects.getLength(); j++)
0870: changedObjects.appendChild(objects.item(j));
0871:
0872: break; // we're only interested in the NEWOBJECTS tag
0873: }
0874: }
0875: }
0876:
0877: /**
0878: * send other global data wrapped in the problem header
0879: * @param otherDataFile - other data file to read, process, and send
0880: **/
0881: protected Document getOtherDataDoc(String otherDataFile) {
0882: Document doc = new DocumentImpl();
0883: Element root = doc.createElement("PROBLEM");
0884: root.setAttribute("NAME", comm.getProblem());
0885: doc.appendChild(root);
0886: Element df = doc.createElement("DATA");
0887: root.appendChild(df);
0888:
0889: Element newobjects = doc.createElement("NEWOBJECTS");
0890: df.appendChild(newobjects);
0891:
0892: // attach other data
0893: appendOtherData(doc, newobjects, otherDataFile);
0894:
0895: return doc;
0896: }
0897:
0898: /**
0899: * <pre>
0900: * Append any global other data
0901: *
0902: * Global data is optional, so if it can't find the file specified
0903: * (for instance a default odd file) nothing will happen.
0904: * </pre>
0905: */
0906: protected void appendOtherData(Document dataDoc,
0907: Element placeToAdd, String otherData) {
0908: if (otherDataFileExists(otherData)) {
0909: if (logger.isInfoEnabled())
0910: logger.info(getName() + " appending " + otherData
0911: + " other data file");
0912:
0913: domUtil.appendChildrenToDoc(dataDoc, placeToAdd, // NEWOBJECTS tag
0914: otherData);
0915: }
0916: }
0917:
0918: public boolean otherDataFileExists(String otherDataFile) {
0919: try {
0920: return (configFinder.open(otherDataFile) != null);
0921: } catch (FileNotFoundException fnf) {
0922: if (logger.isInfoEnabled())
0923: logger
0924: .info(getName()
0925: + ".otherDataFileExists could not find optional file : "
0926: + otherDataFile);
0927: } catch (IOException ioe) {
0928: logger.error(getName()
0929: + ".otherDataFileExists - got io exception " + ioe,
0930: ioe);
0931: }
0932: return false;
0933: }
0934:
0935: /**
0936: * OK - horrible hack -- for allocators, need givenPE, since
0937: * query won't work within same transaction cycle.
0938: */
0939: /*
0940: protected void handleRoleSchedule (Node field, PlanElement givenPE) {
0941: if (logger.isInfoEnabled())
0942: debug (getName () + ".handleRoleSchedule - found role schedule.");
0943:
0944: Node list = field.getFirstChild ();
0945: NodeList values = list.getChildNodes ();
0946:
0947: for (int i = 0; i < values.getLength(); i++) {
0948: Node value = (Node) values.item (i);
0949: Node object = value.getFirstChild ();
0950: Node startField = object.getFirstChild ();
0951: Node endField = object.getLastChild ();
0952:
0953: final String uid =
0954: startField.getAttributes().getNamedItem ("value").getNodeValue();
0955: if (logger.isInfoEnabled())
0956: debug ("Looking for UID " + uid);
0957:
0958: Collection results;
0959:
0960: if (givenPE != null) {
0961: results = new HashSet ();
0962: results.add (givenPE);
0963: }
0964: else
0965: results = query (new UnaryPredicate () {
0966: public boolean execute (Object obj) {
0967: if (obj instanceof PlanElement) {
0968: //debug ("\t found PE with uid <" + ((PlanElement) obj).getUID () + ">");
0969: return ((PlanElement) obj).getUID ().equals (uid);
0970: }
0971:
0972: return false;
0973: }
0974: });
0975:
0976: if (results.iterator ().hasNext ()) {
0977: TimeSpan ts = (TimeSpan) results.iterator ().next ();
0978:
0979: String startString = format.format (new Date (ts.getStartTime ()));
0980: String endString = format.format (new Date (ts.getEndTime ()));
0981:
0982: startField.getAttributes().getNamedItem ("value").setNodeValue(startString);
0983: endField.getAttributes().getNamedItem ("value").setNodeValue(endString);
0984: }
0985: else
0986: debug (getName () + ".handleRoleSchedule : ERROR - could not find plan element UID " +
0987: uid);
0988:
0989: }
0990: }
0991: */
0992:
0993: /** make a document that tells Vishnu to freeze all assignments */
0994: public Document prepareFreezeAll() {
0995: Document doc = new DocumentImpl();
0996: Element newRoot = doc.createElement("PROBLEM");
0997: newRoot.setAttribute("NAME", comm.getProblem());
0998: doc.appendChild(newRoot);
0999:
1000: Element freeze = doc.createElement("FREEZEALL");
1001: newRoot.appendChild(freeze);
1002:
1003: return doc;
1004: }
1005:
1006: public Document prepareRescind(Enumeration removedTasks, String verb) {
1007: Document doc = new DocumentImpl();
1008: Element newRoot = doc.createElement("PROBLEM");
1009: newRoot.setAttribute("NAME", comm.getProblem());
1010: doc.appendChild(newRoot);
1011:
1012: Element df = doc.createElement("DATA");
1013:
1014: Element window = doc.createElement("WINDOW");
1015: window.setAttribute("starttime", "2000-01-01 00:00:00");
1016: window.setAttribute("endtime", "2002-01-01 00:00:00");
1017: df.appendChild(window);
1018:
1019: Element deletedobjects = doc.createElement("DELETEDOBJECTS");
1020: df.appendChild(deletedobjects);
1021:
1022: while (removedTasks.hasMoreElements()) {
1023: Task t = (Task) removedTasks.nextElement();
1024:
1025: // Element unfreeze = doc.createElement("UNFREEZE");
1026: // unfreeze.setAttribute ("task", t.getUID ().toString());
1027:
1028: if (logger.isDebugEnabled())
1029: logger
1030: .debug("XMLProcessor.prepareRescind - telling scheduler to forget "
1031: + t.getUID());
1032:
1033: // newRoot.appendChild (unfreeze);
1034:
1035: Element obj = doc.createElement("OBJECT");
1036: obj.setAttribute("type", verb);
1037:
1038: Element elem = doc.createElement("FIELD");
1039: elem.setAttribute("name", "id");
1040: elem.setAttribute("value", t.getUID().toString());
1041: obj.appendChild(elem);
1042: deletedobjects.appendChild(obj);
1043: }
1044: newRoot.appendChild(df);
1045:
1046: return doc;
1047: }
1048:
1049: public Document prepareUnfreeze(Collection unfreezeTasks) {
1050: Document doc = new DocumentImpl();
1051: Element newRoot = doc.createElement("PROBLEM");
1052: newRoot.setAttribute("NAME", comm.getProblem());
1053: doc.appendChild(newRoot);
1054:
1055: for (Iterator iter = unfreezeTasks.iterator(); iter.hasNext();) {
1056: Task t = (Task) iter.next();
1057:
1058: Element unfreeze = doc.createElement("UNFREEZE");
1059: unfreeze.setAttribute("task", t.getUID().toString());
1060:
1061: if (logger.isDebugEnabled())
1062: logger
1063: .debug("XMLProcessor.prepareUnfreeze - telling scheduler to unfreeze "
1064: + t.getUID());
1065:
1066: newRoot.appendChild(unfreeze);
1067: }
1068:
1069: return doc;
1070: }
1071:
1072: public class ObjectDescrip {
1073: Map fields = new HashMap();
1074: Map newNames = new HashMap();
1075:
1076: // boolean debug = false;
1077:
1078: public void addFields(Node node) {
1079: NodeList nlist = node.getChildNodes();
1080:
1081: for (int i = 0; i < nlist.getLength(); i++) {
1082: Node field = nlist.item(i);
1083:
1084: String name = field.getAttributes()
1085: .getNamedItem("name").getNodeValue();
1086: String type = field.getAttributes().getNamedItem(
1087: "datatype").getNodeValue();
1088:
1089: addField(name, type);
1090: }
1091: }
1092:
1093: public void addField(String name, String type) {
1094: Set namedFields = (Set) fields.get(name);
1095:
1096: if (namedFields == null) {
1097: namedFields = new TreeSet();
1098: fields.put(name, namedFields);
1099: }
1100:
1101: if (!namedFields.contains(type)) {
1102: namedFields.add(type);
1103: /*
1104: if (debug && namedFields.size () > 1)
1105: debug ("\tfield " + name +
1106: " now " + namedFields);
1107: */
1108: }
1109: }
1110:
1111: public void addNewNameType(String oldname, String newname,
1112: String newtype) {
1113: Set nameTypePairs = (Set) newNames.get(oldname);
1114:
1115: if (nameTypePairs == null) {
1116: nameTypePairs = new HashSet();
1117: newNames.put(oldname, nameTypePairs);
1118: }
1119: /*
1120: if (debug)
1121: debug ("OD.addNewNameType - for oldname " + oldname +
1122: " adding newname " + newname +
1123: " newtype " + newtype);
1124: */
1125:
1126: nameTypePairs.add(new String[] { newname, newtype });
1127: }
1128:
1129: public Set getNameTypePairs(String oldname) {
1130: return (Set) newNames.get(oldname);
1131: }
1132:
1133: public Set typesForField(String name) {
1134: return (Set) fields.get(name);
1135: }
1136:
1137: public Map getFields() {
1138: return fields;
1139: }
1140: }
1141:
1142: protected VishnuComm getComm() {
1143: return comm;
1144: }
1145:
1146: // protected boolean getExtraOutput () { return logger.isInfoEnabled(); }
1147:
1148: protected boolean showFormatXML = false;
1149: protected boolean showDataXML = false;
1150: protected boolean debugFormatXMLizer = false;
1151: protected boolean debugDataXMLizer = false;
1152: protected String name;
1153: protected String clusterName;
1154: protected VishnuComm comm;
1155: protected VishnuDomUtil domUtil;
1156: protected ParamMap myParamTable;
1157: protected String vishnuEpochStartTime;
1158: protected String vishnuEpochEndTime;
1159: protected XMLizer dataXMLizer;
1160: protected Logger logger, formatXMLizeLogger, dataXMLizeLogger;
1161:
1162: ConfigFinder configFinder;
1163: }
|