/projects/quickserver-1.4.7/src/main/org/quickserver/net/server/impl/BasicClientHandler.java
Java | 1356 lines | 739 code | 147 blank | 470 comment | 125 complexity | 60f1e5dcc859d78a4f202c5992e2b249 MD5 | raw file
- /*
- * This file is part of the QuickServer library
- * Copyright (C) 2003-2005 QuickServer.org
- *
- * Use, modification, copying and distribution of this software is subject to
- * the terms and conditions of the GNU Lesser General Public License.
- * You should have received a copy of the GNU LGP License along with this
- * library; if not, you can download a copy from <http://www.quickserver.org/>.
- *
- * For questions, suggestions, bug-reports, enhancement-requests etc.
- * visit http://www.quickserver.org
- *
- */
-
- package org.quickserver.net.server.impl;
-
- import java.io.*;
- import java.net.Socket;
- import java.net.SocketException;
- import java.net.SocketTimeoutException;
- import java.net.InetAddress;
- import java.util.*;
- import java.util.logging.*;
- import javax.net.ssl.*;
- import java.security.*;
- import java.nio.*;
- import java.nio.channels.*;
-
- import org.quickserver.net.*;
- import org.quickserver.util.*;
- import org.quickserver.net.server.*;
-
- /**
- * Basic implementation of ClientHandler that handles clients for QuickServer.
- * <p> This class is used by {@link QuickServer} to handle each new client
- * connected. This class is responsible to handle client sockets. It can operate
- * in both blocking mode and non-blocking mode (java nio).</p>
- * <p>
- * Contributions By:
- * Martin Benns : BYTE Mode
- * </p>
- * @author Akshathkumar Shetty
- * @author Martin Benns : Added BYTE mode
- */
- public abstract class BasicClientHandler implements ClientHandler {
- private static final Logger logger = Logger.getLogger(BasicClientHandler.class.getName());
-
- protected static final String NEW_LINE = QuickServer.getNewLine();
- protected static final byte NEW_LINE_BYTES[] = NEW_LINE.getBytes();
-
- //Some variable are not initialised to any value because the
- //default java value was desired initial value.
-
- /** Client socket */
- protected Socket socket;
- /** Client authorisation status */
- protected volatile boolean authorised;
- /** Count of client login attempts */
- protected int counAuthTry;
- /** max allowed login attempts */
- protected int maxAuthTry = 5;
- /** timeout message */
- protected String timeoutMsg;
- /** Message to be displayed when max login attempt reaches.*/
- protected String maxAuthTryMsg;
-
- protected int socketTimeout;
- protected volatile boolean connection; //false
- protected boolean lost; //false
-
- protected QuickServer quickServer;
- protected Authenticator authenticator; //v1.3
- protected ClientAuthenticationHandler clientAuthenticationHandler; //v1.4.6
- protected ClientEventHandler clientEventHandler; //v1.4.6
- protected ClientExtendedEventHandler clientExtendedEventHandler; //v1.4.6
- protected ClientCommandHandler clientCommandHandler;
- protected ClientObjectHandler clientObjectHandler; //v1.2
- protected ClientBinaryHandler clientBinaryHandler; //1.4
- protected ClientData clientData;
-
- protected InputStream in;
- protected OutputStream out;
- protected BufferedReader bufferedReader;
- //if DataMode.OBJECT
- protected ObjectOutputStream o_out; //v1.2
- protected ObjectInputStream o_in; //v1.2
- //added for BYTE mode and BINARY mode
- protected BufferedInputStream b_in;
- protected BufferedOutputStream b_out;
-
- //logger for the application using this QuickServer
- protected Logger appLogger;
- protected DataMode dataModeIN = null;
- protected DataMode dataModeOUT = null;
-
- protected boolean communicationLogging = true;
- protected Date clientConnectedTime = null;
- protected Date lastCommunicationTime = null;
- protected boolean secure = false;
-
- //--v1.4.5
- protected static final ThreadLocal threadEvent = new ThreadLocal();
-
- protected String maxConnectionMsg;
- protected Set clientEvents = new HashSet();
- protected List unprocessedClientEvents = Collections.synchronizedList(new ArrayList());
-
- protected volatile boolean closeOrLostNotified;
- protected Object lockObj = new Object();
- protected volatile boolean willClean;
- protected String charset;
-
- private static Map idMap = new HashMap();
- private int instanceCount;
- private int id;
- private String name;
- private String hostAddress;
- private int port;
-
- static class InstanceId {
- private int id = 0;
- public int getNextId() {
- return ++id;
- }
- };
-
- private static int getNewId(int instanceCount) {
- InstanceId instanceId = (InstanceId) idMap.get(""+instanceCount);
- if(instanceId==null) {
- instanceId = new InstanceId();
- idMap.put(""+instanceCount, instanceId);
- }
- return instanceId.getNextId();
- }
-
- public BasicClientHandler(int instanceCount) {
- this.instanceCount = instanceCount;
- id = getNewId(instanceCount);
-
- StringBuffer sb = new StringBuffer();
- sb.append("<ClientHandler-Pool#");
- sb.append(instanceCount);
- sb.append("-ID:");
- sb.append(id);
- sb.append(">");
- name = sb.toString();
- }
-
- public int getInstanceCount() {
- return instanceCount;
- }
-
-
- public BasicClientHandler() {
- this(-1);
- }
-
- public void clean() {
- counAuthTry = 0;
- authorised = false;
- in = null;
- out = null;
- bufferedReader = null;
- o_out = null; o_in = null;
- b_in = null; b_out = null;
-
- dataModeIN = null;
- dataModeOUT = null;
-
- lost = false;
- clientData = null;
- clientConnectedTime = null;
- lastCommunicationTime = null;
- communicationLogging = true;
- socketTimeout = 0;
- secure = false;
-
- authenticator = null;
- clientAuthenticationHandler = null;//1.4.6
- clientCommandHandler = null;
- clientObjectHandler = null;
- clientBinaryHandler = null;//1.4
- clientData = null;
-
- maxConnectionMsg = null;
- synchronized(clientEvents) {
- clientEvents.clear();
- unprocessedClientEvents.clear();
- }
-
- closeOrLostNotified = false;
-
- if(socket!=null) {
- try {
- socket.close();
- } catch(Exception er) {
- appLogger.warning("Error in closing socket: "+er);
- }
- socket = null;
- }
-
- hostAddress = null;
- port = 0;
-
- quickServer = null;
- willClean = false;
- charset = null;
- }
-
- protected void finalize() throws Throwable {
- super.finalize();
- }
-
- /**
- * Associates the ClientHanlder with the client encapsulated by
- * <code>theClient</code>.
- * @param theClient object that encapsulates client socket
- * and its configuration details.
- */
- public void handleClient(TheClient theClient) {
- setServer(theClient.getServer());
-
- if(getServer().isRunningSecure()==true) {
- setSecure(true);
- }
- setSocket(theClient.getSocket());
-
- if(theClient.getTrusted()==false) {
- setAuthenticator(theClient.getAuthenticator());
- setClientAuthenticationHandler(theClient.getClientAuthenticationHandler());
- }
- setClientEventHandler(theClient.getClientEventHandler());
- setClientExtendedEventHandler(theClient.getClientExtendedEventHandler());
- setClientCommandHandler(theClient.getClientCommandHandler());
- setClientObjectHandler(theClient.getClientObjectHandler());
- setClientBinaryHandler(theClient.getClientBinaryHandler()); //v1.4
-
- setClientData(theClient.getClientData());
- if(theClient.getTrusted()==false) {
- socketTimeout = theClient.getTimeout();
- }
- timeoutMsg = theClient.getTimeoutMsg();
- maxAuthTryMsg = theClient.getMaxAuthTryMsg();
- maxAuthTry = theClient.getMaxAuthTry(); //v1.2
- appLogger = quickServer.getAppLogger(); //v1.2
-
- setCommunicationLogging(theClient.getCommunicationLogging()); //v1.3.2
-
- maxConnectionMsg = theClient.getMaxConnectionMsg();//1.4.5
- addEvent(theClient.getClientEvent());//1.4.5
- }
-
- /**
- * Returns the QuickServer object that created it.
- * @see #setServer
- */
- public QuickServer getServer() {
- return quickServer;
- }
- /**
- * Sets the QuickServer object associated with this ClientHandler.
- * @see #getServer
- */
- protected void setServer(QuickServer server) {
- Assertion.affirm(server!=null, "QuickServer can't be null!");
- quickServer = server;
- }
-
- /**
- * Sets the ClientData object associated with this ClientHandler
- * @see ClientData
- * @see #getClientData
- */
- protected void setClientData(ClientData data) {
- this.clientData = data;
- }
- /**
- * Returns the ClientData object associated with this ClientHandler,
- * if not set will return <code>null</code>
- * @see ClientData
- * @see #setClientData
- */
- public ClientData getClientData() {
- return clientData;
- }
-
- /**
- * Sets the ClientAuthenticationHandler class that handles the
- * authentication of a client.
- * @param clientAuthenticationHandler fully qualified name of the class that
- * implements {@link ClientAuthenticationHandler}.
- * @since 1.4.6
- */
- protected void setClientAuthenticationHandler(ClientAuthenticationHandler clientAuthenticationHandler) {
- this.clientAuthenticationHandler = clientAuthenticationHandler;
- }
-
- /**
- * Sets the Authenticator class that handles the
- * authentication of a client.
- * @param authenticator fully qualified name of the class that
- * implements {@link Authenticator}.
- * @since 1.3
- */
- protected void setAuthenticator(Authenticator authenticator) {
- this.authenticator = authenticator;
- }
-
- /**
- * Returns the {@link java.io.InputStream} associated with
- * the Client being handled.
- * @see #setInputStream
- */
- public InputStream getInputStream() {
- return in;
- }
- /**
- * Sets the {@link java.io.InputStream} associated with
- * the Client being handled.
- * @since 1.1
- * @see #getInputStream
- */
- protected abstract void setInputStream(InputStream in) throws IOException;
-
- /**
- * Returns the {@link java.io.OutputStream} associated with
- * the Client being handled.
- * @see #setOutputStream
- */
- public OutputStream getOutputStream() {
- return out;
- }
- /**
- * Set the {@link java.io.OutputStream} associated with
- * the Client being handled.
- * @since 1.1
- * @see #getOutputStream
- * @exception IOException if ObjectOutputStream could not be created.
- */
- public void setOutputStream(OutputStream out) throws IOException {
- this.out = out;
- if(getDataMode(DataType.OUT) == DataMode.STRING ||
- getDataMode(DataType.OUT) == DataMode.BYTE ||
- getDataMode(DataType.OUT) == DataMode.BINARY) {
- o_out = null;
- b_out = new BufferedOutputStream(out);
- } else if(getDataMode(DataType.OUT) == DataMode.OBJECT) {
- b_out = null;
- o_out = new ObjectOutputStream(out);
- o_out.flush();
- } else {
- throw new IllegalStateException("Unknown DataMode " +getDataMode(DataType.OUT));
- }
- }
-
- /**
- * Returns the {@link java.io.BufferedReader} associated with
- * the Client being handled. Note that this is only available under blocking mode.
- * @see #getBufferedWriter
- */
- public abstract BufferedReader getBufferedReader();
-
- /**
- * Returns the {@link java.io.BufferedWriter} associated with
- * the Client being handled.
- * @deprecated since 1.4.5 use getOutputStream()
- */
- public BufferedWriter getBufferedWriter() {
- return new BufferedWriter(new OutputStreamWriter(b_out));
- }
-
- /**
- * Returns the {@link java.io.ObjectOutputStream} associated with
- * the Client being handled.
- * It will be <code>null</code> if no {@link ClientObjectHandler}
- * was set in {@link QuickServer}.
- * @see #getObjectInputStream
- * @since 1.2
- */
- public ObjectOutputStream getObjectOutputStream() {
- return o_out;
- }
- /**
- * Returns the {@link java.io.ObjectInputStream} associated with
- * the Client being handled.
- * It will be <code>null</code> if no {@link ClientObjectHandler}
- * was set in {@link QuickServer}.
- * @see #getObjectOutputStream
- * @since 1.2
- */
- public ObjectInputStream getObjectInputStream() {
- return o_in;
- }
-
- /**
- * Sets the ClientEventHandler class that gets notified of client events.
- * @since 1.4.6
- */
- protected void setClientEventHandler(ClientEventHandler handler) {
- clientEventHandler=handler;
- }
-
- /**
- * Sets the ClientExtendedEventHandler class that gets notified of extended client events.
- * @since 1.4.6
- */
- protected void setClientExtendedEventHandler(ClientExtendedEventHandler handler) {
- clientExtendedEventHandler=handler;
- }
-
- /**
- * Sets the ClientCommandHandler class that interacts with
- * client sockets.
- */
- protected void setClientCommandHandler(ClientCommandHandler handler) {
- clientCommandHandler=handler;
- }
-
- /**
- * Sets the ClientObjectHandler class that interacts with
- * client sockets.
- * @param handler fully qualified name of the class that
- * implements {@link ClientObjectHandler}
- * @since 1.2
- */
- protected void setClientObjectHandler(ClientObjectHandler handler) {
- clientObjectHandler = handler;
- }
-
- /** Closes client socket associated. */
- public abstract void closeConnection();
-
- /** Returns client socket associated. */
- public Socket getSocket() {
- return socket;
- }
-
- /**
- * Returns client socket associated.
- * @since 1.4.0
- * @see #updateInputOutputStreams
- */
- public void setSocket(Socket socket) {
- this.socket = socket;
- }
-
- /**
- * Checks if the client is still connected.
- * @exception SocketException if Socket is not open.
- * @deprecated since 1.4.5 Use {@link #isConnected}
- */
- public boolean isConected() throws SocketException {
- return isConnected();
- }
-
- /**
- * Checks if the client is still connected.
- * @exception SocketException if Socket is not open.
- * @since 1.4.5
- */
- public boolean isConnected() throws SocketException {
- if(isOpen()==false)
- throw new SocketException("Connection is no more open!");
- else
- return true;
- }
-
- /**
- * Checks if the client is still connected and if socket is open. This is same as isConnected()
- * but does not throw SocketException.
- * @since 1.4.6
- */
- public boolean isOpen() {
- if(lost==true || socket==null || socket.isConnected()==false || socket.isClosed()==true)
- return false;
- else
- return true;
- }
-
- /**
- * Checks if the client is closed.
- * @since 1.4.1
- */
- public boolean isClosed() {
- if(socket==null || socket.isClosed()==true)
- return true;
- else
- return false;
- }
-
- /**
- * Send a String message to the connected client
- * it adds a new line{\r\n} to the end of the string.
- * If client is not connected it will just return.
- * @exception IOException
- * if Socket IO Error or Socket was closed by the client.
- */
- public void sendClientMsg(String msg) throws IOException {
- isConnected();
-
- if(dataModeOUT != DataMode.STRING)
- throw new IllegalStateException("Can't send String :" +
- "DataType.OUT is not in DataMode.STRING");
- if(getCommunicationLogging()) {
- appLogger.fine("Sending ["+getHostAddress()+"] : "+msg);
- }
- byte data[] = msg.getBytes(charset);
- b_out.write(data, 0, data.length);
- b_out.write(NEW_LINE_BYTES, 0, NEW_LINE_BYTES.length);
- b_out.flush();
-
- updateLastCommunicationTime();
- }
-
- /**
- * Send a String message to the connected client as a string of bytes.
- * If client is not connected it will just return.
- * @since 1.3.1
- * @exception IOException
- * if Socket IO Error or Socket was closed by the client.
- */
- public void sendClientBytes(String msg) throws IOException {
- isConnected();
-
- if (dataModeOUT != DataMode.BYTE)
- throw new IllegalStateException("Can't send String :" +
- "DataType.OUT is not in DataMode.BYTE");
- if(getCommunicationLogging()) {
- appLogger.fine("Sending ["+getHostAddress()+"] : "+msg);
- }
- byte data[] = msg.getBytes(charset);
- b_out.write(data,0,data.length);
- b_out.flush();
-
- updateLastCommunicationTime();
- }
-
-
- /**
- * Send a Object message to the connected client. The message Object
- * passed must be serializable. If client is not connected it
- * will just return.
- * @exception IOException if Socket IO Error or Socket was closed
- * by the client.
- * @exception IllegalStateException if DataType.OUT is not in
- * DataMode.OBJECT
- * @see #setDataMode
- * @since 1.2
- */
- public void sendClientObject(Object msg) throws IOException {
- isConnected();
-
- if(dataModeOUT != DataMode.OBJECT)
- throw new IllegalStateException("Can't send Object : DataType.OUT is not in DataMode.OBJECT");
- if(getCommunicationLogging()) {
- appLogger.fine("Sending ["+getHostAddress()+"] : "+msg.toString());
- }
- o_out.writeObject(msg);
- o_out.flush();
-
- updateLastCommunicationTime();
- }
-
- /**
- * Send a String message to the logger associated with
- * {@link QuickServer#getAppLogger} with Level.INFO as its level.
- */
- public void sendSystemMsg(String msg) {
- sendSystemMsg(msg, Level.INFO);
- }
-
- /**
- * Send a String message to the logger associated with
- * {@link QuickServer#getAppLogger}.
- * @since 1.2
- */
- public void sendSystemMsg(String msg, Level level) {
- appLogger.log(level, msg);
- }
-
- /**
- * Send a String message to the system output stream.
- * @param newline indicates if new line required at the end.
- * @deprecated Use {@link #sendSystemMsg(java.lang.String)},
- * since it uses Logging.
- */
- public void sendSystemMsg(String msg, boolean newline) {
- if(newline)
- System.out.println(msg);
- else
- System.out.print(msg);
- }
-
- public abstract void run();
-
- protected void prepareForRun() throws SocketException, IOException {
- clientConnectedTime = new java.util.Date(); //v1.3.2
- lastCommunicationTime = clientConnectedTime;//v1.3.3
-
- setCharset(getServer().getBasicConfig().getAdvancedSettings().getCharset());//1.4.5
- hostAddress = getSocket().getInetAddress().getHostAddress();//1.4.5
- port = getSocket().getPort();
-
- if(logger.isLoggable(Level.FINEST)) {
- StringBuffer sb = new StringBuffer();
- sb.append(getName());
- sb.append(" -> ");
- sb.append(hostAddress);
- sb.append(':');
- sb.append(port);
- logger.finest(sb.toString());
- }
-
- socket.setSoTimeout(socketTimeout);
- connection = true;
-
- dataModeIN = getServer().getDefaultDataMode(DataType.IN);
- dataModeOUT = getServer().getDefaultDataMode(DataType.OUT);
-
- updateInputOutputStreams();
- }
-
- protected void processMaxConnection(ClientEvent currentEvent) throws IOException {
- if(clientExtendedEventHandler!=null) {
- if(clientExtendedEventHandler.handleMaxConnection(this)) {
- removeEvent(getThreadEvent());
- if(getThreadEvent()==ClientEvent.MAX_CON) {
- currentEvent = ClientEvent.ACCEPT;
- } else if(getThreadEvent()==ClientEvent.MAX_CON_BLOCKING) {
- currentEvent = ClientEvent.RUN_BLOCKING;
- } else {
- throw new IllegalArgumentException("Unknown ClientEvent: "+getThreadEvent());
- }
- synchronized(clientEvents) {
- clientEvents.add(currentEvent);
- }
- threadEvent.set(currentEvent);
- }
- } else if(maxConnectionMsg.length()!=0) {
- out.write(maxConnectionMsg.getBytes(charset), 0, maxConnectionMsg.length());
- out.write(NEW_LINE_BYTES, 0, NEW_LINE_BYTES.length);
- out.flush();
- }
- }
-
- protected AuthStatus processAuthorisation() throws SocketException,
- IOException, AppException {
- logger.finest("INSIDE");
- while(authorised==false && connection==true) {
- isConnected();
-
- counAuthTry++;
-
- if(authorised == false) {
- if(counAuthTry > maxAuthTry) {
- processMaxAuthTry();
- }
- }
-
- try {
- if(clientAuthenticationHandler!=null) {
- return clientAuthenticationHandler.askAuthentication(this);
- } else if(authenticator!=null) {
- authorised = authenticator.askAuthorisation(this);
- }
- } catch(NullPointerException e) {
- logger.severe("Authenticator implementation has not handled null properly."+
- " Input from client should be checked for null!");
- throw e;
- } catch(SocketTimeoutException e) {
- handleTimeout(e);
- }
-
- updateLastCommunicationTime();
- } //end of auth while
- return AuthStatus.SUCCESS;
- }
-
- private void processMaxAuthTry() throws SocketException, IOException, AppException {
- if(clientExtendedEventHandler!=null) {
- clientExtendedEventHandler.handleMaxAuthTry(this);
- } else {
- String temp = maxAuthTryMsg;
- if(dataModeOUT == DataMode.STRING)
- temp = temp + NEW_LINE;
- if(dataModeOUT != DataMode.OBJECT) {
- out.write(temp.getBytes(charset));
- out.flush();
- }
- }
- appLogger.warning("Max Auth Try Reached - Client : "+getHostAddress());
- if(true) throw new AppException(maxAuthTryMsg);
- }
-
-
- protected void notifyCloseOrLost() throws IOException {
- synchronized(this) {
- if(closeOrLostNotified==false) {
- if(lost==true) {
- clientEventHandler.lostConnection(this);
- } else {
- clientEventHandler.closingConnection(this);
- }
- closeOrLostNotified = true;
- }
- }
- }
-
- protected synchronized void returnClientData() {
- if(clientData==null || getServer().getClientDataPool()==null)
- return;
- logger.finest("Returning ClientData to pool");
- try {
- getServer().getClientDataPool().returnObject(clientData);
- clientData = null;
- } catch(Exception e) {
- logger.warning("IGNORED: Could not return ClientData to pool: "+e);
- }
- }
-
- protected void returnClientHandler() {
- try {
- synchronized(lockObj) {
- logger.finest(Thread.currentThread().getName()+" returning "+getName());
- getServer().getClientHandlerPool().returnObject(this);
- }
- } catch(Exception e) {
- logger.warning("IGNORED: Could not return ClientHandler to pool: "+e);
- }
- }
-
- /**
- * Returns the ClientHandler name
- * @since 1.4.6
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the ClientHandler detailed information.
- * If ClientData is present and is ClientIdentifiable will return ClientInfo else
- * it will return Clients InetAddress and port information.
- */
- public String info() {
- StringBuffer sb = new StringBuffer();
- sb.append("{");
- sb.append(name);
- sb.append(" - ");
- String info = getClientIdentifiable(this);
- if(info!=null) {
- sb.append("[ClientInfo: ");
- sb.append(info);
- sb.append(']');
- }
-
- if(getSocket()==null || getSocket().isClosed()==true) {
- sb.append("[non-connected]");
- } else if(info==null) {
- sb.append('[');
- sb.append(hostAddress);
- sb.append(':');
- sb.append(port);
- sb.append(']');
- }
- sb.append('}');
- return sb.toString();
- }
-
- /**
- * Returns the ClientHandler information.
- * If ClientData is present and is ClientIdentifiable will return ClientInfo else
- * it will return Clients InetAddress and port information.
- */
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("{");
- sb.append(name);
- sb.append(" - ");
- if(getSocket()==null || getSocket().isClosed()==true) {
- sb.append("[non-connected]");
- } else if(hostAddress!=null) {
- sb.append('[');
- sb.append(hostAddress);
- sb.append(':');
- sb.append(port);
- sb.append(']');
- }
- synchronized(clientEvents) {
- if(clientEvents.size()!=0) {
- sb.append(' ');
- sb.append(clientEvents);
- }
- }
- sb.append('}');
- return sb.toString();
- }
-
- protected static String getClientIdentifiable(ClientHandler foundClientHandler) {
- if(foundClientHandler==null) return null;
- ClientData foundClientData = null;
- foundClientData = foundClientHandler.getClientData();
- if(foundClientData==null)
- return null;
- else if(ClientIdentifiable.class.isInstance(foundClientData)==false)
- return null;
- else
- return ((ClientIdentifiable)foundClientData).getClientInfo();
- }
-
- /**
- * Sets the {@link DataMode} for the ClientHandler
- *
- * Note: When mode is DataMode.OBJECT and type is DataType.IN
- * this call will block until the client ObjectOutputStream has
- * written and flushes the header.
- * @since 1.2
- * @exception IOException if mode could not be changed.
- * @param dataMode mode of data exchange - String or Object.
- * @param dataType type of data for which mode has to be set.
- */
- public abstract void setDataMode(DataMode dataMode, DataType dataType) throws IOException;
-
- protected void checkDataModeSet(DataMode dataMode, DataType dataType) {
- if(dataMode==DataMode.STRING && dataType==DataType.IN && clientCommandHandler==null) {
- throw new IllegalArgumentException("Can't set DataType.IN mode to STRING when ClientCommandHandler is not set!");
- }
-
- if(dataMode==DataMode.BYTE && dataType==DataType.IN && clientCommandHandler==null) {
- throw new IllegalArgumentException("Can't set DataType.IN mode to BYTE when ClientCommandHandler is not set!");
- }
-
- if(dataMode==DataMode.OBJECT && dataType==DataType.IN && clientObjectHandler==null) {
- throw new IllegalArgumentException("Can't set DataType.IN mode to OBJECT when ClientObjectHandler is not set!");
- }
-
- if(dataMode==DataMode.BINARY && dataType==DataType.IN && clientBinaryHandler==null) {
- throw new IllegalArgumentException("Can't set DataType.IN mode to BINARY when ClientBinaryHandler is not set!");
- }
- }
-
- /**
- * Returns the {@link DataMode} of the ClientHandler for the
- * DataType.
- * @since 1.2
- */
- public DataMode getDataMode(DataType dataType) {
- if(dataType == DataType.IN)
- return dataModeIN;
- else if(dataType == DataType.OUT)
- return dataModeOUT;
- else
- throw new IllegalArgumentException("Unknown DataType : " +
- dataType);
- }
-
- /**
- * Returns the {@link java.sql.Connection} object for the
- * DatabaseConnection that is identified by id passed. If id passed
- * does not match with any connection loaded by this class it will
- * return <code>null</code>.
- * This just calls <code>getServer().getDBPoolUtil().getConnection(id)</code>
- * @since 1.3
- * @deprecated as of v1.4.5 use <code>getServer().getDBPoolUtil().getConnection(id)</code>
- */
- public java.sql.Connection getConnection(String id) throws Exception {
- if(getServer()==null)
- throw new Exception("ClientHandler no longer is associated with any client! Try to use quickserver.getDBPoolUtil().getConnection("+id+")");
- return getServer().getDBPoolUtil().getConnection(id);
- }
-
- /**
- * Returns the date/time when the client socket was assigned to this
- * ClientHanlder. If no client is currently connected it will return
- * <code>null</code>
- * @since 1.3.1
- */
- public Date getClientConnectedTime() {
- return clientConnectedTime;
- }
-
- /**
- * Read the byte input. This will block till some data is
- * received from the stream.
- * @return The data as a String
- * @since 1.3.1
- */
- protected abstract byte[] readInputStream() throws IOException;
-
- protected static byte[] readInputStream(InputStream _in) throws IOException {
- byte data[] = null;
- if(_in==null)
- throw new IOException("InputStream can't be null!");
-
- int s = _in.read();
- if(s==-1) {
- return null; //Connection lost
- }
- int alength = _in.available();
- if(alength > 0) {
- data = new byte[alength+1];
- _in.read(data, 1, alength);
- } else {
- data = new byte[1];
- }
- data[0] = (byte)s;
- return data;
- }
-
- /**
- * Read the byte input. This will block till some data is
- * received from the stream. Allowed only when
- * <code>DataType.IN</code> is in <code>DataMode.BYTE</code> mode.
- * @return The data as a String
- * @since 1.3.2
- */
- public String readBytes() throws IOException {
- if(dataModeIN != DataMode.BYTE)
- throw new IllegalStateException("Can't read Byte: " +
- "DataType.IN is not in DataMode.BYTE");
- byte data[] = readInputStream();
- if(data!=null)
- return new String(data, charset);
- else
- return null;
- }
-
- /**
- * Sets the communication logging flag.
- * @see #getCommunicationLogging
- * @since 1.3.2
- */
- public void setCommunicationLogging(boolean communicationLogging) {
- this.communicationLogging = communicationLogging;
- }
- /**
- * Returns the communication logging flag.
- * @see #setCommunicationLogging
- * @since 1.3.2
- */
- public boolean getCommunicationLogging() {
- return communicationLogging;
- }
-
- /**
- * Returns the date/time when the client socket last sent a data to this
- * ClientHanlder. If no client is currently connected it will return
- * <code>null</code>
- * @since 1.3.3
- */
- public Date getLastCommunicationTime() {
- return lastCommunicationTime;
- }
-
- /**
- * Updates the last communication time for this client
- * @since 1.3.3
- */
- public void updateLastCommunicationTime() {
- lastCommunicationTime = new Date();
- }
-
- /**
- * Force the closing of the client by closing the associated socket.
- * @since 1.3.3
- */
- public synchronized void forceClose() throws IOException {
- if(getSelectionKey()!=null) getSelectionKey().cancel();
- if(getSocketChannel()!=null) {
- getSocketChannel().close();
- setSocketChannel(null);
- }
- if(getSocket()!=null) {
- getSocket().close();
- setSocket(null);
- }
- }
-
- /**
- * Returns flag indicating if the client is connected in secure mode
- * (SSL or TLS).
- * @return secure flag
- * @since 1.4.0
- */
- public boolean isSecure() {
- return secure;
- }
-
- /**
- * Sets flag indicating if the client is connected in secure mode
- * (SSL or TLS).
- * @param secure
- * @since 1.4.0
- */
- public void setSecure(boolean secure) {
- this.secure = secure;
- }
-
- /**
- * Updates the InputStream and OutputStream for the ClientHandler for the
- * set Socket.
- * @since 1.4.0
- * @see #setSocket
- */
- public abstract void updateInputOutputStreams() throws IOException;
-
- /**
- * Makes current Client connection to secure protocol based on the
- * secure configuration set to the server. This method will just call
- * <code>makeSecure(false, false, true, null)</code>.
- * @throws IOException
- * @throws NoSuchAlgorithmException
- * @throws KeyManagementException
- * @since 1.4.0
- */
- public void makeSecure() throws IOException, NoSuchAlgorithmException,
- KeyManagementException {
- makeSecure(false, false, true, null);
- }
-
- /**
- * Makes current Client connection to secure protocol.
- * This method will just call <code>makeSecure(false, false, true, protocol)</code>.
- * @throws IOException
- * @throws NoSuchAlgorithmException
- * @throws KeyManagementException
- * @since 1.4.0
- */
- public void makeSecure(String protocol) throws IOException,
- NoSuchAlgorithmException, KeyManagementException {
- makeSecure(false, false, true, protocol);
- }
-
- /**
- * Makes current Client connection to secure protocol.
- * @param useClientMode falg if the socket should start its first handshake in "client" mode.
- * @param needClientAuth flag if the clients must authenticate themselves.
- * @param autoClose close the underlying socket when this socket is closed
- * @param protocol the standard name of the requested protocol. If <code>null</code> will use the protocol set in secure configuration of the server.
- * @throws IOException
- * @throws NoSuchAlgorithmException
- * @throws KeyManagementException
- * @since 1.4.0
- */
- public void makeSecure(boolean useClientMode, boolean needClientAuth,
- boolean autoClose, String protocol) throws IOException,
- NoSuchAlgorithmException, KeyManagementException {
- if(isSecure()==true) {
- throw new IllegalStateException("Client is already in secure mode!");
- }
-
- appLogger.fine("Making secure - Protocol: "+protocol+
- ", Client: ["+getHostAddress()+"]");
-
- javax.net.ssl.SSLSocketFactory sslSf = getServer().getSSLSocketFactory(protocol);
- String host = getServer().getBindAddr().getHostAddress();
- if(host.equals("0.0.0.0")) host = InetAddress.getLocalHost().getHostAddress();
- SSLSocket newSocket = (SSLSocket) sslSf.createSocket(
- getSocket(), host, getServer().getPort(), autoClose);
- newSocket.setNeedClientAuth(needClientAuth);
- newSocket.setUseClientMode(useClientMode);
- setSocket(newSocket);
- setSecure(true);
- updateInputOutputStreams();
- }
-
- /**
- * Send a binary data to the connected client.
- * If client is not connected it will just return.
- * @since 1.4
- * @exception IOException
- * if Socket IO Error or Socket was closed by the client.
- */
- public void sendClientBinary(byte data[]) throws IOException {
- sendClientBinary(data, 0, data.length);
- }
-
- /**
- * Send a binary data to the connected client.
- * If client is not connected it will just return.
- * @since 1.4.5
- * @exception IOException
- * if Socket IO Error or Socket was closed by the client.
- */
- public void sendClientBinary(byte data[], int off, int len) throws IOException {
- if(isConnected()) {
- if(dataModeOUT != DataMode.BINARY)
- throw new IllegalStateException("Can't send Binary :" +
- "DataType.OUT is not in DataMode.BINARY");
- if(getCommunicationLogging()) {
- appLogger.fine("Sending ["+getHostAddress()+"] : "+MyString.getMemInfo(len));
- }
- b_out.write(data, off, len);
- b_out.flush();
- } else {
- logger.warning("Client not connected.");
- }
- }
-
- /**
- * Read the binary input. This will block till some data is
- * received from the stream. Allowed only when
- * <code>DataType.IN</code> is in <code>DataMode.BINARY</code> mode.
- * @return The data as a String
- * @since 1.4
- */
- public byte[] readBinary() throws IOException {
- if(dataModeIN != DataMode.BINARY)
- throw new IllegalStateException("Can't read Binary :" +
- "DataType.IN is not in DataMode.BINARY");
- byte data[] = readInputStream();
- return data;
- }
-
- /**
- * Sets the ClientBinaryHandler class that interacts with
- * client sockets.
- * @param handler fully qualified name of the class that
- * implements {@link ClientBinaryHandler}
- * @since 1.4
- */
- protected void setClientBinaryHandler(ClientBinaryHandler handler) {
- clientBinaryHandler=handler;
- }
-
- /**
- * Returns client SelectionKey associated, if any.
- * @since 1.4.5
- */
- public Logger getAppLogger() {
- return appLogger;
- }
-
- /**
- * Sets the client socket's timeout.
- * @param time client socket timeout in milliseconds.
- * @see #getTimeout
- * @since 1.4.5
- */
- public void setTimeout(int time) {
- socketTimeout = time;
- }
- /**
- * Returns the Client socket timeout in milliseconds.
- * @see #setTimeout
- * @since 1.4.5
- */
- public int getTimeout() {
- return socketTimeout;
- }
-
- /**
- * Checks if this client has the event.
- * @since 1.4.5
- */
- public boolean hasEvent(ClientEvent event) {
- synchronized(clientEvents) {
- return clientEvents.contains(event);
- }
- }
-
- /**
- * Adds the ClientEvent.
- * @since 1.4.5
- */
- public void addEvent(ClientEvent event) {
- synchronized(clientEvents) {
- unprocessedClientEvents.add(event);
- clientEvents.add(event);
- }
- }
-
- /**
- * Removes the ClientEvent.
- * @since 1.4.5
- */
- public void removeEvent(ClientEvent event) {
- if(event==null) return;
-
- synchronized(clientEvents) {
- clientEvents.remove(event);
- }
-
- ClientEvent _clientEvent = (ClientEvent)threadEvent.get();
- if(_clientEvent!=null && _clientEvent==event) {
- threadEvent.set(null);
- }
-
- }
-
- /**
- * Returns threads current event for this client.
- * @since 1.4.5
- */
- protected ClientEvent getThreadEvent() {
- return (ClientEvent)threadEvent.get();
- }
-
- /**
- * Sets message to be displayed when maximum connection reaches.
- * @since 1.4.5
- */
- public void setMaxConnectionMsg(String msg) {
- maxConnectionMsg = msg;
- }
- /**
- * Returns message to be displayed to the client when maximum
- * connection reaches.
- * @since 1.4.5
- */
- public String getMaxConnectionMsg() {
- return maxConnectionMsg;
- }
-
- /**
- * Sets client socket channel associated, if any.
- * @since 1.4.5
- */
- public abstract void setSocketChannel(SocketChannel socketChannel);
- /**
- * Returns client socket channel associated, if any.
- * @since 1.4.5
- */
- public abstract SocketChannel getSocketChannel();
-
- /**
- * Sets client SelectionKey associated, if any.
- * @since 1.4.5
- */
- public abstract void setSelectionKey(SelectionKey selectionKey);
- /**
- * Returns client SelectionKey associated, if any.
- * @since 1.4.5
- */
- public abstract SelectionKey getSelectionKey();
-
- public boolean getWillClean() {
- return willClean;
- }
-
- /**
- * Register OP_READ with the SelectionKey associated with the channel. If SelectionKey is
- * not set then it registers the channel with the Selector.
- * @since 1.4.5
- */
- public abstract void registerForRead() throws IOException,
- ClosedChannelException;
-
- /**
- * Register OP_WRITE with the SelectionKey associated with the channel.
- * @since 1.4.5
- */
- public abstract void registerForWrite() throws IOException,
- ClosedChannelException;
-
- /**
- * Sets the ClientWriteHandler class that interacts with
- * client sockets.
- * @param handler fully qualified name of the class that
- * implements {@link ClientWriteHandler}
- * @since 1.4.5
- */
- protected abstract void setClientWriteHandler(ClientWriteHandler handler);
-
- /**
- * Sets the Charset to be used for String decoding and encoding.
- * @param charset to be used for String decoding and encoding
- * @see #getCharset
- * @since 1.4.5
- */
- public void setCharset(String charset) {
- if(charset==null || charset.trim().length()==0)
- return;
- this.charset = charset;
- }
- /**
- * Returns Charset to be used for String decoding and encoding..
- * @see #setCharset
- * @since 1.4.5
- */
- public String getCharset() {
- return charset;
- }
-
- /**
- * Returns cached socket host ip address.
- * @since 1.4.5
- */
- public String getHostAddress() {
- return hostAddress;
- }
-
- protected void assertionSystemExit() {
- logger.warning("[Assertions Was Enabled] Forcing program exit to help developer.");
- org.quickserver.net.qsadmin.QSAdminShell.tryFullThreadDump();//it can help debug.
- try {
- Thread.sleep(100);
- } catch(InterruptedException e) {
- logger.fine("Interrupted: "+e);
- }
- System.exit(-1);
- }
-
- /**
- * Checks if the passed ClientEvent is the one next for
- * processing if a thread is allowed through this object.
- * @since 1.4.6
- */
- public boolean isClientEventNext(ClientEvent clientEvent) {
- ClientEvent ce = null;
- synchronized(clientEvents) {
- if(unprocessedClientEvents.size()>0)
- ce = (ClientEvent) unprocessedClientEvents.get(0);
- }
- return clientEvent == ce;
- }
-
- /**
- *Returns the {@link java.io.BufferedInputStream} associated with
- * the Client being handled. Can be null if not available at the time of method call.
- * @see #getBufferedOutputStream
- * @since 1.4.6
- */
- public BufferedInputStream getBufferedInputStream() {
- return b_in;
- }
-
- /**
- * Returns the {@link java.io.BufferedOutputStream} associated with
- * the Client being handled. Can be null if not available at the time of method call.
- * @see #getBufferedInputStream
- * @since 1.4.6
- */
- public BufferedOutputStream getBufferedOutputStream() {
- return b_out;
- }
-
- protected void handleTimeout(SocketTimeoutException e) throws SocketException, IOException {
- appLogger.fine("Timeout - Client [" + getHostAddress() +"]");
- appLogger.finest("SocketTimeoutException : " + e.getMessage());
-
- String temp = null;
- if(clientExtendedEventHandler!=null) {
- clientExtendedEventHandler.handleTimeout(this);
- } else {
- temp = timeoutMsg;
- if(dataModeOUT == DataMode.STRING)
- temp = temp + NEW_LINE;
- if(dataModeOUT != DataMode.OBJECT) {
- out.write(temp.getBytes(charset));
- out.flush();
- }
- if(true) throw new SocketException("Timeout");
- }
- }
- }