001/*
002 * Copyright (c) 2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030/* A thread for executing the lidar processing. 
031 */
032
033package org.geon;
034
035import java.io.BufferedReader;
036import java.io.BufferedWriter;
037import java.io.File;
038import java.io.FileInputStream;
039import java.io.FileOutputStream;
040import java.io.FileWriter;
041import java.io.IOException;
042import java.io.InputStream;
043import java.io.InputStreamReader;
044import java.io.OutputStream;
045import java.io.RandomAccessFile;
046import java.io.Reader;
047import java.net.URL;
048import java.util.Date;
049import java.util.HashMap;
050import java.util.Map;
051import java.util.Properties;
052import java.util.TreeMap;
053import java.util.Vector;
054
055import javax.mail.Message;
056import javax.mail.MessagingException;
057import javax.mail.Session;
058import javax.mail.Transport;
059import javax.mail.internet.InternetAddress;
060import javax.mail.internet.MimeMessage;
061import javax.servlet.http.HttpServletRequest;
062
063//////////////////////////////////////////////////////////////////////////
064//// ExecutionThread
065/**
066 * Thread for executing the Lidar processing.
067 * 
068 * @author Efrat Jaeger
069 */
070public class ExecutionThread extends Thread {
071
072        public ExecutionThread() {
073        }
074
075        public ExecutionThread(HttpServletRequest request, StringBuffer threadResp,
076                        String appPath, String uniqueId, String host, String port) {
077                super();
078                this.request = request;
079                this.appPath = appPath;
080                this.uniqueId = uniqueId;
081                this.threadResp = threadResp;
082                this.host = host;
083                this.port = port;
084        }
085
086        private HttpServletRequest request;
087        private String appPath;
088        private String uniqueId;
089        private String host;
090        private String port;
091        public StringBuffer threadResp;
092        private String header;
093        private String footer;
094
095        public void run() {
096
097                header = "<TABLE>\n";
098                header += "<TR>\n";
099                header += "<TD><A HREF=\"http://activetectonics.la.asu.edu/GEONatASU/index.htm\" target=\"_new\"><IMG SRC=\"http://agassiz.la.asu.edu/logos/GEONASUWebBanner.jpg\" alt=\"GEON at ASU homepage\"></A></TD>\n";
100                header += "<TD><a href=\"http://www.sdsc.edu\" target=\"_new\"><img src=\"http://www.sdsc.edu/logos/SDSClogo-plusname-red.gif\" alt=\"San Diego Supercomputer Center\" height=\"60\" width=\"216\"></a></TD>\n";
101                header += "</TR>\n";
102                header += "</TABLE>\n";
103                header += "<table cellpadding=2>\n";
104
105                footer = "</table>\n";
106
107                String configFile = (String) request.getAttribute("configFile");
108                if (configFile == null || configFile.equals("")) {
109                        System.out
110                                        .println("unable to connect to lidar db - missing configuration file");
111
112                        threadResp.append(header);
113                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
114                        threadResp
115                                        .append("<tr><td>Unable to connect to the LiDAR database.");
116                        threadResp.append("</td></tr>");
117                        threadResp.append(footer);
118                        return;
119                }
120                LidarJobDB lidarJobDB = new LidarJobDB(configFile, new Date()
121                                .toString());
122                try {
123                        lidarJobDB.createNewEntry(request);
124                } catch (Exception ex) {
125                        ex.printStackTrace();
126                        threadResp.append(header);
127                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
128                        threadResp.append("<tr><td>Unable to submit job.");
129                        threadResp.append("</td></tr>");
130                        threadResp.append(footer);
131                        return;
132
133                }
134                // For logging purposes.
135                String log = "";
136
137                // For recording execution times.
138                Map timings = new HashMap();
139
140                // get parameters.
141                Map inputs = new TreeMap();
142                inputs.put("id", uniqueId);
143                System.out.println("uniqueId ==> " + uniqueId + "\n");
144                log += uniqueId + " ";
145
146                // use username instead of email.
147                String email = request.getParameter("email");
148                // System.out.println("email ==> " + email);
149                inputs.put("email", email);
150
151                String user = request.getParameter("username");
152
153                String ip = request.getRemoteAddr();
154                log += ip + " ";
155
156                if (email == null || email.equals("")) {
157                        email = "noEmail";
158                }
159                log += email + " ";
160
161                String srid = request.getParameter("srid");
162                log += srid + " ";
163
164                String rawdata = request.getParameter("rawdata");
165                if (rawdata == null)
166                        rawdata = "0";
167                inputs.put("rawdata", rawdata);
168
169                String download = request.getParameter("download");
170                System.out.println("download = " + download);
171
172                // Read processing parameters.
173                StringBuffer sb = new StringBuffer();
174                StringBuffer xmlParams = new StringBuffer();
175                xmlParams
176                                .append("<command><dataset><filename name=\"/export/downloads/kepler/rawData/");
177                xmlParams.append(uniqueId + "\"/></dataset>\n");
178                xmlParams.append("<query>\n");
179
180                String algs[] = { "elev", "slope", "aspect", "pcurv" };
181                String formats[] = { "view", "arc", "ascii", "tiff" };
182                String logAlgs = "";
183
184                for (int i = 0; i < 4; i++) {
185                        for (int j = 0; j < 4; j++) {
186                                String type = algs[i] + formats[j];
187                                String typeVal = request.getParameter(type);
188                                if (j == 0) {
189                                        inputs.put(type, typeVal);
190                                        logAlgs += (i == 0 ? "spline" : algs[i]) + "="
191                                                        + (typeVal.equals("") ? "0" : "1") + " ";
192                                }
193                                System.out.println(type + "=" + typeVal);
194                                if (typeVal != null && !typeVal.equals("")) {
195                                        sb.append(type + "=" + typeVal + "\n");
196                                        xmlParams
197                                                        .append("<attribute name=\"" + algs[i]
198                                                                        + "\" type=\"" + formats[j]
199                                                                        + "\" value=\"1\" />\n");
200                                }
201                        }
202                }
203                String resolution = request.getParameter("resolution");
204                if (resolution != null && !resolution.equals("")) {
205                        sb.append("res=" + resolution + "\n");
206                        xmlParams.append("<attribute name=\"res\" type=\"\" value=\""
207                                        + resolution + "\" />\n");
208                        logAlgs += "res=" + resolution + " ";
209                } else
210                        logAlgs += "res=6 ";
211
212                String dmin = request.getParameter("dmin");
213                String tension = request.getParameter("spline_tension");
214                String smooth = request.getParameter("spline_smoothing");
215
216                if (dmin != null && !dmin.equals("")) {
217                        sb.append("dmin=" + dmin + "\n");
218                        xmlParams.append("<attribute name=\"dmin\" type=\"\" value=\""
219                                        + dmin + "\" />\n");
220                        logAlgs += "dmin=" + dmin + " ";
221                } else
222                        logAlgs += "dmin=1 ";
223                if (tension != null && !tension.equals("")) {
224                        sb.append("tension=" + tension + "\n");
225                        xmlParams.append("<attribute name=\"tension\" type=\"\" value=\""
226                                        + tension + "\" />\n");
227                        logAlgs += "tension=" + tension + " ";
228                } else
229                        logAlgs += "tension=40 ";
230                if (smooth != null && !smooth.equals("")) {
231                        sb.append("smooth=" + smooth + "\n");
232                        xmlParams.append("<attribute name=\"smooth\" type=\"\" value=\""
233                                        + smooth + "\" />\n");
234                        logAlgs += "smooth=" + smooth + " ";
235                } else
236                        logAlgs += "smooth=0.1 ";
237
238                String projection = request.getParameter("projection");
239                String units = request.getParameter("units");
240                sb.append("projection=" + projection + "\n");
241                sb.append("units=" + units + "\n");
242
243                xmlParams.append("<attribute name=\"id\" type=\"\" value=\"" + uniqueId
244                                + "\" />\n");
245                xmlParams
246                                .append("<attribute name=\"path\" type=\"\" value=\"./\" />\n");
247                xmlParams.append("</query></command>");
248                System.out.println("xmlParams:\n" + xmlParams.toString());
249
250                String MinX = request.getParameter("MinX");
251                String MaxX = request.getParameter("MaxX");
252                String MinY = request.getParameter("MinY");
253                String MaxY = request.getParameter("MaxY");
254                System.out.println("MinX ==> " + MinX);
255                System.out.println("MinY ==> " + MinY);
256                System.out.println("MaxX ==> " + MaxX);
257                System.out.println("MaxY ==> " + MaxY);
258                log += MinX + " " + MaxX + " " + MinY + " " + MaxY + " ";
259
260                String[] classification = request.getParameterValues("c");
261                log += "{";
262                // log += classification.toString() + " ";
263                if (classification != null) {
264                        for (int i = 0; i < classification.length - 1; i++) {
265                                log += classification[i] + ",";
266                                // System.out.println("clasification (Execution thread) ==> " +
267                                // classification[i]);
268                        }
269                        log += classification[classification.length - 1];
270                }
271                log += "} ";
272
273                LidarUtilities lutil = new LidarUtilities(threadResp, header, footer,
274                                srid);
275                boolean propSet = lutil.setProperties(configFile);
276                if (!propSet) {
277                        lidarJobDB.setJobStatus(uniqueId, "query failure",
278                                        "Unable to setup database connection properties.");
279                        log += "query failure ";
280                        _logExecution(log + "\n", "errorLog");
281                        return;
282                }
283
284                StringBuffer constraint = new StringBuffer();
285                constraint = lutil.createConstraint(classification, MinX, MinY, MaxX,
286                                MaxY);
287
288                // count the number of matching ROWS - TEMPORARILY DONE HERE!!!
289                String numRows = request.getParameter("numRows");
290                long queryCount = Long.parseLong(numRows);
291                System.out.println("inside exec thread queryCount/rowNum = "
292                                + queryCount);
293                Vector tableNames = new Vector();
294                if (queryCount == -1) {// calculate num rows only if it wasn't
295                                                                // calculated yet.
296                        queryCount = lutil.calculateNumRows(MinX, MinY, MaxX, MaxY,
297                                        classification, download);
298
299                        tableNames = lutil.tableNames;
300                        System.out.println("query returned " + queryCount + "rows.");
301                } else {
302                        tableNames = lutil.getTableNames(MinX, MinY, MaxX, MaxY);
303                }
304                timings.put("NUMROWS", String.valueOf(queryCount));
305                lidarJobDB.updateJobEntry(uniqueId, timings);
306                timings.clear();
307                log += queryCount + " ";
308                if (queryCount == -1) {
309                        lidarJobDB.setJobStatus(uniqueId, "query failure", "");
310                        log += "query failure ";
311                        _logExecution(log + "\n", "errorLog");
312                        return;
313                }
314                if (tableNames.size() == 0) {
315                        lidarJobDB.setJobStatus(uniqueId, "query failure",
316                                        "Empty query response.");
317                        log += "empty query response ";
318                        _logExecution(log + "\n", "errorLog");
319                        return;
320                }
321
322                String cStr = "";
323                if (classification != null) {
324                        if (classification.length > 0 && classification.length < 4) {// something
325                                                                                                                                                        // was
326                                                                                                                                                        // selected
327                                                                                                                                                        // but
328                                                                                                                                                        // not
329                                                                                                                                                        // all
330                                cStr = "classification = " + classification[0];
331                                for (int i = 1; i < classification.length; i++) {
332                                        // if (classification.length > 1) {
333                                        cStr += "," + classification[i];
334                                }
335                                cStr += " and ";
336                        }
337                }
338                // System.out.println("cstr = " + cStr);
339                if (queryCount == 0) {
340                        lidarJobDB.setJobStatus(uniqueId, "query failure",
341                                        "Empty query response.");
342                        threadResp.append(header);
343                        threadResp
344                                        .append("<tr><td><h2>Empty Query Response!<h2></td></tr>");
345                        threadResp.append("<tr><td>Querying for " + cStr);
346                        threadResp.append("bounding box selection: MinX = " + MinX
347                                        + ", MaxX = " + MaxX + ", ");
348                        threadResp.append("MinY = " + MinY + ", MaxY = " + MaxY
349                                        + " returned no result!</td></tr>");
350                        threadResp.append(footer);
351                        log += "empty query response ";
352                        _logExecution(log + "\n", "errorLog");
353                        return;
354                }
355
356                long PROCESSLIMIT = lutil.PROCESSLIMIT;
357                long QUERYLIMIT = lutil.QUERYLIMIT;
358                boolean hasAccess = lidarJobDB.verifyUser(user);
359                if (!hasAccess) {
360                        PROCESSLIMIT = lutil.PROCESSLIMITNOACC;
361                        QUERYLIMIT = lutil.QUERYLIMITNOACC;
362                }
363
364                if (queryCount > PROCESSLIMIT) {
365                        if (download.equals("1")) {
366                                // if exceeding the process limit and a processing algorithm was
367                                // selected then return a warning.
368                                // else return the rawdata.
369                                threadResp.append(header);
370                                threadResp
371                                                .append("<tr><td><h3>Sorry, unable to process your request.<h3></td></tr>");
372                                threadResp.append("<tr><td>Querying for " + cStr);
373                                threadResp.append("bounding box selection: MinX = " + MinX
374                                                + ", MaxX = " + MaxX + ", ");
375                                threadResp.append("MinY = " + MinY + ", MaxY = " + MaxY
376                                                + " returned more than the maximum capacity. ");
377                                threadResp
378                                                .append("Currently the process is limited to 1,600,000 points, please modify your query or ");
379                                threadResp.append("try again in the future.</td></tr>");
380                                threadResp.append(footer);
381                                lidarJobDB.setJobStatus(uniqueId, "process failure",
382                                                "Processing exceeds maximum points limit.");
383
384                                String fromAddress = "GLW Support <efrat@geon01.sdsc.edu>";
385
386                                String messageBody = "Thank you for using the GEON LiDAR Workflow running on the GEONgrid.\n\n";
387                                messageBody += "We were unable to process your request as bounding box selection: ";
388                                messageBody += "MinX = " + MinX + ", MaxX = " + MaxX + ", "
389                                                + "MinY = " + MinY + ", MaxY = " + MaxY;
390                                messageBody += "exceeds maximum processing limits. Please modify your selection and try again.\n\n";
391                                if (!hasAccess)
392                                        messageBody += "To be able to process larger amounts of data please requst access on the LiDAR main page.\n\n";
393                                messageBody += "---------------\nThe GEON project";
394                                String messageSubject = "GEON LiDAR Workflow processing error notification";
395                                String[] toAddress = { email };
396                                lutil.sendEmail(fromAddress, toAddress, null, null,
397                                                messageSubject, messageBody);
398
399                                log += "query returned more than 1600000 points ";
400                                _logExecution(log + "\n", "errorLog");
401                                return;
402                        }
403                }
404
405                if (queryCount > QUERYLIMIT) {
406                        // if exceeding the query limit (20,000,000 rows).
407                        threadResp.append(header);
408                        threadResp
409                                        .append("<tr><td><h3>Sorry, unable to process your request.<h3></td></tr>");
410                        threadResp.append("<tr><td>Querying for " + cStr);
411                        threadResp.append("bounding box selection: MinX = " + MinX
412                                        + ", MaxX = " + MaxX + ", ");
413                        threadResp.append("MinY = " + MinY + ", MaxY = " + MaxY
414                                        + " returned more than the maximum capacity. ");
415                        threadResp
416                                        .append("and is unsupported. Please modify your bounding box selection and/or attributes ");
417                        threadResp.append("and try again.</td></tr>");
418                        threadResp.append(footer);
419                        lidarJobDB.setJobStatus(uniqueId, "query failure",
420                                        "Query exceeds maximum points limits.");
421
422                        String fromAddress = "GLW Support <efrat@geon01.sdsc.edu>";
423
424                        String messageBody = "Thank you for using the GEON LiDAR Workflow running on the GEONgrid.\n\n";
425                        messageBody += "We were unable to process your request as bounding box selection: ";
426                        messageBody += "MinX = " + MinX + ", MaxX = " + MaxX + ", "
427                                        + "MinY = " + MinY + ", MaxY = " + MaxY;
428                        messageBody += "exceeds maximum download quota and cannot be processed. Please modify your selection and try again.\n\n";
429                        if (!hasAccess)
430                                messageBody += "To be able to download more data please requst access on the LiDAR main page.\n\n";
431                        messageBody += "---------------\nThe GEON project";
432
433                        String messageSubject = "GEON LiDAR Workflow processing error notification";
434                        String[] toAddress = { email };
435                        lutil.sendEmail(fromAddress, toAddress, null, null, messageSubject,
436                                        messageBody);
437
438                        log += "query returned more than 20000000 points ";
439                        _logExecution(log + "\n", "errorLog");
440                        return;
441                }
442
443                log += logAlgs;
444                // call query template
445
446                int i;
447                String tableNamesStr = "{";
448                for (i = 0; i < tableNames.size() - 1; i++) {
449                        tableNamesStr += "\"" + (String) tableNames.get(i) + "\"" + ",";
450                }
451                tableNamesStr += "\"" + tableNames.get(i) + "\"" + "}";
452                System.out.println("tableNamesStr ==> " + tableNamesStr);
453
454                String columnNames = request.getParameter("columnNames");
455                System.out.println("columnNames = " + columnNames);
456                String columnExpression = request.getParameter("columnExpression");
457                System.out.println("columnExpression = " + columnExpression);
458
459                Map queryInputs = new TreeMap();
460                queryInputs.put("uniqueId", uniqueId);
461                queryInputs.put("appPath", appPath); // NO LONGER NECESSARY??
462                queryInputs.put("tableNames", tableNamesStr);
463                queryInputs.put("constraint", constraint.toString());
464                queryInputs.put("columnExpression", columnExpression);
465                queryInputs.put("columnNames", columnNames);
466
467                String qtemplate = appPath + "data/queryAcrossTemplate.xml";
468                File qtemplateFile = new File(qtemplate);
469                // System.out.println("original query template ==> " + qtemplate);
470
471                // copy the template.
472                String queryTemplate = appPath + "data/tmp/queryAcrossTemplate"
473                                + uniqueId + ".xml";
474                File qwftemplateFile = new File(queryTemplate);
475                queryTemplate = "file:///" + queryTemplate;
476                // System.out.println("unique id query template ==> " + queryTemplate);
477
478                try {
479                        InputStream is = new FileInputStream(qtemplateFile);
480                        OutputStream os = new FileOutputStream(qwftemplateFile);
481
482                        // Transfer bytes from in to out
483                        byte[] buf = new byte[1024];
484                        int len;
485                        while ((len = is.read(buf)) > 0) {
486                                os.write(buf, 0, len);
487                        }
488                        is.close();
489                        os.close();
490
491                } catch (Exception ex) {
492                        lidarJobDB.setJobStatus(uniqueId, "query failure", ex.getMessage());
493                        System.out.println("unable to create query template for "
494                                        + uniqueId + ex.getMessage());
495
496                        threadResp.append(header);
497                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
498                        threadResp.append("<tr><td>Unable to create query template for "
499                                        + uniqueId + ":\n" + ex.getMessage());
500                        threadResp.append("</td></tr>");
501                        threadResp.append(footer);
502                        log += "unable to query the lidar db ";
503                        _logExecution(log + "\n", "errorLog");
504                        return;
505                }
506
507                // System.out.println("query template url ==> " + queryTemplate);
508                System.out.println("BEFORE executing query!!");
509
510                lidarJobDB.setJobStatus(uniqueId, "querying", ""); // set the job status
511                                                                                                                        // in the monitoring
512                                                                                                                        // DB.
513
514                LidarWorkflowExecute lwfe = new LidarWorkflowExecute();
515                String res = "";
516                try {
517                        long begin = new Date().getTime();
518                        res = lwfe.executeQuery(queryTemplate, queryInputs);
519                        long end = new Date().getTime();
520                        long queryTime = end - begin;
521                        String queryTimeSec = queryTime / 1000 + "";
522                        timings.put("QUERYTIME", queryTimeSec);
523                        log += queryTimeSec + " ";
524                        System.out.println("query response url ==> " + res
525                                        + "\n queryTime = " + queryTimeSec);
526                        if (res.equals(""))
527                                throw new Exception("res is empty");
528                } catch (Exception ex) {
529                        lidarJobDB.setJobStatus(uniqueId, "query failure",
530                                        "Unable to query LiDAR database.");
531                        ex.printStackTrace();
532                        threadResp.append(header);
533                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
534                        threadResp.append("<tr><td>Unable to query the LiDAR database.");
535                        threadResp.append("</td></tr>");
536                        threadResp.append(footer);
537                        log += "unable to query the lidar db ";
538                        _logExecution(log + "\n", "errorLog");
539                        return;
540                        // ADD EXCEPTION NOTIFICATION TO USER AND STOP EXECUTION!!!!
541                }
542
543                // /TODO! this test is no longer necessary
544                if (res.equals("0")) {
545                        lidarJobDB.setJobStatus(uniqueId, "query failure",
546                                        "No available data for user selection.");
547                        threadResp.append(header);
548                        threadResp
549                                        .append("<tr><td><h2>Empty Query Response!<h2></td></tr>");
550                        threadResp.append("<tr><td>Querying for " + cStr);
551                        threadResp.append("bounding box selection: MinX = " + MinX
552                                        + ", MaxX = " + MaxX + ", ");
553                        threadResp.append("MinY = " + MinY + ", MaxY = " + MaxY
554                                        + " returned no result!</td></tr>");
555                        threadResp.append(footer);
556                        log += "empty query response ";
557                        _logExecution(log + "\n", "errorLog");
558                        return;
559                }
560                inputs.put("rawdataURL", res);
561
562                // remove query file - TODO!
563
564                inputs.put("appPath", appPath);
565                inputs.put("host", host);
566                inputs.put("port", port);
567                inputs.put("download", download);
568                // inputs.put("xmlParams",xmlParams.toString());
569
570                // if only download raw data was selected
571                if (download.equals("0")) {
572                        // The user is only interested in raw data.
573                        lidarJobDB.setJobStatus(uniqueId, "done", "");
574                        timings.put("COMPLETIONDATE", new Date().toString());
575                        lidarJobDB.updateJobEntry(uniqueId, timings);
576                        StringBuffer queryResp = new StringBuffer();
577                        queryResp.append("Raw data for " + cStr);
578                        queryResp.append("bounding box selection: MinX = " + MinX
579                                        + ", MaxX = " + MaxX + ", ");
580                        queryResp.append("MinY = " + MinY + ", MaxY = " + MaxY
581                                        + " is available at ");
582
583                        threadResp.append(header);
584                        threadResp.append("<tr><td>");
585                        threadResp.append(queryResp.toString());
586                        threadResp.append("<A href=\"" + res + "\">queryResult</A> ("
587                                        + queryCount + " points).</td></tr>");
588                        threadResp.append(footer);
589                        threadResp.append("<br><table><tr><td>Download ");
590                        threadResp
591                                        .append("<A href=\"http://activetectonics.la.asu.edu/GEONatASU/LViz.html\">");
592                        threadResp.append("LViz</A>");
593                        threadResp
594                                        .append(" - A free application for visualization of LiDAR point cloud and interpolated surface ");
595                        threadResp
596                                        .append("data developed in the Active Tectonics Research Group at Arizona State University.");
597                        threadResp.append("</td></tr></table>");
598
599                        // Email results.
600                        if (email != null && !email.equals("")) {
601                                emailQueryResp(queryResp.toString(), res, email, queryCount);
602                        }
603                        _logExecution(log + "\n", "rawDataLog");
604                        return;
605                }
606                // else..
607                inputs.put("queryCount", String.valueOf(queryCount));
608                if (rawdata.equals("1")) {
609                        // send bounding box for printout.
610                        inputs.put("MinX", MinX);
611                        inputs.put("MinY", MinY);
612                        inputs.put("MaxX", MaxX);
613                        inputs.put("MaxY", MaxY);
614                        inputs.put("classification", cStr);
615                }
616
617                // Create parameters file from string buffer.
618                try {
619                        String filePath = appPath + "data/tmp/params" + uniqueId + ".txt";
620                        File paramsFile = new File(filePath);
621                        String paramsFileURL = paramsFile.getAbsolutePath();
622                        System.out.println("Writing to parameter file " + paramsFileURL);
623                        BufferedWriter bw = new BufferedWriter(new FileWriter(
624                                        paramsFileURL, false));
625
626                        bw.write(sb.toString());
627                        bw.close();
628
629                } catch (Exception ex) {
630                        lidarJobDB.setJobStatus(uniqueId, "process failure", ex
631                                        .getMessage());
632                        System.out.println("unable to create params file " + uniqueId
633                                        + ": " + ex.getMessage());
634                        threadResp.append(header);
635                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
636                        threadResp.append("<tr><td>Unable to create params file "
637                                        + uniqueId + ": " + ex.getMessage());
638                        threadResp.append("</td></tr>");
639                        threadResp.append(footer);
640                        log += "unable to process user selections ";
641                        _logExecution(log + "\n", "errorLog");
642                        return;
643                }
644
645                // String template = "file:///" + appPath + "data/processTemplate.xml";
646                // String template = appPath + "data/processTemplate.xml";
647                String template = appPath + "data/processTemplateWS.xml";
648                System.out.println("process template ==> " + template);
649                File templateFile = new File(template);
650
651                // copy the template.
652                // String workflowTemplate = "file:///" + appPath +
653                // "data/processTemplate" + uniqueId + ".xml";
654                String workflowTemplate = appPath + "data/tmp/processTemplate"
655                                + uniqueId + ".xml";
656                File wftemplateFile = new File(workflowTemplate);
657                workflowTemplate = "file:///" + workflowTemplate;
658
659                try {
660                        InputStream is = new FileInputStream(templateFile);
661                        OutputStream os = new FileOutputStream(wftemplateFile);
662
663                        // Transfer bytes from in to out
664                        byte[] buf = new byte[1024];
665                        int len;
666                        while ((len = is.read(buf)) > 0) {
667                                os.write(buf, 0, len);
668                        }
669                        is.close();
670                        os.close();
671
672                } catch (Exception ex) {
673                        lidarJobDB.setJobStatus(uniqueId, "process failure", ex
674                                        .getMessage());
675                        System.out.println("unable to create process template for "
676                                        + uniqueId + ex.getMessage());
677
678                        threadResp.append(header);
679                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
680                        threadResp.append("<tr><td>Unable to create process template for "
681                                        + uniqueId + ":\n" + ex.getMessage());
682                        threadResp.append("</td></tr>");
683                        threadResp.append(footer);
684                        log += "unable to process user selections ";
685                        _logExecution(log + "\n", "errorLog");
686                        return;
687                }
688
689                System.out.println("workflow url ==> " + workflowTemplate);
690                System.out.println("BEFORE!!");
691                lidarJobDB.setJobStatus(uniqueId, "processing", ""); // set the job
692                                                                                                                                // status in the
693                                                                                                                                // monitoring
694                                                                                                                                // DB.
695                // LidarWorkflowExecute lwfe = new LidarWorkflowExecute();
696                try {
697                        long begin = new Date().getTime();
698                        res = lwfe.executeProcess(workflowTemplate, inputs);
699                        long end = new Date().getTime();
700                        long processTime = end - begin;
701                        String processTimeSec = processTime / 1000 + "";
702                        timings.put("PROCESSTIME", processTimeSec);
703                        log += processTimeSec + " ";
704                        System.out.println("process result url ==> " + res
705                                        + "\n processTime = " + processTimeSec);
706                        // response.sendRedirect(res);
707                        System.out.println("RES = " + res);
708                        if (res.equals("0")) {
709                                lidarJobDB.setJobStatus(uniqueId, "process failure",
710                                                "GRASS processing error");
711                                threadResp.append(header);
712                                threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
713                                threadResp
714                                                .append("<tr><td>GRASS processing error for bounding box selection: ");
715                                threadResp.append("MinX = " + MinX + ", MaxX = " + MaxX
716                                                + ", MinY = " + MinY + ", MaxY = " + MaxY);
717                                threadResp
718                                                .append(". Please modify selection area and try again.");
719                                threadResp.append("</td></tr>");
720                                threadResp.append(footer);
721                                log += "GRASS processing error ";
722                                _logExecution(log + "\n", "errorLog");
723
724                                String fromAddress = "GLW Support <efrat@geon01.sdsc.edu>";
725
726                                String messageBody = "Thank you for using the GEON LiDAR Workflow running on the GEONgrid.\n\n";
727                                messageBody += "We were unable to process your request for bounding box selection: ";
728                                messageBody += "MinX = " + MinX + ", MaxX = " + MaxX + ", "
729                                                + "MinY = " + MinY + ", MaxY = " + MaxY;
730                                messageBody += "due to a GRASS processing error. Please modify your selection and try again.\n\n";
731                                messageBody += "---------------\nThe GEON project";
732                                String messageSubject = "GEON LiDAR Workflow processing error notification";
733                                String[] toAddress = { email };
734                                lutil.sendEmail(fromAddress, toAddress, null, null,
735                                                messageSubject, messageBody);
736
737                                return;
738
739                        }
740                        URL url = new URL(res);
741                        Reader in = new InputStreamReader(url.openStream());
742                        BufferedReader br = new BufferedReader(in);
743                        String line;
744
745                        while ((line = br.readLine()) != null) {
746                                threadResp.append(line + "\n");
747                        }
748
749                } catch (Exception ex) {
750                        lidarJobDB.setJobStatus(uniqueId, "process failure", ex
751                                        .getMessage());
752                        ex.printStackTrace();
753                        threadResp.append(header);
754                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
755                        threadResp.append("<tr><td>Workflow exception please try again.");
756                        threadResp.append("</td></tr>");
757                        threadResp.append("<tr><td>" + ex.getMessage() + ".");
758                        threadResp.append("</td></tr>");
759                        threadResp.append(footer);
760                        log += "workflow execution error ";
761                        _logExecution(log + "\n", "errorLog");
762                        return;
763                }
764                String completeDate = new Date().toString();
765                log += completeDate;
766                lidarJobDB.setJobStatus(uniqueId, "done", "");
767                timings.put("COMPLETIONDATE", completeDate);
768                lidarJobDB.updateJobEntry(uniqueId, timings);
769                _logExecution(log + "\n", "lidarLog");
770        }
771
772        public void getProcessResponse(String configFile) {
773
774                LidarJobDB lidarJobDB = new LidarJobDB(configFile);
775                LidarJobConfig jobConfig = lidarJobDB.getJobConfig(uniqueId);
776
777                Map inputs = new TreeMap();
778                inputs.put("id", uniqueId);
779                inputs.put("rawdata", "0");
780                inputs.put("download", "1");
781                inputs.put("appPath", appPath);
782                inputs.put("host", host);
783                inputs.put("port", port);
784
785                String[] processings = jobConfig.getProcessings();
786                for (int i = 0; i < processings.length; i++) {
787                        inputs.put(processings[i], "1");
788                }
789
790                String template = appPath + "data/gmTemplate.xml";
791                System.out.println("global mapper template ==> " + template);
792                File templateFile = new File(template);
793
794                // copy the template.
795                String workflowTemplate = appPath + "data/tmp/gmTemplate" + uniqueId
796                                + ".xml";
797                File wftemplateFile = new File(workflowTemplate);
798                workflowTemplate = "file:///" + workflowTemplate;
799
800                try {
801                        InputStream is = new FileInputStream(templateFile);
802                        OutputStream os = new FileOutputStream(wftemplateFile);
803
804                        // Transfer bytes from in to out
805                        byte[] buf = new byte[1024];
806                        int len;
807                        while ((len = is.read(buf)) > 0) {
808                                os.write(buf, 0, len);
809                        }
810                        is.close();
811                        os.close();
812
813                        System.out.println("workflow url ==> " + workflowTemplate);
814                        System.out.println("BEFORE!!");
815
816                        LidarWorkflowExecute lwfe = new LidarWorkflowExecute();
817                        String res = lwfe.executeProcess(workflowTemplate, inputs);
818
819                        URL url = new URL(res);
820                        Reader in = new InputStreamReader(url.openStream());
821                        BufferedReader br = new BufferedReader(in);
822                        String line;
823
824                        while ((line = br.readLine()) != null) {
825                                threadResp.append(line + "\n");
826                        }
827
828                } catch (Exception ex) {
829                        ex.printStackTrace();
830                        threadResp.append(header);
831                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
832                        threadResp.append("<tr><td>Unable to obtain process response:\n"
833                                        + ex.getMessage());
834                        threadResp.append("</td></tr>");
835                        threadResp.append("<tr><td>" + ex.getMessage() + ".");
836                        threadResp.append("</td></tr>");
837                        threadResp.append(footer);
838                        return;
839                }
840        }
841
842        public void getQueryResponse(String configFile) {
843
844                LidarJobDB lidarJobDB = new LidarJobDB(configFile);
845                LidarJobConfig jobConfig = lidarJobDB.getJobConfig(uniqueId);
846
847                String MinX = jobConfig.getXmin();
848                String MaxX = jobConfig.getXmax();
849                String MinY = jobConfig.getYmin();
850                String MaxY = jobConfig.getYmax();
851                String[] classification = jobConfig.getClassifications();
852                String srid = jobConfig.getSrid();
853                String queryCount = jobConfig.getNumRows();
854
855                try {
856                        LidarUtilities lutil = new LidarUtilities(threadResp, header,
857                                        footer, srid);
858                        boolean propSet = lutil.setProperties(configFile);
859                        if (!propSet) {
860                                throw new Exception(
861                                                "unable to setup database connection properties");
862                        }
863
864                        StringBuffer constraint = new StringBuffer();
865                        constraint = lutil.createConstraint(classification, MinX, MinY,
866                                        MaxX, MaxY);
867
868                        Vector tableNames = new Vector();
869                        tableNames = lutil.getTableNames(MinX, MinY, MaxX, MaxY);
870
871                        String cStr = "";
872                        if (classification != null) {
873                                if (classification.length > 0 && classification.length < 4) {// something
874                                                                                                                                                                // was
875                                                                                                                                                                // selected
876                                                                                                                                                                // but
877                                                                                                                                                                // not
878                                                                                                                                                                // all
879                                        cStr = "classification = " + classification[0];
880                                        for (int i = 1; i < classification.length; i++) {
881                                                // if (classification.length > 1) {
882                                                cStr += "," + classification[i];
883                                        }
884                                        cStr += " and ";
885                                }
886                        }
887
888                        int i;
889                        String tableNamesStr = "{";
890                        for (i = 0; i < tableNames.size() - 1; i++) {
891                                tableNamesStr += "\"" + (String) tableNames.get(i) + "\"" + ",";
892                        }
893                        tableNamesStr += "\"" + tableNames.get(i) + "\"" + "}";
894
895                        Map queryInputs = new TreeMap();
896                        queryInputs.put("uniqueId", uniqueId); // check that
897                        queryInputs.put("appPath", appPath); // check that
898                        queryInputs.put("tableNames", tableNamesStr);
899                        queryInputs.put("constraint", constraint.toString());
900
901                        String queryTemplate = appPath + "data/tmp/queryAcrossTemplate"
902                                        + uniqueId + ".xml"; // replace jobId with generated id
903                        File qwftemplateFile = new File(queryTemplate);
904                        queryTemplate = "file:///" + queryTemplate;
905
906                        String qtemplate = appPath + "data/queryAcrossTemplate.xml";
907                        File qtemplateFile = new File(qtemplate);
908
909                        InputStream is = new FileInputStream(qtemplateFile);
910                        OutputStream os = new FileOutputStream(qwftemplateFile);
911
912                        // Transfer bytes from in to out
913                        byte[] buf = new byte[1024];
914                        int len;
915                        while ((len = is.read(buf)) > 0) {
916                                os.write(buf, 0, len);
917                        }
918                        is.close();
919                        os.close();
920
921                        LidarWorkflowExecute lwfe = new LidarWorkflowExecute();
922                        String res = "";
923                        res = lwfe.executeQuery(queryTemplate, queryInputs);
924
925                        StringBuffer queryResp = new StringBuffer();
926                        queryResp.append("Raw data for " + cStr);
927                        queryResp.append("bounding box selection: MinX = " + MinX
928                                        + ", MaxX = " + MaxX + ", ");
929                        queryResp.append("MinY = " + MinY + ", MaxY = " + MaxY
930                                        + " is available at ");
931
932                        threadResp.append("<table><tr><td>");
933                        threadResp.append(queryResp.toString());
934                        threadResp.append("<A href=\"" + res + "\">queryResult</A>");
935                        if (queryCount != null) {
936                                if (!queryCount.equals("-1")) {
937                                        threadResp.append(" (" + queryCount + " points).");
938                                }
939                        }
940                        threadResp.append(".</td></tr></table>");
941                        threadResp.append("<br><table><tr><td>Download ");
942                        threadResp
943                                        .append("<A href=\"http://activetectonics.la.asu.edu/GEONatASU/LViz.html\">");
944                        threadResp.append("LViz</A>");
945                        threadResp
946                                        .append(" - A free application for visualization of LiDAR point cloud and interpolated surface ");
947                        threadResp
948                                        .append("data developed in the Active Tectonics Research Group at Arizona State University.");
949                        threadResp.append("</td></tr></table>");
950
951                } catch (Exception ex) {
952                        ex.printStackTrace();
953                        threadResp.append(header);
954                        threadResp.append("<tr><td><h2>Error!<h2></td></tr>");
955                        threadResp.append("<tr><td>Unable to obtain query response:\n"
956                                        + ex.getMessage());
957                        threadResp.append("</td></tr>");
958                        threadResp.append(footer);
959                        return;
960                }
961        }
962
963        private void emailQueryResp(String queryResp, String URL, String email,
964                        long queryCount) {
965                String messageBody = "Thank you for using the GEON LiDAR Workflow running on the GEONgrid.\n\n";
966                messageBody += queryResp + URL + " (" + queryCount + " points).\n\n";
967                messageBody += "Please note that the results will expire after 48 hours.\n\n";
968                messageBody += "---------------\nThe GEON project";
969
970                String messageSubject = "GEON LiDAR Workflow processing results";
971
972                String host = "localhost";
973                String fromAddress = "GEON LiDAR Workflow Processing Notification <efrat@geon01.sdsc.edu>";
974
975                Properties props = new Properties();
976                props.put("mail.smtp.host", host);
977                props.put("mail.debug", "false");
978
979                Session session = Session.getInstance(props);
980
981                try {
982                        Message msg = new MimeMessage(session);
983                        msg.setFrom(new InternetAddress(fromAddress));
984                        InternetAddress[] address = { new InternetAddress(email) };
985                        msg.setRecipients(Message.RecipientType.TO, address);
986                        msg.setSubject(messageSubject);
987                        msg.setSentDate(new java.util.Date());
988                        msg.setText(messageBody);
989
990                        Transport.send(msg);
991                } catch (MessagingException mex) {
992                        mex.printStackTrace();
993                }
994        }
995
996        public void _logExecution(String log, String fileName) {
997                String logURL = System.getProperty("user.home") + File.separator
998                                + ".lidar" + File.separator + fileName;
999                try {
1000                        File logFile = new File(logURL);
1001                        FileWriter fw = new FileWriter(logFile, true);
1002
1003                        RandomAccessFile raf = new RandomAccessFile(logFile, "r");
1004                        if (raf.length() == 0) {// write header
1005                                logFile.createNewFile();
1006                                fw
1007                                                .write("id ip email dataset minX maxX minY maxY classification munberOfPoints "
1008                                                                + "spline slope aspect pcurv res dmin tension smooth queryTime processTime\n");
1009                        }
1010                        fw.write(log);
1011                        fw.flush();
1012                        fw.close();
1013                } catch (IOException ioex) {
1014                        System.out.println("Unable to write " + log + " to " + logURL
1015                                        + ".\n" + ioex.getMessage());
1016                }
1017        }
1018}