001 package org.apache.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
022 import java.io.Serializable;
023 import java.sql.Connection;
024 import java.sql.DriverManager;
025 import java.sql.SQLException;
026 import java.sql.Statement;
027 import java.util.Collections;
028 import java.util.HashSet;
029 import java.util.Set;
030
031 import org.apache.commons.logging.Log;
032 import org.apache.commons.logging.LogFactory;
033 import org.apache.jcs.auxiliary.AuxiliaryCache;
034 import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
035 import org.apache.jcs.auxiliary.AuxiliaryCacheFactory;
036 import org.apache.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
037 import org.apache.jcs.auxiliary.disk.jdbc.JDBCDiskCacheManager;
038 import org.apache.jcs.engine.behavior.ICompositeCacheManager;
039 import org.apache.jcs.engine.behavior.IElementSerializer;
040 import org.apache.jcs.engine.control.CompositeCacheManager;
041 import org.apache.jcs.engine.logging.behavior.ICacheEventLogger;
042
043 /**
044 * This factory should create mysql disk caches.
045 * <p>
046 * @author Aaron Smuts
047 */
048 public class HSQLDiskCacheFactory
049 implements AuxiliaryCacheFactory
050 {
051 /** The logger */
052 private final static Log log = LogFactory.getLog( HSQLDiskCacheFactory.class );
053
054 /** Name for logging, etc. */
055 private String name = "HSQLDiskCacheFactory";
056
057 /** The databases. */
058 private final Set<String> databases = Collections.synchronizedSet( new HashSet<String>() );
059
060 /**
061 * This factory method should create an instance of the hsqlcache.
062 * <p>
063 * @param rawAttr
064 * @param arg1
065 * @param cacheEventLogger
066 * @param elementSerializer
067 * @return AuxiliaryCache
068 */
069 public <K extends Serializable, V extends Serializable> AuxiliaryCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr, ICompositeCacheManager arg1,
070 ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
071 {
072 JDBCDiskCacheManager mgr = JDBCDiskCacheManager.getInstance( (JDBCDiskCacheAttributes) rawAttr,
073 CompositeCacheManager.getUnconfiguredInstance(),
074 cacheEventLogger, elementSerializer );
075 try
076 {
077 setupDatabase( (JDBCDiskCacheAttributes) rawAttr );
078 }
079 catch ( Exception e )
080 {
081 // TODO we may not want to try and get the cache at this point.
082 log.error( "Problem setting up database.", e );
083 }
084 return mgr.getCache( (JDBCDiskCacheAttributes) rawAttr );
085 }
086
087 /**
088 * The name of the factory.
089 * <p>
090 * @param nameArg
091 */
092 public void setName( String nameArg )
093 {
094 name = nameArg;
095 }
096
097 /**
098 * Returns the display name
099 * <p>
100 * @return name
101 */
102 public String getName()
103 {
104 return name;
105 }
106
107 /**
108 * Creates the database if it doesn't exist, registers the driver class, etc.
109 * <p>
110 * @param attributes
111 * @throws Exception
112 */
113 protected void setupDatabase( JDBCDiskCacheAttributes attributes )
114 throws Exception
115 {
116 if ( attributes == null )
117 {
118 throw new Exception( "The attributes are null." );
119 }
120
121 // url should start with "jdbc:hsqldb:"
122 String database = attributes.getUrl() + attributes.getDatabase();
123
124 if ( databases.contains( database ) )
125 {
126 if ( log.isInfoEnabled() )
127 {
128 log.info( "We already setup database [" + database + "]" );
129 }
130 return;
131 }
132
133 // TODO get this from the attributes.
134 System.setProperty( "hsqldb.cache_scale", "8" );
135
136 // "org.hsqldb.jdbcDriver"
137 String driver = attributes.getDriverClassName();
138 // "sa"
139 String user = attributes.getUserName();
140 // ""
141 String password = attributes.getPassword();
142
143 new org.hsqldb.jdbcDriver();
144 try
145 {
146 Class.forName( driver ).newInstance();
147
148 Connection cConn = DriverManager.getConnection( database, user, password );
149
150 setupTABLE( cConn, attributes.getTableName() );
151
152 if ( log.isInfoEnabled() )
153 {
154 log.info( "Finished setting up database [" + database + "]" );
155 }
156
157 databases.add( database );
158 }
159 catch ( Exception e )
160 {
161 log.error( "Fatal problem setting up the database.", e );
162 }
163 }
164
165 /**
166 * SETUP TABLE FOR CACHE
167 * <p>
168 * @param cConn
169 * @param tableName
170 */
171 private void setupTABLE( Connection cConn, String tableName ) throws SQLException
172 {
173 boolean newT = true;
174
175 // TODO make the cached nature of the table configurable
176 StringBuffer createSql = new StringBuffer();
177 createSql.append( "CREATE CACHED TABLE " + tableName );
178 createSql.append( "( " );
179 createSql.append( "CACHE_KEY VARCHAR(250) NOT NULL, " );
180 createSql.append( "REGION VARCHAR(250) NOT NULL, " );
181 createSql.append( "ELEMENT BINARY, " );
182 createSql.append( "CREATE_TIME DATE, " );
183 createSql.append( "CREATE_TIME_SECONDS BIGINT, " );
184 createSql.append( "MAX_LIFE_SECONDS BIGINT, " );
185 createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS BIGINT, " );
186 createSql.append( "IS_ETERNAL CHAR(1), " );
187 createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " );
188 createSql.append( ");" );
189
190 Statement sStatement = cConn.createStatement();
191
192 try
193 {
194 sStatement.executeQuery( createSql.toString() );
195 sStatement.close();
196 }
197 catch ( SQLException e )
198 {
199 // FIXME: This is not reliable
200 if ( e.toString().indexOf( "already exists" ) != -1 )
201 {
202 newT = false;
203 }
204 else
205 {
206 throw e;
207 }
208 }
209
210 // TODO create an index on SYSTEM_EXPIRE_TIME_SECONDS
211 String setupData[] = { "create index iKEY on " + tableName + " (CACHE_KEY, REGION)" };
212
213 if ( newT )
214 {
215 for ( int i = 1; i < setupData.length; i++ )
216 {
217 try
218 {
219 sStatement.executeQuery( setupData[i] );
220 }
221 catch ( SQLException e )
222 {
223 log.error( "Exception caught when creating index." + e );
224 }
225 }
226 }
227 }
228 }