/** * Dispatch a serialized command to the BackEnd and get back a serialized response. Mutual * exclusion with itself to preserve dispatching order */ public synchronized byte[] dispatch(byte[] payload, boolean flush) throws ICPException { // Note that we don't even try to dispatch packets while the // device is not reachable to preserve dispatching order. // If dispatching succeeded in fact this command would overcome // any postponed command waiting to be flushed. if (myDisconnectionManager.isReachable()) { // The following check preserves dispatching order when the // device has just reconnected but flushing has not started yet if (waitingForFlush && !flush) { throw new ICPException("Upsetting dispatching order"); } waitingForFlush = false; int sid = outCnt; outCnt = (outCnt + 1) & 0x0f; myLogger.log(Logger.FINE, "Issuing outgoing command " + sid); try { JICPPacket pkt = new JICPPacket(JICPProtocol.COMMAND_TYPE, JICPProtocol.DEFAULT_INFO, payload); pkt.setSessionID((byte) sid); pkt = deliver(pkt); myLogger.log(Logger.FINE, "Response received " + pkt.getSessionID()); if (pkt.getType() == JICPProtocol.ERROR_TYPE) { // Communication OK, but there was a JICP error on the peer throw new ICPException(new String(pkt.getData())); } return pkt.getData(); } catch (IOException ioe) { // Can't reach the BackEnd. Assume we are unreachable myLogger.log(Logger.WARNING, "IOException on output connection", ioe); myDisconnectionManager.setUnreachable(false); throw new ICPException("Dispatching error.", ioe); } } else { throw new ICPException("Unreachable"); } }
public void run() { if (cnt == 0) { // Give precedence to the Thread that is creating the BackEnd Thread.yield(); // In the meanwhile load the ConnectionListener if any try { myConnectionListener = (ConnectionListener) Class.forName(props.getProperty("connection-listener")).newInstance(); } catch (Exception e) { // Just ignore it } } myId = cnt++; myLogger.log(Logger.INFO, "IM-" + myId + " started"); // Prepare an initial dummy response JICPPacket rsp = new JICPPacket(JICPProtocol.RESPONSE_TYPE, JICPProtocol.DEFAULT_INFO, null); while (active) { try { // Prepare the connection for next incoming command refreshConnection(); myDisconnectionManager.waitUntilReachable(); // Deliver the response to the previous incoming command and wait for the next one // If we are delivering the response to an exit command, set active to false to avoid an // annoying stack trace // (due to the fact that the back-end will close the connection instead of sending further // commands) and exit if (this == terminator) { active = false; } JICPPacket cmd = deliver(rsp, myConnection); myKeepAliveManager.update(); if (cmd.getType() == JICPProtocol.KEEP_ALIVE_TYPE) { // Keep-alive if (myLogger.isLoggable(Logger.FINER)) { myLogger.log(Logger.FINER, "Keep-alive received"); } rsp = new JICPPacket(JICPProtocol.RESPONSE_TYPE, JICPProtocol.OK_INFO, null); } else { // Command byte sid = cmd.getSessionID(); if (sid == lastSid) { myLogger.log(Logger.WARNING, "Duplicated command received " + sid); rsp = lastResponse; } else { myLogger.log(Logger.FINE, "Incoming command received " + sid); byte[] rspData = mySkel.handleCommand(cmd.getData()); myLogger.log(Logger.FINE, "Incoming command served " + sid); rsp = new JICPPacket(JICPProtocol.RESPONSE_TYPE, JICPProtocol.DEFAULT_INFO, rspData); rsp.setSessionID(sid); lastSid = sid; lastResponse = rsp; } } } catch (Exception e) { if (active) { myLogger.log(Logger.WARNING, "Exception on input connection", e); // Note that the boolean value passed to setUnreachable() only indicates if the // unreachability was detected by a missing keep-alive myDisconnectionManager.setUnreachable(false); } } } myLogger.log(Logger.INFO, "IM-" + myId + " terminated"); }