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    }