1 16 package org.outerj.daisy.install; 17 18 import org.outerj.daisy.repository.Repository; 19 import org.outerj.daisy.repository.Credentials; 20 import org.outerj.daisy.repository.RepositoryManager; 21 import org.outerj.daisy.repository.user.Role; 22 import org.outerj.daisy.repository.clientimpl.RemoteRepositoryManager; 23 import org.outerj.daisy.jdbcutil.DriverLoader; 24 import org.outerj.daisy.configutil.PropertyResolver; 25 import org.w3c.dom.Document ; 26 import org.w3c.dom.Element ; 27 import org.w3c.dom.NodeList ; 28 29 import javax.xml.parsers.DocumentBuilderFactory ; 30 import javax.xml.parsers.DocumentBuilder ; 31 import javax.xml.transform.TransformerFactory ; 32 import javax.xml.transform.Transformer ; 33 import javax.xml.transform.stream.StreamResult ; 34 import javax.xml.transform.dom.DOMSource ; 35 import java.io.*; 36 import java.util.Properties ; 37 import java.util.List ; 38 import java.util.ArrayList ; 39 import java.util.regex.Pattern ; 40 import java.util.regex.Matcher ; 41 import java.nio.channels.FileChannel ; 42 import java.security.SecureRandom ; 43 import java.sql.DriverManager ; 44 import java.sql.Connection ; 45 import java.sql.DatabaseMetaData ; 46 47 public class InstallHelper { 48 private static List ALL_DATABASES; 49 static { 50 ALL_DATABASES = new ArrayList (); 51 ALL_DATABASES.add(new DatabaseInfo("MySQL-4.1.x (requires version 4.1.7 or higher)", 52 "com.mysql.jdbc.Driver", 53 "mysql/jars/mysql-connector-java-3.1.12-bin.jar", 54 "jdbc:mysql://localhost/@dbname@?useServerPrepStmts=false&characterEncoding=UTF-8", 55 new GenericDatabaseValidator("mysql", 4, 1, 7))); 56 ALL_DATABASES.add(new DatabaseInfo("MySQL-5.x", 57 "com.mysql.jdbc.Driver", 58 "mysql/jars/mysql-connector-java-3.1.12-bin.jar", 59 "jdbc:mysql://localhost/@dbname@?characterEncoding=UTF-8", 60 new GenericDatabaseValidator("mysql", 5, 0, -1))); 61 ALL_DATABASES.add(new DatabaseInfo("PostgreSQL (only for 7.4.x !! see http://cocoondev.org/daisyscratchpad/220.html)", 62 "org.postgresql.Driver", 63 "postgresql/jars/postgresql-7.4-215-jdbc3.jar", 64 "jdbc:postgresql://localhost/@dbname@", 65 new NoOpDatabaseValidator())); 66 ALL_DATABASES.add(new DatabaseInfo("ORACLE (tested for ORACLE 10g) (does not work)", 67 "oracle.jdbc.driver.OracleDriver", 68 "oracle/jars/ojdbc14-10.2.0.1.0.jar", 69 "jdbc:oracle:thin:@localhost:1521:ora10g", 70 new NoOpDatabaseValidator())); 71 } 72 73 public static class DatabaseInfo { 74 private String description; 75 private String driverClass; 76 private String driverPath; 77 private String driverUrl; 78 private DatabaseValidator validator; 79 80 public DatabaseInfo(String description, String driverClass, String driverPath, String driverUrl, DatabaseValidator validator) { 81 this.description = description; 82 this.driverClass = driverClass; 83 this.driverPath = driverPath; 84 this.driverUrl = driverUrl; 85 this.validator = validator; 86 } 87 88 public String getDescription() { 89 return description; 90 } 91 92 public String getDriverClass() { 93 return driverClass; 94 } 95 96 public String getDriverPath() { 97 return driverPath; 98 } 99 100 public String getDriverUrl(String dbname) { 101 return driverUrl.replaceAll("@dbname@", dbname); 102 } 103 104 public DatabaseValidator getValidator() { 105 return validator; 106 } 107 } 108 109 public static DatabaseInfo chooseDatabase() throws Exception { 110 System.out.println("Choose database (MySQL in the only 'officially' supported one):"); 111 for (int i = 0; i < ALL_DATABASES.size(); i++) { 112 DatabaseInfo dbInfo = (DatabaseInfo)ALL_DATABASES.get(i); 113 System.out.println(" " + (i + 1) + ". " + dbInfo.getDescription()); 114 } 115 System.out.println(); 116 int dbIndex = Integer.parseInt(prompt("Choose database type [enter number, default 1] : ", "1")); 117 if (dbIndex < 1 || dbIndex > ALL_DATABASES.size()) { 118 System.out.println("Number too large or small, quiting."); 119 System.exit(1); 120 } 121 return (DatabaseInfo)ALL_DATABASES.get(dbIndex - 1); 122 } 123 124 public static class DatabaseParams { 125 private final String url; 126 private final String user; 127 private final String password; 128 private final String driverClassName; 129 private final String driverClassPath; 130 private final DatabaseValidator validator; 131 132 public DatabaseParams(String url, String user, String password, String driverClassName, String driverClassPath) { 133 this(url, user, password, driverClassName, driverClassPath, null); 134 } 135 136 public DatabaseParams(String url, String user, String password, String driverClassName, String driverClassPath, 137 DatabaseValidator validator) { 138 this.url = url; 139 this.user = user; 140 this.password = password; 141 this.driverClassName = driverClassName; 142 this.driverClassPath = driverClassPath; 143 this.validator = validator; 144 } 145 146 public String getUrl() { 147 return url; 148 } 149 150 public String getUser() { 151 return user; 152 } 153 154 public String getPassword() { 155 return password; 156 } 157 158 public String getDriverClassName() { 159 return driverClassName; 160 } 161 162 public String getDriverClassPath() { 163 return driverClassPath; 164 } 165 166 public void loadDriver() throws Exception { 167 DriverLoader.loadDatabaseDriver(PropertyResolver.resolveProperties(driverClassPath), driverClassName); 168 } 169 170 public void checkDatabase() throws Exception { 171 Connection conn = null; 172 try { 173 conn = DriverManager.getConnection(getUrl(), getUser(), getPassword()); 174 if (validator != null) 175 validator.validate(conn); 176 } finally { 177 if (conn != null) 178 conn.close(); 179 } 180 } 181 } 182 183 public static DatabaseParams collectDatabaseParams(DatabaseInfo dbInfo, String user, String password, String dbName) throws Exception { 184 String dbUrl = dbInfo.getDriverUrl(dbName); 185 dbUrl = InstallHelper.prompt("Enter database URL [default = " + dbUrl + "] : ", dbUrl); 186 String dbUser = InstallHelper.prompt("Enter database user [default = " + user + "] : ", user); 187 String dbPassword = InstallHelper.prompt("Enter database password [default = " + password + "] : ", password); 188 189 String dbDriverClassName = dbInfo.getDriverClass(); 190 dbDriverClassName = InstallHelper.prompt("Enter database driver class [default = " + dbDriverClassName + "] : ", dbDriverClassName); 191 192 String dbDriverClasspath = getRepoLocation() + "/" + dbInfo.getDriverPath(); 193 dbDriverClasspath = InstallHelper.prompt("Enter database driver jar location [default = " + dbDriverClasspath + "] : ", dbDriverClasspath); 194 195 DatabaseParams dbParams = new DatabaseParams(dbUrl, dbUser, dbPassword, dbDriverClassName, dbDriverClasspath, dbInfo.getValidator()); 196 System.out.println("Registering driver..."); 197 dbParams.loadDriver(); 198 System.out.println("Successful."); 199 System.out.println(); 200 201 return dbParams; 202 } 203 204 public static String getRepoLocation() { 205 String daisyHome = System.getProperty("daisy.home"); 206 String repoLocation; 207 if (daisyHome != null) { 208 repoLocation = "${daisy.home}" + File.separator + "lib"; 209 } else { 210 repoLocation = System.getProperty("user.home") + "/.maven/repository"; 211 } 212 return repoLocation; 213 } 214 215 public static File getDaisyHome() throws Exception { 216 String daisyHomeProp = System.getProperty("daisy.home"); 217 218 if (daisyHomeProp == null) 219 throw new Exception ("System property daisy.home missing."); 220 221 File daisyHome = new File(daisyHomeProp); 222 if (!daisyHome.exists() || !daisyHome.isDirectory()) 223 throw new Exception ("daisy.home does not point to an existing directory"); 224 225 return daisyHome; 226 } 227 228 public static File getDaisySourceHome() throws Exception { 229 String daisySourceHomeProp = System.getProperty("daisy.sourcehome"); 230 231 if (daisySourceHomeProp == null) 232 throw new Exception ("System property daisy.sourcehome missing."); 233 234 File daisySourceHome = new File(daisySourceHomeProp); 235 if (!daisySourceHome.exists() || !daisySourceHome.isDirectory()) 236 throw new Exception ("daisy.sourcehome does not point to an existing directory"); 237 238 return daisySourceHome; 239 } 240 241 public static boolean isDevelopmentSetup() { 242 return System.getProperty("daisy.home") == null; 243 } 244 245 public static boolean isDistroDirectory(File daisyHome) { 246 File file = new File(daisyHome, "repository-server"); 248 return file.exists(); 249 } 250 251 public static String prompt(String message) throws Exception { 252 System.out.println(message); 253 System.out.flush(); 254 String input = null; 255 while (input == null || input.trim().equals("")) { 256 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 257 try { 258 input = in.readLine(); 259 } catch (IOException e) { 260 throw new Exception ("Error reading input from console.", e); 261 } 262 } 263 return input; 264 } 265 266 public static String prompt(String message, String defaultInput) throws Exception { 267 System.out.println(message); 268 System.out.flush(); 269 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 270 String input; 271 try { 272 input = in.readLine(); 273 } catch (IOException e) { 274 throw new Exception ("Error reading input from console.", e); 275 } 276 if (input == null || input.trim().equals("")) 277 input = defaultInput; 278 return input; 279 } 280 281 public static boolean promptYesNo(String message, boolean defaultInput) throws Exception { 282 String input = ""; 283 while (!input.equals("yes") && !input.equals("no")) { 284 input = prompt(message, defaultInput ? "yes" : "no"); 285 input = input.toLowerCase(); 286 } 287 return input.equals("yes"); 288 } 289 290 public static void waitPrompt() throws Exception { 291 promptYesNo("Press enter to continue.", true); 292 } 293 294 public static void printTitle(String title) { 295 System.out.println("--------------------------------------------------------------------------"); 296 System.out.println(title); 297 System.out.println("--------------------------------------------------------------------------"); 298 } 299 300 public static String generatePassword() throws Exception { 301 byte[] bytes = new byte[15]; 302 SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 303 random.nextBytes(bytes); 304 return toHexString(bytes); 305 } 306 307 public static String toHexString(byte[] b) { 308 StringBuffer sb = new StringBuffer (b.length * 2); 309 for (int i = 0; i < b.length; i++) { 310 sb.append(hexChar[(b[i] & 0xf0) >>> 4]); 311 sb.append(hexChar[b[i] & 0x0f]); 312 } 313 return sb.toString(); 314 } 315 316 static char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 317 318 public static Properties loadDistroProperties(File daisyHome) throws Exception { 319 Properties properties = new Properties (); 320 File config = new File(daisyHome, "config.properties"); 321 if (config.exists()) { 322 properties.load(new FileInputStream(config)); 323 } 324 return properties; 325 } 326 327 public static void storeDistroProperties(Properties properties, File daisyHome) throws Exception { 328 File config = new File(daisyHome, "config.properties"); 329 properties.store(new FileOutputStream(config), null); 330 } 331 332 public static void copyFile(File source, File destination) throws Exception { 333 if (source.isDirectory()) { 334 destination.mkdirs(); 335 File[] files = source.listFiles(); 336 for (int i = 0; i < files.length; i++) { 337 copyFile(files[i], new File(destination, files[i].getName())); 338 } 339 } else { 340 destination.getParentFile().mkdirs(); 341 destination.createNewFile(); 342 copyFileFile(source, destination); 343 } 344 } 345 346 private static void copyFileFile(File source, File destination) throws Exception { 347 FileChannel srcChannel = new FileInputStream(source).getChannel(); 348 FileChannel dstChannel = new FileOutputStream(destination).getChannel(); 349 dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); 350 srcChannel.close(); 351 dstChannel.close(); 352 } 353 354 public static void deleteFile(File file) { 355 if (file.isDirectory()) { 356 File[] files = file.listFiles(); 357 for (int i = 0; i < files.length; i++) 358 deleteFile(files[i]); 359 } 360 file.delete(); 361 } 362 363 public static void copyStream(InputStream source, File destination) throws Exception { 364 FileOutputStream os = null; 365 try { 366 os = new FileOutputStream(destination); 367 byte[] buffer = new byte[32768]; 368 int read; 369 while ((read = source.read(buffer)) != -1) { 370 os.write(buffer, 0, read); 371 } 372 } finally { 373 if (source != null) 374 source.close(); 375 if (os != null) 376 os.close(); 377 } 378 } 379 380 public static Repository promptRepository() throws Exception { 381 System.out.println(" == Login To Daisy Repository Server =="); 382 String url = InstallHelper.prompt("Address where the Daisy Repository Server is listening [default = http://localhost:9263] :", "http://localhost:9263"); 383 System.out.println("Enter login (user) and password for Daisy (this should be a user with the Administrator role):"); 384 String login = InstallHelper.prompt("Enter login: "); 385 String pwd = InstallHelper.prompt("Enter password: "); 386 System.out.println(); 387 Credentials credentials = new Credentials(login, pwd); 388 389 RepositoryManager repositoryManager = new RemoteRepositoryManager(url, credentials); 390 Repository repository = repositoryManager.getRepository(credentials); 391 repository.switchRole(Role.ADMINISTRATOR); 392 return repository; 393 } 394 395 public static File promptForEmptyDir(String message, String defaultPath) throws Exception { 396 File dir; 397 while (true) { 398 String dirInput = defaultPath == null ? InstallHelper.prompt(message) : InstallHelper.prompt(message + " [ default = " + defaultPath + "]", defaultPath); 400 dir = new File(dirInput); 401 if (dir.exists() && !dir.isDirectory()) { 402 System.out.println("\nThe specified path exists and is not a directory."); 403 continue; 404 } else if (dir.exists() && dir.list().length > 0) { 405 System.out.println("\nThe specified directory exists and is not empty."); 406 continue; 407 } 408 break; 409 } 410 return dir; 411 } 412 413 public static void backupFile(File file) throws Exception { 414 File backupFile = new File(file.getAbsolutePath() + ".backup"); 415 InstallHelper.copyFile(file, backupFile); 416 System.out.println("Made backup file " + backupFile.getAbsolutePath()); 417 } 418 419 public static Document parseFile(File file) throws Exception { 420 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); 421 documentBuilderFactory.setNamespaceAware(true); 422 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); 423 return documentBuilder.parse(file); 424 } 425 426 public static void saveDocument(File file, Document document) throws Exception { 427 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 428 Transformer transformer = transformerFactory.newTransformer(); 429 DOMSource source = new DOMSource (document); 430 StreamResult result = new StreamResult (file); 431 transformer.setOutputProperty("encoding", "UTF-8"); 432 transformer.transform(source, result); 433 } 434 435 public static void setElementValue(Element element, String value) { 436 NodeList nodes = element.getChildNodes(); 437 for (int i = 0; i < nodes.getLength(); i++) 438 element.removeChild(nodes.item(i)); 439 440 element.appendChild(element.getOwnerDocument().createTextNode(value)); 441 } 442 443 450 public static String getPropertyValue (Properties props, String key) throws PropertyNotFoundException { 451 if ((props.containsKey(key))&&(props.getProperty(key)!=null)){ 452 return props.getProperty(key); 453 }else { 454 throw new PropertyNotFoundException(key); 455 } 456 } 457 458 465 public static String getPropertyValue (Properties props, String key, String defaultValue) { 466 String value = defaultValue; 467 try { 468 value = getPropertyValue(props, key); 469 } catch (PropertyNotFoundException e) { 470 System.out.println("Value for property " + key + " not found. Falling back to a default value."); 471 } 472 return value; 473 } 474 475 static interface DatabaseValidator { 476 void validate(Connection conn) throws Exception ; 477 } 478 479 static class NoOpDatabaseValidator implements DatabaseValidator { 480 public void validate(Connection conn) throws Exception { 481 } 483 } 484 485 static class GenericDatabaseValidator implements DatabaseValidator { 486 private String databaseProductName; 487 private int majorVersion; 488 private int minorVersion; 489 private int patchVersion; 490 491 public GenericDatabaseValidator(String databaseProductName, int majorVersion, int minorVersion, int patchVersion) { 492 this.databaseProductName = databaseProductName; 493 this.majorVersion = majorVersion; 494 this.minorVersion = minorVersion; 495 this.patchVersion = patchVersion; 496 } 497 498 public void validate(Connection conn) throws Exception { 499 DatabaseMetaData metadata = conn.getMetaData(); 500 501 String dbProductName = metadata.getDatabaseProductName(); 502 if (!dbProductName.equalsIgnoreCase(databaseProductName)) { 503 System.out.println(" *** WARNING ***"); 504 System.out.println("Database reported it is \"" + dbProductName + "\" but \"" + databaseProductName + "\" was expected."); 505 if (!promptYesNo("Continue anyway? [yes/no, default: no]", false)) { 506 System.exit(1); 507 } else { 508 return; 510 } 511 } 512 513 System.out.println("Detected database version: " + metadata.getDatabaseProductVersion()); 514 515 int foundMajorVersion = metadata.getDatabaseMajorVersion(); 516 int foundMinorVersion = metadata.getDatabaseMinorVersion(); 517 if (foundMajorVersion != majorVersion || foundMinorVersion != minorVersion) { 518 System.out.println(" *** WARNING ***"); 519 System.out.println("Expected database product version " + majorVersion + "." + minorVersion + " but instead found " + foundMajorVersion + "." + foundMinorVersion); 520 if (!promptYesNo("Continue anyway? [yes/no, default: no]", false)) { 521 System.exit(1); 522 } else { 523 return; 524 } 525 } 526 527 if (patchVersion != -1) { 529 Pattern versionPattern = Pattern.compile("([0-9]+)\\.([0-9]+)\\.([0-9]+).*"); 530 Matcher versionMatcher = versionPattern.matcher(metadata.getDatabaseProductVersion()); 531 if (versionMatcher.matches()) { 532 int majorVersion = Integer.parseInt(versionMatcher.group(1)); 533 int minorVersion = Integer.parseInt(versionMatcher.group(2)); 534 int patchVersion = Integer.parseInt(versionMatcher.group(3)); 535 536 if (patchVersion < this.patchVersion) { 537 String version = majorVersion + "." + minorVersion + "." + patchVersion; 538 String recommendedVersion = majorVersion + "." + minorVersion + "." + patchVersion; 539 System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 540 System.out.println(" WARNING: you are using " + databaseProductName + " version " + version); 541 System.out.println(" but for Daisy we recommend at least " + recommendedVersion); 542 System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 543 } 544 } else { 545 System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 546 System.out.println(" Warning: unrecognized version string: " + metadata.getDatabaseProductName()); 547 System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); 548 } 549 } 550 } 551 552 } 553 } 554 | Popular Tags |