001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: HSQLDBComponent.java 1970 2007-10-16 11:49:25Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.component.hsqldb;
025:
026: import java.io.File;
027: import java.sql.Connection;
028: import java.sql.DriverManager;
029: import java.sql.ResultSet;
030: import java.sql.SQLException;
031: import java.sql.Statement;
032: import java.util.Iterator;
033: import java.util.List;
034:
035: import org.hsqldb.DatabaseManager;
036: import org.hsqldb.Server;
037: import org.hsqldb.ServerConstants;
038: import org.ow2.easybeans.component.api.EZBComponentException;
039: import org.ow2.easybeans.component.itf.EmbeddedDBComponent;
040: import org.ow2.util.log.Log;
041: import org.ow2.util.log.LogFactory;
042:
043: /**
044: * Allows to start an embedded HSQLDB server.
045: * @author Florent Benoit
046: */
047: public class HSQLDBComponent implements EmbeddedDBComponent {
048:
049: /**
050: * Logger.
051: */
052: private static Log logger = LogFactory
053: .getLog(HSQLDBComponent.class);
054:
055: /**
056: * List of users.
057: */
058: private List<User> users = null;
059:
060: /**
061: * Name of database.
062: */
063: private String databaseName = null;
064:
065: /**
066: * Default port number.
067: */
068: private static final String DEFAULT_PORT = "9001";
069:
070: /**
071: * Sleep value.
072: */
073: private static final int SLEEP_VALUE = 100;
074:
075: /**
076: * Max retry number.
077: */
078: private static final int MAX_RETRY_NB = 20;
079:
080: /**
081: * port number used.
082: */
083: private String portNumber = null;
084:
085: /**
086: * HsqlDB server.
087: */
088: private Server server = null;
089:
090: /**
091: * Default constructor.<br>
092: * Use default port number.
093: */
094: public HSQLDBComponent() {
095: this .portNumber = DEFAULT_PORT;
096: }
097:
098: /**
099: * Init method.<br/> This method is called before the start method.
100: * @throws EZBComponentException if the initialization has failed.
101: */
102: @SuppressWarnings("unchecked")
103: public void init() throws EZBComponentException {
104:
105: server = new Server();
106: // Remove all traces if level != DEBUG
107: if (!logger.isDebugEnabled()) {
108: server.setLogWriter(null);
109: server.setErrWriter(null);
110: server.setSilent(true);
111: server.setTrace(false);
112: server.setLogWriter(null);
113: } else {
114: // Enable all traces : verbose mode (as user needs DEBUG)
115: server.setSilent(false);
116: server.setTrace(true);
117: }
118:
119: String baseDir = System.getProperty("java.io.tmpdir")
120: + File.separator + "easybeans" + File.separator
121: + "hsqldb" + File.separator + databaseName;
122: String pString = "";
123: if (portNumber != null) {
124: pString = ";port=" + portNumber;
125: }
126: String serverProps = "database.0=" + baseDir + ";dbname.0="
127: + databaseName + pString;
128: logger.debug("Server properties = {0}", serverProps);
129: server.putPropertiesFromString(serverProps);
130:
131: try {
132: Class.forName("org.hsqldb.jdbcDriver");
133: } catch (ClassNotFoundException e) {
134: throw new EZBComponentException(
135: "Cannot access to HSQL Driver 'org.hsqldb.jdbcDriver'.",
136: e);
137: }
138:
139: }
140:
141: /**
142: * Start method.<br/> This method is called after the init method.
143: * @throws EZBComponentException if the start has failed.
144: */
145: @SuppressWarnings("boxing")
146: public void start() throws EZBComponentException {
147:
148: logger.info("Starting ''{0}'' ''{1}'' on port ''{2}''", server
149: .getProductName(), server.getProductVersion(),
150: portNumber);
151:
152: server.start();
153:
154: // Wait the start
155: int retryNb = 0;
156: while (server.getState() != ServerConstants.SERVER_STATE_ONLINE) {
157: try {
158: Thread.sleep(SLEEP_VALUE);
159: } catch (InterruptedException ie) {
160: logger.error("Cannot wait that the service is online",
161: ie);
162: }
163: // Error if server state is "SHUTDOWN" during a long period
164: // Maybe strange but 'SHUTDOWN' state seems to be an intermediate
165: // state during startup
166: retryNb++;
167: if (server.getState() == ServerConstants.SERVER_STATE_SHUTDOWN
168: && retryNb >= MAX_RETRY_NB) {
169: Throwable t = server.getServerError();
170: throw new EZBComponentException(
171: "Cannot start the server. The server has not started and is shutdown.",
172: t);
173: }
174: logger.debug("retry= {0}, serverState= {1}", retryNb,
175: server.getState());
176: }
177:
178: String connURL = "jdbc:hsqldb:hsql://localhost:" + portNumber
179: + "/" + databaseName;
180: logger.info("{0} started with URL {1}",
181: server.getProductName(), connURL);
182:
183: Connection conn = null;
184: Statement st = null;
185:
186: try {
187: conn = DriverManager.getConnection(connURL, "sa", "");
188: st = conn.createStatement();
189: } catch (SQLException e) {
190: throw new EZBComponentException("Cannot access to HSQL", e);
191: }
192:
193: // Drop users before recreating it
194: User user = null;
195: String userName = null;
196: String password = null;
197: ResultSet rs = null;
198: for (Iterator it = users.iterator(); it.hasNext();) {
199: user = (User) it.next();
200: try {
201: password = user.getPassword();
202: userName = user.getUserName();
203: logger
204: .debug(
205: "Dropping and adding user {0} with password {1}.",
206: userName, password);
207: try {
208: rs = st.executeQuery("DROP USER " + userName);
209: } catch (SQLException e) {
210: logger
211: .debug("User {0} doesn't exists", userName,
212: e);
213: }
214: rs = st.executeQuery("Create USER " + userName
215: + " PASSWORD " + password + " ADMIN");
216: rs.close();
217: } catch (SQLException e) {
218: logger.error("Error while creating/adding user", e);
219: }
220:
221: }
222:
223: try {
224: st.close();
225: } catch (SQLException e) {
226: logger.error("Error while closing statement object", e);
227: }
228:
229: }
230:
231: /**
232: * Gets the list of users.
233: * @return the list of users.
234: */
235: public List<User> getUsers() {
236: return this .users;
237: }
238:
239: /**
240: * Set the list of users.
241: * @param users the list of users.
242: */
243: public void setUsers(final List<User> users) {
244: this .users = users;
245: }
246:
247: /**
248: * Stop method.<br/> This method is called when component needs to be
249: * stopped.
250: * @throws EZBComponentException if the stop is failing.
251: */
252: public void stop() throws EZBComponentException {
253: server.shutdown();
254: DatabaseManager.getTimer().shutDown();
255: }
256:
257: /**
258: * Sets the port number.
259: * @param portNumber the port number to use.
260: */
261: public void setPortNumber(final String portNumber) {
262: this .portNumber = portNumber;
263: }
264:
265: /**
266: * Sets the database name.
267: * @param databaseName the name of the database.
268: */
269: public void setDatabaseName(final String databaseName) {
270: this.databaseName = databaseName;
271: }
272:
273: }
|