1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 package mod._dbaccess; 29 30 import java.io.PrintWriter; 31 import java.util.Vector; 32 33 import lib.Status; 34 import lib.StatusException; 35 import lib.TestCase; 36 import lib.TestEnvironment; 37 import lib.TestParameters; 38 import util.DBTools; 39 import util.utils; 40 41 import com.sun.star.beans.PropertyValue; 42 import com.sun.star.beans.XPropertySet; 43 import com.sun.star.lang.XComponent; 44 import com.sun.star.lang.XMultiServiceFactory; 45 import com.sun.star.sdb.CommandType; 46 import com.sun.star.sdb.ParametersRequest; 47 import com.sun.star.sdb.XInteractionSupplyParameters; 48 import com.sun.star.sdbc.XConnection; 49 import com.sun.star.sdbc.XResultSet; 50 import com.sun.star.sdbc.XResultSetUpdate; 51 import com.sun.star.sdbc.XRow; 52 import com.sun.star.sdbc.XRowSet; 53 import com.sun.star.sdbc.XRowUpdate; 54 import com.sun.star.task.XInteractionAbort; 55 import com.sun.star.task.XInteractionContinuation; 56 import com.sun.star.task.XInteractionRequest; 57 import com.sun.star.ucb.AuthenticationRequest; 58 import com.sun.star.uno.UnoRuntime; 59 import com.sun.star.uno.XInterface; 60 import com.sun.star.util.XCloseable; 61 import com.sun.star.frame.XModel; 62 import com.sun.star.sdb.RowChangeEvent; 63 import com.sun.star.sdbc.SQLException; 64 import com.sun.star.sdbc.XParameters; 65 import ifc.sdb._XCompletedExecution; 66 import util.db.DataSource; 67 import util.db.DataSourceDescriptor; 68 69 /** 70 * Test for object which is represented by service 71 * <code>com.sun.star.sdb.RowSet</code>. <p> 72 * 73 * The following files used by this test : 74 * <ul> 75 * <li><b> TestDB/TestDB.dbf </b> : the database file with some 76 * predefined fields described in <code>util.DBTools</code>. 77 * The copy of this file is always made in temp directory for 78 * testing purposes.</li> 79 * </ul> 80 * The following parameters in ini-file used by this test: 81 * <ul> 82 * <li><code>test.db.url</code> - URL to MySQL database. 83 * For example: <code>mysql://mercury:3306/api_current</code></li> 84 * <li><code>test.db.user</code> - user for MySQL database</li> 85 * <li><code>test.db.password</code> - password for MySQL database</li> 86 * </ul> 87 * 88 * @see com.sun.star.sdbc.RowSet 89 * @see com.sun.star.sdbcx.XRowLocate 90 * @see com.sun.star.sdbc.XResultSetUpdate 91 * @see com.sun.star.util.XCancellable 92 * @see com.sun.star.sdbc.XParameters 93 * @see com.sun.star.sdbc.XResultSetMetaDataSupplier 94 * @see com.sun.star.sdbcx.XDeleteRows 95 * @see com.sun.star.sdbc.XCloseable 96 * @see com.sun.star.sdbcx.XColumnsSupplier 97 * @see com.sun.star.sdb.XResultSetAccess 98 * @see com.sun.star.sdbc.XResultSet 99 * @see com.sun.star.sdbc.XColumnLocate 100 * @see com.sun.star.sdbc.XRowSet 101 * @see com.sun.star.sdb.RowSet 102 * @see com.sun.star.sdbc.XRowUpdate 103 * @see com.sun.star.sdb.XRowSetApproveBroadcaster 104 * @see com.sun.star.beans.XPropertySet 105 * @see com.sun.star.sdbc.XRow 106 * @see com.sun.star.sdbc.XWarningsSupplier 107 * @see com.sun.star.lang.XComponent 108 * @see com.sun.star.sdbcx.ResultSet 109 * @see com.sun.star.sdbc.ResultSet 110 * @see ifc.sdbc._RowSet 111 * @see ifc.sdbcx._XRowLocate 112 * @see ifc.sdbc._XResultSetUpdate 113 * @see ifc.util._XCancellable 114 * @see ifc.sdbc._XParameters 115 * @see ifc.sdbc._XResultSetMetaDataSupplier 116 * @see ifc.sdbcx._XDeleteRows 117 * @see ifc.sdbc._XCloseable 118 * @see ifc.sdbcx._XColumnsSupplier 119 * @see ifc.sdb._XResultSetAccess 120 * @see ifc.sdbc._XResultSet 121 * @see ifc.sdbc._XColumnLocate 122 * @see ifc.sdbc._XRowSet 123 * @see ifc.sdb._RowSet 124 * @see ifc.sdbc._XRowUpdate 125 * @see ifc.sdb._XRowSetApproveBroadcaster 126 * @see ifc.beans._XPropertySet 127 * @see ifc.sdbc._XRow 128 * @see ifc.sdbc._XWarningsSupplier 129 * @see ifc.lang._XComponent 130 * @see ifc.sdbcx._ResultSet 131 * @see ifc.sdbc._ResultSet 132 */ 133 public class ORowSet extends TestCase { 134 135 private static int uniqueSuffix = 0 ; 136 private DBTools dbTools = null ; 137 private static String origDB = null ; 138 String tableName = null; 139 DataSourceDescriptor srcInf = null; 140 boolean isMySQLDB = false; 141 protected final static String dbSourceName = "ORowSetDataSource"; 142 public XConnection m_connection = null; 143 private Object m_rowSet = null; 144 private DataSource m_dataSource; 145 private String m_tableFile; 146 private XMultiServiceFactory m_orb = null; 147 148 /** 149 * Initializes some class fields. Then creates DataSource, which serves 150 * as a single source for all tables created in the test. 151 * This DataSource then registered in the global 152 * <code>DatabaseContext</code> service. This data source's URL 153 * points to SOffice temp directory where tables are copied from 154 * <code>TestDocuments</code> directory on every environment 155 * creation. 156 * To create DataSource for MySQL database next parameters required 157 * in ini-file: 158 * <ul> 159 * <li><code>test.db.url</code> - URL to MySQL database. 160 * For example: <code>mysql://mercury:3306/api_current</code></li> 161 * <li><code>test.db.user</code> - user for MySQL database</li> 162 * <li><code>test.db.password</code> - password for MySQL database</li> 163 * </ul> 164 * 165 * @throws StatusException if DataSource can not be created or 166 * registered. 167 */ 168 protected void initialize ( TestParameters Param, PrintWriter _log) 169 throws StatusException 170 { 171 m_orb = (XMultiServiceFactory)Param.getMSF(); 172 173 String tmpDir = utils.getOfficeTemp( m_orb ); 174 175 origDB = util.utils.getFullTestDocName("TestDB/testDB.dbf"); 176 177 dbTools = new DBTools( m_orb, _log ); 178 179 // creating DataSource and registering it in DatabaseContext 180 String dbURL = (String) Param.get("test.db.url"); 181 String dbUser = (String) Param.get("test.db.user"); 182 String dbPassword = (String) Param.get("test.db.password"); 183 184 log.println("Creating and registering DataSource ..."); 185 srcInf = new DataSourceDescriptor( m_orb ); 186 if (dbURL != null && dbUser != null && dbPassword != null) 187 { 188 isMySQLDB = true; 189 log.println("dbURL = " + dbURL); 190 log.println("dbUSER = " + dbUser); 191 log.println("dbPASSWORD = " + dbPassword); 192 //DataSource for mysql db 193 tableName = "soffice_test_table"; 194 srcInf.URL = "jdbc:" + dbURL; 195 srcInf.IsPasswordRequired = new Boolean(true); 196 srcInf.Password = dbPassword; 197 srcInf.User = dbUser; 198 PropertyValue[] propInfo = new PropertyValue[1]; 199 propInfo[0] = new PropertyValue(); 200 propInfo[0].Name = "JavaDriverClass"; 201 propInfo[0].Value = "org.gjt.mm.mysql.Driver"; 202 srcInf.Info = propInfo; 203 } 204 else 205 { 206 srcInf.URL = "sdbc:dbase:" + DBTools.dirToUrl(tmpDir); 207 } 208 m_dataSource = srcInf.createDataSource(); 209 m_dataSource.registerAs( dbSourceName, true ); 210 } 211 212 /** 213 * Creating a Testenvironment for the interfaces to be tested. 214 * The database (DBF) file is copied from test document directory 215 * into SOffice temp dir with unique name for each enviroment 216 * creation. If the file cann't be copied (is not released) 217 * then another unique name is used (file name suffix incremented 218 * by 1).<p> 219 * 220 * <code>com.sun.star.sdb.RowSet</code> service created and its 221 * source is all rows from the current copy of the table. Then 222 * row set command ("select all rows from a table") is executed 223 * and cursor is positioned to the first row. <p> 224 * 225 * Object relations created : 226 * <ul> 227 * <li> <code>'ORowSet.Connection'</code> for 228 * internal component test usage. Is used for 229 * closing connection when cleaning up environment. </li> 230 * <li> <code>'XRowSetApproveBroadcaster.ApproveChecker'</code> for 231 * {@link ifc.sdb._XRowSetApproveBroadcaster} interface 232 * implementation which made actions required </li> 233 * <li> <code>'CurrentRowData'</code> for 234 * {@link ifc.sdbc._XRow}, {@link ifc.sdbc._XRowUpdate} : 235 * exports types and values of the current row data.</li> 236 * <li> <code>'XColumnLocate.ColumnName'</code> for 237 * {@link ifc.sdbc._XColumnLocate} : 238 * the name of the first column of the table.</li> 239 * <li> <code>'XParameters.ParamValues'</code> for 240 * {@link ifc.sdbc._XParameters} : 241 * Collection of parameter types presented in the query. </li> 242 * <li> <code>'XRowUpdate.XRow'</code> for 243 * {@link ifc.sdbc._XRowUpdate} : 244 * <code>XRow</code> interface of the current component.</li> 245 * <li> <code>'XResultSetUpdate.UpdateTester'</code> for 246 * {@link ifc.sdbc._XResultSetUpdate} </li> 247 * </ul> 248 * 249 * @see com.sun.star.sdb.DatabaseContext 250 * @see com.sun.star.sdb.DataSource 251 */ 252 protected TestEnvironment createTestEnvironment(TestParameters Param, 253 PrintWriter log) 254 { 255 XMultiServiceFactory orb = (XMultiServiceFactory)Param.getMSF(); 256 uniqueSuffix++; 257 boolean envCreatedOK = false ; 258 259 //initialize test table 260 if (isMySQLDB) 261 { 262 try 263 { 264 DBTools.DataSourceInfo legacyDescriptor = dbTools.newDataSourceInfo(); 265 legacyDescriptor.Name = srcInf.Name; 266 legacyDescriptor.User = srcInf.User; 267 legacyDescriptor.Password = srcInf.Password; 268 legacyDescriptor.Info = srcInf.Info; 269 legacyDescriptor.URL = srcInf.URL; 270 legacyDescriptor.IsPasswordRequired = srcInf.IsPasswordRequired; 271 dbTools.initTestTableUsingJDBC(tableName, legacyDescriptor); 272 } 273 catch(java.sql.SQLException e) 274 { 275 e.printStackTrace(log); 276 throw new StatusException(Status.failed("Couldn't " + 277 " init test table. SQLException...")); 278 } 279 catch(java.lang.ClassNotFoundException e) 280 { 281 throw new StatusException(Status.failed("Couldn't " + 282 "register mysql driver")); 283 } 284 } 285 else 286 { 287 String oldF = null ; 288 String newF = null ; 289 String tempFolder = utils.getOfficeTemp( orb ); 290 do 291 { 292 tableName = "ORowSet_tmp" + uniqueSuffix ; 293 oldF = utils.getFullURL(origDB); 294 newF = tempFolder + tableName + ".dbf"; 295 } 296 while ( !utils.tryOverwriteFile( orb, oldF, newF ) ); 297 m_tableFile = newF; 298 } 299 300 try 301 { 302 m_rowSet = orb.createInstance("com.sun.star.sdb.RowSet"); 303 304 XPropertySet rowSetProps = UnoRuntime.queryInterface( XPropertySet.class, m_rowSet ); 305 306 log.println("Trying to open: " + tableName); 307 308 rowSetProps.setPropertyValue("DataSourceName", dbSourceName); 309 rowSetProps.setPropertyValue("Command", tableName); 310 rowSetProps.setPropertyValue("CommandType", 311 new Integer(CommandType.TABLE)); 312 313 final XRowSet rowSet = UnoRuntime.queryInterface( XRowSet.class, m_rowSet); 314 rowSet.execute(); 315 m_connection = UnoRuntime.queryInterface( XConnection.class, rowSetProps.getPropertyValue("ActiveConnection") ); 316 317 XResultSet xRes = UnoRuntime.queryInterface( XResultSet.class, m_rowSet ); 318 xRes.first(); 319 320 log.println( "creating a new environment for object" ); 321 TestEnvironment tEnv = new TestEnvironment( (XInterface)m_rowSet ); 322 323 // Adding obj relation for XRowSetApproveBroadcaster test 324 { 325 final XResultSet resultSet = UnoRuntime.queryInterface( XResultSet.class, m_rowSet ); 326 final XResultSetUpdate resultSetUpdate = UnoRuntime.queryInterface( XResultSetUpdate.class, m_rowSet ); 327 final XRowUpdate rowUpdate = UnoRuntime.queryInterface(XRowUpdate.class, m_rowSet ); 328 final PrintWriter logF = log ; 329 tEnv.addObjRelation( "XRowSetApproveBroadcaster.ApproveChecker", 330 new ifc.sdb._XRowSetApproveBroadcaster.RowSetApproveChecker() 331 { 332 public void moveCursor() 333 { 334 try 335 { 336 resultSet.beforeFirst(); 337 resultSet.afterLast(); 338 resultSet.first(); 339 } 340 catch (com.sun.star.sdbc.SQLException e) 341 { 342 logF.println("### _XRowSetApproveBroadcaster.RowSetApproveChecker.moveCursor() :"); 343 e.printStackTrace(logF); 344 throw new StatusException( "RowSetApproveChecker.moveCursor failed", e ); 345 } 346 } 347 public RowChangeEvent changeRow() 348 { 349 try 350 { 351 resultSet.first(); 352 rowUpdate.updateString(1, "ORowSetTest2"); 353 resultSetUpdate.updateRow(); 354 } 355 catch (com.sun.star.sdbc.SQLException e) 356 { 357 logF.println("### _XRowSetApproveBroadcaster.RowSetApproveChecker.changeRow() :"); 358 e.printStackTrace(logF); 359 throw new StatusException( "RowSetApproveChecker.changeRow failed", e ); 360 } 361 RowChangeEvent ev = new RowChangeEvent(); 362 ev.Action = com.sun.star.sdb.RowChangeAction.UPDATE ; 363 ev.Rows = 1 ; 364 365 return ev ; 366 } 367 public void changeRowSet() 368 { 369 try 370 { 371 // since we gave the row set a parametrized statement, we need to ensure the 372 // parameter is actually filled, otherwise we would get an empty result set, 373 // which would imply some further tests failing 374 XParameters rowSetParams = UnoRuntime.queryInterface( XParameters.class, resultSet ); 375 rowSetParams.setString( 1, "String2" ); 376 rowSet.execute(); 377 resultSet.first(); 378 } 379 catch (com.sun.star.sdbc.SQLException e) 380 { 381 logF.println("### _XRowSetApproveBroadcaster.RowSetApproveChecker.changeRowSet() :"); 382 e.printStackTrace(logF); 383 throw new StatusException( "RowSetApproveChecker.changeRowSet failed", e ); 384 } 385 } 386 } 387 ); 388 } 389 // Adding relations for XRow as a Vector with all data 390 // of current row of RowSet. 391 392 Vector rowData = new Vector(); 393 394 for (int i = 0; i < DBTools.TST_TABLE_VALUES[0].length; i++) { 395 rowData.add(DBTools.TST_TABLE_VALUES[0][i]); 396 } 397 398 // here XRef must be added 399 // here XBlob must be added 400 // here XClob must be added 401 // here XArray must be added 402 403 tEnv.addObjRelation("CurrentRowData", rowData); 404 405 // Adding relation for XColumnLocate ifc test 406 tEnv.addObjRelation( "XColumnLocate.ColumnName", DBTools.TST_STRING_F ); 407 408 // Adding relation for XCompletedExecution 409 tEnv.addObjRelation( "InteractionHandlerChecker", new InteractionHandlerImpl() ); 410 try 411 { 412 String sqlCommand = isMySQLDB 413 ? "SELECT Column0 FROM soffice_test_table WHERE ( ( Column0 = :param1 ) )" 414 : "SELECT \"_TEXT\" FROM \"" + tableName + "\" WHERE ( ( \"_TEXT\" = :param1 ) )"; 415 rowSetProps.setPropertyValue( "DataSourceName", dbSourceName ); 416 rowSetProps.setPropertyValue( "Command", sqlCommand ); 417 rowSetProps.setPropertyValue( "CommandType", new Integer(CommandType.COMMAND) ); 418 } 419 catch(Exception e) 420 { 421 throw new StatusException( "setting up the RowSet with a parametrized command failed", e ); 422 } 423 424 // Adding relation for XParameters ifc test 425 tEnv.addObjRelation( "XParameters.ParamValues", new Vector() ); 426 427 // Adding relation for XRowUpdate 428 final XRow row = UnoRuntime.queryInterface( XRow.class, m_rowSet ); 429 tEnv.addObjRelation("XRowUpdate.XRow", row); 430 431 // Adding relation for XResultSetUpdate 432 { 433 final XResultSet resultSet = UnoRuntime.queryInterface( XResultSet.class, m_rowSet ); 434 final XRowUpdate rowUpdate = UnoRuntime.queryInterface( XRowUpdate.class, m_rowSet ); 435 436 tEnv.addObjRelation("XResultSetUpdate.UpdateTester", 437 new ifc.sdbc._XResultSetUpdate.UpdateTester() 438 { 439 String lastUpdate = null ; 440 441 public int rowCount() throws SQLException 442 { 443 int prevPos = resultSet.getRow(); 444 resultSet.last(); 445 int count = resultSet.getRow(); 446 resultSet.absolute(prevPos); 447 448 return count ; 449 } 450 451 public void update() throws SQLException 452 { 453 lastUpdate = row.getString(1); 454 lastUpdate += "_" ; 455 rowUpdate.updateString(1, lastUpdate); 456 } 457 458 public boolean wasUpdated() throws SQLException 459 { 460 String getStr = row.getString(1); 461 return lastUpdate.equals(getStr); 462 } 463 464 public int currentRow() throws SQLException 465 { 466 return resultSet.getRow(); 467 } 468 } 469 ); 470 } 471 472 envCreatedOK = true ; 473 return tEnv; 474 475 } 476 catch(com.sun.star.uno.Exception e) 477 { 478 log.println( "couldn't set up tes tenvironment:" ); 479 e.printStackTrace(log); 480 try 481 { 482 if ( m_connection != null ) 483 m_connection.close(); 484 } 485 catch(Exception ex) 486 { 487 } 488 throw new StatusException( "couldn't set up tes tenvironment", e ); 489 } 490 finally 491 { 492 if (!envCreatedOK) 493 { 494 try 495 { 496 m_connection.close(); 497 } 498 catch(Exception ex) 499 { 500 } 501 } 502 } 503 504 } // finish method getTestEnvironment 505 506 /** 507 * Closes connection of <code>RowSet</code> instance created. 508 */ 509 protected void cleanup( TestParameters Param, PrintWriter log) 510 { 511 String doing = null; 512 try 513 { 514 doing = "revoking data source registration"; 515 log.println( doing ); 516 m_dataSource.revokeRegistration(); 517 518 doing = "closing database document"; 519 log.println( doing ); 520 XModel databaseDocModel = UnoRuntime.queryInterface( XModel.class, 521 m_dataSource.getDatabaseDocument().getDatabaseDocument() ); 522 String documentFile = databaseDocModel.getURL(); 523 524 XCloseable closeModel = UnoRuntime.queryInterface( XCloseable.class, 525 m_dataSource.getDatabaseDocument().getDatabaseDocument() ); 526 closeModel.close( true ); 527 528 if ( m_rowSet != null ) 529 { 530 doing = "disposing row set"; 531 log.println( doing ); 532 XComponent rowSetComponent = UnoRuntime.queryInterface( XComponent.class, m_rowSet ); 533 rowSetComponent.dispose(); 534 } 535 536 try 537 { 538 doing = "closing connection"; 539 log.println( doing ); 540 m_connection.close(); 541 } 542 catch (com.sun.star.lang.DisposedException e) 543 { 544 log.println( "already closed - okay." ); 545 } 546 547 doing = "deleting database file (" + documentFile + ")"; 548 log.println( doing ); 549 impl_deleteFile( documentFile ); 550 551 if ( m_tableFile != null ) 552 { 553 doing = "deleting dBase table file (" + m_tableFile + ")"; 554 log.println( doing ); 555 impl_deleteFile( m_tableFile ); 556 } 557 } 558 catch (com.sun.star.uno.Exception e) 559 { 560 log.println( "error: "); 561 e.printStackTrace(log); 562 } 563 } 564 565 private final void impl_deleteFile( final String _file ) 566 { 567 java.io.File file = new java.io.File( _file ); 568 file.delete(); 569 if ( file.exists() ) 570 file.deleteOnExit(); 571 } 572 573 /** 574 * Implementation of interface _XCompletedExecution.CheckInteractionHandler 575 * for the XCompletedExecution test 576 * @see ifc.sdb._XCompletedExecution 577 */ 578 public class InteractionHandlerImpl implements _XCompletedExecution.CheckInteractionHandler { 579 private boolean handlerWasUsed = false; 580 private PrintWriter log = new PrintWriter(System.out); 581 582 public boolean checkInteractionHandler() { 583 return handlerWasUsed; 584 } 585 586 public void handle(XInteractionRequest xInteractionRequest) { 587 log.println("### _XCompletedExecution.InteractionHandlerImpl: handle called."); 588 ParametersRequest req = null; 589 boolean abort = false; 590 591 Object o = xInteractionRequest.getRequest(); 592 if (o instanceof ParametersRequest) { 593 req = (ParametersRequest)o; 594 } 595 else if (o instanceof AuthenticationRequest) { 596 log.println("### The request in XCompletedExecution is of type 'AuthenticationRequest'"); 597 log.println("### This is not implemented in ORowSet.InteractionHandlerImpl test -> abort."); 598 abort = true; 599 } 600 else { 601 log.println("### Unknown request:" + o.toString()); 602 log.println("### This is not implemented in ORowSet.InteractionHandlerImpl test -> abort."); 603 abort = true; 604 } 605 606 XInteractionContinuation[]xCont = xInteractionRequest.getContinuations(); 607 XInteractionSupplyParameters xParamCallback = null; 608 for(int i=0; i<xCont.length; i++) { 609 if (abort) { 610 XInteractionAbort xAbort = null; 611 xAbort = UnoRuntime.queryInterface(XInteractionAbort.class, xCont[i]); 612 if (xAbort != null) 613 xAbort.select(); 614 return; 615 } 616 else { 617 xParamCallback = UnoRuntime.queryInterface(XInteractionSupplyParameters.class, xCont[i]); 618 if (xParamCallback != null) 619 break; 620 } 621 } 622 if (xParamCallback != null) { 623 log.println("### _XCompletedExecution.InteractionHandlerImpl: supplying parameters."); 624 handlerWasUsed = true; 625 PropertyValue[] prop = new PropertyValue[1]; 626 prop[0] = new PropertyValue(); 627 prop[0].Name = "param1"; 628 prop[0].Value = "Hi."; 629 630 xParamCallback.setParameters(prop); 631 xParamCallback.select(); 632 } 633 else { // we should never reach this: abort has to be true first. 634 log.println("### _XCompletedExecution.InteractionHandlerImpl: Got no " + 635 "'XInteractionSupplyParameters' and no 'XInteractionAbort'."); 636 } 637 } 638 639 public void setLog(PrintWriter log) { 640 this.log = log; 641 } 642 643 } 644 } 645