src/org/objectweb/cjdbc/controller/backup/Octopus.java

説明を見る。
00001 00025 package org.objectweb.cjdbc.controller.backup; 00026 00027 import java.io.BufferedReader; 00028 import java.io.BufferedWriter; 00029 import java.io.File; 00030 import java.io.FileNotFoundException; 00031 import java.io.FileReader; 00032 import java.io.FileWriter; 00033 import java.io.IOException; 00034 import java.io.PrintStream; 00035 import java.util.ArrayList; 00036 import java.util.HashMap; 00037 import java.util.Hashtable; 00038 import java.util.Iterator; 00039 import java.util.Vector; 00040 00041 import org.apache.log4j.Category; 00042 import org.apache.log4j.Priority; 00043 import org.apache.regexp.RE; 00044 import org.objectweb.cjdbc.common.exceptions.BackupException; 00045 import org.objectweb.cjdbc.common.exceptions.OctopusException; 00046 import org.objectweb.cjdbc.common.i18n.Translate; 00047 import org.objectweb.cjdbc.common.jmx.notifications.CjdbcNotificationList; 00048 import org.objectweb.cjdbc.common.log.Trace; 00049 import org.objectweb.cjdbc.common.shared.BackendState; 00050 import org.objectweb.cjdbc.common.shared.BackupListener; 00051 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable; 00052 import org.objectweb.cjdbc.common.util.LoggingOutputStream; 00053 import org.objectweb.cjdbc.common.util.ZipMe; 00054 import org.objectweb.cjdbc.controller.backend.DatabaseBackend; 00055 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager; 00056 import org.webdocwf.util.loader.Loader; 00057 import org.webdocwf.util.loader.generator.LoaderGenerator; 00058 00066 public class Octopus extends Thread 00067 { 00068 static Trace logger; 00069 00070 static final String TYPE_CSV = "csv"; 00071 static final String COPY_MODE = "copy"; 00072 static final String OVERRIDE_MODE = "sync"; 00073 static final String GENERATE_DOC = "sql"; 00074 static final String OCTOPUS_LOG_FILE = "octopusLog.txt"; 00075 boolean cleanOctopus = false; 00076 boolean zipOctopus = true; 00077 00078 static final int ZIP_MODE_CREATE = 0; 00079 static final int ZIP_MODE_EXPAND = 1; 00080 00081 static final int OCTOPUS_MODE_FROM_CSV = 0; 00082 static final int OCTOPUS_MODE_TO_CSV = 1; 00083 00085 public static final int MODE_BACKUP = 0; 00087 public static final int MODE_RECOVERY = 1; 00088 00089 private DatabaseBackend database; 00090 00091 private String user; 00092 private String password; 00093 private String checkpoint; 00094 private String octopusDir; 00095 private String csvDir; 00096 private String loaderJobXmlFile; 00097 private ArrayList tables; 00098 private static PrintStream stream; 00099 00100 static String mainDirectory = ".." + File.separator 00101 + "backup"; 00102 00103 private boolean backupMode; 00104 00105 private Exception runException; 00106 00107 private BackupListener listener; 00108 00114 public Exception getRunException() 00115 { 00116 return runException; 00117 } 00118 00124 public final void setOctopusDirectory(String path) 00125 { 00126 mainDirectory = path; 00127 } 00128 00134 public final String getOctopusDirectory() 00135 { 00136 return mainDirectory; 00137 } 00138 00146 public Octopus(DatabaseBackend database, String checkpoint) 00147 throws BackupException 00148 { 00149 logger = Trace.getLogger(this.getClass().getName()); 00150 // Prepare references 00151 this.database = database; 00152 this.checkpoint = checkpoint; 00153 this.tables = null; 00154 00155 // Retrieve information 00156 getUserLogin(); 00157 setPaths(); 00158 } 00159 00169 public Octopus(DatabaseBackend database, String checkpoint, boolean backupMode) 00170 throws BackupException 00171 { 00172 this(database, checkpoint); 00173 this.backupMode = backupMode; 00174 } 00175 00185 public Octopus(DatabaseBackend database, String checkpoint, ArrayList tables, 00186 boolean backupMode) throws BackupException 00187 { 00188 this(database, checkpoint, backupMode); 00189 this.tables = tables; 00190 } 00191 00200 public Octopus(DatabaseBackend database, String checkpoint, ArrayList tables) 00201 throws BackupException 00202 { 00203 this(database, checkpoint); 00204 this.tables = tables; 00205 } 00206 00213 public void backup() throws BackupException, OctopusException 00214 { 00215 sanityCheck(); 00216 prepareOctopus(OCTOPUS_MODE_TO_CSV); 00217 launchOctopus(); 00218 if (zipOctopus) 00219 zipOctopus(ZIP_MODE_CREATE); 00220 if (cleanOctopus) 00221 cleanUp(); 00222 } 00223 00230 public void restore() throws BackupException, OctopusException 00231 { 00232 if (zipOctopus) 00233 zipOctopus(ZIP_MODE_EXPAND); 00234 prepareOctopus(OCTOPUS_MODE_FROM_CSV); 00235 setOctopusLoaderJob(); 00236 launchOctopus(); 00237 if (cleanOctopus) 00238 cleanUp(); 00239 } 00240 00247 public void setOctopusMode(boolean backup) 00248 { 00249 this.backupMode = backup; 00250 } 00251 00255 public void run() 00256 { 00257 if (backupMode) 00258 try 00259 { 00260 database.setState(BackendState.BACKUPING); 00261 backup(); 00262 database 00263 .notifyJmx(CjdbcNotificationList.CONTROLLER_VIRTUALDATABASE_NEW_DUMP_LIST); 00264 database.setLastKnownCheckpoint(checkpoint); 00265 database.setState(BackendState.DISABLED); 00266 if (listener != null) 00267 listener.success(database.getName()); 00268 } 00269 catch (Exception e) 00270 { 00271 database.setState(BackendState.UNKNOWN); 00272 runException = e; 00273 if (listener != null) 00274 listener.failure(database.getName(), e); 00275 } 00276 else 00277 { 00278 try 00279 { 00280 database.setState(BackendState.RECOVERING); 00281 restore(); 00282 database.setLastKnownCheckpoint(checkpoint); 00283 database.setState(BackendState.DISABLED); 00284 if (listener != null) 00285 listener.success(database.getName()); 00286 } 00287 catch (Exception e1) 00288 { 00289 database.setState(BackendState.UNKNOWN); 00290 runException = e1; 00291 if (listener != null) 00292 listener.failure(database.getName(), e1); 00293 } 00294 } 00295 00296 // Wake up everybody waiting on the listener 00297 if (listener != null) 00298 { 00299 synchronized (listener) 00300 { 00301 listener.notifyAll(); 00302 } 00303 } 00304 } 00305 00306 private void getUserLogin() 00307 { 00308 //Retrieve user login and password to connect to database 00309 HashMap connectionManagers = database.getConnectionManagers(); 00310 Iterator iter = connectionManagers.values().iterator(); 00311 AbstractConnectionManager connectionManager = (AbstractConnectionManager) iter 00312 .next(); 00313 user = connectionManager.getLogin(); 00314 password = connectionManager.getPassword(); 00315 if (logger.isDebugEnabled()) 00316 logger.debug("User:" + user + ":Password:" + password); 00317 } 00318 00319 private void setPaths() throws BackupException 00320 { 00321 // Change output stream 00322 if (stream == null) 00323 stream = new PrintStream(new LoggingOutputStream(Category 00324 .getInstance(this.getClass().getName()), Priority.DEBUG), true); 00325 //stream.close(); 00326 System.setOut(stream); 00327 00328 // Create main octopus directory 00329 octopusDir = mainDirectory + File.separator + checkpoint; 00330 00331 File octopusd = new File(octopusDir); 00332 octopusd.mkdirs(); 00333 00334 // Create Csv directory 00335 // Octopus needs a relative path from the loader file, 00336 // so just give the name of the directory 00337 csvDir = "csv"; 00338 File csvd = new File(octopusDir + File.separator + csvDir); 00339 csvd.mkdirs(); 00340 00341 // Create LoaderFile name 00342 loaderJobXmlFile = octopusDir + File.separator + "LoaderJob.olj"; 00343 00344 if (logger.isDebugEnabled()) 00345 { 00346 logger.debug("OCTOPUS_DIR=" + octopusDir); 00347 logger.debug("CSV_DIR=" + csvDir); 00348 logger.debug("LOADER_JOB_XML_FILE=" + loaderJobXmlFile); 00349 logger.debug("cleanOctopus=" + cleanOctopus); 00350 logger.debug("zipOctopus=" + cleanOctopus); 00351 } 00352 00353 if (!octopusd.exists() || !csvd.exists()) 00354 { 00355 throw new BackupException("backup.directory.cannot.be.created"); 00356 } 00357 } 00358 00364 public void sanityCheck() throws BackupException 00365 { 00366 boolean notEnabled = false, noPendingRequests = false; 00367 if (database.isReadEnabled() == false) 00368 notEnabled = true; 00369 00370 Vector pending = database.getPendingRequests(); 00371 int size = pending.size(); 00372 noPendingRequests = (size == 0) ? true : false; 00373 if (logger.isDebugEnabled()) 00374 { 00375 if (!noPendingRequests) 00376 { 00377 for (int i = 0; i < size; i++) 00378 { 00379 logger.debug("Pending:" + pending.get(i).toString()); 00380 } 00381 } 00382 logger.debug("Pending Requests:" + database.getPendingRequests().size()); 00383 logger.debug("Read enabled:" + database.isReadEnabled()); 00384 logger.debug("Write enabled:" + database.isWriteEnabled()); 00385 } 00386 if (!(notEnabled && noPendingRequests)) 00387 throw new BackupException(Translate.get("backend.not.ready.for.backup")); 00388 } 00389 00390 private void setOctopusLoaderJob() throws OctopusException, BackupException 00391 { 00392 Hashtable options = getOctopusStrings(database); 00393 String sourceType = (String) options.get("octopusType"); 00394 String onErrorContinueEqualFalse = "onErrorContinue=\"false\""; 00395 String onErrorContinueEqualTrue = "onErrorContinue=\"true\""; 00396 BufferedReader br = null; 00397 BufferedWriter bw = null; 00398 00399 try 00400 { 00401 br = new BufferedReader(new FileReader(loaderJobXmlFile)); 00402 String line = ""; 00403 StringBuffer buffer = new StringBuffer(); 00404 while ((line = br.readLine()) != null) 00405 { 00406 00407 /* Give the metadata location */ 00408 00409 RE href = new RE("(<include.*href\\s*=\\s*\")(.*/)(.*?\\.sql\".*)"); 00410 00411 /* XX in this string is a hack to workaround a bug in apache regexp 1.3 */ 00412 00413 line = href.subst(line, "XX$1.." + File.separator + octopusDir 00414 + File.separator + "SQLForAllVendors" + File.separator + sourceType 00415 + File.separator + "sql" + File.separator + "$3", 00416 RE.REPLACE_BACKREFERENCES); 00417 00418 /* Force on error continue */ 00419 int index7 = line.indexOf(onErrorContinueEqualFalse); 00420 if (index7 != -1) 00421 { 00422 line = line.substring(0, index7) + onErrorContinueEqualTrue 00423 + line.substring(index7 + onErrorContinueEqualFalse.length()); 00424 } 00425 buffer.append(line + System.getProperty("line.separator")); 00426 } 00427 br.close(); 00428 00429 if (logger.isDebugEnabled()) 00430 { 00431 logger.debug("Octopus file updated with success"); 00432 } 00433 00434 bw = new BufferedWriter(new FileWriter(loaderJobXmlFile)); 00435 bw.write(buffer.toString()); 00436 bw.close(); 00437 } 00438 catch (FileNotFoundException fie) 00439 { 00440 // loader job was not generated properly 00441 logger.warn(Translate.get("controller.octopus.loader.job.not.found")); 00442 throw new OctopusException(fie.getMessage()); 00443 } 00444 catch (IOException e) 00445 { 00446 // Error while reading file 00447 logger.warn(Translate.get("controller.octopus.loader.io.problem")); 00448 } 00449 finally 00450 { 00451 // close the open streams 00452 if (bw != null) 00453 try 00454 { 00455 bw.close(); 00456 } 00457 catch (IOException e1) 00458 { 00459 00460 } 00461 if (br != null) 00462 try 00463 { 00464 br.close(); 00465 } 00466 catch (IOException e2) 00467 { 00468 } 00469 } 00470 } 00471 00477 private void launchOctopus() throws OctopusException 00478 { 00479 try 00480 { 00481 Loader myOctopus; 00482 if (tables == null) 00483 { 00484 // Copy everything 00485 myOctopus = new Loader(loaderJobXmlFile, Loader.LOGMODE_NORMAL, 00486 "cjdbc", octopusDir, OCTOPUS_LOG_FILE, true, null, null, true, 00487 null, 0, 100); 00488 } 00489 else 00490 { 00491 // Copy only the tables we want 00492 myOctopus = new Loader(loaderJobXmlFile, Loader.LOGMODE_NORMAL, 00493 "cjdbc", octopusDir, OCTOPUS_LOG_FILE, true, null, null, true, 00494 null, 0, 100, this.convertTablesToArray(tables)); 00495 00496 } 00497 try 00498 { 00499 myOctopus.load(); 00500 } 00501 catch (Exception e) 00502 { 00503 logger.error("Failed to load octopus",e); 00504 throw new OctopusException(Translate.get( 00505 "controller.octopus.load.failed", e)); 00506 } 00507 } 00508 // I am doing this because Octopus throws NullPointerException 00509 // all the time so it is impossible to know which failed 00510 catch (OctopusException oe) 00511 { 00512 // This is thrown only by the above. 00513 throw oe; 00514 } 00515 catch (Exception e) 00516 { 00517 throw new OctopusException(Translate 00518 .get("controller.octopus.instance.failed")); 00519 } 00520 } 00521 00522 private void cleanUp() 00523 { 00524 if (logger.isDebugEnabled()) 00525 logger.debug("Cleaning up temporary backup files..."); 00526 File toRemove = new File(octopusDir); 00527 deleteDir(toRemove); 00528 } 00529 00536 public boolean deleteDir(File dir) 00537 { 00538 if (dir.isDirectory()) 00539 { 00540 String[] children = dir.list(); 00541 for (int i = 0; i < children.length; i++) 00542 { 00543 boolean success = deleteDir(new File(dir, children[i])); 00544 if (!success) 00545 { 00546 return false; 00547 } 00548 } 00549 } 00550 // The directory is now empty so delete it 00551 return dir.delete(); 00552 } 00553 00554 private void zipOctopus(int zipMode) throws BackupException 00555 { 00556 try 00557 { 00558 if (logger.isDebugEnabled()) 00559 { 00560 logger.debug("Checkpoint:" + checkpoint); 00561 logger.debug("CsvDir:" + csvDir); 00562 logger.debug("MainDir:" + mainDirectory); 00563 } 00564 switch (zipMode) 00565 { 00566 case ZIP_MODE_CREATE : 00567 new ZipMe().create(checkpoint, octopusDir, mainDirectory); 00568 break; 00569 case ZIP_MODE_EXPAND : 00570 new ZipMe().expand(checkpoint, ".", mainDirectory); 00571 break; 00572 default : 00573 throw new BackupException("invalid.zip.mode"); 00574 } 00575 } 00576 catch (Exception e) 00577 { 00578 logger.error(e.getMessage(), e); 00579 throw new BackupException(e.getMessage()); 00580 } 00581 } 00582 00583 private String getDbType(String url) throws BackupException 00584 { 00585 if (url == null) 00586 throw new BackupException("Invalid null source url"); 00587 int index = url.indexOf(':'); 00588 int index2 = url.indexOf(':', index + 1); 00589 if (index == -1 || index2 == -1 || index > index2) 00590 throw new BackupException("Invalid source url format"); 00591 String type = url.substring(index + 1, index2); 00592 return type; 00593 } 00594 00595 private void prepareOctopus(int octopusMode) throws BackupException, 00596 OctopusException 00597 { 00598 // Declare variables 00599 String sourceType = ""; 00600 String sourceUrl = ""; 00601 String sourceDriver = ""; 00602 String sourceUser = ""; 00603 String sourcePassword = ""; 00604 00605 String targetType = ""; 00606 String targetDriver = ""; 00607 String targetUrl = ""; 00608 String targetUser = ""; 00609 String targetPassword = ""; 00610 00611 boolean backupMode = true; 00612 00613 Hashtable options = getOctopusStrings(database); 00614 00615 // Prepare Variables 00616 switch (octopusMode) 00617 { 00618 case OCTOPUS_MODE_FROM_CSV : 00619 targetType = (String) options.get("octopusType"); 00620 targetUrl = (String) options.get("octopusUrl"); 00621 targetDriver = (String) options.get("octopusDriver"); 00622 targetUser = user; 00623 targetPassword = password; 00624 sourceType = OctopusConstants.getOctopusType(TYPE_CSV); 00625 sourceDriver = OctopusConstants.getOctopusDriver(TYPE_CSV); 00626 sourceUrl = csvDir; 00627 sourceUser = ""; 00628 sourcePassword = ""; 00629 backupMode = false; 00630 break; 00631 case OCTOPUS_MODE_TO_CSV : 00632 sourceType = (String) options.get("octopusType"); 00633 sourceUrl = (String) options.get("octopusUrl"); 00634 sourceDriver = (String) options.get("octopusDriver"); 00635 sourceUser = user; 00636 sourcePassword = password; 00637 targetType = OctopusConstants.getOctopusType(TYPE_CSV); 00638 targetDriver = OctopusConstants.getOctopusDriver(TYPE_CSV); 00639 targetUrl = csvDir; 00640 targetUser = ""; 00641 targetPassword = ""; 00642 backupMode = true; 00643 // Generate metadata 00644 generateMetadata(sourceType, sourceUrl, sourceDriver, sourceUser, 00645 sourcePassword, targetType, targetDriver, targetUrl, targetUser, 00646 targetPassword, backupMode); 00647 break; 00648 default : 00649 throw new BackupException("invalid.octopus.prepare.type"); 00650 } 00651 00652 // Generate loader job 00653 prepareOctopus(sourceType, sourceUrl, sourceDriver, sourceUser, 00654 sourcePassword, targetType, targetDriver, targetUrl, targetUser, 00655 targetPassword, backupMode); 00656 00657 } 00658 00659 final Hashtable getOctopusStrings(DatabaseBackend database) 00660 throws BackupException 00661 { 00662 Hashtable strings = new Hashtable(3); 00663 String type = getDbType(database.getURL()); 00664 String octopusPrefixUrl = OctopusConstants.getUrlPrefix(type); 00665 String databaseUrl = database.getURL(); 00666 00667 strings.put("octopusType", OctopusConstants.getOctopusType(type)); 00668 strings.put("octopusDriver", OctopusConstants.getOctopusDriver(type)); 00669 strings.put("octopusUrl", databaseUrl.substring(octopusPrefixUrl.length())); 00670 00671 return strings; 00672 } 00673 00674 final void generateMetadata(String sourceType, String sourceUrl, 00675 String sourceDriver, String sourceUser, String sourcePassword, 00676 String targetType, String targetDriver, String targetUrl, 00677 String targetUser, String targetPassword, boolean backup) 00678 throws OctopusException 00679 { 00680 logger.debug("### Generating metadata ###"); 00681 callOctopusLoader(sourceType, sourceUrl, sourceDriver, sourceUser, 00682 sourcePassword, targetType, targetDriver, targetUrl, targetUser, 00683 targetPassword, backup, true); 00684 } 00685 00689 final void prepareOctopus(String sourceType, String sourceUrl, 00690 String sourceDriver, String sourceUser, String sourcePassword, 00691 String targetType, String targetDriver, String targetUrl, 00692 String targetUser, String targetPassword, boolean backup) 00693 throws OctopusException 00694 { 00695 callOctopusLoader(sourceType, sourceUrl, sourceDriver, sourceUser, 00696 sourcePassword, targetType, targetDriver, targetUrl, targetUser, 00697 targetPassword, backup, false); 00698 } 00699 00703 final void callOctopusLoader(String sourceType, String sourceUrl, 00704 String sourceDriver, String sourceUser, String sourcePassword, 00705 String targetType, String targetDriver, String targetUrl, 00706 String targetUser, String targetPassword, boolean backup, 00707 boolean generateAllVendors) throws OctopusException 00708 { 00709 try 00710 { 00711 if (logger.isDebugEnabled()) 00712 { 00713 logger.debug("Source Type:" + sourceType); 00714 logger.debug("Source Driver:" + sourceDriver); 00715 logger.debug("Source URL :" + sourceUrl); 00716 logger.debug("Source User :" + sourceUser); 00717 logger.debug("Target Type:" + targetType); 00718 logger.debug("Target Driver:" + targetDriver); 00719 logger.debug("Target URL:" + targetUrl); 00720 logger.debug("Target User :" + targetUser); 00721 if (backup) 00722 logger.debug("Backup Mode"); 00723 else 00724 logger.debug("Restore Mode"); 00725 logger.debug("Generate SQL for all vendors :" + generateAllVendors); 00726 } 00727 LoaderGenerator loader = new LoaderGenerator(sourceType, // sourceType 00728 sourceUrl, // sourceDatabase Url? 00729 COPY_MODE, // valueMode 00730 octopusDir, // generatorOutput 00731 sourceDriver, // sourceDriverName 00732 targetDriver, // TargetDriverName 00733 targetUrl, // targetDataBase 00734 targetType, // TargetType 00735 sourceUser, // sourceUser 00736 sourcePassword, // sourcePassword 00737 targetUser, // targetUser 00738 targetPassword, //targetPassword 00739 "", // domlPath 00740 "org.webdoc.util.loader", // package name 00741 "true", // generate drop table stmt 00742 "true", // generate drop integrity statement 00743 "true", // generate create table stmt 00744 "true", // generate create pk statement 00745 "true", // generate create fk statement 00746 "true", // generate create index stmt 00747 String.valueOf(generateAllVendors), // generate 00748 // sql 00749 // for 00750 // all 00751 // vendors 00752 String.valueOf(!generateAllVendors), // generate 00753 // xml 00754 "false", // generate doml 00755 String.valueOf(!generateAllVendors), // full 00756 // mode 00757 // ?? 00758 String.valueOf(!backup), // restore mode 00759 null, //convertTablesToSemicolonSeparatedList(database.getTables()), 00760 // // tables list 00761 null // Jar file structure 00762 ); 00763 loader.generate(); 00764 } 00765 catch (Exception e) 00766 { 00767 throw new OctopusException(e); 00768 } 00769 } 00770 00771 private String[] convertTablesToArray(ArrayList tablesList) 00772 { 00773 int length = tablesList.size(); 00774 String[] result = new String[length]; 00775 for (int i = 0; i < length; i++) 00776 result[i] = ((DatabaseTable) tablesList.get(i)).getName(); 00777 return result; 00778 } 00779 00785 public boolean isCleanOctopus() 00786 { 00787 return cleanOctopus; 00788 } 00789 00795 public void setCleanOctopus(boolean cleanOctopus) 00796 { 00797 this.cleanOctopus = cleanOctopus; 00798 } 00799 00805 public boolean isZipOctopus() 00806 { 00807 return zipOctopus; 00808 } 00809 00815 public void setZipOctopus(boolean zipOctopus) 00816 { 00817 this.zipOctopus = zipOctopus; 00818 } 00819 00825 public void setListener(BackupListener listener) 00826 { 00827 this.listener = listener; 00828 } 00829 }

CJDBCversion1.0.4に対してTue Oct 12 15:16:00 2004に生成されました。 doxygen 1.3.8