// // Copyright (c)1998-2011 Pearson Education, Inc. or its affiliate(s). // All rights reserved. // package openadk.library.impl; import openadk.library.*; import openadk.library.infra.SIF_Protocol; import openadk.library.threadpool.IThreadPoolDelayTask; /** * A protocol handler implementation for HTTP. Each zone that is registered with * a ZIS using the HTTP or HTTPS protocol has an instance of this class as its * protocol handler. It implements the HttpHandler interface to process SIF * messages received by the agent's internal Jetty HTTP Server. When a message * is received via that interface it is delegated to the zone's * MessageDispatcher. HttpProtocolHandler also implements the IProtocolHandler * interface so it can send outgoing messages received by the MessageDispatcher. * * An instance of this class runs in a separate thread only when the agent is * registered with the ZIS in Pull mode. In this case it does not accept * ,essages from the HttpHandler interface but instead periodically queries the * ZIS for new messages waiting in the agent's queue. Messages are delegated to * the MessageDispatcher for processing. * * @author Andrew Elmhorst * @version 2.1 * */ public class HttpPullProtocolHandler extends BaseHttpProtocolHandler implements Runnable, IThreadPoolDelayTask { /** * Creates an instance of HttpPullProtocolHandler running on an HTTP or * HTTPS transport * * @param transport */ HttpPullProtocolHandler(HttpTransport transport) { super(transport); } private int fDelay; private boolean fStarted = false; @Override public synchronized void start() { // Polling thread already running? if (fStarted) { fZone.log .debug("Polling thread (HTTP/HTTPS) already running for zone"); return; } if ((ADK.debug & ADK.DBG_TRANSPORT) != 0) { fZone.log .debug("Starting polling thread (HTTP/HTTPS), zone connected in Pull mode..."); } // fStarted must be true _prior_ before run method is called // because "this" is entered into an executor, "this" may execute // prior to the execute method returning try { fStarted = true; fTransport.fThreadPoolManager.execute(this); } catch (Exception e) { fStarted = false; fZone.log.error("Polling thread (HTTP/HTTPS) failed to start", e); } } @Override public synchronized void shutdown() { fStarted = false; fTransport.fThreadPoolManager.removeTask(this); fDelay = -1; } /* (non-Javadoc) * @see openadk.library.impl.BaseHttpProtocolHandler#open(openadk.library.impl.ZoneImpl) */ @Override public void open(ZoneImpl zone) throws ADKException { super.open(zone); fDelay = fZone.getProperties().getPullFrequency(); } /** * Thread periodically sends a SIF_GetMessage request to the ZIS to get the * next message waiting in the agent queue. When running in a thread pool * this method returns after a single pull, otherwise runs until shutdown. */ public void run() { if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) { fZone.log .debug("Polling task (HTTP/HTTPS) started"); } int freq = fZone.getProperties().getPullFrequency(); int delay = fZone.getProperties().getPullDelayOnError(); try { if (fZone.isShutdown() || !fStarted) { if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) { fZone.log .debug("Polling thread (HTTP/HTTPS) will stop, zone has shut down"); } delayProcessing(-1); // negative delay removes handler from thread pool } else if (fZone.isSleeping( ADKFlags.QUEUE_LOCAL ) ) { if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0){ fZone.log.debug("Polling thread (HTTP/HTTPS) will delay " + delay / 1000 + " seconds, zone is sleeping."); } delayProcessing(delay); } else if (!fZone.isConnected()) { if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0){ fZone.log.debug("Polling thread (HTTP/HTTPS) will delay " + delay / 1000 + " seconds, zone is no longer connected"); } delayProcessing(delay); } else { int i = fZone.getFDispatcher().pull(); if (i == -1) { // The zone is sleeping if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) fZone.log.debug("Polling thread (HTTP/HTTPS) will delay " + delay / 1000 + " seconds, zone is sleeping"); delayProcessing(delay); } else if (i == 1) { // Pulled message from ZIS queue delayProcessing(0); // Reschedule immediately } else { // No messages in ZIS queue delayProcessing(freq); } } } catch (LifecycleException le) { // Agent was shutdown - exit gracefully } catch (Exception adke) { // TT139 Andy E. Catch all exceptions, not just ADK Exceptions if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) fZone.log .debug("Polling thread (HTTP/HTTPS) failed to retrieve message: " + adke); // // Special Check: If registered in Push mode and we're still // pulling, stop the thread - there is no sense in continuing. // This should not happen, but just in case... // if (adke instanceof ADKException && ((ADKException) adke).hasSIFError( SIFErrorCategory.REGISTRATION, SIFErrorCodes.REG_PUSH_EXPECTED_9)) { if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) fZone.log .debug("Polling thread (HTTP/HTTPS) will now stop because agent is registered in Push mode"); delayProcessing(-1); // negative delay removes handler from thread pool return; } delayProcessing(freq); } if ((ADK.debug & ADK.DBG_MESSAGING_PULL) != 0) { fZone.log .debug("Polling task (HTTP/HTTPS) will delay for " + getScheduleDelay() + "ms"); } } /** * Causes the currently executing thread to sleep when not running in a * thread pool. Otherwise notifies the thread pool to reschedule after * delay. * * @param delay the length of time to sleep in milliseconds * @throws InterruptedException */ private void delayProcessing(int delay) { fDelay = delay; // notify thread scheduler of delay time } public synchronized boolean isActive(ZoneImpl zone) { return fStarted; } public SIF_Protocol makeSIF_Protocol(Zone zone, SIFVersion version) throws ADKTransportException { // No SIF_Protocol element is necessary in pull mode return null; } public int getScheduleDelay() { return fDelay; } }