Java tutorial
/* ************************************************************************ ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* ************** CENTRE CANADIEN DE DONNES ASTRONOMIQUES ************** * * (c) 2009. (c) 2009. * Government of Canada Gouvernement du Canada * National Research Council Conseil national de recherches * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 * All rights reserved Tous droits rservs * * NRC disclaims any warranties, Le CNRC dnie toute garantie * expressed, implied, or nonce, implicite ou lgale, * statutory, of any kind with de quelque nature que ce * respect to the software, soit, concernant le logiciel, * including without limitation y compris sans restriction * any warranty of merchantability toute garantie de valeur * or fitness for a particular marchande ou de pertinence * purpose. NRC shall not be pour un usage particulier. * liable in any event for any Le CNRC ne pourra en aucun cas * damages, whether direct or tre tenu responsable de tout * indirect, special or general, dommage, direct ou indirect, * consequential or incidental, particulier ou gnral, * arising from the use of the accessoire ou fortuit, rsultant * software. Neither the name de l'utilisation du logiciel. Ni * of the National Research le nom du Conseil National de * Council of Canada nor the Recherches du Canada ni les noms * names of its contributors may de ses participants ne peuvent * be used to endorse or promote tre utiliss pour approuver ou * products derived from this promouvoir les produits drivs * software without specific prior de ce logiciel sans autorisation * written permission. pralable et particulire * par crit. * * This file is part of the Ce fichier fait partie du projet * OpenCADC project. OpenCADC. * * OpenCADC is free software: OpenCADC est un logiciel libre ; * you can redistribute it and/or vous pouvez le redistribuer ou le * modify it under the terms of modifier suivant les termes de * the GNU Affero General Public la GNU Affero General Public * License as published by the License? telle que publie * Free Software Foundation, par la Free Software Foundation * either version 3 of the : soit la version 3 de cette * License, or (at your option) licence, soit ( votre gr) * any later version. toute version ultrieure. * * OpenCADC is distributed in the OpenCADC est distribu * hope that it will be useful, dans lespoir quil vous * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE * without even the implied GARANTIE : sans mme la garantie * warranty of MERCHANTABILITY implicite de COMMERCIALISABILIT * or FITNESS FOR A PARTICULAR ni dADQUATION UN OBJECTIF * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence * General Public License for Gnrale Publique GNU Affero * more details. pour plus de dtails. * * You should have received Vous devriez avoir reu une * a copy of the GNU Affero copie de la Licence Gnrale * General Public License along Publique GNU Affero avec * with OpenCADC. If not, see OpenCADC ; si ce nest * <http://www.gnu.org/licenses/>. pas le cas, consultez : * <http://www.gnu.org/licenses/>. * * $Revision: 4 $ * ************************************************************************ */ package ca.nrc.cadc.uws.sample; import ca.nrc.cadc.net.NetUtil; import ca.nrc.cadc.uws.ErrorSummary; import ca.nrc.cadc.uws.ErrorType; import ca.nrc.cadc.uws.ExecutionPhase; import ca.nrc.cadc.uws.Job; import ca.nrc.cadc.uws.JobInfo; import ca.nrc.cadc.uws.ParameterUtil; import ca.nrc.cadc.uws.Result; import ca.nrc.cadc.uws.server.JobRunner; import ca.nrc.cadc.uws.server.JobUpdater; import ca.nrc.cadc.uws.server.SyncOutput; import ca.nrc.cadc.xml.XmlUtil; import java.io.IOException; import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.jdom2.Document; import org.jdom2.Element; /** * Basic Job Runner class. The sample job takes two params: * <ul> * <li>RUNFOR=[number of seconds to run] to control how long it runs * <li>PASS=[true|false] to control whether it succeeds or fails * <li>SYNC=[true|false] to control whether * </ul> */ public class HelloWorld implements JobRunner { private static final Logger log = Logger.getLogger(HelloWorld.class); public static long MIN_RUNFOR = 500L; // milliseconds public static long MAX_RUNFOR = 10000L; // milliseconds public static String PASS = "PASS"; public static String RUNFOR = "RUNFOR"; public static String STREAM = "STREAM"; public static String RESULT = "HelloWorld -- OK"; public static String ERROR = "HelloWorld -- FAIL"; private Job job; private JobUpdater jobUpdater; private SyncOutput syncOutput; public HelloWorld() { } public void setJob(Job job) { this.job = job; } public void setJobUpdater(JobUpdater ju) { this.jobUpdater = ju; } public void setSyncOutput(SyncOutput so) { this.syncOutput = so; } private ErrorSummary generateError() { try { URL url = new URL("http://" + NetUtil.getServerName(HelloWorld.class) + "/cadcSampleUWS/error.txt"); return new ErrorSummary("job failed to say hello", ErrorType.FATAL, url); } catch (MalformedURLException ex) { throw new RuntimeException("BUG: failed to create error URL", ex); } } private List<Result> generateResults() { try { URI uri = new URI("http://" + NetUtil.getServerName(HelloWorld.class) + "/cadcSampleUWS/result.txt"); List<Result> ret = new ArrayList<Result>(); ret.add(new Result("result", uri)); return ret; } catch (URISyntaxException ex) { throw new RuntimeException("BUG: failed to create result URI", ex); } } public void run() { log.debug("run: " + job.getID()); try { ExecutionPhase ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.QUEUED, ExecutionPhase.EXECUTING, new Date()); if (!ExecutionPhase.EXECUTING.equals(ep)) { ep = jobUpdater.getPhase(job.getID()); log.debug(job.getID() + ": QUEUED -> EXECUTING [FAILED] -- DONE"); return; } log.info(job.getID() + ": QUEUED -> EXECUTING [OK]"); String passValue = null; String streamValue = null; String runforValue = null; boolean pass = false; boolean stream = false; long runfor = 1; // JobInfo input (XML) if (job.getJobInfo() != null) { // TODO: content type/error handling here JobInfo ji = job.getJobInfo(); if (ji.getValid() != null && ji.getValid()) { Document document = XmlUtil.buildDocument(ji.getContent()); Element root = document.getRootElement(); passValue = root.getChildText("pass"); streamValue = root.getChildText("stream"); runforValue = root.getChildText("runfor"); } } else // parameter list input { passValue = ParameterUtil.findParameterValue(PASS, job.getParameterList()); streamValue = ParameterUtil.findParameterValue(STREAM, job.getParameterList()); runforValue = ParameterUtil.findParameterValue(RUNFOR, job.getParameterList()); } if (passValue != null) try { pass = Boolean.parseBoolean(passValue); } catch (Exception ignore) { log.debug("invalid boolean value: " + PASS + "=" + passValue); } if (streamValue != null) try { stream = Boolean.parseBoolean(streamValue); } catch (Exception ignore) { log.debug("invalid boolean value: " + STREAM + "=" + streamValue); } if (runforValue != null) try { runfor = Long.parseLong(runforValue); } catch (Exception ignore) { log.debug("invalid long value: " + RUNFOR + "=" + runforValue); } // sanity check runfor *= 1000L; // convert to milliseconds if (runfor < MIN_RUNFOR) runfor = MIN_RUNFOR; else if (runfor > MAX_RUNFOR) runfor = MAX_RUNFOR; log.debug("pass: " + pass + ", stream: " + stream + ", duration: " + runfor); Thread.sleep(runfor); ExecutionPhase expected = null; ep = null; if (pass) { expected = ExecutionPhase.COMPLETED; List<Result> results = generateResults(); if (syncOutput != null) { if (stream) { syncOutput.setHeader("Content-Type", "text/plain"); PrintWriter w = new PrintWriter(syncOutput.getOutputStream()); w.println(RESULT); w.close(); ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.COMPLETED, new Date()); } else { syncOutput.setResponseCode(303); syncOutput.setHeader("Location", results.get(0).getURI().toASCIIString()); ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.COMPLETED, new Date()); } } else // async { ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.COMPLETED, results, new Date()); } } else { expected = ExecutionPhase.ERROR; ErrorSummary error = generateError(); if (syncOutput != null) { if (stream) { syncOutput.setHeader("Content-Type", "text/plain"); PrintWriter w = new PrintWriter(syncOutput.getOutputStream()); w.println(ERROR); w.close(); ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.COMPLETED, new Date()); } else { syncOutput.setResponseCode(303); syncOutput.setHeader("Location", error.getDocumentURL().toExternalForm()); ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.ERROR, error, new Date()); } } else // async { ep = jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.ERROR, error, new Date()); } } if (expected.equals(ep)) log.info(job.getID() + ": EXECUTING -> " + expected.name() + " [OK]"); else log.info(job.getID() + ": EXECUTING -> " + expected.name() + " [FAILED]"); } //catch(JobNotFoundException ex) { } // either a bug or someone deleted the job after executing it //catch(JobPersistenceException ex) { } // back end persistence is failing catch (Throwable t) { log.error("unexpected failure", t); ErrorSummary error = new ErrorSummary(t.toString(), ErrorType.FATAL); if (syncOutput != null) { try { PrintWriter pw = new PrintWriter(syncOutput.getOutputStream()); pw.println(t.getMessage()); pw.close(); } catch (IOException ex) { log.error("failed to write unexpected failure message to output", ex); } } try { jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, ExecutionPhase.ERROR, error, new Date()); } catch (Exception ex) { log.error("failed to set unexpected error state: " + ex); } } } }