/* | |
* 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(); | |
} | |
} |