001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.core.node;
028:
029: import java.io.IOException;
030: import java.sql.Connection;
031: import java.sql.ResultSet;
032: import java.sql.SQLException;
033: import java.sql.Statement;
034: import java.util.Collections;
035: import java.util.HashMap;
036: import java.util.Map;
037:
038: import org.cougaar.util.DBConnectionPool;
039: import org.cougaar.util.DBProperties;
040: import org.cougaar.util.Parameters;
041: import org.cougaar.util.log.Logger;
042: import org.cougaar.util.log.Logging;
043: import org.cougaar.util.log.NullLogger;
044:
045: /**
046: * Implementation of {@link DBInitializerService}.
047: */
048: public class DBInitializerServiceImpl implements DBInitializerService {
049:
050: public static final String QUERY_FILE = "DBInitializer.q";
051:
052: private final Logger logger;
053: private final String trialId;
054: private final String assemblyMatch;
055: private final DBProperties dbp;
056: private final String database;
057: private final String username;
058: private final String password;
059:
060: /**
061: * Constructor creates a DBInitializer from the DBInitializer.q
062: * query control file and sets up variables for referencing the database.
063: * <p>
064: * @param trialId the Trial identifier.
065: */
066: public DBInitializerServiceImpl(String trialId)
067: throws SQLException, IOException {
068: Logger l = Logging.getLogger(getClass());
069: logger = ((l == null) ? NullLogger.getLogger() : l);
070:
071: dbp = DBProperties.readQueryFile(QUERY_FILE);
072: database = dbp.getProperty("database");
073: username = dbp.getProperty("username");
074: password = dbp.getProperty("password");
075: this .trialId = trialId;
076: if (logger.isInfoEnabled()) {
077: logger.info("Will initialize for trial " + trialId
078: + " from DB " + database);
079: }
080:
081: try {
082: String dbtype = dbp.getDBType();
083: ensureDriverClass(dbtype);
084: Connection conn = getConnection();
085: try {
086: Statement stmt = conn.createStatement();
087: String query = getQuery("queryExperiment", Collections
088: .singletonMap(":trial_id:", trialId));
089: ResultSet rs = executeQuery(stmt, query);
090: boolean first = true;
091: StringBuffer asbBuffer = new StringBuffer();
092: asbBuffer.append("in (");
093: while (rs.next()) {
094: if (first) {
095: first = false;
096: } else {
097: asbBuffer.append(", ");
098: }
099: asbBuffer.append("'");
100: asbBuffer.append(getNonNullString(rs, 1, query));
101: asbBuffer.append("'");
102: }
103: asbBuffer.append(")");
104: assemblyMatch = asbBuffer.toString();
105: rs.close();
106: stmt.close();
107: } finally {
108: conn.close();
109: }
110: } catch (ClassNotFoundException e) {
111: throw new SQLException("Driver not found for " + database);
112: }
113: if (logger.isInfoEnabled()) {
114: logger.info("Initializing from assemblies: AsbMatch: "
115: + assemblyMatch);
116: }
117: }
118:
119: public Map createSubstitutions() {
120: Map m = new HashMap(7);
121: m.put(":trial_id:", trialId);
122: m.put(":assemblyMatch:", assemblyMatch);
123: return m;
124: }
125:
126: public String getNonNullString(ResultSet rs, int ix, String query)
127: throws SQLException {
128: String result = rs.getString(ix);
129: if (result == null)
130: throw new RuntimeException("Null in DB ix=" + ix
131: + " query=" + query);
132: return result;
133: }
134:
135: public String getQuery(String queryName, Map substitutions) {
136: return dbp.getQuery(queryName, substitutions);
137: }
138:
139: public Connection getConnection() throws SQLException {
140: return DBConnectionPool.getConnection(database, username,
141: password);
142: }
143:
144: public ResultSet executeQuery(Statement stmt, String query)
145: throws SQLException {
146: try {
147: boolean shouldLog = logger.isDebugEnabled();
148: long startTime = (shouldLog ? 0L : System
149: .currentTimeMillis());
150: ResultSet rs = stmt.executeQuery(query);
151: if (shouldLog) {
152: long endTime = System.currentTimeMillis();
153: logger.debug((endTime - startTime) + " " + query);
154: }
155: return rs;
156: } catch (SQLException sqle) {
157: if (logger.isErrorEnabled()) {
158: logger.error("Query failed: " + query, sqle);
159: }
160: throw sqle;
161: }
162: }
163:
164: /**
165: * Translate the value of a "query" attribute type. The "key"
166: * should be one or more query substitutions. Each substitution is
167: * an equals separated key and value. Multiple substitutions are
168: * separated by semi-colon. Backslash can quote a character. The
169: * query may be in a different database. If so, then the dbp
170: * should contain properties named by concatenating the query
171: * name with .database, .username, .password describing the
172: * database to connect to.
173: * @param type is the "data type" of the attribute value and
174: * names a query that should be done to obtain the actual
175: * value.
176: * @return a two-element array of attribute type and value.
177: */
178: public Object[] translateAttributeValue(String type, String key)
179: throws SQLException {
180: Map substitutions = createSubstitutions();
181: substitutions.put(":key:", key);
182: String db = dbp.getProperty(type + ".database", database);
183: String un = dbp.getProperty(type + ".username", username);
184: String pw = dbp.getProperty(type + ".password", password);
185: try {
186: ensureDriverClass(dbp.getDBType(db));
187: } catch (ClassNotFoundException cnfe) {
188: throw new SQLException("Driver not found for " + db);
189: }
190: Connection conn = DBConnectionPool.getConnection(db, un, pw);
191: try {
192: Statement stmt = conn.createStatement();
193: String query = dbp.getQueryForDatabase(type, substitutions,
194: type + ".database");
195: ResultSet rs = executeQuery(stmt, query);
196: Object[] result = new Object[2];
197: if (rs.next()) {
198: result[0] = rs.getString(1);
199: result[1] = rs.getString(2);
200: } else {
201: // It would be nice to not die if the GEOLOC or whatever
202: // is not found. I'm just not certain
203: // how the caller (ie AssetDataDBReader) will react
204: // if the result is an empty String.
205: // result[0] = type;
206: // result[1] = "";
207: throw new SQLException(
208: "No row returned for attribute value query "
209: + type + "(" + key + ")");
210: }
211: rs.close();
212: stmt.close();
213: return result;
214: } finally {
215: conn.close();
216: }
217: }
218:
219: private void ensureDriverClass(String dbtype) throws SQLException,
220: ClassNotFoundException {
221: String driverParam = "driver." + dbtype;
222: String driverClass = Parameters.findParameter(driverParam);
223: if (driverClass == null) {
224: // this is likely a "cougaar.rc" problem.
225: // Parameters should be modified to help generate this exception:
226: throw new SQLException("Unable to find driver class for \""
227: + driverParam + "\" -- check your \"cougaar.rc\"");
228: }
229: Class.forName(driverClass);
230: }
231:
232: }
|