/** * Copyright 2012 Comcast Corporation * * Licensed 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 com.comcast.cns.controller; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import com.comcast.cmb.common.persistence.PersistenceFactory; import com.comcast.cmb.common.util.CMBProperties; import com.comcast.cmb.common.util.ExpiringCache; import com.comcast.cmb.common.util.ExpiringCache.CacheFullException; import com.comcast.cns.model.CNSSubscription; import com.comcast.cns.model.CNSTopic; import com.comcast.cns.model.CNSTopicAttributes; import com.comcast.cns.persistence.ICNSAttributesPersistence; import com.comcast.cns.persistence.ICNSSubscriptionPersistence; import com.comcast.cns.persistence.ICNSTopicPersistence; /** * Utility class that contains most of the caches the rest of the code uses * @author bwolf, aseem */ public class CNSCache { private static volatile ExpiringCache<String, CNSTopicAttributes> attributeCache = new ExpiringCache<String, CNSTopicAttributes>(CMBProperties.getInstance().getCNSCacheSizeLimit()); private static volatile ICNSAttributesPersistence attributeHandler = PersistenceFactory.getCNSAttributePersistence(); private static volatile ExpiringCache<String, List<CNSSubscription>> confirmedSubscriptionsCache = new ExpiringCache<String, List<CNSSubscription>>(CMBProperties.getInstance().getCNSCacheSizeLimit()); private static volatile ICNSSubscriptionPersistence subscriptionHandler = PersistenceFactory.getSubscriptionPersistence(); private static ExpiringCache<String, CNSTopic> topicCache = new ExpiringCache<String, CNSTopic>(CMBProperties.getInstance().getCNSCacheSizeLimit()); private static ICNSTopicPersistence topicHandler = PersistenceFactory.getTopicPersistence(); private static class CNSTopicCallable implements Callable<CNSTopic> { String arn = null; public CNSTopicCallable(String arn) { this.arn = arn; } @Override public CNSTopic call() throws Exception { CNSTopic topic = topicHandler.getTopic(arn); return topic; } } /** * * @param topicArn * @return CNSTopicAttributes for the given topic or null if doesn't exist * @throws Exception */ public static CNSTopic getTopic(String topicArn) throws Exception { if (topicArn == null) { return null; } return topicCache.getAndSetIfNotPresent(topicArn, new CNSTopicCallable(topicArn), CMBProperties.getInstance().getCNSCacheExpiring() * 1000); } private static class TopicAttributesCallable implements Callable<CNSTopicAttributes> { String topicArn = null; public TopicAttributesCallable(String key) { this.topicArn = key; } @Override public CNSTopicAttributes call() throws Exception { CNSTopicAttributes attributes = attributeHandler.getTopicAttributes(this.topicArn); return attributes; } } /** * * @param topicArn */ public static void removeTopic(String topicArn) { if (topicArn == null) { return; } confirmedSubscriptionsCache.remove(topicArn); attributeCache.remove(topicArn); topicCache.remove(topicArn); } /** * * @param topicArn * @return CNSTopicAttributes for the given topic or null if doesn't exist * @throws Exception */ public static CNSTopicAttributes getTopicAttributes(String topicArn) throws Exception { if (topicArn == null) { return null; } return attributeCache.getAndSetIfNotPresent(topicArn, new TopicAttributesCallable(topicArn), CMBProperties.getInstance().getCNSCacheExpiring() * 1000); } /** * * @param topicArn */ public static void removeTopicAttributes(String topicArn) { if (topicArn == null) { return; } attributeCache.remove(topicArn); } private static class SubscriptionCallable implements Callable<List<CNSSubscription>> { String topicArn = null; public SubscriptionCallable(String key) { this.topicArn = key; } @Override public List<CNSSubscription> call() throws Exception { String nextToken = null; int round = 0; List<CNSSubscription> allSubscriptions = new ArrayList<CNSSubscription>(); while (round == 0 || nextToken != null) { List<CNSSubscription> subscriptions = subscriptionHandler.listSubscriptionsByTopic(nextToken, topicArn, null); if (subscriptions.size() > 0) { nextToken = subscriptions.get(subscriptions.size()-1).getArn(); } else { nextToken = null; } for (CNSSubscription s : subscriptions) { if (s.isConfirmed()) { allSubscriptions.add(s); } } round++; } return allSubscriptions; } } public static List<CNSSubscription> getConfirmedSubscriptions(String topicArn) throws Exception { List<CNSSubscription> subscriptions = null; try { subscriptions = confirmedSubscriptionsCache.getAndSetIfNotPresent(topicArn, new SubscriptionCallable(topicArn), CMBProperties.getInstance().getCNSCacheExpiring() * 1000); } catch (CacheFullException ex1) { subscriptions = new SubscriptionCallable(topicArn).call(); } catch (Exception ex2) { subscriptions = null; } return subscriptions; } }