ca.nrc.cadc.uws.JobReader.java Source code

Java tutorial

Introduction

Here is the source code for ca.nrc.cadc.uws.JobReader.java

Source

/*
************************************************************************
*******************  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;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.log4j.Logger;
import org.jdom2.Attribute;
import org.jdom2.DataConversionException;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.XMLOutputter;

import ca.nrc.cadc.date.DateUtil;
import ca.nrc.cadc.xml.XmlUtil;

/**
 * Constructs a Job from an XML source. This class is not thread safe but it is
 * re-usable  so it can safely be used to sequentially parse multiple XML transfer
 * documents.
 */
public class JobReader {
    @SuppressWarnings("unused")
    private static Logger log = Logger.getLogger(JobReader.class);

    private static final String UWS_SCHEMA_URL = "http://www.ivoa.net/xml/UWS/v1.0";
    private static final String UWS_SCHEMA_RESOURCE = "UWS-v1.0.xsd";
    private static final String XLINK_SCHEMA_URL = "http://www.w3.org/1999/xlink";
    private static final String XLINK_SCHEMA_RESOURCE = "XLINK.xsd";

    private static final String uwsSchemaUrl;
    private static final String xlinkSchemaUrl;
    static {
        uwsSchemaUrl = XmlUtil.getResourceUrlString(UWS_SCHEMA_RESOURCE, JobReader.class);
        log.debug("uwsSchemaUrl: " + uwsSchemaUrl);

        xlinkSchemaUrl = XmlUtil.getResourceUrlString(XLINK_SCHEMA_RESOURCE, JobReader.class);
        log.debug("xlinkSchemaUrl: " + xlinkSchemaUrl);
    }

    private Map<String, String> schemaMap;
    private DateFormat dateFormat;
    private SAXBuilder docBuilder;

    /**
     * Constructor. XML Schema validation is enabled by default.
     */
    public JobReader() {
        this(true);
    }

    /**
     * Constructor. XML schema validation may be disabled, in which case the client
     * is likely to fail in horrible ways (e.g. NullPointerException) if it receives
     * invalid documents. However, performance may be improved.
     *
     * @param enableSchemaValidation
     */
    public JobReader(boolean enableSchemaValidation) {
        if (enableSchemaValidation) {
            schemaMap = new HashMap<String, String>();
            schemaMap.put(UWS_SCHEMA_URL, uwsSchemaUrl);
            schemaMap.put(XLINK_SCHEMA_URL, xlinkSchemaUrl);
            log.debug("schema validation enabled");
        } else {
            log.debug("schema validation disabled");
        }

        this.docBuilder = XmlUtil.createBuilder(schemaMap);
        this.dateFormat = DateUtil.getDateFormat(DateUtil.IVOA_DATE_FORMAT, DateUtil.UTC);
    }

    /**
     * Alternative constructor to pass in additional schemas used to valid the
     * documents being read.
     *
     * Passing in an empty Map enables schema validation with no additional schemas
     * other than the default UWS and XLink schemas.
     *
     * @param schemas Map of schema namespace to resource.
     */
    public JobReader(Map<String, String> schemas) {
        if (schemas == null) {
            throw new IllegalArgumentException("Map of schema namespace to resource cannot be null");
        }
        schemaMap = new HashMap<String, String>();
        schemaMap.put(UWS_SCHEMA_URL, uwsSchemaUrl);
        schemaMap.put(XLINK_SCHEMA_URL, xlinkSchemaUrl);
        if (!schemas.isEmpty()) {
            Set<Entry<String, String>> entries = schemas.entrySet();
            for (Entry<String, String> entry : entries) {
                schemaMap.put(entry.getKey(), entry.getValue());
                log.debug("added to SchemaMap: " + entry.getKey() + " = " + entry.getValue());
            }
        }
        log.debug("schema validation enabled");

        this.docBuilder = XmlUtil.createBuilder(schemaMap);
        this.dateFormat = DateUtil.getDateFormat(DateUtil.IVOA_DATE_FORMAT, DateUtil.UTC);
    }

    public Job read(InputStream in) throws JDOMException, IOException, ParseException {
        try {
            return read(new InputStreamReader(in, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF-8 encoding not supported");
        }
    }

    public Job read(Reader reader) throws JDOMException, IOException, ParseException {
        Document doc = docBuilder.build(reader);
        return parseJob(doc);
    }

    private Job parseJob(Document doc) throws ParseException, DataConversionException {
        Element root = doc.getRootElement();

        String jobID = root.getChildText(JobAttribute.JOB_ID.getAttributeName(), UWS.NS);
        if (jobID != null && jobID.trim().length() == 0)
            jobID = null;
        String runID = parseStringContent(root.getChild(JobAttribute.RUN_ID.getAttributeName(), UWS.NS));
        String ownerID = parseStringContent(root.getChild(JobAttribute.OWNER_ID.getAttributeName(), UWS.NS));
        Date quote = parseDate(parseStringContent(root.getChild(JobAttribute.QUOTE.getAttributeName(), UWS.NS)));
        Date startTime = parseDate(
                parseStringContent(root.getChild(JobAttribute.START_TIME.getAttributeName(), UWS.NS)));
        Date endTime = parseDate(
                parseStringContent(root.getChild(JobAttribute.END_TIME.getAttributeName(), UWS.NS)));
        Date creationTime = parseDate(
                parseStringContent(root.getChild(JobAttribute.CREATION_TIME.getAttributeName(), UWS.NS)));
        Date destructionTime = parseDate(
                parseStringContent(root.getChild(JobAttribute.DESTRUCTION_TIME.getAttributeName(), UWS.NS)));
        Long executionDuration = new Long(
                parseStringContent(root.getChild(JobAttribute.EXECUTION_DURATION.getAttributeName(), UWS.NS)));

        ExecutionPhase executionPhase = parseExecutionPhase(doc);

        ErrorSummary errorSummary = null;
        if (executionPhase.equals(ExecutionPhase.ERROR))
            errorSummary = parseErrorSummary(doc);

        List<Result> resultsList = parseResultsList(doc);

        List<Parameter> parameterList = parseParametersList(doc);

        JobInfo jobInfo = parseJobInfo(doc);

        Job job = new Job(jobID, executionPhase, executionDuration, destructionTime, quote, startTime, endTime,
                creationTime, errorSummary, ownerID, runID, null, null, jobInfo, parameterList, resultsList);

        return job;
    }

    private Date parseDate(String strDate) throws ParseException {
        if (strDate == null)
            return null;
        strDate = strDate.trim();
        if (strDate.length() == 0)
            return null;
        return dateFormat.parse(strDate);
    }

    private String parseStringContent(Element e) throws DataConversionException {
        if (e == null)
            return null;
        Attribute nil = e.getAttribute("nil", UWS.XSI_NS);
        if (nil != null && nil.getBooleanValue())
            return null;
        return e.getTextTrim();
    }

    private ExecutionPhase parseExecutionPhase(Document doc) {
        ExecutionPhase rtn = null;
        Element root = doc.getRootElement();
        String strPhase = root.getChildText(JobAttribute.EXECUTION_PHASE.getAttributeName(), UWS.NS);
        if (strPhase.equalsIgnoreCase(ExecutionPhase.PENDING.toString()))
            rtn = ExecutionPhase.PENDING;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.QUEUED.toString()))
            rtn = ExecutionPhase.QUEUED;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.EXECUTING.toString()))
            rtn = ExecutionPhase.EXECUTING;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.COMPLETED.toString()))
            rtn = ExecutionPhase.COMPLETED;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.ERROR.toString()))
            rtn = ExecutionPhase.ERROR;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.UNKNOWN.toString()))
            rtn = ExecutionPhase.UNKNOWN;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.HELD.toString()))
            rtn = ExecutionPhase.HELD;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.SUSPENDED.toString()))
            rtn = ExecutionPhase.SUSPENDED;
        else if (strPhase.equalsIgnoreCase(ExecutionPhase.ABORTED.toString()))
            rtn = ExecutionPhase.ABORTED;

        return rtn;
    }

    private List<Parameter> parseParametersList(Document doc) {
        List<Parameter> rtn = null;
        Element root = doc.getRootElement();
        Element elementParameters = root.getChild(JobAttribute.PARAMETERS.getAttributeName(), UWS.NS);
        if (elementParameters != null) {
            rtn = new ArrayList<Parameter>();

            Parameter par = null;
            List<?> listElement = elementParameters.getChildren(JobAttribute.PARAMETER.getAttributeName(), UWS.NS);
            for (Object obj : listElement) {
                Element e = (Element) obj;
                String id = e.getAttributeValue("id");
                String value = e.getText();
                par = new Parameter(id, value);
                rtn.add(par);
            }
        }
        return rtn;
    }

    private List<Result> parseResultsList(Document doc) {
        List<Result> rtn = null;
        Element root = doc.getRootElement();
        Element e = root.getChild(JobAttribute.RESULTS.getAttributeName(), UWS.NS);
        if (e != null) {
            rtn = new ArrayList<Result>();

            Result rs = null;
            List<?> listE = e.getChildren(JobAttribute.RESULT.getAttributeName(), UWS.NS);
            for (Object obj : listE) {
                Element eRs = (Element) obj;
                String id = eRs.getAttributeValue("id");
                String href = eRs.getAttributeValue("href", UWS.XLINK_NS);
                try {
                    rs = new Result(id, new URI(href));
                    rtn.add(rs);
                } catch (URISyntaxException ex) {
                    // do nothing; just do not add rs to list
                    log.debug(ex.getMessage());
                }
            }
        }
        return rtn;
    }

    private ErrorSummary parseErrorSummary(Document doc) {
        ErrorSummary rtn = null;
        Element root = doc.getRootElement();
        Element e = root.getChild(JobAttribute.ERROR_SUMMARY.getAttributeName(), UWS.NS);
        if (e != null) {
            ErrorType errorType = null;
            String strType = e.getAttributeValue("type");
            if (strType.equalsIgnoreCase(ErrorType.FATAL.toString()))
                errorType = ErrorType.FATAL;
            else if (strType.equalsIgnoreCase(ErrorType.TRANSIENT.toString()))
                errorType = ErrorType.TRANSIENT;

            boolean hasDetail = false;
            String strDetail = e.getAttributeValue("hasDetail");
            if (strDetail.equalsIgnoreCase("true"))
                hasDetail = true;

            String summaryMessage = e.getChildText(JobAttribute.ERROR_SUMMARY_MESSAGE.getAttributeName(), UWS.NS);
            rtn = new ErrorSummary(summaryMessage, errorType, hasDetail);
        }
        return rtn;
    }

    private JobInfo parseJobInfo(Document doc) {
        JobInfo rtn = null;
        Element root = doc.getRootElement();
        Element e = root.getChild(JobAttribute.JOB_INFO.getAttributeName(), UWS.NS);
        if (e != null) {
            log.debug("found jobInfo element");
            String content = e.getText();
            List children = e.getChildren();
            if (content != null)
                content = content.trim();
            if (content.length() > 0) // it was text content
            {
                rtn = new JobInfo(content, null, null);
            } else if (children != null) {
                if (children.size() == 1) {
                    try {
                        Element ce = (Element) children.get(0);
                        Document jiDoc = new Document((Element) ce.detach());
                        XMLOutputter outputter = new XMLOutputter();
                        StringWriter sw = new StringWriter();
                        outputter.output(jiDoc, sw);
                        sw.close();
                        rtn = new JobInfo(sw.toString(), null, null);

                    } catch (IOException ex) {
                        throw new RuntimeException("BUG while writing element to string", ex);
                    }
                }
            }
        }
        log.debug("parseJobInfo: " + rtn);
        return rtn;
    }

}