1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 package com.sun.star.comp.beans; 25 26 import java.awt.Container; 27 import java.io.File; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Vector; 31 32 import com.sun.star.lang.XMultiComponentFactory; 33 import com.sun.star.lang.XComponent; 34 import com.sun.star.lang.XEventListener; 35 import com.sun.star.connection.XConnection; 36 import com.sun.star.connection.XConnector; 37 import com.sun.star.bridge.XBridge; 38 import com.sun.star.bridge.XBridgeFactory; 39 import com.sun.star.beans.XPropertySet; 40 import com.sun.star.uno.XComponentContext; 41 import com.sun.star.uno.UnoRuntime; 42 import com.sun.star.uno.Exception; 43 import com.sun.star.lib.uno.helper.UnoUrl; 44 import com.sun.star.lib.util.NativeLibraryLoader; 45 46 /** 47 * This class reprecents a connection to the local office application. 48 * 49 * @since OOo 2.0.0 50 */ 51 public class LocalOfficeConnection 52 implements OfficeConnection 53 { 54 public static final String OFFICE_APP_NAME = "soffice"; 55 public static final String OFFICE_LIB_NAME = "officebean"; 56 public static final String OFFICE_ID_SUFFIX = "_Office"; 57 58 private static String mProgramPath; 59 60 private Process mProcess; 61 private ContainerFactory mContainerFactory; 62 private XComponentContext mContext; 63 private XBridge mBridge; 64 65 private String mURL; 66 private String mConnType; 67 private String mPipe; 68 private String mPort; 69 private String mProtocol; 70 private String mInitialObject; 71 72 private List mComponents = new Vector(); 73 74 private static long m_nBridgeCounter = 0; 75 //------------------------------------------------------------------------- 76 static 77 { 78 // preload shared libraries whichs import lips are linked to officebean 79 if ( System.getProperty( "os.name" ).startsWith( "Windows" ) ) 80 { 81 try 82 { LocalOfficeConnection.class.getClassLoader()83 NativeLibraryLoader.loadLibrary(LocalOfficeConnection.class.getClassLoader(), "msvcr70"); 84 } 85 catch (Throwable e) 86 { 87 // loading twice would fail 88 System.err.println( "cannot find msvcr70" ); 89 } 90 91 try 92 { LocalOfficeConnection.class.getClassLoader()93 NativeLibraryLoader.loadLibrary(LocalOfficeConnection.class.getClassLoader(), "msvcr71"); 94 } 95 catch (Throwable e) 96 { 97 // loading twice would fail 98 System.err.println( "cannot find msvcr71" ); 99 } 100 101 try 102 { LocalOfficeConnection.class.getClassLoader()103 NativeLibraryLoader.loadLibrary(LocalOfficeConnection.class.getClassLoader(), "uwinapi"); 104 } 105 catch (Throwable e) 106 { 107 // loading twice would fail 108 System.err.println( "cannot find uwinapi" ); 109 } 110 111 try 112 { LocalOfficeConnection.class.getClassLoader()113 NativeLibraryLoader.loadLibrary(LocalOfficeConnection.class.getClassLoader(), "jawt"); 114 } 115 catch (Throwable e) 116 { 117 // loading twice would fail 118 System.err.println( "cannot find jawt" ); 119 } 120 } 121 122 // load shared library for JNI code LocalOfficeConnection.class.getClassLoader()123 NativeLibraryLoader.loadLibrary( LocalOfficeConnection.class.getClassLoader(), "officebean" ); 124 } 125 126 //------------------------------------------------------------------------- 127 // debugging method dbgPrint( String aMessage )128 private void dbgPrint( String aMessage ) 129 { 130 System.err.println( aMessage ); 131 } 132 133 /** 134 * Constructor. 135 * Sets up paths to the office application and native libraries if 136 * values are available in <code>OFFICE_PROP_FILE</code> in the user 137 * home directory.<br /> 138 * "com.sun.star.beans.path" - the office application directory;<br/> 139 * "com.sun.star.beans.libpath" - native libraries directory. 140 */ LocalOfficeConnection()141 public LocalOfficeConnection() 142 { 143 // init member vars 144 try 145 { 146 setUnoUrl( "uno:pipe,name=" + getPipeName() + ";urp;StarOffice.ServiceManager" ); 147 } 148 catch ( java.net.MalformedURLException e ) 149 {} 150 } 151 152 /** 153 * protected Constructor 154 * Initialise a LocalOfficeConnection with an already running office. 155 * This C'Tor is only used in complex tests at the moment. 156 * @param xContext 157 */ LocalOfficeConnection(com.sun.star.uno.XComponentContext xContext)158 protected LocalOfficeConnection(com.sun.star.uno.XComponentContext xContext) 159 { 160 this.mContext = xContext; 161 } 162 163 /** 164 * Sets a connection URL. 165 * This implementation accepts a UNO URL with following format:<br /> 166 * <pre> 167 * url := uno:localoffice[,<params>];urp;StarOffice.ServiceManager 168 * params := <path>[,<pipe>] 169 * path := path=<pathv> 170 * pipe := pipe=<pipev> 171 * pathv := platform_specific_path_to_the_local_office_distribution 172 * pipev := local_office_connection_pipe_name 173 * </pre> 174 * 175 * @param url This is UNO URL which discribes the type of a connection. 176 */ setUnoUrl(String url)177 public void setUnoUrl(String url) 178 throws java.net.MalformedURLException 179 { 180 mURL = null; 181 182 String prefix = "uno:localoffice"; 183 if ( url.startsWith(prefix) ) 184 parseUnoUrlWithOfficePath( url, prefix ); 185 else 186 { 187 try 188 { 189 UnoUrl aURL = UnoUrl.parseUnoUrl( url ); 190 mProgramPath = null; 191 mConnType = aURL.getConnection(); 192 mPipe = (String) aURL.getConnectionParameters().get( "pipe" ); 193 mPort = (String) aURL.getConnectionParameters().get( "port" ); 194 mProtocol = aURL.getProtocol(); 195 mInitialObject = aURL.getRootOid(); 196 } 197 catch ( com.sun.star.lang.IllegalArgumentException eIll ) 198 { 199 throw new java.net.MalformedURLException( 200 "Invalid UNO connection URL."); 201 } 202 } 203 mURL = url; 204 } 205 206 /** 207 * Sets an AWT container catory. 208 * 209 * @param containerFactory This is a application provided AWT container 210 * factory. 211 */ setContainerFactory(ContainerFactory containerFactory)212 public void setContainerFactory(ContainerFactory containerFactory) 213 { 214 mContainerFactory = containerFactory; 215 } 216 217 /** 218 * Retrives the UNO component context. 219 * Establishes a connection if necessary and initialises the 220 * UNO service manager if it has not already been initialised. 221 * This method can return <code>null</code> if it fails to connect 222 * to the office application. 223 * 224 * @return The office UNO component context. 225 */ getComponentContext()226 synchronized public XComponentContext getComponentContext() 227 { 228 if ( mContext == null ) 229 mContext = connect(); 230 return mContext; 231 } 232 233 /** 234 * Creates an office window. 235 * The window is either a sub-class of java.awt.Canvas (local) or 236 * java.awt.Container (RVP). 237 * 238 * @param container This is an AWT container. 239 * @return The office window instance. 240 */ createOfficeWindow(Container container)241 public OfficeWindow createOfficeWindow(Container container) 242 { 243 return new LocalOfficeWindow(this); 244 } 245 246 /** 247 * Closes the connection. 248 */ dispose()249 public void dispose() 250 { 251 Iterator itr = mComponents.iterator(); 252 while (itr.hasNext() == true) { 253 // ignore runtime exceptions in dispose 254 try { ((XEventListener)itr.next()).disposing(null); } 255 catch ( RuntimeException aExc ) {} 256 } 257 mComponents.clear(); 258 259 //Terminate the bridge. It turned out that this is necessary for the bean 260 //to work properly when displayed in an applet within Internet Explorer. 261 //When navigating off the page which is showing the applet and then going 262 //back to it, then the Java remote bridge is damaged. That is the Java threads 263 //do not work properly anymore. Therefore when Applet.stop is called the connection 264 //to the office including the bridge needs to be terminated. 265 if (mBridge != null) 266 { 267 XComponent comp = (XComponent)UnoRuntime.queryInterface( 268 XComponent.class, mBridge); 269 if (comp != null) 270 comp.dispose(); 271 else 272 System.err.println("LocalOfficeConnection: could not dispose bridge!"); 273 274 mBridge = null; 275 } 276 277 mContainerFactory = null; 278 mContext = null; 279 } 280 281 /** 282 * Adds an event listener to the object. 283 * 284 * @param listener is a listener object. 285 */ addEventListener(XEventListener listener)286 public void addEventListener(XEventListener listener) 287 { 288 mComponents.add(listener); 289 } 290 291 /** 292 * Removes an event listener from the listener list. 293 * 294 * @param listener is a listener object. 295 */ removeEventListener(XEventListener listener)296 public void removeEventListener(XEventListener listener) 297 { 298 mComponents.remove(listener); 299 } 300 301 /** 302 * Establishes the connection to the office. 303 */ connect()304 private XComponentContext connect() 305 { 306 try 307 { 308 // create default local component context 309 XComponentContext xLocalContext = 310 com.sun.star.comp.helper.Bootstrap.createInitialComponentContext(null); 311 312 // initial serviceManager 313 XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager(); 314 315 // try to connect to soffice 316 Object aInitialObject = null; 317 try 318 { 319 aInitialObject = resolve(xLocalContext, mURL); 320 } 321 catch( com.sun.star.connection.NoConnectException e ) 322 { 323 // launch soffice 324 OfficeService aSOffice = new OfficeService(); 325 aSOffice.startupService(); 326 327 // wait until soffice is started 328 long nMaxMillis = System.currentTimeMillis() + 1000*aSOffice.getStartupTime(); 329 while ( aInitialObject == null ) 330 { 331 try 332 { 333 // try to connect to soffice 334 Thread.currentThread().sleep( 500 ); 335 aInitialObject = resolve(xLocalContext, mURL); 336 } 337 catch( com.sun.star.connection.NoConnectException aEx ) 338 { 339 // soffice did not start in time 340 if ( System.currentTimeMillis() > nMaxMillis ) 341 throw aEx; 342 343 } 344 } 345 } 346 finally 347 { 348 } 349 350 // XComponentContext 351 if( null != aInitialObject ) 352 { 353 XPropertySet xPropertySet = (XPropertySet) 354 UnoRuntime.queryInterface( XPropertySet.class, aInitialObject); 355 Object xContext = xPropertySet.getPropertyValue("DefaultContext"); 356 XComponentContext xComponentContext = (XComponentContext) UnoRuntime.queryInterface( 357 XComponentContext.class, xContext); 358 return xComponentContext; 359 } 360 } 361 catch( com.sun.star.connection.NoConnectException e ) 362 { 363 System.out.println( "Couldn't connect to remote server" ); 364 System.out.println( e.getMessage() ); 365 } 366 catch( com.sun.star.connection.ConnectionSetupException e ) 367 { 368 System.out.println( "Couldn't access necessary local resource to establish the interprocess connection" ); 369 System.out.println( e.getMessage() ); 370 } 371 catch( com.sun.star.lang.IllegalArgumentException e ) 372 { 373 System.out.println( "uno-url is syntactical illegal ( " + mURL + " )" ); 374 System.out.println( e.getMessage() ); 375 } 376 catch( com.sun.star.uno.RuntimeException e ) 377 { 378 System.out.println( "--- RuntimeException:" ); 379 System.out.println( e.getMessage() ); 380 e.printStackTrace(); 381 System.out.println( "--- end." ); 382 throw e; 383 } 384 catch( java.lang.Exception e ) 385 { 386 System.out.println( "java.lang.Exception: " ); 387 System.out.println( e ); 388 e.printStackTrace(); 389 System.out.println( "--- end." ); 390 throw new com.sun.star.uno.RuntimeException( e.toString() ); 391 } 392 393 return null; 394 } 395 396 397 //The function is copied and adapted from the UrlResolver.resolve. 398 //We cannot use the URLResolver because we need access to the bridge which has 399 //to be disposed when Applet.stop is called. resolve(XComponentContext xLocalContext, String dcp)400 private Object resolve(XComponentContext xLocalContext, String dcp) 401 throws com.sun.star.connection.NoConnectException, 402 com.sun.star.connection.ConnectionSetupException, 403 com.sun.star.lang.IllegalArgumentException 404 { 405 String conDcp = null; 406 String protDcp = null; 407 String rootOid = null; 408 409 if(dcp.indexOf(';') == -1) {// use old style 410 conDcp = dcp; 411 protDcp = "iiop"; 412 rootOid = "classic_uno"; 413 } 414 else { // new style 415 int index = dcp.indexOf(':'); 416 String url = dcp.substring(0, index).trim(); 417 dcp = dcp.substring(index + 1).trim(); 418 419 index = dcp.indexOf(';'); 420 conDcp = dcp.substring(0, index).trim(); 421 dcp = dcp.substring(index + 1).trim(); 422 423 index = dcp.indexOf(';'); 424 protDcp = dcp.substring(0, index).trim(); 425 dcp = dcp.substring(index + 1).trim(); 426 427 rootOid = dcp.trim().trim(); 428 } 429 430 Object rootObject = null; 431 XBridgeFactory xBridgeFactory= null; 432 433 XMultiComponentFactory xLocalServiceManager = xLocalContext.getServiceManager(); 434 try { 435 xBridgeFactory = (XBridgeFactory)UnoRuntime.queryInterface( 436 XBridgeFactory.class, 437 xLocalServiceManager.createInstanceWithContext( 438 "com.sun.star.bridge.BridgeFactory", xLocalContext)); 439 } catch (com.sun.star.uno.Exception e) { 440 throw new com.sun.star.uno.RuntimeException(e.getMessage()); 441 } 442 synchronized(this) { 443 if(mBridge == null) { 444 Object connector= null; 445 try { 446 connector = xLocalServiceManager.createInstanceWithContext( 447 "com.sun.star.connection.Connector", xLocalContext); 448 } catch (com.sun.star.uno.Exception e) { 449 throw new com.sun.star.uno.RuntimeException(e.getMessage()); 450 } 451 XConnector connector_xConnector = (XConnector)UnoRuntime.queryInterface(XConnector.class, connector); 452 // connect to the server 453 XConnection xConnection = connector_xConnector.connect(conDcp); 454 // create the bridge name. This should not be necessary if we pass an 455 //empty string as bridge name into createBridge. Then we should always get 456 //a new bridge. This does not work because of (i51323). Therefore we 457 //create unique bridge names for the current process. 458 String sBridgeName = "OOoBean_private_bridge_" + String.valueOf(m_nBridgeCounter++); 459 try { 460 mBridge = xBridgeFactory.createBridge(sBridgeName, protDcp, xConnection, null); 461 } catch (com.sun.star.bridge.BridgeExistsException e) { 462 throw new com.sun.star.uno.RuntimeException(e.getMessage()); 463 } 464 } 465 rootObject = mBridge.getInstance(rootOid); 466 return rootObject; 467 } 468 } 469 470 471 /** 472 * Retrives a path to the office program folder. 473 * 474 * @return The path to the office program folder. 475 */ getProgramPath()476 static private String getProgramPath() 477 { 478 if (mProgramPath == null) 479 { 480 // determine name of executable soffice 481 String aExec = OFFICE_APP_NAME; // default for UNIX 482 String aOS = System.getProperty("os.name"); 483 484 // running on Windows? 485 if (aOS.startsWith("Windows")) 486 aExec = OFFICE_APP_NAME + ".exe"; 487 488 // add other non-UNIX operating systems here 489 // ... 490 491 // find soffice executable relative to this class's class loader: 492 File path = NativeLibraryLoader.getResource( 493 LocalOfficeConnection.class.getClassLoader(), aExec); 494 if (path != null) 495 mProgramPath = path.getParent(); 496 497 // default is "" 498 if ( mProgramPath == null ) 499 mProgramPath = ""; 500 } 501 return mProgramPath; 502 } 503 504 /** 505 * Parses a connection URL. 506 * This method accepts a UNO URL with following format:<br /> 507 * <pre> 508 * url := uno:localoffice[,<params>];urp;StarOffice.NamingService 509 * params := <path>[,<pipe>] 510 * path := path=<pathv> 511 * pipe := pipe=<pipev> 512 * pathv := platform_specific_path_to_the_local_office_distribution 513 * pipev := local_office_connection_pipe_name 514 * </pre> 515 * 516 * <h4>Examples</h4> 517 * <ul> 518 * <li>"uno:localoffice,pipe=xyz_Office,path=/opt/openoffice11/program;urp;StarOffice.ServiceManager"; 519 * <li>"uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager"; 520 * </ul> 521 * 522 * @param url This is UNO URL which describes the type of a connection. 523 * @exception java.net.MalformedURLException when inappropreate URL was 524 * provided. 525 */ parseUnoUrlWithOfficePath(String url, String prefix)526 private void parseUnoUrlWithOfficePath(String url, String prefix) 527 throws java.net.MalformedURLException 528 { 529 // Extruct parameters. 530 int idx = url.indexOf(";urp;StarOffice.NamingService"); 531 if (idx < 0) 532 throw new java.net.MalformedURLException( 533 "Invalid UNO connection URL."); 534 String params = url.substring(prefix.length(), idx + 1); 535 536 // Parse parameters. 537 String name = null; 538 String path = null; 539 String pipe = null; 540 char ch; 541 int state = 0; 542 StringBuffer buffer = new StringBuffer(); 543 for(idx = 0; idx < params.length(); idx += 1) { 544 ch = params.charAt(idx); 545 switch (state) { 546 case 0: // initial state 547 switch(ch) { 548 case ',': 549 buffer.delete(0, buffer.length()); 550 state = 1; 551 break; 552 553 case ';': 554 state = 7; 555 break; 556 557 default: 558 buffer.delete(0, buffer.length()); 559 buffer.append(ch); 560 state = 1; 561 break; 562 } 563 break; 564 565 case 1: // parameter name 566 switch(ch) { 567 case ' ': 568 case '=': 569 name = buffer.toString(); 570 state = (ch == ' ')? 2: 3; 571 break; 572 573 case ',': 574 case ';': 575 state = -6; // error: invalid name 576 break; 577 578 default: 579 buffer.append(ch); 580 break; 581 } 582 break; 583 584 case 2: // equal between the name and the value 585 switch(ch) { 586 case '=': 587 state = 3; 588 break; 589 590 case ' ': 591 break; 592 593 default: 594 state = -1; // error: missing '=' 595 break; 596 } 597 break; 598 599 case 3: // value leading spaces 600 switch(ch) { 601 case ' ': 602 break; 603 604 default: 605 buffer.delete(0, buffer.length()); 606 buffer.append(ch); 607 state = 4; 608 break; 609 } 610 break; 611 612 case 4: // value 613 switch(ch) { 614 case ' ': 615 case ',': 616 case ';': 617 idx -= 1; // put back the last read character 618 state = 5; 619 if (name.equals("path")) { 620 if (path == null) 621 path = buffer.toString(); 622 else 623 state = -3; // error: more then one 'path' 624 } else if (name.equals("pipe")) { 625 if (pipe == null) 626 pipe = buffer.toString(); 627 else 628 state = -4; // error: more then one 'pipe' 629 } else 630 state = -2; // error: unknown parameter 631 buffer.delete(0, buffer.length()); 632 break; 633 634 default: 635 buffer.append(ch); 636 break; 637 } 638 break; 639 640 case 5: // a delimeter after the value 641 switch(ch) { 642 case ' ': 643 break; 644 645 case ',': 646 state = 6; 647 break; 648 649 case ';': 650 state = 7; 651 break; 652 653 default: 654 state = -5; // error: ' ' inside the value 655 break; 656 } 657 break; 658 659 case 6: // leading spaces before next parameter name 660 switch(ch) { 661 case ' ': 662 break; 663 664 default: 665 buffer.delete(0, buffer.length()); 666 buffer.append(ch); 667 state = 1; 668 break; 669 } 670 break; 671 672 default: 673 throw new java.net.MalformedURLException( 674 "Invalid UNO connection URL."); 675 } 676 } 677 if (state != 7) 678 throw new java.net.MalformedURLException( 679 "Invalid UNO connection URL."); 680 681 // Set up the connection parameters. 682 if (path != null) 683 mProgramPath = path; 684 if (pipe != null) 685 mPipe = pipe; 686 } 687 688 /* replaces each substring aSearch in aString by aReplace. 689 690 StringBuffer.replaceAll() is not avaialable in Java 1.3.x. 691 */ replaceAll(String aString, String aSearch, String aReplace )692 private static String replaceAll(String aString, String aSearch, String aReplace ) 693 { 694 StringBuffer aBuffer = new StringBuffer(aString); 695 696 int nPos = aString.length(); 697 int nOfs = aSearch.length(); 698 699 while ( ( nPos = aString.lastIndexOf( aSearch, nPos - 1 ) ) > -1 ) 700 aBuffer.replace( nPos, nPos+nOfs, aReplace ); 701 702 return aBuffer.toString(); 703 } 704 705 706 /** creates a unique pipe name. 707 */ getPipeName()708 static String getPipeName() 709 { 710 // turn user name into a URL and file system safe name (% chars will not work) 711 String aPipeName = System.getProperty("user.name") + OFFICE_ID_SUFFIX; 712 aPipeName = replaceAll( aPipeName, "_", "%B7" ); 713 return replaceAll( replaceAll( java.net.URLEncoder.encode(aPipeName), "+", "%20" ), "%", "_" ); 714 } 715 716 /** 717 * @para This is an implementation of the native office service. 718 */ 719 private class OfficeService 720 implements NativeService 721 { 722 /** 723 * Retrive the office service identifier. 724 * 725 * @return The identifier of the office service. 726 */ getIdentifier()727 public String getIdentifier() 728 { 729 if ( mPipe == null) 730 return getPipeName(); 731 else 732 return mPipe; 733 } 734 735 /** 736 * Starts the office process. 737 */ startupService()738 public void startupService() 739 throws java.io.IOException 740 { 741 int nSizeCmdArray = 4; 742 String sOption = null; 743 //examine if user specified command-line options in system properties. 744 //We may offer later a more sophisticated way of providing options if 745 //the need arises. Currently this is intended to ease the pain during 746 //development with pre-release builds of OOo where one wants to start 747 //OOo with the -norestore options. The value of the property is simple 748 //passed on to the Runtime.exec call. 749 try { 750 sOption = System.getProperty("com.sun.star.officebean.Options"); 751 if (sOption != null) 752 nSizeCmdArray ++; 753 } catch (java.lang.SecurityException e) 754 { 755 e.printStackTrace(); 756 } 757 // create call with arguments 758 String[] cmdArray = new String[nSizeCmdArray]; 759 760 // read UNO_PATH environment variable to get path to soffice binary 761 String unoPath = System.getenv("UNO_PATH"); 762 if (unoPath == null) 763 throw new java.io.IOException( "UNO_PATH environment variable is not set (required system path to the office program directory)" ); 764 765 // cmdArray[0] = (new File(getProgramPath(), OFFICE_APP_NAME)).getPath(); 766 cmdArray[0] = (new File(unoPath, OFFICE_APP_NAME)).getPath(); 767 cmdArray[1] = "-nologo"; 768 cmdArray[2] = "-nodefault"; 769 if ( mConnType.equals( "pipe" ) ) 770 cmdArray[3] = "-accept=pipe,name=" + getIdentifier() + ";" + 771 mProtocol + ";" + mInitialObject; 772 else if ( mConnType.equals( "socket" ) ) 773 cmdArray[3] = "-accept=socket,port=" + mPort + ";urp"; 774 else 775 throw new java.io.IOException( "not connection specified" ); 776 777 if (sOption != null) 778 cmdArray[4] = sOption; 779 780 // start process 781 mProcess = Runtime.getRuntime().exec(cmdArray); 782 if ( mProcess == null ) 783 throw new RuntimeException( "cannot start soffice: " + cmdArray ); 784 new StreamProcessor(mProcess.getInputStream(), System.out); 785 new StreamProcessor(mProcess.getErrorStream(), System.err); 786 } 787 788 /** 789 * Retrives the ammount of time to wait for the startup. 790 * 791 * @return The ammount of time to wait in seconds(?). 792 */ getStartupTime()793 public int getStartupTime() 794 { 795 return 60; 796 } 797 } 798 799 800 801 class StreamProcessor extends Thread 802 { 803 java.io.InputStream m_in; 804 java.io.PrintStream m_print; 805 StreamProcessor(final java.io.InputStream in, final java.io.PrintStream out)806 public StreamProcessor(final java.io.InputStream in, final java.io.PrintStream out) 807 { 808 m_in = in; 809 m_print = out; 810 start(); 811 } 812 run()813 public void run() { 814 java.io.BufferedReader r = new java.io.BufferedReader( 815 new java.io.InputStreamReader(m_in) ); 816 try { 817 for ( ; ; ) { 818 String s = r.readLine(); 819 if ( s == null ) { 820 break; 821 } 822 m_print.println(s); 823 } 824 } catch ( java.io.IOException e ) { 825 e.printStackTrace( System.err ); 826 } 827 } 828 } 829 830 } 831