001/*
002 * Copyright (c) 2004-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 java.io.File;
033import java.io.IOException;
034import java.io.StringReader;
035import java.io.StringWriter;
036
037import javax.xml.transform.Result;
038import javax.xml.transform.Source;
039import javax.xml.transform.Transformer;
040import javax.xml.transform.TransformerException;
041import javax.xml.transform.TransformerFactory;
042import javax.xml.transform.dom.DOMSource;
043import javax.xml.transform.stream.StreamResult;
044import javax.xml.transform.stream.StreamSource;
045
046import org.w3c.dom.Document;
047
048import ptolemy.actor.TypedAtomicActor;
049import ptolemy.actor.TypedIOPort;
050import ptolemy.data.StringToken;
051import ptolemy.data.Token;
052import ptolemy.data.XMLToken;
053import ptolemy.data.expr.FileParameter;
054import ptolemy.data.type.BaseType;
055import ptolemy.kernel.CompositeEntity;
056import ptolemy.kernel.util.Attribute;
057import ptolemy.kernel.util.IllegalActionException;
058import ptolemy.kernel.util.NameDuplicationException;
059
060/**
061 * <p>
062 * Given an XSL transformation file, performs the specified transformation on
063 * the input XML doc.
064 * 
065 * </p>
066 * <p>
067 * XSLT is designed for use as part of XSL, which is a stylesheet language for
068 * XML. In addition to XSLT, XSL includes an XML vocabulary for specifying
069 * formatting. XSL specifies the styling of an XML document by using XSLT to
070 * describe how the document is transformed into another XML document that uses
071 * the formatting vocabulary. (ref: http://www.w3.org/TR/xslt)
072 * 
073 * </p>
074 * <p>
075 * Given an xml stream as input, XSLTTransformer is used for for linking (almost
076 * but not quite fitting) output port and input port data formats together. The
077 * actor produces an html stream that can be viewed or queried using the
078 * BrowserUI actor.
079 * 
080 * </p>
081 * <p>
082 * The configuration window for the XSLTTransformer actor can be viewed by
083 * double-clicking on the actor or by selecting 'Configure' from the right-click
084 * context menu. The window displays a GUI for browsing the XSL script which
085 * will be used to perform the transformation.
086 * </p>
087 * 
088 * @author Ilkay Altintas
089 * @version $Id: XSLTActor.java 24234 2010-05-06 05:21:26Z welker $
090 *
091 */
092
093public class XSLTActor extends TypedAtomicActor {
094
095        /**
096         * This parameter is to provide the path for the xsl file in user's
097         * computer.
098         * <P>
099         * This parameter can be filled in by specifying the file using the browse
100         * interface or by typing in the file. <i>The actor has <b>NO</b> default
101         * value. </i> Please double click on the actor to set it.
102         */
103        public FileParameter xslFileName;
104
105        /**
106         * String representation of the XML or HTMl input stream that needs to be
107         * transformed.
108         */
109        public TypedIOPort xmlIn;
110
111        /**
112         * String representation of the output of the transformation.
113         */
114        public TypedIOPort htmlOut;
115
116        public XSLTActor(CompositeEntity container, String name)
117                        throws NameDuplicationException, IllegalActionException {
118
119                super(container, name);
120
121                xmlIn = new TypedIOPort(this, "xmlIn", true, false);
122                htmlOut = new TypedIOPort(this, "htmlOut", false, true);
123
124                htmlOut.setTypeEquals(BaseType.STRING);
125        
126        xslFileName = new FileParameter(this, "XSLT File Path");
127
128                new Attribute(xmlIn, "_showName");
129                new Attribute(htmlOut, "_showName");
130
131        _factory = TransformerFactory.newInstance();;
132
133                _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" "
134                                + "width=\"60\" height=\"30\" " + "style=\"fill:white\"/>\n"
135                                + "<text x=\"10\" y=\"25\" "
136                                + "style=\"font-size:16; fill:blue; font-family:SansSerif\">"
137                                + "XSLT</text>\n" + "</svg>\n");
138
139        }
140
141        public void fire() throws IllegalActionException {
142                super.fire();
143
144        Source xmlSource;
145        StringReader xmlReader = null;
146        
147        Token token = xmlIn.get(0);
148
149        // see what kind of input
150        if(token instanceof StringToken)
151        {
152            String xmlStr = ((StringToken)token).stringValue();    
153            System.out.println(xmlStr);
154            xmlReader = new StringReader(xmlStr);
155            xmlSource = new StreamSource(xmlReader);
156        }
157        else if(token instanceof XMLToken)
158        {
159            Document doc = ((XMLToken)token).getDomTree();
160            xmlSource = new DOMSource(doc);
161        }
162        else
163        {
164            throw new IllegalActionException(this, "Unsupported type of " +
165                "input token: " + token.getType());
166        }
167
168        StringWriter writer = new StringWriter();
169        Result result = new StreamResult(writer);
170
171        // read the xsl file
172        File xslFile = xslFileName.asFile();
173        if(xslFile == null)
174        {
175            throw new IllegalActionException(this, "XSL file required. ");
176        }
177
178        Source xslSource = new StreamSource(xslFile);
179
180        // perform the transformation
181        try
182        {
183            Transformer transformer = _factory.newTransformer(xslSource);
184            transformer.transform(xmlSource, result);
185        }
186        catch(TransformerException e)
187        {
188            throw new IllegalActionException(this, "Error transforming: " + 
189                e.getMessage());
190        }
191
192        // output the result
193                htmlOut.broadcast(new StringToken(writer.toString()));
194
195        // close resources
196        try
197        {
198            if(xmlReader != null)
199            {
200                xmlReader.close();
201            }
202                    writer.close();
203        }
204        catch(IOException e)
205        {
206            throw new IllegalActionException(this, "Error closing " +
207                " string writer: " + e.getMessage());
208        }
209        }
210
211    /////////////////////////////////////////////////////////////////////////
212    //// private variables                                               ////
213
214    /** Factory for xsl transformers. */
215    private TransformerFactory _factory;
216}