001/* 002 * Copyright 2012-2016 the original author or authors. 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 017package org.springframework.boot.autoconfigure.jdbc; 018 019import java.sql.Connection; 020import java.sql.SQLException; 021 022import javax.sql.DataSource; 023 024import org.springframework.dao.DataAccessException; 025import org.springframework.jdbc.core.ConnectionCallback; 026import org.springframework.jdbc.core.JdbcTemplate; 027import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 028import org.springframework.util.Assert; 029import org.springframework.util.ClassUtils; 030 031/** 032 * Connection details for {@link EmbeddedDatabaseType embedded databases}. 033 * 034 * @author Phillip Webb 035 * @author Dave Syer 036 * @author Stephane Nicoll 037 * @see #get(ClassLoader) 038 */ 039public enum EmbeddedDatabaseConnection { 040 041 /** 042 * No Connection. 043 */ 044 NONE(null, null, null), 045 046 /** 047 * H2 Database Connection. 048 */ 049 H2(EmbeddedDatabaseType.H2, "org.h2.Driver", 050 "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"), 051 052 /** 053 * Derby Database Connection. 054 */ 055 DERBY(EmbeddedDatabaseType.DERBY, "org.apache.derby.jdbc.EmbeddedDriver", 056 "jdbc:derby:memory:%s;create=true"), 057 058 /** 059 * HSQL Database Connection. 060 */ 061 HSQL(EmbeddedDatabaseType.HSQL, "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:%s"); 062 063 private static final String DEFAULT_DATABASE_NAME = "testdb"; 064 065 private final EmbeddedDatabaseType type; 066 067 private final String driverClass; 068 069 private final String url; 070 071 EmbeddedDatabaseConnection(EmbeddedDatabaseType type, String driverClass, 072 String url) { 073 this.type = type; 074 this.driverClass = driverClass; 075 this.url = url; 076 } 077 078 /** 079 * Returns the driver class name. 080 * @return the driver class name 081 */ 082 public String getDriverClassName() { 083 return this.driverClass; 084 } 085 086 /** 087 * Returns the {@link EmbeddedDatabaseType} for the connection. 088 * @return the database type 089 */ 090 public EmbeddedDatabaseType getType() { 091 return this.type; 092 } 093 094 /** 095 * Returns the URL for the connection using the default database name. 096 * @return the connection URL 097 */ 098 public String getUrl() { 099 return getUrl(DEFAULT_DATABASE_NAME); 100 } 101 102 /** 103 * Returns the URL for the connection using the specified {@code databaseName}. 104 * @param databaseName the name of the database 105 * @return the connection URL 106 */ 107 public String getUrl(String databaseName) { 108 Assert.hasText(databaseName, "DatabaseName must not be null."); 109 return this.url != null ? String.format(this.url, databaseName) : null; 110 } 111 112 /** 113 * Override for testing. 114 */ 115 static EmbeddedDatabaseConnection override; 116 117 /** 118 * Convenience method to determine if a given driver class name represents an embedded 119 * database type. 120 * @param driverClass the driver class 121 * @return true if the driver class is one of the embedded types 122 */ 123 public static boolean isEmbedded(String driverClass) { 124 return driverClass != null && (driverClass.equals(HSQL.driverClass) 125 || driverClass.equals(H2.driverClass) 126 || driverClass.equals(DERBY.driverClass)); 127 } 128 129 /** 130 * Convenience method to determine if a given data source represents an embedded 131 * database type. 132 * @param dataSource the data source to interrogate 133 * @return true if the data source is one of the embedded types 134 */ 135 public static boolean isEmbedded(DataSource dataSource) { 136 try { 137 return new JdbcTemplate(dataSource).execute(new IsEmbedded()); 138 } 139 catch (DataAccessException ex) { 140 // Could not connect, which means it's not embedded 141 return false; 142 } 143 } 144 145 /** 146 * Returns the most suitable {@link EmbeddedDatabaseConnection} for the given class 147 * loader. 148 * @param classLoader the class loader used to check for classes 149 * @return an {@link EmbeddedDatabaseConnection} or {@link #NONE}. 150 */ 151 public static EmbeddedDatabaseConnection get(ClassLoader classLoader) { 152 if (override != null) { 153 return override; 154 } 155 for (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) { 156 if (candidate != NONE && ClassUtils.isPresent(candidate.getDriverClassName(), 157 classLoader)) { 158 return candidate; 159 } 160 } 161 return NONE; 162 } 163 164 /** 165 * {@link ConnectionCallback} to determine if a connection is embedded. 166 */ 167 private static class IsEmbedded implements ConnectionCallback<Boolean> { 168 169 @Override 170 public Boolean doInConnection(Connection connection) 171 throws SQLException, DataAccessException { 172 String productName = connection.getMetaData().getDatabaseProductName(); 173 if (productName == null) { 174 return false; 175 } 176 productName = productName.toUpperCase(); 177 EmbeddedDatabaseConnection[] candidates = EmbeddedDatabaseConnection.values(); 178 for (EmbeddedDatabaseConnection candidate : candidates) { 179 if (candidate != NONE && productName.contains(candidate.name())) { 180 return true; 181 } 182 } 183 return false; 184 } 185 186 } 187 188}