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 package com.sun.star.wizards.web; 24 25 import java.io.File; 26 import java.io.FileOutputStream; 27 import java.io.IOException; 28 import java.util.Hashtable; 29 import java.util.Iterator; 30 import java.util.Map; 31 32 import javax.xml.transform.Templates; 33 import javax.xml.transform.Transformer; 34 import javax.xml.transform.dom.DOMSource; 35 import javax.xml.transform.stream.StreamResult; 36 37 import org.w3c.dom.Document; 38 39 import com.sun.star.lang.XMultiServiceFactory; 40 import com.sun.star.wizards.common.ConfigSet; 41 import com.sun.star.wizards.common.FileAccess; 42 import com.sun.star.wizards.common.PropertyNames; 43 import com.sun.star.wizards.common.UCB; 44 import com.sun.star.wizards.ui.event.Task; 45 import com.sun.star.wizards.web.data.CGContent; 46 import com.sun.star.wizards.web.data.CGDocument; 47 import com.sun.star.wizards.web.data.CGExporter; 48 import com.sun.star.wizards.web.data.CGLayout; 49 import com.sun.star.wizards.web.data.CGPublish; 50 import com.sun.star.wizards.web.data.CGSettings; 51 import com.sun.star.wizards.web.export.Exporter; 52 53 /** 54 * @author rpiterman 55 * This class is used to process a CGSession object 56 * and generate a site. </br> 57 * it does the following: <br/> 58 * 1. create a temporary directory.<br/> 59 * 2. export documents to the temporary directory.<br/> 60 * 3. generate the TOC page, includes copying images from the 61 * web wizard work directory and other layout files.<br/> 62 * 4. publish, or copy, from the temporary directory to 63 * different destinations.<br/> 64 * 5. delete the temporary directory.<br/> 65 * <br/> 66 * to follow up the status/errors it uses a TaskListener object, 67 * and an ErrorHandler. <br/> 68 * in practice, the TaskListener is the status dialog, 69 * and the Errorhandler does the interaction with the user, 70 * if something goes wrong.<br/> 71 * Note that this class takes it in count that 72 * the given session object is prepared for it - 73 * all preparations are done in WWD_Events.finishWizard methods. 74 * <br/> 75 * <br/> 76 * 77 * note on error handling: <br/> 78 * on "catch" clauses I tries to decide whether the 79 * exception is fatal or not. For fatal exception an error message 80 * is displayed (or rather: the errorHandler is being called...) 81 * and a false is returned. 82 * In less-fatal errors, the errorHandler "should decide" which means, 83 * the user is given the option to "OK" or to "Cancel" and depending 84 * on that interaction I cary on. 85 */ 86 public class Process implements WebWizardConst, ProcessErrors 87 { 88 89 private static final int TASKS_PER_DOC = 5; 90 private static final int TASKS_PER_XSL = 2; 91 private static final int TASKS_PER_PUBLISH = 2; 92 private static final int TASKS_IN_PREPARE = 1; 93 private static final int TASKS_IN_EXPORT = 2; 94 private static final int TASKS_IN_GENERATE = 2; 95 private static final int TASKS_IN_PUBLISH = 2; 96 private static final int TASKS_IN_FINISHUP = 1; 97 private CGSettings settings; 98 private XMultiServiceFactory xmsf; 99 private ErrorHandler errorHandler; 100 private String tempDir; 101 private FileAccess fileAccess; 102 private UCB ucb; 103 public Task myTask; 104 /** 105 * This is a cache for exporters, so I do not need to 106 * instanciate the same exporter more than once. 107 */ 108 private Map exporters = new Hashtable(3); 109 private boolean result; 110 Process( CGSettings settings, XMultiServiceFactory xmsf, ErrorHandler er)111 public Process( 112 CGSettings settings, 113 XMultiServiceFactory xmsf, 114 ErrorHandler er) 115 throws Exception 116 { 117 this.xmsf = xmsf; 118 this.settings = settings; 119 fileAccess = new FileAccess(xmsf); 120 errorHandler = er; 121 122 ucb = new UCB(xmsf); 123 124 int taskSteps = getTaskSteps(); 125 myTask = new Task(TASK, TASK_PREPARE, taskSteps); 126 127 } 128 129 /** 130 * @return to how many destinations should the 131 * generated site be published. 132 */ countPublish()133 private int countPublish() 134 { 135 int count = 0; 136 ConfigSet publishers = settings.cp_DefaultSession.cp_Publishing; 137 for (int i = 0; i < publishers.getSize(); i++) 138 { 139 if (((CGPublish) publishers.getElementAt(i)).cp_Publish) 140 { 141 count++; 142 } 143 } 144 return count; 145 } 146 147 /** 148 * @return the number of task steps that this 149 * session should have 150 */ getTaskSteps()151 private int getTaskSteps() 152 { 153 int docs = settings.cp_DefaultSession.cp_Content.cp_Documents.getSize(); 154 int xsl = 0; 155 try 156 { 157 xsl = settings.cp_DefaultSession.getLayout().getTemplates(xmsf).size(); 158 } 159 catch (Exception ex) 160 { 161 } 162 int publish = countPublish(); 163 return 164 TASKS_IN_PREPARE + 165 TASKS_IN_EXPORT + docs * TASKS_PER_DOC + 166 TASKS_IN_GENERATE + xsl * TASKS_PER_XSL + 167 TASKS_IN_PUBLISH + publish * TASKS_PER_PUBLISH + 168 TASKS_IN_FINISHUP; 169 } 170 171 /** 172 * does the job 173 */ runProcess()174 public void runProcess() 175 { 176 myTask.start(); 177 try 178 { 179 try 180 { 181 /* 182 * I use here '&&' so if one of the 183 * methods returns false, the next 184 * will not be called. 185 */ 186 result = createTempDir(myTask) && export(myTask) && generate(tempDir, myTask) && publish(tempDir, myTask); 187 188 } 189 finally 190 { 191 //cleanup must be called. 192 result = result & cleanup(myTask); 193 } 194 } 195 catch (Exception ex) 196 { 197 result = false; 198 } 199 200 if (!result) 201 { 202 myTask.fail(); //this is a bug protection. 203 } 204 while (myTask.getStatus() < myTask.getMax()) 205 { 206 myTask.advance(true); 207 } 208 } 209 210 /** 211 * creates a temporary directory. 212 * @param task 213 * @return true should continue 214 */ createTempDir(Task task)215 private boolean createTempDir(Task task) 216 { 217 218 tempDir = fileAccess.createNewDir(getSOTempDir(xmsf), "wwiztemp"); 219 if (tempDir == null) 220 { 221 error(null, null, ERROR_MKDIR, ErrorHandler.ERROR_PROCESS_FATAL); 222 return false; 223 } 224 else 225 { 226 task.advance(true); 227 return true; 228 } 229 } 230 231 /** 232 * @param xmsf 233 * @return the staroffice /openoffice temporary directory 234 */ getSOTempDir(XMultiServiceFactory xmsf)235 static String getSOTempDir(XMultiServiceFactory xmsf) 236 { 237 try 238 { 239 return FileAccess.getOfficePath(xmsf, "Temp", PropertyNames.EMPTY_STRING, PropertyNames.EMPTY_STRING); 240 } 241 catch (Exception e) 242 { 243 } 244 return null; 245 } 246 247 // CLEANUP 248 /** 249 * delete the temporary directory 250 * @return true should continue 251 */ cleanup(Task task)252 private boolean cleanup(Task task) 253 { 254 255 task.setSubtaskName(TASK_FINISH); 256 boolean b = fileAccess.delete(tempDir); 257 if (!b) 258 { 259 error(null, null, ERROR_CLEANUP, ErrorHandler.ERROR_WARNING); 260 } 261 task.advance(b); 262 return b; 263 } 264 265 // /** 266 // * deletes the given directory 267 // * @param dir the directory to delete 268 // * @return true if should continue 269 // */ 270 // private boolean cleanup(String dir) { 271 // 272 // boolean success = true; 273 // 274 // if (dir != null && fileAccess.exists(dir,false)) { 275 // 276 // String[] files = fileAccess.listFiles(dir,true); 277 // 278 // for (int i = 0; i < files.length; i++) { 279 // if (fileAccess.isDirectory(files[i])) 280 // success = success && cleanup(files[i]); 281 // else 282 // success = success && fileAccess.delete(files[i]); 283 // 284 // } 285 // } 286 // return success && fileAccess.delete(dir); 287 // } 288 /** 289 * This method is used to copy style files to a target 290 * Directory: css and background. 291 * Note that this method is static since it is 292 * also used when displaying a "preview" 293 */ copyMedia(UCB copy, CGSettings settings, String targetDir, Task task)294 public static void copyMedia(UCB copy, CGSettings settings, String targetDir, Task task) throws Exception 295 { 296 297 //1. .css 298 String sourceDir = FileAccess.connectURLs(settings.workPath, "styles"); 299 String filename = settings.cp_DefaultSession.getStyle().cp_CssHref; 300 copy.copy(sourceDir, filename, targetDir, "style.css"); 301 302 task.advance(true); 303 304 //2. background image 305 String background = settings.cp_DefaultSession.cp_Design.cp_BackgroundImage; 306 if (background != null && !background.equals(PropertyNames.EMPTY_STRING)) 307 { 308 sourceDir = FileAccess.getParentDir(background); 309 filename = background.substring(sourceDir.length()); 310 copy.copy(sourceDir, filename, targetDir + "/images", "background.gif"); 311 } 312 313 task.advance(true); 314 } 315 316 /** 317 * Copy "static" files (which are always the same, 318 * thus not user-input-dependant) to a target directory. 319 * Note that this method is static since it is 320 * also used when displaying a "preview" 321 * @param copy 322 * @param settings 323 * @param targetDir 324 * @throws Exception 325 */ copyStaticImages(UCB copy, CGSettings settings, String targetDir)326 public static void copyStaticImages(UCB copy, CGSettings settings, String targetDir) 327 throws Exception 328 { 329 copy.copy(FileAccess.connectURLs(settings.workPath, "images"), targetDir + "/images"); 330 } 331 332 /** 333 * publish the given directory. 334 * @param dir the source directory to publish from 335 * @param task task tracking. 336 * @return true if should continue 337 */ publish(String dir, Task task)338 private boolean publish(String dir, Task task) 339 { 340 task.setSubtaskName(TASK_PUBLISH_PREPARE); 341 ConfigSet set = settings.cp_DefaultSession.cp_Publishing; 342 try 343 { 344 345 copyMedia(ucb, settings, dir, task); 346 copyStaticImages(ucb, settings, dir); 347 task.advance(true); 348 } 349 catch (Exception ex) 350 { 351 //error in copying media 352 error(ex, PropertyNames.EMPTY_STRING, ERROR_PUBLISH_MEDIA, ErrorHandler.ERROR_PROCESS_FATAL); 353 return false; 354 } 355 356 boolean result = true; 357 358 for (int i = 0; i < set.getSize(); i++) 359 { 360 361 CGPublish p = (CGPublish) set.getElementAt(i); 362 363 if (p.cp_Publish) 364 { 365 366 String key = (String) set.getKey(p); 367 task.setSubtaskName(key); 368 369 if (key.equals(ZIP_PUBLISHER)) 370 { 371 fileAccess.delete(p.cp_URL); 372 } 373 if (!publish(dir, p, ucb, task)) 374 { 375 return false; 376 } 377 378 } 379 } 380 381 return result; 382 } 383 384 /** 385 * publish the given directory to the 386 * given target CGPublish. 387 * @param dir the dir to copy from 388 * @param publish the object that specifies the target 389 * @param copy ucb encapsulation 390 * @param task task tracking 391 * @return true if should continue 392 */ publish(String dir, CGPublish publish, UCB copy, Task task)393 private boolean publish(String dir, CGPublish publish, UCB copy, Task task) 394 { 395 try 396 { 397 //copy.deleteDirContent(publish.url); 398 task.advance(true); 399 copy.copy(dir, publish.url); 400 task.advance(true); 401 return true; 402 } 403 catch (Exception e) 404 { 405 task.advance(false); 406 return error(e, publish, ERROR_PUBLISH, ErrorHandler.ERROR_NORMAL_IGNORE); 407 } 408 } 409 //GENERATING METHODS 410 /** 411 * Generates the TOC pages for the current session. 412 * @param targetDir generating to this directory. 413 */ generate(String targetDir, Task task)414 public boolean generate(String targetDir, Task task) 415 { 416 boolean result = false; 417 task.setSubtaskName(TASK_GENERATE_PREPARE); 418 419 420 CGLayout layout = settings.cp_DefaultSession.getLayout(); 421 422 try 423 { 424 /* 425 * here I create the DOM of the TOC to pass to the XSL 426 */ 427 Document doc = (Document) settings.cp_DefaultSession.createDOM(); 428 generate(xmsf, layout, doc, fileAccess, targetDir, task); 429 430 } 431 catch (Exception ex) 432 { 433 error(ex, PropertyNames.EMPTY_STRING, ERROR_GENERATE_XSLT, ErrorHandler.ERROR_PROCESS_FATAL); 434 return false; 435 } 436 437 /* copy files which are not xsl from layout directory to 438 * website root. 439 */ 440 try 441 { 442 443 task.setSubtaskName(TASK_GENERATE_COPY); 444 445 copyLayoutFiles(ucb, fileAccess, settings, layout, targetDir); 446 447 task.advance(true); 448 449 result = true; 450 } 451 catch (Exception ex) 452 { 453 task.advance(false); 454 return error(ex, null, ERROR_GENERATE_COPY, ErrorHandler.ERROR_NORMAL_ABORT); 455 } 456 457 458 459 return result; 460 461 } 462 463 /** 464 * copies layout files which are not .xsl files 465 * to the target directory. 466 * @param ucb UCB encapsulatzion object 467 * @param fileAccess filaAccess encapsulation object 468 * @param settings web wizard settings 469 * @param layout the layout object 470 * @param targetDir the target directory to copy to 471 * @throws Exception 472 */ copyLayoutFiles(UCB ucb, FileAccess fileAccess, CGSettings settings, CGLayout layout, String targetDir)473 public static void copyLayoutFiles(UCB ucb, FileAccess fileAccess, CGSettings settings, CGLayout layout, String targetDir) 474 throws Exception 475 { 476 String filesPath = fileAccess.getURL( 477 FileAccess.connectURLs(settings.workPath, "layouts/"), layout.cp_FSName); 478 ucb.copy(filesPath, targetDir, new ExtensionVerifier("xsl")); 479 480 } 481 482 /** 483 * generates the TOC page for the given layout. 484 * This method might generate more than one file, depending 485 * on how many .xsl files are in the 486 * directory specifies by the given layout object. 487 * @param xmsf 488 * @param layout specifies the layout to use. 489 * @param doc the DOM representation of the web wizard session 490 * @param fileAccess encapsulation of FileAccess 491 * @param targetPath target directory 492 * @param task 493 * @throws Exception 494 */ generate( XMultiServiceFactory xmsf, CGLayout layout, Document doc, FileAccess fileAccess, String targetPath, Task task)495 public static void generate( 496 XMultiServiceFactory xmsf, 497 CGLayout layout, 498 Document doc, 499 FileAccess fileAccess, 500 String targetPath, 501 Task task) 502 throws Exception 503 { 504 /* 505 * a map that contains xsl templates. the keys are the xsl file names. 506 */ 507 Map templates = layout.getTemplates(xmsf); 508 509 task.advance(true, TASK_GENERATE_XSL); 510 511 /* 512 * each template generates a page. 513 */ 514 for (Iterator i = templates.keySet().iterator(); i.hasNext();) 515 { 516 517 String key = PropertyNames.EMPTY_STRING; 518 519 key = (String) i.next(); 520 521 Transformer transformer = ((Templates) templates.get(key)).newTransformer(); 522 523 doc.normalize(); 524 task.advance(true); 525 526 /* 527 * The target file name is like the xsl template filename 528 * without the .xsl extension. 529 */ 530 String fn = fileAccess.getPath(targetPath, key.substring(0, key.length() - 4)); 531 File f = new File(fn); 532 FileOutputStream oStream = new FileOutputStream(f); 533 // Due to a problem occurring when using Xalan-Java 2.6.0 and 534 // Java 1.5.0, wrap f in a FileOutputStream here (otherwise, the 535 // StreamResult's getSystemId would return a "file:/..." URL while 536 // the Xalan code expects a "file:///..." URL): 537 transformer.transform( 538 new DOMSource(doc), new StreamResult(oStream)); 539 oStream.close(); 540 task.advance(true); 541 } 542 } 543 544 /** 545 * I broke the export method to two methods 546 * in a time where a tree with more than one contents was planned. 547 * I left it that way, because it may be used in the future. 548 * @param task 549 * @return 550 */ export(Task task)551 private boolean export(Task task) 552 { 553 554 return export(settings.cp_DefaultSession.cp_Content, tempDir, task); 555 556 } 557 558 /** 559 * This method could actually, with light modification, use recursion. 560 * In the present situation, where we only use a "flat" list of 561 * documents, instead of the original plan to use a tree, 562 * the recursion is not implemented. 563 * @param content the content ( directory-like, contains documents) 564 * @param dir (target directory for exporting this content. 565 * @param task 566 * @return true if should continue 567 */ export(CGContent content, String dir, Task task)568 private boolean export(CGContent content, String dir, Task task) 569 { 570 int toPerform = 1; 571 String contentDir = dir; 572 573 try 574 { 575 576 task.setSubtaskName(TASK_EXPORT_PREPARE); 577 578 /* 1. create a content directory. 579 * each content (at the moment there is only one :-( ) 580 * is created in its own directory. 581 * faileure here is fatal. 582 */ 583 contentDir = fileAccess.createNewDir(dir, content.cp_Name); 584 if (contentDir == null || contentDir.equals(PropertyNames.EMPTY_STRING)) 585 { 586 throw new IOException("Directory " + dir + " could not be created."); 587 } 588 content.dirName = FileAccess.getFilename(contentDir); 589 590 task.advance(true, TASK_EXPORT_DOCUMENTS); 591 toPerform--; 592 593 /*2. export all documents and sub contents. 594 * (at the moment, only documents, no subcontents) 595 */ 596 Object item = null; 597 for (int i = 0; i < content.cp_Documents.getSize(); i++) 598 { 599 try 600 { 601 item = content.cp_Documents.getElementAt(i); 602 /* 603 * In present this is always the case. 604 * may be in the future, when 605 * a tree is used, it will be abit different. 606 */ 607 if (item instanceof CGDocument) 608 { 609 if (!export((CGDocument) item, contentDir, task)) 610 { 611 return false; 612 } 613 } 614 else /* 615 * we never get here since we 616 * did not implement sub-contents. 617 */ if (!export((CGContent) item, contentDir, task)) 618 { 619 return false; 620 } 621 } 622 catch (SecurityException sx) 623 { 624 // nonfatal 625 if (!error(sx, item, ERROR_EXPORT_SECURITY, ErrorHandler.ERROR_NORMAL_IGNORE)) 626 { 627 return false; 628 } 629 result = false; 630 } 631 } 632 } 633 catch (IOException iox) 634 { 635 //nonfatal 636 return error(iox, content, ERROR_EXPORT_IO, ErrorHandler.ERROR_NORMAL_IGNORE); 637 638 } 639 catch (SecurityException se) 640 { 641 //nonfatal 642 return error(se, content, ERROR_EXPORT_SECURITY, ErrorHandler.ERROR_NORMAL_IGNORE); 643 } 644 failTask(task, toPerform); 645 return true; 646 647 } 648 649 /** 650 * exports a single document 651 * @param doc the document to export 652 * @param dir the target directory 653 * @param task task tracking 654 * @return true if should continue 655 */ export(CGDocument doc, String dir, Task task)656 private boolean export(CGDocument doc, String dir, Task task) 657 { 658 659 //first I check if the document was already validated... 660 if (!doc.valid) 661 { 662 try 663 { 664 doc.validate(xmsf, null); 665 } 666 catch (Exception ex) 667 { 668 //fatal 669 error(ex, doc, ERROR_DOC_VALIDATE, ErrorHandler.ERROR_PROCESS_FATAL); 670 return false; 671 } 672 //get the exporter specified for this document 673 } 674 CGExporter exporter = (CGExporter) settings.cp_Exporters.getElement(doc.cp_Exporter); 675 676 677 try 678 { 679 680 /* 681 * here I calculate the destination filename. 682 * I take the original filename (docFilename), subtract the extension, (docExt) -> (fn) 683 * and find an available filename which starts with 684 * this filename, but with the new extension. (destExt) 685 */ 686 String docFilename = FileAccess.getFilename(doc.cp_URL); 687 688 String docExt = FileAccess.getExtension(docFilename); 689 String fn = doc.localFilename.substring(0, doc.localFilename.length() - docExt.length() - 1); //filename without extension 690 691 /* 692 * the copyExporter does not change 693 * the extension of the target... 694 */ 695 String destExt = (exporter.cp_Extension.equals(PropertyNames.EMPTY_STRING) 696 ? FileAccess.getExtension(docFilename) 697 : exporter.cp_Extension); 698 699 /* if this filter needs to export to its own directory... 700 * this is the case in, for example, impress html export 701 */ 702 if (exporter.cp_OwnDirectory) 703 { //+++ 704 dir = fileAccess.createNewDir(dir, fn); 705 doc.dirName = FileAccess.getFilename(dir); 706 } 707 708 /* 709 * if two files with the same name 710 * need to be exported ? So here 711 * i get a new filename, so I do not 712 * overwrite files... 713 */ 714 String file = fileAccess.getNewFile(dir, fn, destExt); 715 716 717 /* set filename with extension. 718 * this will be used by the exporter, 719 * and to generate the TOC. 720 */ 721 doc.urlFilename = FileAccess.getFilename(file); 722 723 task.advance(true); 724 725 try 726 { 727 //export 728 getExporter(exporter).export(doc, file, xmsf, task); 729 task.advance(true); 730 } 731 /* 732 * getExporter(..) throws 733 * IllegalAccessException, InstantiationException, ClassNotFoundException 734 * export() throws Exception 735 */ 736 catch (Exception ex) 737 { 738 //nonfatal 739 if (!error(ex, doc, ERROR_EXPORT, ErrorHandler.ERROR_NORMAL_IGNORE)) 740 { 741 return false; 742 } 743 } 744 } 745 catch (Exception ex) 746 { 747 //nonfatal 748 if (!error(ex, doc, ERROR_EXPORT_MKDIR, ErrorHandler.ERROR_NORMAL_ABORT)) 749 { 750 return false; 751 } 752 } 753 754 return true; 755 756 } 757 758 /** 759 * submit an error. 760 * @param ex the exception 761 * @param arg1 error argument 762 * @param arg2 error argument 2 763 * @param errType error type 764 * @return the interaction result 765 */ error(Exception ex, Object arg1, int arg2, int errType)766 private boolean error(Exception ex, Object arg1, int arg2, int errType) 767 { 768 result = false; 769 return errorHandler.error(ex, arg1, arg2, errType); 770 } 771 772 /** 773 * advances the given task in the given count of steps, 774 * marked as failed. 775 * @param task the task to advance 776 * @param count the number of steps to advance 777 */ failTask(Task task, int count)778 private void failTask(Task task, int count) 779 { 780 while (count-- > 0) 781 { 782 task.advance(false); 783 } 784 } 785 786 /** 787 * creates an instance of the exporter class 788 * as specified by the 789 * exporter object. 790 * @param export specifies the exporter to be created 791 * @return the Exporter instance 792 * @throws ClassNotFoundException 793 * @throws IllegalAccessException 794 * @throws InstantiationException 795 */ createExporter(CGExporter export)796 private Exporter createExporter(CGExporter export) 797 throws ClassNotFoundException, 798 IllegalAccessException, 799 InstantiationException 800 { 801 Exporter e = (Exporter) Class.forName(export.cp_ExporterClass).newInstance(); 802 e.init(export); 803 return e; 804 } 805 806 /** 807 * searches the an exporter for the given CGExporter object 808 * in the cache. 809 * If its not there, creates it, stores it in the cache and 810 * returns it. 811 * @param export specifies the needed exporter. 812 * @return an Exporter instance 813 * @throws ClassNotFoundException thrown when using Class.forName(string) 814 * @throws IllegalAccessException thrown when using Class.forName(string) 815 * @throws InstantiationException thrown when using Class.forName(string) 816 */ getExporter(CGExporter export)817 private Exporter getExporter(CGExporter export) 818 throws ClassNotFoundException, 819 IllegalAccessException, 820 InstantiationException 821 { 822 Exporter exp = (Exporter) exporters.get(export); 823 if (exp == null) 824 { 825 exp = createExporter(export); 826 exporters.put(export, exp); 827 } 828 return exp; 829 } 830 831 /** 832 * @return tru if everything went smooth, false 833 * if error(s) accured. 834 */ getResult()835 public boolean getResult() 836 { 837 return (myTask.getFailed() == 0) && result; 838 } 839 } 840