001package org.apache.commons.jcs.auxiliary.disk.jdbc.hsql; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.sql.Connection; 023import java.sql.DriverManager; 024import java.sql.SQLException; 025import java.sql.Statement; 026import java.util.Collections; 027import java.util.HashSet; 028import java.util.Set; 029 030import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; 031import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCache; 032import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes; 033import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory; 034import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; 035import org.apache.commons.jcs.engine.behavior.IElementSerializer; 036import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039 040/** 041 * This factory should create hsql disk caches. 042 * <p> 043 * @author Aaron Smuts 044 */ 045public class HSQLDiskCacheFactory 046 extends JDBCDiskCacheFactory 047{ 048 /** The logger */ 049 private static final Log log = LogFactory.getLog( HSQLDiskCacheFactory.class ); 050 051 /** The databases. */ 052 private Set<String> databases; 053 054 /** 055 * This factory method should create an instance of the hsqlcache. 056 * <p> 057 * @param rawAttr 058 * @param compositeCacheManager 059 * @param cacheEventLogger 060 * @param elementSerializer 061 * @return JDBCDiskCache 062 * @throws SQLException if the creation of the cache instance fails 063 */ 064 @Override 065 public <K, V> JDBCDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr, 066 ICompositeCacheManager compositeCacheManager, 067 ICacheEventLogger cacheEventLogger, 068 IElementSerializer elementSerializer ) 069 throws SQLException 070 { 071 setupDatabase( (JDBCDiskCacheAttributes) rawAttr ); 072 return super.createCache(rawAttr, compositeCacheManager, cacheEventLogger, elementSerializer); 073 } 074 075 /** 076 * Initialize this factory 077 */ 078 @Override 079 public void initialize() 080 { 081 super.initialize(); 082 this.databases = Collections.synchronizedSet( new HashSet<String>() ); 083 } 084 085 /** 086 * Creates the database if it doesn't exist, registers the driver class, etc. 087 * <p> 088 * @param attributes 089 * @throws SQLException 090 */ 091 protected void setupDatabase( JDBCDiskCacheAttributes attributes ) 092 throws SQLException 093 { 094 if ( attributes == null ) 095 { 096 throw new SQLException( "The attributes are null." ); 097 } 098 099 // url should start with "jdbc:hsqldb:" 100 String database = attributes.getUrl() + attributes.getDatabase(); 101 102 if ( databases.contains( database ) ) 103 { 104 if ( log.isInfoEnabled() ) 105 { 106 log.info( "We already setup database [" + database + "]" ); 107 } 108 return; 109 } 110 111 // TODO get this from the attributes. 112 System.setProperty( "hsqldb.cache_scale", "8" ); 113 114 // "org.hsqldb.jdbcDriver" 115 String driver = attributes.getDriverClassName(); 116 // "sa" 117 String user = attributes.getUserName(); 118 // "" 119 String password = attributes.getPassword(); 120 121 try 122 { 123 Class.forName( driver ).newInstance(); 124 } 125 catch (Exception e) 126 { 127 throw new SQLException( "Could not initialize driver " + driver, e ); 128 } 129 130 Connection cConn = DriverManager.getConnection( database, user, password ); 131 setupTable( cConn, attributes.getTableName() ); 132 133 if ( log.isInfoEnabled() ) 134 { 135 log.info( "Finished setting up database [" + database + "]" ); 136 } 137 138 databases.add( database ); 139 } 140 141 /** 142 * SETUP TABLE FOR CACHE 143 * <p> 144 * @param cConn 145 * @param tableName 146 */ 147 protected void setupTable( Connection cConn, String tableName ) throws SQLException 148 { 149 // TODO make the cached nature of the table configurable 150 StringBuilder createSql = new StringBuilder(); 151 createSql.append( "CREATE CACHED TABLE ").append( tableName ); 152 createSql.append( "( " ); 153 createSql.append( "CACHE_KEY VARCHAR(250) NOT NULL, " ); 154 createSql.append( "REGION VARCHAR(250) NOT NULL, " ); 155 createSql.append( "ELEMENT BINARY, " ); 156 createSql.append( "CREATE_TIME TIMESTAMP, " ); 157 createSql.append( "UPDATE_TIME_SECONDS BIGINT, " ); 158 createSql.append( "MAX_LIFE_SECONDS BIGINT, " ); 159 createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS BIGINT, " ); 160 createSql.append( "IS_ETERNAL CHAR(1), " ); 161 createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " ); 162 createSql.append( ");" ); 163 164 Statement sStatement = cConn.createStatement(); 165 166 try 167 { 168 sStatement.execute( createSql.toString() ); 169 } 170 catch ( SQLException e ) 171 { 172 if (!"23000".equals(e.getSQLState())) 173 { 174 throw e; 175 } 176 } 177 finally 178 { 179 sStatement.close(); 180 } 181 } 182}