/** * Copyright 2009 ATG DUST Project 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 atg.service.jdbc; import java.sql.DriverManager; import java.sql.SQLException; import org.apache.log4j.Logger; import atg.nucleus.ServiceException; /** * <b>Experimental since Apache Derby is not supported by ATG 9.0.</b> * * This datasource is used for testing. It starts up a Derby in memory instance * on localhost automatically. The database will be named "testdb" by default. * If you need to name it something else set the "databaseName" property on this * component. You may want to change the name if your test requires running two * databases at the same time. * * @author adamb * @version $Id:$ */ public class DerbyDataSource extends InitializingDataSourceBase { static Logger sLog = Logger.getLogger(DerbyDataSource.class); private String framework = "embedded"; private String driver = "org.apache.derby.jdbc.EmbeddedDriver"; private String protocol = "jdbc:derby:"; private boolean mAddedShutdownHook = false; /** * Sets Derby JDBC properties to be used when the first client asks for a * connection. */ @Override public void doStartService() throws ServiceException { logInfo("Starting DerbyDataSource."); loadDriver(); this.setURL(protocol + getDatabaseName() + ";create=true"); this.setDriver(driver); this.setUser("user1"); this.setPassword("user1"); } /** * Cleans up for dynamo shutdown */ @Override public void doStopService() throws ServiceException { // Add a shutdown hook to shut down derby. // We can't shutdown now because not all dynamo services // that depend on us are guaranteed to be stopped when this method is // invoked. if (!mAddedShutdownHook) addShutdownHook(getDatabaseName()); } /** * Adds a shutdown hook to shutdown Derby when the JVM exits. * * @param pDBName * */ private void addShutdownHook(String pDBName) { final String name = pDBName; Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { DerbyDataSource.shutdown(name); } }); } /** * Shuts down derby * * @param name */ private static void shutdown(String name) { try { // the shutdown=true attribute shuts down Derby DriverManager.getConnection("jdbc:derby:" + name + ";shutdown=true"); // To shut down a specific database only, but keeep the // engine running (for example for connecting to other // databases), specify a database in the connection URL: // DriverManager.getConnection("jdbc:derby:" + dbName + // ";shutdown=true"); } catch (SQLException se) { if (((se.getErrorCode() == 50000) && ("XJ015".equals(se.getSQLState())))) { // we got the expected exception sLog.info("Derby shut down normally"); // Note that for single database shutdown, the expected // SQL state is "08006", and the error code is 45000. } else if ((se.getErrorCode() == 45000) && ("08006".equals(se.getSQLState()))) { // database is already shutdown } else { // if the error code or SQLState is different, we have // an unexpected exception (shutdown failed) sLog.error("Derby did not shut down normally", se); printSQLException(se); } } } /** * Prints details of an SQLException chain to <code>System.err</code>. Details * included are SQL State, Error code, Exception message. * * @param e * the SQLException from which to print details. */ public static void printSQLException(SQLException e) { // Unwraps the entire exception chain to unveil the real cause of the // Exception. while (e != null) { System.err.println("\n----- SQLException -----"); System.err.println(" SQL State: " + e.getSQLState()); System.err.println(" Error Code: " + e.getErrorCode()); System.err.println(" Message: " + e.getMessage()); // for stack traces, refer to derby.log or uncomment this: // e.printStackTrace(System.err); e = e.getNextException(); } } /** * Loads the appropriate JDBC driver for this environment/framework. For * example, if we are in an embedded environment, we load Derby's embedded * Driver, <code>org.apache.derby.jdbc.EmbeddedDriver</code>. */ private void loadDriver() { /* * The JDBC driver is loaded by loading its class. If you are using JDBC 4.0 * (Java SE 6) or newer, JDBC drivers may be automatically loaded, making * this code optional. * * In an embedded environment, this will also start up the Derby engine * (though not any databases), since it is not already running. In a client * environment, the Derby engine is being run by the network server * framework. * * In an embedded environment, any static Derby system properties must be * set before loading the driver to take effect. */ try { Class.forName(driver).newInstance(); } catch (ClassNotFoundException cnfe) { sLog.error("\nUnable to load the JDBC driver " + driver); sLog.error("Please check your CLASSPATH."); cnfe.printStackTrace(System.err); } catch (InstantiationException ie) { sLog.error("\nUnable to instantiate the JDBC driver " + driver); ie.printStackTrace(System.err); } catch (IllegalAccessException iae) { sLog.error("\nNot allowed to access the JDBC driver " + driver); iae.printStackTrace(System.err); } } }