/** Send a CONNECT_MEDIATOR packet to the BackEnd to check if it is reachable */ private boolean ping(int cnt) throws ICPException { // Try first with the current transport address, then with the various backup addresses for (int i = -1; i < backEndAddresses.length; i++) { if (i >= 0) { // Set the mediator address to a new address.. String addr = backEndAddresses[i]; int colonPos = addr.indexOf(':'); String host = addr.substring(0, colonPos); String port = addr.substring(colonPos + 1, addr.length()); mediatorTA = new JICPAddress(host, port, myMediatorID, ""); } try { myLogger.log( Logger.FINE, "Ping " + mediatorTA.getHost() + ":" + mediatorTA.getPort() + "(" + cnt + ")..."); JICPPacket pkt = new JICPPacket(JICPProtocol.CONNECT_MEDIATOR_TYPE, JICPProtocol.DEFAULT_INFO, null); pkt = deliver(pkt); if (pkt.getType() == JICPProtocol.ERROR_TYPE) { // Communication OK, but there was a JICP error. String errorMsg = new String(pkt.getData()); if (errorMsg.equals(JICPProtocol.NOT_FOUND_ERROR)) { // Back-end not found: either the max disconnection time expired server side or there // was a fault and restart // --> Try to recreate the Back-end myLogger.log( Logger.WARNING, "Communication OK, but Back-end no longer present. Try to recreate it"); if (myConnectionListener != null) { myConnectionListener.handleConnectionEvent(ConnectionListener.BE_NOT_FOUND, null); } try { createBackEnd(); } catch (IMTPException imtpe) { myLogger.log(Logger.WARNING, "Error re-creating the Back-end."); return false; } } else { // Generic JICP error. No need to go on throw new ICPException("JICP error. " + errorMsg); } } return true; } catch (IOException ioe) { // Ignore it, and try the next address... myLogger.log(Logger.FINE, "Ping KO", ioe); } } // No address succeeded. return false; }
/** Deliver a packet over a given connection and get back a response */ private JICPPacket deliver(JICPPacket pkt, Connection c) throws IOException { boolean lastPacket = false; if (Thread.currentThread() == terminator) { pkt.setTerminatedInfo(true); lastPacket = true; } pkt.setRecipientID(mediatorTA.getFile()); byte type = pkt.getType(); int status = 0; try { c.writePacket(pkt); status = 1; /*#MIDP_INCLUDE_BEGIN lock(); if (type == JICPProtocol.RESPONSE_TYPE) { TimerDispatcher.getTimerDispatcher().add(new Timer(System.currentTimeMillis()+5000, this)); } #MIDP_INCLUDE_END*/ pkt = c.readPacket(); status = 2; if (lastPacket && (pkt.getInfo() & JICPProtocol.TERMINATED_INFO) != 0) { // When we send a packet marked with the terminated-info, the back-end may either close // the connection (in this case we would have got an Exception) or reply with another // packet marked with the terminated-info --> throws an Exception to expose a uniform // behaviour myLogger.log(Logger.INFO, "Termination notification ACK received"); throw new IOException("Terminated-info"); } return pkt; } catch (IOException ioe) { // Re-throw the exception adding the status throw new IOException(ioe.getMessage() + '[' + status + ']'); } finally { /*#MIDP_INCLUDE_BEGIN if (type != JICPProtocol.RESPONSE_TYPE) { // If we delivered a RESPONSE unlock() is already called by the TimerDispatcher unlock(); } #MIDP_INCLUDE_END*/ } }
/** * 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"); }
/** * Send the CREATE_MEDIATOR command with the necessary parameter in order to create the BackEnd in * the fixed network. Executed - at bootstrap time by the thread that creates the * FrontEndContainer. - To re-attach to the platform after a fault of the BackEnd */ private synchronized void createBackEnd() throws IMTPException { StringBuffer sb = BackEndStub.encodeCreateMediatorRequest(props); if (myMediatorID != null) { // This is a request to re-create my expired back-end BackEndStub.appendProp(sb, JICPProtocol.MEDIATOR_ID_KEY, myMediatorID); BackEndStub.appendProp(sb, "outcnt", String.valueOf(outCnt)); BackEndStub.appendProp(sb, "lastsid", String.valueOf(lastSid)); } JICPPacket pkt = new JICPPacket( JICPProtocol.CREATE_MEDIATOR_TYPE, JICPProtocol.DEFAULT_INFO, null, sb.toString().getBytes()); // Try first with the current transport address, then with the various backup addresses for (int i = -1; i < backEndAddresses.length; i++) { if (i >= 0) { // Set the mediator address to a new address.. String addr = backEndAddresses[i]; int colonPos = addr.indexOf(':'); String host = addr.substring(0, colonPos); String port = addr.substring(colonPos + 1, addr.length()); mediatorTA = new JICPAddress(host, port, myMediatorID, ""); } try { HTTPClientConnection hc = (HTTPClientConnection) getConnection(mediatorTA); myLogger.log( Logger.INFO, "Creating BackEnd on " + hc.getProtocol() + mediatorTA.getHost() + ":" + mediatorTA.getPort()); pkt = deliver(pkt); String replyMsg = new String(pkt.getData()); if (pkt.getType() != JICPProtocol.ERROR_TYPE) { // BackEnd creation successful BackEndStub.parseCreateMediatorResponse(replyMsg, props); myMediatorID = props.getProperty(JICPProtocol.MEDIATOR_ID_KEY); // Complete the mediator address with the mediator ID mediatorTA = new JICPAddress(mediatorTA.getHost(), mediatorTA.getPort(), myMediatorID, null); myDisconnectionManager.setReachable(); myKeepAliveManager.update(); myLogger.log(Logger.INFO, "BackEnd OK. Mediator ID is " + myMediatorID); return; } else { myLogger.log(Logger.WARNING, "Mediator error: " + replyMsg); } } catch (IOException ioe) { // Ignore it, and try the next address... myLogger.log(Logger.WARNING, "Connection error", ioe); } } // No address succeeded! throw new IMTPException("Error creating the BackEnd."); }