/** * Excute the pattern matching algorithm to determine if a the current connection must be * suspended or not, and when. * * @param ctx The current {@link Context} * @return true if the ProtocolChain should continue its execution, false if the connection has * been suspended. * @throws java.io.IOException */ public boolean execute(Context ctx) throws IOException { WorkerThread wt = (WorkerThread) Thread.currentThread(); ByteBuffer bb = wt.getByteBuffer(); controller = ctx.getController(); if (ctx.getProtocol() == Controller.Protocol.TCP) { ctx.getSelectionKey().attach(null); } else { wt.getAttachment().setTimeout(Long.MIN_VALUE); } if (protocolChain == null) { if (ctx.getProtocolChain() instanceof DefaultProtocolChain) { protocolChain = (DefaultProtocolChain) ctx.getProtocolChain(); } else { throw new IllegalStateException( "SuspendableFilter cannot be " + "used without the DefaultProtocolChain"); } } if (logger.isLoggable(Level.FINE)) { logger.fine("Trying to match " + ctx.getSelectionKey()); } // This will be quite slow if a lot of registration. // TODO: Need a better algorithm. SuspendableHandlerWrapper<? extends T> sh = null; Iterator<byte[]> iterator = suspendCandidates.keySet().iterator(); byte[] matchBytes = null; while (iterator.hasNext()) { matchBytes = iterator.next(); if (Utils.findBytes(bb, matchBytes) > -1) { if (logger.isLoggable(Level.FINE)) { logger.fine( "Find match: " + (new String(matchBytes)) + " Suspending: " + ctx.getSelectionKey()); } sh = suspendCandidates.get(matchBytes); break; } } if (sh != null) { KeyHandler kh = new KeyHandler(); kh.setSuspendableHandler(sh); suspendedKeys.put(ctx.getSelectionKey(), kh); if (sh.getSuspendWhen() == Suspend.BEFORE) { suspend(ctx, true); if (logger.isLoggable(Level.FINE)) { logger.fine("-----> " + ctx.getKeyRegistrationState()); } return false; } } return true; }
/** * Suspend the request by creating the appropriate structure so the state of the current * connection is not lost. * * @param ctx The current {@link Context} * @param incomingRequest suspend now of after. */ private void suspend(Context ctx, boolean incomingRequest) { try { SelectionKey key = ctx.getSelectionKey(); KeyHandler kh = suspendedKeys.get(key); SuspendableHandlerWrapper<? extends T> sh = null; if (kh != null) { sh = kh.getSuspendableHandler(); } else { kh = new KeyHandler(); } if (kh != null && !incomingRequest) { if (sh.getSuspendWhen() == Suspend.BEFORE) { return; } } // If the users didn't want to be notified. if (sh == null) { // TODO: Configurable. sh = new SuspendableHandlerWrapper( new SuspendableHandler() { public void interupted(Object attachment) {} public void expired(Object attachment) {} public void resumed(Object attachment) {} }, null, 30000, new Suspendable(this), Suspend.AFTER); } sh.setSuspendableFilter(this); sh.suspendable.setKey(key); sh.setSelectorHandler(ctx.getSelectorHandler()); kh.setSuspendableHandler(sh); kh.setKey(key); WorkerThread workerThread = (WorkerThread) Thread.currentThread(); ThreadAttachment attachment = workerThread.getAttachment(); attachment.setMode(Mode.STORE_ALL); kh.setThreadAttachment(workerThread.detach()); ctx.setKeyRegistrationState(KeyRegistrationState.NONE); suspendableMonitor.suspend(kh); } catch (Throwable ex) { if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "suspend", ex); } } }