001/* 002 * (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * dmetzler 018 */ 019package org.nuxeo.launcher.config.backingservices; 020 021import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_DRIVER; 022import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_HOST; 023import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_JDBC_URL; 024import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_NAME; 025import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_PORT; 026import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_PWD; 027import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_DB_USER; 028import static org.nuxeo.launcher.config.ConfigurationGenerator.PARAM_TEMPLATE_DBNAME; 029 030import java.io.File; 031import java.io.FileNotFoundException; 032import java.io.IOException; 033import java.net.MalformedURLException; 034import java.net.URL; 035import java.net.URLClassLoader; 036import java.sql.Connection; 037import java.sql.Driver; 038import java.sql.DriverManager; 039import java.sql.SQLException; 040import java.util.ArrayList; 041import java.util.Arrays; 042import java.util.List; 043import java.util.Properties; 044 045import org.apache.commons.lang.ArrayUtils; 046import org.apache.commons.logging.Log; 047import org.apache.commons.logging.LogFactory; 048import org.nuxeo.common.codec.CryptoProperties; 049import org.nuxeo.common.utils.TextTemplate; 050import org.nuxeo.launcher.commons.DatabaseDriverException; 051import org.nuxeo.launcher.config.ConfigurationException; 052import org.nuxeo.launcher.config.ConfigurationGenerator; 053 054/** 055 * @since 9.2 056 */ 057public class DBCheck implements BackingChecker { 058 059 private static final Log log = LogFactory.getLog(DBCheck.class); 060 061 public static final List<String> DB_EXCLUDE_CHECK_LIST = Arrays.asList("default", "none"); 062 063 @Override 064 public boolean accepts(ConfigurationGenerator cg) { 065 return !DB_EXCLUDE_CHECK_LIST.contains( 066 cg.getUserConfig().getProperty(ConfigurationGenerator.PARAM_TEMPLATE_DBTYPE)); 067 068 } 069 070 @Override 071 public void check(ConfigurationGenerator cg) throws ConfigurationException { 072 try { 073 checkDatabaseConnection(cg); 074 } catch (IOException e) { 075 throw new ConfigurationException(e); 076 } catch (DatabaseDriverException e) { 077 log.debug(e, e); 078 log.error(e.getMessage()); 079 throw new ConfigurationException("Could not find database driver: " + e.getMessage()); 080 } catch (SQLException e) { 081 log.debug(e, e); 082 log.error(e.getMessage()); 083 throw new ConfigurationException("Failed to connect on database: " + e.getMessage()); 084 } 085 } 086 087 /** 088 * Check driver availability and database connection 089 * 090 * @throws DatabaseDriverException 091 * @throws IOException 092 * @throws FileNotFoundException 093 * @throws SQLException 094 */ 095 public void checkDatabaseConnection(ConfigurationGenerator cg) 096 throws FileNotFoundException, IOException, DatabaseDriverException, SQLException { 097 CryptoProperties config = cg.getUserConfig(); 098 String databaseTemplate = config.getProperty(ConfigurationGenerator.PARAM_TEMPLATE_DBNAME); 099 String dbName = config.getProperty(ConfigurationGenerator.PARAM_DB_NAME); 100 String dbUser = config.getProperty(ConfigurationGenerator.PARAM_DB_USER); 101 String dbPassword = config.getProperty(ConfigurationGenerator.PARAM_DB_PWD); 102 String dbHost = config.getProperty(ConfigurationGenerator.PARAM_DB_HOST); 103 String dbPort = config.getProperty(ConfigurationGenerator.PARAM_DB_PORT); 104 105 File databaseTemplateDir = new File(cg.getNuxeoHome(), ConfigurationGenerator.TEMPLATES + File.separator + databaseTemplate); 106 Properties templateProperties = ConfigurationGenerator.loadTrimmedProperties(new File(databaseTemplateDir, ConfigurationGenerator.NUXEO_DEFAULT_CONF)); 107 String classname, connectionUrl; 108 if (config.getProperty(PARAM_TEMPLATE_DBNAME).equals(databaseTemplateDir)) { 109 // config already includes databaseTemplate 110 classname = config.getProperty(PARAM_DB_DRIVER); 111 connectionUrl = config.getProperty(PARAM_DB_JDBC_URL); 112 } else { // testing a databaseTemplate not included in config 113 // check if value is set in nuxeo.conf 114 if (config.containsKey(PARAM_DB_DRIVER)) { 115 classname = (String) config.get(PARAM_DB_DRIVER); 116 } else { 117 classname = templateProperties.getProperty(PARAM_DB_DRIVER); 118 } 119 if (config.containsKey(PARAM_DB_JDBC_URL)) { 120 connectionUrl = (String) config.get(PARAM_DB_JDBC_URL); 121 } else { 122 connectionUrl = templateProperties.getProperty(PARAM_DB_JDBC_URL); 123 } 124 } 125 // Load driver class from template or default lib directory 126 Driver driver = lookupDriver(cg, databaseTemplate, databaseTemplateDir, classname); 127 // Test db connection 128 DriverManager.registerDriver(driver); 129 Properties ttProps = new Properties(config); 130 ttProps.put(PARAM_DB_HOST, dbHost); 131 ttProps.put(PARAM_DB_PORT, dbPort); 132 ttProps.put(PARAM_DB_NAME, dbName); 133 ttProps.put(PARAM_DB_USER, dbUser); 134 ttProps.put(PARAM_DB_PWD, dbPassword); 135 TextTemplate tt = new TextTemplate(ttProps); 136 String url = tt.processText(connectionUrl); 137 Properties conProps = new Properties(); 138 conProps.put("user", dbUser); 139 conProps.put("password", dbPassword); 140 log.debug("Testing URL " + url + " with " + conProps); 141 Connection con = driver.connect(url, conProps); 142 con.close(); 143 } 144 145 146 /** 147 * Build an {@link URLClassLoader} for the given databaseTemplate looking in the templates directory and in the 148 * server lib directory, then looks for a driver 149 * @param cg 150 * 151 * @param classname Driver class name, defined by {@link #PARAM_DB_DRIVER} 152 * @return Driver driver if found, else an Exception must have been raised. 153 * @throws IOException 154 * @throws FileNotFoundException 155 * @throws DatabaseDriverException If there was an error when trying to instantiate the driver. 156 * @since 5.6 157 */ 158 private Driver lookupDriver(ConfigurationGenerator cg, String databaseTemplate, File databaseTemplateDir, String classname) 159 throws FileNotFoundException, IOException, DatabaseDriverException { 160 File[] files = (File[]) ArrayUtils.addAll( // 161 new File(databaseTemplateDir, "lib").listFiles(), // 162 cg.getServerConfigurator().getServerLibDir().listFiles()); 163 List<URL> urlsList = new ArrayList<>(); 164 if (files != null) { 165 for (File file : files) { 166 if (file.getName().endsWith("jar")) { 167 try { 168 urlsList.add(new URL("jar:file:" + file.getPath() + "!/")); 169 log.debug("Added " + file.getPath()); 170 } catch (MalformedURLException e) { 171 log.error(e); 172 } 173 } 174 } 175 } 176 URLClassLoader ucl = new URLClassLoader(urlsList.toArray(new URL[0])); 177 try { 178 return (Driver) Class.forName(classname, true, ucl).newInstance(); 179 } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { 180 throw new DatabaseDriverException(e); 181 } 182 } 183 184}