001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.ksb.messaging.serviceconnectors; 017 018import org.apache.commons.collections.MapUtils; 019import org.apache.cxf.binding.BindingFactoryManager; 020import org.apache.cxf.interceptor.LoggingInInterceptor; 021import org.apache.cxf.interceptor.LoggingOutInterceptor; 022import org.apache.cxf.jaxrs.JAXRSBindingFactory; 023import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; 024import org.apache.log4j.Logger; 025import org.kuali.rice.core.api.exception.RiceRuntimeException; 026import org.kuali.rice.core.api.security.credentials.CredentialsSource; 027import org.kuali.rice.ksb.api.bus.support.RestServiceConfiguration; 028import org.kuali.rice.ksb.api.messaging.ResourceFacade; 029import org.kuali.rice.ksb.messaging.BusClientFailureProxy; 030import org.kuali.rice.ksb.messaging.bam.BAMClientProxy; 031import org.kuali.rice.ksb.security.soap.CredentialsOutHandler; 032import org.kuali.rice.ksb.service.KSBServiceLocator; 033 034import java.net.URL; 035import java.util.Map; 036 037/** 038 * implementation of {@link ResourceFacade} 039 * 040 * @author Kuali Rice Team (rice.collab@kuali.org) 041 * 042 */ 043public class ResourceFacadeImpl implements ResourceFacade { 044 045 private static final Logger LOG = Logger.getLogger(ResourceFacadeImpl.class); 046 047 private final RestServiceConfiguration serviceConfiguration; 048 private CredentialsSource credentialsSource; 049 private URL actualEndpointUrl; 050 051 public ResourceFacadeImpl(final RestServiceConfiguration serviceConfiguration, URL actualEndpointUrl) { 052 if (serviceConfiguration == null) { 053 throw new IllegalArgumentException("serviceConfiguration cannot be null"); 054 } 055 if (actualEndpointUrl == null) { 056 throw new IllegalArgumentException("actual endpoint url cannot be null"); 057 } 058 this.serviceConfiguration = serviceConfiguration; 059 this.actualEndpointUrl = actualEndpointUrl; 060 } 061 062 /** 063 * This overridden method ... 064 * 065 * @see org.kuali.rice.ksb.api.messaging.ResourceFacade#getResource(java.lang.Class) 066 */ 067 public <R> R getResource(Class<R> resourceClass) { 068 if (resourceClass == null) throw new IllegalArgumentException("resourceClass argument must not be null"); 069 070 if (!serviceConfiguration.hasClass(resourceClass.getName())) { 071 throw new IllegalArgumentException("Service " + serviceConfiguration.getServiceName() + 072 " does not contain an implementation of type " + resourceClass.getName()); 073 } 074 075 return getServiceProxy(resourceClass); 076 } 077 078 /** 079 * This overridden method ... 080 * 081 * @see org.kuali.rice.ksb.api.messaging.ResourceFacade#getResource(java.lang.String) 082 */ 083 public <R> R getResource(String resourceName) { 084 085 String resourceClassName = null; 086 087 Map<String, String> resourceToClassNameMap = serviceConfiguration.getResourceToClassNameMap(); 088 089 if (resourceName != null && resourceToClassNameMap != null) 090 resourceClassName = resourceToClassNameMap.get(resourceName); 091 else 092 resourceClassName = serviceConfiguration.getResourceClass(); 093 094 if (resourceClassName == null) 095 throw new RiceRuntimeException("No resource class name was found for the specified resourceName: " + resourceName); 096 097 Class<?> resourceClass = null; 098 099 try { 100 resourceClass = Class.forName(resourceClassName); 101 } catch (ClassNotFoundException e) { 102 throw new RiceRuntimeException("Configured resource class " + resourceClassName + 103 " in service " + serviceConfiguration.getServiceName() + " is not loadable", e); 104 } 105 106 107 // allow this to class cast if the types don't match, up to the caller to ensure this is correct 108 @SuppressWarnings("unchecked") 109 R serviceProxy = (R)getServiceProxy(resourceClass); 110 return serviceProxy; 111 } 112 113 /** 114 * This method ... 115 * 116 * @param resourceClass 117 * @return 118 */ 119 private <R> R getServiceProxy(Class<R> resourceClass) { 120 JAXRSClientFactoryBean clientFactory; 121 122 clientFactory = new JAXRSClientFactoryBean(); 123 clientFactory.setBus(KSBServiceLocator.getCXFBus()); 124 125 clientFactory.setResourceClass(resourceClass); 126 clientFactory.setAddress(actualEndpointUrl.toString()); 127 BindingFactoryManager bindingFactoryManager = KSBServiceLocator.getCXFBus().getExtension(BindingFactoryManager.class); 128 JAXRSBindingFactory bindingFactory = new JAXRSBindingFactory(); 129 bindingFactory.setBus(KSBServiceLocator.getCXFBus()); 130 131 bindingFactoryManager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, bindingFactory); 132 133 //Set logging interceptors 134 if (LOG.isDebugEnabled()) { 135 clientFactory.getOutInterceptors().add(new LoggingOutInterceptor()); 136 } 137 138 if (getCredentialsSource() != null) { 139 clientFactory.getOutInterceptors().add(new CredentialsOutHandler(getCredentialsSource(), serviceConfiguration)); 140 } 141 142 if (LOG.isDebugEnabled()) { 143 clientFactory.getInInterceptors().add(new LoggingInInterceptor()); 144 } 145 146 Object service = clientFactory.create(); 147 return getServiceProxyWithFailureMode(resourceClass, service, serviceConfiguration); 148 } 149 150 public boolean isSingleResourceService() { 151 return MapUtils.isEmpty(serviceConfiguration.getResourceToClassNameMap()); 152 } 153 154 public void setCredentialsSource(final CredentialsSource credentialsSource) { 155 this.credentialsSource = credentialsSource; 156 } 157 158 protected CredentialsSource getCredentialsSource() { 159 return this.credentialsSource; 160 } 161 162 protected <R> R getServiceProxyWithFailureMode(final Class<R> resourceClass, final Object service, final RestServiceConfiguration serviceConfiguration) { 163 Object bamWrappedClientProxy = BAMClientProxy.wrap(service, serviceConfiguration); 164 Object proxy = BusClientFailureProxy.wrap(bamWrappedClientProxy, serviceConfiguration); 165 if (!resourceClass.isInstance(proxy)) { 166 throw new IllegalArgumentException("Wrapped proxy is of the wrong type " + proxy.getClass() + ", expected " + resourceClass); 167 } 168 return resourceClass.cast(proxy); 169 } 170 171}