1 /* Copyright (c) 2011 Peter Troshin
\r
3 * JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0
\r
5 * This library is free software; you can redistribute it and/or modify it under the terms of the
\r
6 * Apache License version 2 as published by the Apache Software Foundation
\r
8 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
\r
9 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache
\r
10 * License for more details.
\r
12 * A copy of the license is in apache_license.txt. It is also available here:
\r
13 * @see: http://www.apache.org/licenses/LICENSE-2.0.txt
\r
15 * Any republication or derived work distributed in source code form
\r
16 * must include this copyright and license notice.
\r
18 package compbio.stat.collector;
\r
20 import java.sql.Connection;
\r
21 import java.sql.DriverManager;
\r
22 import java.sql.PreparedStatement;
\r
23 import java.sql.ResultSet;
\r
24 import java.sql.SQLException;
\r
25 import java.sql.Statement;
\r
26 import java.sql.Timestamp;
\r
27 import java.util.ArrayList;
\r
28 import java.util.Date;
\r
29 import java.util.List;
\r
30 import java.util.Set;
\r
32 import org.apache.log4j.Logger;
\r
34 import compbio.engine.conf.PropertyHelperManager;
\r
35 import compbio.util.Util;
\r
36 import compbio.ws.client.Services;
\r
39 * The database must be stored in the application root directory and called
\r
40 * "ExecutionStatistic"
\r
45 public class StatDB {
\r
47 private static final String driver = "org.apache.derby.jdbc.EmbeddedDriver";
\r
48 private static final String protocol = "jdbc:derby:";
\r
49 private static final String statDBName = "ExecutionStatistic";
\r
51 private static final Logger log = Logger.getLogger(StatDB.class);
\r
53 static Connection conn;
\r
55 private synchronized static Connection getDBConnection() throws SQLException {
\r
56 return getDBConnection(statDBName);
\r
59 private synchronized static Connection getDBConnection(String dbname) throws SQLException {
\r
61 if (conn != null && !conn.isClosed()) {
\r
65 String dbpath = PropertyHelperManager.getLocalPath();
\r
66 log.info("Looking for JABAWS access statistics database at: " + dbpath);
\r
67 System.setProperty("derby.system.home", dbpath);
\r
68 // Apparently under Tomcat webapp you cannot rely on Java
\r
69 // auto discovery and have to register the driver explicitly
\r
70 Class.forName(driver);
\r
71 conn = DriverManager.getConnection(protocol + dbname + ";create=false");
\r
73 conn.setAutoCommit(true);
\r
74 } catch (ClassNotFoundException e) {
\r
75 log.error(e.getMessage(), e);
\r
82 public StatDB(String dbname) throws SQLException {
\r
83 this.conn = getDBConnection(dbname);
\r
86 public StatDB() throws SQLException {
\r
87 this.conn = getDBConnection();
\r
91 * Connect to test database
\r
94 * @throws SQLException
\r
96 StatDB(boolean ignored) throws SQLException {
\r
97 this.conn = getTestDBConnection();
\r
100 private static Connection getTestDBConnection() throws SQLException {
\r
101 System.setProperty("derby.system.home", "testsrc/testdata");
\r
102 Connection conn = DriverManager.getConnection(protocol + statDBName
\r
103 + ";create=false");
\r
104 conn.setAutoCommit(true);
\r
105 log.debug("Connecting to the TEST database!");
\r
109 // ServiceName,jobname,start,finish,inputSize,resultSize,isCancelled,isCollected
\r
112 * rs.getBoolean(i) will return true for any non-zero value and false for 0
\r
113 * on SMALLINT data column.
\r
115 * @throws SQLException
\r
117 private void createStatTable() throws SQLException {
\r
118 // Creating a statement object that we can use for running various SQL
\r
119 // statements commands against the database.
\r
120 Statement s = conn.createStatement();
\r
121 String create = "create table exec_stat("
\r
122 + "number INT GENERATED ALWAYS AS IDENTITY,"
\r
123 + "service_name VARCHAR(15) NOT NULL, "
\r
124 + "cluster_job_id VARCHAR(30), "
\r
125 + "job_id VARCHAR(35) NOT NULL PRIMARY KEY, "
\r
126 + "start TIMESTAMP," + "finish TIMESTAMP,"
\r
127 + "inputsize BIGINT," + "resultsize BIGINT,"
\r
128 + "isCancelled SMALLINT NOT NULL,"
\r
129 + "isCollected SMALLINT NOT NULL, "
\r
130 + "isClusterJob SMALLINT NOT NULL)";
\r
131 // We create a table...
\r
138 static void clearStatTable() throws SQLException {
\r
139 Connection conn = getDBConnection();
\r
140 String query = "delete from exec_stat";
\r
141 Statement st = conn.createStatement();
\r
142 st.executeUpdate(query);
\r
148 void insertData(Set<JobStat> jobstatus) throws SQLException {
\r
149 log.info("Inserting " + jobstatus.size()
\r
150 + " new records into the statistics database");
\r
152 conn.setAutoCommit(false);
\r
153 String insert = "insert into exec_stat (service_name, cluster_job_id, job_id, start, finish, "
\r
154 + "inputsize, resultsize, isCancelled, isCollected, isClusterJob) "
\r
155 + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
\r
156 PreparedStatement pstm = conn.prepareStatement(insert);
\r
158 for (JobStat js : jobstatus) {
\r
160 pstm.setString(1, js.webService.toString());
\r
162 if (!Util.isEmpty(js.clusterJobId)) {
\r
163 pstm.setString(2, js.clusterJobId);
\r
165 pstm.setString(2, null);
\r
168 pstm.setString(3, js.jobname);
\r
170 if (js.start != ExecutionStatCollector.UNDEFINED) {
\r
171 pstm.setTimestamp(4, new Timestamp(js.start));
\r
173 pstm.setTimestamp(4, null);
\r
175 if (js.finish != ExecutionStatCollector.UNDEFINED) {
\r
176 pstm.setTimestamp(5, new Timestamp(js.finish));
\r
178 pstm.setTimestamp(5, null);
\r
181 pstm.setLong(6, js.inputSize);
\r
183 pstm.setLong(7, js.resultSize);
\r
185 pstm.setBoolean(8, js.isCancelled);
\r
186 pstm.setBoolean(9, js.isCollected);
\r
187 pstm.setBoolean(10, js.isClusterJob());
\r
188 pstm.executeUpdate();
\r
192 conn.setAutoCommit(true);
\r
194 log.debug(i + " jobs have been recorded...");
\r
197 public Date getEarliestRecord() throws SQLException {
\r
198 String query = "select min(start) from exec_stat";
\r
199 Statement st = conn.createStatement();
\r
200 ResultSet res = st.executeQuery(query);
\r
201 boolean exist = res.next();
\r
202 Date date = new Date();
\r
204 date = res.getDate(1);
\r
211 public int getTotalJobsCount(Timestamp from, Timestamp to)
\r
212 throws SQLException {
\r
213 String allQuery = "select count(*) from exec_stat where start BETWEEN ? and ? ";
\r
214 return getIntResult(from, to, allQuery);
\r
217 public int getCancelledCount(Timestamp from, Timestamp to)
\r
218 throws SQLException {
\r
220 String cancelledQuery = "select count(*) from exec_stat where start BETWEEN ? and ? and isCancelled=1 ";
\r
221 return getIntResult(from, to, cancelledQuery);
\r
224 public int getAbandonedCount(Timestamp from, Timestamp to)
\r
225 throws SQLException {
\r
226 // !js.isCollected && !js.isCancelled && js.hasResult()
\r
227 String abandonedQuery = "select count(*) from exec_stat where start BETWEEN ? and ? and isCollected=0 and isCancelled=0 and resultsize>0 ";
\r
228 return getIntResult(from, to, abandonedQuery);
\r
231 public int getIncompleteCount(Timestamp from, Timestamp to)
\r
232 throws SQLException {
\r
234 String incompleteQuery = "select count(*) from exec_stat where start BETWEEN ? and ? and resultsize<=0 and isCancelled=0";
\r
235 return getIntResult(from, to, incompleteQuery);
\r
238 private int getIntResult(Timestamp from, Timestamp to, String query)
\r
239 throws SQLException {
\r
241 log.debug("getIntRes: QUERY: " + query);
\r
242 log.debug("getIntRes: FROM: " + from);
\r
243 log.debug("getIntRes: TO: " + to);
\r
245 PreparedStatement pstm = conn.prepareStatement(query);
\r
246 pstm.setTimestamp(1, from);
\r
247 pstm.setTimestamp(2, to);
\r
249 ResultSet res = pstm.getResultSet();
\r
250 boolean exist = res.next();
\r
253 count = res.getInt(1);
\r
255 log.debug("getIntRes: RES: " + count);
\r
261 public List<JobStat> readData(Timestamp from, Timestamp to,
\r
262 Services wservice, Boolean clusterOnly) throws SQLException {
\r
264 String query = "select service_name, cluster_job_id, job_id, start, finish, inputsize, "
\r
265 + "resultsize, isCancelled, isCollected from exec_stat where start BETWEEN ? and ? ";
\r
267 if (wservice != null) {
\r
268 query += " and service_name=? ";
\r
271 if (clusterOnly != null) {
\r
273 query += " and isClusterJob!=0 ";
\r
275 query += " and isClusterJob=0 ";
\r
279 log.debug("QUERY: " + query);
\r
280 log.debug("FROM: " + from);
\r
281 log.debug("TO: " + to);
\r
282 log.debug("WS: " + wservice);
\r
284 PreparedStatement pstm = conn.prepareStatement(query);
\r
285 pstm.setTimestamp(1, from);
\r
286 pstm.setTimestamp(2, to);
\r
287 if (wservice != null) {
\r
288 pstm.setString(3, wservice.toString());
\r
291 List<JobStat> stats = new ArrayList<JobStat>();
\r
292 ResultSet rs = pstm.getResultSet();
\r
295 while (rs.next()) {
\r
297 stats.add(JobStat.newInstance(Services.getService(rs.getString(1)),
\r
298 rs.getString(2), rs.getString(3), rs.getTimestamp(4),
\r
299 rs.getTimestamp(5), rs.getLong(6), rs.getLong(7),
\r
300 rs.getBoolean(8), rs.getBoolean(9)));
\r
303 log.debug("QUERY result len: " + rcount);
\r
311 * Removes the job if
\r
313 * 1) It has already been recorded
\r
315 * 2) It has not completed and did not timeout - this is to prevent
\r
316 * recording the information on the incomplete jobs.
\r
319 * @throws SQLException
\r
321 public void removeRecordedJobs(Set<JobStat> fsJobs) throws SQLException {
\r
323 String query = "select job_id from exec_stat";
\r
325 if (null == conn) {
\r
326 System.out.println ("Something wrong with the DB...");
\r
329 Statement st = conn.createStatement();
\r
330 ResultSet result = st.executeQuery(query);
\r
332 while (result.next()) {
\r
333 String recordedJob = result.getString(1);
\r
334 JobStat recStat = JobStat.newIncompleteStat(recordedJob);
\r
335 if (fsJobs.contains(recStat)) {
\r
336 fsJobs.remove(recStat);
\r
343 public static synchronized final void shutdownDBServer() {
\r
344 // ## DATABASE SHUTDOWN SECTION ##
\r
346 * In embedded mode, an application should shut down Derby. Shutdown
\r
347 * throws the XJ015 exception to confirm success.
\r
350 if (conn != null) {
\r
353 } catch (SQLException e) {
\r
354 log.warn("Database commit failed with " + e.getLocalizedMessage());
\r
356 boolean gotSQLExc = false;
\r
358 DriverManager.getConnection("jdbc:derby:;shutdown=true");
\r
359 } catch (SQLException se) {
\r
360 if (se.getSQLState().equals("XJ015")) {
\r
365 log.warn("Database did not shut down normally");
\r
367 log.info("Database shut down normally");
\r
370 public static void main(String[] args) {
\r
371 // This is called from Ant cleanStatTable task
\r
374 shutdownDBServer();
\r
375 } catch (SQLException e) {
\r
376 System.err.println("Fails to clean up JABAWS stat database!");
\r
377 e.printStackTrace();
\r
379 // new StatDB().createStatTable();
\r
380 // insertData(null);
\r
382 * StatDB statdb = new StatDB(); Date from = new Date();
\r
383 * from.setMonth(1); System.out.println(new
\r
384 * StatProcessor(statdb.readData( new Timestamp(from.getTime()), new
\r
385 * Timestamp(new Date().getTime()), null, null)).reportStat());
\r