1 43 package net.jforum.view.install; 44 45 import java.io.File ; 46 import java.io.FileInputStream ; 47 import java.io.FileOutputStream ; 48 import java.io.IOException ; 49 import java.nio.channels.FileChannel ; 50 import java.sql.Connection ; 51 import java.sql.PreparedStatement ; 52 import java.sql.SQLException ; 53 import java.sql.Statement ; 54 import java.util.Enumeration ; 55 import java.util.Iterator ; 56 import java.util.List ; 57 import java.util.Properties ; 58 59 import javax.servlet.http.HttpServletResponse ; 60 61 import net.jforum.ActionServletRequest; 62 import net.jforum.Command; 63 import net.jforum.ConfigLoader; 64 import net.jforum.DBConnection; 65 import net.jforum.DataSourceConnection; 66 import net.jforum.JForumExecutionContext; 67 import net.jforum.SessionFacade; 68 import net.jforum.SimpleConnection; 69 import net.jforum.entities.UserSession; 70 import net.jforum.util.FileMonitor; 71 import net.jforum.util.I18n; 72 import net.jforum.util.MD5; 73 import net.jforum.util.preferences.ConfigKeys; 74 import net.jforum.util.preferences.SystemGlobals; 75 import net.jforum.util.preferences.SystemGlobalsListener; 76 import net.jforum.util.preferences.TemplateKeys; 77 78 import org.apache.log4j.Logger; 79 80 import freemarker.template.SimpleHash; 81 import freemarker.template.Template; 82 83 89 public class InstallAction extends Command 90 { 91 private static Logger logger = Logger.getLogger(InstallAction.class); 92 93 public void welcome() throws Exception 94 { 95 this.checkLanguage(); 96 97 this.context.put("language", this.getFromSession("language")); 98 this.context.put("database", this.getFromSession("database")); 99 this.context.put("dbhost", this.getFromSession("dbHost")); 100 this.context.put("dbuser", this.getFromSession("dbUser")); 101 this.context.put("dbname", this.getFromSession("dbName")); 102 this.context.put("dbpasswd", this.getFromSession("dbPassword")); 103 this.context.put("dbencoding", this.getFromSession("dbEncoding")); 104 this.context.put("use_pool", this.getFromSession("usePool")); 105 this.context.put("forumLink", this.getFromSession("forumLink")); 106 this.context.put("siteLink", this.getFromSession("siteLink")); 107 this.context.put("dbdatasource", this.getFromSession("dbdatasource")); 108 109 this.setTemplateName(TemplateKeys.INSTALL_WELCOME); 110 } 111 112 private void checkLanguage() throws IOException 113 { 114 String lang = this.request.getParameter("l"); 115 if (lang == null || !I18n.languageExists(lang)) { 116 return; 117 } 118 119 I18n.load(lang); 120 121 UserSession us = new UserSession(); 122 us.setLang(lang); 123 124 SessionFacade.add(us); 125 this.addToSessionAndContext("language", lang); 126 } 127 128 private String getFromSession(String key) 129 { 130 return (String )this.request.getSession().getAttribute(key); 131 } 132 133 private void error() 134 { 135 this.setTemplateName(TemplateKeys.INSTALL_ERROR); 136 } 137 138 public void doInstall() throws Exception 139 { 140 Connection conn = null; 141 142 if (!this.checkForWritableDir()) { 143 return; 144 } 145 146 this.removeUserConfig(); 147 148 if (!"passed".equals(this.getFromSession("configureDatabase"))) { 149 logger.info("Going to configure the database..."); 150 conn = this.configureDatabase(); 151 if (conn == null) { 152 this.context.put("message", I18n.getMessage("Install.databaseError")); 153 this.error(); 154 return; 155 } 156 } 157 158 logger.info("Database configuration ok"); 159 160 this.addToSessionAndContext("configureDatabase", "passed"); 162 163 DBConnection simpleConnection = new SimpleConnection(); 164 if (conn == null) { 165 conn = simpleConnection.getConnection(); 166 } 167 168 if (!"passed".equals(this.getFromSession("createTables")) && !this.createTables(conn)) { 169 this.context.put("message", I18n.getMessage("Install.createTablesError")); 170 simpleConnection.releaseConnection(conn); 171 this.error(); 172 return; 173 } 174 175 this.addToSessionAndContext("createTables", "passed"); 177 logger.info("Table creation is ok"); 178 179 if (!"passed".equals(this.getFromSession("importTablesData")) && !this.importTablesData(conn)) { 180 this.context.put("message", I18n.getMessage("Install.importTablesDataError")); 181 simpleConnection.releaseConnection(conn); 182 this.error(); 183 return; 184 } 185 186 this.addToSessionAndContext("importTablesData", "passed"); 188 189 if (!this.updateAdminPassword(conn)) { 190 this.context.put("message", I18n.getMessage("Install.updateAdminError")); 191 simpleConnection.releaseConnection(conn); 192 this.error(); 193 return; 194 } 195 196 simpleConnection.releaseConnection(conn); 197 198 JForumExecutionContext.setRedirect(this.request.getContextPath() + "/install/install" 199 + SystemGlobals.getValue(ConfigKeys.SERVLET_EXTENSION) 200 + "?module=install&action=finished"); 201 } 202 203 private void removeUserConfig() 204 { 205 File f = new File (SystemGlobals.getValue(ConfigKeys.INSTALLATION_CONFIG)); 206 if (f.exists() && f.canWrite()) { 207 try { 208 f.delete(); 209 } 210 catch (Exception e) { 211 logger.info(e.toString()); 212 } 213 } 214 } 215 216 public void finished() throws Exception 217 { 218 this.setTemplateName(TemplateKeys.INSTALL_FINISHED); 219 220 this.context.put("clickHere", I18n.getMessage("Install.clickHere")); 221 this.context.put("forumLink", this.getFromSession("forumLink")); 222 223 String lang = this.getFromSession("language"); 224 if (lang == null) { 225 lang = "en_US"; 226 } 227 228 this.context.put("lang", lang); 229 230 this.doFinalSteps(); 231 this.configureSystemGlobals(); 232 233 SystemGlobals.loadQueries(SystemGlobals.getValue(ConfigKeys.SQL_QUERIES_GENERIC)); 234 SystemGlobals.loadQueries(SystemGlobals.getValue(ConfigKeys.SQL_QUERIES_DRIVER)); 235 236 SessionFacade.remove(this.request.getSession().getId()); 237 } 238 239 private void doFinalSteps() 240 { 241 try { 242 String modulesMapping = SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) + "/modulesMapping.properties"; 244 if (new File (modulesMapping).canWrite()) { 245 Properties p = new Properties (); 246 p.load(new FileInputStream (modulesMapping)); 247 248 if (p.containsKey("install")) { 249 p.remove("install"); 250 251 p.store(new FileOutputStream (modulesMapping), "Modified by JForum Installer"); 252 253 this.addToSessionAndContext("mappingFixed", "true"); 254 ConfigLoader.loadModulesMapping(SystemGlobals.getValue(ConfigKeys.CONFIG_DIR)); 255 } 256 } 257 } 258 catch (Exception e) { 259 logger.warn("Error while working on modulesMapping.properties: " + e); 260 } 261 262 263 try { 264 String index = SystemGlobals.getApplicationPath() + "/index.htm"; 266 File indexFile = new File (index); 267 268 if (indexFile.canWrite()) { 269 String newIndex = SystemGlobals.getApplicationPath() + "/__index.redirect"; 270 File newIndexFile = new File (newIndex); 271 272 if (newIndexFile.exists()) { 273 indexFile.delete(); 274 newIndexFile.renameTo(indexFile); 275 276 this.addToSessionAndContext("indexFixed", "true"); 277 } 278 } 279 } 280 catch (Exception e) { 281 logger.warn("Error while renaming index.htm: " + e, e); 282 } 283 } 284 285 private void configureSystemGlobals() throws Exception 286 { 287 SystemGlobals.setValue(ConfigKeys.USER_HASH_SEQUENCE, MD5.crypt(this.getFromSession("dbPassword") 288 + System.currentTimeMillis())); 289 290 SystemGlobals.setValue(ConfigKeys.FORUM_LINK, this.getFromSession("forumLink")); 291 SystemGlobals.setValue(ConfigKeys.HOMEPAGE_LINK, this.getFromSession("siteLink")); 292 SystemGlobals.setValue(ConfigKeys.I18N_DEFAULT, this.getFromSession("language")); 293 SystemGlobals.setValue(ConfigKeys.INSTALLED, "true"); 294 SystemGlobals.saveInstallation(); 295 296 this.restartSystemGlobals(); 297 } 298 299 private boolean importTablesData(Connection conn) throws Exception 300 { 301 boolean status = true; 302 boolean autoCommit = conn.getAutoCommit(); 303 conn.setAutoCommit(false); 304 305 String dbType = this.getFromSession("database"); 306 307 List statements = ParseDBDumpFile.parse(SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) 308 + "/database/" 309 + dbType 310 + "/" + dbType + "_data_dump.sql"); 311 312 for (Iterator iter = statements.iterator(); iter.hasNext();) { 313 String query = (String )iter.next(); 314 315 if (query == null || "".equals(query.trim())) { 316 continue; 317 } 318 319 query = query.trim(); 320 321 Statement s = conn.createStatement(); 322 323 try { 324 if (query.startsWith("UPDATE") || query.startsWith("INSERT") 325 || query.startsWith("SET")) { 326 s.executeUpdate(query); 327 } 328 else if (query.startsWith("SELECT")) { 329 s.executeQuery(query); 330 } 331 else { 332 throw new Exception ("Invalid query: " + query); 333 } 334 } 335 catch (SQLException ex) { 336 status = false; 337 conn.rollback(); 338 logger.error("Error importing data for " + query + ": " + ex, ex); 339 this.context.put("exceptionMessage", ex.getMessage() + "\n" + query); 340 break; 341 } 342 finally { 343 s.close(); 344 } 345 } 346 347 conn.setAutoCommit(autoCommit); 348 return status; 349 } 350 351 private boolean createTables(Connection conn) throws Exception 352 { 353 logger.info("Going to create tables..."); 354 String dbType = this.getFromSession("database"); 355 356 if ("postgresql".equals(dbType)) { 357 this.dropPostgresqlTables(conn); 358 } 359 else if ("oracle".equals(dbType)) { 360 this.dropOracleTables(conn); 361 } 362 363 boolean status = true; 364 365 List statements = ParseDBStructFile.parse(SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) 366 + "/database/" 367 + dbType 368 + "/" + dbType + "_db_struct.sql"); 369 370 for (Iterator iter = statements.iterator(); iter.hasNext(); ) { 371 String query = (String )iter.next(); 372 373 if (query == null || "".equals(query.trim())) { 374 continue; 375 } 376 377 Statement s = conn.createStatement(); 378 379 try { 380 s.executeUpdate(query); 381 } 382 catch (SQLException ex) { 383 status = false; 384 385 logger.error("Error executing query: " + query + ": " + ex, ex); 386 this.context.put("exceptionMessage", ex.getMessage() + "\n" + query); 387 388 break; 389 } 390 finally { 391 s.close(); 392 } 393 } 394 395 return status; 396 } 397 398 private void dropOracleTables(Connection conn) 399 { 400 Statement s = null; 401 402 try { 403 List statements = ParseDBStructFile.parse(SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) 404 + "/database/oracle/oracle_db_struct_drop.sql"); 405 406 for (Iterator iter = statements.iterator(); iter.hasNext(); ) { 407 try { 408 String query = (String )iter.next(); 409 410 if (query == null || "".equals(query.trim())) { 411 continue; 412 } 413 414 s = conn.createStatement(); 415 s.executeQuery(query); 416 s.close(); 417 } 418 catch (Exception e) { 419 logger.error("IGNORE: " + e.toString()); 420 } 421 } 422 } 423 catch (Exception e) { 424 logger.error(e.toString(), e); 425 } 426 finally { 427 if (s != null) { 428 try { s.close(); } catch (Exception e) {} 429 } 430 } 431 } 432 433 private boolean checkForWritableDir() 434 { 435 boolean canWriteToWebInf = this.canWriteToWebInf(); 436 boolean canWriteToIndex = this.canWriteToIndex(); 437 438 if (!canWriteToWebInf || !canWriteToIndex) { 439 this.context.put("message", I18n.getMessage("Install.noWritePermission")); 440 this.context.put("tryAgain", true); 441 this.error(); 442 return false; 443 } 444 445 return true; 446 } 447 448 private boolean canWriteToWebInf() 449 { 450 return new File (SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) + "/modulesMapping.properties").canWrite(); 451 } 452 453 454 private boolean canWriteToIndex() 455 { 456 return new File (SystemGlobals.getApplicationPath() + "/index.htm").canWrite(); 457 } 458 459 private void configureJDBCConnection() throws Exception 460 { 461 String username = this.getFromSession("dbUser"); 462 String password = this.getFromSession("dbPassword"); 463 String dbName = this.getFromSession("dbName"); 464 String host = this.getFromSession("dbHost"); 465 String type = this.getFromSession("database"); 466 String encoding = this.getFromSession("dbEncoding"); 467 468 Properties p = new Properties (); 469 p.load(new FileInputStream (SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) 470 + "/database/" + type + "/" + type + ".properties")); 471 472 p.setProperty(ConfigKeys.DATABASE_CONNECTION_HOST, host); 474 p.setProperty(ConfigKeys.DATABASE_CONNECTION_USERNAME, username); 475 p.setProperty(ConfigKeys.DATABASE_CONNECTION_PASSWORD, password); 476 p.setProperty(ConfigKeys.DATABASE_CONNECTION_DBNAME, dbName); 477 p.setProperty(ConfigKeys.DATABASE_CONNECTION_ENCODING, encoding); 478 479 FileOutputStream fos = null; 480 481 try { 482 fos = new FileOutputStream (SystemGlobals.getValue(ConfigKeys.CONFIG_DIR) 483 + "/database/" + type + "/" + type + ".properties"); 484 p.store(fos, null); 485 } 486 catch (Exception e) { 487 logger.warn("Error while trying to write to " + type + ".properties: " + e); 488 } 489 finally { 490 if (fos != null) { 491 fos.close(); 492 } 493 } 494 495 for (Enumeration e = p.keys(); e.hasMoreElements(); ) { 497 String key = (String )e.nextElement(); 498 SystemGlobals.setValue(key, p.getProperty(key)); 499 } 500 501 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_HOST, host); 502 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_USERNAME, username); 503 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_PASSWORD, password); 504 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_DBNAME, dbName); 505 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_ENCODING, encoding); 506 } 507 508 private void copyFile(String from, String to) throws Exception 509 { 510 FileChannel source = new FileInputStream (new File (from)).getChannel(); 511 FileChannel dest = new FileOutputStream (new File (to)).getChannel(); 512 513 source.transferTo(0, source.size(), dest); 514 source.close(); 515 dest.close(); 516 } 517 518 private Connection configureDatabase() throws Exception 519 { 520 String database = this.getFromSession("database"); 521 String connectionType = this.getFromSession("db_connection_type"); 522 String implementation; 523 boolean isDs = false; 524 525 if ("JDBC".equals(connectionType)) { 526 implementation = "yes".equals(this.getFromSession("usePool")) && !"hsqldb".equals(database) 527 ? "net.jforum.PooledConnection" 528 : "net.jforum.SimpleConnection"; 529 530 this.configureJDBCConnection(); 531 } 532 else { 533 isDs = true; 534 implementation = "net.jforum.DataSourceConnection"; 535 SystemGlobals.setValue(ConfigKeys.DATABASE_DATASOURCE_NAME, this.getFromSession("dbdatasource")); 536 } 537 538 SystemGlobals.setValue(ConfigKeys.DATABASE_CONNECTION_IMPLEMENTATION, implementation); 539 SystemGlobals.setValue(ConfigKeys.DATABASE_DRIVER_NAME, database); 540 541 SystemGlobals.saveInstallation(); 542 this.restartSystemGlobals(); 543 544 int fileChangesDelay = SystemGlobals.getIntValue(ConfigKeys.FILECHANGES_DELAY); 545 if (fileChangesDelay > 0) { 546 FileMonitor.getInstance().addFileChangeListener(new SystemGlobalsListener(), 547 SystemGlobals.getValue(ConfigKeys.INSTALLATION_CONFIG), fileChangesDelay); 548 } 549 550 Connection conn = null; 551 552 try { 553 DBConnection s; 554 555 if (!isDs) { 556 s = new SimpleConnection(); 557 } 558 else { 559 s = new DataSourceConnection(); 560 } 561 562 s.init(); 563 564 conn = s.getConnection(); 565 } 566 catch (Exception e) { 567 logger.warn("Error while trying to get a connection: " + e); 568 this.context.put("exceptionMessage", e.getMessage()); 569 return null; 570 } 571 572 return conn; 573 } 574 575 private void restartSystemGlobals() throws Exception 576 { 577 String appPath = SystemGlobals.getApplicationPath(); 578 SystemGlobals.initGlobals(appPath, appPath + "/WEB-INF/config/SystemGlobals.properties"); 579 SystemGlobals.loadAdditionalDefaults(SystemGlobals.getValue(ConfigKeys.DATABASE_DRIVER_CONFIG)); 580 581 if (new File (SystemGlobals.getValue(ConfigKeys.INSTALLATION_CONFIG)).exists()) { 582 SystemGlobals.loadAdditionalDefaults(SystemGlobals.getValue(ConfigKeys.INSTALLATION_CONFIG)); 583 } 584 } 585 586 private boolean updateAdminPassword(Connection conn) throws Exception 587 { 588 logger.info("Going to update the administrator's password"); 589 590 boolean status = false; 591 592 try { 593 PreparedStatement p = conn.prepareStatement("UPDATE jforum_users SET user_password = ? WHERE username = 'Admin'"); 594 p.setString(1, MD5.crypt(this.getFromSession("adminPassword"))); 595 p.executeUpdate(); 596 p.close(); 597 598 status = true; 599 } 600 catch (Exception e) { 601 logger.warn("Error while trying to update the administrator's password: " + e); 602 this.context.put("exceptionMessage", e.getMessage()); 603 } 604 605 return status; 606 } 607 608 public void checkInformation() throws Exception 609 { 610 this.setTemplateName(TemplateKeys.INSTALL_CHECK_INFO); 611 612 String language = this.request.getParameter("language"); 613 String database = this.request.getParameter("database"); 614 String dbHost = this.request.getParameter("dbhost"); 615 String dbUser = this.request.getParameter("dbuser"); 616 String dbName = this.request.getParameter("dbname"); 617 String dbPassword = this.request.getParameter("dbpasswd"); 618 String dbEncoding = this.request.getParameter("dbencoding"); 619 String dbEncodingOther = this.request.getParameter("dbencoding_other"); 620 String usePool = this.request.getParameter("use_pool"); 621 String forumLink = this.request.getParameter("forum_link"); 622 String adminPassword = this.request.getParameter("admin_pass1"); 623 624 dbHost = this.notNullDefault(dbHost, "localhost"); 625 dbEncodingOther = this.notNullDefault(dbEncodingOther, "utf-8"); 626 dbEncoding = this.notNullDefault(dbEncoding, dbEncodingOther); 627 forumLink = this.notNullDefault(forumLink, "http://localhost"); 628 dbName = this.notNullDefault(dbName, "jforum"); 629 630 if ("hsqldb".equals(database)) { 631 dbUser = this.notNullDefault(dbUser, "sa"); 632 } 633 634 this.addToSessionAndContext("language", language); 635 this.addToSessionAndContext("database", database); 636 this.addToSessionAndContext("dbHost", dbHost); 637 this.addToSessionAndContext("dbUser", dbUser); 638 this.addToSessionAndContext("dbName", dbName); 639 this.addToSessionAndContext("dbPassword", dbPassword); 640 this.addToSessionAndContext("dbEncoding", dbEncoding); 641 this.addToSessionAndContext("usePool", usePool); 642 this.addToSessionAndContext("forumLink", forumLink); 643 this.addToSessionAndContext("siteLink", this.request.getParameter("site_link")); 644 this.addToSessionAndContext("adminPassword", adminPassword); 645 this.addToSessionAndContext("dbdatasource", this.request.getParameter("dbdatasource")); 646 this.addToSessionAndContext("db_connection_type", this.request.getParameter("db_connection_type")); 647 648 this.addToSessionAndContext("configureDatabase", null); 649 this.addToSessionAndContext("createTables", null); 650 this.addToSessionAndContext("importTablesData", null); 651 652 this.context.put("canWriteToWebInf", this.canWriteToWebInf()); 653 this.context.put("canWriteToIndex", this.canWriteToIndex()); 654 655 this.context.put("moduleAction", "install_check_info.htm"); 656 } 657 658 private void dropPostgresqlTables(Connection conn) throws Exception 659 { 660 String [] tables = { "jforum_banlist", "jforum_banlist_seq", "jforum_categories", 661 "jforum_categories_order_seq", "jforum_categories_seq", "jforum_config", 662 "jforum_config_seq", "jforum_forums", "jforum_forums_seq", "jforum_groups", 663 "jforum_groups_seq", "jforum_posts", "jforum_posts_seq", "jforum_posts_text", 664 "jforum_privmsgs", "jforum_privmsgs_seq", "jforum_privmsgs_text", 665 "jforum_ranks", "jforum_ranks_seq", "jforum_role_values", "jforum_roles", 666 "jforum_roles_seq", "jforum_search_results", "jforum_search_topics", 667 "jforum_search_wordmatch", "jforum_search_words", "jforum_search_words_seq", "jforum_sessions", 668 "jforum_smilies", "jforum_smilies_seq", "jforum_themes", "jforum_themes_seq", 669 "jforum_topics", "jforum_topics_seq", "jforum_topics_watch", "jforum_user_groups", 670 "jforum_users", "jforum_users_seq", "jforum_vote_desc", "jforum_vote_desc_seq", 671 "jforum_vote_results", "jforum_vote_voters", "jforum_words", "jforum_words_seq", 672 "jforum_karma_seq", "jforum_karma", "jforum_bookmarks_seq", "jforum_bookmarks", 673 "jforum_quota_limit", "jforum_quota_limit_seq", "jforum_extension_groups_seq", 674 "jforum_extension_groups", "jforum_extensions_seq", "jforum_extensions", 675 "jforum_attach_seq", "jforum_attach", "jforum_attach_desc_seq", "jforum_attach_desc", 676 "jforum_attach_quota_seq", "jforum_attach_quota", "jforum_banner", "jforum_banner_seq", 677 "jforum_forums_watch" }; 678 679 for (int i = 0; i < tables.length; i++) { 680 Statement s = conn.createStatement(); 681 String query = tables[i].endsWith("_seq") ? "DROP SEQUENCE " : "DROP TABLE "; 682 query += tables[i]; 683 684 try { 685 s.executeUpdate(query); 686 } 687 catch (SQLException e) { 688 logger.info("IGNORE: " + e.getMessage()); 689 } 690 691 s.close(); 692 } 693 } 694 695 private void addToSessionAndContext(String key, String value) 696 { 697 this.request.getSession().setAttribute(key, value); 698 this.context.put(key, value); 699 } 700 701 private String notNullDefault(String value, String useDefault) 702 { 703 if (value == null || value.trim().equals("")) { 704 return useDefault; 705 } 706 707 return value; 708 } 709 710 713 public void list() throws Exception 714 { 715 this.welcome(); 716 } 717 718 721 public Template process(ActionServletRequest request, 722 HttpServletResponse response, 723 SimpleHash context) throws Exception 724 { 725 this.setTemplateName("default/empty.htm"); 726 return super.process(request, response, context); 727 } 728 } 729 | Popular Tags |