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 }