1385defd1c0cab3646ec0feb871e2732547cf132
[utils] / support / general / src / test / java / org / wamblee / persistence / DerbyDatabase.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
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
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
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.
15  */ 
16 package org.wamblee.persistence;
17
18 import java.io.File;
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
25 import junit.framework.TestCase;
26
27 import org.apache.derby.drda.NetworkServerControl;
28 import org.apache.derby.jdbc.ClientDriver;
29 import org.apache.derby.jdbc.EmbeddedDriver;
30 import org.apache.log4j.Logger;
31 import org.wamblee.io.FileSystemUtils;
32
33
34 /**
35  * Derby database setup.
36  * The external JDBC url used to connect to a running instance is
37  * <pre>
38  *     jdbc:derby:net://localhost:1527/testdb 
39  * </pre>
40  * and the driver class is
41  * <pre>
42  *     com.ibm.db2.jcc.DB2Driver
43  * </pre>
44  * The following jars will have to be used
45  * <code>db2jcc.jar</code> and <code>db2jcc_license_c.jar</code>.
46  */
47 public class DerbyDatabase implements Database {
48     
49     /**
50      * Logger.
51      */
52     private static final Logger LOGGER 
53         = Logger.getLogger( DerbyDatabase.class );
54     
55     /**
56      * Database user name.
57      */
58     private static final String USERNAME = "sa";
59
60     /**
61      * Database password.
62      */
63     private static final String PASSWORD = "123";
64
65     /**
66      * Poll interval for the checking the server status.
67      */
68     private static final int POLL_INTERVAL = 100;
69
70     /**
71      * Maximum time to wait until the server has started or stopped.
72      */
73     private static final int MAX_WAIT_TIME = 10000;
74
75     /**
76      * Database name to use.
77      */
78     private static final String DATABASE_NAME = "testdb";
79
80     /**
81      * Path on the file system where derby files are stored.
82      */
83     private static final String DATABASE_PATH = "target/db/persistence/derby";
84
85     /**
86      * Derby property required to set the file system path
87      * {@link #DATABASE_PATH}.
88      */
89     private static final String SYSTEM_PATH_PROPERTY = "derby.system.home";
90     
91     /**
92      * Constructs derby database class to allow creation of derby
93      * database instances.
94      */
95     public DerbyDatabase(  ) {
96         // Empty
97     }
98
99     /*
100      * (non-Javadoc)
101      * @see org.wamblee.persistence.Database#start()
102      */
103     public void start(  ) throws Exception {
104         // just in case a previous run was killed without the 
105         // cleanup
106         cleanPersistentStorage(  );
107
108         // set database path.
109         Properties lProperties = System.getProperties(  );
110         lProperties.put( SYSTEM_PATH_PROPERTY, DATABASE_PATH );
111         
112         Class.forName( "org.apache.derby.jdbc.EmbeddedDriver" ).newInstance(  );
113         
114         runDatabase(  );
115
116         waitUntilStartedOrStopped( true );
117
118         // Force creation of the database.
119         Connection lConnection = createConnection(  );
120         lConnection.close(  );
121     }
122
123     /**
124      * Waits until the database server has started or stopped.
125      *
126      * @param aStarted
127      *            If true, waits until the server is up, if false, waits until
128      *            the server is down.
129      * @throws InterruptedException
130      */
131     private void waitUntilStartedOrStopped( boolean aStarted )
132         throws InterruptedException {
133         long lWaited = 0;
134
135         while ( aStarted != isStarted(  ) ) {
136             Thread.sleep( POLL_INTERVAL );
137             lWaited += POLL_INTERVAL;
138
139             if ( lWaited > MAX_WAIT_TIME ) {
140                 throw new RuntimeException( 
141                     "Derby database did not start within " + MAX_WAIT_TIME
142                     + "ms" );
143             }
144         }
145     }
146
147     /**
148      * Checks if the database server has started or not.
149      *
150      * @return True if started, false otherwise.
151      */
152     private boolean isStarted(  ) {
153         try {
154             getControl(  ).ping(  );
155
156             return true;
157         } catch ( Exception e ) {
158             return false;
159         }
160     }
161
162     /**
163      * Gets the controller for the database server.
164      *
165      * @return Controller.
166      * @throws Exception
167      */
168     private NetworkServerControl getControl(  ) throws Exception {
169         return new NetworkServerControl(  );
170     }
171
172     /**
173      * Runs the database.
174      *
175      */
176     private void runDatabase(  ) {
177         try {
178             getControl(  ).start( new PrintWriter( System.out ) );
179         } catch ( Exception e ) {
180             throw new RuntimeException( e );
181         }
182     }
183
184    /*
185     * (non-Javadoc)
186     * @see org.wamblee.persistence.Database#getJdbcUrl()
187     */
188     public String getJdbcUrl(  ) {
189         return getBaseJdbcUrl(  )
190         + ";create=true;retrieveMessagesFromServerOnGetMessage=true;";
191     }
192
193     private String getBaseJdbcUrl(  ) {
194         return "jdbc:derby:" + DATABASE_NAME;
195     }
196     
197     /*
198      * (non-Javadoc)
199      * @see org.wamblee.persistence.Database#getExternalJdbcUrl()
200      */
201     public String getExternalJdbcUrl( ) {
202         return "jdbc:derby:net://localhost:1527/" + DATABASE_NAME;
203     }
204
205     /**
206      * Shuts down the derby database and cleans up all created files.
207      *
208      */
209     private void shutdownDerby(  ) {
210         try {
211             DriverManager.getConnection( "jdbc:derby:;shutdown=true" );
212             throw new RuntimeException( 
213                 "Derby did not shutdown, " 
214                     + " should always throw exception at shutdown" );
215         } catch ( Exception e ) {
216             LOGGER.info( "Derby has been shut down." );
217         }
218     }
219     
220    /*
221     * (non-Javadoc)
222     * @see org.wamblee.persistence.Database#getDriverClassName()
223     */
224     public String getDriverClassName( ) {
225         return ClientDriver.class.getName();
226     }
227
228     /**
229      * Gets the user name.
230      */
231     public String getUsername(  ) {
232         return USERNAME;
233     }
234
235     /**
236      * Gets the password.
237      * @return
238      */
239     public String getPassword(  ) {
240         return PASSWORD;
241     }
242
243    /*
244     * (non-Javadoc)
245     * @see org.wamblee.persistence.Database#createConnection()
246     */
247     public Connection createConnection(  ) throws SQLException {
248         Connection c =
249             DriverManager.getConnection( getJdbcUrl(  ), getUsername(  ),
250                 getPassword(  ) );
251
252         return c;
253     }
254
255     /**
256      * Stops the derby database and cleans up all derby files.
257      */
258     public void stop(  ) throws Exception {
259         // shutdown network server.
260         getControl(  ).shutdown(  );
261         waitUntilStartedOrStopped( false );
262
263         // shutdown inmemory access.
264         shutdownDerby(  );
265         cleanPersistentStorage(  );
266     }
267
268     /**
269      * Cleans up persistent storage of Derby.
270      */
271     private void cleanPersistentStorage(  ) {
272         File lFile = new File( DATABASE_PATH );
273
274         if ( lFile.isFile(  ) ) {
275             TestCase.fail( "A regular file by the name " + DATABASE_PATH
276                 + " exists, clean this up first" );
277         }
278
279         if ( !lFile.isDirectory(  ) ) {
280             return; // no-op already cleanup up. 
281         }
282
283         FileSystemUtils.deleteDirRecursively( DATABASE_PATH );
284     }
285 }