/* * ActionSet.java February 2013 * * Copyright (C) 2013, Niall Gallagher <niallg@users.sf.net> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package org.simpleframework.transport.reactor; import static java.nio.channels.SelectionKey.OP_ACCEPT; import static java.nio.channels.SelectionKey.OP_CONNECT; import static java.nio.channels.SelectionKey.OP_READ; import static java.nio.channels.SelectionKey.OP_WRITE; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; /** * The <code>ActionSet</code> object represents a set of actions that * are associated with a particular selection key. Here the set * stores an <code>Action</code> for each of the interested operation * types. In some situations a single action may be interested in * several operations which must be remembered by the set. * * @author Niall Gallagher */ class ActionSet { /** * This is the selection key associated with the action set. */ private final SelectionKey key; /** * This contains the the actions indexed by operation type. */ private final Action[] set; /** * Constructor for the <code>ActionSet</code> object. This is * used to create a set for storing actions keyed by operation * type. Only one action is kept per operation type. * * @param key this is the associated selection key */ public ActionSet(SelectionKey key) { this.set = new Action[4]; this.key = key; } /** * This provides the selection key associated with the action set. * For each ready operation on the selection key the set contains * an action that can be executed. * * @return this provides the selection key for this action set */ public SelectionKey key() { return key; } /** * This provides the channel associated with the action set. This * is the channel that is registered for selection using the * interested operations for the set. * * @return this returns the selectable channel for the action set */ public SelectableChannel channel() { return key.channel(); } /** * This provides an iterator of the actions that exist within the * action set. Regardless of whether a single action is interested * is several operations this will return an iteration of unique * actions. Modifications to the iterator do not affect the set. * * @return this returns an iterator of unique actions for the set */ public Action[] list() { Action[] actions = new Action[4]; int count = 0; for(Action action : set) { if(action != null) { actions[count++] = action; } } return copyOf(actions, count); } /** * This is sued to acquire all actions that match the currently * ready operations of the key. All actions returned by this will * be executed and the interest will typically be removed. * * @return returns the array of ready operations for the set */ public Action[] ready() { int ready = key.readyOps(); if(ready != 0) { return get(ready); } return new Action[]{}; } /** * This is used to attach an action to the set for a specific * interest bitmask. If the bitmask contains several operations * then the action is registered for each individual operation. * * @param action this is the action that is to be attached * @param interest this is the interest for the action */ public void attach(Action action) { int interest = action.getInterest(); if((interest | OP_READ) == interest) { set[0] = action; } if((interest | OP_WRITE) == interest) { set[1] = action; } if((interest | OP_ACCEPT) == interest) { set[2] = action; } if((interest | OP_CONNECT) == interest) { set[3] = action; } } /** * This is used to remove interest from the set. Removal of * interest from the set is performed by registering a null for * the interest operation. * * @param interest this is the interest to be removed */ public Action[] remove(int interest) { Action[] actions = get(interest); if((interest | OP_READ) == interest) { set[0] = null; } if((interest | OP_WRITE) == interest) { set[1] = null; } if((interest | OP_ACCEPT) == interest) { set[2] = null; } if((interest | OP_CONNECT) == interest) { set[3] = null; } return actions; } /** * This is used to acquire the actions that match the bitmask of * interest operations. If there are no actions representing the * interest required an empty array will be returned. * * @param interest this is the interest to acquire actions for * * @return this will return an array of actions for the interest */ public Action[] get(int interest) { Action[] actions = new Action[4]; int count = 0; if((interest | OP_READ) == interest) { if(set[0] != null) { actions[count++] = set[0]; } } if((interest | OP_WRITE) == interest) { if(set[1] != null) { actions[count++] = set[1]; } } if((interest | OP_ACCEPT) == interest) { if(set[2] != null) { actions[count++] = set[2]; } } if((interest | OP_CONNECT) == interest) { if(set[3] != null) { actions[count++] = set[3]; } } return copyOf(actions, count); } /** * This is used to create a copy of the specified list with only * the first few non null values. This ensures we can keep the * internal array immutable and still use arrays. * * @param list this is the list that is to be copied to a new array * @param count this is the number of entries to copy from the list * * @return a copy of the original list up to the specified count */ private Action[] copyOf(Action[] list, int count) { Action[] copy = new Action[count]; for(int i = 0; i < count; i++) { copy[i] = list[i]; } return copy; } /** * This is used to acquire the operations that this is interested * in. If there are currently no registered actions then this will * return zero. Interest is represented by non-null actions only. * * @return this returns the interested operations for this */ public int interest() { int interest = 0; if(set[0] != null) { interest |= OP_READ; } if(set[1] != null) { interest |= OP_WRITE; } if(set[2] != null) { interest |= OP_ACCEPT; } if(set[3] != null) { interest |= OP_CONNECT; } return interest; } /** * This is used to clear all interest from the set. This will * basically clear out any actions that have been registered with * the set. After invocation the iterator will be empty. */ public void clear() { set[0] = set[1] = set[2] = set[3] = null; } /** * This is used to cancel the <code>SelectionKey</code> associated * with the action set. Canceling the key in this manner ensures * it is not returned in further selection operations. */ public void cancel() { key.cancel(); } }