org.mule.module.pubsubhubbub.data.DataStore.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.module.pubsubhubbub.data.DataStore.java

Source

/**
 * Mule PubSubHubbub Connector
 *
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.module.pubsubhubbub.data;

import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mule.api.store.ObjectDoesNotExistException;
import org.mule.api.store.ObjectStoreException;
import org.mule.api.store.PartitionableObjectStore;

import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.SyndFeedInfo;

public class DataStore implements FeedFetcherCache {
    private static final Log LOG = LogFactory.getLog(FeedFetcherCache.class);

    private static final String TOPIC_SUBSCRIPTION_CALLBACKS_PARTITION = "TopicSubscriptionCallbacks";
    private static final String TOPIC_FEED_IDS_PARTITION = "TopicFeedEntryIds";
    private static final String SUBSCRIBER_COUNTS_PARTITION_PREFIX = "SubscriberCounts";
    private static final String FEED_FETCHER_CACHE_PARTITION = "FeedFetcherCache";

    private final PartitionableObjectStore<Serializable> objectStore;

    public DataStore(final PartitionableObjectStore<Serializable> objectStore) {
        Validate.notNull(objectStore, "objectStore can't be null");
        this.objectStore = objectStore;
    }

    public void storeTopicSubscription(final TopicSubscription subscription) {
        storeInSet(subscription.getTopicUrl(), subscription, TOPIC_SUBSCRIPTION_CALLBACKS_PARTITION);
    }

    public void removeTopicSubscription(final TopicSubscription subscription) {
        removeFromSet(subscription.getTopicUrl(), subscription, TOPIC_SUBSCRIPTION_CALLBACKS_PARTITION);
    }

    @SuppressWarnings("unchecked")
    public Set<TopicSubscription> getTopicSubscriptions(final URI topicUrl) {
        final Set<TopicSubscription> result = new HashSet<TopicSubscription>();

        for (final TopicSubscription topicSubscription : (Set<TopicSubscription>) retrieve(topicUrl,
                TOPIC_SUBSCRIPTION_CALLBACKS_PARTITION, (Serializable) Collections.EMPTY_SET)) {
            if (topicSubscription.isExpired()) {
                removeTopicSubscription(topicSubscription);
            } else {
                result.add(topicSubscription);
            }
        }

        return result;
    }

    public void storeTopicFeedId(final URI topicUrl, final String feedId) {
        storeInSet(topicUrl, feedId, TOPIC_FEED_IDS_PARTITION);
    }

    @SuppressWarnings("unchecked")
    public Set<String> getTopicFeedIds(final URI topicUrl) {
        return (Set<String>) retrieve(topicUrl, TOPIC_FEED_IDS_PARTITION, (Serializable) Collections.EMPTY_SET);
    }

    public void storeSubscriberCount(final URI topicUrl, final URI callbackUrl, final int count) {
        store(callbackUrl, count, getTopicSubscribersCountDomain(topicUrl));
    }

    public int getTotalSubscriberCount(final URI topicUrl) {
        Integer result = 0;

        try {
            final List<Serializable> keys = objectStore.allKeys(getTopicSubscribersCountDomain(topicUrl));

            for (final Serializable key : keys) {
                result += (Integer) retrieve(key, getTopicSubscribersCountDomain(topicUrl), 0);
            }
        } catch (final ObjectStoreException ose) {
            LOG.error("Failed to get total subscriber count", ose);
        }

        // return what we have, doesn't need to be accurate but no need to throw an exception if we can't get the exact
        // number
        return result;
    }

    // Support for Rome feed fetcher
    public SyndFeedInfo getFeedInfo(final URL feedUrl) {
        return (SyndFeedInfo) retrieve(feedUrl, FEED_FETCHER_CACHE_PARTITION, null);
    }

    public void setFeedInfo(final URL feedUrl, final SyndFeedInfo syndFeedInfo) {
        store(feedUrl, syndFeedInfo, FEED_FETCHER_CACHE_PARTITION);
    }

    public void clear() {
        flush(FEED_FETCHER_CACHE_PARTITION);
    }

    public SyndFeedInfo remove(final URL feedUrl) {
        return (SyndFeedInfo) remove(feedUrl, FEED_FETCHER_CACHE_PARTITION);
    }

    // Private supporting methods, mostly synchronized because of the lack of atomicity of ObjectStore
    private synchronized void store(final Serializable key, final Serializable value, final String domain) {
        try {
            // not atomic :(
            if (objectStore.contains(key, domain)) {
                objectStore.remove(key, domain);
            }

            objectStore.store(key, value, domain);
        } catch (final ObjectStoreException ose) {
            throw new RuntimeException("Failed to store: " + value, ose);
        }
    }

    private synchronized Serializable remove(final Serializable key, final String domain) {
        try {
            return objectStore.remove(key, domain);
        } catch (final ObjectDoesNotExistException odnee) {
            return null;
        } catch (final ObjectStoreException ose) {
            throw new RuntimeException("Failed to remove: " + key, ose);
        }
    }

    private synchronized void flush(final String domain) {
        try {
            // not atomic :(
            final List<Serializable> keys = objectStore.allKeys(domain);
            for (final Serializable key : keys) {
                remove(key, domain);
            }
        } catch (final ObjectStoreException ose) {
            throw new RuntimeException("Failed to flush: " + domain, ose);
        }
    }

    private synchronized void storeInSet(final Serializable key, final Serializable value, final String domain) {
        // not atomic :(
        @SuppressWarnings("unchecked")
        Set<Serializable> values = (Set<Serializable>) retrieve(key, domain, null);

        if (values == null) {
            values = new HashSet<Serializable>();
        }

        values.add(value);

        store(key, (Serializable) values, domain);
    }

    private synchronized void removeFromSet(final Serializable key, final Serializable value, final String domain) {
        // not atomic :(
        @SuppressWarnings("unchecked")
        final Set<Serializable> values = (Set<Serializable>) retrieve(key, domain,
                (Serializable) Collections.EMPTY_SET);

        if (values.isEmpty()) {
            return;
        }

        values.remove(value);

        store(key, (Serializable) values, domain);
    }

    private synchronized Serializable retrieve(final Serializable key, final String domain,
            final Serializable defaultValue) {
        try {
            return objectStore.retrieve(key, domain);
        } catch (final ObjectDoesNotExistException odnee) {
            return defaultValue;
        } catch (final ObjectStoreException ose) {
            throw new RuntimeException("Failed to retrieve: " + key + " at " + domain, ose);
        }
    }

    private static String getTopicSubscribersCountDomain(final URI topicUrl) {
        return SUBSCRIBER_COUNTS_PARTITION_PREFIX + topicUrl.toString();
    }
}