001 /**
002 * Copyright 2005-2014 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 org.apache.commons.collections.MapUtils;
019 import org.apache.cxf.binding.BindingFactoryManager;
020 import org.apache.cxf.interceptor.LoggingInInterceptor;
021 import org.apache.cxf.interceptor.LoggingOutInterceptor;
022 import org.apache.cxf.jaxrs.JAXRSBindingFactory;
023 import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
024 import org.apache.log4j.Logger;
025 import org.kuali.rice.core.api.exception.RiceRuntimeException;
026 import org.kuali.rice.core.api.security.credentials.CredentialsSource;
027 import org.kuali.rice.ksb.api.bus.support.RestServiceConfiguration;
028 import org.kuali.rice.ksb.api.messaging.ResourceFacade;
029 import org.kuali.rice.ksb.messaging.BusClientFailureProxy;
030 import org.kuali.rice.ksb.messaging.bam.BAMClientProxy;
031 import org.kuali.rice.ksb.security.soap.CredentialsOutHandler;
032 import org.kuali.rice.ksb.service.KSBServiceLocator;
033
034 import java.net.URL;
035 import java.util.Map;
036
037 /**
038 * implementation of {@link ResourceFacade}
039 *
040 * @author Kuali Rice Team (rice.collab@kuali.org)
041 *
042 */
043 public 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 }