001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
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    
018    package org.apache.geronimo.security.remoting.jmx;
019    
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    import java.io.ObjectOutputStream;
023    import java.net.URI;
024    import java.net.URISyntaxException;
025    import java.lang.reflect.InvocationHandler;
026    import java.lang.reflect.Method;
027    
028    import org.activeio.Packet;
029    import org.activeio.RequestChannel;
030    import org.activeio.Service;
031    import org.activeio.SyncChannel;
032    import org.activeio.adapter.AsyncChannelToClientRequestChannel;
033    import org.activeio.adapter.PacketToInputStream;
034    import org.activeio.filter.PacketAggregatingSyncChannel;
035    import org.activeio.net.SocketMetadata;
036    import org.activeio.net.SocketSyncChannelFactory;
037    import org.activeio.packet.ByteArrayPacket;
038    
039    import org.apache.geronimo.interceptor.Interceptor;
040    import org.apache.geronimo.interceptor.Invocation;
041    import org.apache.geronimo.interceptor.InvocationResult;
042    import org.apache.geronimo.kernel.ObjectInputStreamExt;
043    
044    /**
045     * @version $Rev: 487175 $ $Date: 2006-12-14 03:10:31 -0800 (Thu, 14 Dec 2006) $
046     */
047    public class RequestChannelInterceptor implements Interceptor, InvocationHandler {
048    
049        private final ClassLoader cl;
050        private final URI target;
051    
052        public RequestChannelInterceptor(URI target, ClassLoader cl) {
053            this.target = target;
054            this.cl = cl;
055        }
056    
057    
058        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
059            Invocation invocation = new SerializableInvocation(method, args, proxy);
060            InvocationResult result = invoke(invocation);
061            if( result.isException() ) {
062                throw result.getException();
063            }
064            return result.getResult();
065        }
066    
067        public InvocationResult invoke(Invocation invocation) throws Throwable {
068    
069            ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
070            try {
071    
072                RequestChannel channel = createRequestChannel(target);
073                Packet response;
074                try {
075                    channel.start();
076                    Packet request = serialize(invocation);
077                    response = channel.request(request, Service.WAIT_FOREVER_TIMEOUT);
078                } finally {
079                    channel.dispose();
080                }
081    
082                Object obj;
083                try {
084                    obj =  deserialize(response, cl);
085                } catch ( ClassNotFoundException e ) {
086                    // Weird.
087                    Thread.currentThread().setContextClassLoader(RequestChannelInterceptor.class.getClassLoader());
088                    response.clear();
089                    obj =  deserialize(response, cl);
090                }
091    
092                // Are we demarshalling a thrown exception.
093                if (obj instanceof RequestChannelInterceptorInvoker.ThrowableWrapper) {
094                    throw ((RequestChannelInterceptorInvoker.ThrowableWrapper) obj).exception;
095                }
096                return (InvocationResult)obj;
097    
098            } finally {
099                Thread.currentThread().setContextClassLoader(originalLoader);
100            }
101        }
102    
103        private static RequestChannel createRequestChannel(URI target) throws IOException, URISyntaxException {
104            SocketSyncChannelFactory factory = new SocketSyncChannelFactory();
105            SyncChannel channel = factory.openSyncChannel(target);
106            SocketMetadata socket = (SocketMetadata) channel.narrow(SocketMetadata.class);
107            socket.setTcpNoDelay(true);
108            return new AsyncChannelToClientRequestChannel(
109                       new PacketAggregatingSyncChannel(
110                           channel));
111        }
112    
113        /**
114         * @param response
115         * @param cl
116         * @return
117         * @throws IOException
118         * @throws ClassNotFoundException
119         */
120        static public Object deserialize(Packet response, ClassLoader cl) throws IOException, ClassNotFoundException {
121            ObjectInputStreamExt is = new ObjectInputStreamExt(new PacketToInputStream(response), cl);
122            Object rc = is.readObject();
123            is.close();
124            return rc;
125        }
126    
127        static public Packet serialize(Object object) throws IOException {
128            ByteArrayOutputStream baos = new ByteArrayOutputStream();
129            ObjectOutputStream oos = new ObjectOutputStream(baos);
130            oos.writeObject(object);
131            oos.close();
132            return new ByteArrayPacket(baos.toByteArray());
133        }
134    }