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