001 /*
002 * Copyright 2005-2007 The Kuali Foundation
003 *
004 *
005 * Licensed under the Educational Community License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.opensource.org/licenses/ecl2.php
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.kuali.rice.ksb.messaging;
018
019 import java.io.ByteArrayInputStream;
020 import java.io.ByteArrayOutputStream;
021 import java.io.IOException;
022 import java.io.ObjectInputStream;
023 import java.io.ObjectOutput;
024 import java.io.ObjectOutputStream;
025
026 import org.apache.log4j.Logger;
027 import org.kuali.rice.core.config.ConfigContext;
028 import org.kuali.rice.core.exception.RiceRuntimeException;
029 import org.kuali.rice.ksb.messaging.serviceconnectors.ServiceConnectorFactory;
030
031
032 /**
033 * Holds the reference to an endpoint of a service as well as the {@link ServiceInfo}
034 * that defines the service. Provides lazy loading of services at call time.
035 *
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038 public class RemotedServiceHolder implements ServiceHolder {
039
040
041 private static final Logger LOG = Logger.getLogger(RemotedServiceHolder.class);
042
043 private Object service;
044 private ServiceInfo serviceInfo;
045
046 public RemotedServiceHolder(ServiceInfo entry) {
047 this.setServiceInfo(entry);
048 }
049
050 public ServiceInfo getServiceInfo() {
051 return this.serviceInfo;
052 }
053
054 public void setServiceInfo(ServiceInfo entry) {
055 if (ConfigContext.getCurrentContextConfig().getDevMode()) {
056 this.serviceInfo = cloneServiceInfo(entry);
057 } else {
058 this.serviceInfo = entry;
059 }
060 }
061
062 public Object getService() throws Exception {
063 synchronized (this) {
064 if (this.service == null) {
065 this.setService(ServiceConnectorFactory.getServiceConnector(serviceInfo).getService());
066 }
067 }
068 return this.service;
069 }
070
071 public void setService(Object service) {
072 this.service = service;
073 }
074
075 /**
076 * this is a hack so we don't mess with the {@link ServiceInfo} on the deployment side of things from the
077 * {@link RemotedServiceRegistry}. We need the service in the {@link ServiceInfo} used on the client to be null but
078 * it can't be for the server side stuff - solution serialize the object just like it was put in a datastore.
079 *
080 * @param serviceInfo
081 * @return
082 * @throws Exception
083 */
084 private static ServiceInfo cloneServiceInfo(final ServiceInfo serviceInfo) {
085
086 ObjectInputStream in = null;
087 ObjectOutput out = null;
088 Object tempService = serviceInfo.getServiceDefinition().getService();
089
090 try {
091 serviceInfo.getServiceDefinition().setService(null);
092 ByteArrayOutputStream bos = new ByteArrayOutputStream();
093 out = new ObjectOutputStream(bos);
094 out.writeObject(serviceInfo);
095
096 in = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
097 return (ServiceInfo) in.readObject();
098 } catch (Exception e) {
099 throw new RiceRuntimeException(e);
100 } finally {
101
102 serviceInfo.getServiceDefinition().setService(tempService);
103 if (in != null) {
104 try {
105 in.close();
106 } catch (IOException ioe) {
107 LOG.info("failed to close InputStream", ioe);
108 }
109 }
110 if (out != null) {
111 try {
112 out.close();
113 } catch (IOException ioe) {
114 LOG.info("Failed to close OutputStream", ioe);
115 }
116 }
117
118 }
119 }
120 }