001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.setup.ui; 029 030import org.opencms.setup.CmsSetupBean; 031import org.opencms.setup.CmsSetupDb; 032import org.opencms.ui.CmsVaadinUtils; 033import org.opencms.util.CmsStringUtil; 034 035import java.util.ArrayList; 036import java.util.List; 037import java.util.Map; 038import java.util.Properties; 039 040import com.vaadin.ui.Button; 041import com.vaadin.ui.ComboBox; 042import com.vaadin.ui.VerticalLayout; 043 044/** 045 * Setup step: Databbase settings. 046 */ 047public class CmsSetupStep03Database extends A_CmsSetupStep { 048 049 /** 050 * Exception class for use during DB setup, where we get lists of strings as errors from CmsSetupDb instead of the original exceptions. 051 */ 052 class DBException extends RuntimeException { 053 054 /** The list of original errors. */ 055 private List<String> m_errors; 056 057 /** The error message. */ 058 private String m_message; 059 060 /** 061 * Creates a new instance.<p> 062 * 063 * @param message the error message 064 * @param errors the list of original errors 065 */ 066 public DBException(String message, List<String> errors) { 067 068 m_message = message; 069 m_errors = new ArrayList<>(errors); 070 071 } 072 073 /** 074 * Gets original errors, separated by newlines. 075 * 076 * @return the original errors 077 */ 078 public String getDetails() { 079 080 return CmsStringUtil.listAsString(m_errors, "\n"); 081 } 082 083 /** 084 * @see java.lang.Throwable#getMessage() 085 */ 086 @Override 087 public String getMessage() { 088 089 return m_message; 090 } 091 } 092 093 /** Back button. */ 094 private Button m_backButton; 095 096 /** DB selector. */ 097 private ComboBox m_dbSelect; 098 099 /** Forward button. */ 100 private Button m_forwardButton; 101 102 /** Main layout. */ 103 private VerticalLayout m_mainLayout; 104 105 /** Array for storing the DB settings panel (need to wrap it in array because it's not part of the declarative layout). */ 106 private CmsDbSettingsPanel[] m_panel = {null}; 107 108 /** Setup bean. */ 109 private CmsSetupBean m_setupBean; 110 111 /** 112 * Creates a new instance. 113 * 114 * @param context the setup context 115 */ 116 public CmsSetupStep03Database(I_SetupUiContext context) { 117 118 super(context); 119 CmsVaadinUtils.readAndLocalizeDesign(this, null, null); 120 m_setupBean = context.getSetupBean(); 121 Map<String, Properties> propsForDbs = m_setupBean.getDatabaseProperties(); 122 List<String> dbList = new ArrayList<>(); 123 124 for (Map.Entry<String, Properties> entry : propsForDbs.entrySet()) { 125 dbList.add(entry.getKey()); 126 } 127 m_dbSelect.setItems(dbList); 128 m_dbSelect.setItemCaptionGenerator(db -> propsForDbs.get(db).get(db + ".name").toString()); 129 String path = context.getSetupBean().getServletConfig().getServletContext().getContextPath(); 130 int lastSlash = path.lastIndexOf("/"); 131 String webapp = null; 132 if (lastSlash != -1) { 133 String lastSegment = path.substring(lastSlash + 1); 134 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(lastSegment)) { 135 webapp = lastSegment; 136 } 137 } 138 final String fWebapp = webapp; 139 m_dbSelect.addValueChangeListener(evt -> { 140 String value = (String)(evt.getValue()); 141 updateDb(value, fWebapp); 142 }); 143 m_dbSelect.setNewItemProvider(null); 144 m_dbSelect.setEmptySelectionAllowed(false); 145 m_dbSelect.setValue("mysql"); 146 m_forwardButton.addClickListener(evt -> forward()); 147 m_backButton.addClickListener(evt -> m_context.stepBack()); 148 } 149 150 /** 151 * Creates DB and tables when necessary.<p> 152 * 153 * @throws Exception in case creating DB or tables fails 154 */ 155 public void setupDb(boolean createDb, boolean createTables, boolean dropDb) throws Exception { 156 157 boolean dbExists = false; 158 if (m_setupBean.isInitialized()) { 159 System.out.println("Setup-Bean initialized successfully."); 160 CmsSetupDb db = new CmsSetupDb(m_setupBean.getWebAppRfsPath()); 161 try { 162 // try to connect as the runtime user 163 System.out.println("Check runtime connection...."); 164 db.setConnection( 165 m_setupBean.getDbDriver(), 166 m_setupBean.getDbWorkConStr(), 167 m_setupBean.getDbConStrParams(), 168 m_setupBean.getDbWorkUser(), 169 m_setupBean.getDbWorkPwd(), 170 false); 171 System.out.println("Check runtime connection - COMPLETED"); 172 if (!db.noErrors()) { 173 System.out.println("Check setup connection...."); 174 // try to connect as the setup user 175 db.closeConnection(); 176 db.clearErrors(); 177 db.setConnection( 178 m_setupBean.getDbDriver(), 179 m_setupBean.getDbCreateConStr(), 180 m_setupBean.getDbConStrParams(), 181 m_setupBean.getDbCreateUser(), 182 m_setupBean.getDbCreatePwd()); 183 System.out.println("Check setup connection - COMPLETED"); 184 } else { 185 dbExists = true; 186 } 187 if (!db.noErrors()) { 188 throw new DBException("DB connection test failed.", db.getErrors()); 189 } 190 } finally { 191 db.clearErrors(); 192 db.closeConnection(); 193 } 194 } 195 196 System.out.println("DB connection tested successfully."); 197 198 CmsSetupDb db = null; 199 if (m_setupBean.isInitialized()) { 200 if (createDb || createTables) { 201 db = new CmsSetupDb(m_setupBean.getWebAppRfsPath()); 202 // check if database exists 203 if (m_setupBean.getDatabase().startsWith("oracle") 204 || m_setupBean.getDatabase().startsWith("db2") 205 || m_setupBean.getDatabase().startsWith("as400")) { 206 setWorkConnection(db); 207 } else { 208 db.setConnection( 209 m_setupBean.getDbDriver(), 210 m_setupBean.getDbWorkConStr(), 211 m_setupBean.getDbConStrParams(), 212 m_setupBean.getDbCreateUser(), 213 m_setupBean.getDbCreatePwd(), 214 false); 215 dbExists = db.noErrors(); 216 if (dbExists) { 217 db.closeConnection(); 218 } else { 219 db.clearErrors(); 220 } 221 } 222 if (!dbExists || dropDb) { 223 db.closeConnection(); 224 if (!m_setupBean.getDatabase().startsWith("db2") 225 && !m_setupBean.getDatabase().startsWith("as400")) { 226 db.setConnection( 227 m_setupBean.getDbDriver(), 228 m_setupBean.getDbCreateConStr(), 229 m_setupBean.getDbConStrParams(), 230 m_setupBean.getDbCreateUser(), 231 m_setupBean.getDbCreatePwd()); 232 } 233 } 234 } 235 } 236 if (!createDb && !createTables && !dbExists) { 237 throw new Exception("You have not created the Alkacon OpenCms database."); 238 } 239 if (dbExists && createTables && !dropDb && (db != null)) { 240 throw new Exception("You have selected to not drop existing DBs, but a DB with the given name exists."); 241 } 242 if (dbExists && createDb && dropDb && (db != null)) { 243 // drop the DB 244 db.closeConnection(); 245 db.setConnection( 246 m_setupBean.getDbDriver(), 247 m_setupBean.getDbCreateConStr(), 248 m_setupBean.getDbConStrParams(), 249 m_setupBean.getDbCreateUser(), 250 m_setupBean.getDbCreatePwd()); 251 db.dropDatabase(m_setupBean.getDatabase(), m_setupBean.getReplacer()); 252 if (!db.noErrors()) { 253 List<String> errors = new ArrayList<>(db.getErrors()); 254 db.clearErrors(); 255 throw new DBException("Error occurred while dropping the DB!", errors); 256 } 257 System.out.println("Database dropped successfully."); 258 } 259 260 if (createDb && (db != null)) { 261 // Create Database 262 db.createDatabase(m_setupBean.getDatabase(), m_setupBean.getReplacer()); 263 if (!db.noErrors()) { 264 DBException ex = new DBException("Error occurred while creating the DB!", db.getErrors()); 265 db.clearErrors(); 266 throw ex; 267 } 268 db.closeConnection(); 269 System.out.println("Database created successfully."); 270 } 271 272 if (createTables && (db != null)) { 273 setWorkConnection(db); 274 //Drop Tables (intentionally quiet) 275 db.dropTables(m_setupBean.getDatabase()); 276 db.clearErrors(); 277 db.closeConnection(); 278 // reopen the connection in order to display errors 279 setWorkConnection(db); 280 //Create Tables 281 db.createTables(m_setupBean.getDatabase(), m_setupBean.getReplacer()); 282 if (!db.noErrors()) { 283 DBException ex = new DBException("Error occurred while creating the DB!", db.getErrors()); 284 db.clearErrors(); 285 throw ex; 286 } 287 db.closeConnection(); 288 System.out.println("Tables created successfully."); 289 } 290 if (db != null) { 291 db.closeConnection(); 292 } 293 System.out.println("Database setup was successful."); 294 m_context.stepForward(); 295 } 296 297 /** 298 * Set work connection. 299 * 300 * @param db the db setup bean 301 */ 302 public void setWorkConnection(CmsSetupDb db) { 303 304 db.setConnection( 305 m_setupBean.getDbDriver(), 306 m_setupBean.getDbWorkConStr(), 307 m_setupBean.getDbConStrParams(), 308 m_setupBean.getDbWorkUser(), 309 m_setupBean.getDbWorkPwd()); 310 } 311 312 /** 313 * Proceed to next step. 314 */ 315 private void forward() { 316 317 try { 318 CmsDbSettingsPanel panel = m_panel[0]; 319 panel.saveToSetupBean(); 320 321 boolean createDb = panel.getCreateDb(); 322 boolean dropDb = panel.getDropDb(); 323 boolean createTables = panel.getCreateTables(); 324 setupDb(createDb, createTables, dropDb); 325 } catch (DBException e) { 326 CmsSetupErrorDialog.showErrorDialog(e.getMessage(), e.getDetails()); 327 } catch (Exception e) { 328 CmsSetupErrorDialog.showErrorDialog(e); 329 } 330 331 } 332 333 /** 334 * Switches DB type. 335 * 336 * @param dbName the database type 337 * @param webapp the webapp name 338 */ 339 private void updateDb(String dbName, String webapp) { 340 341 m_mainLayout.removeAllComponents(); 342 m_setupBean.setDatabase(dbName); 343 CmsDbSettingsPanel panel = new CmsDbSettingsPanel(m_setupBean); 344 m_panel[0] = panel; 345 panel.initFromSetupBean(webapp); 346 m_mainLayout.addComponent(panel); 347 } 348 349}