001package org.apache.commons.jcs3.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.DatabaseMetaData;
024import java.sql.ResultSet;
025import java.sql.SQLException;
026import java.sql.Statement;
027
028import javax.sql.DataSource;
029
030import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes;
031import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCache;
032import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
033import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
034import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
035import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
036import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
037import org.apache.commons.jcs3.log.Log;
038import org.apache.commons.jcs3.log.LogManager;
039
040/**
041 * This factory should create hsql disk caches.
042 */
043public class HSQLDiskCacheFactory
044    extends JDBCDiskCacheFactory
045{
046    /** The logger */
047    private static final Log log = LogManager.getLog( HSQLDiskCacheFactory.class );
048
049    /**
050     * This factory method should create an instance of the hsqlcache.
051     * <p>
052     * @param rawAttr
053     * @param compositeCacheManager
054     * @param cacheEventLogger
055     * @param elementSerializer
056     * @return JDBCDiskCache
057     * @throws SQLException if the creation of the cache instance fails
058     */
059    @Override
060    public <K, V> JDBCDiskCache<K, V> createCache( final AuxiliaryCacheAttributes rawAttr,
061                        final ICompositeCacheManager compositeCacheManager,
062                        final ICacheEventLogger cacheEventLogger,
063                        final IElementSerializer elementSerializer )
064                        throws SQLException
065    {
066        // TODO get this from the attributes.
067        System.setProperty( "hsqldb.cache_scale", "8" );
068
069        final JDBCDiskCache<K, V> cache = super.createCache(rawAttr, compositeCacheManager,
070                cacheEventLogger, elementSerializer);
071        setupDatabase( cache.getDataSource(), (JDBCDiskCacheAttributes) rawAttr );
072
073        return cache;
074    }
075
076    /**
077     * Creates the table if it doesn't exist
078     * <p>
079     * @param ds Data Source
080     * @param attributes Cache region configuration
081     * @throws SQLException
082     */
083    protected void setupDatabase( final DataSource ds, final JDBCDiskCacheAttributes attributes )
084        throws SQLException
085    {
086        try (Connection cConn = ds.getConnection())
087        {
088            setupTable( cConn, attributes.getTableName() );
089            log.info( "Finished setting up table [{0}]", attributes.getTableName());
090        }
091    }
092
093    /**
094     * SETUP TABLE FOR CACHE
095     * <p>
096     * @param cConn
097     * @param tableName
098     */
099    protected synchronized void setupTable( final Connection cConn, final String tableName ) throws SQLException
100    {
101        final DatabaseMetaData dmd = cConn.getMetaData();
102        final ResultSet result = dmd.getTables(null, null, tableName, null);
103
104        if (!result.next())
105        {
106            // TODO make the cached nature of the table configurable
107            final StringBuilder createSql = new StringBuilder();
108            createSql.append( "CREATE CACHED TABLE ").append( tableName );
109            createSql.append( "( " );
110            createSql.append( "CACHE_KEY             VARCHAR(250)          NOT NULL, " );
111            createSql.append( "REGION                VARCHAR(250)          NOT NULL, " );
112            createSql.append( "ELEMENT               BINARY, " );
113            createSql.append( "CREATE_TIME           TIMESTAMP, " );
114            createSql.append( "UPDATE_TIME_SECONDS   BIGINT, " );
115            createSql.append( "MAX_LIFE_SECONDS      BIGINT, " );
116            createSql.append( "SYSTEM_EXPIRE_TIME_SECONDS      BIGINT, " );
117            createSql.append( "IS_ETERNAL            CHAR(1), " );
118            createSql.append( "PRIMARY KEY (CACHE_KEY, REGION) " );
119            createSql.append( ");" );
120
121            try (Statement sStatement = cConn.createStatement())
122            {
123                sStatement.execute( createSql.toString() );
124            }
125        }
126    }
127}