1 24 25 package org.objectweb.cjdbc.controller.backup; 26 27 import java.io.BufferedInputStream ; 28 import java.io.BufferedOutputStream ; 29 import java.io.BufferedReader ; 30 import java.io.BufferedWriter ; 31 import java.io.File ; 32 import java.io.FileInputStream ; 33 import java.io.FileNotFoundException ; 34 import java.io.FileOutputStream ; 35 import java.io.FileReader ; 36 import java.io.FileWriter ; 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.io.ObjectInputStream ; 40 import java.io.ObjectOutputStream ; 41 import java.io.OutputStream ; 42 import java.io.PrintStream ; 43 import java.net.ServerSocket ; 44 import java.net.Socket ; 45 import java.util.ArrayList ; 46 import java.util.Date ; 47 import java.util.Hashtable ; 48 49 import org.apache.log4j.Category; 50 import org.apache.log4j.Priority; 51 import org.objectweb.cjdbc.common.exceptions.BackupException; 52 import org.objectweb.cjdbc.common.exceptions.OctopusException; 53 import org.objectweb.cjdbc.common.i18n.Translate; 54 import org.objectweb.cjdbc.common.log.Trace; 55 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable; 56 import org.objectweb.cjdbc.common.util.FileManagement; 57 import org.objectweb.cjdbc.common.util.LoggingOutputStream; 58 import org.objectweb.cjdbc.common.util.Zipper; 59 import org.objectweb.cjdbc.controller.backend.DatabaseBackend; 60 import org.webdocwf.util.loader.Loader; 61 import org.webdocwf.util.loader.generator.LoaderGenerator; 62 63 74 public class OctopusBackuper implements Backuper 75 { 76 static Trace logger = Trace 77 .getLogger(OctopusBackuper.class 78 .getName()); 79 private boolean zipBackupFiles = true; 80 81 static 82 { 83 String cjdbcHome = System.getProperty("cjdbc.home"); 84 if (cjdbcHome != null) 85 System.setProperty("OCTOPUS_HOME", cjdbcHome + File.separator + "lib" 86 + File.separator + "octopus" + File.separator + "xml"); 87 } 88 89 93 private static final int DB_NAME = 0; 94 private static final int DRIVER = 1; 95 private static final int FULL_NAME = 2; 96 private static final int PREFIX_URL = 3; 97 98 105 private static final String [] HSQL = {"hsqldb", "hsql", 106 "HypersonicSQL", "jdbc:hsqldb:" }; 107 private static final String [] CSV = {"csv", "csv", "Csv", 108 "jdbc:relique:csv:" }; 109 private static final String [] MYSQL = {"mysql", "mm", "MySQL", 110 "jdbc:mysql://" }; 111 private static final String [] POSTGRESQL = {"postgresql", "postgresql", 112 "PostgreSQL", "jdbc:postgresql://" }; 113 private static final String [] ORACLE = {"oracle", "oracle", "Oracle", 114 "jdbc:oracle:thin:" }; 115 private static final String [] JTURBO = {"jTurbo", "jTurbo", "MSQL", 116 "jdbc:JTurbo://" }; 117 private static final String [] MSSQL = {"microsoft", "microsoft", 118 "MSQL", "jdbc:microsoft:sqlserver://" }; 119 120 static final Hashtable TYPES; 121 static 122 { 123 TYPES = new Hashtable (); 124 TYPES.put(HSQL[DB_NAME], HSQL); 125 TYPES.put(CSV[DB_NAME], CSV); 126 TYPES.put(MYSQL[DB_NAME], MYSQL); 127 TYPES.put(ORACLE[DB_NAME], ORACLE); 128 TYPES.put(POSTGRESQL[DB_NAME], POSTGRESQL); 129 TYPES.put(JTURBO[DB_NAME], JTURBO); 130 TYPES.put(MSSQL[DB_NAME], MSSQL); 131 } 132 133 137 140 public OctopusBackuper() 141 { 142 } 143 144 147 public String getDumpFormat() 148 { 149 if (zipBackupFiles) 150 return "Octopus v2.8 database neutral dump compressed"; 151 else 152 return "Octopus v2.8 database neutral dump"; 153 } 154 155 160 public Date backup(DatabaseBackend backend, String login, String password, 161 String dumpName, String path, ArrayList tables) throws BackupException 162 { 163 logger.info(Translate.get("backup.manager.backuping.backend", new String []{ 164 backend.getName(), dumpName})); 165 166 String octopusDir = createOctopusDir(path, dumpName); 168 169 String type = getDatabaseType(backend.getURL()); 170 String sourceType = getOctopusType(type); 171 String sourceUrl = backend.getURL().substring(getUrlPrefix(type).length()); 172 String sourceDriver = getOctopusDriver(type); 173 String targetType = getOctopusType(TYPE_CSV); 174 String targetDriver = getOctopusDriver(TYPE_CSV); 175 String targetUrl = createCsvDir(octopusDir); 176 String targetUser = ""; 177 String targetPassword = ""; 178 179 try 180 { 181 redirectOutputStream(); 183 184 if (logger.isDebugEnabled()) 186 logger.debug("### Generating Octopus metadata ###"); 187 callOctopusLoader(sourceType, sourceUrl, sourceDriver, login, password, 188 targetType, targetDriver, targetUrl, targetUser, targetPassword, 189 true, true, octopusDir); 190 191 if (logger.isDebugEnabled()) 193 logger.debug("### Generating loader job ###"); 194 callOctopusLoader(sourceType, sourceUrl, sourceDriver, login, password, 195 targetType, targetDriver, targetUrl, targetUser, targetPassword, 196 true, false, octopusDir); 197 198 if (logger.isDebugEnabled()) 199 { 200 logger.debug("======================================="); 201 logger.debug("Using the following Octopus settings:"); 202 logger.debug("Octopus dump directory=" + octopusDir); 203 logger.debug("Target URL=" + targetUrl); 204 logger.debug("Loader job file=" + getLoaderJobFile(octopusDir)); 205 logger.debug("Compress backup=" + zipBackupFiles); 206 logger.debug("OCTOPUS HOME:" + System.getProperty("OCTOPUS_HOME")); 207 logger.debug("======================================="); 208 } 209 210 launchOctopus(octopusDir, dumpName, tables); 212 } 213 catch (Exception e) 214 { 215 String msg = "Error while performing backup for backend " 216 + backend.getName(); 217 logger.error(msg, e); 218 throw new BackupException(msg, e); 219 } 220 221 if (zipBackupFiles) 223 { 224 try 225 { 226 if (logger.isDebugEnabled()) 227 logger.debug("Compressing dump"); 228 Zipper.zip(path + File.separator + dumpName + Zipper.ZIP_EXT, 229 octopusDir, Zipper.STORE_PATH_FROM_ZIP_ROOT); 230 if (logger.isDebugEnabled()) 231 logger.debug("Cleaning uncompressed dump files"); 232 cleanUp(octopusDir); 233 } 234 catch (Exception e) 235 { 236 String msg = "Error while compressing dump"; 237 logger.error(msg, e); 238 throw new BackupException(msg, e); 239 } 240 } 241 242 return new Date (System.currentTimeMillis()); 243 } 244 245 250 public void restore(DatabaseBackend backend, String login, String password, 251 String dumpName, String path, ArrayList tables) throws BackupException 252 { 253 logger.info(Translate.get("backup.manager.restoring.backend", new String []{ 254 backend.getName(), dumpName})); 255 256 String octopusDir = createOctopusDir(path, dumpName); 258 259 if (zipBackupFiles) 260 { 261 try 262 { 263 if (logger.isDebugEnabled()) 264 logger.debug("Uncompressing dump"); 265 Zipper.unzip(path + File.separator + dumpName + Zipper.ZIP_EXT, 266 octopusDir); 267 } 268 catch (Exception e) 269 { 270 String msg = "Error while uncompressing dump"; 271 logger.error(msg, e); 272 throw new BackupException(msg, e); 273 } 274 } 275 276 String type = getDatabaseType(backend.getURL()); 277 String targetType = getOctopusType(type); 278 String targetUrl = backend.getURL().substring(getUrlPrefix(type).length()); 279 String targetDriver = getOctopusDriver(type); 280 String sourceType = getOctopusType(TYPE_CSV); 281 String sourceDriver = getOctopusDriver(TYPE_CSV); 282 String sourceUrl = createCsvDir(octopusDir); 283 String sourceUser = ""; 284 String sourcePassword = ""; 285 286 try 287 { 288 redirectOutputStream(); 290 291 if (logger.isDebugEnabled()) 293 logger.debug("### Generating loader job ###"); 294 callOctopusLoader(sourceType, sourceUrl, sourceDriver, sourceUser, 295 sourcePassword, targetType, targetDriver, targetUrl, login, password, 296 false, false, octopusDir); 297 298 setOctopusLoaderJob(octopusDir, sourceType); 299 300 if (logger.isDebugEnabled()) 301 { 302 logger.debug("======================================="); 303 logger.debug("Using the following Octopus settings:"); 304 logger.debug("Octopus dump directory=" + octopusDir); 305 logger.debug("Source URL=" + sourceUrl); 306 logger.debug("Target URL=" + targetUrl); 307 logger.debug("Loader job file=" + getLoaderJobFile(octopusDir)); 308 logger.debug("Compress backup=" + zipBackupFiles); 309 logger.debug("OCTOPUS HOME:" + System.getProperty("OCTOPUS_HOME")); 310 logger.debug("======================================="); 311 } 312 313 launchOctopus(octopusDir, dumpName, tables); 315 316 if (zipBackupFiles) 317 { 318 if (logger.isDebugEnabled()) 319 logger.debug("Cleaning backup files"); 320 cleanUp(octopusDir); 321 } 322 } 323 catch (Exception e) 324 { 325 String msg = "Error while performing restore operation on backend " 326 + backend.getName(); 327 logger.error(msg, e); 328 throw new BackupException(msg, e); 329 } 330 331 } 332 333 337 public void deleteDump(String path, String dumpName) throws BackupException 338 { 339 if (zipBackupFiles) 340 { 341 File toRemove = new File (path + File.separator + dumpName 342 + Zipper.ZIP_EXT); 343 if (logger.isDebugEnabled()) 344 logger.debug("Deleting compressed dump " + toRemove); 345 toRemove.delete(); 346 } 347 else 348 { 349 if (logger.isDebugEnabled()) 350 logger.debug("Deleting dump directory " + path + File.separator 351 + dumpName); 352 cleanUp(path + File.separator + dumpName); 353 } 354 } 355 356 360 private static final String TYPE_CSV = "csv"; 361 private static final String COPY_MODE = "copy"; 362 private static final String OCTOPUS_INCLUDE_HREF = "<include HREF=\"sql/"; 363 364 private void callOctopusLoader(String sourceType, String sourceUrl, 365 String sourceDriver, String sourceUser, String sourcePassword, 366 String targetType, String targetDriver, String targetUrl, 367 String targetUser, String targetPassword, boolean backup, 368 boolean generateAllVendors, String octopusDir) throws OctopusException 369 { 370 try 371 { 372 if (logger.isDebugEnabled()) 373 { 374 logger.debug("Source Type:" + sourceType); 375 logger.debug("Source Driver:" + sourceDriver); 376 logger.debug("Source URL :" + sourceUrl); 377 logger.debug("Source User :" + sourceUser); 378 logger.debug("Target Type:" + targetType); 379 logger.debug("Target Driver:" + targetDriver); 380 logger.debug("Target URL:" + targetUrl); 381 logger.debug("Target User :" + targetUser); 382 logger.debug("Generate SQL for all vendors :" + generateAllVendors); 383 } 384 LoaderGenerator loader = new LoaderGenerator(sourceType, sourceUrl, COPY_MODE, octopusDir, sourceDriver, targetDriver, targetUrl, targetType, sourceUser, sourcePassword, targetUser, targetPassword, "", "org.webdoc.util.loader", "true", "true", "true", "true", "true", "true", String.valueOf(generateAllVendors), String.valueOf(!generateAllVendors), "false", String.valueOf(!generateAllVendors), String.valueOf(!backup), null, null ); 413 loader.generate(); 414 } 415 catch (Exception e) 416 { 417 throw new OctopusException(e); 418 } 419 } 420 421 428 private void launchOctopus(String octopusDir, String dumpName, 429 ArrayList tables) throws OctopusException 430 { 431 try 432 { 433 Loader myOctopus; 434 String loaderLogging; 435 if (logger.isDebugEnabled()) 436 loaderLogging = Loader.LOGMODE_FULL; 437 else if (!logger.isFatalEnabled()) loaderLogging = Loader.LOGMODE_NONE; 439 else 440 loaderLogging = Loader.LOGMODE_NORMAL; 441 442 if (tables == null) 443 { 444 myOctopus = new Loader(getLoaderJobFile(octopusDir), loaderLogging, 446 "cjdbc", octopusDir, "Octopus" + dumpName + ".log", true, null, 447 null, true, null, 0, 100); 448 } 449 else 450 { 451 myOctopus = new Loader(getLoaderJobFile(octopusDir), loaderLogging, 453 "cjdbc", octopusDir, "Octopus" + dumpName + ".log", true, null, 454 null, true, null, 0, 100, convertTablesToArray(tables)); 455 } 456 try 457 { 458 myOctopus.load(); 459 } 460 catch (Exception e) 461 { 462 logger.error("Failed to load octopus", e); 463 throw new OctopusException(Translate.get( 464 "controller.octopus.load.failed", e)); 465 } 466 } 467 catch (OctopusException oe) 470 { 471 throw oe; 473 } 474 catch (Exception e) 475 { 476 throw new OctopusException(Translate 477 .get("controller.octopus.instance.failed")); 478 } 479 } 480 481 private void cleanUp(String octopusDir) 482 { 483 if (logger.isDebugEnabled()) 484 logger.debug("Cleaning up temporary backup files..."); 485 File toRemove = new File (octopusDir); 486 FileManagement.deleteDir(toRemove); 487 } 488 489 private String [] convertTablesToArray(ArrayList tablesList) 490 { 491 int length = tablesList.size(); 492 String [] result = new String [length]; 493 for (int i = 0; i < length; i++) 494 result[i] = ((DatabaseTable) tablesList.get(i)).getName(); 495 return result; 496 } 497 498 private String createOctopusDir(String path, String dumpName) 499 throws BackupException 500 { 501 String octopusDir = path + File.separator + dumpName; 503 504 File octopusd = new File (octopusDir); 505 octopusd.mkdirs(); 506 octopusd.mkdir(); 507 508 if (!octopusd.exists()) 509 throw new BackupException("backup.directory.cannot.be.created"); 510 511 return octopusDir; 512 } 513 514 private String createCsvDir(String octopusDir) throws BackupException 515 { 516 String csvDir = TYPE_CSV; 518 File csvd = new File (octopusDir + File.separator + csvDir); 519 csvDir = csvd.getAbsolutePath(); 520 csvd.mkdirs(); 521 csvd.mkdir(); 522 523 if (!csvd.exists()) 524 throw new BackupException("backup.directory.cannot.be.created"); 525 526 return csvDir; 527 } 528 529 private String getDatabaseType(String url) throws BackupException 530 { 531 if (url == null) 532 throw new BackupException("Invalid null source url"); 533 int index = url.indexOf(':'); 534 int index2 = url.indexOf(':', index + 1); 535 if (index == -1 || index2 == -1 || index > index2) 536 throw new BackupException("Invalid source url format"); 537 String type = url.substring(index + 1, index2); 538 return type; 539 } 540 541 private String getLoaderJobFile(String octopusDir) 542 { 543 return octopusDir + File.separator + "LoaderJob.olj"; 544 } 545 546 private void redirectOutputStream() 547 { 548 System.setOut(new PrintStream (new LoggingOutputStream(Category 549 .getInstance(this.getClass().getName()), Priority.DEBUG), true)); 550 } 551 552 private void setOctopusLoaderJob(String octopusDir, String sourceType) 553 throws OctopusException 554 { 555 String onErrorContinueEqualFalse = "onErrorContinue=\"false\""; 556 String onErrorContinueEqualTrue = "onErrorContinue=\"true\""; 557 BufferedReader br = null; 558 BufferedWriter bw = null; 559 560 try 561 { 562 br = new BufferedReader (new FileReader (getLoaderJobFile(octopusDir))); 563 String line = ""; 564 StringBuffer buffer = new StringBuffer (); 565 566 while ((line = br.readLine()) != null) 567 { 568 569 int idx = line.indexOf(OCTOPUS_INCLUDE_HREF); 570 if (idx != -1) 571 { 572 idx += OCTOPUS_INCLUDE_HREF.length(); 573 line = line.substring(0, idx - 4) + ".." + File.separator 575 + octopusDir + File.separator + "SQLForAllVendors" 576 + File.separator + sourceType + File.separator + "sql" 577 + File.separator + line.substring(idx); 578 } 579 580 581 int index7 = line.indexOf(onErrorContinueEqualFalse); 582 if (index7 != -1) 583 { 584 line = line.substring(0, index7) + onErrorContinueEqualTrue 585 + line.substring(index7 + onErrorContinueEqualFalse.length()); 586 } 587 buffer.append(line + System.getProperty("line.separator")); 588 } 589 br.close(); 590 if (logger.isDebugEnabled()) 591 { 592 logger.debug("Octopus file updated with success"); 593 } 594 595 bw = new BufferedWriter (new FileWriter (getLoaderJobFile(octopusDir))); 596 bw.write(buffer.toString()); 597 bw.close(); 598 } 599 catch (FileNotFoundException fie) 600 { 601 logger.warn(Translate.get("controller.octopus.loader.job.not.found")); 603 throw new OctopusException(fie.getMessage()); 604 } 605 catch (IOException e) 606 { 607 logger.warn(Translate.get("controller.octopus.loader.io.problem")); 609 } 610 finally 611 { 612 if (bw != null) 614 try 615 { 616 bw.close(); 617 } 618 catch (IOException e1) 619 { 620 621 } 622 if (br != null) 623 try 624 { 625 br.close(); 626 } 627 catch (IOException e2) 628 { 629 } 630 } 631 } 632 633 639 private String getOctopusType(String type) 640 { 641 if (type == null) 642 return null; 643 return ((String []) TYPES.get(type))[OctopusBackuper.FULL_NAME]; 644 } 645 646 652 private String getOctopusDriver(String type) 653 { 654 if (type == null) 655 return null; 656 return ((String []) TYPES.get(type))[OctopusBackuper.DRIVER]; 657 } 658 659 665 private String getUrlPrefix(String type) 666 { 667 if (type == null) 668 return null; 669 return ((String []) TYPES.get(type))[OctopusBackuper.PREFIX_URL]; 670 } 671 672 676 679 public String getOptions() 680 { 681 return "zip=" + String.valueOf(zipBackupFiles); 682 } 683 684 687 public void setOptions(String options) 688 { 689 if (options != null) 690 { 691 int idx = options.indexOf("zip="); 692 if (idx > -1) 693 { 694 try 695 { 696 zipBackupFiles = !"false".equals(options.substring(idx + 1).trim()); 697 } 698 catch (RuntimeException e) 699 { 700 zipBackupFiles = true; 701 logger 702 .warn("Invalid option for OctopusBackuper, available option is 'zip=[true,false]' (" 703 + options + ")"); 704 } 705 } 706 } 707 logger.info("OctopusBackuper backup compression is set to " 708 + zipBackupFiles); 709 } 710 711 714 public BackupManager getBackupManager() 715 { 716 return null; 718 } 719 720 724 public void fetchDump(DumpTransferInfo dumpTransferInfo, String path, 725 String dumpName) throws BackupException, IOException 726 { 727 728 732 Socket soc = new Socket (); 733 734 soc.connect(dumpTransferInfo.getBackuperServerAddress()); 735 736 ObjectOutputStream oos = new ObjectOutputStream (soc.getOutputStream()); 737 738 oos.writeLong(dumpTransferInfo.getSessionKey()); 739 oos.writeObject(path); 740 oos.writeObject(dumpName); 741 742 InputStream is = new BufferedInputStream (soc.getInputStream()); 744 int response = is.read(); 745 if (response != 0xEC) throw new BackupException("bad response from dump server"); 747 748 752 File thePath = new File (path); 753 if (!thePath.exists()) 754 thePath.mkdirs(); 755 756 File theFile = new File (path + File.separator + dumpName + Zipper.ZIP_EXT); 757 theFile.createNewFile(); 758 759 OutputStream os = new BufferedOutputStream (new FileOutputStream (theFile)); 760 int c = is.read(); 761 while (c != -1) 762 { 763 os.write(c); 764 c = is.read(); 765 } 766 os.flush(); 767 os.close(); 768 } 769 770 class DumpTransferServerThread extends Thread 771 { 772 private ServerSocket serverSocket; 773 private long sessionKey; 774 775 public void run() 776 { 777 try 778 { 779 Socket soc = serverSocket.accept(); 783 ObjectInputStream ois = new ObjectInputStream (soc.getInputStream()); 784 785 long key = ois.readLong(); 789 790 if (key != this.sessionKey) 791 { 792 soc.close(); 793 return; } 795 796 String path = (String ) ois.readObject(); 797 String dumpName = (String ) ois.readObject(); 798 799 if (!zipBackupFiles) 800 { 801 logger.error("non-zipped backup server not supported"); 802 soc.close(); 803 return; 804 } 805 806 File theFile = new File (path + File.separator + dumpName 807 + Zipper.ZIP_EXT); 808 809 if (!theFile.exists()) 810 { 811 logger.error("requested dump does not exist: " + theFile.getPath()); 812 soc.close(); 813 return; 814 } 815 816 InputStream is = new BufferedInputStream (new FileInputStream (theFile)); 817 OutputStream os = new BufferedOutputStream (soc.getOutputStream()); 818 819 os.write(0xEC); 822 823 int c = is.read(); 827 while (c != -1) 828 { 829 os.write(c); 830 c = is.read(); 831 } 832 os.flush(); 833 os.close(); 834 } 835 catch (IOException e) 836 { 837 e.printStackTrace(); 838 } 839 catch (ClassNotFoundException e) 840 { 841 e.printStackTrace(); 842 } 843 } 844 845 DumpTransferServerThread(ServerSocket serverSocket, long sessionKey) 846 { 847 setName("DumpTransfer server thread"); 848 this.serverSocket = serverSocket; 849 this.sessionKey = sessionKey; 850 } 851 } 852 853 856 public DumpTransferInfo setupServer() throws IOException 857 { 858 ServerSocket soc = new ServerSocket (); 859 soc.bind(null); 860 long sessionKey = soc.hashCode(); 861 862 new DumpTransferServerThread(soc, sessionKey).start(); 863 864 return new DumpTransferInfo(soc.getLocalSocketAddress(), sessionKey); 865 } 866 } 867 | Popular Tags |