/* * Copyright 2005 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.persistence; import java.io.File; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; import junit.framework.TestCase; import org.apache.derby.drda.NetworkServerControl; import org.apache.derby.jdbc.ClientDriver; import org.apache.derby.jdbc.EmbeddedDriver; import org.apache.log4j.Logger; import org.wamblee.io.FileSystemUtils; /** * Derby database setup. * The external JDBC url used to connect to a running instance is *
 *     jdbc:derby:net://localhost:1527/testdb 
 * 
* and the driver class is *
 *     com.ibm.db2.jcc.DB2Driver
 * 
* The following jars will have to be used * db2jcc.jar and db2jcc_license_c.jar. */ public class DerbyDatabase implements Database { /** * Logger. */ private static final Logger LOGGER = Logger.getLogger( DerbyDatabase.class ); /** * Database user name. */ private static final String USERNAME = "sa"; /** * Database password. */ private static final String PASSWORD = "123"; /** * Poll interval for the checking the server status. */ private static final int POLL_INTERVAL = 100; /** * Maximum time to wait until the server has started or stopped. */ private static final int MAX_WAIT_TIME = 10000; /** * Database name to use. */ private static final String DATABASE_NAME = "testdb"; /** * Path on the file system where derby files are stored. */ private static final String DATABASE_PATH = "target/db/persistence/derby"; /** * Derby property required to set the file system path * {@link #DATABASE_PATH}. */ private static final String SYSTEM_PATH_PROPERTY = "derby.system.home"; /** * Constructs derby database class to allow creation of derby * database instances. */ public DerbyDatabase( ) { // Empty } /* * (non-Javadoc) * @see org.wamblee.persistence.Database#start() */ public void start( ) throws Exception { // just in case a previous run was killed without the // cleanup cleanPersistentStorage( ); // set database path. Properties lProperties = System.getProperties( ); lProperties.put( SYSTEM_PATH_PROPERTY, DATABASE_PATH ); Class.forName( "org.apache.derby.jdbc.EmbeddedDriver" ).newInstance( ); runDatabase( ); waitUntilStartedOrStopped( true ); // Force creation of the database. Connection lConnection = createConnection( ); lConnection.close( ); } /** * Waits until the database server has started or stopped. * * @param aStarted * If true, waits until the server is up, if false, waits until * the server is down. * @throws InterruptedException */ private void waitUntilStartedOrStopped( boolean aStarted ) throws InterruptedException { long lWaited = 0; while ( aStarted != isStarted( ) ) { Thread.sleep( POLL_INTERVAL ); lWaited += POLL_INTERVAL; if ( lWaited > MAX_WAIT_TIME ) { throw new RuntimeException( "Derby database did not start within " + MAX_WAIT_TIME + "ms" ); } } } /** * Checks if the database server has started or not. * * @return True if started, false otherwise. */ private boolean isStarted( ) { try { getControl( ).ping( ); return true; } catch ( Exception e ) { return false; } } /** * Gets the controller for the database server. * * @return Controller. * @throws Exception */ private NetworkServerControl getControl( ) throws Exception { return new NetworkServerControl( ); } /** * Runs the database. * */ private void runDatabase( ) { try { getControl( ).start( new PrintWriter( System.out ) ); } catch ( Exception e ) { throw new RuntimeException( e ); } } /* * (non-Javadoc) * @see org.wamblee.persistence.Database#getJdbcUrl() */ public String getJdbcUrl( ) { return getBaseJdbcUrl( ) + ";create=true;retrieveMessagesFromServerOnGetMessage=true;"; } private String getBaseJdbcUrl( ) { return "jdbc:derby:" + DATABASE_NAME; } /* * (non-Javadoc) * @see org.wamblee.persistence.Database#getExternalJdbcUrl() */ public String getExternalJdbcUrl( ) { return "jdbc:derby:net://localhost:1527/" + DATABASE_NAME; } /** * Shuts down the derby database and cleans up all created files. * */ private void shutdownDerby( ) { try { DriverManager.getConnection( "jdbc:derby:;shutdown=true" ); throw new RuntimeException( "Derby did not shutdown, " + " should always throw exception at shutdown" ); } catch ( Exception e ) { LOGGER.info( "Derby has been shut down." ); } } /* * (non-Javadoc) * @see org.wamblee.persistence.Database#getDriverClassName() */ public String getDriverClassName( ) { return ClientDriver.class.getName(); } /** * Gets the user name. */ public String getUsername( ) { return USERNAME; } /** * Gets the password. * @return */ public String getPassword( ) { return PASSWORD; } /* * (non-Javadoc) * @see org.wamblee.persistence.Database#createConnection() */ public Connection createConnection( ) throws SQLException { Connection c = DriverManager.getConnection( getJdbcUrl( ), getUsername( ), getPassword( ) ); return c; } /** * Stops the derby database and cleans up all derby files. */ public void stop( ) throws Exception { // shutdown network server. getControl( ).shutdown( ); waitUntilStartedOrStopped( false ); // shutdown inmemory access. shutdownDerby( ); cleanPersistentStorage( ); } /** * Cleans up persistent storage of Derby. */ private void cleanPersistentStorage( ) { File lFile = new File( DATABASE_PATH ); if ( lFile.isFile( ) ) { TestCase.fail( "A regular file by the name " + DATABASE_PATH + " exists, clean this up first" ); } if ( !lFile.isDirectory( ) ) { return; // no-op already cleanup up. } FileSystemUtils.deleteDirRecursively( DATABASE_PATH ); } }