001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mq.il.uil2;
023:
024: import java.io.IOException;
025: import java.lang.reflect.Method;
026: import java.net.InetAddress;
027: import java.net.ServerSocket;
028: import java.net.Socket;
029: import java.net.UnknownHostException;
030: import java.util.Iterator;
031: import java.util.Properties;
032:
033: import javax.naming.InitialContext;
034: import javax.net.ServerSocketFactory;
035:
036: import org.jboss.mq.il.Invoker;
037: import org.jboss.mq.il.ServerIL;
038: import org.jboss.mq.il.ServerILJMXService;
039: import org.jboss.mq.il.uil2.msgs.BaseMsg;
040: import org.jboss.mq.il.uil2.msgs.MsgTypes;
041: import org.jboss.security.SecurityDomain;
042: import org.jboss.system.server.ServerConfigUtil;
043:
044: import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
045: import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
046:
047: /** This is the server side MBean for the UIL2 transport layer.
048: *
049: * @author Scott.Stark@jboss.org
050: * @version $Revision: 61545 $
051: *
052: * @jmx:mbean extends="org.jboss.mq.il.ServerILJMXServiceMBean"
053: */
054: public class UILServerILService extends ServerILJMXService implements
055: MsgTypes, Runnable, UILServerILServiceMBean {
056: final static int SO_TIMEOUT = 5000;
057:
058: /** The security domain name to use with SSL aware socket factories.
059: */
060: private String securityDomain;
061: /* The javax.net.SocketFactory implementation class to use on the client.
062: */
063: private String clientSocketFactoryName;
064: /** The socket factory used to obtain the server socket.
065: */
066: private ServerSocketFactory serverSocketFactory;
067: /** The UIL2 server socket clients connect to
068: */
069: private ServerSocket serverSocket;
070: private UILServerIL serverIL;
071: private SynchronizedBoolean running = new SynchronizedBoolean(false);
072: /** The server jms listening port */
073: private int serverBindPort = 0;
074: /** The server jms address the listening socket binds to */
075: private InetAddress bindAddress = null;
076: /** The thread that manages the client connection attempts */
077: private Thread acceptThread;
078: /** The address passed to the client il layer as the address that should
079: * be used to connect to the server.
080: */
081: private InetAddress clientAddress;
082: /** The address passed to the client il layer as the address that should
083: * be used to connect to the server.
084: */
085: private String connectAddress;
086: /** The port passed to the client il layer as the address that should
087: * be used to connect to the server.
088: */
089: private int connectPort;
090: /**
091: * If the TcpNoDelay option should be used on the socket.
092: */
093: private boolean enableTcpNoDelay = false;
094:
095: /**
096: * The socket read timeout.
097: */
098: private int readTimeout = 0;
099:
100: /**
101: * The client socket read timeout.
102: */
103: private int clientReadTimeout = 0;
104:
105: /**
106: * The buffer size.
107: */
108: private int bufferSize = 1;
109:
110: /**
111: * The chunk size.
112: */
113: private int chunkSize = 0x40000000;
114:
115: /**
116: * The connection properties passed to the client to connect to this IL
117: */
118: private Properties connectionProperties;
119:
120: /** The server handlers */
121: private CopyOnWriteArrayList handlers = new CopyOnWriteArrayList();
122:
123: /**
124: * Used to construct the GenericConnectionFactory (bindJNDIReferences()
125: * builds it) Sets up the connection properties need by a client to use this
126: * IL
127: *
128: * @return The ClientConnectionProperties value
129: */
130: public Properties getClientConnectionProperties() {
131: return connectionProperties;
132: }
133:
134: /**
135: * Used to construct the GenericConnectionFactory (bindJNDIReferences()
136: * builds it)
137: *
138: * @return The ServerIL value
139: * @return ServerIL the instance of this IL
140: */
141: public ServerIL getServerIL() {
142: return serverIL;
143: }
144:
145: /** Client socket accept thread.
146: */
147: public void run() {
148: boolean trace = log.isTraceEnabled();
149: while (running.get()) {
150: Socket socket = null;
151: SocketManager socketMgr = null;
152: try {
153: socket = serverSocket.accept();
154: if (trace)
155: log.trace("Accepted connection: " + socket);
156: socket.setSoTimeout(readTimeout);
157: socket.setTcpNoDelay(enableTcpNoDelay);
158: socketMgr = new SocketManager(socket);
159: ServerSocketManagerHandler handler = new ServerSocketManagerHandler(
160: getJMSServer(), socketMgr, this );
161: handlers.add(handler);
162: socketMgr.setHandler(handler);
163: socketMgr.setBufferSize(bufferSize);
164: socketMgr.setChunkSize(chunkSize);
165: Invoker s = getJMSServer();
166: socketMgr.start(s.getThreadGroup());
167: } catch (IOException e) {
168: if (running.get())
169: log.warn("Failed to setup client connection", e);
170: } catch (Throwable e) {
171: if (running.get() || trace)
172: log
173: .warn(
174: "Unexpected error in setup of client connection",
175: e);
176: }
177: }
178: }
179:
180: /**
181: * Starts this IL, and binds it to JNDI
182: *
183: * @exception Exception Description of Exception
184: */
185: public void startService() throws Exception {
186: super .startService();
187:
188: // Use the default javax.net.ServerSocketFactory if none was set
189: if (serverSocketFactory == null)
190: serverSocketFactory = ServerSocketFactory.getDefault();
191:
192: /* See if the server socket supports setSecurityDomain(SecurityDomain)
193: if an securityDomain was specified
194: */
195: if (securityDomain != null) {
196: try {
197: InitialContext ctx = new InitialContext();
198: Class ssfClass = serverSocketFactory.getClass();
199: SecurityDomain domain = (SecurityDomain) ctx
200: .lookup(securityDomain);
201: Class[] parameterTypes = { SecurityDomain.class };
202: Method m = ssfClass.getMethod("setSecurityDomain",
203: parameterTypes);
204: Object[] args = { domain };
205: m.invoke(serverSocketFactory, args);
206: } catch (NoSuchMethodException e) {
207: log
208: .error("Socket factory does not support setSecurityDomain(SecurityDomain)");
209: } catch (Exception e) {
210: log.error("Failed to setSecurityDomain="
211: + securityDomain + " on socket factory");
212: }
213: }
214:
215: // Create the server socket using the socket factory
216: serverSocket = serverSocketFactory.createServerSocket(
217: serverBindPort, 50, bindAddress);
218:
219: InetAddress socketAddress = serverSocket.getInetAddress();
220: log.info("JBossMQ UIL service available at : " + socketAddress
221: + ":" + serverSocket.getLocalPort());
222: acceptThread = new Thread(getJMSServer().getThreadGroup(),
223: this , "UILServerILService Accept Thread");
224: running.set(true);
225: acceptThread.start();
226:
227: /* We need to check the socketAddress against "0.0.0.0/0.0.0.0"
228: because this is not a valid address on Win32 while it is for
229: *NIX. See BugParade bug #4343286.
230: */
231: socketAddress = ServerConfigUtil
232: .fixRemoteAddress(socketAddress);
233: // If an explicit client bind address has been specified use it
234: if (clientAddress != null)
235: socketAddress = clientAddress;
236: serverIL = new UILServerIL(socketAddress, serverSocket
237: .getLocalPort(), clientSocketFactoryName,
238: enableTcpNoDelay, bufferSize, chunkSize,
239: clientReadTimeout, connectAddress, connectPort);
240:
241: // Initialize the connection poperties using the base class.
242: connectionProperties = super .getClientConnectionProperties();
243: connectionProperties.setProperty(
244: UILServerILFactory.CLIENT_IL_SERVICE_KEY,
245: UILClientILService.class.getName());
246: connectionProperties.setProperty(
247: UILServerILFactory.UIL_PORT_KEY, ""
248: + serverSocket.getLocalPort());
249: connectionProperties.setProperty(
250: UILServerILFactory.UIL_ADDRESS_KEY, ""
251: + socketAddress.getHostAddress());
252: connectionProperties.setProperty(
253: UILServerILFactory.UIL_TCPNODELAY_KEY,
254: enableTcpNoDelay ? "yes" : "no");
255: connectionProperties.setProperty(
256: UILServerILFactory.UIL_BUFFERSIZE_KEY, "" + bufferSize);
257: connectionProperties.setProperty(
258: UILServerILFactory.UIL_CHUNKSIZE_KEY, "" + chunkSize);
259: connectionProperties.setProperty(
260: UILServerILFactory.UIL_RECEIVE_REPLIES_KEY, "No");
261: connectionProperties.setProperty(
262: UILServerILFactory.UIL_SOTIMEOUT_KEY, ""
263: + clientReadTimeout);
264: connectionProperties.setProperty(
265: UILServerILFactory.UIL_CONNECTADDRESS_KEY, ""
266: + connectAddress);
267: connectionProperties.setProperty(
268: UILServerILFactory.UIL_CONNECTPORT_KEY, ""
269: + connectPort);
270:
271: bindJNDIReferences();
272: BaseMsg.setUseJMSServerMsgIDs(true);
273: }
274:
275: /**
276: * Stops this IL, and unbinds it from JNDI
277: */
278: public void stopService() {
279: try {
280: running.set(false);
281: unbindJNDIReferences();
282:
283: // unbind Server Socket if needed
284: if (serverSocket != null) {
285: serverSocket.close();
286: }
287: } catch (Exception e) {
288: log
289: .error(
290: "Exception occured when trying to stop UIL Service: ",
291: e);
292: }
293:
294: // Try to close any open sockets that we know about
295: for (Iterator i = handlers.iterator(); i.hasNext();) {
296: ServerSocketManagerHandler handler = (ServerSocketManagerHandler) i
297: .next();
298: if (handler != null) {
299: try {
300: handler.close();
301: } catch (Throwable ignored) {
302: }
303: }
304: }
305: }
306:
307: protected void removeHandler(ServerSocketManagerHandler handler) {
308: handlers.remove(handler);
309: }
310:
311: /**
312: * Get the UIL server listening port
313: *
314: * @return Value of property serverBindPort.
315: *
316: * @jmx:managed-attribute
317: */
318: public int getServerBindPort() {
319: return serverBindPort;
320: }
321:
322: /**
323: * Set the UIL server listening port
324: *
325: * @param serverBindPort New value of property serverBindPort.
326: *
327: * @jmx:managed-attribute
328: */
329: public void setServerBindPort(int serverBindPort) {
330: this .serverBindPort = serverBindPort;
331: }
332:
333: /**
334: * Get the interface address the UIL2 server bind its listening port on
335: *
336: * @jmx:managed-attribute
337: */
338: public String getBindAddress() {
339: String addr = "0.0.0.0";
340: if (bindAddress != null)
341: addr = bindAddress.getHostName();
342: return addr;
343: }
344:
345: /**
346: * Set the interface address the UIL2 server bind its listening port on
347: *
348: * @jmx:managed-attribute
349: */
350: public void setBindAddress(String host) throws UnknownHostException {
351: // If host is null or empty use any address
352: if (host == null || host.length() == 0)
353: bindAddress = null;
354: else
355: bindAddress = InetAddress.getByName(host);
356: }
357:
358: public InetAddress getClientAddress() {
359: return clientAddress;
360: }
361:
362: public void setClientAddress(InetAddress addr) {
363: log
364: .warn("ClientAddress has been deprecated, use ConnectAddress");
365: clientAddress = addr;
366: }
367:
368: public String getConnectAddress() {
369: return connectAddress;
370: }
371:
372: public void setConnectAddress(String addr) {
373: connectAddress = addr;
374: }
375:
376: public int getConnectPort() {
377: return connectPort;
378: }
379:
380: public void setConnectPort(int port) {
381: connectPort = port;
382: }
383:
384: /**
385: * Gets the enableTcpNoDelay.
386: * @return Returns a boolean
387: *
388: * @jmx:managed-attribute
389: */
390: public boolean getEnableTcpNoDelay() {
391: return enableTcpNoDelay;
392: }
393:
394: /**
395: * Sets the enableTcpNoDelay.
396: * @param enableTcpNoDelay The enableTcpNoDelay to set
397: *
398: * @jmx:managed-attribute
399: */
400: public void setEnableTcpNoDelay(boolean enableTcpNoDelay) {
401: this .enableTcpNoDelay = enableTcpNoDelay;
402: }
403:
404: /**
405: * Gets the buffer size.
406: * @return Returns an int
407: *
408: * @jmx:managed-attribute
409: */
410: public int getBufferSize() {
411: return bufferSize;
412: }
413:
414: /**
415: * Sets the buffer size.
416: * @param size the buffer size
417: *
418: * @jmx:managed-attribute
419: */
420: public void setBufferSize(int size) {
421: this .bufferSize = size;
422: }
423:
424: /**
425: * Gets the chunk size.
426: * @return Returns an int
427: *
428: * @jmx:managed-attribute
429: */
430: public int getChunkSize() {
431: return chunkSize;
432: }
433:
434: /**
435: * Sets the chunk size.
436: * @param size the chunk size
437: *
438: * @jmx:managed-attribute
439: */
440: public void setChunkSize(int size) {
441: this .chunkSize = size;
442: }
443:
444: public int getReadTimeout() {
445: return readTimeout;
446: }
447:
448: public void setReadTimeout(int timeout) {
449: this .readTimeout = timeout;
450: }
451:
452: public int getClientReadTimeout() {
453: return clientReadTimeout;
454: }
455:
456: public void setClientReadTimeout(int timeout) {
457: this .clientReadTimeout = timeout;
458: }
459:
460: /** Get the javax.net.SocketFactory implementation class to use on the
461: *client.
462: * @jmx:managed-attribute
463: */
464: public String getClientSocketFactory() {
465: return clientSocketFactoryName;
466: }
467:
468: /** Set the javax.net.SocketFactory implementation class to use on the
469: *client.
470: * @jmx:managed-attribute
471: */
472: public void setClientSocketFactory(String name) {
473: this .clientSocketFactoryName = name;
474: }
475:
476: /** Set the javax.net.ServerSocketFactory implementation class to use to
477: *create the service SocketFactory.
478: *@jmx:managed-attribute
479: */
480: public void setServerSocketFactory(String name) throws Exception {
481: ClassLoader loader = Thread.currentThread()
482: .getContextClassLoader();
483: Class ssfClass = loader.loadClass(name);
484: serverSocketFactory = (ServerSocketFactory) ssfClass
485: .newInstance();
486: }
487:
488: /** Get the javax.net.ServerSocketFactory implementation class to use to
489: *create the service SocketFactory.
490: *@jmx:managed-attribute
491: */
492: public String getServerSocketFactory() {
493: String name = null;
494: if (serverSocketFactory != null)
495: name = serverSocketFactory.getClass().getName();
496: return name;
497: }
498:
499: /** Set the security domain name to use with SSL aware socket factories
500: *@jmx:managed-attribute
501: */
502: public void setSecurityDomain(String domainName) {
503: this .securityDomain = domainName;
504: }
505:
506: /** Get the security domain name to use with SSL aware socket factories
507: *@jmx:managed-attribute
508: */
509: public String getSecurityDomain() {
510: return this.securityDomain;
511: }
512: }
|