org.n52.ses.wsn.dissemination.updateinterval.UpdateIntervalDisseminationMethod.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.ses.wsn.dissemination.updateinterval.UpdateIntervalDisseminationMethod.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.wsn.dissemination.updateinterval;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.xml.namespace.QName;

import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.notification.NotificationMessage;
import org.apache.muse.ws.notification.remote.NotificationConsumerClient;
import org.joda.time.Period;
import org.n52.ses.wsn.dissemination.AbstractDisseminationMethod;
import org.n52.ses.wsn.dissemination.DisseminationMethodFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Update Interval dissemination method.
 * 
 * This implementation collects all messages within a given period
 * and batches all messages in one or only sends the latest messages,
 * depending on the policy configuration.
 * 
 * @author matthes rieke
 *
 */
public class UpdateIntervalDisseminationMethod extends AbstractDisseminationMethod {

    public static final QName UPDATE_INTERVAL_NAME = new QName(
            DisseminationMethodFactory.SUBSCRIPTION_POLICY_NAMESPACE, "UpdateInterval");
    public static final QName INTERVAL_DURATION_NAME = new QName(
            DisseminationMethodFactory.SUBSCRIPTION_POLICY_NAMESPACE, "IntervalDuration");
    public static final QName DISSEMINATION_METHOD_NAME = new QName(
            DisseminationMethodFactory.SUBSCRIPTION_POLICY_NAMESPACE, "DisseminationMethod");
    public static final QName NON_RELATED_NAME = new QName(DisseminationMethodFactory.SUBSCRIPTION_POLICY_NAMESPACE,
            "NonRelatedEventTreatment");
    public static final QName NO_NEW_MESSAGES_NAME = new QName(
            DisseminationMethodFactory.SUBSCRIPTION_POLICY_NAMESPACE, "NoNewMessages");

    public static enum DisseminationMethod {
        batching, latest
    };

    public static enum NonRelatedEventTreatment {
        separate, ignore
    };

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

    private long duration;
    private MessageCollector messageCollector;
    private boolean ignoreNonRelatedEvents;
    private DisseminationMethod disseminationMethod;
    private AtomicBoolean firstRun = new AtomicBoolean(true);
    private NotificationConsumerClient soapClient;
    private EndpointReference subscription;
    private EndpointReference producer;
    private EndpointReference consumer;
    private Timer timer;

    public UpdateIntervalDisseminationMethod(Node updateInterval, NotificationConsumerClient client,
            EndpointReference subscriptionReference) {
        List<Node> children = getChildElements(updateInterval);
        for (int i = 0; i < children.size(); i++) {
            parseChild(children.get(i));
        }

        this.soapClient = client;
        storeReferences(client, subscriptionReference, client.getProducerReference(),
                client.getConsumerReference());
        this.messageCollector = createMessageCollector();
        createIntervalThread();
    }

    private List<Node> getChildElements(Node updateInterval) {
        List<Node> result = new ArrayList<Node>();
        NodeList children = updateInterval.getChildNodes();
        Node child;
        for (int i = 0; i < children.getLength(); i++) {
            child = children.item(i);
            if (child instanceof Element)
                result.add(child);
        }
        return result;
    }

    private void parseChild(Node item) {
        QName qn = new QName(item.getNamespaceURI(), item.getLocalName());
        if (qn.equals(INTERVAL_DURATION_NAME)) {
            this.duration = parseDuration(item.getTextContent());
        } else if (qn.equals(DISSEMINATION_METHOD_NAME)) {
            this.disseminationMethod = parseDisseminationMethod(item.getTextContent());
        } else if (qn.equals(NON_RELATED_NAME)) {
            this.ignoreNonRelatedEvents = isIgnoreNonRelatedEventsBehaviour(item.getTextContent());
        }
    }

    private DisseminationMethod parseDisseminationMethod(String textContent) {
        if (textContent.equals(DisseminationMethod.batching.toString())) {
            //         throw new UnsupportedOperationException("<DisseminationMethod>batching</DisseminationMethod> for Update Intervals is currently not supported.");
            return DisseminationMethod.batching;
        }
        return DisseminationMethod.latest;
    }

    private boolean isIgnoreNonRelatedEventsBehaviour(String nonRelated) {
        if (nonRelated.equals(NonRelatedEventTreatment.ignore.toString())) {
            return true;
        }
        throw new UnsupportedOperationException(
                "<NonRelatedEventTreatment>separate</NonRelatedEventTreatment> for Update Intervals is currently not supported.");
    }

    private MessageCollector createMessageCollector() {
        return new MessageCollector(this.ignoreNonRelatedEvents,
                this.disseminationMethod == DisseminationMethod.batching);
    }

    private long parseDuration(String textContent) {
        return new Period(textContent).toStandardSeconds().getSeconds() * 1000;
    }

    @Override
    public boolean newMessage(NotificationMessage message, NotificationConsumerClient client,
            EndpointReference subscriptionReference, EndpointReference producerReference,
            EndpointReference consumerReference) {
        synchronized (this) {
            if (firstRun.getAndSet(false)) {
                storeReferences(client, subscriptionReference, producerReference, consumerReference);
            }
        }

        if (!validateReferences(client, subscriptionReference, producerReference, consumerReference)) {
            logger.warn("Not the same reference objects for Update Interval dissemination! Skipping message.");
            return false;
        }

        this.messageCollector.newMessage(message);

        return true;
    }

    private boolean validateReferences(NotificationConsumerClient client, EndpointReference subscriptionReference,
            EndpointReference producerReference, EndpointReference consumerReference) {
        return this.soapClient.equals(client) && this.subscription.equals(subscriptionReference)
                && this.producer.equals(producerReference) && this.consumer.equals(consumerReference);
    }

    private void storeReferences(NotificationConsumerClient client, EndpointReference subscriptionReference,
            EndpointReference producerReference, EndpointReference consumerReference) {
        this.soapClient = client;
        this.subscription = subscriptionReference;
        this.producer = producerReference;
        this.consumer = consumerReference;
    }

    public MessageCollector getMessageCollector() {
        return messageCollector;
    }

    private void createIntervalThread() {
        this.timer = new Timer();

        timer.schedule(new IntervalCycle(), this.duration, this.duration);
    }

    private class IntervalCycle extends TimerTask {

        @Override
        public void run() {
            NotificationMessage message = messageCollector.pullMessageForLastInterval();

            if (message == null) {
                message = createNoNewMessagesSystemMessage();
                if (logger.isInfoEnabled())
                    logger.debug("Sending system message for no new messages within update interval.");
            } else {
                if (logger.isInfoEnabled())
                    logger.debug("Sending update interval message.");
            }

            sendMessage(message, soapClient, consumer, numberOfTries, producer, subscription);
        }

        private NotificationMessage createNoNewMessagesSystemMessage() {
            return new NoNewMessagesMessage(subscription);
        }

    }

    @Override
    public void shutdown() {
        if (this.timer != null)
            this.timer.cancel();
        if (this.messageCollector != null)
            this.messageCollector.shutdown();
    }
}