001/*
002 * Copyright (c) 2007-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2012-07-11 22:13:03 +0000 (Wed, 11 Jul 2012) $' 
007 * '$Revision: 30175 $'
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 org.jdom.Document;
033import org.jdom.Element;
034import org.jdom.input.DOMBuilder;
035import org.jdom.output.XMLOutputter;
036
037import ptolemy.actor.TypedAtomicActor;
038import ptolemy.actor.TypedIOPort;
039import ptolemy.data.StringToken;
040import ptolemy.data.Token;
041import ptolemy.data.XMLToken;
042import ptolemy.data.type.ArrayType;
043import ptolemy.data.type.BaseType;
044import ptolemy.data.type.Type;
045import ptolemy.kernel.CompositeEntity;
046import ptolemy.kernel.util.IllegalActionException;
047import ptolemy.kernel.util.NameDuplicationException;
048
049//////////////////////////////////////////////////////////////////////////
050//// XMLUpdater class name
051/**
052 * On each firing, read an XML token from port <i>input</i>, one token from each
053 * additional input port, and output the original XML updated with new values.
054 * This actor is similar to RecordUpdater.
055 * 
056 * @author Daniel Crawl
057 * @version $Id: XMLUpdater.java 30175 2012-07-11 22:13:03Z crawl $
058 */
059
060public class XMLUpdater extends TypedAtomicActor {
061
062        /**
063         * Construct an XMLUpdater source with the given container and name.
064         * 
065         * @param name
066         *            The name of this actor.
067         * @exception IllegalActionException
068         *                If the entity cannot be contained by the proposed
069         *                container.
070         * @exception NameDuplicationException
071         *                If the container already has an actor with this name.
072         */
073        public XMLUpdater(CompositeEntity container, String name)
074                        throws NameDuplicationException, IllegalActionException {
075                super(container, name);
076
077                input = new TypedIOPort(this, XML_IN_PORT_NAME, true, false);
078                input.setTypeEquals(BaseType.XMLTOKEN);
079
080                output = new TypedIOPort(this, "output", false, true);
081                output.setTypeEquals(BaseType.XMLTOKEN);
082
083                _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" "
084                                + "width=\"60\" height=\"20\" " + "style=\"fill:white\"/>\n"
085                                + "</svg>\n");
086
087                _domBuilder = new DOMBuilder();
088                _xo = new XMLOutputter();
089        }
090
091        // /////////////////////////////////////////////////////////////////
092        // // ports and parameters ////
093        
094        /** The input port that reads the XML document. */
095        public TypedIOPort input = null;
096
097        /** The output port that writes the XML document. */
098        public TypedIOPort output = null;
099
100        // /////////////////////////////////////////////////////////////////
101        // // public methods ////
102
103        /**
104         * Send the token in the value parameter to the output.
105         * 
106         * @exception IllegalActionException
107         *                If it is thrown by the send() method sending out the
108         *                token.
109         */
110        public void fire() throws IllegalActionException {
111                super.fire();
112
113                XMLToken token = (XMLToken) input.get(0);
114                org.w3c.dom.Document d = token.getDomTree();
115                Document doc = _domBuilder.build(d);
116                Element root = doc.getRootElement();
117
118                Object[] inPortArray = inputPortList().toArray();
119                for (int i = 0; i < inPortArray.length; i++) {
120                        TypedIOPort port = (TypedIOPort) inPortArray[i];
121                        String name = port.getName();
122
123                        if (!name.equals(XML_IN_PORT_NAME) && port.getWidth() > 0) {
124                                _appendToDoc(root, port);
125                        }
126                }
127
128                XMLToken outToken = null;
129
130                try {
131                        outToken = new XMLToken(_xo.outputString(doc));
132                } catch (Exception e) {
133                        throw new IllegalActionException(this,
134                                        "Exception creating XMLToken: " + e.getMessage());
135                }
136
137                output.broadcast(outToken);
138        }
139
140        // /////////////////////////////////////////////////////////////////
141        // // private methods ////
142
143        private void _appendToDoc(Element root, TypedIOPort port)
144                        throws IllegalActionException {
145                Token token = port.get(0);
146
147                if (port.getType() instanceof ArrayType) {
148                        throw new IllegalActionException(this, "Arrays not yet supported");
149                } else {
150                        _appendOneToken(root, port.getName(), token);
151                }
152        }
153
154        private void _appendOneToken(Element root, String name, Token token)
155                        throws IllegalActionException {
156                Type type = token.getType();
157                String str = null;
158
159                if (type == BaseType.XMLTOKEN) {
160                        throw new IllegalActionException(this, "xml not supported");
161                } else if (type == BaseType.STRING) {
162                        str = ((StringToken) token).stringValue();
163                } else {
164                        str = token.toString();
165                }
166
167                Element child = new Element(name);
168                child.setText(str);
169                root.addContent(child);
170        }
171
172        // /////////////////////////////////////////////////////////////////
173        // // private variables ////
174
175        private final static String XML_IN_PORT_NAME = "input";
176
177        private DOMBuilder _domBuilder;
178        private XMLOutputter _xo;
179}