001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: jianwu $'
006 * '$Date: 2013-10-22 21:29:41 +0000 (Tue, 22 Oct 2013) $' 
007 * '$Revision: 32507 $'
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.BufferedReader;
033import java.io.BufferedWriter;
034import java.io.File;
035import java.io.FileWriter;
036import java.io.IOException;
037import java.io.InputStreamReader;
038import java.io.Reader;
039import java.io.StringReader;
040import java.net.HttpURLConnection;
041import java.net.URL;
042import java.util.ArrayList;
043import java.util.HashMap;
044import java.util.Iterator;
045import java.util.List;
046import java.util.Map;
047import java.util.Set;
048import java.util.TreeSet;
049
050import org.kepler.configuration.ConfigurationManager;
051import org.kepler.configuration.ConfigurationProperty;
052
053import ptolemy.actor.IOPort;
054import ptolemy.actor.TypedAtomicActor;
055import ptolemy.actor.TypedIOPort;
056import ptolemy.actor.gui.BrowserLauncher;
057import ptolemy.actor.gui.style.TextStyle;
058import ptolemy.data.BooleanToken;
059import ptolemy.data.LongToken;
060import ptolemy.data.StringToken;
061import ptolemy.data.XMLToken;
062import ptolemy.data.expr.FileParameter;
063import ptolemy.data.expr.Parameter;
064import ptolemy.data.expr.SingletonParameter;
065import ptolemy.data.expr.StringParameter;
066import ptolemy.data.type.BaseType;
067import ptolemy.gui.GraphicalMessageHandler;
068import ptolemy.kernel.CompositeEntity;
069import ptolemy.kernel.util.Attribute;
070import ptolemy.kernel.util.IllegalActionException;
071import ptolemy.kernel.util.NameDuplicationException;
072import util.UUIDGen;
073
074//////////////////////////////////////////////////////////////////////////
075////BrowserUI
076/*
077 * <p>BrowserUI actor is an actor that:
078 * <ul>
079 * <li> displays a text/HTML output of an actor including different
080 * graphical output, and
081 * <li> interacts with the user during workflow execution.
082 * </ul>
083 * </p>
084 * <p>Given a <i>file path or URL</i> including a CGI-based form, or
085 * <i>text/HTML content</i>, this actor can be used for injecting user
086 * control and input. It can also be used for efficient output of legacy
087 * applications anywhere in a workflow via the user's local web browser.
088 * The BrowserUI actor uses the default browser in the user's computer.
089 * execution, the actor just outputs the (name, value) pairs in XML format and
090 * as separate arrays.</p>
091 *
092 * <p>The actor can be configured using the configuration interface to allow
093 * for automatic CGI form generation. The configuration is made through a text
094 * box that simply specifies the name and type of the output ports that the
095 * user wants to configure the actor for. Please refer to
096 * BrowserUIConfigureTest.xml under workflows/test in your directory for
097 * more information on the configuration of this actor.</p>
098 *
099 * @author Ilkay Altintas, Efrat Jaeger and Kai Lin
100 * @version $Id: BrowserUI.java 32507 2013-10-22 21:29:41Z jianwu $
101 *
102 */
103
104public class BrowserUI extends TypedAtomicActor {
105
106        /**
107         * Construct a BrowserUI actor with the given container and name.
108         * 
109         * @param container
110         *            The container.
111         * @param name
112         *            The name of this actor.
113         * @exception IllegalActionException
114         *                If the actor cannot be contained by the proposed
115         *                container.
116         * @exception NameDuplicationException
117         *                If the container already has an actor with this name.
118         */
119        public BrowserUI(CompositeEntity container, String name)
120                        throws IllegalActionException, NameDuplicationException {
121                super(container, name);
122
123                fileOrURLPort = new TypedIOPort(this, "fileOrURL", true, false);
124                fileOrURLPort.setTypeEquals(BaseType.STRING);
125                new Attribute(fileOrURLPort, "_showName");
126
127                fileOrURLParameter = new FileParameter(this, "fileOrURL");
128
129                fileFormat = new StringParameter(this, "file extension");
130                fileFormat.setExpression("");
131                fileFormat.addChoice(".html");
132                fileFormat.addChoice(".xml");
133                fileFormat.addChoice(".txt");
134                fileFormat.addChoice(".xsl");
135                fileFormat.addChoice(".svg");
136
137                fileContent = new TypedIOPort(this, "fileContent", true, false);
138                fileContent.setTypeEquals(BaseType.STRING);
139                new Attribute(fileContent, "_showName");
140
141                portConfiguration = new StringParameter(this, "portConfiguration");
142                TextStyle portConfigStyle = new TextStyle(portConfiguration,
143                                "portConfiguration");
144
145                maxWaitTime = new Parameter(this, "max wait time",
146                                new LongToken("300"));
147                maxWaitTime.setTypeEquals(BaseType.LONG);
148                
149                useForDisplay = new Parameter(this, "use for display",
150                                new BooleanToken(false));
151                useForDisplay.setTypeEquals(BaseType.BOOLEAN);
152
153                hasTrigger = new Parameter(this, "hasTrigger", new BooleanToken(false));
154                hasTrigger.setTypeEquals(BaseType.BOOLEAN);
155
156                xmlOutput = new TypedIOPort(this, "xmlOutput", false, true);
157                xmlOutput.setTypeEquals(BaseType.XMLTOKEN);
158                new Attribute(xmlOutput, "_showName");
159
160                trigger = new TypedIOPort(this, "trigger", true, false);
161                trigger.setTypeEquals(BaseType.GENERAL);
162                // trigger.setContainer(null);
163                hide = new SingletonParameter(trigger, "_hide"); // DFH
164                hide.setToken(BooleanToken.TRUE); // DFH
165
166                _attachText("_iconDescription", "<svg>\n" + "<rect x=\"0\" y=\"0\" "
167                                + "width=\"100\" height=\"30\" " + "style=\"fill:white\"/>\n"
168                                + "<text x=\"10\" y=\"25\" "
169                                + "style=\"font-size:16; fill:blue; font-family:SansSerif\">"
170                                + "BROWSER</text>\n" + "</svg>\n");
171
172        } // end of constructor
173
174        // /////////////////////////////////////////////////////////////////
175        // // ports and parameters ////
176
177        public SingletonParameter hide;
178
179        /**
180         * A parameter indicating how many seconds this actor will wait before
181         * throwing time out exception.
182         */
183        public Parameter maxWaitTime;
184        
185        /**
186         * A boolean parameter indicating whether this actor is used only for
187         * display only or will it be used for user interactions.
188         */
189        public Parameter useForDisplay;
190
191        /**
192         * A boolean parameter indicating whether trigger port has to be activated
193         * in order to schedule the actor.
194         */
195        public Parameter hasTrigger;
196
197        /**
198         * Output ports configuration.
199         * <p>
200         * The description of the ports should be represented as
201         * <ul>
202         * <li>portName portType
203         * </ul>
204         * one line per each output port.
205         */
206        public StringParameter portConfiguration;
207
208        /**
209         * Input file or URL parameter.
210         */
211        public TypedIOPort fileOrURLPort;
212
213        /**
214         * Input file or URL parameter.
215         */
216        public FileParameter fileOrURLParameter;
217
218        /** Content of the file. */
219        public TypedIOPort fileContent;
220
221        /**
222         * An xml name, value pair user response output.
223         */
224        public TypedIOPort xmlOutput;
225
226        /**
227         * The format of the data (used for content input).
228         */
229        public StringParameter fileFormat;
230
231        /**
232         * The port to trigger the actor in case there are no input ports connected.
233         * This port is used only for scheduling the actor.
234         * <p>
235         * <i>Please activate the hasTrigger parameter to display this port, and
236         * uncheck it to hide/disable it.</i>
237         * </p>
238         */
239        public TypedIOPort trigger;
240
241        // /////////////////////////////////////////////////////////////////
242        // // public methods ////
243
244        /**
245         * Callback for changes in attribute values.
246         * 
247         * @param at
248         *            The attribute that changed.
249         * @exception IllegalActionException
250         *                If the offsets array is not nondecreasing and nonnegative.
251         */
252        public void attributeChanged(Attribute at) throws IllegalActionException {
253                if (at == hasTrigger) {
254                        _triggerFlag = ((BooleanToken) hasTrigger.getToken())
255                                        .booleanValue();
256                        _debug("<TRIGGER_FLAG>" + _triggerFlag + "</TRIGGER_FLAG>");
257                        if (_triggerFlag) {
258                                // check if the trigger input port exists.
259                                boolean triggerExists = false;
260                                List inPortList = this.inputPortList();
261                                Iterator ports = inPortList.iterator();
262                                while (ports.hasNext()) {
263                                        IOPort p = (IOPort) ports.next();
264                                        if (p.isInput()) {
265                                                if (p.getName().equals("trigger")) {
266                                                        triggerExists = true;
267                                                }
268                                        }
269                                }
270                                if (!triggerExists) { // if there is no trigger port.
271                                        try {
272                                                trigger.setContainer(this);
273                                                hide.setToken(BooleanToken.FALSE); // DFH
274                                        } catch (NameDuplicationException ndex) {
275                                                _debug(ndex.getMessage());
276                                                GraphicalMessageHandler.message(ndex.getMessage()
277                                                                + "Could not create the trigger port in actor:"
278                                                                + this.getName());
279                                        }
280                                }
281                        } else {
282                                List inPortList = this.inputPortList();
283                                Iterator ports = inPortList.iterator();
284                                while (ports.hasNext()) {
285                                        IOPort p = (IOPort) ports.next();
286                                        if (p.isInput()) {
287                                                try {
288                                                        if (p.getName().equals("trigger")) {
289                                                                // p.setContainer(null); //DFH
290                                                                hide.setToken(BooleanToken.TRUE); // DFH
291                                                        }
292                                                } catch (Exception e) {
293                                                        GraphicalMessageHandler
294                                                                        .message(e.getMessage()
295                                                                                        + "Could not delete the trigger port in the actor: "
296                                                                                        + this.getName());
297                                                }
298                                        }
299                                }
300                        }
301                } else if (at == portConfiguration) {
302                        try {
303                                String configuration = ((StringToken) portConfiguration
304                                                .getToken()).stringValue();
305                                BufferedReader br = new BufferedReader(new StringReader(
306                                                configuration));
307                                String line = "";
308                                List ports = new ArrayList();
309                                while ((line = br.readLine()) != null) {
310                                        if (!line.trim().equals("")) {
311                                                String portName = line.trim();
312                                                if (portName.equals("xmlOutput")) {
313                                                        throw new IllegalActionException(
314                                                                        "xmlOutput port is already in use "
315                                                                                        + "in actor " + this.getName());
316                                                }
317                                                ports.add(portName);
318                                                // Type _inferType(portType);//FIXME: ADD TYPES
319                                        }
320                                }
321                                // if there are any named ports add them and turn
322                                // _namedPortsExist on.
323                                if (ports.size() > 0) {
324                                        _setOutputPorts(ports);
325                                        _namedPortsExist = true;
326                                }
327                        } catch (IOException ioex) {
328                                throw new IllegalActionException(
329                                                "Could not process configuration in actor "
330                                                                + this.getName() + ": " + ioex.getMessage());
331                        }
332                } else if (at == useForDisplay) {
333                        forDisplay = ((BooleanToken) useForDisplay.getToken())
334                                        .booleanValue();
335                        // if true remove all output ports.
336                        if (forDisplay) {
337                                try {
338                                        List outputPorts = this.outputPortList();
339                                        Iterator it = outputPorts.iterator();
340                                        while (it.hasNext()) {
341                                                IOPort iop = (IOPort) it.next();
342                                                iop.setContainer(null);
343                                        }
344                                } catch (NameDuplicationException nex) {
345                                        throw new IllegalActionException(this,
346                                                        "Could not remove xmlOutput port in actor "
347                                                                        + this.getName() + ": " + nex.getMessage());
348                                }
349                        } else {
350                                // else add xml output attribute
351                                try {
352                                        xmlOutput.setContainer(this);
353                                } catch (NameDuplicationException nex) {
354                                        throw new IllegalActionException(this,
355                                                        "Could not add xmlOutput port in actor "
356                                                                        + this.getName() + ": " + nex.getMessage());
357                                }
358                                attributeChanged(portConfiguration);
359                        }
360                } else
361                        super.attributeChanged(at);
362
363        } // end of attributeChanged
364
365        /**
366         * Given a ...., BrowserUI actor opens a broser ...
367         * 
368         * @exception IllegalActionException
369         *                If there is no director.
370         */
371        public void fire() throws IllegalActionException {
372
373                Reader in = null;
374                StringToken inputToken = null;
375                // String ext = "";
376                boolean fileContentFlag = false;
377                boolean hasForm = false;
378                // UUIDGen uuidgen = new UUIDGen();
379                String strFileOrURL = "";
380
381                // TODO: read trgier
382                try {
383                        for (int i = 0; i < trigger.getWidth(); i++) {
384                                trigger.get(i);
385                        }
386
387                        // if content port is connected then the input is a file content.
388                        if (fileContent.getWidth() > 0) {
389                                inputToken = (StringToken) fileContent.get(0);
390
391                                if (inputToken != null) {
392                                        String content = inputToken.stringValue();
393                                        _ext = fileFormat.getExpression();
394                                        // ADDED if forDisplay or known display content extension.
395                                        // display and return.                                  
396                                        if (forDisplay || _extensions.contains(_ext)) {
397                                                strFileOrURL = _writeContentToFile(content);
398                                                BrowserLauncher.openURL(strFileOrURL);
399                                                //sleep for 1000 ms because the BrowserLauncher may not be able to open url before the workflow execution finishes.
400                                                Thread.sleep(1000);
401                                                return;
402                                        } else {
403                                                in = new StringReader(content);
404                                                fileContentFlag = true;
405                                        }
406
407                                } else {
408                                        // If the inputToken is null set _reFire to false.
409                                        System.out.println("No Token Exception!");
410                                        _reFire = false;
411                                        return;
412                                }
413                        }
414
415                        // the input is a file or a url.
416                        else {
417                                if (fileOrURLPort.getWidth() > 0) {
418                                        try {
419                                                inputToken = (StringToken) fileOrURLPort.get(0);
420                                        } catch (Exception ex) {
421                                        }
422
423                                        if (inputToken != null) {
424                                                // set the fileOrURL parameter to be the input token.
425                                                fileOrURLParameter.setExpression(inputToken
426                                                                .stringValue());
427                                        } else {
428                                                // If the inputToken is null set _reFire to false.
429                                                System.out.println("No Token Exception!");
430                                                _reFire = false;
431                                                return;
432                                        }
433                                }
434                                // Remove an ending \n (before converting to URL).
435                                strFileOrURL = ((StringToken) fileOrURLParameter.getToken())
436                                                .stringValue();
437                                int lineEndInd = strFileOrURL.indexOf("\n");
438                                if (lineEndInd > -1) {
439                                        strFileOrURL = strFileOrURL.substring(0, lineEndInd);
440                                        fileOrURLParameter.setExpression(strFileOrURL);
441                                }
442
443                                // Read the fileOrURL parameter.
444                                URL fileOrURL = fileOrURLParameter.asURL();
445                                strFileOrURL = fileOrURL.toExternalForm();
446
447                                _debug("<fileOrURL>" + strFileOrURL + "</fileOrURL>");
448                                if (strFileOrURL.trim().equals("")) {
449                                        throw new IllegalActionException(this,
450                                                        "Input string is empty. ");
451                                }
452                                // Immediately display contents of non interactive extensions
453                                // (e.g., jpeg,,,).
454                                if (forDisplay || _isDisplayExtension(fileOrURL)) {
455                                        BrowserLauncher.openURL(strFileOrURL);
456                                        // TODO: if used only for display remove ports.
457                                        // TODO: if there is no connected output ports use only for
458                                        // display.
459                                        return;
460                                }
461
462                                // Get the input stream.
463                                URL url = new URL(strFileOrURL);
464                                in = new InputStreamReader(url.openStream());
465
466                                // in = _getURLReader(strFileOrURL);
467                        }
468                        // THIS CODE ASSUMES THAT THERE WILL BE JUST ONE FORM IN THE HTML!!!
469
470                        BufferedReader br = new BufferedReader(in);
471                        String line;
472
473                        // TODO: perhaps a better approach is necessary here
474                        // (not to save the whole file content to ram).
475                        StringBuffer sbContent = new StringBuffer();
476
477                        while ((line = br.readLine()) != null) {
478                                int beginFormTagInd = line.toLowerCase().indexOf("<form ");
479                                if (beginFormTagInd != -1) {
480                                        int endFormTagInd = line.toLowerCase().indexOf(">",
481                                                        beginFormTagInd + 5);
482                                        String formTag = "";
483                                        if (endFormTagInd > -1) {
484                                                formTag = line.substring(beginFormTagInd,
485                                                                endFormTagInd + 1);
486                                        } else
487                                                formTag = line.substring(beginFormTagInd);
488
489                                        String formLine = line;
490                                        while (endFormTagInd == -1) {
491                                                formLine = br.readLine();
492                                                endFormTagInd = formLine.toLowerCase().indexOf(">");
493                                                if (endFormTagInd > -1) {
494                                                        formTag += formLine.substring(0, endFormTagInd + 1);
495                                                } else
496                                                        formTag = formLine;
497
498                                        }
499                                        formTag = _processFormTag(formTag);
500                                        line = line.substring(0, beginFormTagInd) + formTag
501                                                        + formLine.substring(endFormTagInd + 1);
502                                }
503                                int closeFormInd = line.toLowerCase().indexOf("</form>");
504                                if (closeFormInd != -1) {
505                                        // the file has a form.
506                                        hasForm = true;
507                                        sbContent.append(line.substring(0, closeFormInd) + "\n");
508                                        // Generate a universal id for the request
509                                        _procID = _uuidgen.generateUUID();
510
511                                        // Append the form in the html source with "extraLine" that
512                                        // has the id.
513                                        String extraLine = "<input type=\"hidden\" name=\"ptid\" value=\""
514                                                        + _procID + "\"/>";
515
516                                        sbContent.append(extraLine + "\n");
517                                        sbContent.append(line.substring(closeFormInd) + "\n");
518                                } else {
519                                        sbContent.append(line + "\n");
520                                }
521                        }
522                        br.close();
523                        String contentFileToDisplay = "";
524                        if (!hasForm) {
525                                // if this is a file content, write it to a temp file and
526                                // display.
527                                if (fileContentFlag) {
528                                        strFileOrURL = _writeContentToFile(sbContent.toString());
529                                }
530                                BrowserLauncher.openURL(strFileOrURL);
531                                return;
532                        } else { // if there is a form.
533                                if (!fileContentFlag) {
534                                        // TODO: if this is a file or a url. replace relative paths
535                                        // (A6). --- Efrat: Replace relative paths in general
536                                }
537                                if (_ext.equals("")) {
538                                        _ext = ".html";
539                                }
540                                strFileOrURL = _writeContentToFile(sbContent.toString());
541                                BrowserLauncher.openURL(strFileOrURL);
542
543                                // FIXME: change to kepler server.
544                                String fetchURL = serverPath + "?ptid="
545                                                + _procID;
546                                System.out.println("fetchURL:  " + fetchURL + "\n");
547                                URL url = new URL(fetchURL);
548
549                                String xml = _getUserResponse(url);
550                                xmlOutput.broadcast(new XMLToken(xml));
551
552                                // create name value pairs and broadcast response if
553                                // _namedPortsExists.
554                                if (_namedPortsExist) {
555                                        _sendValuesToNamedPorts(xml);
556                                }
557                        }
558
559                } catch (Exception ex) {
560                        ex.printStackTrace();
561                        if (contentDisplayFile != null) {
562                                if (contentDisplayFile.exists()) {
563                                        contentDisplayFile.delete();
564                                }
565                        }
566                        throw new IllegalActionException(this,
567                        "An exception occured in actor " + this.getName() + ":"
568                                        + ex.getMessage());
569//                      try {
570//                              if (server != null)
571//                              {
572//                                      server.stopServer();
573//                                      server = null;
574//                              }
575//                      } catch (IOException e) {
576//                              // TODO Auto-generated catch block
577//                              e.printStackTrace();
578//                              throw new IllegalActionException("exception in actor " + this.getName() + ":" + e.getMessage());
579//                      }                       
580//                      throw new IllegalActionException(this,
581//                                      "An exception occured in actor " + this.getName() + ":"
582//                                                      + ex.getMessage());
583                }
584        } // end of fire
585
586        public void initialize() throws IllegalActionException {
587
588                // create the unique id generator.
589                _uuidgen = new UUIDGen();
590
591                // Get the useForDisplay parameter or verify whether to just display the
592                // url.
593                forDisplay = ((BooleanToken) useForDisplay.getToken()).booleanValue();
594                
595                
596
597                // Set the path to the backend server.
598    ConfigurationManager confMan = ConfigurationManager.getInstance();
599    //get the specific configuration we want
600    ConfigurationProperty commonProperty = confMan.getProperty(ConfigurationManager.getModule("common"));
601    ConfigurationProperty serversProperty = commonProperty.getProperty("servers.server");
602    ConfigurationProperty geonProperty = serversProperty.findProperties("name", "geon").get(0);
603    serverUrl = geonProperty.getProperty("url").getValue();
604        serverPort = new Integer (geonProperty.getProperty("port").getValue()).intValue();
605        serverContext = geonProperty.getProperty("context").getValue();
606        if (maxWaitTime.getToken() == null)
607                serverMaxWaitTime = new Long (geonProperty.getProperty("maxWaitTime").getValue()).longValue();
608        else
609                serverMaxWaitTime = ((LongToken) maxWaitTime.getToken()).longValue();
610        serverPath = serverUrl + ":" + serverPort + "/" + serverContext;
611    
612                // If there are no connected output ports - set forDisplay to be true.
613                if (!forDisplay) {
614                        List outputPorts = outputPortList();
615                        Iterator outputPortsIterator = outputPorts.iterator();
616                        // check whether this actor is a sink.
617                        boolean isSink = true;
618                        while (outputPortsIterator.hasNext()) {
619                                IOPort p = (IOPort) outputPortsIterator.next();
620                                if (p.getWidth() > 0) {
621                                        // the actor is not a sink.
622                                        isSink = false;
623                                        break;
624                                }
625                        }
626                        if (isSink) {
627                                forDisplay = true;
628                        }
629                }
630
631                try {
632                        server = new BrowserUIServer();
633                        server.startServer(serverContext, serverPort);
634                } catch (IOException e) {
635                        // TODO Auto-generated catch block
636                        e.printStackTrace();
637                        throw new IllegalActionException("exception in actor " + this.getName() + ":" + e.getMessage());
638                }
639        }
640
641        /**
642         * Post fire the actor. Return false to indicate that the process has
643         * finished. If it returns true, the process will continue indefinitely.
644         */
645        public boolean postfire() throws IllegalActionException {
646
647                if (contentDisplayFile != null) {
648                        if (contentDisplayFile.exists()) {
649                                contentDisplayFile.delete();
650                        }
651                }
652                contentDisplayFile = null;
653
654                if (_reFire)
655                        return super.postfire();
656                else
657                        return _reFire;
658                        
659        } // end of postfire
660
661        /**
662         * Wrapup the actor. Set _reFire to true.
663         */
664        public void wrapup() throws IllegalActionException {
665//              try {
666//                      if (server != null)
667//                      {
668//                              server.stopServer();
669//                              server = null;
670//                      }                       
671//              } catch (IOException e) {
672//                      // TODO Auto-generated catch block
673//                      e.printStackTrace();
674//                      throw new IllegalActionException("exception in actor " + this.getName() + ":" + e.getMessage());
675//              }
676
677                if (contentDisplayFile != null) {
678                        if (contentDisplayFile.exists()) {
679                                contentDisplayFile.delete();
680                        }
681                }
682                contentDisplayFile = null;
683                _reFire = true;
684        }
685
686        private Map _createNameValuePairs(String xml) {
687
688                Map output = new HashMap();
689                while (!xml.trim().equals("</xmp>")) {
690
691                        int indStart = xml.toLowerCase().indexOf("<name>");
692                        if (indStart == -1) { // no name tag - return output hashmap.
693                                return output;
694                        }
695                        int indEnd = xml.toLowerCase().indexOf("</name>");
696                        String currentParamName = xml.substring(indStart + 6, indEnd);
697                        xml = xml.substring(indEnd + 7);
698                        indStart = xml.toLowerCase().indexOf("<value>");
699                        indEnd = xml.toLowerCase().indexOf("</value>");
700                        String currentParamValue = xml.substring(indStart + 7, indEnd);
701                        xml = xml.substring(indEnd + 8);
702
703                        output.put(currentParamName, currentParamValue);
704                }
705                return output;
706        }
707
708        private String _getUserResponse(URL url) throws IllegalActionException {
709                long startTime  = System.currentTimeMillis();
710                long currentTime  = System.currentTimeMillis();
711
712                while (serverMaxWaitTime < 0 || currentTime < (startTime + (serverMaxWaitTime * 1000))) {
713                        HttpURLConnection urlconn;
714                        try {
715                                urlconn = (HttpURLConnection) url.openConnection();
716                                urlconn.connect();
717                                try {
718                                        Thread.sleep(5000);
719                                } catch (InterruptedException e1) {
720                                        // TODO Auto-generated catch block
721                                        e1.printStackTrace();
722                                }
723                                BufferedReader br = new BufferedReader(new InputStreamReader(
724                                                urlconn.getInputStream()));
725                                String line = br.readLine();
726                                String resp = "";
727                                while (line != null) {
728                                        resp += line + "\n";
729                                        line = br.readLine();
730                                }
731                                br.close();
732                                urlconn.disconnect();
733
734                                int xmpInd = resp.toLowerCase().indexOf("<xmp>");
735                                if (xmpInd != -1) {
736                                        return resp;
737                                }
738                        } catch (IOException e) {
739                                // TODO Auto-generated catch block
740                                e.printStackTrace();
741                        }
742                        currentTime  = System.currentTimeMillis();
743                }
744                throw new IllegalActionException("Operation timed out in actor "
745                                + this.getName() + ".");
746        }
747
748        private void _sendValuesToNamedPorts(String xml)
749                        throws IllegalActionException {
750                Map pairs = _createNameValuePairs(xml);
751                List outputPorts = this.outputPortList();
752                Iterator outputs = outputPorts.iterator();
753                while (outputs.hasNext()) {
754                        IOPort p = (IOPort) outputs.next();
755                        String portName = p.getName();
756                        if (!portName.equals("xmlOutput")) {
757                                String value = (String) pairs.get(portName);
758                                // TODO: by port configuration convert the string to the desired
759                                // type.
760
761                                p.broadcast(new StringToken(value));
762                        }
763                }
764        }
765
766        /**
767         * if this is a file with no extension, just display it. if this is a url
768         * with no extension, it can have a form.
769         */
770        private boolean _isDisplayExtension(URL pfileOrURL) {
771                String path = pfileOrURL.getPath();
772                String _fileExtension = "";
773                int lastDotInd = path.lastIndexOf(".");
774                // there is an extension.
775                if (lastDotInd > -1) {
776                        _fileExtension = path.substring(lastDotInd);
777                        _fileExtension = _fileExtension.trim();
778                        String ext = _fileExtension.toLowerCase();
779                        if (_extensions.contains(ext))
780                                return true;
781                        else
782                                return false;
783                } else { // there is no extension.
784                        return false;
785                }
786        }
787
788        /**
789         * This function accepts the form tab and sets the post action.
790         * 
791         * @param formTag
792         *       */
793        private String _processFormTag(String formTag) {
794                int actionInd = formTag.toLowerCase().indexOf("action");
795                actionLine = "action=\"" + serverPath + "\"";
796                // if there is already an action - overide it.
797                if (actionInd > -1) {
798                        int firstquoteInd = formTag.indexOf("\"", actionInd + 1);
799                        int endActionInd = -1;
800                        if (firstquoteInd == -1) {
801                                firstquoteInd = formTag.indexOf("'", actionInd + 1);
802                                endActionInd = formTag.indexOf("'", firstquoteInd + 1);
803                        } else {
804                                endActionInd = formTag.indexOf("\"", firstquoteInd + 1);
805                        }
806                        if (firstquoteInd == -1) { // no action tag value
807                                formTag = formTag.substring(0, actionInd) + actionLine
808                                                + formTag.substring(actionInd + 6);
809                        } else {
810                                formTag = formTag.substring(0, actionInd) + actionLine
811                                                + formTag.substring(endActionInd + 1);
812                        }
813                }
814                // else add action
815                else
816                        formTag = formTag.substring(0, 6) + actionLine
817                                        + formTag.substring(6);
818
819                return formTag;
820        }
821
822        private void _setOutputPorts(List ports) throws IllegalActionException {
823                // remove unnecessary ports
824                List outputPorts = this.outputPortList();
825                Iterator it = outputPorts.iterator();
826                while (it.hasNext()) {
827                        IOPort iop = (IOPort) it.next();
828                        if (!ports.contains(iop.getName())
829                                        && !iop.getName().equals("xmlOutput"))
830                                try {
831                                        iop.setContainer(null);
832                                } catch (NameDuplicationException nex) {
833                                        throw new IllegalActionException(this, nex.getMessage()
834                                                        + " Could not delete port " + iop.getName()
835                                                        + " to actor " + this.getName());
836                                }
837
838                }
839                // create desired ports and set types for existing ones.
840                outputPorts = this.outputPortList();
841                for (int i = 0; i < ports.size(); i++) {
842                        it = outputPorts.iterator();
843                        boolean portExists = false; // checking whether the output port
844                                                                                // exists.
845                        while (it.hasNext()) {
846                                TypedIOPort p = (TypedIOPort) it.next();
847                                if (p.getName().equals((String) ports.get(i))) {
848                                        p.setTypeEquals(BaseType.STRING);
849                                        portExists = true;
850                                        break;
851                                }
852                        }
853                        if (!portExists) {
854                                try {
855                                        TypedIOPort iop = new TypedIOPort(this, (String) ports
856                                                        .get(i), false, true);
857                                        iop.setTypeEquals(BaseType.STRING);
858                                        new Attribute(iop, "_showName");
859                                } catch (NameDuplicationException ex) {
860                                        throw new IllegalActionException(ex.getMessage()
861                                                        + " Actor " + this.getName()
862                                                        + " already contains a port " + "named "
863                                                        + (String) ports.get(i));
864                                }
865                        }
866                }
867        }
868
869        /**
870         * Writes the content input to a uniquely identified file.
871         * 
872         * @param content
873         *       * @throws IOException
874         */
875        private String _writeContentToFile(String content) throws IOException {
876                String contentFileToDisplay = _uuidgen.generateUUID() + _ext;
877                contentDisplayFile = new File(System.getProperty("user.home") + File.separator + contentFileToDisplay);
878                String strFileOrURL = contentDisplayFile.getAbsolutePath();
879                BufferedWriter out = new BufferedWriter(new FileWriter(strFileOrURL,
880                                false));
881                out.write(content);
882                out.close();
883                return strFileOrURL;
884
885        }
886
887        // /////////////////////////////////////////////////////////////////
888        // // private members ////
889
890        // a flag to verify whether the html contains a form.
891        private boolean _reFire = true;
892
893        private static Set _extensions = new TreeSet();
894
895        static {
896
897                _extensions.add(".xml");
898                _extensions.add(".xsl");
899                _extensions.add(".gif");
900                _extensions.add(".jpg");
901                _extensions.add(".jpeg");
902                _extensions.add(".svg");
903                _extensions.add(".pdf");
904                _extensions.add(".ps");
905                _extensions.add(".ppt");
906                _extensions.add(".doc");
907                _extensions.add(".pps");
908                _extensions.add(".txt");
909                _extensions.add(".zip");
910                // _extensions.add(""); - would cause an unentered extension to be a
911                // display extension..
912
913        }
914
915        private boolean _triggerFlag = false;
916        private File contentDisplayFile = null;
917        // private String _fileExtension = "";
918        private String _absoluteFilePathToDisplay = "";
919        private String _procID = "";
920        private boolean forDisplay;
921        private String _ext = "";
922
923        /**
924         * The unique id generator.
925         */
926        private UUIDGen _uuidgen;
927
928        /**
929         * Specifies whether to broadcast response to name ports set by the
930         * configuration parameter.
931         */
932        private boolean _namedPortsExist = false;
933
934        /**
935         * Represents the server post action URL.
936         */
937        private String actionLine = "";
938
939        // private static final String ACTIONLINE =
940        // "action=\"http://geon01.sdsc.edu:8080/pt2/jsp/pts.jsp\"";
941
942        /**
943         * Path to the geon server url in the config file.
944         */
945        private static final String SERVERPATH = "//servers/server[@name=\"geon\"]/url";
946
947        /**
948         * URL to backend server
949         */
950        private String serverPath = "";
951
952    private String serverUrl = "";
953
954        private int serverPort= 0;
955
956        private long serverMaxWaitTime = 0;
957
958    private String serverContext = "";
959
960        private BrowserUIServer server = null;
961
962}