View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.ksb.impl.registry.diff;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import javax.xml.namespace.QName;
24  
25  import org.apache.log4j.Logger;
26  import org.kuali.rice.ksb.api.registry.ServiceInfo;
27  import org.kuali.rice.ksb.api.registry.ServiceRegistry;
28  import org.kuali.rice.ksb.impl.bus.LocalService;
29  import org.kuali.rice.ksb.impl.bus.RemoteService;
30  
31  /**
32   * Default implementation of the {@link ServiceRegistryDiffCalculator} which calculates
33   * differences between client service bus state and service registry state.
34   * 
35   * @author Kuali Rice Team (rice.collab@kuali.org)
36   *
37   */
38  public class ServiceRegistryDiffCalculatorImpl implements ServiceRegistryDiffCalculator {
39  
40  	private static final Logger LOG = Logger.getLogger(ServiceRegistryDiffCalculatorImpl.class);
41  	
42  	private ServiceRegistry serviceRegistry;
43  	
44  	public void setServiceRegistry(ServiceRegistry serviceRegistry) {
45  		this.serviceRegistry = serviceRegistry;
46  	}
47  	
48  	@Override
49  	public CompleteServiceDiff diffServices(String instanceId, List<LocalService> localServices, List<RemoteService> clientRegistryCache) {
50  		List<ServiceInfo> allRegistryServicesForInstance = serviceRegistry.getAllServicesForInstance(instanceId);
51  		LocalServicesDiff localServicesDiff = calculateLocalServicesDiff(allRegistryServicesForInstance, instanceId, localServices);
52  		List<ServiceInfo> allRegistryServices = serviceRegistry.getAllOnlineServices();
53  		RemoteServicesDiff remoteServicesDiff = calculateRemoteServicesDiff(allRegistryServices, clientRegistryCache);
54  		return new CompleteServiceDiff(localServicesDiff, remoteServicesDiff);
55  	}
56  	
57  	protected LocalServicesDiff calculateLocalServicesDiff(List<ServiceInfo> allRegistryServicesForInstance, String instanceId, List<LocalService> localServices) {
58  		
59  		List<ServiceInfo> servicesToRemoveFromRegistry = new ArrayList<ServiceInfo>();
60  		List<LocalService> localServicesToPublish = new ArrayList<LocalService>();
61  		Map<LocalService, ServiceInfo> localServicesToUpdate = new HashMap<LocalService, ServiceInfo>();
62  		
63  		Map<QName, LocalService> localServiceIndex = indexLocalServices(instanceId, localServices);
64  		for (ServiceInfo serviceInfo : allRegistryServicesForInstance) {
65  			// first validate that the service has a valid instance id
66  			if (!instanceId.equals(serviceInfo.getInstanceId())) {
67  				throw new IllegalArgumentException("ServiceInfo given for local service diff does not have a valid instance id.  Should have been '" + instanceId + "' but was '" + serviceInfo.getInstanceId() + "'");
68  			}
69  			LocalService localService = localServiceIndex.get(serviceInfo.getServiceName());
70  			if (localService == null) {
71  				// this means the registry has the service but there is no local service, it has been unregistered
72  				servicesToRemoveFromRegistry.add(serviceInfo);
73  			} else {
74  				// if the LocalService is not null, that means that it exists but it may have changed, or this may be the first time the service
75  				// is being published upon startup in which case it's service id will be null
76  				if (!localService.getServiceEndpoint().getInfo().equals(serviceInfo)) {
77  					// if the service infos don't match, that means we need to re-publish our current copy of the local service
78  					localServicesToUpdate.put(localService, serviceInfo);
79  				}
80  				// whether or not it matches, remove it from the index
81  				localServiceIndex.remove(serviceInfo.getServiceName());
82  			}
83  		}
84  		// what's left in the localServiceIndex will be services that weren't in the registry at all, they need to be published
85  		localServicesToPublish.addAll(localServiceIndex.values());
86  		
87  		if (LOG.isDebugEnabled()) {
88  			LOG.info("For instance '" + instanceId + "', found " + servicesToRemoveFromRegistry.size() + " services to remove from registry, "+
89  				localServicesToPublish.size() + " local services to publish");
90  		}
91  		
92  		return new LocalServicesDiff(servicesToRemoveFromRegistry, localServicesToPublish, localServicesToUpdate);
93  				
94  	}
95  	
96  	private Map<QName, LocalService> indexLocalServices(String instanceId, List<LocalService> localServices) {
97  		Map<QName, LocalService> localServiceIndex = new HashMap<QName, LocalService>(localServices.size());
98  		for (LocalService localService : localServices) {
99  			String localServiceInstanceId = localService.getServiceEndpoint().getInfo().getInstanceId(); 
100 			if (!instanceId.equals(localServiceInstanceId)) {
101 				throw new IllegalStateException("Instance id of local service (" + localServiceInstanceId + ") does not match instance id given to the diff calculator (" + instanceId + ")");
102 			}
103 			localServiceIndex.put(localService.getServiceName(), localService);
104 		}
105 		return localServiceIndex;
106 	}
107 	
108 	protected List<ServiceInfo> filterServicesForInstance(String instanceId, List<ServiceInfo> allServices) {
109 		List<ServiceInfo> filteredServices = new ArrayList<ServiceInfo>();
110 		for (ServiceInfo serviceInfo : allServices) {
111 			if (instanceId.equals(serviceInfo.getInstanceId())) {
112 				filteredServices.add(serviceInfo);
113 			}
114 		}
115 		return filteredServices;
116 	}
117 	
118 	protected RemoteServicesDiff calculateRemoteServicesDiff(List<ServiceInfo> allRegistryServices, List<RemoteService> clientRegistryCache) {
119 		
120 		List<ServiceInfo> servicesToAddToClientRegistryCache = new ArrayList<ServiceInfo>(allRegistryServices);
121 		List<RemoteService> servicesToRemoveFromClientRegistryCache = new ArrayList<RemoteService>();
122 		
123 		Map<String, ServiceInfo> indexedRegistryServices = indexRegistryServices(allRegistryServices);
124 		for (RemoteService remoteService : clientRegistryCache) {
125 			ServiceInfo indexedRegistryService = indexedRegistryServices.get(remoteService.getServiceInfo().getServiceId());
126 			if (indexedRegistryService == null) {
127 				servicesToRemoveFromClientRegistryCache.add(remoteService);
128 			} else {
129 				if (!remoteService.getServiceInfo().getChecksum().equals(indexedRegistryService.getChecksum())) {
130 					servicesToRemoveFromClientRegistryCache.add(remoteService);
131 					
132 				} else {
133 					servicesToAddToClientRegistryCache.remove(remoteService.getServiceInfo());
134 				}
135 			}
136 		}
137 		
138 		if (LOG.isDebugEnabled()) {
139 			LOG.debug("For instance found " + servicesToRemoveFromClientRegistryCache.size() + " services to remove from client registry cache, "+
140 				servicesToAddToClientRegistryCache.size() + " services to add to client registry cache");
141 		}
142 		
143 		return new RemoteServicesDiff(servicesToAddToClientRegistryCache, servicesToRemoveFromClientRegistryCache);
144 	}
145 	
146 	private Map<String, ServiceInfo> indexRegistryServices(List<ServiceInfo> allRegistryServices) {
147 		Map<String, ServiceInfo> indexedRegistryServices = new HashMap<String, ServiceInfo>(allRegistryServices.size());
148 		for (ServiceInfo serviceInfo : allRegistryServices) {
149 			indexedRegistryServices.put(serviceInfo.getServiceId(), serviceInfo);
150 		}
151 		return indexedRegistryServices;
152 	}
153 
154 }