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}