Package org.apache.airavata.wsmg.broker.subscription

Source Code of org.apache.airavata.wsmg.broker.subscription.SubscriptionManager

/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

package org.apache.airavata.wsmg.broker.subscription;

import java.io.StringReader;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.apache.airavata.wsmg.broker.context.ContextParameters;
import org.apache.airavata.wsmg.broker.context.ProcessingContext;
import org.apache.airavata.wsmg.broker.context.ProcessingContextBuilder;
import org.apache.airavata.wsmg.broker.wseventing.WSEProcessingContextBuilder;
import org.apache.airavata.wsmg.broker.wseventing.WSEProtocolSupport;
import org.apache.airavata.wsmg.broker.wsnotification.WSNTProtocolSupport;
import org.apache.airavata.wsmg.broker.wsnotification.WSNotificationProcessingContextBuilder;
import org.apache.airavata.wsmg.commons.WsmgCommonConstants;
import org.apache.airavata.wsmg.commons.NameSpaceConstants;
import org.apache.airavata.wsmg.commons.storage.WsmgStorage;
import org.apache.airavata.wsmg.config.WSMGParameter;
import org.apache.airavata.wsmg.config.WsmgConfigurationContext;
import org.apache.airavata.wsmg.matching.AbstractMessageMatcher;
import org.apache.airavata.wsmg.messenger.OutGoingQueue;
import org.apache.airavata.wsmg.util.RunTimeStatistics;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.AxisFault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Manages subscribers.
*
*/
public class SubscriptionManager {

    private static final Logger log = LoggerFactory.getLogger(SubscriptionManager.class);

    private HashMap<String, SubscriptionState> subscriptions = new HashMap<String, SubscriptionState>();

    private ReentrantReadWriteLock subscriptionLock = new ReentrantReadWriteLock();

    private WSEProtocolSupport wseProtocalSupport = new WSEProtocolSupport();

    private WSNTProtocolSupport wsntProtocolSupport = new WSNTProtocolSupport();

    private WsmgStorage subscriptionDB;

    private WsmgConfigurationContext wsmgConfig;

    private OutGoingQueue outGoingQueue;

    private int counter = 1;

    public SubscriptionManager(WsmgConfigurationContext paramters, WsmgStorage storage) {
        init(paramters, storage);
    }

    private void init(WsmgConfigurationContext parameters, WsmgStorage storage) {

        this.wsmgConfig = parameters;

        subscriptionDB = storage;
        outGoingQueue = parameters.getOutgoingQueue();
        if (WSMGParameter.enableAutoCleanSubscriptions) {
            CleanUpThread cleanUpThread = new CleanUpThread(this);
            Thread t = new Thread(cleanUpThread);
            t.start();
        }

        try {
            checkSubscriptionDB(storage);
        } catch (AxisFault e) {
            log.error("Subscription database has malformed" + " subscriptions. Ignoring them.", e);

        }

    }

    /**
     * @return Returns the subscriptions.
     */
    public AbstractMap<String, SubscriptionState> getShallowSubscriptionsCopy() {

        AbstractMap<String, SubscriptionState> ret = null;
        readLockUnlockSubscriptions(true);
        try {
            ret = new HashMap<String, SubscriptionState>(subscriptions);
        } finally {
            readLockUnlockSubscriptions(false);
        }

        return ret;

    }

    public void subscribe(ProcessingContext ctx) throws AxisFault {

        String subId = createSubscription(null, ctx);
        if (subId == null) {
            log.error("ERROR: No subscription created");
            return;
        }

        if (NameSpaceConstants.WSE_NS.equals(ctx.getContextParameter(ContextParameters.SUBSCRIBE_ELEMENT)
                .getNamespace())) {
            wseProtocalSupport.createSubscribeResponse(ctx, subId);

        } else { // WSNT

            wsntProtocolSupport.createSubscribeResponse(ctx, subId);
        }
    }

    /**
     * @param subscriptionId
     *            this is the ID that is in the SOAP header
     * @param ctx
     *            contexts constructed with the body elements
     * @return subscription id
     * @throws AxisFault
     */
    private String createSubscription(String subscriptionId, ProcessingContext ctx) throws AxisFault {

        SubscriptionState state = null;
        String key = null;

        // get the first element element inside the soap body element and check
        // whether namespace is WSE
        if (NameSpaceConstants.WSE_NS.equals(ctx.getContextParameter(ContextParameters.SUBSCRIBE_ELEMENT)
                .getNamespace())) {
            state = wseProtocalSupport.createSubscriptionState(ctx, outGoingQueue);
        } else { // Handle WSNT

            state = wsntProtocolSupport.createSubscriptionState(ctx, outGoingQueue);
        }

        if (subscriptionId == null) { // New subscription entry
            key = checkSubscriptionExist(state);
            if (key != null) { // just renew previous subscriptions
                return key;
            }
            // new subscriptions

            state.setCreationTime(System.currentTimeMillis());

            key = generateSubscriptionId(state.getXpathString() != null && state.getXpathString().length() > 0);

        } else { // Startup from previous subscription database
            key = subscriptionId;
        }

        for (AbstractMessageMatcher m : wsmgConfig.getMessageMatchers()) {
            m.handleSubscribe(state, key);
        }

        if (subscriptionId == null) { // New subscription entry,

            RunTimeStatistics.totalSubscriptions++;
            try {
                String subscribeXml = ctx.getContextParameter(ContextParameters.SUBSCRIBE_ELEMENT)
                        .toStringWithConsume();

                state.setId(key);
                state.setSubscribeXml(subscribeXml);
                subscriptionDB.insert(state);

            } catch (Exception ex) {
                log.error("unable to insert subscription to database", ex);
                throw new AxisFault("unable to insert subscription to database ", ex);
            }
        }

        addToSubscriptionMap(key, state);
        return key;
    }

    private void addToSubscriptionMap(String key, SubscriptionState state) {

        writeLockUnlockSubscription(true);
        try {
            subscriptions.put(key, state);
        } finally {
            writeLockUnlockSubscription(false);
        }

    }

    /**
     * @param xpathString
     * @return
     */
    private String generateSubscriptionId(boolean xPath) {
        String key;
        String subIdPrefix = null; // Used to indicate weather a subscription
        // has an XPath subscription Or Topic
        // only.
        if (!xPath) {
            subIdPrefix = "T";
        } else {
            subIdPrefix = "X";
        }
        key = subIdPrefix + "sub" + (counter++) + "@" + WsmgCommonConstants.PREFIX;
        return key;
    }

    /**
     * if find the subscription already exists, return the current subscriptionId else return null;
     */

    public String checkSubscriptionExist(SubscriptionState state) {

        String key = null;

        readLockUnlockSubscriptions(true);
        try {

            for (Iterator<String> keyIterator = subscriptions.keySet().iterator(); keyIterator.hasNext();) {

                String currentKey = keyIterator.next();
                SubscriptionState value = subscriptions.get(currentKey);

                if (value.equals(state)) {
                    value.setCreationTime(System.currentTimeMillis());
                    log.info("Subscription Already exists." + " Using the current subscriptionId");
                    key = currentKey;
                    break;
                }

            }

        } finally {
            readLockUnlockSubscriptions(false);
        }

        return key;
    }

    public void checkSubscriptionDB(WsmgStorage storage) throws AxisFault {
        OMElement subscribeXmlElement;
        String subscriptionId;
        // Read subscription Info from Subscription DB
        List<SubscriptionEntry> subscriptionEntry = storage.getAllSubscription();
        if (subscriptionEntry == null) {
            return;
        }

        WSNotificationProcessingContextBuilder wsntBuilder = new WSNotificationProcessingContextBuilder();
        WSEProcessingContextBuilder wseBuilder = new WSEProcessingContextBuilder();

        // Create subscription for these entries from DB
        for (int i = 0; i < subscriptionEntry.size(); i++) {

            ProcessingContextBuilder processingCtxBuilder = null;

            log.info("Subscription No. " + i + " is " + subscriptionEntry.get(i).getSubscriptionId());

            StringReader sr = new StringReader(subscriptionEntry.get(i).getSubscribeXml());
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            XMLStreamReader inflow;
            try {
                inflow = inputFactory.createXMLStreamReader(sr);

                StAXOMBuilder builder = new StAXOMBuilder(inflow); // get the
                // root
                // element (in
                // this case the
                // envelope)
                subscribeXmlElement = builder.getDocumentElement();

                if (subscribeXmlElement.getNamespace().getNamespaceURI()
                        .equals(NameSpaceConstants.WSNT_NS.getNamespaceURI())) {
                    processingCtxBuilder = wsntBuilder;

                } else {
                    processingCtxBuilder = wseBuilder;
                }

                subscriptionId = subscriptionEntry.get(i).getSubscriptionId();

                ProcessingContext context = processingCtxBuilder.build(subscribeXmlElement);
                createSubscription(subscriptionId, context);

            } catch (XMLStreamException e) {
                log.error("error occured while checking subscription db", e);
            }
        }
        RunTimeStatistics.totalSubscriptionsAtStartUp += subscriptionEntry.size();
    }

    // This is used for debug
    public void showAllSubscription() {
        String key = null;
        SubscriptionState value = null;
        Set<String> keySet = subscriptions.keySet();
        log.info("List of all subscriptions:");
        for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext();) {
            key = iterator.next();
            value = subscriptions.get(key);
            log.info("******" + key + "-->" + value.getConsumerIPAddressStr() + "##" + value.getLocalTopic());
        }
    }

    public int unsubscribe(ProcessingContext ctx) throws AxisFault {

        String subscriptionId = ctx.getContextParameter(ContextParameters.SUB_ID);
        if (subscriptionId == null || subscriptionId.trim().length() == 0) {
            throw new AxisFault("subscription identifier is not provided");
        }

        removeSubscription(subscriptionId);
        RunTimeStatistics.totalUnSubscriptions++;
        return 0;
    }

    int removeSubscription(String subId) throws AxisFault {

        SubscriptionState subscription = null;

        writeLockUnlockSubscription(true);
        try {
            subscription = subscriptions.remove(subId);
        } finally {
            writeLockUnlockSubscription(false);
        }

        if (subscription == null) {
            throw AxisFault.makeFault(new RuntimeException("unknown subscription: " + subId));

        }

        subscriptionDB.delete(subId);

        for (AbstractMessageMatcher mm : wsmgConfig.getMessageMatchers()) {
            mm.handleUnsubscribe(subId);
        }

        return 0;
    }

    public void resumeSubscription(ProcessingContext ctx) throws AxisFault {

        String subscriptionId = ctx.getContextParameter(ContextParameters.SUB_ID);

        if (subscriptionId == null) {
            throw AxisFault.makeFault(new RuntimeException("missing subscription id"));
        }

        writeLockUnlockSubscription(true);// lock
        try {
            SubscriptionState subscription = subscriptions.get(subscriptionId);

            if (subscription == null) {

                throw AxisFault.makeFault(new RuntimeException("no subscription found for id: " + subscriptionId));
            }

            subscription.resume();
        } finally {
            // this will execute even exception is thrown.
            writeLockUnlockSubscription(false);
        }
    }

    public void pauseSubscription(ProcessingContext ctx) throws AxisFault {

        String subscriptionId = ctx.getContextParameter(ContextParameters.SUB_ID);

        if (subscriptionId == null) {
            throw AxisFault.makeFault(new RuntimeException("missing subscription id"));
        }

        writeLockUnlockSubscription(true);// read lock should be sufficient
        // (since we are not modifying the
        // map)
        try {
            SubscriptionState subscription = subscriptions.get(subscriptionId);

            if (subscription == null) {

                throw AxisFault.makeFault(new RuntimeException("no subscription found for id: " + subscriptionId));

            }

            subscription.pause();
        } finally {
            // this will execute even exception is thrown.
            writeLockUnlockSubscription(false);
        }
    }

    public void readLockUnlockSubscriptions(boolean lock) {
        ReadLock readlock = subscriptionLock.readLock();
        lockUnlock(readlock, lock);
    }

    public void writeLockUnlockSubscription(boolean lock) {
        WriteLock writeLock = subscriptionLock.writeLock();
        lockUnlock(writeLock, lock);
    }

    private void lockUnlock(Lock l, boolean lock) {

        if (lock) {
            l.lock();
        } else {
            l.unlock();
        }

    }
}
TOP

Related Classes of org.apache.airavata.wsmg.broker.subscription.SubscriptionManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.