View Javadoc
1   /*
2    * Copyright 2001-2011 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *      http://www.apache.org/licenses/LICENSE-2.0
8    * 
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.apache.juddi.v3.client.mapping;
16  
17  import java.lang.management.ManagementFactory;
18  import java.net.BindException;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.rmi.RemoteException;
22  import java.util.ArrayList;
23  import java.util.Map;
24  import java.util.Properties;
25  import java.util.Set;
26  import java.util.concurrent.ConcurrentHashMap;
27  
28  import javax.management.MBeanServer;
29  import javax.management.MBeanServerFactory;
30  import javax.management.ObjectName;
31  import javax.wsdl.Definition;
32  import javax.wsdl.WSDLException;
33  import javax.xml.datatype.DatatypeConfigurationException;
34  import javax.xml.datatype.DatatypeFactory;
35  import javax.xml.datatype.Duration;
36  import javax.xml.namespace.QName;
37  import javax.xml.ws.Endpoint;
38  
39  import org.apache.commons.configuration.ConfigurationException;
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  import org.apache.juddi.v3.client.config.UDDIClerk;
43  import org.apache.juddi.v3.client.config.UDDIKeyConvention;
44  import org.apache.juddi.v3.client.mapping.wsdl.ReadWSDL;
45  import org.apache.juddi.v3.client.mapping.wsdl.WSDL2UDDI;
46  import org.apache.juddi.v3.client.transport.TransportException;
47  import org.uddi.api_v3.FindQualifiers;
48  import org.uddi.api_v3.FindService;
49  import org.uddi.api_v3.Name;
50  import org.uddi.sub_v3.Subscription;
51  import org.uddi.sub_v3.SubscriptionFilter;
52  import org.uddi.v3_service.UDDISubscriptionListenerPortType;
53  
54  /**
55   * The UDDIServiceCache maintains a cache of the service bindingTemplates of all service
56   * the lookupService method is called for. 
57   * 
58   * To prevent the cache from going stale it
59   * registers an Subscription with the UDDI server. The subscription matches any update
60   * on any service. When the subscription is matched, the UDDI server will callback to
61   * the UDDIClientSubscriptionListenerService which is a WebService Endpoint brought
62   * up by this cache.
63   * 
64   * The Cache also registers an MBean which allows for managing and monitoring via JMX.
65   * 
66   * @author <a href="mailto:kstam@apache.org">Kurt T Stam</a>
67   * @see UDDIClientSubscriptionListenerImpl
68   * @see UDDIServiceCacheMBean
69   * @see UDDISubscriptionListenerPortType
70   * @see ServiceLocator
71    */
72  public class UDDIServiceCache implements UDDIServiceCacheMBean {
73  	
74  	public static final String UDDI_ORG_NS                       = "urn:uddi-org:v3_service";
75  	public static final String UDDI_CLIENT_SUBSCRIPTION_LISTENER = "UDDIClientSubscriptionListenerService";
76  	public static final QName  SUBSCRIPTION_LISTENER_SERVICE_NAME= new QName(UDDI_ORG_NS, UDDI_CLIENT_SUBSCRIPTION_LISTENER);
77  	public static final String SUBSCRIPTION_LISTENER_PORT_NAME   = "UDDIClientSubscriptionListenerImplPort";
78  	public static final String DEFAULT_SUBSCRIPTION_LISTENER_URL = "http://localhost:8080/subscriptionlistener_uddi_client";
79  	
80  	private Log log = LogFactory.getLog(this.getClass());
81  	
82  	private UDDIClerk clerk = null;
83  	private URLLocalizer urlLocalizer = null;
84  	private Properties properties = null;
85  	
86  	private String subscriptionKey = null;
87  	private Endpoint listenerEndpoint = null;
88  	private URL listenerServiceUrl = null;
89  	private ObjectName mbeanName = null;
90  	
91  	
92  	private ConcurrentHashMap<String, Topology> serviceLocationMap = new ConcurrentHashMap<String, Topology>();
93  	
94  	public UDDIServiceCache() {
95  		super();
96  	}
97  	
98  	public UDDIServiceCache(UDDIClerk clerk) throws MalformedURLException {
99  		super();
100 		this.clerk = clerk;
101 		this.urlLocalizer = new URLLocalizerDefaultImpl(null);
102 		this.properties = clerk.getUDDINode().getProperties();
103 	}
104 	
105 	public UDDIServiceCache(UDDIClerk clerk, URL callbackBaseUrl) {
106 		super();
107 		this.clerk = clerk;
108 		this.urlLocalizer = new URLLocalizerDefaultImpl(callbackBaseUrl);
109         this.properties = clerk.getUDDINode().getProperties();
110 	}
111 
112 	public UDDIServiceCache(UDDIClerk clerk, URLLocalizer urlLocalizer, Properties properties) throws DatatypeConfigurationException, MalformedURLException, RemoteException, ConfigurationException, WSDLException, TransportException, Exception {
113 		super();
114 		this.clerk = clerk;
115 		this.urlLocalizer = urlLocalizer;
116 		
117 		Properties properties2 = clerk.getUDDINode().getProperties();
118 		if (properties2!=null) {
119 			properties2.putAll(properties);
120 		} else {
121 			properties2 = properties;
122 		}
123 		this.properties = properties2;
124 	}
125 	
126 	public UDDIClerk getClerk() {
127 		return clerk;
128 	}
129 	
130 	public void publishAndRegisterHttpCallbackEndpoint() throws BindException {
131 		if (clerk!=null && listenerEndpoint==null) {
132 			try {
133 				listenerServiceUrl = new URL(urlLocalizer.rewrite(new URL(DEFAULT_SUBSCRIPTION_LISTENER_URL)));
134 				WSDL2UDDI wsdl2UDDI = new WSDL2UDDI(clerk, urlLocalizer, properties);
135 				Definition wsdlDefinition = new ReadWSDL().readWSDL("org/apache/juddi/v3/client/mapping/UDDIClientSubscriptionListener.wsdl");
136 				
137 				String bindingKey = wsdl2UDDI.registerBusinessService(
138 						SUBSCRIPTION_LISTENER_SERVICE_NAME, 
139 						SUBSCRIPTION_LISTENER_PORT_NAME, listenerServiceUrl, wsdlDefinition).getBindingKey();
140 				UDDISubscriptionListenerPortType subscriptionListener = new UDDIClientSubscriptionListenerImpl(bindingKey, this);
141 				log.info("Bringing up a UDDIClientSubscriptionListenerImpl on Endpoint " + listenerServiceUrl.toExternalForm());
142 				listenerEndpoint = Endpoint.create(subscriptionListener);
143 				listenerEndpoint.publish(listenerServiceUrl.toExternalForm());
144 				
145 				log.info("Registering a CallbackSubscription to this endpoint using bindingKey " + bindingKey);
146 				registerSubscription(bindingKey);
147 				
148 			} catch (RuntimeException t) {
149 				listenerEndpoint = null;
150 				if (t.getCause() instanceof BindException) {
151 					throw new BindException(t.getCause().getMessage());
152 				} else {
153 					throw t;
154 				}
155 			} catch (Exception e) {
156 				log.error("Cannot publish or register the CallbackEndpoint " + e.getMessage(),e);
157 			}
158 		}
159 	}
160 	
161 	public boolean hasListener() {
162 		if (listenerEndpoint==null) return false;
163 		return listenerEndpoint.isPublished();
164 	}
165 	
166 	public void registerAsMBean() {
167 		try {
168 			if (clerk!=null) {
169 				mbeanName = new ObjectName("apache.juddi.client:type=UDDIServerCache-" + clerk.getManagerName() + "-" + clerk.getName());
170 			} else {
171 				mbeanName = new ObjectName("apache.juddi.client:type=UDDIServerCache-" + this);
172 			}
173 			MBeanServer mbeanServer = getMBeanServer();
174 			if (mbeanServer!=null) {
175 				mbeanServer.registerMBean(this, mbeanName);
176 			} else {
177 				mbeanServer=null;
178 			}
179 		} catch (Exception e) {
180 			log.error("Not able to register the UDDIServiceCache MBean " + e.getMessage(),e);
181 		}
182 	}
183 	
184 	public void shutdown() {
185 		if (subscriptionKey!=null) {
186 			clerk.unRegisterSubscription(subscriptionKey);
187 		}
188 		if (listenerEndpoint!=null) {
189 			listenerEndpoint.stop();
190 			WSDL2UDDI wsdl2UDDI;
191 			try {
192 				wsdl2UDDI = new WSDL2UDDI(clerk, urlLocalizer, properties);
193 				wsdl2UDDI.unRegisterBusinessService(
194 						SUBSCRIPTION_LISTENER_SERVICE_NAME, 
195 						SUBSCRIPTION_LISTENER_PORT_NAME, listenerServiceUrl);
196 			} catch (Exception e) {
197 				/* we did our best*/
198 				log.debug(e.getMessage(),e);
199 			}
200 		}
201 		if (mbeanName!=null) {
202 			try {
203 				MBeanServer mbeanServer = getMBeanServer();
204 				if (mbeanServer!=null) {
205 					mbeanServer.unregisterMBean(mbeanName);
206 				}
207 			} catch (Exception e) {
208 				/* we did our best*/
209 				log.debug(e.getMessage(),e);
210 			}
211 		}
212 	}
213 	
214 	public void removeAll() {
215 		log.info("Flushing the client side " + clerk.getManagerName() + " UDDIServiceCache ");
216                 serviceLocationMap.clear();
217 	}
218 	/**
219 	 * Adds or updates epr information for the given serviceKey.
220 	 * @param serviceKey
221 	 * @param topology
222 	 */
223 	public void addService(String serviceKey, Topology topology) {
224 		serviceLocationMap.put(serviceKey, topology);
225 	}
226 	
227 	public Topology lookupService(String serviceKey) {
228 		return serviceLocationMap.get(serviceKey);
229 	}
230 	
231 	public void removeService(String serviceKey) {
232 		serviceLocationMap.remove(serviceKey);
233 	}
234 	
235         /**
236          * Create a subscription for changes in any Service in the Registry
237          * @throws DatatypeConfigurationException 
238          * @param bindingKey the binding key
239          */
240 	public void registerSubscription(String bindingKey) throws DatatypeConfigurationException {
241 		
242 		String subscriptionKey = UDDIKeyConvention.getSubscriptionKey(properties);
243 		//Create a subscription for changes in any Service in the Registry
244 		FindService findAllServices = new FindService();
245 		FindQualifiers qualifiers = new FindQualifiers();
246 		qualifiers.getFindQualifier().add("approximateMatch");
247 		
248 		findAllServices.setFindQualifiers(qualifiers);
249 		
250 		Name name = new Name();
251 		name.setValue("%");
252 		findAllServices.getName().add(name);
253 		
254 		SubscriptionFilter filter = new SubscriptionFilter();
255 		filter.setFindService(findAllServices);
256 		
257 		Subscription subscription = new Subscription();
258 		subscription.setSubscriptionFilter(filter);
259 		subscription.setBindingKey(bindingKey);
260 		subscription.setBrief(true);
261 		Duration oneMinute = DatatypeFactory.newInstance().newDuration("PT1M");
262 		subscription.setNotificationInterval(oneMinute);
263 		subscription.setSubscriptionKey(subscriptionKey);
264 		clerk.register(subscription);
265 		this.subscriptionKey = subscriptionKey;
266 	}
267 
268 	public Map<String, Topology> getServiceCacheMap() {
269 		return serviceLocationMap;
270 	}
271 	
272 	private MBeanServer getMBeanServer() {
273         MBeanServer mbserver = null;
274         ArrayList<MBeanServer> mbservers = MBeanServerFactory.findMBeanServer(null);
275         if (mbservers.size() > 0) {
276             mbserver = (MBeanServer) mbservers.get(0);
277         }
278         if (mbserver != null && log.isDebugEnabled()) {
279         	log.debug("Found MBean server");
280         } else {
281         	mbserver = ManagementFactory.getPlatformMBeanServer();
282         }
283         return mbserver;
284     }
285 
286 	/** Method callable from the mbean */
287 	@Override
288 	public int getServiceCacheSize() {
289 		return serviceLocationMap.size();
290 	}
291 
292 	/** Method callable from the mbean */
293 	@Override
294 	public Set<String> getCacheEntries() {
295 		return serviceLocationMap.keySet();
296 	}
297 
298 	/** Method callable from the mbean */
299 	@Override
300 	public void resetCache() {
301 		serviceLocationMap.clear();
302 	}
303 	
304 	
305 	
306 	
307 }