/* * 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 );
}
}