This project has retired. For details please refer to its Attic page.
UDDIServiceCache.java

UDDIServiceCache.java

/*
 * Copyright 2001-2011 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.apache.juddi.v3.client.mapping;

import java.lang.management.ManagementFactory;
import java.net.BindException;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.wsdl.Definition;
import javax.wsdl.WSDLException;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.namespace.QName;
import javax.xml.ws.Endpoint;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.juddi.v3.client.config.UDDIClerk;
import org.apache.juddi.v3.client.config.UDDIKeyConvention;
import org.apache.juddi.v3.client.mapping.wsdl.ReadWSDL;
import org.apache.juddi.v3.client.mapping.wsdl.WSDL2UDDI;
import org.apache.juddi.v3.client.transport.TransportException;
import org.uddi.api_v3.FindQualifiers;
import org.uddi.api_v3.FindService;
import org.uddi.api_v3.Name;
import org.uddi.sub_v3.Subscription;
import org.uddi.sub_v3.SubscriptionFilter;
import org.uddi.v3_service.UDDISubscriptionListenerPortType;

/**
 * The UDDIServiceCache maintains a cache of the service bindingTemplates of all service
 * the lookupService method is called for. 
 * 
 * To prevent the cache from going stale it
 * registers an Subscription with the UDDI server. The subscription matches any update
 * on any service. When the subscription is matched, the UDDI server will callback to
 * the UDDIClientSubscriptionListenerService which is a WebService Endpoint brought
 * up by this cache.
 * 
 * The Cache also registers an MBean which allows for managing and monitoring via JMX.
 * 
 * @author <a href="mailto:kstam@apache.org">Kurt T Stam</a>
 * @see UDDIClientSubscriptionListenerImpl
 * @see UDDIServiceCacheMBean
 * @see UDDISubscriptionListenerPortType
 * @see ServiceLocator
  */
public class UDDIServiceCache implements UDDIServiceCacheMBean {
	
	public static final String UDDI_ORG_NS                       = "urn:uddi-org:v3_service";
	public static final String UDDI_CLIENT_SUBSCRIPTION_LISTENER = "UDDIClientSubscriptionListenerService";
	public static final QName  SUBSCRIPTION_LISTENER_SERVICE_NAME= new QName(UDDI_ORG_NS, UDDI_CLIENT_SUBSCRIPTION_LISTENER);
	public static final String SUBSCRIPTION_LISTENER_PORT_NAME   = "UDDIClientSubscriptionListenerImplPort";
	public static final String DEFAULT_SUBSCRIPTION_LISTENER_URL = "http://localhost:8080/subscriptionlistener_uddi_client";
	
	private Log log = LogFactory.getLog(this.getClass());
	
	private UDDIClerk clerk = null;
	private URLLocalizer urlLocalizer = null;
	private Properties properties = null;
	
	private String subscriptionKey = null;
	private Endpoint listenerEndpoint = null;
	private URL listenerServiceUrl = null;
	private ObjectName mbeanName = null;
	
	
	private ConcurrentHashMap<String, Topology> serviceLocationMap = new ConcurrentHashMap<String, Topology>();
	
	public UDDIServiceCache() {
		super();
	}
	
	public UDDIServiceCache(UDDIClerk clerk) throws MalformedURLException {
		super();
		this.clerk = clerk;
		this.urlLocalizer = new URLLocalizerDefaultImpl(null);
		this.properties = clerk.getUDDINode().getProperties();
	}
	
	public UDDIServiceCache(UDDIClerk clerk, URL callbackBaseUrl) {
		super();
		this.clerk = clerk;
		this.urlLocalizer = new URLLocalizerDefaultImpl(callbackBaseUrl);
        this.properties = clerk.getUDDINode().getProperties();
	}

	public UDDIServiceCache(UDDIClerk clerk, URLLocalizer urlLocalizer, Properties properties) throws DatatypeConfigurationException, MalformedURLException, RemoteException, ConfigurationException, WSDLException, TransportException, Exception {
		super();
		this.clerk = clerk;
		this.urlLocalizer = urlLocalizer;
		
		Properties properties2 = clerk.getUDDINode().getProperties();
		if (properties2!=null) {
			properties2.putAll(properties);
		} else {
			properties2 = properties;
		}
		this.properties = properties2;
	}
	
	public UDDIClerk getClerk() {
		return clerk;
	}
	
	public void publishAndRegisterHttpCallbackEndpoint() throws BindException {
		if (clerk!=null && listenerEndpoint==null) {
			try {
				listenerServiceUrl = new URL(urlLocalizer.rewrite(new URL(DEFAULT_SUBSCRIPTION_LISTENER_URL)));
				WSDL2UDDI wsdl2UDDI = new WSDL2UDDI(clerk, urlLocalizer, properties);
				Definition wsdlDefinition = new ReadWSDL().readWSDL("org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListener.wsdl");
				
				String bindingKey = wsdl2UDDI.registerBusinessService(
						SUBSCRIPTION_LISTENER_SERVICE_NAME, 
						SUBSCRIPTION_LISTENER_PORT_NAME, listenerServiceUrl, wsdlDefinition).getBindingKey();
				UDDISubscriptionListenerPortType subscriptionListener = new UDDIClientSubscriptionListenerImpl(bindingKey, this);
				log.info("Bringing up a UDDIClientSubscriptionListenerImpl on Endpoint " + listenerServiceUrl.toExternalForm());
				listenerEndpoint = Endpoint.create(subscriptionListener);
				listenerEndpoint.publish(listenerServiceUrl.toExternalForm());
				
				log.info("Registering a CallbackSubscription to this endpoint using bindingKey " + bindingKey);
				registerSubscription(bindingKey);
				
			} catch (RuntimeException t) {
				listenerEndpoint = null;
				if (t.getCause() instanceof BindException) {
					throw new BindException(t.getCause().getMessage());
				} else {
					throw t;
				}
			} catch (Exception e) {
				log.error("Cannot publish or register the CallbackEndpoint " + e.getMessage(),e);
			}
		}
	}
	
	public boolean hasListener() {
		if (listenerEndpoint==null) return false;
		return listenerEndpoint.isPublished();
	}
	
	public void registerAsMBean() {
		try {
			if (clerk!=null) {
				mbeanName = new ObjectName("apache.juddi.client:type=UDDIServerCache-" + clerk.getManagerName() + "-" + clerk.getName());
			} else {
				mbeanName = new ObjectName("apache.juddi.client:type=UDDIServerCache-" + this);
			}
			MBeanServer mbeanServer = getMBeanServer();
			if (mbeanServer!=null) {
				mbeanServer.registerMBean(this, mbeanName);
			} else {
				mbeanServer=null;
			}
		} catch (Exception e) {
			log.error("Not able to register the UDDIServiceCache MBean " + e.getMessage(),e);
		}
	}
	
	public void shutdown() {
		if (subscriptionKey!=null) {
			clerk.unRegisterSubscription(subscriptionKey);
		}
		if (listenerEndpoint!=null) {
			listenerEndpoint.stop();
			WSDL2UDDI wsdl2UDDI;
			try {
				wsdl2UDDI = new WSDL2UDDI(clerk, urlLocalizer, properties);
				wsdl2UDDI.unRegisterBusinessService(
						SUBSCRIPTION_LISTENER_SERVICE_NAME, 
						SUBSCRIPTION_LISTENER_PORT_NAME, listenerServiceUrl);
			} catch (Exception e) {
				/* we did our best*/
				log.debug(e.getMessage(),e);
			}
		}
		if (mbeanName!=null) {
			try {
				MBeanServer mbeanServer = getMBeanServer();
				if (mbeanServer!=null) {
					mbeanServer.unregisterMBean(mbeanName);
				}
			} catch (Exception e) {
				/* we did our best*/
				log.debug(e.getMessage(),e);
			}
		}
	}
	
	public void removeAll() {
		log.info("Flushing the client side " + clerk.getManagerName() + " UDDIServiceCache ");
                serviceLocationMap.clear();
	}
	/**
	 * Adds or updates epr information for the given serviceKey.
	 * @param serviceKey
	 * @param topology
	 */
	public void addService(String serviceKey, Topology topology) {
		serviceLocationMap.put(serviceKey, topology);
	}
	
	public Topology lookupService(String serviceKey) {
		return serviceLocationMap.get(serviceKey);
	}
	
	public void removeService(String serviceKey) {
		serviceLocationMap.remove(serviceKey);
	}
	
        /**
         * Create a subscription for changes in any Service in the Registry
         * @throws DatatypeConfigurationException 
         * @param bindingKey the binding key
         */
	public void registerSubscription(String bindingKey) throws DatatypeConfigurationException {
		
		String subscriptionKey = UDDIKeyConvention.getSubscriptionKey(properties);
		//Create a subscription for changes in any Service in the Registry
		FindService findAllServices = new FindService();
		FindQualifiers qualifiers = new FindQualifiers();
		qualifiers.getFindQualifier().add("approximateMatch");
		
		findAllServices.setFindQualifiers(qualifiers);
		
		Name name = new Name();
		name.setValue("%");
		findAllServices.getName().add(name);
		
		SubscriptionFilter filter = new SubscriptionFilter();
		filter.setFindService(findAllServices);
		
		Subscription subscription = new Subscription();
		subscription.setSubscriptionFilter(filter);
		subscription.setBindingKey(bindingKey);
		subscription.setBrief(true);
		Duration oneMinute = DatatypeFactory.newInstance().newDuration("PT1M");
		subscription.setNotificationInterval(oneMinute);
		subscription.setSubscriptionKey(subscriptionKey);
		clerk.register(subscription);
		this.subscriptionKey = subscriptionKey;
	}

	public Map<String, Topology> getServiceCacheMap() {
		return serviceLocationMap;
	}
	
	private MBeanServer getMBeanServer() {
        MBeanServer mbserver = null;
        ArrayList<MBeanServer> mbservers = MBeanServerFactory.findMBeanServer(null);
        if (mbservers.size() > 0) {
            mbserver = (MBeanServer) mbservers.get(0);
        }
        if (mbserver != null && log.isDebugEnabled()) {
        	log.debug("Found MBean server");
        } else {
        	mbserver = ManagementFactory.getPlatformMBeanServer();
        }
        return mbserver;
    }

	/** Method callable from the mbean */
	@Override
	public int getServiceCacheSize() {
		return serviceLocationMap.size();
	}

	/** Method callable from the mbean */
	@Override
	public Set<String> getCacheEntries() {
		return serviceLocationMap.keySet();
	}

	/** Method callable from the mbean */
	@Override
	public void resetCache() {
		serviceLocationMap.clear();
	}
	
	
	
	
}