PageRenderTime 56ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/quickserver-1.4.7/src/main/org/quickserver/net/server/impl/BasicClientHandler.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1356 lines | 739 code | 147 blank | 470 comment | 125 complexity | 60f1e5dcc859d78a4f202c5992e2b249 MD5 | raw file
  1. /*
  2. * This file is part of the QuickServer library
  3. * Copyright (C) 2003-2005 QuickServer.org
  4. *
  5. * Use, modification, copying and distribution of this software is subject to
  6. * the terms and conditions of the GNU Lesser General Public License.
  7. * You should have received a copy of the GNU LGP License along with this
  8. * library; if not, you can download a copy from <http://www.quickserver.org/>.
  9. *
  10. * For questions, suggestions, bug-reports, enhancement-requests etc.
  11. * visit http://www.quickserver.org
  12. *
  13. */
  14. package org.quickserver.net.server.impl;
  15. import java.io.*;
  16. import java.net.Socket;
  17. import java.net.SocketException;
  18. import java.net.SocketTimeoutException;
  19. import java.net.InetAddress;
  20. import java.util.*;
  21. import java.util.logging.*;
  22. import javax.net.ssl.*;
  23. import java.security.*;
  24. import java.nio.*;
  25. import java.nio.channels.*;
  26. import org.quickserver.net.*;
  27. import org.quickserver.util.*;
  28. import org.quickserver.net.server.*;
  29. /**
  30. * Basic implementation of ClientHandler that handles clients for QuickServer.
  31. * <p> This class is used by {@link QuickServer} to handle each new client
  32. * connected. This class is responsible to handle client sockets. It can operate
  33. * in both blocking mode and non-blocking mode (java nio).</p>
  34. * <p>
  35. * Contributions By:
  36. * Martin Benns : BYTE Mode
  37. * </p>
  38. * @author Akshathkumar Shetty
  39. * @author Martin Benns : Added BYTE mode
  40. */
  41. public abstract class BasicClientHandler implements ClientHandler {
  42. private static final Logger logger = Logger.getLogger(BasicClientHandler.class.getName());
  43. protected static final String NEW_LINE = QuickServer.getNewLine();
  44. protected static final byte NEW_LINE_BYTES[] = NEW_LINE.getBytes();
  45. //Some variable are not initialised to any value because the
  46. //default java value was desired initial value.
  47. /** Client socket */
  48. protected Socket socket;
  49. /** Client authorisation status */
  50. protected volatile boolean authorised;
  51. /** Count of client login attempts */
  52. protected int counAuthTry;
  53. /** max allowed login attempts */
  54. protected int maxAuthTry = 5;
  55. /** timeout message */
  56. protected String timeoutMsg;
  57. /** Message to be displayed when max login attempt reaches.*/
  58. protected String maxAuthTryMsg;
  59. protected int socketTimeout;
  60. protected volatile boolean connection; //false
  61. protected boolean lost; //false
  62. protected QuickServer quickServer;
  63. protected Authenticator authenticator; //v1.3
  64. protected ClientAuthenticationHandler clientAuthenticationHandler; //v1.4.6
  65. protected ClientEventHandler clientEventHandler; //v1.4.6
  66. protected ClientExtendedEventHandler clientExtendedEventHandler; //v1.4.6
  67. protected ClientCommandHandler clientCommandHandler;
  68. protected ClientObjectHandler clientObjectHandler; //v1.2
  69. protected ClientBinaryHandler clientBinaryHandler; //1.4
  70. protected ClientData clientData;
  71. protected InputStream in;
  72. protected OutputStream out;
  73. protected BufferedReader bufferedReader;
  74. //if DataMode.OBJECT
  75. protected ObjectOutputStream o_out; //v1.2
  76. protected ObjectInputStream o_in; //v1.2
  77. //added for BYTE mode and BINARY mode
  78. protected BufferedInputStream b_in;
  79. protected BufferedOutputStream b_out;
  80. //logger for the application using this QuickServer
  81. protected Logger appLogger;
  82. protected DataMode dataModeIN = null;
  83. protected DataMode dataModeOUT = null;
  84. protected boolean communicationLogging = true;
  85. protected Date clientConnectedTime = null;
  86. protected Date lastCommunicationTime = null;
  87. protected boolean secure = false;
  88. //--v1.4.5
  89. protected static final ThreadLocal threadEvent = new ThreadLocal();
  90. protected String maxConnectionMsg;
  91. protected Set clientEvents = new HashSet();
  92. protected List unprocessedClientEvents = Collections.synchronizedList(new ArrayList());
  93. protected volatile boolean closeOrLostNotified;
  94. protected Object lockObj = new Object();
  95. protected volatile boolean willClean;
  96. protected String charset;
  97. private static Map idMap = new HashMap();
  98. private int instanceCount;
  99. private int id;
  100. private String name;
  101. private String hostAddress;
  102. private int port;
  103. static class InstanceId {
  104. private int id = 0;
  105. public int getNextId() {
  106. return ++id;
  107. }
  108. };
  109. private static int getNewId(int instanceCount) {
  110. InstanceId instanceId = (InstanceId) idMap.get(""+instanceCount);
  111. if(instanceId==null) {
  112. instanceId = new InstanceId();
  113. idMap.put(""+instanceCount, instanceId);
  114. }
  115. return instanceId.getNextId();
  116. }
  117. public BasicClientHandler(int instanceCount) {
  118. this.instanceCount = instanceCount;
  119. id = getNewId(instanceCount);
  120. StringBuffer sb = new StringBuffer();
  121. sb.append("<ClientHandler-Pool#");
  122. sb.append(instanceCount);
  123. sb.append("-ID:");
  124. sb.append(id);
  125. sb.append(">");
  126. name = sb.toString();
  127. }
  128. public int getInstanceCount() {
  129. return instanceCount;
  130. }
  131. public BasicClientHandler() {
  132. this(-1);
  133. }
  134. public void clean() {
  135. counAuthTry = 0;
  136. authorised = false;
  137. in = null;
  138. out = null;
  139. bufferedReader = null;
  140. o_out = null; o_in = null;
  141. b_in = null; b_out = null;
  142. dataModeIN = null;
  143. dataModeOUT = null;
  144. lost = false;
  145. clientData = null;
  146. clientConnectedTime = null;
  147. lastCommunicationTime = null;
  148. communicationLogging = true;
  149. socketTimeout = 0;
  150. secure = false;
  151. authenticator = null;
  152. clientAuthenticationHandler = null;//1.4.6
  153. clientCommandHandler = null;
  154. clientObjectHandler = null;
  155. clientBinaryHandler = null;//1.4
  156. clientData = null;
  157. maxConnectionMsg = null;
  158. synchronized(clientEvents) {
  159. clientEvents.clear();
  160. unprocessedClientEvents.clear();
  161. }
  162. closeOrLostNotified = false;
  163. if(socket!=null) {
  164. try {
  165. socket.close();
  166. } catch(Exception er) {
  167. appLogger.warning("Error in closing socket: "+er);
  168. }
  169. socket = null;
  170. }
  171. hostAddress = null;
  172. port = 0;
  173. quickServer = null;
  174. willClean = false;
  175. charset = null;
  176. }
  177. protected void finalize() throws Throwable {
  178. super.finalize();
  179. }
  180. /**
  181. * Associates the ClientHanlder with the client encapsulated by
  182. * <code>theClient</code>.
  183. * @param theClient object that encapsulates client socket
  184. * and its configuration details.
  185. */
  186. public void handleClient(TheClient theClient) {
  187. setServer(theClient.getServer());
  188. if(getServer().isRunningSecure()==true) {
  189. setSecure(true);
  190. }
  191. setSocket(theClient.getSocket());
  192. if(theClient.getTrusted()==false) {
  193. setAuthenticator(theClient.getAuthenticator());
  194. setClientAuthenticationHandler(theClient.getClientAuthenticationHandler());
  195. }
  196. setClientEventHandler(theClient.getClientEventHandler());
  197. setClientExtendedEventHandler(theClient.getClientExtendedEventHandler());
  198. setClientCommandHandler(theClient.getClientCommandHandler());
  199. setClientObjectHandler(theClient.getClientObjectHandler());
  200. setClientBinaryHandler(theClient.getClientBinaryHandler()); //v1.4
  201. setClientData(theClient.getClientData());
  202. if(theClient.getTrusted()==false) {
  203. socketTimeout = theClient.getTimeout();
  204. }
  205. timeoutMsg = theClient.getTimeoutMsg();
  206. maxAuthTryMsg = theClient.getMaxAuthTryMsg();
  207. maxAuthTry = theClient.getMaxAuthTry(); //v1.2
  208. appLogger = quickServer.getAppLogger(); //v1.2
  209. setCommunicationLogging(theClient.getCommunicationLogging()); //v1.3.2
  210. maxConnectionMsg = theClient.getMaxConnectionMsg();//1.4.5
  211. addEvent(theClient.getClientEvent());//1.4.5
  212. }
  213. /**
  214. * Returns the QuickServer object that created it.
  215. * @see #setServer
  216. */
  217. public QuickServer getServer() {
  218. return quickServer;
  219. }
  220. /**
  221. * Sets the QuickServer object associated with this ClientHandler.
  222. * @see #getServer
  223. */
  224. protected void setServer(QuickServer server) {
  225. Assertion.affirm(server!=null, "QuickServer can't be null!");
  226. quickServer = server;
  227. }
  228. /**
  229. * Sets the ClientData object associated with this ClientHandler
  230. * @see ClientData
  231. * @see #getClientData
  232. */
  233. protected void setClientData(ClientData data) {
  234. this.clientData = data;
  235. }
  236. /**
  237. * Returns the ClientData object associated with this ClientHandler,
  238. * if not set will return <code>null</code>
  239. * @see ClientData
  240. * @see #setClientData
  241. */
  242. public ClientData getClientData() {
  243. return clientData;
  244. }
  245. /**
  246. * Sets the ClientAuthenticationHandler class that handles the
  247. * authentication of a client.
  248. * @param clientAuthenticationHandler fully qualified name of the class that
  249. * implements {@link ClientAuthenticationHandler}.
  250. * @since 1.4.6
  251. */
  252. protected void setClientAuthenticationHandler(ClientAuthenticationHandler clientAuthenticationHandler) {
  253. this.clientAuthenticationHandler = clientAuthenticationHandler;
  254. }
  255. /**
  256. * Sets the Authenticator class that handles the
  257. * authentication of a client.
  258. * @param authenticator fully qualified name of the class that
  259. * implements {@link Authenticator}.
  260. * @since 1.3
  261. */
  262. protected void setAuthenticator(Authenticator authenticator) {
  263. this.authenticator = authenticator;
  264. }
  265. /**
  266. * Returns the {@link java.io.InputStream} associated with
  267. * the Client being handled.
  268. * @see #setInputStream
  269. */
  270. public InputStream getInputStream() {
  271. return in;
  272. }
  273. /**
  274. * Sets the {@link java.io.InputStream} associated with
  275. * the Client being handled.
  276. * @since 1.1
  277. * @see #getInputStream
  278. */
  279. protected abstract void setInputStream(InputStream in) throws IOException;
  280. /**
  281. * Returns the {@link java.io.OutputStream} associated with
  282. * the Client being handled.
  283. * @see #setOutputStream
  284. */
  285. public OutputStream getOutputStream() {
  286. return out;
  287. }
  288. /**
  289. * Set the {@link java.io.OutputStream} associated with
  290. * the Client being handled.
  291. * @since 1.1
  292. * @see #getOutputStream
  293. * @exception IOException if ObjectOutputStream could not be created.
  294. */
  295. public void setOutputStream(OutputStream out) throws IOException {
  296. this.out = out;
  297. if(getDataMode(DataType.OUT) == DataMode.STRING ||
  298. getDataMode(DataType.OUT) == DataMode.BYTE ||
  299. getDataMode(DataType.OUT) == DataMode.BINARY) {
  300. o_out = null;
  301. b_out = new BufferedOutputStream(out);
  302. } else if(getDataMode(DataType.OUT) == DataMode.OBJECT) {
  303. b_out = null;
  304. o_out = new ObjectOutputStream(out);
  305. o_out.flush();
  306. } else {
  307. throw new IllegalStateException("Unknown DataMode " +getDataMode(DataType.OUT));
  308. }
  309. }
  310. /**
  311. * Returns the {@link java.io.BufferedReader} associated with
  312. * the Client being handled. Note that this is only available under blocking mode.
  313. * @see #getBufferedWriter
  314. */
  315. public abstract BufferedReader getBufferedReader();
  316. /**
  317. * Returns the {@link java.io.BufferedWriter} associated with
  318. * the Client being handled.
  319. * @deprecated since 1.4.5 use getOutputStream()
  320. */
  321. public BufferedWriter getBufferedWriter() {
  322. return new BufferedWriter(new OutputStreamWriter(b_out));
  323. }
  324. /**
  325. * Returns the {@link java.io.ObjectOutputStream} associated with
  326. * the Client being handled.
  327. * It will be <code>null</code> if no {@link ClientObjectHandler}
  328. * was set in {@link QuickServer}.
  329. * @see #getObjectInputStream
  330. * @since 1.2
  331. */
  332. public ObjectOutputStream getObjectOutputStream() {
  333. return o_out;
  334. }
  335. /**
  336. * Returns the {@link java.io.ObjectInputStream} associated with
  337. * the Client being handled.
  338. * It will be <code>null</code> if no {@link ClientObjectHandler}
  339. * was set in {@link QuickServer}.
  340. * @see #getObjectOutputStream
  341. * @since 1.2
  342. */
  343. public ObjectInputStream getObjectInputStream() {
  344. return o_in;
  345. }
  346. /**
  347. * Sets the ClientEventHandler class that gets notified of client events.
  348. * @since 1.4.6
  349. */
  350. protected void setClientEventHandler(ClientEventHandler handler) {
  351. clientEventHandler=handler;
  352. }
  353. /**
  354. * Sets the ClientExtendedEventHandler class that gets notified of extended client events.
  355. * @since 1.4.6
  356. */
  357. protected void setClientExtendedEventHandler(ClientExtendedEventHandler handler) {
  358. clientExtendedEventHandler=handler;
  359. }
  360. /**
  361. * Sets the ClientCommandHandler class that interacts with
  362. * client sockets.
  363. */
  364. protected void setClientCommandHandler(ClientCommandHandler handler) {
  365. clientCommandHandler=handler;
  366. }
  367. /**
  368. * Sets the ClientObjectHandler class that interacts with
  369. * client sockets.
  370. * @param handler fully qualified name of the class that
  371. * implements {@link ClientObjectHandler}
  372. * @since 1.2
  373. */
  374. protected void setClientObjectHandler(ClientObjectHandler handler) {
  375. clientObjectHandler = handler;
  376. }
  377. /** Closes client socket associated. */
  378. public abstract void closeConnection();
  379. /** Returns client socket associated. */
  380. public Socket getSocket() {
  381. return socket;
  382. }
  383. /**
  384. * Returns client socket associated.
  385. * @since 1.4.0
  386. * @see #updateInputOutputStreams
  387. */
  388. public void setSocket(Socket socket) {
  389. this.socket = socket;
  390. }
  391. /**
  392. * Checks if the client is still connected.
  393. * @exception SocketException if Socket is not open.
  394. * @deprecated since 1.4.5 Use {@link #isConnected}
  395. */
  396. public boolean isConected() throws SocketException {
  397. return isConnected();
  398. }
  399. /**
  400. * Checks if the client is still connected.
  401. * @exception SocketException if Socket is not open.
  402. * @since 1.4.5
  403. */
  404. public boolean isConnected() throws SocketException {
  405. if(isOpen()==false)
  406. throw new SocketException("Connection is no more open!");
  407. else
  408. return true;
  409. }
  410. /**
  411. * Checks if the client is still connected and if socket is open. This is same as isConnected()
  412. * but does not throw SocketException.
  413. * @since 1.4.6
  414. */
  415. public boolean isOpen() {
  416. if(lost==true || socket==null || socket.isConnected()==false || socket.isClosed()==true)
  417. return false;
  418. else
  419. return true;
  420. }
  421. /**
  422. * Checks if the client is closed.
  423. * @since 1.4.1
  424. */
  425. public boolean isClosed() {
  426. if(socket==null || socket.isClosed()==true)
  427. return true;
  428. else
  429. return false;
  430. }
  431. /**
  432. * Send a String message to the connected client
  433. * it adds a new line{\r\n} to the end of the string.
  434. * If client is not connected it will just return.
  435. * @exception IOException
  436. * if Socket IO Error or Socket was closed by the client.
  437. */
  438. public void sendClientMsg(String msg) throws IOException {
  439. isConnected();
  440. if(dataModeOUT != DataMode.STRING)
  441. throw new IllegalStateException("Can't send String :" +
  442. "DataType.OUT is not in DataMode.STRING");
  443. if(getCommunicationLogging()) {
  444. appLogger.fine("Sending ["+getHostAddress()+"] : "+msg);
  445. }
  446. byte data[] = msg.getBytes(charset);
  447. b_out.write(data, 0, data.length);
  448. b_out.write(NEW_LINE_BYTES, 0, NEW_LINE_BYTES.length);
  449. b_out.flush();
  450. updateLastCommunicationTime();
  451. }
  452. /**
  453. * Send a String message to the connected client as a string of bytes.
  454. * If client is not connected it will just return.
  455. * @since 1.3.1
  456. * @exception IOException
  457. * if Socket IO Error or Socket was closed by the client.
  458. */
  459. public void sendClientBytes(String msg) throws IOException {
  460. isConnected();
  461. if (dataModeOUT != DataMode.BYTE)
  462. throw new IllegalStateException("Can't send String :" +
  463. "DataType.OUT is not in DataMode.BYTE");
  464. if(getCommunicationLogging()) {
  465. appLogger.fine("Sending ["+getHostAddress()+"] : "+msg);
  466. }
  467. byte data[] = msg.getBytes(charset);
  468. b_out.write(data,0,data.length);
  469. b_out.flush();
  470. updateLastCommunicationTime();
  471. }
  472. /**
  473. * Send a Object message to the connected client. The message Object
  474. * passed must be serializable. If client is not connected it
  475. * will just return.
  476. * @exception IOException if Socket IO Error or Socket was closed
  477. * by the client.
  478. * @exception IllegalStateException if DataType.OUT is not in
  479. * DataMode.OBJECT
  480. * @see #setDataMode
  481. * @since 1.2
  482. */
  483. public void sendClientObject(Object msg) throws IOException {
  484. isConnected();
  485. if(dataModeOUT != DataMode.OBJECT)
  486. throw new IllegalStateException("Can't send Object : DataType.OUT is not in DataMode.OBJECT");
  487. if(getCommunicationLogging()) {
  488. appLogger.fine("Sending ["+getHostAddress()+"] : "+msg.toString());
  489. }
  490. o_out.writeObject(msg);
  491. o_out.flush();
  492. updateLastCommunicationTime();
  493. }
  494. /**
  495. * Send a String message to the logger associated with
  496. * {@link QuickServer#getAppLogger} with Level.INFO as its level.
  497. */
  498. public void sendSystemMsg(String msg) {
  499. sendSystemMsg(msg, Level.INFO);
  500. }
  501. /**
  502. * Send a String message to the logger associated with
  503. * {@link QuickServer#getAppLogger}.
  504. * @since 1.2
  505. */
  506. public void sendSystemMsg(String msg, Level level) {
  507. appLogger.log(level, msg);
  508. }
  509. /**
  510. * Send a String message to the system output stream.
  511. * @param newline indicates if new line required at the end.
  512. * @deprecated Use {@link #sendSystemMsg(java.lang.String)},
  513. * since it uses Logging.
  514. */
  515. public void sendSystemMsg(String msg, boolean newline) {
  516. if(newline)
  517. System.out.println(msg);
  518. else
  519. System.out.print(msg);
  520. }
  521. public abstract void run();
  522. protected void prepareForRun() throws SocketException, IOException {
  523. clientConnectedTime = new java.util.Date(); //v1.3.2
  524. lastCommunicationTime = clientConnectedTime;//v1.3.3
  525. setCharset(getServer().getBasicConfig().getAdvancedSettings().getCharset());//1.4.5
  526. hostAddress = getSocket().getInetAddress().getHostAddress();//1.4.5
  527. port = getSocket().getPort();
  528. if(logger.isLoggable(Level.FINEST)) {
  529. StringBuffer sb = new StringBuffer();
  530. sb.append(getName());
  531. sb.append(" -> ");
  532. sb.append(hostAddress);
  533. sb.append(':');
  534. sb.append(port);
  535. logger.finest(sb.toString());
  536. }
  537. socket.setSoTimeout(socketTimeout);
  538. connection = true;
  539. dataModeIN = getServer().getDefaultDataMode(DataType.IN);
  540. dataModeOUT = getServer().getDefaultDataMode(DataType.OUT);
  541. updateInputOutputStreams();
  542. }
  543. protected void processMaxConnection(ClientEvent currentEvent) throws IOException {
  544. if(clientExtendedEventHandler!=null) {
  545. if(clientExtendedEventHandler.handleMaxConnection(this)) {
  546. removeEvent(getThreadEvent());
  547. if(getThreadEvent()==ClientEvent.MAX_CON) {
  548. currentEvent = ClientEvent.ACCEPT;
  549. } else if(getThreadEvent()==ClientEvent.MAX_CON_BLOCKING) {
  550. currentEvent = ClientEvent.RUN_BLOCKING;
  551. } else {
  552. throw new IllegalArgumentException("Unknown ClientEvent: "+getThreadEvent());
  553. }
  554. synchronized(clientEvents) {
  555. clientEvents.add(currentEvent);
  556. }
  557. threadEvent.set(currentEvent);
  558. }
  559. } else if(maxConnectionMsg.length()!=0) {
  560. out.write(maxConnectionMsg.getBytes(charset), 0, maxConnectionMsg.length());
  561. out.write(NEW_LINE_BYTES, 0, NEW_LINE_BYTES.length);
  562. out.flush();
  563. }
  564. }
  565. protected AuthStatus processAuthorisation() throws SocketException,
  566. IOException, AppException {
  567. logger.finest("INSIDE");
  568. while(authorised==false && connection==true) {
  569. isConnected();
  570. counAuthTry++;
  571. if(authorised == false) {
  572. if(counAuthTry > maxAuthTry) {
  573. processMaxAuthTry();
  574. }
  575. }
  576. try {
  577. if(clientAuthenticationHandler!=null) {
  578. return clientAuthenticationHandler.askAuthentication(this);
  579. } else if(authenticator!=null) {
  580. authorised = authenticator.askAuthorisation(this);
  581. }
  582. } catch(NullPointerException e) {
  583. logger.severe("Authenticator implementation has not handled null properly."+
  584. " Input from client should be checked for null!");
  585. throw e;
  586. } catch(SocketTimeoutException e) {
  587. handleTimeout(e);
  588. }
  589. updateLastCommunicationTime();
  590. } //end of auth while
  591. return AuthStatus.SUCCESS;
  592. }
  593. private void processMaxAuthTry() throws SocketException, IOException, AppException {
  594. if(clientExtendedEventHandler!=null) {
  595. clientExtendedEventHandler.handleMaxAuthTry(this);
  596. } else {
  597. String temp = maxAuthTryMsg;
  598. if(dataModeOUT == DataMode.STRING)
  599. temp = temp + NEW_LINE;
  600. if(dataModeOUT != DataMode.OBJECT) {
  601. out.write(temp.getBytes(charset));
  602. out.flush();
  603. }
  604. }
  605. appLogger.warning("Max Auth Try Reached - Client : "+getHostAddress());
  606. if(true) throw new AppException(maxAuthTryMsg);
  607. }
  608. protected void notifyCloseOrLost() throws IOException {
  609. synchronized(this) {
  610. if(closeOrLostNotified==false) {
  611. if(lost==true) {
  612. clientEventHandler.lostConnection(this);
  613. } else {
  614. clientEventHandler.closingConnection(this);
  615. }
  616. closeOrLostNotified = true;
  617. }
  618. }
  619. }
  620. protected synchronized void returnClientData() {
  621. if(clientData==null || getServer().getClientDataPool()==null)
  622. return;
  623. logger.finest("Returning ClientData to pool");
  624. try {
  625. getServer().getClientDataPool().returnObject(clientData);
  626. clientData = null;
  627. } catch(Exception e) {
  628. logger.warning("IGNORED: Could not return ClientData to pool: "+e);
  629. }
  630. }
  631. protected void returnClientHandler() {
  632. try {
  633. synchronized(lockObj) {
  634. logger.finest(Thread.currentThread().getName()+" returning "+getName());
  635. getServer().getClientHandlerPool().returnObject(this);
  636. }
  637. } catch(Exception e) {
  638. logger.warning("IGNORED: Could not return ClientHandler to pool: "+e);
  639. }
  640. }
  641. /**
  642. * Returns the ClientHandler name
  643. * @since 1.4.6
  644. */
  645. public String getName() {
  646. return name;
  647. }
  648. /**
  649. * Returns the ClientHandler detailed information.
  650. * If ClientData is present and is ClientIdentifiable will return ClientInfo else
  651. * it will return Clients InetAddress and port information.
  652. */
  653. public String info() {
  654. StringBuffer sb = new StringBuffer();
  655. sb.append("{");
  656. sb.append(name);
  657. sb.append(" - ");
  658. String info = getClientIdentifiable(this);
  659. if(info!=null) {
  660. sb.append("[ClientInfo: ");
  661. sb.append(info);
  662. sb.append(']');
  663. }
  664. if(getSocket()==null || getSocket().isClosed()==true) {
  665. sb.append("[non-connected]");
  666. } else if(info==null) {
  667. sb.append('[');
  668. sb.append(hostAddress);
  669. sb.append(':');
  670. sb.append(port);
  671. sb.append(']');
  672. }
  673. sb.append('}');
  674. return sb.toString();
  675. }
  676. /**
  677. * Returns the ClientHandler information.
  678. * If ClientData is present and is ClientIdentifiable will return ClientInfo else
  679. * it will return Clients InetAddress and port information.
  680. */
  681. public String toString() {
  682. StringBuffer sb = new StringBuffer();
  683. sb.append("{");
  684. sb.append(name);
  685. sb.append(" - ");
  686. if(getSocket()==null || getSocket().isClosed()==true) {
  687. sb.append("[non-connected]");
  688. } else if(hostAddress!=null) {
  689. sb.append('[');
  690. sb.append(hostAddress);
  691. sb.append(':');
  692. sb.append(port);
  693. sb.append(']');
  694. }
  695. synchronized(clientEvents) {
  696. if(clientEvents.size()!=0) {
  697. sb.append(' ');
  698. sb.append(clientEvents);
  699. }
  700. }
  701. sb.append('}');
  702. return sb.toString();
  703. }
  704. protected static String getClientIdentifiable(ClientHandler foundClientHandler) {
  705. if(foundClientHandler==null) return null;
  706. ClientData foundClientData = null;
  707. foundClientData = foundClientHandler.getClientData();
  708. if(foundClientData==null)
  709. return null;
  710. else if(ClientIdentifiable.class.isInstance(foundClientData)==false)
  711. return null;
  712. else
  713. return ((ClientIdentifiable)foundClientData).getClientInfo();
  714. }
  715. /**
  716. * Sets the {@link DataMode} for the ClientHandler
  717. *
  718. * Note: When mode is DataMode.OBJECT and type is DataType.IN
  719. * this call will block until the client ObjectOutputStream has
  720. * written and flushes the header.
  721. * @since 1.2
  722. * @exception IOException if mode could not be changed.
  723. * @param dataMode mode of data exchange - String or Object.
  724. * @param dataType type of data for which mode has to be set.
  725. */
  726. public abstract void setDataMode(DataMode dataMode, DataType dataType) throws IOException;
  727. protected void checkDataModeSet(DataMode dataMode, DataType dataType) {
  728. if(dataMode==DataMode.STRING && dataType==DataType.IN && clientCommandHandler==null) {
  729. throw new IllegalArgumentException("Can't set DataType.IN mode to STRING when ClientCommandHandler is not set!");
  730. }
  731. if(dataMode==DataMode.BYTE && dataType==DataType.IN && clientCommandHandler==null) {
  732. throw new IllegalArgumentException("Can't set DataType.IN mode to BYTE when ClientCommandHandler is not set!");
  733. }
  734. if(dataMode==DataMode.OBJECT && dataType==DataType.IN && clientObjectHandler==null) {
  735. throw new IllegalArgumentException("Can't set DataType.IN mode to OBJECT when ClientObjectHandler is not set!");
  736. }
  737. if(dataMode==DataMode.BINARY && dataType==DataType.IN && clientBinaryHandler==null) {
  738. throw new IllegalArgumentException("Can't set DataType.IN mode to BINARY when ClientBinaryHandler is not set!");
  739. }
  740. }
  741. /**
  742. * Returns the {@link DataMode} of the ClientHandler for the
  743. * DataType.
  744. * @since 1.2
  745. */
  746. public DataMode getDataMode(DataType dataType) {
  747. if(dataType == DataType.IN)
  748. return dataModeIN;
  749. else if(dataType == DataType.OUT)
  750. return dataModeOUT;
  751. else
  752. throw new IllegalArgumentException("Unknown DataType : " +
  753. dataType);
  754. }
  755. /**
  756. * Returns the {@link java.sql.Connection} object for the
  757. * DatabaseConnection that is identified by id passed. If id passed
  758. * does not match with any connection loaded by this class it will
  759. * return <code>null</code>.
  760. * This just calls <code>getServer().getDBPoolUtil().getConnection(id)</code>
  761. * @since 1.3
  762. * @deprecated as of v1.4.5 use <code>getServer().getDBPoolUtil().getConnection(id)</code>
  763. */
  764. public java.sql.Connection getConnection(String id) throws Exception {
  765. if(getServer()==null)
  766. throw new Exception("ClientHandler no longer is associated with any client! Try to use quickserver.getDBPoolUtil().getConnection("+id+")");
  767. return getServer().getDBPoolUtil().getConnection(id);
  768. }
  769. /**
  770. * Returns the date/time when the client socket was assigned to this
  771. * ClientHanlder. If no client is currently connected it will return
  772. * <code>null</code>
  773. * @since 1.3.1
  774. */
  775. public Date getClientConnectedTime() {
  776. return clientConnectedTime;
  777. }
  778. /**
  779. * Read the byte input. This will block till some data is
  780. * received from the stream.
  781. * @return The data as a String
  782. * @since 1.3.1
  783. */
  784. protected abstract byte[] readInputStream() throws IOException;
  785. protected static byte[] readInputStream(InputStream _in) throws IOException {
  786. byte data[] = null;
  787. if(_in==null)
  788. throw new IOException("InputStream can't be null!");
  789. int s = _in.read();
  790. if(s==-1) {
  791. return null; //Connection lost
  792. }
  793. int alength = _in.available();
  794. if(alength > 0) {
  795. data = new byte[alength+1];
  796. _in.read(data, 1, alength);
  797. } else {
  798. data = new byte[1];
  799. }
  800. data[0] = (byte)s;
  801. return data;
  802. }
  803. /**
  804. * Read the byte input. This will block till some data is
  805. * received from the stream. Allowed only when
  806. * <code>DataType.IN</code> is in <code>DataMode.BYTE</code> mode.
  807. * @return The data as a String
  808. * @since 1.3.2
  809. */
  810. public String readBytes() throws IOException {
  811. if(dataModeIN != DataMode.BYTE)
  812. throw new IllegalStateException("Can't read Byte: " +
  813. "DataType.IN is not in DataMode.BYTE");
  814. byte data[] = readInputStream();
  815. if(data!=null)
  816. return new String(data, charset);
  817. else
  818. return null;
  819. }
  820. /**
  821. * Sets the communication logging flag.
  822. * @see #getCommunicationLogging
  823. * @since 1.3.2
  824. */
  825. public void setCommunicationLogging(boolean communicationLogging) {
  826. this.communicationLogging = communicationLogging;
  827. }
  828. /**
  829. * Returns the communication logging flag.
  830. * @see #setCommunicationLogging
  831. * @since 1.3.2
  832. */
  833. public boolean getCommunicationLogging() {
  834. return communicationLogging;
  835. }
  836. /**
  837. * Returns the date/time when the client socket last sent a data to this
  838. * ClientHanlder. If no client is currently connected it will return
  839. * <code>null</code>
  840. * @since 1.3.3
  841. */
  842. public Date getLastCommunicationTime() {
  843. return lastCommunicationTime;
  844. }
  845. /**
  846. * Updates the last communication time for this client
  847. * @since 1.3.3
  848. */
  849. public void updateLastCommunicationTime() {
  850. lastCommunicationTime = new Date();
  851. }
  852. /**
  853. * Force the closing of the client by closing the associated socket.
  854. * @since 1.3.3
  855. */
  856. public synchronized void forceClose() throws IOException {
  857. if(getSelectionKey()!=null) getSelectionKey().cancel();
  858. if(getSocketChannel()!=null) {
  859. getSocketChannel().close();
  860. setSocketChannel(null);
  861. }
  862. if(getSocket()!=null) {
  863. getSocket().close();
  864. setSocket(null);
  865. }
  866. }
  867. /**
  868. * Returns flag indicating if the client is connected in secure mode
  869. * (SSL or TLS).
  870. * @return secure flag
  871. * @since 1.4.0
  872. */
  873. public boolean isSecure() {
  874. return secure;
  875. }
  876. /**
  877. * Sets flag indicating if the client is connected in secure mode
  878. * (SSL or TLS).
  879. * @param secure
  880. * @since 1.4.0
  881. */
  882. public void setSecure(boolean secure) {
  883. this.secure = secure;
  884. }
  885. /**
  886. * Updates the InputStream and OutputStream for the ClientHandler for the
  887. * set Socket.
  888. * @since 1.4.0
  889. * @see #setSocket
  890. */
  891. public abstract void updateInputOutputStreams() throws IOException;
  892. /**
  893. * Makes current Client connection to secure protocol based on the
  894. * secure configuration set to the server. This method will just call
  895. * <code>makeSecure(false, false, true, null)</code>.
  896. * @throws IOException
  897. * @throws NoSuchAlgorithmException
  898. * @throws KeyManagementException
  899. * @since 1.4.0
  900. */
  901. public void makeSecure() throws IOException, NoSuchAlgorithmException,
  902. KeyManagementException {
  903. makeSecure(false, false, true, null);
  904. }
  905. /**
  906. * Makes current Client connection to secure protocol.
  907. * This method will just call <code>makeSecure(false, false, true, protocol)</code>.
  908. * @throws IOException
  909. * @throws NoSuchAlgorithmException
  910. * @throws KeyManagementException
  911. * @since 1.4.0
  912. */
  913. public void makeSecure(String protocol) throws IOException,
  914. NoSuchAlgorithmException, KeyManagementException {
  915. makeSecure(false, false, true, protocol);
  916. }
  917. /**
  918. * Makes current Client connection to secure protocol.
  919. * @param useClientMode falg if the socket should start its first handshake in "client" mode.
  920. * @param needClientAuth flag if the clients must authenticate themselves.
  921. * @param autoClose close the underlying socket when this socket is closed
  922. * @param protocol the standard name of the requested protocol. If <code>null</code> will use the protocol set in secure configuration of the server.
  923. * @throws IOException
  924. * @throws NoSuchAlgorithmException
  925. * @throws KeyManagementException
  926. * @since 1.4.0
  927. */
  928. public void makeSecure(boolean useClientMode, boolean needClientAuth,
  929. boolean autoClose, String protocol) throws IOException,
  930. NoSuchAlgorithmException, KeyManagementException {
  931. if(isSecure()==true) {
  932. throw new IllegalStateException("Client is already in secure mode!");
  933. }
  934. appLogger.fine("Making secure - Protocol: "+protocol+
  935. ", Client: ["+getHostAddress()+"]");
  936. javax.net.ssl.SSLSocketFactory sslSf = getServer().getSSLSocketFactory(protocol);
  937. String host = getServer().getBindAddr().getHostAddress();
  938. if(host.equals("0.0.0.0")) host = InetAddress.getLocalHost().getHostAddress();
  939. SSLSocket newSocket = (SSLSocket) sslSf.createSocket(
  940. getSocket(), host, getServer().getPort(), autoClose);
  941. newSocket.setNeedClientAuth(needClientAuth);
  942. newSocket.setUseClientMode(useClientMode);
  943. setSocket(newSocket);
  944. setSecure(true);
  945. updateInputOutputStreams();
  946. }
  947. /**
  948. * Send a binary data to the connected client.
  949. * If client is not connected it will just return.
  950. * @since 1.4
  951. * @exception IOException
  952. * if Socket IO Error or Socket was closed by the client.
  953. */
  954. public void sendClientBinary(byte data[]) throws IOException {
  955. sendClientBinary(data, 0, data.length);
  956. }
  957. /**
  958. * Send a binary data to the connected client.
  959. * If client is not connected it will just return.
  960. * @since 1.4.5
  961. * @exception IOException
  962. * if Socket IO Error or Socket was closed by the client.
  963. */
  964. public void sendClientBinary(byte data[], int off, int len) throws IOException {
  965. if(isConnected()) {
  966. if(dataModeOUT != DataMode.BINARY)
  967. throw new IllegalStateException("Can't send Binary :" +
  968. "DataType.OUT is not in DataMode.BINARY");
  969. if(getCommunicationLogging()) {
  970. appLogger.fine("Sending ["+getHostAddress()+"] : "+MyString.getMemInfo(len));
  971. }
  972. b_out.write(data, off, len);
  973. b_out.flush();
  974. } else {
  975. logger.warning("Client not connected.");
  976. }
  977. }
  978. /**
  979. * Read the binary input. This will block till some data is
  980. * received from the stream. Allowed only when
  981. * <code>DataType.IN</code> is in <code>DataMode.BINARY</code> mode.
  982. * @return The data as a String
  983. * @since 1.4
  984. */
  985. public byte[] readBinary() throws IOException {
  986. if(dataModeIN != DataMode.BINARY)
  987. throw new IllegalStateException("Can't read Binary :" +
  988. "DataType.IN is not in DataMode.BINARY");
  989. byte data[] = readInputStream();
  990. return data;
  991. }
  992. /**
  993. * Sets the ClientBinaryHandler class that interacts with
  994. * client sockets.
  995. * @param handler fully qualified name of the class that
  996. * implements {@link ClientBinaryHandler}
  997. * @since 1.4
  998. */
  999. protected void setClientBinaryHandler(ClientBinaryHandler handler) {
  1000. clientBinaryHandler=handler;
  1001. }
  1002. /**
  1003. * Returns client SelectionKey associated, if any.
  1004. * @since 1.4.5
  1005. */
  1006. public Logger getAppLogger() {
  1007. return appLogger;
  1008. }
  1009. /**
  1010. * Sets the client socket's timeout.
  1011. * @param time client socket timeout in milliseconds.
  1012. * @see #getTimeout
  1013. * @since 1.4.5
  1014. */
  1015. public void setTimeout(int time) {
  1016. socketTimeout = time;
  1017. }
  1018. /**
  1019. * Returns the Client socket timeout in milliseconds.
  1020. * @see #setTimeout
  1021. * @since 1.4.5
  1022. */
  1023. public int getTimeout() {
  1024. return socketTimeout;
  1025. }
  1026. /**
  1027. * Checks if this client has the event.
  1028. * @since 1.4.5
  1029. */
  1030. public boolean hasEvent(ClientEvent event) {
  1031. synchronized(clientEvents) {
  1032. return clientEvents.contains(event);
  1033. }
  1034. }
  1035. /**
  1036. * Adds the ClientEvent.
  1037. * @since 1.4.5
  1038. */
  1039. public void addEvent(ClientEvent event) {
  1040. synchronized(clientEvents) {
  1041. unprocessedClientEvents.add(event);
  1042. clientEvents.add(event);
  1043. }
  1044. }
  1045. /**
  1046. * Removes the ClientEvent.
  1047. * @since 1.4.5
  1048. */
  1049. public void removeEvent(ClientEvent event) {
  1050. if(event==null) return;
  1051. synchronized(clientEvents) {
  1052. clientEvents.remove(event);
  1053. }
  1054. ClientEvent _clientEvent = (ClientEvent)threadEvent.get();
  1055. if(_clientEvent!=null && _clientEvent==event) {
  1056. threadEvent.set(null);
  1057. }
  1058. }
  1059. /**
  1060. * Returns threads current event for this client.
  1061. * @since 1.4.5
  1062. */
  1063. protected ClientEvent getThreadEvent() {
  1064. return (ClientEvent)threadEvent.get();
  1065. }
  1066. /**
  1067. * Sets message to be displayed when maximum connection reaches.
  1068. * @since 1.4.5
  1069. */
  1070. public void setMaxConnectionMsg(String msg) {
  1071. maxConnectionMsg = msg;
  1072. }
  1073. /**
  1074. * Returns message to be displayed to the client when maximum
  1075. * connection reaches.
  1076. * @since 1.4.5
  1077. */
  1078. public String getMaxConnectionMsg() {
  1079. return maxConnectionMsg;
  1080. }
  1081. /**
  1082. * Sets client socket channel associated, if any.
  1083. * @since 1.4.5
  1084. */
  1085. public abstract void setSocketChannel(SocketChannel socketChannel);
  1086. /**
  1087. * Returns client socket channel associated, if any.
  1088. * @since 1.4.5
  1089. */
  1090. public abstract SocketChannel getSocketChannel();
  1091. /**
  1092. * Sets client SelectionKey associated, if any.
  1093. * @since 1.4.5
  1094. */
  1095. public abstract void setSelectionKey(SelectionKey selectionKey);
  1096. /**
  1097. * Returns client SelectionKey associated, if any.
  1098. * @since 1.4.5
  1099. */
  1100. public abstract SelectionKey getSelectionKey();
  1101. public boolean getWillClean() {
  1102. return willClean;
  1103. }
  1104. /**
  1105. * Register OP_READ with the SelectionKey associated with the channel. If SelectionKey is
  1106. * not set then it registers the channel with the Selector.
  1107. * @since 1.4.5
  1108. */
  1109. public abstract void registerForRead() throws IOException,
  1110. ClosedChannelException;
  1111. /**
  1112. * Register OP_WRITE with the SelectionKey associated with the channel.
  1113. * @since 1.4.5
  1114. */
  1115. public abstract void registerForWrite() throws IOException,
  1116. ClosedChannelException;
  1117. /**
  1118. * Sets the ClientWriteHandler class that interacts with
  1119. * client sockets.
  1120. * @param handler fully qualified name of the class that
  1121. * implements {@link ClientWriteHandler}
  1122. * @since 1.4.5
  1123. */
  1124. protected abstract void setClientWriteHandler(ClientWriteHandler handler);
  1125. /**
  1126. * Sets the Charset to be used for String decoding and encoding.
  1127. * @param charset to be used for String decoding and encoding
  1128. * @see #getCharset
  1129. * @since 1.4.5
  1130. */
  1131. public void setCharset(String charset) {
  1132. if(charset==null || charset.trim().length()==0)
  1133. return;
  1134. this.charset = charset;
  1135. }
  1136. /**
  1137. * Returns Charset to be used for String decoding and encoding..
  1138. * @see #setCharset
  1139. * @since 1.4.5
  1140. */
  1141. public String getCharset() {
  1142. return charset;
  1143. }
  1144. /**
  1145. * Returns cached socket host ip address.
  1146. * @since 1.4.5
  1147. */
  1148. public String getHostAddress() {
  1149. return hostAddress;
  1150. }
  1151. protected void assertionSystemExit() {
  1152. logger.warning("[Assertions Was Enabled] Forcing program exit to help developer.");
  1153. org.quickserver.net.qsadmin.QSAdminShell.tryFullThreadDump();//it can help debug.
  1154. try {
  1155. Thread.sleep(100);
  1156. } catch(InterruptedException e) {
  1157. logger.fine("Interrupted: "+e);
  1158. }
  1159. System.exit(-1);
  1160. }
  1161. /**
  1162. * Checks if the passed ClientEvent is the one next for
  1163. * processing if a thread is allowed through this object.
  1164. * @since 1.4.6
  1165. */
  1166. public boolean isClientEventNext(ClientEvent clientEvent) {
  1167. ClientEvent ce = null;
  1168. synchronized(clientEvents) {
  1169. if(unprocessedClientEvents.size()>0)
  1170. ce = (ClientEvent) unprocessedClientEvents.get(0);
  1171. }
  1172. return clientEvent == ce;
  1173. }
  1174. /**
  1175. *Returns the {@link java.io.BufferedInputStream} associated with
  1176. * the Client being handled. Can be null if not available at the time of method call.
  1177. * @see #getBufferedOutputStream
  1178. * @since 1.4.6
  1179. */
  1180. public BufferedInputStream getBufferedInputStream() {
  1181. return b_in;
  1182. }
  1183. /**
  1184. * Returns the {@link java.io.BufferedOutputStream} associated with
  1185. * the Client being handled. Can be null if not available at the time of method call.
  1186. * @see #getBufferedInputStream
  1187. * @since 1.4.6
  1188. */
  1189. public BufferedOutputStream getBufferedOutputStream() {
  1190. return b_out;
  1191. }
  1192. protected void handleTimeout(SocketTimeoutException e) throws SocketException, IOException {
  1193. appLogger.fine("Timeout - Client [" + getHostAddress() +"]");
  1194. appLogger.finest("SocketTimeoutException : " + e.getMessage());
  1195. String temp = null;
  1196. if(clientExtendedEventHandler!=null) {
  1197. clientExtendedEventHandler.handleTimeout(this);
  1198. } else {
  1199. temp = timeoutMsg;
  1200. if(dataModeOUT == DataMode.STRING)
  1201. temp = temp + NEW_LINE;
  1202. if(dataModeOUT != DataMode.OBJECT) {
  1203. out.write(temp.getBytes(charset));
  1204. out.flush();
  1205. }
  1206. if(true) throw new SocketException("Timeout");
  1207. }
  1208. }
  1209. }