View Javadoc

1   /**
2    * Copyright 2005-2014 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.bus.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.commons.collections.MapUtils;
26  import org.apache.log4j.Logger;
27  import org.kuali.rice.ksb.api.registry.ServiceInfo;
28  import org.kuali.rice.ksb.api.registry.ServiceRegistry;
29  import org.kuali.rice.ksb.impl.bus.LocalService;
30  import org.kuali.rice.ksb.impl.bus.RemoteService;
31  
32  /**
33   * Default implementation of the {@link ServiceRegistryDiffCalculator} which calculates
34   * differences between client service bus state and service registry state.
35   * 
36   * @author Kuali Rice Team (rice.collab@kuali.org)
37   *
38   */
39  public class ServiceRegistryDiffCalculatorImpl implements ServiceRegistryDiffCalculator {
40  
41  	private static final Logger LOG = Logger.getLogger(ServiceRegistryDiffCalculatorImpl.class);
42  	
43  	private ServiceRegistry serviceRegistry;
44  	
45  	public void setServiceRegistry(ServiceRegistry serviceRegistry) {
46  		this.serviceRegistry = serviceRegistry;
47  	}
48  	
49  	@Override
50  	public CompleteServiceDiff diffServices(String instanceId, List<LocalService> localServices, List<RemoteService> clientRegistryCache) {
51          List<ServiceInfo> allRegistryServices = serviceRegistry.getAllOnlineServices();
52          List<ServiceInfo> allRegistryServicesForInstance = serviceRegistry.getAllServicesForInstance(instanceId);
53  		LocalServicesDiff localServicesDiff = calculateLocalServicesDiff(allRegistryServicesForInstance, instanceId, localServices);
54  		RemoteServicesDiff remoteServicesDiff = calculateRemoteServicesDiff(allRegistryServices, clientRegistryCache);
55  		return new CompleteServiceDiff(localServicesDiff, remoteServicesDiff);
56  	}
57  
58  	protected LocalServicesDiff calculateLocalServicesDiff(List<ServiceInfo> allRegistryServicesForInstance, String instanceId, List<LocalService> localServices) {
59  		
60  		List<ServiceInfo> servicesToRemoveFromRegistry = new ArrayList<ServiceInfo>();
61  		List<LocalService> localServicesToPublish = new ArrayList<LocalService>();
62  		Map<LocalService, ServiceInfo> localServicesToUpdate = new HashMap<LocalService, ServiceInfo>();
63  		
64  		Map<QName, LocalService> localServiceIndex = indexLocalServices(instanceId, localServices);
65  		for (ServiceInfo serviceInfo : allRegistryServicesForInstance) {
66  			// first validate that the service has a valid instance id
67  			if (!instanceId.equals(serviceInfo.getInstanceId())) {
68                  StringBuffer errorMessage = new StringBuffer("ServiceInfo given for local service diff does not have a valid instance id.  Should have been '" + instanceId + "' but was '" + serviceInfo.getInstanceId() + "'");
69                  if (serviceInfo.getInstanceId() == null) {
70                      errorMessage.append(" Null instanceIds can be the result of multiple asm.jars or none in the classpath.");
71                  }
72  				throw new IllegalArgumentException(errorMessage.toString());
73  			}
74  			LocalService localService = localServiceIndex.get(serviceInfo.getServiceName());
75  			if (localService == null) {
76  				// this means the registry has the service but there is no local service, it has been unregistered
77  				servicesToRemoveFromRegistry.add(serviceInfo);
78  			} else {
79  				// 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
80  				// is being published upon startup in which case it's service id will be null
81  				if (!localService.getServiceEndpoint().getInfo().equals(serviceInfo)) {
82  					// if the service infos don't match, that means we need to re-publish our current copy of the local service
83  					localServicesToUpdate.put(localService, serviceInfo);
84  				}
85  				// whether or not it matches, remove it from the index
86  				localServiceIndex.remove(serviceInfo.getServiceName());
87  			}
88  		}
89  		// what's left in the localServiceIndex will be services that weren't in the registry at all, they need to be published
90  		localServicesToPublish.addAll(localServiceIndex.values());
91  		
92  		if (LOG.isDebugEnabled()) {
93  			LOG.info("For instance '" + instanceId + "', found " + servicesToRemoveFromRegistry.size() + " services to remove from registry, "+
94  				localServicesToPublish.size() + " local services to publish");
95  		}
96  		
97  		return new LocalServicesDiff(servicesToRemoveFromRegistry, localServicesToPublish, localServicesToUpdate);
98  				
99  	}
100 	
101 	private Map<QName, LocalService> indexLocalServices(String instanceId, List<LocalService> localServices) {
102 		Map<QName, LocalService> localServiceIndex = new HashMap<QName, LocalService>(localServices.size());
103 		for (LocalService localService : localServices) {
104 			String localServiceInstanceId = localService.getServiceEndpoint().getInfo().getInstanceId(); 
105 			if (!instanceId.equals(localServiceInstanceId)) {
106 				throw new IllegalStateException("Instance id of local service (" + localServiceInstanceId + ") does not match instance id given to the diff calculator (" + instanceId + ")");
107 			}
108 			localServiceIndex.put(localService.getServiceName(), localService);
109 		}
110 		return localServiceIndex;
111 	}
112 		
113 	protected RemoteServicesDiff calculateRemoteServicesDiff(List<ServiceInfo> allRegistryServices, List<RemoteService> clientRegistryCache) {
114 
115         Map<String, ServiceInfo> indexedRegistryServices = indexRegistryServices(allRegistryServices);
116 		Map<String, ServiceInfo> servicesToAddToClientRegistryCache = new HashMap<String, ServiceInfo>(indexedRegistryServices);
117 		List<RemoteService> servicesToRemoveFromClientRegistryCache = new ArrayList<RemoteService>();
118 
119 		for (RemoteService remoteService : clientRegistryCache) {
120 			ServiceInfo indexedRegistryService = indexedRegistryServices.get(remoteService.getServiceInfo().getServiceId());
121 			if (indexedRegistryService == null) {
122 				servicesToRemoveFromClientRegistryCache.add(remoteService);
123 			} else {
124 				if (!remoteService.getServiceInfo().getChecksum().equals(indexedRegistryService.getChecksum())) {
125 					servicesToRemoveFromClientRegistryCache.add(remoteService);
126 				} else {
127 					servicesToAddToClientRegistryCache.remove(remoteService.getServiceInfo().getServiceId());
128 				}
129 			}
130 		}
131 		
132 		if (LOG.isDebugEnabled()) {
133 			LOG.debug("For instance found " + servicesToRemoveFromClientRegistryCache.size() + " services to remove from client registry cache, "+
134 				servicesToAddToClientRegistryCache.size() + " services to add to client registry cache");
135 		}
136 		
137 		return new RemoteServicesDiff(new ArrayList<ServiceInfo>(servicesToAddToClientRegistryCache.values()),
138                 servicesToRemoveFromClientRegistryCache);
139 	}
140 	
141 	private Map<String, ServiceInfo> indexRegistryServices(List<ServiceInfo> allRegistryServices) {
142 		Map<String, ServiceInfo> indexedRegistryServices = new HashMap<String, ServiceInfo>(allRegistryServices.size());
143 		for (ServiceInfo serviceInfo : allRegistryServices) {
144 			indexedRegistryServices.put(serviceInfo.getServiceId(), serviceInfo);
145 		}
146 		return indexedRegistryServices;
147 	}
148 
149 }