org.n52.ses.io.parser.SASParser.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.ses.io.parser.SASParser.java

Source

/**
 * Copyright (C) 2012
 * by 52 North Initiative for Geospatial Open Source Software GmbH
 *
 * Contact: Andreas Wytzisk
 * 52 North Initiative for Geospatial Open Source Software GmbH
 * Martin-Luther-King-Weg 24
 * 48155 Muenster, Germany
 * info@52north.org
 *
 * This program is free software; you can redistribute and/or modify it under
 * the terms of the GNU General Public License version 2 as published by the
 * Free Software Foundation.
 *
 * This program is distributed WITHOUT ANY WARRANTY; even without the implied
 * WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program (see gnu-gpl v2.txt). If not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA or
 * visit the Free Software Foundation web page, http://www.fsf.org.
 */
package org.n52.ses.io.parser;

import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;

import org.apache.muse.ws.notification.NotificationMessage;
import org.apache.xmlbeans.XmlObject;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.n52.oxf.xmlbeans.parser.XMLBeansParser;
import org.n52.ses.api.AbstractParser;
import org.n52.ses.api.event.MapEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

/**
 * Parser for notification messages encoded as SAS (RFC, 06-028r5) alerts.
 * 
 * As the alert structure is not known to the parser
 * it is currently build only for specific SAS alerts.
 * The alert data has to be formatted in the following way:
 * <code><AlertData>%TIME,%LAT,%LON,%VALUE</AlertData></code>
 * where %VALUE has to be in a base (SI) unit,
 * %LAT and %LON are in WGS 84 and define a point, 
 * all entries have to be separated by a comma (",").
 * 
 * @author Thomas Everding
 *
 */
public class SASParser extends AbstractParser {

    /**
     * XML namespace of the SAS (RFC; 06-028r5)
     */
    public static final String SAS_NAMESPACE = "http://www.opengis.net/sas/0.0";

    /**
     * XML namespace of the SAS as used by some implementers (e.g. RSA in GENESIS Project)
     */
    public static final String SAS_NAMESPACE_090 = "http://www.opengis.net/sas/0.9.0";

    private String value;
    private String geometry;
    private String sensorID;
    private String timestamp;
    private String alertdata;

    private static final Logger logger = LoggerFactory.getLogger(SASParser.class);

    /**
     * Parses an SAS alert
     * 
     * @param xmlObj the SAS alert as DOM node
     * 
     * @return A list of {@link MapEvent}s containing the alert as first entity.
     */
    public List<MapEvent> parseXML(XmlObject xmlObj) {
        //parse string based
        this.parseAlertDocumentText(xmlObj.toString());

        //parse time stamp text
        DateTimeFormatter dtf = this.buildDTFormatter();
        DateTime dt = dtf.parseDateTime(this.timestamp);
        long timeStamp = dt.getMillis();

        //parse alert data
        this.parseAlertData(this.alertdata);

        //build result list
        List<MapEvent> result = new ArrayList<MapEvent>();

        //build MapEvent
        MapEvent event = new MapEvent(timeStamp, timeStamp);

        //set value
        event.put(MapEvent.VALUE_KEY, this.value);

        //set geometry
        event.put(MapEvent.GEOMETRY_KEY, this.geometry);

        //set sensor ID
        event.put(MapEvent.SENSORID_KEY, this.sensorID);

        //set original message
        event.put(MapEvent.ORIGNIAL_MESSAGE_KEY, xmlObj.toString());

        //add event to result
        result.add(event);

        SASParser.logger.info("SAS alert parsed");
        return result;
    }

    /**
     * extracts the content of a SAS alert
     * 
     * @param xmlText the alert text
     */
    private void parseAlertDocumentText(String xmlText) {
        //split alert
        String[] entries = xmlText.split(">");

        /*
         * content of "entries":
         * 
         * 0: <Alert...
         * 1: <SensorID
         * 2: urn:ogc...</SensorID
         * 3: <Timestamp
         * 4: 2010-04...</Timestamp
         * 5: <AlertData
         * 6: 2010-04..., 47....</AlertData
         * 7: </Alert
         */

        //remove closing tags
        this.sensorID = entries[2].substring(0, entries[2].indexOf("<"));
        this.timestamp = entries[4].substring(0, entries[4].indexOf("<"));
        this.alertdata = entries[6].substring(0, entries[6].indexOf("<"));
    }

    /**
     * parses the alert data
     * 
     * @param data an AlertData element content
     */
    private void parseAlertData(String data) {
        //split data string
        String[] parts = data.split(",");

        //store value
        this.value = parts[3];

        //store geometry as WKT
        this.geometry = "POINT (" + parts[1] + " " + parts[2] + ")";

        //time key is repeated at parts[0] but parsed from the time specific element
    }

    /**
     * 
     * @return a formatter for common ISO strings
     */
    private DateTimeFormatter buildDTFormatter() {
        //build a parser for time stamps
        return new DateTimeFormatterBuilder().appendYear(4, 4) //4 digit year (YYYY)
                .appendLiteral("-").appendMonthOfYear(2) //2 digit month (MM)
                .appendLiteral("-").appendDayOfMonth(2) //2 digit day (DD)
                .appendLiteral("T").appendHourOfDay(2) //2 digit hour (hh)
                .appendLiteral(":").appendMinuteOfHour(2) //2 digit minute (mm)
                .appendLiteral(":").appendSecondOfMinute(2)//2 digit second (ss)
                //optional 3 digit milliseconds of second
                .appendOptional(
                        new DateTimeFormatterBuilder().appendLiteral(".").appendMillisOfSecond(3).toParser())
                //optional time zone offset as (+|-)hh:mm
                .appendOptional(new DateTimeFormatterBuilder().appendTimeZoneOffset("", true, 2, 2).toParser())
                //optional 'Z' at the end of the time string
                .appendOptional(new DateTimeFormatterBuilder().appendLiteral("Z").toParser()).toFormatter();
    }

    @Override
    public boolean accept(NotificationMessage message) {
        //namespace as defined in RFC Specification
        QName sasQName = new QName(SAS_NAMESPACE, "Alert");
        Element content = message.getMessageContent(sasQName);

        if (content != null) {
            return true;
        }

        //alternative namespace
        sasQName = new QName(SAS_NAMESPACE_090, "Alert");
        content = message.getMessageContent(sasQName);

        if (content != null) {
            return true;
        }

        return false;
    }

    @Override
    public List<MapEvent> parse(NotificationMessage message) throws Exception {
        //namespace as defined in RFC Specification
        QName sasQName = new QName(SAS_NAMESPACE, "Alert");
        Element content = message.getMessageContent(sasQName);

        if (content != null) {
            XmlObject obj = XMLBeansParser.parse(content, false);
            return this.parseXML(obj);
        }

        //alternative namespace
        sasQName = new QName(SASParser.SAS_NAMESPACE_090, "Alert");
        content = message.getMessageContent(sasQName);

        if (content != null) {
            XmlObject obj = XMLBeansParser.parse(content, false);
            return this.parseXML(obj);
        }

        return null;
    }

    @Override
    protected String getName() {
        return "SASParser";
    }
}