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 }