All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.grizzly.Context Maven / Gradle / Ivy

There is a newer version: 10.0-b28
Show newest version
/*
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 */

package com.sun.grizzly;

import com.sun.grizzly.async.AsyncQueueDataProcessor;
import com.sun.grizzly.async.AsyncQueueReadable;
import com.sun.grizzly.async.AsyncQueueReader;
import com.sun.grizzly.async.AsyncQueueWritable;
import com.sun.grizzly.async.AsyncQueueWriter;
import com.sun.grizzly.async.AsyncReadCallbackHandler;
import com.sun.grizzly.async.AsyncReadCondition;
import com.sun.grizzly.async.AsyncWriteCallbackHandler;
import com.sun.grizzly.util.AttributeHolder;
import com.sun.grizzly.util.Copyable;
import com.sun.grizzly.util.SelectionKeyAttachment;
import com.sun.grizzly.util.WorkerThread;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;

/**
 * This Object is used to share information between the Grizzly Framework
 * classes and {@link ProtocolFilter} implementation. Since {@link Context}
 * is a pooled resource 
 * {@link Controller#pollContext(java.nio.channels.SelectionKey)} 
 * transactions using {@link Context} outside its {@link ProtocolChain}
 * must invoke {@link #incrementRefCount()} and
 * {@link Controller#returnContext(com.sun.grizzly.Context)} to keep its pooling
 * intact.
 * @author Jeanfrancois Arcand
 */
public class Context implements AttributeHolder, Copyable {


    public enum AttributeScope {
        REQUEST,
        CONNECTION,
        SELECTOR,
        CONTROLLER
    }
    
    /**
     * A {@link SelectionKey}'s registration state.
     */
    public enum KeyRegistrationState {
        /** A cancelled {@link SelectionKey} registration state. */
        CANCEL,
        /** A registered {@link SelectionKey} registration state. */
        REGISTER,
        /** A {@link SelectionKey} with no registration state. */
        NONE }
    
    
    /**
     * The list of possible {@link SelectionKey}.OP_XXXX.
     */
    public enum OpType { OP_READ,
        OP_WRITE,
        OP_CONNECT,
        OP_READ_WRITE,
        OP_ACCEPT
    }
    
    
    /**
     * The current {@link SelectionKey} interest ops this Context is processing.
     */
    private OpType currentOpType;
    
    
    /**
     * The {@link ProtocolChain} used to execute this {@link Context}
     */
    private ProtocolChain protocolChain;
    
    
    /**
     * Constant 'throwable' String
     */
    public final static String THROWABLE ="throwable";
    
    
    /**
     * Used to share object between {@link ProtocolFilter}.
     * WARNING: Attributes which are added are never removed automatically
     * The removal operation must be done explicitly inside a  {@link ProtocolFilter}.
     */
    private Map attributes = null;
    
    
    /**
     * The current connection (@link SelectionKey}.
     */
    private SelectionKey key;
    
    
    /**
     * The {@link SelectorHandler} associated with this Context.
     */
    private SelectorHandler selectorHandler;

    
    /**
     * The {@link Controller} associated with this Context.
     */
    private Controller controller;
    
    
    /**
     * The state's of the key registration.
     */
    private KeyRegistrationState keyRegistrationState
            = KeyRegistrationState.REGISTER;
    
    
    /**
     * The current {@linl Pipeline} that execute this object.
     */
    private Pipeline pipeline;
    
    
    /**
     * An optional {@link IOEvent} that can be invoked
     * before the {@link ProtocolChain} is invoked.
     */
    private IOEvent ioEvent;
    
    
    /**
     * {@link AsyncQueueReader}
     */
    private AsyncQueueReader asyncQueueReader;

    /**
     * {@link AsyncQueueWriter}
     */
    private AsyncQueueWriter asyncQueueWriter;
    
    /**
     * {@link AsyncQueueReadable}
     */
    private AsyncQueueReadable asyncQueueReadable;

    /**
     * {@link AsyncQueueWritable}
     */
    private AsyncQueueWritable asyncQueueWritable;
    
    
    /**
     * Is this context suspended.
     */
    private boolean isSuspended = false;
    
     /**
     *  Reference Counter indicating how many Threads share this Context.
     *  Starts at one already counting {@link WorkerThread}.
     */
    private AtomicInteger refCounter=new AtomicInteger(1);
    
    
    /**
     * Constructor
     */
    public Context() {
    }
    
    
    public void copyTo(Copyable copy) {
        Context copyContext = (Context) copy;
        copyContext.currentOpType = currentOpType;
        copyContext.protocolChain = protocolChain;
        if (attributes != null) {
            copyContext.attributes = new HashMap(attributes);
        }
        copyContext.key = key;
        copyContext.selectorHandler = selectorHandler;
        copyContext.controller = controller;
        copyContext.keyRegistrationState = keyRegistrationState;
        copyContext.pipeline = pipeline;
        copyContext.ioEvent = ioEvent;
        copyContext.asyncQueueReader = asyncQueueReader;
        copyContext.asyncQueueWriter = asyncQueueWriter;
    }

    /**
     * Remove a key/value object.
     * @param key - name of an attribute
     * @return  attribute which has been removed
     */
    public Object removeAttribute(String key){
        if (attributes == null){
            return null;
        }
        return attributes.remove(key);
    }
    
    
    /**
     * Set a key/value object.
     * @param key - name of an attribute
     * @param value - value of named attribute
     */
    public void setAttribute(String key,Object value){
        if (attributes == null){
            attributes = new HashMap();
        }
        attributes.put(key,value);
    }
    
    
    /**
     * Return an object based on a key.
     * @param key - name of an attribute
     * @return - attribute value for the key, null if key
     *           does not exist in attributes
     */
    public Object getAttribute(String key){
        if (attributes == null){
            return null;
        }
        return attributes.get(key);
    }
    
    
    /**
     * Return {@link AttributeHolder}, which corresponds to the 
     * given {@link AttributeScope}>
     * 
     * @param scope - {@link AttributeScope}>
     * @return - {@link AttributeHolder} instance, which contains
     *           {@link AttributeScope}> attributes
     */
    public AttributeHolder getAttributeHolderByScope(AttributeScope scope){
        AttributeHolder holder = null;
        switch(scope) {
            case REQUEST: 
                holder = this;
                break;
            case CONNECTION:
                Object attachment = getSelectionKey().attachment();
                if (attachment instanceof AttributeHolder) {
                    holder = (AttributeHolder) attachment;
                }
                break;
            case SELECTOR:
                holder = selectorHandler;
                break;
            case CONTROLLER:
                holder = controller;
                break;
        }
        
        return holder;
    }

    
    /**
     * Set a {@link Map} of attribute name/value pairs.
     * Old {@link AttributeHolder} values will not be available.
     * Later changes of this {@link Map} will lead to changes to the current
     * {@link AttributeHolder}.
     * 
     * @param attributes - map of name/value pairs
     */
    public void setAttributes(Map attributes) {
        this.attributes = attributes;
    }

    
    /**
     * Return a {@link Map} of attribute name/value pairs.
     * Updates, performed on the returned {@link Map} will be reflected in
     * this {@link AttributeHolder}
     * 
     * @return - {@link Map} of attribute name/value pairs
     */
    public Map getAttributes() {
        return attributes;
    }

    
    /**
     * Return the current {@link SelectionKey}.
     * @return - this Context's SelectionKey
     */
    public SelectionKey getSelectionKey() {
        return key;
    }
    
    
    /**
     * Set the connection {@link SelectionKey}.
     * @param key - set this Context's SelectionKey
     */
    public void setSelectionKey(SelectionKey key) {
        this.key = key;
    }
    
    
    /**
     * Return the current {@link Controller}.
     * @return - this Context's current {@link Controller}
     */
    public Controller getController() {
        return controller;
    }
    
    
    /**
     * Set the current {@link Controller}.
     * @param {@link Controller}
     */
    public void setController(Controller controller) {
        this.controller = controller;
    }


    /**
     * Recycle this instance. 
     */
    public void recycle(){        
        if (isSuspended){
            throw new IllegalStateException("The Context has been marked as " +
                    "suspended and cannot be recycled");
        }
                
        getProtocolChainInstanceHandler().offer(protocolChain);            
        key = null;
        keyRegistrationState = KeyRegistrationState.REGISTER;
        currentOpType = null;
        protocolChain = null;
        ioEvent = null;
        asyncQueueReader = null;
        asyncQueueWriter = null;
        if (attributes != null) {
            attributes.clear();
        }
        isSuspended = false;
        refCounter.set(1);
    }
    
    
    /**
     * Return {@link SelectionKey}'s next registration state.
     * @return this Context's SelectionKey registration state
     */
    public KeyRegistrationState getKeyRegistrationState() {
        return keyRegistrationState;
    }
    
    
    /**
     * Set the {@link SelectionKey}'s next registration state
     * @param {@link keyRegistrationState} - set this Context's SelectionKey
     *        registration state
     */
    public void setKeyRegistrationState(KeyRegistrationState keyRegistrationState) {
        this.keyRegistrationState = keyRegistrationState;
    }
    
    
    /**
     * Return {@link ProtocolChain} executed by this instance.
     * @return {@link ProtocolChain} instance
     */
    public ProtocolChain getProtocolChain() {
        return protocolChain;
    }
    
    
    /**
     * Set the {@link ProtocolChain} used by this {@link Context}.
     * @param protocolChain instance of {@link ProtocolChain} to be used by the Context
     */
    public void setProtocolChain(ProtocolChain protocolChain) {
        this.protocolChain = protocolChain;
    }
    
    
    /**
     * Get the current {@link SelectionKey} interest ops this instance is executing.
     * @return OpType the currentOpType.
     */
    public OpType getCurrentOpType() {
        return currentOpType;
    }
    
    
    /**
     * Set the current OpType value.
     * @param currentOpType sets current operation type
     */
    public void setCurrentOpType(OpType currentOpType) {
        this.currentOpType = currentOpType;
    }

    
    /**
     * Configure the {@link #currentOpType} based on the 
     * {@link SelectionKey#readyOps()} values.
     * @param key
     */
    protected void configureOpType(SelectionKey key) {
        int readyOps = key.readyOps();   
        switch (readyOps){
            case SelectionKey.OP_CONNECT:
                currentOpType = OpType.OP_CONNECT;
                break;
            case SelectionKey.OP_READ:
                currentOpType = OpType.OP_READ;
                break; 
            case SelectionKey.OP_WRITE:
                currentOpType = OpType.OP_WRITE;
                break; 
            case (SelectionKey.OP_WRITE | SelectionKey.OP_READ):
                currentOpType = OpType.OP_READ_WRITE;
                break;  
             case (SelectionKey.OP_ACCEPT):
                currentOpType = OpType.OP_ACCEPT;
                break;       
            /**
             * Fallback to an upcoming OP_CONNECT ops. This happens
             * because the {@link SocketChannel#finishConnect()} has not yet
             * been invoked.
             * 
             */
            default:
                currentOpType = OpType.OP_CONNECT;
                break;
                
        } 
    }
    
        
    
    /**
     * Execute this Context using the Controller's Pipeline
     * @throws {@link PipelineFullException}
     * @deprecated
     */
    public void execute() throws PipelineFullException {
        // If a IOEvent has been defined, invoke it first and
        // let its associated CallbackHandler decide if the ProtocolChain
        // be invoked or not.
        Object attachment = SelectionKeyAttachment.getAttachment(key);
        if (ioEvent != null && (attachment instanceof CallbackHandler)) {
            CallbackHandlerContextTask task = CallbackHandlerContextTask.poll();
            task.setCallBackHandler((CallbackHandler) attachment);
            execute(task);
        } else {
            execute(ProtocolChainContextTask.poll());
        }
    }

    
    /**
     * Execute this Context using the Controller's Pipeline
     * @param contextTask {@link ContextTask}, which will be 
     *                    executed by {@link Pipeline}
     * @throws {@link PipelineFullException}
     */
    public void execute(ContextTask contextTask) throws PipelineFullException {
        execute(contextTask, true);
    }
    
    
    /**
     * Execute this Context using either Controller's Pipeline or current thread
     * @param contextTask {@link ContextTask}, which will be 
     *                    executed by {@link Pipeline}
     * @param runInSeparateThread if true - {@link ContextTask} will
     *      be executed in separate thread, false - in current thread.
     * @throws {@link PipelineFullException}
     */
    @SuppressWarnings("unchecked")
    public void execute(ContextTask contextTask, boolean runInSeparateThread) throws PipelineFullException {       
        if (protocolChain == null){
            ProtocolChainInstanceHandler 
                    pciHandler = getProtocolChainInstanceHandler();
            protocolChain = pciHandler.poll();
        }
        
        if (contextTask != null) {
            contextTask.setContext(this);
            if (runInSeparateThread) {
                getPipeline().execute(contextTask);
            } else {
                try {
                    contextTask.call();
                } catch(Exception e) {
                    Controller.logger().log(Level.SEVERE,
                            "Unexpected exception occured, when executing task: " + 
                            contextTask, e);
                }
            }
        }
    }


    /**
     * Return the {@link ProtocolChainInstanceListener} associated with this
     * {@link Context}
     * @return ProtocolChainInstanceListener
     */
    public ProtocolChainInstanceHandler getProtocolChainInstanceHandler() {
        ProtocolChainInstanceHandler protocolChainInstanceHandler =
               selectorHandler.getProtocolChainInstanceHandler();
        return protocolChainInstanceHandler != null ?
           protocolChainInstanceHandler :
           controller.getProtocolChainInstanceHandler();
    } 
    
    
    /**
     * Return the {@link Pipeline} executing this instance.
     * @return {@link Pipeline}
     */
    public Pipeline getPipeline() {
        if (pipeline == null && controller != null){
            pipeline = controller.getPipeline();
        }
        return pipeline;
    }
    
    
    /**
     * Set the {@link Pipeline} that will execute this instance.
     * @param pipeline  the {@link Pipeline} to set
     */
    public void setPipeline(Pipeline pipeline) {
        this.pipeline = pipeline;
    }
    
    
    /**
     * Set an optional CallbackHandler.
     * @param ioEvent  the {@link IOEvent} to set
     */
    protected void setIOEvent(IOEvent ioEvent){
        this.ioEvent = ioEvent;
    }
    
    /**
     * Return the current {@link IOEvent} associated with this
     * instance.
     * @return IOEvent the current {@link IOEvent} associated with this
     * instance.
     */
    protected IOEvent getIOEvent(){
        return ioEvent;
    }
    
    
    /**
     * Return the current {@link Controller#Protocol} this instance is executing.
     * @return the current Controller.Protocol this instance is executing.
     */
    public Controller.Protocol getProtocol() {
        return selectorHandler.protocol();
    }
    
    
    /**
     * @Deprecated
     *
     * Set the current {@link Controller#Protocol} this instance is executing.
     * @param protocol The current protocol.
     */
    public void setProtocol(Controller.Protocol protocol) {
    }
    
    
    /**
     * Return the current {@link SelectorHandler} this instance is executing.
     * @return the current {@link SelectorHandler} this instance is executing.
     */
    public SelectorHandler getSelectorHandler() {
        return selectorHandler;
    }
    
    /**
     * Set the current {@link SelectorHandler} this instance is executing.
     * @param selectorHandler {@link SelectorHandler}
     */
    public void setSelectorHandler(SelectorHandler selectorHandler) {
        this.selectorHandler = selectorHandler;
    }


    /**
     * Returns {@link AsyncQueueReadable}, assciated with the current
     * {@link Context}. This method is not threadsafe.
     * 
     * @return {@link AsyncQueueReadable}
     */
    public AsyncQueueReadable getAsyncQueueReadable() {
        if (asyncQueueReadable == null) {
            asyncQueueReadable = new AsyncQueueReadableContextWrapper();
        }
        
        return asyncQueueReadable;
    }

    /**
     * Returns {@link AsyncQueueWritable}, assciated with the current
     * {@link Context}. This method is not threadsafe.
     * 
     * @return {@link AsyncQueueWritable}
     */
    public AsyncQueueWritable getAsyncQueueWritable() {
        if (asyncQueueWritable == null) {
            asyncQueueWritable = new AsyncQueueWritableContextWrapper();
        }
        
        return asyncQueueWritable;
    }

    /**
     * Return the {@linkAsyncQueueReader}
     * @return the {@linkAsyncQueueReader}
     */
    protected AsyncQueueReader getAsyncQueueReader() {
        return asyncQueueReader;
    }

    /**
     * Set the {@linkAsyncQueueReader}
     * @param asyncQueueReader {@linkAsyncQueueReader}
     */
    protected void setAsyncQueueReader(AsyncQueueReader asyncQueueReader) {
        this.asyncQueueReader = asyncQueueReader;
    }

    /**
     * Return the {@linkAsyncQueueWriter}
     * @return the {@linkAsyncQueueWriter}
     */
    protected AsyncQueueWriter getAsyncQueueWriter() {
        return asyncQueueWriter;
    }

    /**
     * Set the {@linkAsyncQueueWriter}
     * @param asyncQueueWriter {@linkAsyncQueueWriter}
     */
    protected void setAsyncQueueWriter(AsyncQueueWriter asyncQueueWriter) {
        this.asyncQueueWriter = asyncQueueWriter;
    }
    
    private class AsyncQueueWritableContextWrapper implements AsyncQueueWritable {
        /**
        * {@inheritDoc}
        */
        public void writeToAsyncQueue(ByteBuffer buffer) throws IOException {
            asyncQueueWriter.write(key, buffer);
        }

        /**
         * {@inheritDoc}
         */
        public void writeToAsyncQueue(ByteBuffer buffer, 
                AsyncWriteCallbackHandler callbackHandler) throws IOException {
            asyncQueueWriter.write(key, buffer, callbackHandler);
        }

        /**
         * {@inheritDoc}
         */
        public void writeToAsyncQueue(ByteBuffer buffer, 
                AsyncWriteCallbackHandler callbackHandler,
                AsyncQueueDataProcessor writePreProcessor) throws IOException {
            asyncQueueWriter.write(key, buffer, callbackHandler, writePreProcessor);
        }

        /**
         * {@inheritDoc}
         */
        public void writeToAsyncQueue(ByteBuffer buffer,
                AsyncWriteCallbackHandler callbackHandler,
                AsyncQueueDataProcessor writePreProcessor,
                boolean isCloneByteBuffer) throws IOException {
            asyncQueueWriter.write(key, buffer, callbackHandler,
                    writePreProcessor, isCloneByteBuffer);
        }
        
        /**
        * {@inheritDoc}
        */
        public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer)
                throws IOException {
            asyncQueueWriter.write(key, dstAddress, buffer);
        }

        /**
        * {@inheritDoc}
        */
        public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
                AsyncWriteCallbackHandler callbackHandler) throws IOException {
            asyncQueueWriter.write(key, dstAddress, buffer, 
                    callbackHandler);
        }

        /**
        * {@inheritDoc}
        */
        public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
                AsyncWriteCallbackHandler callbackHandler, 
                AsyncQueueDataProcessor writePreProcessor) throws IOException {
            asyncQueueWriter.write(key, dstAddress, buffer, 
                    callbackHandler, writePreProcessor);
        }

        /**
        * {@inheritDoc}
        */
        public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
                AsyncWriteCallbackHandler callbackHandler, 
                AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer)
                throws IOException {
            asyncQueueWriter.write(key, dstAddress, buffer, 
                    callbackHandler, writePreProcessor, isCloneByteBuffer);
        }
    }
    
    private class AsyncQueueReadableContextWrapper implements AsyncQueueReadable {
        /**
        * {@inheritDoc}
        */
        public void readFromAsyncQueue(ByteBuffer buffer, 
                AsyncReadCallbackHandler callbackHandler) throws IOException {
            asyncQueueReader.read(key, buffer, callbackHandler);
        }

        /**
        * {@inheritDoc}
        */
        public void readFromAsyncQueue(ByteBuffer buffer, 
                AsyncReadCallbackHandler callbackHandler, 
                AsyncReadCondition condition) throws IOException {
            asyncQueueReader.read(key, buffer, callbackHandler, condition);
        }

        /**
        * {@inheritDoc}
        */
        public void readFromAsyncQueue(ByteBuffer buffer, 
                AsyncReadCallbackHandler callbackHandler, 
                AsyncReadCondition condition, 
                AsyncQueueDataProcessor readPostProcessor) throws IOException {
            asyncQueueReader.read(key, buffer, callbackHandler, 
                    condition, readPostProcessor);
        }
    }
    
    
    /**
     * Suspend the execution of this {@link Context}. Suspending the execution
     * allow application to store the current instance, and re-use it later
     * by not only the  Thread used when called suspend, but also from any other Thread.
     * A suspended Context will not be re-used by any other transaction and Thread. 
     * A suspended Context will keep its current state intact, meaning its
     * SelectionKey, attributes, SelectorHandler, etc, will not change. Internally,
     * The Context will not be recyled and will not be re-used by any Thread.
     * 
     * When invoked this method will automatically set the 
     * {@link Context#setKeyRegistrationState} to {@link KeyRegistrationState}
     * to KeyRegistrationState.NONE.
     * 
     * Invoking this method many times as not effect once suspended. 
     */
    public void suspend(){
        if (isSuspended) return;
        isSuspended = true;
        incrementRefCount();
        setKeyRegistrationState(keyRegistrationState.NONE);               
    }
    
    
    /**
     * Return true if this Context has been suspended by
     * invoking {@link suspend}. When suspended, invoking {@link Context#recycle}
     * will throw an {@link IllegalStateException}
     * @return true if this Context has been suspended
     */
    public boolean isSuspended(){
        return isSuspended;
    }
    
    
    /**
     * Resume a {@link #suspend}ed {@link Context}. 
     *  Resume will not call {@link Context#recycle}. So
     * after the caller is finished using Context caller must
     * call {@link  Controller#returnContext(com.sun.grizzly.Context)}
     * to  mark it as a candidate  for being re-used by another Thread and connection.
     * 
     * Important. When resumed, all operations done on this
     * object are not thread-safe and there is probability that another
     * thread is already using this object. Never use this object once resumed.
     * 
     * When invoked this method will automatically set the 
     * {@link Context#setKeyRegistrationState} to {@link KeyRegistrationState}
     * to KeyRegistrationState.REGISTER and automatically re-enable read and 
     * write operations. 
     * 
     * If the Context hasn't been suspended, calling that method has no effet.
     */
    public void resume(){
        if (!isSuspended) return;
        isSuspended = false;
        selectorHandler.register(key, SelectionKey.OP_READ);
    }
    
    
    /**
     * Cancel a {@link #suspend}ed {@link Context}. Invoking this method will
     * automatically clean the state of this Context and mark it as a candidate
     * for being re-used by another Thread and connection. 
     * 
     * Important. When cancelled, all operations done on this
     * object are not thread-safe and there is probability that another
     * thread is already using this object. Never use this object once cancelled.
     * 
     * 
     * When invoked this method will automatically close the underlying 
     * connection (represented by its {@link SelectionKey}.
     * 
     * If the Context hasn't been suspended, calling that method has no effet.
     */
    public void cancel(){
        if (!isSuspended) return;
        isSuspended = false;
        selectorHandler.getSelectionKeyHandler().cancel(key);
        getController().returnContext(this);
    }   
    /**
     * Called by outer Threads that are not instances of {@link WorkerThread} to
     * indicate that this {@link Context} should not be
     * {@link #recycle()} or offered back to its pool.
     * 
     * When a outer Thread is done with {@link Context} it must call
     * {@link Controller#returnContext(com.sun.grizzly.Context) to
     * ensure that {@link Context} will be properly recycled.
     * 
     * @return Current Thread reference count
     */
    public void incrementRefCount(){
         refCounter.incrementAndGet();
    } 
    
    /**
     * Decrements the reference count of this {@link Context}.
     * Threads wanting to release {@link Context} should not call
     * this method but instead use 
     * {@link Controller#returnContext(com.sun.grizzly.Context)}
     * @return return decremented reference count
     */
    public int  decrementRefCount(){
        return  refCounter.decrementAndGet();
}
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy