(no commit message)
[utils] / test / enterprise / src / main / java / org / wamblee / support / persistence / DerbyDatabase.java
diff --git a/test/enterprise/src/main/java/org/wamblee/support/persistence/DerbyDatabase.java b/test/enterprise/src/main/java/org/wamblee/support/persistence/DerbyDatabase.java
new file mode 100755 (executable)
index 0000000..646931c
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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.support.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 java.util.logging.Level;
+import java.util.logging.Logger;
+
+import junit.framework.TestCase;
+
+import org.apache.derby.drda.NetworkServerControl;
+import org.wamblee.io.FileSystemUtils;
+
+/**
+ * Derby database setup. The external JDBC url used to connect to a running
+ * instance is
+ * 
+ * <pre>
+ *     jdbc:derby:net://localhost:1527/testdb
+ * </pre>
+ * 
+ * and the driver class is
+ * 
+ * <pre>
+ * com.ibm.db2.jcc.DB2Driver
+ * </pre>
+ * 
+ * The following jars will have to be used <code>db2jcc.jar</code> and
+ * <code>db2jcc_license_c.jar</code>.
+ */
+public class DerbyDatabase extends AbstractDatabase {
+
+       /**
+        * Logger.
+        */
+       private static final Logger LOGGER = Logger.getLogger(DerbyDatabase.class
+                       .getName());
+
+       /**
+        * 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";
+       
+
+       private boolean inmemory;
+               
+       
+       /**
+        * Constructs derby database class to allow creation of derby database
+        * instances.
+        */
+       public DerbyDatabase() {
+               inmemory = true;
+       }
+
+       public DerbyDatabase(boolean aInMemoryFlag) {
+               inmemory = aInMemoryFlag;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.wamblee.persistence.Database#start()
+        */
+       public void doStart() {
+               try {
+                       // just in case a previous run was killed without the
+                       // cleanup
+                       cleanPersistentStorage();
+
+                       if (!inmemory) {
+                               // 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();
+                       
+                       LOGGER.info("Database started: \n    URL = " + getExternalJdbcUrl() + "\n    user = " + getUsername() + "\n    password = " 
+                                       + getPassword()); 
+
+                       createDataSource();
+                       
+                       Runtime.getRuntime().addShutdownHook(new Thread() {
+                               @Override
+                               public void run() {
+                                       if (isStarted()) {
+                                               LOGGER.warning("Shutting down db");
+                                               DerbyDatabase.this.stop();
+                                       }
+                               }
+                       });
+               } catch (Exception e) {
+                       throw new RuntimeException("Problem starting database", e);
+               }
+       }
+
+       /**
+        * 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 (inmemory ? "jdbc:derby:memory:": "jdbc:derby:") + DATABASE_NAME;
+       }
+
+       /*
+        * (non-Javadoc)
+        * 
+        * @see org.wamblee.persistence.Database#getExternalJdbcUrl()
+        */
+       public String getExternalJdbcUrl() {
+               return "jdbc:derby://localhost:1527/" + (inmemory ? "memory:" : "") + 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.");
+               }
+       }
+
+       /**
+        * 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 doStop() {
+               try {
+                       // shutdown network server.
+                       getControl().shutdown();
+                       waitUntilStartedOrStopped(false);
+
+                       // shutdown inmemory access.
+                       shutdownDerby();
+                       cleanPersistentStorage();
+               } catch (Exception e) {
+                       LOGGER.log(Level.WARNING, "Problem stopping database", e);
+               }
+       }
+
+       /**
+        * 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);
+       }
+}