package marubinotto.piggydb.impl.db; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import javax.servlet.ServletContext; import marubinotto.util.Assert; import marubinotto.util.FileSystemUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.UnhandledException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.io.Resource; import org.springframework.web.context.ServletContextAware; public class H2JdbcUrl implements ServletContextAware { private static Log logger = LogFactory.getLog(H2JdbcUrl.class); public static final String DEFAULT_DATABASE_NAME = "piggydb"; private String prefix; private String databaseName; private String deployName; private Resource logFile; public void setServletContext(ServletContext context) { String path = null; try { path = context.getContextPath(); } catch (NoSuchMethodError e) { logger.info("Servlet 2.5 is not available."); } logger.debug("getContextPath: " + path); if (path == null) return; if (path.startsWith("/")) path = path.substring(1); this.deployName = path; logger.debug("deployName: " + this.deployName); } public void setDatabasePrefix(String databasePrefix) throws Exception { Assert.Arg.notNull(databasePrefix, "databasePrefix"); this.prefix = preparePrefix(databasePrefix); } public String getDatabasePrefix() { return this.prefix; } public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public String getDatabaseName() { if (StringUtils.isNotBlank(this.databaseName)) { return this.databaseName; } if (StringUtils.isNotBlank(this.deployName)) { return this.deployName; } return DEFAULT_DATABASE_NAME; } public boolean isInMemory() { Assert.Property.requireNotNull(prefix, "prefix"); return isInMemoryPrefix(this.prefix); } public void setLogFile(Resource logFile) { this.logFile = logFile; } private static final String URL_PREFIX = "jdbc:h2:"; private static final String URL_SUFFIX = ";DB_CLOSE_DELAY=-1"; /** * Database path = prefix + name */ public String getDatabasePath() { Assert.Property.requireNotNull(prefix, "prefix"); String path = this.prefix + StringUtils.defaultString(getDatabaseName(), ""); return path; } public String getUrl() throws IOException { String url = URL_PREFIX + getDatabasePath() + URL_SUFFIX; logUrl(url); return url; } // Internals private static boolean isInMemoryPrefix(String prefix) { return prefix.startsWith("mem:"); } public static String toUrlWithoutEscape(File file) { String url = file.toURI().toString(); try { return URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new UnhandledException(e); } } private static String preparePrefix(String original) throws Exception { String prepared = null; if (original.startsWith("~") || original.startsWith("file:~")) { String homeUrl = toUrlWithoutEscape(FileSystemUtils.getUserHome(false)); if (homeUrl.endsWith("/")) homeUrl = StringUtils.chop(homeUrl); prepared = homeUrl + original.substring(original.indexOf('~') + 1); } else { prepared = original; } if (!isInMemoryPrefix(prepared) && !prepared.endsWith("/")) { prepared += "/"; } return prepared; } private void logUrl(String url) throws IOException { logger.info("jdbcUrl: " + url); if (this.logFile == null) return; File logFilePath = this.logFile.getFile(); synchronized (getClass()) { List<String> urlList = new ArrayList<String>(); if (logFilePath.isFile()) urlList = FileUtils.readLines(logFilePath); if (!urlList.contains(url)) { urlList.add(url); FileUtils.writeLines(logFilePath, urlList); } } } }