2 * Copyright 2005-2010 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.support.persistence;
19 import java.io.PrintWriter;
20 import java.sql.Connection;
21 import java.sql.DriverManager;
22 import java.sql.SQLException;
23 import java.util.Properties;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
27 import junit.framework.TestCase;
29 import org.apache.derby.drda.NetworkServerControl;
30 import org.wamblee.io.FileSystemUtils;
33 * Derby database setup. The external JDBC url used to connect to a running
37 * jdbc:derby:net://localhost:1527/testdb
40 * and the driver class is
43 * com.ibm.db2.jcc.DB2Driver
46 * The following jars will have to be used <code>db2jcc.jar</code> and
47 * <code>db2jcc_license_c.jar</code>.
49 public class DerbyDatabase extends AbstractDatabase {
54 private static final Logger LOGGER = Logger.getLogger(DerbyDatabase.class
60 private static final String USERNAME = "sa";
65 private static final String PASSWORD = "123";
67 * Poll interval for the checking the server status.
69 private static final int POLL_INTERVAL = 100;
72 * Maximum time to wait until the server has started or stopped.
74 private static final int MAX_WAIT_TIME = 10000;
77 * Database name to use.
79 private static final String DATABASE_NAME = "testdb";
82 * Path on the file system where derby files are stored.
84 private static final String DATABASE_PATH = "target/db/persistence/derby";
87 * Derby property required to set the file system path
88 * {@link #DATABASE_PATH}.
90 private static final String SYSTEM_PATH_PROPERTY = "derby.system.home";
92 private boolean inmemory;
95 * Constructs derby database class to allow creation of derby database
98 public DerbyDatabase() {
102 public DerbyDatabase(boolean aInMemoryFlag) {
103 inmemory = aInMemoryFlag;
109 * @see org.wamblee.persistence.Database#start()
111 public void doStart() {
113 System.setProperty("derby.stream.error.file", "target/derby.log");
114 // just in case a previous run was killed without the
116 cleanPersistentStorage();
119 // set database path.
120 Properties lProperties = System.getProperties();
121 lProperties.put(SYSTEM_PATH_PROPERTY, DATABASE_PATH);
124 Class.forName("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
128 waitUntilStartedOrStopped(true);
130 // Force creation of the database.
131 Connection lConnection = createConnection();
134 LOGGER.info("Database started: \n URL = " +
135 getExternalJdbcUrl() + "\n user = " + getUsername() +
136 "\n password = " + getPassword());
140 Runtime.getRuntime().addShutdownHook(new Thread() {
144 LOGGER.warning("Shutting down db");
145 DerbyDatabase.this.stop();
149 } catch (Exception e) {
150 throw new RuntimeException("Problem starting database", e);
155 * Waits until the database server has started or stopped.
158 * If true, waits until the server is up, if false, waits until
159 * the server is down.
160 * @throws InterruptedException
162 private void waitUntilStartedOrStopped(boolean aStarted)
163 throws InterruptedException {
166 while (aStarted != isStarted()) {
167 Thread.sleep(POLL_INTERVAL);
168 lWaited += POLL_INTERVAL;
170 if (lWaited > MAX_WAIT_TIME) {
171 throw new RuntimeException(
172 "Derby database did not start within " + MAX_WAIT_TIME +
179 * Checks if the database server has started or not.
181 * @return True if started, false otherwise.
183 private boolean isStarted() {
188 } catch (Exception e) {
194 * Gets the controller for the database server.
196 * @return Controller.
199 private NetworkServerControl getControl() throws Exception {
200 return new NetworkServerControl();
207 private void runDatabase() {
209 getControl().start(new PrintWriter(System.out));
210 } catch (Exception e) {
211 throw new RuntimeException(e);
218 * @see org.wamblee.persistence.Database#getJdbcUrl()
220 public String getJdbcUrl() {
221 return getBaseJdbcUrl() +
222 ";create=true;retrieveMessagesFromServerOnGetMessage=true;";
225 private String getBaseJdbcUrl() {
226 return (inmemory ? "jdbc:derby:memory:" : "jdbc:derby:") +
233 * @see org.wamblee.persistence.Database#getExternalJdbcUrl()
235 public String getExternalJdbcUrl() {
236 return "jdbc:derby://localhost:1527/" + (inmemory ? "memory:" : "") +
241 * Shuts down the derby database and cleans up all created files.
244 private void shutdownDerby() {
246 DriverManager.getConnection("jdbc:derby:;shutdown=true");
247 throw new RuntimeException(
248 "Derby did not shutdown, should always throw exception at shutdown");
249 } catch (Exception e) {
250 LOGGER.info("Derby has been shut down.");
255 * Gets the user name.
257 public String getUsername() {
266 public String getPassword() {
273 * @see org.wamblee.persistence.Database#createConnection()
275 public Connection createConnection() throws SQLException {
276 Connection c = DriverManager.getConnection(getJdbcUrl(), getUsername(),
283 * Stops the derby database and cleans up all derby files.
285 public void doStop() {
287 // shutdown network server.
288 getControl().shutdown();
289 waitUntilStartedOrStopped(false);
291 // shutdown inmemory access.
293 cleanPersistentStorage();
294 } catch (Exception e) {
295 LOGGER.log(Level.WARNING, "Problem stopping database", e);
300 * Cleans up persistent storage of Derby.
302 private void cleanPersistentStorage() {
303 File lFile = new File(DATABASE_PATH);
305 if (lFile.isFile()) {
306 TestCase.fail("A regular file by the name " + DATABASE_PATH +
307 " exists, clean this up first");
310 if (!lFile.isDirectory()) {
311 return; // no-op already cleanup up.
313 FileSystemUtils.deleteDirRecursively(DATABASE_PATH);