1 /***************************************************************************************
2 * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.connectivity;
9
10 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
11
12 import java.io.IOException;
13 import java.io.ObjectInputStream;
14 import java.io.ObjectOutputStream;
15 import java.net.Socket;
16
17 /***
18 * Implements a server thread. Each request from the client gets its own instance. <p/>Response to three different
19 * commands: <br/>Command.CREATE, Command.INVOKE and Command.CLOSE. <p/>It redirects the method invocation to the
20 * Invoker for the class.
21 *
22 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
23 */
24 public class RemoteProxyServerThread implements Runnable {
25 /***
26 * The socket.
27 */
28 private final Socket m_socket;
29
30 /***
31 * The input stream.
32 */
33 private ObjectInputStream m_in = null;
34
35 /***
36 * The output stream.
37 */
38 private ObjectOutputStream m_out = null;
39
40 /***
41 * The class loader to use.
42 */
43 private ClassLoader m_loader = null;
44
45 /***
46 * The custom invoker instance.
47 */
48 private Invoker m_invoker = null;
49
50 /***
51 * The time-out for the socket.
52 */
53 private int m_timeout = 60000;
54
55 /***
56 * Is-running flag.
57 */
58 private boolean m_running = true;
59
60 /***
61 * Creates a new instance.
62 *
63 * @param clientSocket the client socket
64 * @param loader the classloader to use
65 * @param invoker the invoker that makes the method invocation in the client thread
66 */
67 public RemoteProxyServerThread(final Socket clientSocket,
68 final ClassLoader loader,
69 final Invoker invoker,
70 final int timeout) {
71 if (clientSocket == null) {
72 throw new IllegalArgumentException("client socket can not be null");
73 }
74 m_socket = clientSocket;
75 m_loader = loader;
76 m_invoker = invoker;
77 m_timeout = timeout;
78 }
79
80 /***
81 * Does the actual work of serving the client.
82 */
83 public void run() {
84 Thread.currentThread().setContextClassLoader(m_loader);
85 try {
86 m_socket.setTcpNoDelay(true);
87 m_socket.setSoTimeout(m_timeout);
88 m_in = new ObjectInputStream(m_socket.getInputStream());
89 m_out = new ObjectOutputStream(m_socket.getOutputStream());
90 } catch (IOException e) {
91 throw new WrappedRuntimeException(e);
92 }
93 while (m_running) {
94 try {
95 switch (m_in.read()) {
96 case Command.CREATE:
97 handleCreateCommand();
98 break;
99 case Command.INVOKE:
100 handleInvocationCommand();
101 break;
102 case Command.CLOSE:
103 m_running = false;
104 break;
105 default:
106 break;
107 }
108 } catch (Exception e) {
109 close();
110 throw new WrappedRuntimeException(e);
111 }
112 }
113 close();
114 }
115
116 /***
117 * Handles the command CREATE.
118 *
119 * @throws IOException
120 * @throws ClassNotFoundException
121 * @throws InstantiationException
122 * @throws IllegalAccessException
123 */
124 private void handleCreateCommand() throws IOException,
125 ClassNotFoundException,
126 InstantiationException,
127 IllegalAccessException {
128 final String className = (String) m_in.readObject();
129 Class klass = m_loader.loadClass(className);
130 final Object instance = klass.newInstance();
131 final String handle = RemoteProxy.wrapInstance(instance);
132 m_out.writeObject(handle);
133 m_out.flush();
134 }
135
136 /***
137 * Handles the command INVOKE.
138 *
139 * @throws IOException
140 * @throws ClassNotFoundException
141 */
142 private void handleInvocationCommand() throws IOException, ClassNotFoundException {
143 final Object context = m_in.readObject();
144 final String handle = (String) m_in.readObject();
145 final String methodName = (String) m_in.readObject();
146 final Class[] paramTypes = (Class[]) m_in.readObject();
147 final Object[] args = (Object[]) m_in.readObject();
148 Object result = null;
149 try {
150 result = m_invoker.invoke(handle, methodName, paramTypes, args, context);
151 } catch (Exception e) {
152 result = e;
153 }
154 m_out.writeObject(result);
155 m_out.flush();
156 }
157
158 /***
159 * Close the input/output streams along with the socket.
160 */
161 private void close() {
162 try {
163 if (m_in != null) {
164 m_in.close();
165 }
166 if (m_out != null) {
167 m_out.close();
168 }
169 if (m_socket != null) {
170 m_socket.close();
171 }
172 } catch (IOException e) {
173 throw new WrappedRuntimeException(e);
174 }
175 }
176 }