001/* 002 * Copyright (c) 2007-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-04-17 21:39:59 +0000 (Tue, 17 Apr 2012) $' 007 * '$Revision: 29739 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.sdm.spa; 031 032import java.util.List; 033 034import org.jdom.Document; 035import org.jdom.Element; 036import org.jdom.input.DOMBuilder; 037import org.jdom.output.XMLOutputter; 038 039import ptolemy.actor.AtomicActor; 040import ptolemy.actor.TypedIOPort; 041import ptolemy.data.ArrayToken; 042import ptolemy.data.BooleanToken; 043import ptolemy.data.DoubleToken; 044import ptolemy.data.IntToken; 045import ptolemy.data.LongToken; 046import ptolemy.data.StringToken; 047import ptolemy.data.Token; 048import ptolemy.data.UnsignedByteToken; 049import ptolemy.data.XMLToken; 050import ptolemy.data.type.ArrayType; 051import ptolemy.data.type.BaseType; 052import ptolemy.data.type.Type; 053import ptolemy.kernel.util.IllegalActionException; 054 055////////////////////////////////////////////////////////////////////////// 056//// XMLHelper 057 058/** 059 * This splits an XML document into its child elements and each is sent to the 060 * output port with the same name. It is used by both XMLDisassembler and the 061 * new web service actor. (The latter uses this class so that when the web 062 * service does not have complex return types, it can output them directly [like 063 * the original WebServiceActor]). 064 * 065 * @author Daniel Crawl 066 * @version $Id: XMLHelper.java 29739 2012-04-17 21:39:59Z crawl $ 067 */ 068 069public class XMLHelper { 070 /** 071 * Initialize helper classes. 072 * 073 * @param actor 074 * the using this class 075 */ 076 public XMLHelper(AtomicActor actor) { 077 _actor = actor; 078 _outputter = new XMLOutputter(); 079 _builder = new DOMBuilder(); 080 } 081 082 /** Set the value of _outputNilVal. */ 083 public void setOutputNil(boolean val) { 084 _outputNilVal = val; 085 } 086 087 /** Set the value of _arraysWrappedVal. */ 088 public void setArraysWrapped(boolean val) { 089 _arraysWrappedVal = val; 090 } 091 092 /** 093 * Peel off the root element from an XML document, and output the content in 094 * each child element to the output port with same name. 095 * 096 * @param name 097 * the root element name in the XML document to peel off 098 * @param doc 099 * the XML document 100 * @param outputPorts 101 * the output ports 102 * @param portPrepend 103 * optional string to remove from beginning of port name 104 */ 105 public void splitOutXML(String name, org.w3c.dom.Document doc, 106 List outputPorts, String portPrepend) throws IllegalActionException { 107 Document jdomDoc = _builder.build(doc); 108 Element rootEl = jdomDoc.getRootElement(); 109 110 /* 111 * System.out.println("peeling for " + name); 112 * System.out.println("rootel name " + rootEl.getName()); 113 * System.out.println("xml = " + _outputter.outputString(jdomDoc)); 114 */ 115 116 // remove all the name spaces so the getChildren() call below 117 // retrieves all the children 118 List k = rootEl.getChildren(); 119 for (int z = 0; z < k.size(); z++) { 120 Element e = (Element) k.get(z); 121 e.setNamespace(null); 122 // System.out.println("rm ns for " + e.getName()); 123 // System.out.println("z " + z + " name |" + e.getName() + "|"); 124 // System.out.println("z " + z + " vat " + e.getText()); 125 } 126 127 // make sure document root element name matches port name 128 if (!rootEl.getName().equals(name)) { 129 throw new IllegalActionException(_actor, "No xml input with name " 130 + name); 131 } 132 133 // output each part to the corresponding port 134 Object[] portArray = outputPorts.toArray(); 135 for (int i = 0; i < portArray.length; i++) { 136 TypedIOPort port = (TypedIOPort) portArray[i]; 137 String portName = port.getName(); 138 Type portType = port.getType(); 139 140 Token token = null; 141 142 // see if the port's name begins with the port prepend string 143 if (portPrepend != null && portName.startsWith(portPrepend)) { 144 // remove port prepend string from port name 145 portName = portName.substring(portPrepend.length()); 146 } 147 148 // System.out.println("looking for child " + portName); 149 150 // get the children matching this port name 151 List kids = rootEl.getChildren(portName); 152 153 if (kids.size() == 0) { 154 System.out.println("WARNING: no xml child for " + portName); 155 } else if (((Element) kids.get(0)).getAttribute("href") != null) { 156 System.out 157 .println("WARNING: multi-reference values not supported."); 158 } else if (portType instanceof ArrayType) { 159 Type subType = ((ArrayType) portType).getElementType(); 160 161 // see if wrapped 162 if (_arraysWrappedVal) { 163 // remove the additional element 164 kids = ((Element) kids.get(0)).getChildren(); 165 } 166 167 Token[] array = new Token[kids.size()]; 168 if(array.length == 0) { 169 token = new ArrayToken(subType); 170 } else { 171 for (int j = 0; j < kids.size(); j++) { 172 array[j] = _makeToken(subType, (Element) kids.get(j)); 173 } 174 token = new ArrayToken(array); 175 } 176 } else if (kids.size() > 1) { 177 throw new IllegalActionException(_actor, "XML part " + portName 178 + " contained array, but port is not arrayType"); 179 } else { 180 token = _makeToken(portType, (Element) kids.get(0)); 181 } 182 183 if (token == null) { 184 System.out.println("null token"); 185 } else { 186 port.broadcast(token); 187 } 188 } 189 } 190 191 /** 192 * Create a token from an Element matching the type of output port. 193 * 194 * @param portType 195 * the type 196 * @param child 197 * the data 198 * @return the token 199 */ 200 private Token _makeToken(Type portType, Element child) 201 throws IllegalActionException { 202 Token retval = null; 203 204 // see if it is nil 205 String nilStr = child.getAttributeValue("nil"); 206 if (nilStr != null && nilStr.equals("true")) { 207 if (!_outputNilVal) { 208 throw new IllegalActionException(_actor, 209 "Got nil value but not configured to output them."); 210 } else { 211 retval = Token.NIL; 212 } 213 } else { 214 String valStr = null; 215 216 // get a string of the data 217 if (portType == BaseType.XMLTOKEN) { 218 valStr = "<?xml version=\"1.0\"?>" 219 + _outputter.outputString(child); 220 } else { 221 valStr = child.getText(); 222 } 223 224 // System.out.println("make token " + portType + " for " 225 // + child.getName() + " : " + valStr); 226 227 // create a token based on the type using the data 228 if (portType == BaseType.STRING) { 229 retval = new StringToken(valStr); 230 } else if (portType == BaseType.BOOLEAN) { 231 retval = new BooleanToken(valStr); 232 } else if (portType == BaseType.INT) { 233 retval = new IntToken(valStr); 234 } else if (portType == BaseType.DOUBLE) { 235 retval = new DoubleToken(valStr); 236 } else if (portType == BaseType.LONG) { 237 retval = new LongToken(valStr); 238 } else if (portType == BaseType.UNSIGNED_BYTE) { 239 retval = new UnsignedByteToken(valStr); 240 } else if (portType == BaseType.XMLTOKEN) { 241 try { 242 retval = new XMLToken(valStr); 243 } catch (Exception e) { 244 // e.printStackTrace(); 245 throw new IllegalActionException(_actor, 246 "XMLToken constructor exception: " + e.getMessage()); 247 } 248 } 249 } 250 return retval; 251 } 252 253 // ///////////////////////////////////////////////////////////////// 254 // // private members //// 255 256 // whether we output nil tokens for nil="true" attributes 257 private boolean _outputNilVal = false; 258 259 // whether array elements are wrapped in an additional element 260 private boolean _arraysWrappedVal = false; 261 262 // used to create jdom documents from dom documents. 263 private DOMBuilder _builder = null; 264 265 // used to get the string value of an Element 266 private XMLOutputter _outputter = null; 267 268 // the actor that's using this class 269 private AtomicActor _actor = null; 270}