001/* 002 * Copyright (c) 2007-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 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 ptolemy.actor.TypedAtomicActor; 033import ptolemy.actor.TypedIOPort; 034import ptolemy.data.ArrayToken; 035import ptolemy.data.BooleanToken; 036import ptolemy.data.StringToken; 037import ptolemy.data.Token; 038import ptolemy.data.XMLToken; 039import ptolemy.data.expr.Parameter; 040import ptolemy.data.type.ArrayType; 041import ptolemy.data.type.BaseType; 042import ptolemy.data.type.Type; 043import ptolemy.kernel.CompositeEntity; 044import ptolemy.kernel.util.Attribute; 045import ptolemy.kernel.util.IllegalActionException; 046import ptolemy.kernel.util.NameDuplicationException; 047 048////////////////////////////////////////////////////////////////////////// 049//// XMLAssembler 050/** 051 * 052 * On each firing, read one token from each input port and assemble them into an 053 * XML document where the root element name is specified by the output port 054 * name. 055 * 056 * @author Daniel Crawl 057 * @version $Id: XMLAssembler.java 24234 2010-05-06 05:21:26Z welker $ 058 */ 059public class XMLAssembler extends TypedAtomicActor { 060 061 /** 062 * Construct a XMLAssembler source with the given container and name. 063 * 064 * @param name 065 * The name of this actor. 066 * @exception IllegalActionException 067 * If the entity cannot be contained by the proposed 068 * container. 069 * @exception NameDuplicationException 070 * If the container already has an actor with this name. 071 */ 072 public XMLAssembler(CompositeEntity container, String name) 073 throws NameDuplicationException, IllegalActionException { 074 super(container, name); 075 076 inputNil = new Parameter(this, "inputNil"); 077 inputNil.setTypeEquals(BaseType.BOOLEAN); 078 inputNil.setExpression(String.valueOf(_inputNilVal)); 079 080 encloseInputPortName = new Parameter(this, "encloseInputPortName"); 081 encloseInputPortName.setTypeEquals(BaseType.BOOLEAN); 082 encloseInputPortName.setExpression(String 083 .valueOf(_encloseInputPortNameVal)); 084 085 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" " 086 + "width=\"60\" height=\"20\" " + "style=\"fill:white\"/>\n" 087 + "</svg>\n"); 088 } 089 090 // ///////////////////////////////////////////////////////////////// 091 // // ports and parameters //// 092 093 /** 094 * If true, then for each unconnected input port an element is created in 095 * the output document with an attribute nil whose value is "true". 096 */ 097 public Parameter inputNil = null; 098 099 /** 100 * If true, then each token received will be added to an element with the 101 * name of the input port. By setting it false, input XML documents can be 102 * merged into a single document. 103 */ 104 public Parameter encloseInputPortName = null; 105 106 // ///////////////////////////////////////////////////////////////// 107 // // public methods //// 108 109 /** 110 * React to a change in an attribute. 111 * 112 * @param attribute 113 * The changed parameter. 114 * @exception IllegalActionException 115 * If the parameter set is not valid. 116 */ 117 public void attributeChanged(Attribute attribute) 118 throws IllegalActionException { 119 if (attribute == inputNil) { 120 Token token = inputNil.getToken(); 121 _inputNilVal = ((BooleanToken) token).booleanValue(); 122 } else if (attribute == encloseInputPortName) { 123 Token token = encloseInputPortName.getToken(); 124 _encloseInputPortNameVal = ((BooleanToken) token).booleanValue(); 125 } 126 super.attributeChanged(attribute); 127 } 128 129 /** 130 * Set all output ports whose types have not been set to XMLToken. 131 * 132 * @exception IllegalActionException 133 */ 134 public void preinitialize() throws IllegalActionException { 135 super.preinitialize(); 136 137 Object[] portArray = outputPortList().toArray(); 138 for (int i = 0; i < portArray.length; i++) { 139 TypedIOPort port = (TypedIOPort) portArray[0]; 140 if (port.getType() == BaseType.UNKNOWN) { 141 port.setTypeEquals(BaseType.XMLTOKEN); 142 } 143 } 144 } 145 146 /** 147 * Read each input port, assemble the XML document, and send it to all 148 * output ports. 149 * 150 * @exception IllegalActionException 151 * If it is thrown by the send() method sending out the 152 * token. 153 */ 154 public void fire() throws IllegalActionException { 155 super.fire(); 156 157 StringBuffer xmlStr = new StringBuffer(); 158 159 // read a value from each port into an xml string 160 Object[] inPortArray = inputPortList().toArray(); 161 for (int i = 0; i < inPortArray.length; i++) { 162 TypedIOPort port = (TypedIOPort) inPortArray[i]; 163 String name = port.getName(); 164 165 // see if there's nothing connected and we allow nils 166 if (_inputNilVal && port.getWidth() == 0) { 167 xmlStr.append("<" + name + " nil=\"true\"/>"); 168 } else { 169 _addTokenStr(xmlStr, port); 170 } 171 } 172 173 // create documents and send for each output port 174 Object[] outPortArray = outputPortList().toArray(); 175 for (int i = 0; i < outPortArray.length; i++) { 176 TypedIOPort port = (TypedIOPort) outPortArray[i]; 177 String name = port.getName(); 178 179 String outputStr = "<" + name + ">" + xmlStr.toString() + "</" 180 + name + ">"; 181 182 Token token = null; 183 184 try { 185 token = new XMLToken(outputStr); 186 } catch (Exception e) { 187 throw new IllegalActionException(this, 188 "XMLAssembler: unable to create XMLToken with string: " 189 + xmlStr); 190 } 191 192 port.broadcast(token); 193 } 194 } 195 196 // ///////////////////////////////////////////////////////////////// 197 // // private methods //// 198 199 /** 200 * Consume and add the token to a string buffer. 201 * 202 * @param buf 203 * the buffer 204 * @param port 205 * input port that supplies the token 206 */ 207 private void _addTokenStr(StringBuffer buf, TypedIOPort port) 208 throws IllegalActionException { 209 Token token = port.get(0); 210 211 if (port.getType() instanceof ArrayType) { 212 Token[] array = ((ArrayToken) token).arrayValue(); 213 for (int i = 0; i < array.length; i++) { 214 _addOneTokenStr(buf, port.getName(), array[i]); 215 } 216 } else { 217 _addOneTokenStr(buf, port.getName(), token); 218 } 219 } 220 221 /** 222 * Add a single value from a token, optionally enclosing it in the port's 223 * name, to a StringBuffer. 224 * 225 * @param buf 226 * the buffer 227 * @param portName 228 * the name of the input port 229 * @param token 230 * the token 231 */ 232 private void _addOneTokenStr(StringBuffer buf, String portName, Token token) { 233 if (_encloseInputPortNameVal) { 234 buf.append("<" + portName + ">"); 235 } 236 237 // if it's a string token, do a stringValue so we don't get 238 // the quotes 239 Type tokenType = token.getType(); 240 if (tokenType == BaseType.STRING) { 241 buf.append(((StringToken) token).stringValue()); 242 } else { 243 String tokenStr = token.toString(); 244 245 // see if xml token with beginning <?xml 246 if (tokenType == BaseType.XMLTOKEN 247 && tokenStr.indexOf("<?xml") == 0) { 248 tokenStr = tokenStr.substring(tokenStr.indexOf(">") + 1); 249 } 250 251 buf.append(tokenStr); 252 } 253 254 if (_encloseInputPortNameVal) { 255 buf.append("</" + portName + ">"); 256 } 257 } 258 259 // ///////////////////////////////////////////////////////////////// 260 // // private members //// 261 262 // whether to add element with nil="true" attribute for unconnected 263 // input ports. (see inputNil) 264 private boolean _inputNilVal = true; 265 266 // whether to put each token value read into an element with the same 267 // name as input port. (see encloseInputPortName) 268 private boolean _encloseInputPortNameVal = true; 269}