# This patch file was generated by NetBeans IDE
# Following Index: paths are relative to: C:\Projects\Grizzly\trunk\modules\grizzly\src\main\java\com\sun\grizzly
# This patch can be applied using context Tools: Patch action on respective folder.
# It uses platform neutral UTF-8 encoding and \n newlines.
# Above lines and this line are ignored by the patching process.
Index: Controller.java
--- Controller.java Base (BASE)
+++ Controller.java Locally Modified (Based On LOCAL)
@@ -26,6 +26,9 @@
 import com.sun.grizzly.util.AttributeHolder;
 import com.sun.grizzly.util.Cloner;
 import com.sun.grizzly.util.Copyable;
+import com.sun.grizzly.util.State;
+import com.sun.grizzly.util.StateHolder;
+import com.sun.grizzly.util.SupportStateHolder;
 import java.io.IOException;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.ClosedSelectorException;
@@ -40,7 +43,6 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.ReentrantLock;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -125,7 +127,7 @@
  * @author Jeanfrancois Arcand
  */
 public class Controller implements Runnable, Lifecycle, Copyable, 
-        ConnectorHandlerPool, AttributeHolder {
+        ConnectorHandlerPool, AttributeHolder, SupportStateHolder<State> {
     
     public enum Protocol { UDP, TCP , TLS, CUSTOM }
     
@@ -173,27 +175,12 @@
     
     
     /**
-     * Controller state enum
-     * STOPPED - Controller is in a stopped, not running state
-     * STARTED - Controller is in a started, running state
-     *
+     * Current <code>Controller</code> state
      */
-    protected enum State { STOPPED, STARTED }
+    protected StateHolder<State> stateHolder;
     
     
     /**
-     * Current Controller state
-     */
-    protected volatile State state;
-    
-    
-    /**
-     * State lock to have consistent state value
-     */
-    protected ReentrantLock stateLock;
-    
-    
-    /**
      * The number of read threads
      */
     protected int readThreadsCount = 0;
@@ -253,7 +240,7 @@
      */
     public Controller() {
         contexts = new ConcurrentLinkedQueue<Context>();
-        stateLock = new ReentrantLock();
+        stateHolder = new StateHolder<State>(true);
     }
     
     
@@ -301,7 +288,9 @@
             readyKeys = selectorHandler.select(serverCtx);
             selectorState = readyKeys.size();
             
-            if (state == State.STARTED && selectorState != 0) {
+            if (stateHolder.getState(false) == State.STARTED && 
+                    selectorHandler.getStateHolder().getState(false) == State.STARTED &&
+                    selectorState != 0) {
                 iterator = readyKeys.iterator();
                 while (iterator.hasNext()) {
                     key = iterator.next();
@@ -398,20 +387,17 @@
             //       shutting down. Hence, we need to handle this Exception
             //       appropriately. Perhaps check the state before logging
             //       what's happening ?
-            stateLock.lock();
-            try {
-                if (state != State.STOPPED) {
+            if (stateHolder.getState() == State.STARTED &&
+                    selectorHandler.getStateHolder().getState() == State.STARTED) {
                     logger.log(Level.SEVERE, "Selector was unexpectedly closed.");
                     notifyException(e);
                 } else {
                     logger.log(Level.FINE, "doSelect Selector closed");
                 }
-            } finally {
-                stateLock.unlock();
-            }
         } catch (ClosedChannelException e) {
             // Don't use stateLock. This case is not strict
-            if (state != State.STOPPED) {
+            if (stateHolder.getState() == State.STARTED &&
+                    selectorHandler.getStateHolder().getState() == State.STARTED) {
                 logger.log(Level.WARNING, "Channel was unexpectedly closed");
                 if (key != null){
                     selectorHandler.getSelectionKeyHandler().cancel(key);
@@ -457,7 +443,7 @@
      * @param protocol specified protocol SelectorHandler key should be registered on
      */
     public void registerKey(SelectionKey key, int ops, Protocol protocol){
-        if (state == State.STOPPED) {
+        if (stateHolder.getState() == State.STOPPED) {
             return;
         }
         
@@ -471,7 +457,7 @@
      * @deprecated
      */
     public void cancelKey(SelectionKey key){
-        if (state == State.STOPPED) {
+        if (stateHolder.getState() == State.STOPPED) {
             return;
         }
         
@@ -587,7 +573,17 @@
             selectorHandlers = new ConcurrentLinkedQueue<SelectorHandler>();
         }
         selectorHandlers.add(selectorHandler);
+        if (stateHolder.getState(false) != null && 
+                !State.STOPPED.equals(stateHolder.getState())) {
+            addSelectorHandlerOnReadControllers(selectorHandler);
+            if (readySelectorHandlerCounter != null && 
+                    stoppedSelectorHandlerCounter != null) {
+                readySelectorHandlerCounter.incrementAndGet();
+                stoppedSelectorHandlerCounter.incrementAndGet();
     }
+            startSelectorHandlerRunner(selectorHandler, true);
+        }
+    }
     
     
     /**
@@ -639,6 +635,25 @@
     
     
     /**
+     * Shuts down <code>SelectorHandler</code> and removes it from this 
+     * <code>Controller</code> list
+     * @param <code>SelectorHandler</code> to remove
+     */
+    public void removeSelectorHandler(SelectorHandler selectorHandler) {
+        if (selectorHandlers.remove(selectorHandler)) {
+            if (stateHolder.getState(false) != null &&
+                    !State.STOPPED.equals(stateHolder.getState())) {
+                readySelectorHandlerCounter.decrementAndGet();
+                stoppedSelectorHandlerCounter.decrementAndGet();
+            }
+            
+            removeSelectorHandlerOnReadControllers(selectorHandler);
+            selectorHandler.shutdown();
+        }
+    }
+    
+    
+    /**
      * Return the <code>Pipeline</code> (Thread Pool) used by this Controller.
      */
     public Pipeline getPipeline() {
@@ -715,8 +730,7 @@
         copyController.readThreadControllers = readThreadControllers;
         copyController.readThreadsCount = readThreadsCount;
         copyController.selectionKeyHandler = selectionKeyHandler;
-        copyController.stateLock = stateLock;
-        copyController.state = state;
+        copyController.stateHolder = stateHolder;
     }
     
     // -------------------------------------------------------- Lifecycle ----//
@@ -813,12 +827,7 @@
         pipeline.initPipeline();
         pipeline.startPipeline();
                 
-        stateLock.lock();
-        try {
-            state = State.STARTED;
-        } finally {
-            stateLock.unlock();
-        }
+        stateHolder.setState(State.STARTED);
         notifyStarted();
 
         if (readThreadsCount > 0) {
@@ -832,15 +841,8 @@
         stoppedSelectorHandlerCounter = new AtomicInteger(selectorHandlerCount);
         
         for (SelectorHandler selectorHandler : selectorHandlers) {
-            Runnable selectorRunner = new SelectorHandlerRunner(this, selectorHandler);
-            if(selectorHandlerCount > 1) {
-                // if there are more than 1 selector handler - run it in separate thread
-                new Thread(selectorRunner).start();
-            } else {
-                // else run it in current thread
-                selectorRunner.run();
+            startSelectorHandlerRunner(selectorHandler, selectorHandlerCount > 1);
             }
-        }
         
         waitUntilSeletorHandlersStop();
         selectorHandlers.clear();
@@ -853,10 +855,10 @@
      * Stop the Controller by canceling all the registered keys.
      */
     public void stop() throws IOException {
-        stateLock.lock();
+        stateHolder.getStateLocker().writeLock().lock();
         try {
-            if (state != State.STOPPED) {
-                state = State.STOPPED;
+            if (stateHolder.getState(false) != State.STOPPED) {
+                stateHolder.setState(State.STOPPED, false);
                 // TODO: Consider moving the for Controller loop below to
                 //       the end of the start() method and using a
                 //       wait() / notify() construct to shutdown this
@@ -883,29 +885,38 @@
                 logger.log(Level.FINE, "Controller is already in stopped state");
             }
         } finally {
-            stateLock.unlock();
+            stateHolder.getStateLocker().writeLock().unlock();
         }
         
     }
     
     
     /**
-     * Not implemented.
+     * Pause this <code>Controller</code> and associated <code>SelectorHandler</code>s
      */
     public void pause() throws IOException {
-        ; // Not yet implemented
+        stateHolder.setState(State.PAUSED);
     }
     
     
     /**
-     * Not implemented.
+     * Resume this <code>Controller</code> and associated <code>SelectorHandler</code>s
      */    
     public void resume() throws IOException {
-        ; // Not yet implemented
+        stateHolder.setState(State.STARTED);
     }
     
     
     /**
+     * Gets this <code>Controller</code>'s <code>StateHolder</code>
+     * @return <code>StateHolder</code>
+     */
+    public StateHolder<State> getStateHolder() {
+        return stateHolder;
+    }
+
+    
+    /**
      * Initialize the number of ReadThreadController.
      */
     private void initReadThreads() throws IOException {
@@ -918,40 +929,80 @@
         for(int i=0; i<readThreadsCount; i++) {
             ReadController controller = new ReadController();
             copyTo(controller);
-            for (SelectorHandler selectorHandler: selectorHandlers){
+            controller.setReadThreadsCount(0);
+            readThreadControllers[i] = controller;
+        }
+        
+        for (SelectorHandler selectorHandler : selectorHandlers) {
+            addSelectorHandlerOnReadControllers(selectorHandler);
+        }
+        
+        for (Controller readController : readThreadControllers) {
+            // TODO Get a Thread from a Pool instead.
+            new Thread(readController).start();
+        }
+    }
+    
+    
+    /**
+     * Register <code>SelectorHandler</code> on all read controllers
+     * @param selectorHandler
+     */
+    private void addSelectorHandlerOnReadControllers(SelectorHandler selectorHandler) {
+        if (readThreadControllers == null || readThreadsCount == 0) return;
+        
                 // Attributes need to be shared among SelectorHandler and its read-copies
                 if (selectorHandler.getAttributes() == null) {
                     selectorHandler.setAttributes(new HashMap<String, Object>(2));
                 }
                 
+        for (Controller readController : readThreadControllers) {
                 SelectorHandler copySelectorHandler = Cloner.clone(selectorHandler);
                 copySelectorHandler.setSelector(null);
-                controller.addSelectorHandler(copySelectorHandler);
+            readController.addSelectorHandler(copySelectorHandler);
             }
-            controller.setReadThreadsCount(0);
-            readThreadControllers[i] = controller;
-            // TODO Get a Thread from a Pool instead.
-            new Thread(controller).start();
         }
+    
+    
+    /**
+     * Starts <code>SelectorHandlerRunner</code>
+     * @param selectorHandler
+     * @param isRunAsync if true - <code>SelectorHandlerRunner</code> will be run
+     *          in separate <code>Thread</code>, if false - in current <code>Thread</code>
+     */
+    private void startSelectorHandlerRunner(SelectorHandler selectorHandler, 
+            boolean isRunAsync) {
+            Runnable selectorRunner = new SelectorHandlerRunner(this, selectorHandler);
+            if(isRunAsync) {
+                // if there are more than 1 selector handler - run it in separate thread
+                new Thread(selectorRunner).start();
+            } else {
+                // else run it in current thread
+                selectorRunner.run();
     }
+    }
     
     
     /**
+     * Register <code>SelectorHandler</code> on all read controllers
+     * @param selectorHandler
+     */
+    private void removeSelectorHandlerOnReadControllers(SelectorHandler selectorHandler) {
+        if (readThreadControllers == null) return;
+        
+        for (ReadController readController : readThreadControllers) {
+            readController.removeSelectorHandlerClone(selectorHandler);
+        }
+    }
+
+    
+    /**
      * Is this Controller started?
      * @return <code>boolean</code> true / false
      */
     public boolean isStarted() {
-        boolean result = false;
-        if (stateLock != null){
-            stateLock.lock();
-            try {
-                result = (state == State.STARTED);
-            } finally {
-                stateLock.unlock();
+        return stateHolder.getState() == State.STARTED;
             }
-        }
-        return result;
-    }
     
     
     // ----------- ConnectorHandlerPool interface implementation ----------- //  
Index: ReadController.java
--- ReadController.java Base (BASE)
+++ ReadController.java Locally Modified (Based On LOCAL)
@@ -27,6 +27,7 @@
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
+import java.util.Iterator;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 
@@ -42,6 +43,23 @@
 public class ReadController extends Controller {
 
     /**
+     * Removes <code>SelectorHandler</code>'s clone, registered 
+     * on this <code>Controller</code>
+     * 
+     * @param selectorHandler
+     */
+    public void removeSelectorHandlerClone(SelectorHandler selectorHandler) {
+        Iterator<SelectorHandler> it = selectorHandlers.iterator();
+        while(it.hasNext()) {
+            SelectorHandler cloneSelectorHandler = it.next();
+            if (cloneSelectorHandler.getStateHolder() == selectorHandler.getStateHolder()) {
+                removeSelectorHandler(cloneSelectorHandler);
+                return;
+            }
+        }
+    }
+    
+    /**
      * Add a <code>Channel</code>
      * to be processed by <code>ReadController</code>'s
      * <code>SelectorHandler</code>
@@ -78,15 +96,6 @@
      */
     @Override
     public void start() throws IOException {
-        stateLock.lock();
-        try {
-            // could be null if ReadController will be used outside main Controller
-            if (state == null) {
-                state = State.STARTED;
-            }
-        } finally {
-            stateLock.unlock();
-        }
         notifyStarted();
 
         int selectorHandlerCount = selectorHandlers.size();
Index: SelectorHandler.java
--- SelectorHandler.java Base (BASE)
+++ SelectorHandler.java Locally Modified (Based On LOCAL)
@@ -26,6 +26,8 @@
 import com.sun.grizzly.async.AsyncQueueWriter;
 import com.sun.grizzly.util.AttributeHolder;
 import com.sun.grizzly.util.Copyable;
+import com.sun.grizzly.util.State;
+import com.sun.grizzly.util.SupportStateHolder;
 import java.io.IOException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
@@ -40,7 +42,8 @@
  *
  * @author Jeanfrancois Arcand
  */
-public interface SelectorHandler extends Handler, Copyable, AttributeHolder {   
+public interface SelectorHandler extends Handler, Copyable, 
+        AttributeHolder, SupportStateHolder<State> {   
     
     /**
      * A token decribing the protocol supported by an implementation of this
@@ -79,6 +82,18 @@
     
     
     /**
+     * Pause this <code>SelectorHandler</code>
+     */
+    public void pause();
+    
+    
+    /**
+     * Resume this <code>SelectorHandler</code>
+     */
+    public void resume();
+    
+    
+    /**
      * Shutdown this instance.
      */
     public void shutdown();
Index: SelectorHandlerRunner.java
--- SelectorHandlerRunner.java Base (BASE)
+++ SelectorHandlerRunner.java Locally Modified (Based On LOCAL)
@@ -23,8 +23,11 @@
 
 package com.sun.grizzly;
 
-import java.nio.channels.SelectionKey;
-import com.sun.grizzly.Controller.State;
+import com.sun.grizzly.util.State;
+import com.sun.grizzly.util.StateHolder;
+import com.sun.grizzly.util.StateHolder.ConditionListener;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Class is responsible for processing certain (single)
@@ -48,25 +51,65 @@
     
     public void run() {
         boolean firstTimeSelect = true;
+        StateHolder<State> controllerStateHolder = controller.stateHolder;
+        StateHolder<State> selectorHandlerStateHolder = selectorHandler.getStateHolder();
+        
         try {
-            while (controller.state == State.STARTED) {
+            selectorHandler.getStateHolder().setState(State.STARTED);
+            
+            while (controllerStateHolder.getState(false) != State.STOPPED &&
+                    selectorHandlerStateHolder.getState(false) != State.STOPPED) {
+                
+                State controllerState = controllerStateHolder.getState(false);
+                State selectorHandlerState = selectorHandlerStateHolder.getState(false);
+                
+                if (controllerState != State.PAUSED &&
+                        selectorHandlerState != State.PAUSED) {
                 controller.doSelect(selectorHandler);
 
                 if (firstTimeSelect) {
                     firstTimeSelect = false;
                     controller.notifyReady();
                 }
-            }
+                } else {
+                    CountDownLatch latch = new CountDownLatch(1);
+                    ConditionListener<State> controllerConditionListener = 
+                            registerForNotification(controllerState, 
+                            controllerStateHolder, latch);
+                    ConditionListener<State> selectorHandlerConditionListener = 
+                            registerForNotification(selectorHandlerState, 
+                            selectorHandlerStateHolder, latch);
 
-            SelectionKeyHandler selectionKeyHandler = selectorHandler.getSelectionKeyHandler();
-
-            for (SelectionKey selectionKey : selectorHandler.keys()) {
-                selectionKeyHandler.close(selectionKey);
+                    try {
+                        latch.await(5000, TimeUnit.MILLISECONDS);
+                    } catch(InterruptedException e) {
+                    } finally {
+                        controllerStateHolder.removeConditionListener(controllerConditionListener);
+                        selectorHandlerStateHolder.removeConditionListener(selectorHandlerConditionListener);
             }
-
-            selectorHandler.shutdown();
+                }
+            }
         } finally {
+            selectorHandler.shutdown();
             controller.notifyStopped();
         }
     }
+    
+    /**
+     * Register <code>CountDownLatch</code> to be notified, when either Controller
+     * or SelectorHandler will change their state to correspondent values
+     * @param currentState initial/current <code>StateHolder</code> state
+     * @param stateHolder
+     * @param latch
+     * @return <code>ConditionListener</code> if listener is registered, null if
+     *        condition is true right now
+     */
+    private ConditionListener<State> registerForNotification(State currentState, 
+            StateHolder<State> stateHolder, CountDownLatch latch) {
+        if (currentState == State.PAUSED) {
+            return stateHolder.notifyWhenStateIsNotEqual(State.PAUSED, latch);
+        } else {
+            return stateHolder.notifyWhenStateIsEqual(State.STOPPED, latch);
 }
+    }
+}
\ No newline at end of file
Index: TCPSelectorHandler.java
--- TCPSelectorHandler.java Base (BASE)
+++ TCPSelectorHandler.java Locally Modified (Based On LOCAL)
@@ -33,6 +33,8 @@
 import com.sun.grizzly.util.Copyable;
 import com.sun.grizzly.util.SelectionKeyOP;
 import com.sun.grizzly.util.SelectionKeyOP.ConnectSelectionKeyOP;
+import com.sun.grizzly.util.State;
+import com.sun.grizzly.util.StateHolder;
 import java.io.IOException;
 import java.net.BindException;
 import java.net.InetAddress;
@@ -42,6 +44,7 @@
 import java.net.SocketAddress;
 import java.net.SocketException;
 import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ClosedSelectorException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
@@ -204,7 +207,10 @@
      */
     protected Map<String, Object> attributes;
 
+    protected StateHolder<State> stateHolder = new StateHolder<State>(true);
+
     public TCPSelectorHandler(){
+        this(false);
     }
     
     
@@ -232,6 +238,7 @@
         copyHandler.logger = logger;
         copyHandler.reuseAddress = reuseAddress;
         copyHandler.connectorInstanceHandler = connectorInstanceHandler;
+        copyHandler.stateHolder = stateHolder;
     }
     
     
@@ -463,16 +470,42 @@
         selector.wakeup();
     }
     
+    /**
+     * {@inheritDoc}
+     */
+    public void pause() {
+        stateHolder.setState(State.PAUSED);
+    }
     
     /**
+     * {@inheritDoc}
+     */
+    public void resume() {
+        stateHolder.setState(State.STARTED);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public StateHolder<State> getStateHolder() {
+        return stateHolder;
+    }
+
+    /**
      * Shuntdown this instance by closing its Selector and associated channels.
      */
     public void shutdown() {
-        if (selector != null){
+        stateHolder.setState(State.STOPPED);
+        
+        if (selector != null) {
+            try {
             for (SelectionKey selectionKey : selector.keys()) {                
                 selectionKeyHandler.close(selectionKey);
             } 
+            } catch (ClosedSelectorException e) {
+                // If Selector is already closed - OK
         }
+        }
         
         try{
             if (serverSocket != null)
Index: util/State.java
--- util/State.java Locally New
+++ util/State.java Locally New
@@ -0,0 +1,36 @@
+/*
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (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/CDDLv1.0.html or
+ * glassfish/bootstrap/legal/CDDLv1.0.txt.
+ * See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * Header Notice in each file and include the License file
+ * at glassfish/bootstrap/legal/CDDLv1.0.txt.
+ * If applicable, add the following below the CDDL Header,
+ * with the fields enclosed by brackets [] replaced by
+ * you own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ */
+
+package com.sun.grizzly.util;
+
+/**
+ * State enum
+ * STOPPED - Process is stopped, not running state
+ * STARTED - Process is started, running state
+ * PAUSED - Process is paused, not processing tasks
+ * 
+ * @author Alexey Stashok
+ */
+public enum State {
+    STOPPED, STARTED, PAUSED
+}
Index: util/StateHolder.java
--- util/StateHolder.java Locally New
+++ util/StateHolder.java Locally New
@@ -0,0 +1,354 @@
+/*
+ * The contents of this file are subject to the terms 
+ * of the Common Development and Distribution License 
+ * (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/CDDLv1.0.html or
+ * glassfish/bootstrap/legal/CDDLv1.0.txt.
+ * See the License for the specific language governing 
+ * permissions and limitations under the License.
+ * 
+ * When distributing Covered Code, include this CDDL 
+ * Header Notice in each file and include the License file 
+ * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
+ * If applicable, add the following below the CDDL Header, 
+ * with the fields enclosed by brackets [] replaced by
+ * you own identifying information: 
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * 
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ */
+
+package com.sun.grizzly.util;
+
+import com.sun.grizzly.Controller;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+
+/**
+ * Class, which holds the state.
+ * Provides API for state change notification, state read/write access locking.
+ * 
+ * @author Alexey Stashok
+ */
+public class StateHolder<E> {
+    private AtomicReference<E> stateRef;
+    
+    private ReentrantReadWriteLock readWriteLock;
+    private volatile boolean isLockEnabled;
+    
+    private Map<ConditionListener<E>, Object> conditionListeners;
+    
+    /**
+     * Constructs <code>StateHolder</code>.
+     * StateHolder will work in not-locking mode.
+     */
+    public StateHolder() {
+        this(false);
+    }
+    
+    /**
+     * Constructs <code>StateHolder</code>.
+     * @param isLockEnabled locking mode
+     */
+    public StateHolder(boolean isLockEnabled) {
+        stateRef = new AtomicReference<E>();
+        readWriteLock = new ReentrantReadWriteLock();
+        conditionListeners = new ConcurrentHashMap<ConditionListener<E>, Object>();
+        this.isLockEnabled = isLockEnabled;
+    }
+
+    /**
+     * Gets current state
+     * Current StateHolder locking mode will be used
+     * @return state
+     */
+    public E getState() {
+        return getState(isLockEnabled);
+    }
+    
+    /**
+     * Gets current state
+     * @param locked if true, get will be invoked in locking mode, false - non-locked
+     * @return state
+     */
+    public E getState(boolean locked) {
+        if (locked) {
+            readWriteLock.readLock().lock();
+        }
+        
+        E retState = stateRef.get();
+        
+        if (locked) {
+            readWriteLock.readLock().unlock();
+        }
+        return retState;
+    }
+
+    /**
+     * Sets current state
+     * Current StateHolder locking mode will be used
+     * @param state
+     */
+    public void setState(E state) {
+        setState(state, isLockEnabled);
+    }
+    
+    /**
+     * Sets current state
+     * @param state
+     * @param locked if true, set will be invoked in locking mode, false - non-locking
+     */
+    public void setState(E state, boolean locked) {
+        if (locked) {
+            readWriteLock.writeLock().lock();
+        }
+        
+        stateRef.set(state);
+        
+        // downgrading lock to read
+        if (locked) {
+            readWriteLock.readLock().lock();
+            readWriteLock.writeLock().unlock();
+        }
+        
+        checkConditionListeners(state);
+
+        if (locked) {
+            readWriteLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Gets Read/Write locker, which is used by this <code>StateHolder</code>
+     * @return locker
+     */
+    public ReentrantReadWriteLock getStateLocker() {
+        return readWriteLock;
+    }
+    
+    /**
+     * Gets current locking mode
+     * @return true, if mode is set to locking, false otherwise
+     */
+    public boolean isLockEnabled() {
+        return isLockEnabled;
+    }
+    
+    /**
+     * Setss current locking mode
+     * @param isLockEnabled true, if mode will be set to locking, false otherwise
+     */
+    public void setLockEnabled(boolean isLockEnabled) {
+        this.isLockEnabled = isLockEnabled;
+    }
+    
+    /**
+     * Register listener, which will be notified, when state will be equal to passed
+     * one. Once listener will be notified - it will be removed from this 
+     * <code>StateHolder</code>'s listener set.
+     * @param state State, listener is interested in
+     * @param listener Object, which will be notified. This <code>StateHolder</code>
+     *          implementation works with Runnable, Callable, CountDownLatch, Object
+     *          listeners
+     * @return <code>ConditionListener</code>, if current state is not equal to required 
+     *          and listener was registered, null if current state is equal to required.
+     *          In both cases listener will be notified
+     */
+    public ConditionListener<E> notifyWhenStateIsEqual(E state, Object listener) {
+        boolean isLockEnabledLocal = isLockEnabled;
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().lock();
+        }
+        
+        ConditionListener<E> conditionListener = null;
+
+        if (stateRef.get().equals(state)) {
+            EventListener.notifyListener(listener);
+        } else {
+            conditionListener = new EqualConditionListener<E>();
+            EventListener eventListener = new EventListener();
+            eventListener.set(listener);
+            conditionListener.set(state, eventListener);
+            
+            conditionListeners.put(conditionListener, this);
+        }
+        
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().unlock();
+        }
+        
+        return conditionListener;
+    }
+    
+    /**
+     * Register listener, which will be notified, when state will become not equal 
+     * to passed one. Once listener will be notified - it will be removed from
+     * this <code>StateHolder</code>'s listener set.
+     * @param state State, listener is interested in
+     * @param listener Object, which will be notified. This <code>StateHolder</code>
+     *          implementation works with Runnable, Callable, CountDownLatch, Object
+     *          listeners
+     * @return <code>ConditionListener</code>, if current state is equal to required 
+     *          and listener was registered, null if current state is not equal to required.
+     *          In both cases listener will be notified
+     */
+    public ConditionListener<E> notifyWhenStateIsNotEqual(E state, Object listener) {
+        boolean isLockEnabledLocal = isLockEnabled;
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().lock();
+        }
+        
+        ConditionListener<E> conditionListener = null;
+        
+        if (!stateRef.get().equals(state)) {
+            EventListener.notifyListener(listener);
+        } else {
+            conditionListener = new NotEqualConditionListener<E>();
+            EventListener eventListener = new EventListener();
+            eventListener.set(listener);
+            conditionListener.set(state, eventListener);
+            
+            conditionListeners.put(conditionListener, this);
+        }
+        
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().unlock();
+        }
+        
+        return conditionListener;
+    }
+    
+    /**
+     * Register custom condition listener, which will be notified, when listener's
+     * condition will become true. Once listener will be notified - it will be 
+     * removed from this <code>StateHolder</code>'s listener set.
+     * @param conditionListener contains both condition and listener, which will be
+     *          called, when condition become true
+     */
+    public void notifyWhenConditionMatchState(ConditionListener<E> conditionListener) {
+        boolean isLockEnabledLocal = isLockEnabled;
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().lock();
+        }
+        
+        E currentState = getState();
+
+        if (conditionListener.check(currentState)) {
+            conditionListener.notifyListener();
+        } else {
+            conditionListeners.put(conditionListener, this);
+        }
+        
+        if (isLockEnabledLocal) {
+            getStateLocker().writeLock().unlock();
+        }
+    }
+    
+    public void removeConditionListener(ConditionListener<E> conditionListener) {
+        if (conditionListener == null) return;
+        
+        conditionListeners.remove(conditionListener);
+    }
+    
+    protected void checkConditionListeners(E state) {
+        Iterator<ConditionListener<E>> it = conditionListeners.keySet().iterator();
+        while(it.hasNext()) {
+            ConditionListener<E> listener = it.next();
+            try {
+                if (listener.check(state)) {
+                    it.remove();
+                    listener.notifyListener();
+                }
+            } catch(Exception e) {
+                Controller.logger().log(Level.WARNING, "Error calling ConditionListener", e);
+            }
+        }
+    }
+    
+    /**
+     * Common ConditionListener class, which could be used with StateHolder, to
+     * register custom conditions.
+     * 
+     * On each state change - condition will be checked, if it's true - Condition's
+     * listener will be notified.
+     */
+    public static abstract class ConditionListener<E> {
+        public E state;
+        public EventListener listener;
+        
+        protected void set(E state, EventListener listener) {
+            this.state = state;
+            this.listener = listener;
+        }
+        
+        public void notifyListener() {
+            listener.notifyEvent();
+        }
+        
+        public abstract boolean check(E state);
+    }
+    
+    /**
+     * Equal ConditionListener implementation
+     * @param E state class
+     */
+    public static class EqualConditionListener<E> extends ConditionListener<E> {
+        public boolean check(E state) {
+            return state.equals(this.state);
+        }
+    }
+
+    /**
+     * Not equal ConditionListener implementation
+     * @param E state class
+     */
+    public static class NotEqualConditionListener<E> extends ConditionListener<E> {
+        public boolean check(E state) {
+            return !state.equals(this.state);
+        }
+    }
+    
+    /**
+     * EventListener class, which is a part of 
+     * <codE>EventConditionListener</code>, and implements notificatation logic,
+     * when condition becomes true.
+     */
+    public static class EventListener {
+        public Object notificationObject;
+        
+        public void set(Object notificationObject) {
+            this.notificationObject = notificationObject;
+        }
+        
+        public void notifyEvent() {
+            notifyListener(notificationObject);
+        }
+        
+        protected static void notifyListener(Object listener) {
+            if (listener instanceof CountDownLatch) {
+                ((CountDownLatch) listener).countDown();
+            } else if (listener instanceof Callable) {
+                try {
+                    ((Callable) listener).call();
+                } catch(Exception e) {
+                    throw new RuntimeException(e);
+                }
+            } else if (listener instanceof Runnable) {
+                ((Runnable) listener).run();
+            } else {
+                synchronized(listener) {
+                    listener.notify();
+                }
+            }
+        }
+    }
+}
Index: util/SupportStateHolder.java
--- util/SupportStateHolder.java Locally New
+++ util/SupportStateHolder.java Locally New
@@ -0,0 +1,37 @@
+/*
+ * The contents of this file are subject to the terms 
+ * of the Common Development and Distribution License 
+ * (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/CDDLv1.0.html or
+ * glassfish/bootstrap/legal/CDDLv1.0.txt.
+ * See the License for the specific language governing 
+ * permissions and limitations under the License.
+ * 
+ * When distributing Covered Code, include this CDDL 
+ * Header Notice in each file and include the License file 
+ * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
+ * If applicable, add the following below the CDDL Header, 
+ * with the fields enclosed by brackets [] replaced by
+ * you own identifying information: 
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * 
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ */
+
+package com.sun.grizzly.util;
+
+/**
+ * Interface implementors support <code>StateHolder</code> for state control
+ * 
+ * @author Alexey Stashok
+ */
+public interface SupportStateHolder<E> {
+    /**
+     * Gets <code>StateHolder</code> for this object
+     * @return <code>StateHolder</code>
+     */
+    public StateHolder<E> getStateHolder();
+}