예제 #1
0
 /**
  * @return <tt>true</tt> if the previous ProtocolFilter postExecute method needs to be invoked.
  */
 public boolean postExecute(Context ctx) throws IOException {
   AIOContext context = (AIOContext) ctx;
   if (!context.isKeepAlive()) {
     try {
       context.getChannel().close();
     } catch (AsynchronousCloseException ex) {
       if (Controller.logger().isLoggable(Level.FINE)) {
         Controller.logger().log(Level.FINE, "postExecute()", ex);
       }
     } finally {
       context.getController().returnContext(context);
     }
     return false;
   } else {
     ByteBuffer buffer = ((WorkerThread) Thread.currentThread()).getByteBuffer();
     ByteBuffer bb = context.getByteBuffer();
     if (bb == null && buffer != null) {
       bb = buffer;
       ((WorkerThread) Thread.currentThread()).setByteBuffer(null);
     } else if (bb == null && buffer == null) {
       int size = 8192;
       ByteBufferType bbt = ByteBufferType.DIRECT;
       if (ctx.getThreadPool() instanceof DefaultThreadPool) {
         size = ((DefaultThreadPool) ctx.getThreadPool()).getInitialByteBufferSize();
         bbt = ((DefaultThreadPool) ctx.getThreadPool()).getByteBufferType();
       }
       bb = ByteBufferFactory.allocate(bbt, size);
     }
     bb.clear();
     context.setByteBuffer(bb);
     long timeOut = (Long) ctx.getAttribute("timeout");
     context.getChannel().read(bb, timeOut, TimeUnit.SECONDS, null, context);
     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);
      }
    }
  }
  /**
   * 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 postExecute(Context ctx) throws IOException {
    if (logger.isLoggable(Level.FINE)) {
      logger.fine("<----- " + ctx.getKeyRegistrationState());
    }

    if (!suspendedKeys.isEmpty()
        && ctx.getKeyRegistrationState() == KeyRegistrationState.REGISTER) {
      suspend(ctx, false);
      return false;
    }
    return true;
  }
  /**
   * 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;
  }
 /**
  * Return a {@link Context} to its pool if it is not shared.
  *
  * @param ctx - the {@link Context}
  */
 public void returnContext(Context ctx) {
   if (ctx instanceof NIOContext && ((NIOContext) ctx).decrementRefCount() > 0) {
     return;
   }
   if (logger.isLoggable(Level.FINE)) {
     logger.log(Level.FINE, "returnContext() Context : " + ctx);
   }
   ctx.recycle();
   contexts.offer(ctx);
 }
  /**
   * Configure the {@link Context}
   *
   * @param context
   * @param selectorHandler
   */
  /* package */ public void configureContext(Context context, SelectorHandler selectorHandler) {

    if (!(context instanceof NIOContext)) {
      throw new RuntimeException("Invalid Context instance: " + context.getClass().getName());
    }
    NIOContext ctx = (NIOContext) context;

    ctx.setSelectorHandler(selectorHandler);
    ctx.setThreadPool(selectorHandler.getThreadPool());
    ctx.setAsyncQueueReader(selectorHandler.getAsyncQueueReader());
    ctx.setAsyncQueueWriter(selectorHandler.getAsyncQueueWriter());
  }
  /**
   * Get an instance of a {@link NIOContext}
   *
   * @param key {@link SelectionKey}
   * @param opType the current SelectionKey op.
   * @return {@link Context}
   */
  /* package */ public NIOContext pollContext(SelectionKey key, OpType opType) {
    Context context = contexts.poll();
    if (!(context instanceof NIOContext)) {
      throw new RuntimeException("Invalid Context instance: " + context.getClass().getName());
    }
    NIOContext ctx = (NIOContext) context;
    ctx.setController(this);
    ctx.setSelectionKey(key);
    if (opType != null) {
      ctx.setCurrentOpType(opType);
    } else {
      if (key != null) {
        ctx.configureOpType(key);
      }
    }

    if (logger.isLoggable(Level.FINE)) {
      logger.log(Level.FINE, "pollContext(..) Context : " + ctx);
    }
    return ctx;
  }
  /**
   * Resume the connection by register back the SelectionKey for OP event.
   *
   * @param key
   * @return true if the connection was resumed.
   */
  protected boolean resume(SelectionKey key) {
    KeyHandler kh = suspendedKeys.remove(key);
    if (kh.getSuspendableHandler() == null) {
      return false;
    }
    if (logger.isLoggable(Level.FINE)) {
      logger.fine("Resuming: " + kh.getSuspendableHandler());
    }

    kh.getSuspendableHandler()
        .getSuspendableHandler()
        .resumed(kh.getSuspendableHandler().getAttachment());

    if (kh.getSuspendableHandler().getSuspendWhen() == Suspend.AFTER) {
      kh.getSuspendableHandler().getSelectorHandler().register(key.channel(), SelectionKey.OP_READ);
    } else {
      Context ctx = controller.pollContext(key);
      controller.configureContext(ctx, kh.getSuspendableHandler().getSelectorHandler());
      ctx.execute(
          SuspendableContextTask.poll(protocolChain, kh.getThreadAttachment(), nextFilterPosition));
    }

    return true;
  }