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