/* * Copyright 2015 The Apache Software Foundation. * * 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 org.wso2.carbon.registry.event.core.internal.subscription.registry; import org.apache.axis2.databinding.utils.ConverterUtil; import org.wso2.carbon.registry.event.core.exception.EventBrokerConfigurationException; import org.wso2.carbon.registry.event.core.exception.EventBrokerException; import org.wso2.carbon.registry.event.core.internal.util.EventBrokerHolder; import org.wso2.carbon.registry.event.core.internal.util.JavaUtil; import org.wso2.carbon.registry.event.core.subscription.Subscription; import org.wso2.carbon.registry.event.core.subscription.SubscriptionManager; import org.wso2.carbon.registry.event.core.util.EventBrokerConstants; import org.wso2.carbon.registry.core.RegistryConstants; import org.wso2.carbon.registry.core.Resource; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.registry.core.session.UserRegistry; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Properties; /** * Subscription manager implementation using registry. * <p/> * This subscription manager stores the subscriptions in the registry patch calculated as given * subscriptionStoragePath(read from the configuration file) + "/" + topicName + * "/system.subscriptions/" + subscriptionID * <p/> * In-order to get the subscriptions quickly it also stores the subscription details in a resource * called topicIndex. * <p/> * Topic index resource contains subscriptionID , topicName. * <p/> * When getting the subscriptions we calculate the subscription stored path using above two * parameters. */ public class RegistrySubscriptionManager implements SubscriptionManager { /** * Star wildcard - can substitute for exactly one word. */ private static final char STAR_WILDCARD = '*'; /** * Hash wildcard - can substitute for zero or more words. */ private static final char HASH_WILDCARD = '#'; /** * Registry service to access the registry. this is get from the EBBrokerHolder */ private RegistryService registryService; /** * Root patch which used to start the subscription related details. */ private String topicStoragePath; /** * Topic index resource path. */ private String indexStoragePath; /** * Adds topic storage path and index storage path to user registry. * * @param topicStoragePath topic storage path. the path where topics will be stored. * @param indexStoragePath index storage path. * @throws EventBrokerConfigurationException */ public RegistrySubscriptionManager(String topicStoragePath, String indexStoragePath) throws EventBrokerConfigurationException { this.registryService = EventBrokerHolder.getInstance().getRegistryService(); this.topicStoragePath = topicStoragePath; this.indexStoragePath = indexStoragePath; // creates the the subscription index // when creating subscriptions we going to add entries to this this resource try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); //create the topic storage path if it does not exists if (!userRegistry.resourceExists(this.topicStoragePath)) { userRegistry.put(this.topicStoragePath, userRegistry.newCollection()); } // we need to create the index here only it is not exists. if (!userRegistry.resourceExists(this.indexStoragePath)) { userRegistry.put(this.indexStoragePath, userRegistry.newResource()); } } catch (RegistryException e) { throw new EventBrokerConfigurationException("Cannot access the registry ", e); } } /** * {@inheritDoc} */ @Override public void addSubscription(Subscription subscription) throws EventBrokerException { try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); String resourcePath = getResourcePath(subscription.getId(), subscription.getTopicName()); Resource resource = userRegistry.newResource(); resource.setProperty(EventBrokerConstants.EB_RES_SUBSCRIPTION_URL, subscription .getEventSinkURL()); resource.setProperty(EventBrokerConstants.EB_RES_EVENT_DISPATCHER_NAME, subscription .getEventDispatcherName()); if (subscription.getExpires() != null) { resource.setProperty(EventBrokerConstants.EB_RES_EXPIRS, ConverterUtil .convertToString(subscription .getExpires())); } resource.setProperty(EventBrokerConstants.EB_RES_OWNER, subscription.getOwner()); resource.setProperty(EventBrokerConstants.EB_RES_TOPIC_NAME, subscription .getTopicName()); resource.setProperty(EventBrokerConstants.EB_RES_CREATED_TIME, System.currentTimeMillis() + ""); resource.setProperty(EventBrokerConstants.EB_RES_MODE, JavaUtil .getSubscriptionMode(subscription .getTopicName())); //set the other properties of the subscription. Map<String, String> properties = subscription.getProperties(); for (String key : properties.keySet()) { resource.setProperty(key, properties.get(key)); } userRegistry.put(resourcePath, resource); // add the subscription index String fullPath = this.indexStoragePath; Resource topicIndexResource; if (userRegistry.resourceExists(fullPath)) { topicIndexResource = userRegistry.get(fullPath); topicIndexResource.addProperty(subscription.getId(), subscription.getTopicName()); } else { topicIndexResource = userRegistry.newResource(); topicIndexResource.addProperty(subscription.getId(), subscription.getTopicName()); } userRegistry.put(fullPath, topicIndexResource); } catch (RegistryException e) { throw new EventBrokerException("Cannot save to registry ", e); } } /** * Calculates the resource stored path using subscription id and the topic name. * * @param subscriptionID the subscription ID * @param topicName topic name * @return the resource path */ private String getResourcePath(String subscriptionID, String topicName) { String resourcePath = this.topicStoragePath; // first convert the . to / topicName = topicName.replaceAll("\\.", RegistryConstants.PATH_SEPARATOR); if (!topicName.startsWith(RegistryConstants.PATH_SEPARATOR)) { resourcePath = resourcePath + RegistryConstants.PATH_SEPARATOR; } // this topic name can have # and * marks if the user wants to subscribes to the // child topics as well. but we consider the topic here as the topic name just before any // special character. // eg. if topic name is myTopic/*/* then topic name is myTopic if (topicName.indexOf(STAR_WILDCARD) > -1) { topicName = topicName.substring(0, topicName.indexOf(STAR_WILDCARD)); } else { if (topicName.indexOf(HASH_WILDCARD) > -1) { topicName = topicName.substring(0, topicName.indexOf(HASH_WILDCARD)); } } resourcePath = resourcePath + topicName; if (!resourcePath.endsWith(RegistryConstants.PATH_SEPARATOR)) { resourcePath = resourcePath + RegistryConstants.PATH_SEPARATOR; } resourcePath = resourcePath + EventBrokerConstants.EB_CONF_WS_SUBSCRIPTION_COLLECTION_NAME + RegistryConstants.PATH_SEPARATOR + subscriptionID; return resourcePath; } /** * Calculates the JMS subscription stored path for a WSSubscription using subscription id and * the topic name. * * @param subscriptionID the subscription ID * @param topicName the topic name * @return the JMS subscription resource path for a subscription */ private String getJMSSubResourcePath(String subscriptionID, String topicName) { String resourcePath = this.topicStoragePath; // first convert the . to / topicName = topicName.replaceAll("\\.", RegistryConstants.PATH_SEPARATOR); if (!topicName.startsWith(RegistryConstants.PATH_SEPARATOR)) { resourcePath = resourcePath + RegistryConstants.PATH_SEPARATOR; } // this topic name can have # and * marks if the user wants to subscribes to the // child topics as well. but we consider the topic here as the topic name just before any // special character. // eg. if topic name is myTopic/*/* then topic name is myTopic if (topicName.indexOf(STAR_WILDCARD) > -1) { topicName = topicName.substring(0, topicName.indexOf(STAR_WILDCARD)); } else if (topicName.indexOf(HASH_WILDCARD) > -1) { topicName = topicName.substring(0, topicName.indexOf(HASH_WILDCARD)); } resourcePath = resourcePath + topicName; if (!resourcePath.endsWith(RegistryConstants.PATH_SEPARATOR)) { resourcePath = resourcePath + RegistryConstants.PATH_SEPARATOR; } resourcePath = resourcePath + (EventBrokerConstants.EB_CONF_JMS_SUBSCRIPTION_COLLECTION_NAME + RegistryConstants.PATH_SEPARATOR + subscriptionID); return resourcePath; } /** * {@inheritDoc} */ @Override public List<Subscription> getAllSubscriptions() throws EventBrokerException { List<Subscription> subscriptions = new ArrayList<Subscription>(); try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); if (userRegistry.resourceExists(this.indexStoragePath)) { Resource topicIndexResource = userRegistry.get(this.indexStoragePath); Properties savedSubscriptions = topicIndexResource.getProperties(); Resource subscriptionResource; Subscription subscription; String subscriptionID; String topicName; for (Enumeration e = savedSubscriptions.propertyNames(); e.hasMoreElements(); ) { subscriptionID = (String) e.nextElement(); // when the registry is remotely mount to another registry. then registry // automatically added some properties stays with registry we need to skip them. topicName = topicIndexResource.getProperty(subscriptionID); String resourcePath = getResourcePath(subscriptionID, topicName); if (!subscriptionID.startsWith("registry") && userRegistry.resourceExists(resourcePath)) { subscriptionResource = userRegistry.get(resourcePath); subscription = JavaUtil.getSubscription(subscriptionResource); subscription.setId(subscriptionID); subscription.setTopicName(topicName); subscription.setTenantId(EventBrokerHolder.getInstance().getTenantId()); subscriptions.add(subscription); } } } } catch (RegistryException e) { throw new EventBrokerException("Cannot access the registry ", e); } return subscriptions; } /** * {@inheritDoc} */ @Override public Subscription getSubscription(String id) throws EventBrokerException { try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); Resource topicIndexResource = userRegistry.get(this.indexStoragePath); String subscriptionPath = getResourcePath(id, topicIndexResource.getProperty(id)); if (subscriptionPath != null && userRegistry.resourceExists(subscriptionPath)) { Resource subscriptionResource = userRegistry.get(subscriptionPath); Subscription subscription = JavaUtil.getSubscription(subscriptionResource); subscription.setTenantId(EventBrokerHolder.getInstance().getTenantId()); return subscription; } else { return null; } } catch (RegistryException e) { throw new EventBrokerException("Cannot access the registry ", e); } } /** * {@inheritDoc} */ @Override public void renewSubscription(Subscription subscription) throws EventBrokerException { try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); Resource topicIndexResource = userRegistry.get(this.indexStoragePath); String topicName = topicIndexResource.getProperty(subscription.getId()); String subscriptionPath = getResourcePath(subscription.getId(), topicName); if (subscriptionPath != null) { Resource subscriptionResource = userRegistry.get(subscriptionPath); // Set the expires property only if it has been set again. if (subscription.getExpires() != null) { subscriptionResource.setProperty( EventBrokerConstants.EB_RES_EXPIRS, ConverterUtil.convertToString(subscription.getExpires())); } // There might be updated subscription properties. Set them too. Subscription currentSubscription = JavaUtil.getSubscription(subscriptionResource); //Since the subscription renewal does not include name parameters setting up them //https://wso2.org/jira/browse/ESBJAVA-1021 subscription.setTopicName(currentSubscription.getTopicName()); Map<String, String> properties = currentSubscription.getProperties(); for (String key : properties.keySet()) { subscriptionResource.removeProperty(key); } properties = subscription.getProperties(); for (String key : properties.keySet()) { subscriptionResource.setProperty(key, properties.get(key)); } userRegistry.put(subscriptionPath, subscriptionResource); } else { throw new EventBrokerException("Cannot find the resource to the subscription with" + " id " + subscription.getId()); } } catch (RegistryException e) { throw new EventBrokerException("Cannot access the registry ", e); } } /** * {@inheritDoc} */ @Override public void unSubscribe(String subscriptionID) throws EventBrokerException { try { UserRegistry userRegistry = this.registryService.getGovernanceSystemRegistry(EventBrokerHolder.getInstance() .getTenantId()); String fullPath = this.indexStoragePath; if (userRegistry.resourceExists(fullPath)) { Resource topicIndexResource = userRegistry.get(fullPath); String topicName = topicIndexResource.getProperty(subscriptionID); // delete the subscriptions resource // if the registry is read only there can be situations where the the subscriptions // is not saved to registry and hence the topic name if (topicName != null) { String resourcePath = getResourcePath(subscriptionID, topicName); if (userRegistry.resourceExists(resourcePath)) { userRegistry.delete(resourcePath); } String jMSResourcePath = getJMSSubResourcePath(subscriptionID, topicName); if (userRegistry.resourceExists(jMSResourcePath)) { userRegistry.delete(jMSResourcePath); } } topicIndexResource.removeProperty(subscriptionID); userRegistry.put(fullPath, topicIndexResource); } } catch (RegistryException e) { throw new EventBrokerException("Cannot access the registry ", e); } } /** * {@inheritDoc} */ @Override public String getTopicStoragePath() throws EventBrokerException { return topicStoragePath; } }