Coverage Report - org.kuali.rice.ksb.messaging.RemotedServiceRegistryImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
RemotedServiceRegistryImpl
0%
0/195
0%
0/78
3
RemotedServiceRegistryImpl$1
N/A
N/A
3
RemotedServiceRegistryImpl$ServiceNameFinder
0%
0/29
0%
0/12
3
 
 1  
 /*
 2  
  * Copyright 2007 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.messaging;
 17  
 
 18  
 import java.net.URI;
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collections;
 21  
 import java.util.HashMap;
 22  
 import java.util.Iterator;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 import java.util.concurrent.ScheduledFuture;
 26  
 import java.util.concurrent.TimeUnit;
 27  
 
 28  
 import javax.servlet.http.HttpServletRequest;
 29  
 import javax.servlet.http.HttpServletResponse;
 30  
 import javax.xml.namespace.QName;
 31  
 
 32  
 import org.apache.commons.lang.StringUtils;
 33  
 import org.apache.log4j.Logger;
 34  
 import org.kuali.rice.core.config.Config;
 35  
 import org.kuali.rice.core.config.ConfigContext;
 36  
 import org.kuali.rice.core.config.ConfigurationException;
 37  
 import org.kuali.rice.core.util.RiceUtilities;
 38  
 import org.kuali.rice.kns.util.ObjectUtils;
 39  
 import org.kuali.rice.ksb.messaging.callforwarding.ForwardedCallHandler;
 40  
 import org.kuali.rice.ksb.messaging.callforwarding.ForwardedCallHandlerImpl;
 41  
 import org.kuali.rice.ksb.messaging.service.ServiceRegistry;
 42  
 import org.kuali.rice.ksb.messaging.serviceexporters.ServiceExporterFactory;
 43  
 import org.kuali.rice.ksb.service.KSBContextServiceLocator;
 44  
 import org.kuali.rice.ksb.service.KSBServiceLocator;
 45  
 import org.kuali.rice.ksb.util.KSBConstants;
 46  
 import org.springframework.web.servlet.mvc.Controller;
 47  
 
 48  0
 public class RemotedServiceRegistryImpl implements RemotedServiceRegistry, Runnable {
 49  
 
 50  0
         private static final Logger LOG = Logger.getLogger(RemotedServiceRegistryImpl.class);
 51  
 
 52  0
         private Map<QName, ServerSideRemotedServiceHolder> publishedServices = Collections.synchronizedMap(new HashMap<QName, ServerSideRemotedServiceHolder>());
 53  
 
 54  0
         private Map<QName, ServerSideRemotedServiceHolder> publishedTempServices = Collections.synchronizedMap(new HashMap<QName, ServerSideRemotedServiceHolder>());
 55  
 
 56  
         /**
 57  
          * A Map for encapsulating copies of the ServiceDefinition objects and their checksums, so that it is not necessary to regenerate the checksums
 58  
          * during every registry refresh, and so that isSame() checks on non-serialized ServiceDefinitions can be performed properly to determine when
 59  
          * the checksums require recomputation.
 60  
          */
 61  0
         private Map<QName, ServiceInfo> serviceInfoCopies = Collections.synchronizedMap(new HashMap<QName, ServiceInfo>());
 62  
         
 63  
         /**
 64  
          * A Map for temporarily storing the values located in the serviceInfoCopies Map during a registry refresh.
 65  
          */
 66  0
         private Map<QName, ServiceInfo> serviceInfoCopyHolder = Collections.synchronizedMap(new HashMap<QName, ServiceInfo>());
 67  
         
 68  
         private String serverIp;
 69  
         
 70  
         /**
 71  
          * lookup QNameS of published services from request URLs
 72  
          */
 73  0
         private ServiceNameFinder publishedServiceNameFinder = new ServiceNameFinder();
 74  
 
 75  
         /**
 76  
          * lookup QNameS of published temp services from request URLs
 77  
          */
 78  0
         private ServiceNameFinder publishedTempServiceNameFinder = new ServiceNameFinder();
 79  
 
 80  
         private boolean started;
 81  
 
 82  
         private ScheduledFuture future;
 83  
 
 84  
         protected ServiceRegistry serviceRegistry;
 85  
         
 86  
         protected KSBContextServiceLocator serviceLocator;
 87  
         
 88  
         public void handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 89  0
                 ((Controller) handler).handleRequest(request, response);
 90  0
         }
 91  
 
 92  
         private void registerService(ServiceInfo entry, Object serviceImpl) throws Exception {
 93  0
                 ServerSideRemotedServiceHolder serviceHolder = ServiceExporterFactory.getServiceExporter(entry, serviceLocator).getServiceExporter(serviceImpl);
 94  0
                 this.publishedServices.put(entry.getQname(), serviceHolder);
 95  0
                 this.serviceInfoCopies.put(entry.getQname(), this.serviceInfoCopyHolder.get(entry.getQname()));
 96  0
                 this.publishedServiceNameFinder.register(entry, entry.getQname());
 97  0
         }
 98  
 
 99  
         /**
 100  
          * Constructs a new ServiceInfo object based on the given ServiceDefinition, and also creates/updates another ServiceInfo for encapsulating copies
 101  
          * of the ServiceDefinition and its checksum. 
 102  
          * 
 103  
          * @param serviceDef The ServiceDefinition to encapsulate inside of a ServiceInfo object.
 104  
          * @return A new ServiceInfo constructed from the provided ServiceDefinition and an associated ServiceInfo copy.
 105  
          */
 106  
         private ServiceInfo createServiceInfoAndServiceInfoCopy(ServiceDefinition serviceDef) {
 107  0
                 ServiceInfo copiedInfo = this.serviceInfoCopies.get(serviceDef.getServiceName());
 108  
                 
 109  0
                 if (copiedInfo == null) {
 110  
                         // Create a new ServiceInfo copy if one does not exist.
 111  0
                         copiedInfo = new ServiceInfo();
 112  0
                         copiedInfo.setServiceDefinition((ServiceDefinition) ObjectUtils.deepCopy(serviceDef));
 113  0
                         copiedInfo.setChecksum(copiedInfo.objectToChecksum(serviceDef));
 114  0
                 } else if (!serviceDef.isSame(copiedInfo.getServiceDefinition(serviceLocator.getMessageHelper()))) {
 115  
                         // Update the existing ServiceInfo copy if its ServiceDefinition copy fails an isSame() check with the given ServiceDefinition.
 116  0
                         copiedInfo.setServiceDefinition((ServiceDefinition) ObjectUtils.deepCopy(serviceDef));
 117  0
                         copiedInfo.setChecksum(copiedInfo.objectToChecksum(serviceDef));
 118  
                 }
 119  0
                 this.serviceInfoCopyHolder.put(serviceDef.getServiceName(), copiedInfo);
 120  
                 
 121  0
                 return new ServiceInfo(serviceDef, this.serverIp, new String(copiedInfo.getChecksum()));
 122  
         }
 123  
         
 124  
         private ServiceInfo getForwardHandlerServiceInfo(ServiceDefinition serviceDef) {
 125  0
                 ForwardedCallHandler callHandler = new ForwardedCallHandlerImpl();
 126  
                 
 127  0
                 ServiceDefinition serviceDefinition = new JavaServiceDefinition();
 128  0
                 serviceDefinition.setBusSecurity(serviceDef.getBusSecurity());
 129  0
                 if (serviceDef.getLocalServiceName() == null && serviceDef.getServiceName() != null) {
 130  0
                         serviceDefinition.setServiceName(new QName(serviceDef.getServiceName().getNamespaceURI(), serviceDef.getServiceName().getLocalPart() + KSBConstants.FORWARD_HANDLER_SUFFIX));
 131  
                 } else {
 132  0
                         serviceDefinition.setLocalServiceName(serviceDef.getLocalServiceName() + KSBConstants.FORWARD_HANDLER_SUFFIX);
 133  0
                         serviceDefinition.setServiceNameSpaceURI(serviceDef.getServiceNameSpaceURI());
 134  
                 }
 135  0
                 serviceDefinition.setMessageExceptionHandler(serviceDef.getMessageExceptionHandler());
 136  0
                 serviceDefinition.setMillisToLive(serviceDef.getMillisToLive());
 137  0
                 serviceDefinition.setPriority(serviceDef.getPriority());
 138  0
                 serviceDefinition.setQueue(serviceDef.getQueue());
 139  0
                 serviceDefinition.setRetryAttempts(serviceDef.getRetryAttempts());
 140  0
                 serviceDefinition.setService(callHandler);
 141  0
                 serviceDefinition.validate();
 142  
 
 143  0
                 return createServiceInfoAndServiceInfoCopy(serviceDefinition);
 144  
         }
 145  
 
 146  
         
 147  
         public void registerService(ServiceDefinition serviceDefinition, boolean forceRegistryRefresh) {
 148  0
                 if (serviceDefinition == null) {
 149  0
                         throw new RuntimeException("Service Definition is null");
 150  
                 }
 151  0
                 final Config config = ConfigContext.getCurrentContextConfig();
 152  
                 
 153  
                 @SuppressWarnings("unchecked")
 154  0
                 List<ServiceDefinition> services = (List<ServiceDefinition>) config.getObject(Config.BUS_DEPLOYED_SERVICES);
 155  0
                 if (services == null) {
 156  0
                         services = new ArrayList<ServiceDefinition>();
 157  0
                         config.putObject(Config.BUS_DEPLOYED_SERVICES, services);
 158  
                 }
 159  
                 
 160  
                 //removing any existing services already registered with the same QName - allows client apps to override rice pushlished services
 161  0
                 removeServicesWithName(serviceDefinition.getServiceName(), services);
 162  0
                 services.add(serviceDefinition);
 163  
                 
 164  
                 // force an immediate registry of the service
 165  0
                 if (forceRegistryRefresh) {
 166  0
                         run();
 167  
                 }
 168  0
         }
 169  
         
 170  
         /**
 171  
          * removes any services from the list with the same QName.
 172  
          * 
 173  
          * @param name the QName to search for
 174  
          * @param services the list of services
 175  
          */
 176  
         private void removeServicesWithName(QName name, List<ServiceDefinition> services) {
 177  0
                 for (Iterator<ServiceDefinition> i = services.iterator(); i.hasNext(); ) {
 178  0
                         final ServiceDefinition service = i.next();
 179  0
                         if (service.getServiceName().equals(name)) {
 180  0
                                 LOG.debug("removing existing service with QName: " + service.getServiceName());
 181  0
                                 i.remove();
 182  
                         }
 183  0
                 }
 184  0
         }
 185  
 
 186  
         public void registerTempService(ServiceDefinition serviceDefinition, Object service) {
 187  0
                 ServiceInfo serviceInfo = new ServiceInfo(serviceDefinition);
 188  0
                 Object existingService = getService(serviceInfo.getQname());
 189  0
                 if (existingService != null) {
 190  0
                         throw new RuntimeException("Service with that name is already registered");
 191  
                 }
 192  
                 try {
 193  0
                         ServerSideRemotedServiceHolder serviceHolder = 
 194  
                                 ServiceExporterFactory.getServiceExporter(serviceInfo, serviceLocator).getServiceExporter(service);
 195  0
                         this.publishedTempServices.put(serviceInfo.getQname(), serviceHolder);
 196  0
                         this.publishedTempServiceNameFinder.register(serviceInfo, serviceInfo.getQname());
 197  
                         
 198  0
                         LOG.debug("Registered temp service " + serviceDefinition.getServiceName());
 199  0
                 } catch (Exception e) {
 200  0
                         throw new RuntimeException(e);
 201  0
                 }
 202  0
         }
 203  
 
 204  
         public ServerSideRemotedServiceHolder getRemotedServiceHolder(QName qname) {
 205  0
                 final ServerSideRemotedServiceHolder serviceHolder = this.publishedServices.get(qname);
 206  0
                 return serviceHolder != null ? serviceHolder : this.publishedTempServices.get(qname);
 207  
         }
 208  
 
 209  
         public Object getService(QName qName, String url) {
 210  0
                 ServerSideRemotedServiceHolder serviceHolder = this.publishedServices.get(qName);
 211  0
                 if (serviceHolder != null && serviceHolder.getServiceInfo().getEndpointUrl().equals(url)) {
 212  0
                         return serviceHolder.getInjectedPojo();
 213  
                 }
 214  
 
 215  0
                 serviceHolder = this.publishedTempServices.get(qName);
 216  0
                 if (serviceHolder != null && serviceHolder.getServiceInfo().getEndpointUrl().equals(url)) {
 217  0
                         return serviceHolder.getInjectedPojo();
 218  
                 }
 219  
 
 220  0
                 return null;
 221  
         }
 222  
 
 223  
         public Object getLocalService(QName serviceName) {
 224  0
                 ServerSideRemotedServiceHolder serviceHolder = this.publishedServices.get(serviceName);
 225  0
                 if (serviceHolder == null) {
 226  0
                         return null;
 227  
                 }
 228  0
                 return serviceHolder.getInjectedPojo();
 229  
         }
 230  
 
 231  
         public Object getService(QName qname) {
 232  0
                 ServiceHolder serviceHolder = getRemotedServiceHolder(qname);
 233  0
                 if (serviceHolder != null) {
 234  
                             try {
 235  0
                         Object service = serviceHolder.getService();
 236  0
                         return service;
 237  0
                             } catch (Exception e) {
 238  0
                                 this.removeRemoteServiceFromRegistry(qname);
 239  
                 }
 240  
                 }
 241  0
                 if (!StringUtils.isEmpty(qname.getNamespaceURI())) {
 242  0
                         return getService(new QName(qname.getLocalPart()));
 243  
                 }
 244  0
                 return null;
 245  
         }
 246  
 
 247  
         /**
 248  
          * This method is used to obtain the qualified service name for the service deployed at the given url.
 249  
          *  
 250  
          * @param url
 251  
          * @return the service
 252  
          */
 253  
         public QName getServiceName(String url){
 254  0
                 QName qname = null;
 255  0
                 qname = this.publishedServiceNameFinder.lookup(url);
 256  
 
 257  
                 // try temp services map
 258  0
                 if (qname == null) {
 259  0
                         qname = this.publishedTempServiceNameFinder.lookup(url);
 260  
                 }
 261  
                         
 262  0
                 return qname;
 263  
         }
 264  
 
 265  
         public void removeRemoteServiceFromRegistry(QName serviceName) {
 266  
                 ServerSideRemotedServiceHolder serviceHolder;
 267  0
                 serviceHolder = this.publishedTempServices.remove(serviceName);
 268  0
                 if (serviceHolder != null){
 269  0
                         this.publishedTempServiceNameFinder.remove(serviceHolder.getServiceInfo().getEndpointUrl());
 270  
                 }
 271  0
         }
 272  
 
 273  
         public void refresh() {
 274  0
             run();
 275  0
         }
 276  
 
 277  
         public synchronized void run() {
 278  0
                     String serviceNamespace = ConfigContext.getCurrentContextConfig().getServiceNamespace();
 279  0
                 LOG.debug("Checking for newly published services on service namespace " + serviceNamespace + " ...");
 280  0
                 this.serverIp = RiceUtilities.getIpNumber();
 281  
 
 282  0
                 String serviceServletUrl = (String) ConfigContext.getObjectFromConfigHierarchy(Config.SERVICE_SERVLET_URL);
 283  0
                 if (serviceServletUrl == null) {
 284  0
                         throw new RuntimeException("No service url provided to locate services.  This is configured in the KSBConfigurer.");
 285  
                 }
 286  
 
 287  
                 // First, we need to get the list of services that we should be publishing
 288  
                 
 289  0
                 List<?> javaServices = (List<?>) ConfigContext.getCurrentContextConfig().getObject(Config.BUS_DEPLOYED_SERVICES);
 290  
                 // convert the ServiceDefinitions into ServiceInfos for diff comparison
 291  0
                 List<ServiceInfo> configuredJavaServices = new ArrayList<ServiceInfo>();
 292  0
                 for (Iterator<?> iter = javaServices.iterator(); iter.hasNext();) {
 293  0
                         ServiceDefinition serviceDef = (ServiceDefinition) iter.next();
 294  0
                         configuredJavaServices.add(createServiceInfoAndServiceInfoCopy(serviceDef));
 295  0
                         configuredJavaServices.add(getForwardHandlerServiceInfo(serviceDef));
 296  0
                 }
 297  
 
 298  0
                 List<ServiceInfo> configuredServices = new ArrayList<ServiceInfo>();
 299  0
                 configuredServices.addAll(configuredJavaServices);
 300  0
                 List<ServiceInfo> fetchedServices = null;
 301  
                 
 302  
                 // Next, let's find the services that we have already published in the registry
 303  
                  
 304  0
                 if (ConfigContext.getCurrentContextConfig().getDevMode() || ConfigContext.getCurrentContextConfig().getBatchMode()) {
 305  0
                         fetchedServices = new ArrayList<ServiceInfo>();
 306  
                 } else {
 307  
                         //TODO we are not verifying that this read is not being done in dev mode in a test
 308  0
                         fetchedServices = this.getServiceRegistry().findLocallyPublishedServices(RiceUtilities.getIpNumber(), serviceNamespace);
 309  
                 }
 310  
                 
 311  0
                 RoutingTableDiffCalculator diffCalc = new RoutingTableDiffCalculator();
 312  0
                 diffCalc.setEnMessageHelper(serviceLocator.getMessageHelper());
 313  0
                 boolean needUpdated = diffCalc.calculateServerSideUpdateLists(configuredServices, fetchedServices);
 314  0
                 if (needUpdated) {
 315  0
                         boolean updateSRegTable = true;
 316  0
                           if (ConfigContext.getCurrentContextConfig().getDevMode() || ConfigContext.getCurrentContextConfig().getBatchMode()) {
 317  0
                                   updateSRegTable = false;
 318  
                           }
 319  0
                           if (updateSRegTable) {
 320  0
                                 getServiceRegistry().saveEntries(diffCalc.getServicesNeedUpdated());
 321  0
                                 getServiceRegistry().removeEntries(diffCalc.getServicesNeedRemoved());
 322  
                         }
 323  0
                         this.publishedServices.clear();
 324  0
                         this.serviceInfoCopies.clear();
 325  0
                         publishServiceList(diffCalc.getMasterServiceList());
 326  0
                 } else if (this.publishedServices.isEmpty()) {
 327  0
                         publishServiceList(configuredServices);
 328  
                 }
 329  0
                 this.serviceInfoCopyHolder.clear();
 330  0
                 LOG.debug("...Finished checking for remote services.");
 331  0
         }
 332  
 
 333  
         private void publishServiceList(List<ServiceInfo> services) {
 334  0
                 for (ServiceInfo serviceInfo : services) {
 335  
                         try {
 336  0
                                 registerService(serviceInfo, serviceInfo.getServiceDefinition(serviceLocator.getMessageHelper()).getService());
 337  0
                         } catch (Exception e) {
 338  0
                                 LOG.error("Encountered error registering service " + serviceInfo.getQname(), e);
 339  0
                                 this.publishedServices.remove(serviceInfo.getQname());
 340  0
                                 this.serviceInfoCopies.remove(serviceInfo.getQname());
 341  0
                                 this.publishedServiceNameFinder.remove(serviceInfo.getEndpointUrl());
 342  0
                                 continue;
 343  0
                         }
 344  
                 }
 345  0
         }
 346  
 
 347  
         public boolean isStarted() {
 348  0
                 return this.started;
 349  
         }
 350  
 
 351  
         public synchronized void start() throws Exception {
 352  0
                 if (isStarted()) {
 353  0
                         return;
 354  
                 }
 355  0
                 LOG.info("Starting the Service Registry...");
 356  0
                 run();
 357  0
                 if (!ConfigContext.getCurrentContextConfig().getDevMode()) {
 358  0
                         int refreshRate = ConfigContext.getCurrentContextConfig().getRefreshRate();
 359  0
                         this.future = serviceLocator.getScheduledPool()==null?KSBServiceLocator.getScheduledPool().scheduleWithFixedDelay(this, 30, refreshRate, TimeUnit.SECONDS)
 360  
                                                         :serviceLocator.getScheduledPool().scheduleWithFixedDelay(this, 30, refreshRate, TimeUnit.SECONDS);
 361  
                 }
 362  0
                 this.started = true;
 363  0
                 LOG.info("...Service Registry successfully started.");
 364  0
         }
 365  
 
 366  
         public void stop() throws Exception {
 367  0
                 LOG.info("Stopping the Service Registry...");
 368  
                 // remove services from the bus
 369  0
                 if (this.future != null) {
 370  0
                         if (!this.future.cancel(false)) {
 371  0
                                 LOG.warn("Failed to cancel the RemotedServiceRegistry.");
 372  
                         }
 373  0
                         this.future = null;
 374  
                 }
 375  0
                 List<ServiceInfo> fetchedServices = this.getServiceRegistry().findLocallyPublishedServices(RiceUtilities.getIpNumber(), ConfigContext.getCurrentContextConfig().getServiceNamespace());
 376  0
                 this.getServiceRegistry().markServicesDead(fetchedServices);
 377  0
                 this.publishedServices.clear();
 378  0
                 this.getPublishedTempServices().clear();
 379  0
                 this.serviceInfoCopies.clear();
 380  0
                 this.started = false;
 381  0
                 LOG.info("...Service Registry successfully stopped.");
 382  0
         }
 383  
 
 384  
         public String getContents(String indent, boolean servicePerLine) {
 385  0
                 String content = indent + "RemotedServiceRegistryImpl services=";
 386  
 
 387  0
                 for (ServiceHolder serviceHolder : this.publishedServices.values()) {
 388  0
                         if (servicePerLine) {
 389  0
                                 content += indent + "+++" + serviceHolder.getServiceInfo().toString() + "\n";
 390  
                         } else {
 391  0
                                 content += serviceHolder.getServiceInfo().toString() + ", ";
 392  
                         }
 393  
                 }
 394  0
                 return content;
 395  
         }
 396  
 
 397  
         public ServiceRegistry getServiceRegistry() {
 398  0
                 return serviceRegistry == null ? KSBServiceLocator.getServiceRegistry() : serviceRegistry;
 399  
         }
 400  
 
 401  
         public Map<QName, ServerSideRemotedServiceHolder> getPublishedServices() {
 402  0
                 if (!isStarted()) {
 403  
                         try {
 404  0
                                 start();
 405  0
                         } catch (Exception e) {
 406  0
                                 throw new ConfigurationException(e);
 407  0
                         }
 408  
                 }
 409  0
                 return this.publishedServices;
 410  
         }
 411  
 
 412  
         public Map<QName, ServerSideRemotedServiceHolder> getPublishedTempServices() {
 413  0
                 return this.publishedTempServices;
 414  
         }
 415  
 
 416  
         public void setServiceRegistry(ServiceRegistry serviceRegistry) {
 417  0
                 this.serviceRegistry = serviceRegistry;
 418  0
         }
 419  
 
 420  
         /**
 421  
          * @return the serviceLocator
 422  
          */
 423  
         public KSBContextServiceLocator getServiceLocator() {
 424  0
                 return this.serviceLocator;
 425  
         }
 426  
 
 427  
         /**
 428  
          * @param serviceLocator the serviceLocator to set
 429  
          */
 430  
         public void setServiceLocator(KSBContextServiceLocator serviceLocator) {
 431  0
                 this.serviceLocator = serviceLocator;
 432  0
         }
 433  
         
 434  
         
 435  
         /**
 436  
          * Looks up service QNameS based on URL StringS.  API is Map-like, but non-service specific portions of the
 437  
          * URL are trimmed prior to accessing its internal Map.
 438  
          * 
 439  
          * @author Kuali Rice Team (rice.collab@kuali.org)
 440  
          *
 441  
          */
 442  0
         private static class ServiceNameFinder {
 443  
             
 444  
                 /**
 445  
                  * A service path to service QName map
 446  
                  */
 447  0
                 private Map<String, QName> servicePathToQName = Collections.synchronizedMap(new HashMap<String, QName>());
 448  
                 
 449  
 
 450  
                 /**
 451  
                  * This method trims the endpoint url base ({@link Config#getEndPointUrl()}) base off of the full service URL, e.g.
 452  
                  * "http://kuali.edu/kr-dev/remoting/SomeService" -> "SomeService".  It makes an effort to do so even if the host
 453  
                  * and ip don't match what is in {@link Config#getEndPointUrl()} by stripping host/port info.
 454  
                  * 
 455  
                  * If the service URL contains the configured subpath for RESTful service, additional trimming is done to
 456  
                  * isolate the service name from the rest of the url.
 457  
                  * 
 458  
                  * @param url
 459  
                  * @return the service specific suffix.  If fullServiceUrl doesn't contain the endpoint url base,
 460  
                  * fullServiceUrl is returned unmodified.  
 461  
                  */
 462  
                 private String trimServiceUrlBase(String url) {
 463  0
                         String trimmedUrl = 
 464  
                                 StringUtils.removeStart(url, ConfigContext.getCurrentContextConfig().getEndPointUrl());
 465  
                         
 466  0
                         if (trimmedUrl.length() == url.length()) { // it didn't contain the endpoint url base.
 467  
                                 // Perhaps the incoming url has a different host (or the ip) or a different port.
 468  
                                 // Trim off the host & port, then trim off the common base.
 469  0
                                 URI serviceUri = URI.create(url);
 470  0
                                 URI endpointUrlBase = URI.create(ConfigContext.getCurrentContextConfig().getEndPointUrl());
 471  
                                 
 472  0
                                 String reqPath = serviceUri.getPath();
 473  0
                                 String basePath = endpointUrlBase.getPath();
 474  
                                 
 475  0
                                 trimmedUrl = StringUtils.removeStart(reqPath, basePath);
 476  
                         }
 477  
                         
 478  0
                         return trimmedUrl;
 479  
                 }
 480  
                 
 481  
                 /**
 482  
                  * adds a mapping from the service specific portion of the service URL to the service name.
 483  
                  * 
 484  
                  * @param serviceUrl
 485  
                  * @param serviceName
 486  
                  */
 487  
                 public void register(ServiceInfo entry, QName serviceName) {
 488  0
                         String serviceUrlBase = trimServiceUrlBase(entry.getEndpointUrl());
 489  
 
 490  0
                         if (serviceUrlBase.endsWith("/"))
 491  0
                                 serviceUrlBase = StringUtils.chop(serviceUrlBase);
 492  
 
 493  0
                         servicePathToQName.put(serviceUrlBase, serviceName);
 494  0
                 }
 495  
                 
 496  
                 /**
 497  
                  * removes the mapping (if one exists) for the service specific portion of this url.
 498  
                  * 
 499  
                  * @param serviceUrl
 500  
                  */
 501  
                 public void remove(String serviceUrl) {
 502  0
                         servicePathToQName.remove(trimServiceUrlBase(serviceUrl));
 503  0
                 }
 504  
                 
 505  
                 /**
 506  
                  * gets the QName for the service
 507  
                  * 
 508  
                  * @param serviceUrl
 509  
                  * @return
 510  
                  */
 511  
                 public QName lookup(String serviceUrl) {
 512  0
                         String serviceUrlBase = trimServiceUrlBase(serviceUrl);
 513  
 
 514  
                         // First, make sure we don't have any query params
 515  0
                         if (serviceUrlBase.length() > 0 && serviceUrlBase.lastIndexOf('?') != -1) {
 516  0
                                 serviceUrlBase = serviceUrlBase.substring(0, serviceUrlBase.lastIndexOf('?'));
 517  
                         }
 518  
 
 519  0
                         QName qname = null;
 520  
                         // Now, iterate backwards through the url, stripping off pieces until you match -- this should work for rest too
 521  0
                         while (qname == null) {
 522  0
                                 qname = servicePathToQName.get(serviceUrlBase);
 523  
 
 524  0
                                 int lastSeparatorIndex = serviceUrlBase.lastIndexOf('/');
 525  0
                                 if (lastSeparatorIndex == -1)
 526  0
                                         break;
 527  0
                                 serviceUrlBase = serviceUrlBase.substring(0, lastSeparatorIndex);
 528  0
                         }
 529  
 
 530  0
                         return qname;
 531  
                 }
 532  
 
 533  
         }
 534  
 
 535  
 }