Stat collection and display done
[jabaws.git] / webservices / compbio / stat / collector / ExecutionStatCollector.java
index cef65f9..31a5747 100644 (file)
@@ -2,11 +2,11 @@ package compbio.stat.collector;
 \r
 import java.io.File;\r
 import java.io.FileFilter;\r
-import java.io.FileWriter;\r
 import java.io.IOException;\r
 import java.sql.SQLException;\r
 import java.text.SimpleDateFormat;\r
 import java.util.ArrayList;\r
+import java.util.Date;\r
 import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.List;\r
@@ -15,13 +15,10 @@ import java.util.Set;
 \r
 import org.apache.log4j.Logger;\r
 \r
-import compbio.engine.client.ConfExecutable;\r
 import compbio.engine.client.Executable;\r
-import compbio.engine.conf.PropertyHelperManager;\r
+import compbio.engine.client.PathValidator;\r
 import compbio.metadata.JobStatus;\r
-import compbio.runner.msa.ClustalW;\r
 import compbio.util.FileUtil;\r
-import compbio.util.PropertyHelper;\r
 import compbio.ws.client.Services;\r
 \r
 /**\r
@@ -52,7 +49,7 @@ import compbio.ws.client.Services;
  * @author pvtroshin\r
  * \r
  */\r
-public class ExecutionStatCollector {\r
+public class ExecutionStatCollector implements Runnable {\r
 \r
        static final int UNDEFINED = -1;\r
 \r
@@ -61,69 +58,78 @@ public class ExecutionStatCollector {
 \r
        static SimpleDateFormat DF = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");\r
 \r
-       static PropertyHelper ph = PropertyHelperManager.getPropertyHelper();\r
-\r
+       final private File workDirectory;\r
        final private List<JobStat> stats;\r
+       /**\r
+        * Consider the job that has been working for longer than timeOutInHours\r
+        * completed, whatever the outcome\r
+        */\r
+       final private int timeOutInHours;\r
 \r
-       public ExecutionStatCollector(String workDirectory) {\r
-               File[] files = FileUtil.getFiles(workDirectory, directories);\r
+       /**\r
+        * List subdirectories in the job directory\r
+        * \r
+        * @param workDirectory\r
+        * @param timeOutInHours\r
+        */\r
+       public ExecutionStatCollector(String workDirectory, int timeOutInHours) {\r
+               log.info("Starting stat collector for directory: " + workDirectory);\r
+               log.info("Maximum allowed runtime(h): " + timeOutInHours);\r
+               if (!PathValidator.isValidDirectory(workDirectory)) {\r
+                       throw new IllegalArgumentException("workDirectory '"\r
+                                       + workDirectory + "' does not exist!");\r
+               }\r
+               this.workDirectory = new File(workDirectory);\r
                stats = new ArrayList<JobStat>();\r
-               for (File file : files) {\r
-                       JobDirectory jd = new JobDirectory(file);\r
-                       stats.add(jd.getJobStat());\r
-                       // System.out.println(jd.getJobStat().getJobReportTabulated());\r
+               if (timeOutInHours <= 0) {\r
+                       throw new IllegalArgumentException(\r
+                                       "Timeout value must be greater than 0! Given value: "\r
+                                                       + timeOutInHours);\r
                }\r
+               this.timeOutInHours = timeOutInHours;\r
        }\r
 \r
-       public StatProcessor getStats() {\r
+       boolean hasCompleted(JobDirectory jd) {\r
+               JobStat jstat = jd.getJobStat();\r
+               if (jstat.hasResult() || jstat.getIsCancelled()\r
+                               || jstat.getIsFinished() || hasTimedOut(jd)) {\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       boolean hasTimedOut(JobDirectory jd) {\r
+               return ((System.currentTimeMillis() - jd.jobdir.lastModified()) / (1000 * 60 * 60)) > timeOutInHours;\r
+       }\r
+\r
+       StatProcessor getStats() {\r
                return new StatProcessor(stats);\r
        }\r
 \r
-       public void writeStatToDB() throws SQLException {\r
+       void writeStatToDB() throws SQLException {\r
                Set<JobStat> rjobs = new HashSet<JobStat>(stats);\r
                StatDB statdb = new StatDB();\r
+               log.debug("Removing records that has already been recorded");\r
+\r
                statdb.removeRecordedJobs(rjobs);\r
+               log.debug("New records left: " + rjobs.size());\r
                statdb.insertData(rjobs);\r
-               statdb.conn.close();\r
-       }\r
-\r
-       static String getClusterJobDir() {\r
-               String clusterdir = ph.getProperty("cluster.tmp.directory");\r
-               if (clusterdir != null) {\r
-                       clusterdir.trim();\r
-               }\r
-               return clusterdir;\r
-       }\r
-\r
-       static void updateTime(File statFile) throws IOException {\r
-               long lastMod = statFile.lastModified();\r
-               FileWriter fw = new FileWriter(statFile);\r
-               fw.write(new Long(lastMod).toString());\r
-               fw.close();\r
        }\r
 \r
-       static String getLocalJobDir() {\r
-               String locdir = ph.getProperty("local.tmp.directory");\r
-               if (locdir != null) {\r
-                       locdir.trim();\r
-               }\r
-               return locdir;\r
-       }\r
+       /*\r
+        * static void updateTime(File statFile) throws IOException { long lastMod =\r
+        * statFile.lastModified(); FileWriter fw = new FileWriter(statFile);\r
+        * fw.write(new Long(lastMod).toString()); fw.close(); }\r
+        */\r
 \r
        /**\r
-        * \r
-        * @param args\r
-        * @throws IOException\r
-        * @throws SQLException\r
+        * Not in use\r
         */\r
        public static void main(String[] args) throws IOException, SQLException {\r
 \r
                // updateTime(new File(\r
                // "D:\\workspace\\JABA2\\jobsout\\AACon#170462904473672\\STARTED"));\r
 \r
-               String workDir = PropertyHelperManager.getLocalPath()\r
-                               + getLocalJobDir().trim();\r
-               System.out.println(workDir);\r
                File[] files = FileUtil.getFiles("Y:\\fc\\www-jws2\\jaba\\jobsout",\r
                                directories);\r
                List<JobStat> stats = new ArrayList<JobStat>();\r
@@ -147,7 +153,8 @@ public class ExecutionStatCollector {
        static FileFilter directories = new FileFilter() {\r
                @Override\r
                public boolean accept(File pathname) {\r
-                       return pathname.isDirectory();\r
+                       return pathname.isDirectory()\r
+                                       && !pathname.getName().startsWith(".");\r
                }\r
        };\r
 \r
@@ -156,14 +163,14 @@ public class ExecutionStatCollector {
                File jobdir;\r
                Map<String, File> files = new HashMap<String, File>();\r
 \r
-               public JobDirectory(File directory) {\r
+               JobDirectory(File directory) {\r
                        this.jobdir = directory;\r
                        for (File f : jobdir.listFiles()) {\r
                                files.put(f.getName(), f);\r
                        }\r
                }\r
 \r
-               public boolean hasStatus(JobStatus status) {\r
+               boolean hasStatus(JobStatus status) {\r
                        return files.containsKey(status.toString());\r
                }\r
 \r
@@ -199,8 +206,9 @@ public class ExecutionStatCollector {
                                        clustjobId = FileUtil.readFileToString(jobid);\r
                                }\r
                        } catch (IOException ioe) {\r
-                               ioe.printStackTrace();\r
-                               // TODO LOG\r
+                               log.error(\r
+                                               "IO Exception while reading the content of JOBID file for job "\r
+                                                               + jobid, ioe);\r
                        }\r
                        return clustjobId.trim();\r
                }\r
@@ -225,26 +233,8 @@ public class ExecutionStatCollector {
                        return ftime;\r
                }\r
 \r
-               @SuppressWarnings("unchecked")\r
-               Class<Executable<?>> getWSRunnerName() {\r
-                       String name = jobdir.getName().split("#")[0];\r
-                       try {\r
-                               if (name.startsWith(ConfExecutable.CLUSTER_TASK_ID_PREFIX)) {\r
-                                       assert ConfExecutable.CLUSTER_TASK_ID_PREFIX.length() == 1;\r
-                                       name = name.substring(1);\r
-                               }\r
-                               name = ClustalW.class.getPackage().getName() + "." + name;\r
-                               return (Class<Executable<?>>) Class.forName(name);\r
-                       } catch (ClassNotFoundException e) {\r
-                               e.printStackTrace();\r
-                               throw new RuntimeException(\r
-                                               "Cannot match the directory name to the executable! Executable name is "\r
-                                                               + name);\r
-                       }\r
-               }\r
-\r
                private Services getService() {\r
-                       return Services.getService(getWSRunnerName());\r
+                       return Services.getServiceByJobDirectory(jobdir);\r
                }\r
 \r
                // Mafft, Muscle, Tcoffee, Clustal task:fasta.in result:fasta.out\r
@@ -253,7 +243,9 @@ public class ExecutionStatCollector {
                 * TODO replace with Universal names for WS!\r
                 */\r
                long getResultSize() {\r
-                       Class<Executable<?>> name = getWSRunnerName();\r
+                       Class<? extends Executable<?>> name = Services\r
+                                       .getRunnerByJobDirectory(jobdir);\r
+\r
                        File f = null;\r
                        if (name.getSimpleName().equalsIgnoreCase("Probcons")) {\r
                                f = files.get("alignment.out");\r
@@ -308,6 +300,38 @@ public class ExecutionStatCollector {
                                return false;\r
                        return true;\r
                }\r
+       }\r
+\r
+       private void collectStatistics() {\r
+               File[] files = workDirectory.listFiles(directories);\r
+               for (File file : files) {\r
+                       JobDirectory jd = new JobDirectory(file);\r
+                       JobStat jstat = jd.getJobStat();\r
+                       // Do not record stats on the job that has not completed yet\r
+                       if (hasCompleted(jd)) {\r
+                               stats.add(jstat);\r
+                       } else {\r
+                               log.debug("Skipping the job: " + jstat);\r
+                               log.debug("As it has not completed yet");\r
+                       }\r
+                       // System.out.println(jd.getJobStat().getJobReportTabulated());\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void run() {\r
+               log.info("Started updating statistics at " + new Date());\r
 \r
+               collectStatistics();\r
+\r
+               StatProcessor local_stats = getStats();\r
+               log.info("Found " + local_stats.getJobNumber() + " jobs!");\r
+               try {\r
+                       writeStatToDB();\r
+               } catch (SQLException e) {\r
+                       log.error("Fails to update jobs statistics database!");\r
+                       log.error(e.getLocalizedMessage(), e);\r
+               }\r
+               log.info("Finished updating statistics at " + new Date());\r
        }\r
 }\r