org.n52.sos.feeder.baw.connector.SESConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.sos.feeder.baw.connector.SESConnector.java

Source

/**
 * Copyright (C) 2014-2014 52North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License version 2 as publishedby the Free
 * Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of the
 * following licenses, the combination of the program with the linked library is
 * not considered a "derivative work" of the program:
 *
 *     - Apache License, version 2.0
 *     - Apache Software License, version 1.0
 *     - GNU Lesser General Public License, version 3
 *     - Mozilla Public License, versions 1.0, 1.1 and 2.0
 *     - Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed under
 * the aforementioned licenses, is permitted by the copyright holders if the
 * distribution is compliant with both the GNU General Public License version 2
 * and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 */
package org.n52.sos.feeder.baw.connector;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.opengis.om.x10.ObservationPropertyType;
import net.opengis.sensorML.x101.SensorMLDocument;
import net.opengis.ses.x00.CapabilitiesDocument;

import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.n52.oxf.OXFException;
import org.n52.oxf.ows.ExceptionReport;
import org.n52.oxf.ows.ServiceDescriptor;
import org.n52.oxf.ows.capabilities.Operation;
import org.n52.oxf.adapter.OperationResult;
import org.n52.oxf.adapter.ParameterContainer;
import org.n52.oxf.ses.adapter.ISESRequestBuilder;
import org.n52.oxf.ses.adapter.SESAdapter;
import org.n52.sos.feeder.baw.Configuration;
import org.n52.sos.feeder.baw.SosSesFeeder;
import org.n52.sos.feeder.baw.utils.SESAdapter_01;
import org.n52.sos.feeder.baw.utils.SESRequestBuilder_01;
import org.w3.x2003.x05.soapEnvelope.Body;
import org.w3.x2003.x05.soapEnvelope.Envelope;
import org.w3.x2003.x05.soapEnvelope.EnvelopeDocument;

/**
 * The SESConnector class manages the communication between the feeder and the SES.
 *
 * @author Jan Schulte
 */
public class SESConnector {

    /** The logger. */
    private static final Logger log = Logger.getLogger(SESConnector.class);

    /** The ses adapter. */
    private SESAdapter_01 sesAdapter;

    /** The ses url. */
    private String sesUrl;

    private String topic;

    private String dialect;

    private boolean closed = false;

    /**
     * Instantiates a new SESConnector.
     */
    public SESConnector() {
        this.sesAdapter = new SESAdapter_01();
        try {
            this.topic = Configuration.getInstance().getSesDefaultTopic();
            this.dialect = Configuration.getInstance().getSesDefaultTopicDialect();
            this.sesUrl = Configuration.getInstance().getSesUrl()
                    + Configuration.getInstance().getSesBasicPortType();
        } catch (IllegalStateException e) {
            e.printStackTrace();
            log.debug("Configuration is not available (anymore).");
        }
    }

    /**
     * Initialize the connection to the SES.
     *
     * @return true - if service is running
     */
    public boolean initService() {
        log.trace("initService()");

        try {
            ServiceDescriptor desc = this.sesAdapter.initService(this.sesUrl);
            log.info(desc.toXML());
        } catch (ExceptionReport e) {
            log.error("SES not accessible");
            return false;
        } catch (OXFException e) {
            log.error(String.format("SES '%s' not accessible.", this.sesUrl));
            return false;
        }
        log.info("SES accessible");
        return true;
    }

    /**
     * Register the publisher by sending a sensorML document to the SES.
     *
     * @param sensorML
     *        The sensorML document
     * @return The ID given by the SES
     */
    public String registerPublisher(SensorMLDocument sensorML) {
        log.trace("registerPublisher");

        ParameterContainer parameter = new ParameterContainer();

        OperationResult opRes;

        try {

            String defaultTopicDialect = Configuration.getInstance().getSesDefaultTopicDialect();
            String defaultTopic = Configuration.getInstance().getSesDefaultTopic();
            String lifetime = Configuration.getInstance().getSesLifetimeDuration();
            String localEndpoint = Configuration.getInstance().getSesEndpoint();
            String sensorMLString = sensorML.toString();
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_SES_URL, this.sesUrl);
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_SENSORML, sensorMLString);
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_TOPIC_DIALECT, defaultTopicDialect);
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_TOPIC, defaultTopic);
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_LIFETIME_DURATION, lifetime);
            parameter.addParameterShell(ISESRequestBuilder.REGISTER_PUBLISHER_FROM, localEndpoint);

            log.debug("RegisterPublisher request: \n"
                    + new SESRequestBuilder_01().buildRegisterPublisherRequest(parameter));

            opRes = this.sesAdapter.doOperation(
                    new Operation(SESAdapter.REGISTER_PUBLISHER, this.sesUrl + "?", this.sesUrl), parameter);

            XmlObject response = this.sesAdapter.handleResponse(SESAdapter.REGISTER_PUBLISHER,
                    opRes.getIncomingResultAsStream());

            log.debug("RegisterPublisher response: \n" + response);
            String tmp = response.toString();
            String sesID = tmp.substring(tmp.indexOf('>', tmp.indexOf("ResourceId")) + 1,
                    tmp.indexOf('<', tmp.indexOf("ResourceId")));

            return sesID;
        } catch (OXFException e) {
            log.error("Error while sending registerPublisher request to SES: " + e.getMessage());
        } catch (IllegalStateException e) {
            e.printStackTrace();
            log.debug("Configuration is not available (anymore).");
        }
        return null;
    }

    /**
     * Send a given Observation to the SES.
     *
     * @param obsPropType
     *        The given Observation
     * @return true - when sending successful
     * @throws OXFException
     */
    public boolean publishObservation(ObservationPropertyType obsPropType) throws OXFException {
        log.trace("publishObservation()");

        String observationXML = obsPropType.xmlText();
        String[] observations;

        // split in individual observations
        try {
            observations = splitObservations(observationXML);
        } catch (Exception e1) {
            log.error("Error while splitting observations. Send observations in one request.");
            createAndSendRequest(observationXML);
            return true;
        }

        // send request as single observation
        for (String observation : observations) {
            if (SosSesFeeder.active) {
                createAndSendRequest(observation);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    //
                }
            } else {
                throw new OXFException("Servlet is stopped");
            }
        }

        return false;
    }

    private void createAndSendRequest(String observationXML) {
        ParameterContainer parameter = new ParameterContainer();
        try {
            parameter.addParameterShell(ISESRequestBuilder.NOTIFY_SES_URL, sesUrl);
            parameter.addParameterShell(ISESRequestBuilder.NOTIFY_TOPIC, topic);
            parameter.addParameterShell(ISESRequestBuilder.NOTIFY_TOPIC_DIALECT, dialect);
            parameter.addParameterShell(ISESRequestBuilder.NOTIFY_XML_MESSAGE, observationXML);

            log.debug("Notify request: \n" + new SESRequestBuilder_01().buildNotifyRequest(parameter));

            this.sesAdapter.doOperation(new Operation(SESAdapter.NOTIFY, this.sesUrl + "?", this.sesUrl),
                    parameter);

        } catch (OXFException e) {
            log.error("Error while sending notify message to SES: " + e.getMessage());
        } catch (NullPointerException e) {
            log.debug("Response of notify is null");
        }
    }

    /**
     * Gets the content lists.
     *
     * @return the content lists
     */
    public List<String> getContentLists() {
        ArrayList<String> registeredSensors = new ArrayList<String>();

        ParameterContainer parameter = new ParameterContainer();

        OperationResult opsRes;
        try {
            parameter.addParameterShell(ISESRequestBuilder.GET_CAPABILITIES_SES_URL, this.sesUrl);
            opsRes = this.sesAdapter.doOperation(
                    new Operation(SESAdapter.GET_CAPABILITIES, this.sesUrl + "?", this.sesUrl), parameter);

            Envelope env = EnvelopeDocument.Factory.parse(opsRes.getIncomingResultAsStream()).getEnvelope();
            Body body = env.getBody();

            XmlObject result = XmlObject.Factory.parse(body.toString());
            if (result instanceof CapabilitiesDocument) {
                CapabilitiesDocument capDoc = (CapabilitiesDocument) result;
                if (capDoc.getCapabilities().getContents().isSetRegisteredSensors()) {
                    String[] sensors = capDoc.getCapabilities().getContents().getRegisteredSensors()
                            .getSensorIDArray();
                    for (int i = 0; i < sensors.length; i++) {
                        registeredSensors.add(sensors[i]);
                        log.debug("Sensor is in the SES: " + sensors[i]);
                    }
                }
            } else {
                log.error("Get no valid capabilities!");
                registeredSensors = null;
                log.debug(result);
            }
        } catch (OXFException e) {
            log.error("Error while init SES: " + e.getMessage());
        } catch (XmlException e) {
            log.error("Error while init SES: " + e.getMessage());
        } catch (IOException e) {
            log.error("Error while init SES: " + e.getMessage());
        }
        return registeredSensors;
    }

    private String[] splitObservations(String inputObservation) throws Exception {

        try {
            // Determining how many observations are contained in the observation collection
            Pattern countPattern = Pattern.compile("<swe:value>(.*?)</swe:value>");
            Matcher countMatcher = countPattern.matcher(inputObservation);
            String countString = null;
            if (countMatcher.find()) {
                countString = countMatcher.group(1).trim();
            }
            int observationCount = Integer.parseInt(countString);

            // This array will contain one observation string for each observation of the observation
            // collection
            String[] outputStrings;

            // If the observation collection contains only one value it can be directly returned
            if (observationCount == 1) {
                outputStrings = new String[] { inputObservation };
            }

            // If the observation collection contains more than one value it must be split
            else {

                // Extracting the values that are contained in the observation collection and creating a
                // StringTokenizer that allows to access the values
                Pattern valuesPattern = Pattern.compile("<swe:values>(.*?)</swe:values>");
                Matcher valuesMatcher = valuesPattern.matcher(inputObservation);
                String valuesString = null;
                if (valuesMatcher.find()) {
                    valuesString = valuesMatcher.group(1).trim();
                }

                // Read the id of the observation collection
                Pattern idPattern = Pattern
                        .compile("ObservationCollection gml:id=\"(.*?)\"(.*?)xsi:schemaLocation=");
                Matcher idMatcher = idPattern.matcher(inputObservation);
                String idString = "";
                if (idMatcher.find()) {
                    idString = idMatcher.group(1).trim();
                }

                StringTokenizer valuesTokenizer = new StringTokenizer(valuesString, ";");
                // If only the latest observation is wished, find youngest
                // observation.
                if (Configuration.getInstance().isOnlyYoungestName()) {
                    DateTime youngest = new DateTime(0);
                    String youngestValues = "";
                    DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
                    while (valuesTokenizer.hasMoreElements()) {
                        String valueString = (String) valuesTokenizer.nextElement();
                        DateTime time = fmt.parseDateTime(valueString.split(",")[0]);
                        if (time.isAfter(youngest.getMillis())) {
                            youngest = time;
                            youngestValues = valueString;
                        }
                    }
                    outputStrings = new String[] {
                            createSingleObservationString(inputObservation, youngestValues) };
                } else {
                    outputStrings = new String[observationCount];

                    for (int i = 0; i < observationCount; i++) {

                        // Add the extracted observation to an array containing
                        // all extracted observations
                        outputStrings[i] = createSingleObservationString(inputObservation,
                                valuesTokenizer.nextToken());
                    }
                }

            }
            // Returning the extracted observations
            return outputStrings;
        }

        catch (Exception e) {
            throw e;
        }
    }

    private String createSingleObservationString(String observation, String individualValuesString) {

        // This string will contain the next extracted single
        // observation
        String singleObservationString = observation;

        //        // Replace the id of the observation collection
        //        singleObservationString = singleObservationString.replaceFirst(idString, idString + "_" + i);

        // Replace the time period of the observation with the
        // time of the contained observation
        Pattern timePattern = Pattern.compile("(.*?),");
        Matcher timeMatcher = timePattern.matcher(individualValuesString);
        String timeString = "";
        if (timeMatcher.find()) {
            timeString = timeMatcher.group(1).trim();
        }
        singleObservationString = singleObservationString.replaceAll("<gml:beginPosition>[^<]*</gml:beginPosition>",
                "<gml:beginPosition>" + timeString + "</gml:beginPosition>");
        singleObservationString = singleObservationString.replaceAll("<gml:endPosition>[^<]*</gml:endPosition>",
                "<gml:endPosition>" + timeString + "</gml:endPosition>");

        // Set the number of elements in the observation
        // collection to 1
        singleObservationString = singleObservationString.replaceAll("<swe:value>[^<]*</swe:value>",
                "<swe:value>1</swe:value>");

        // Replace the elements in the values element with one
        // singe value
        singleObservationString = singleObservationString.replaceAll("<swe:values>[^<]*</swe:values>",
                "<swe:values>" + individualValuesString + ";</swe:values>");

        return singleObservationString;
    }

    /**
     * @return the closed
     */
    public boolean isClosed() {
        return closed;
    }

    /**
     * @param closed the closed to set
     */
    public void setClosed(boolean closed) {
        this.closed = closed;
    }

}