/*
 * Copyright (c) 2008, 2017 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.grizzly.filterchain;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.grizzly.Appendable;
import org.glassfish.grizzly.Appender;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Closeable;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.Context;
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.IOEvent;
import org.glassfish.grizzly.ProcessorExecutor;
import org.glassfish.grizzly.ReadResult;
import org.glassfish.grizzly.ThreadCache;
import org.glassfish.grizzly.WriteResult;
import org.glassfish.grizzly.asyncqueue.MessageCloner;
import org.glassfish.grizzly.attributes.AttributeHolder;
import org.glassfish.grizzly.attributes.AttributeStorage;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.memory.MemoryManager;
import org.glassfish.grizzly.utils.Holder;

FilterChain Context implementation.
Author:Alexey Stashok
See Also:
/** * {@link FilterChain} {@link Context} implementation. * * @see Context * @see FilterChain * * @author Alexey Stashok */
@SuppressWarnings("deprecation") public class FilterChainContext implements AttributeStorage { private static final Logger logger = Grizzly.logger(FilterChainContext.class); public enum State { RUNNING, SUSPEND } public enum Operation { NONE, ACCEPT, CONNECT, READ, WRITE, EVENT, CLOSE } private static final ThreadCache.CachedTypeIndex<FilterChainContext> CACHE_IDX = ThreadCache.obtainIndex(FilterChainContext.class, 8); public static FilterChainContext create(final Connection connection) { return create(connection, connection); } public static FilterChainContext create(final Connection connection, final Closeable closeable) { FilterChainContext context = ThreadCache.takeFromCache(CACHE_IDX); if (context == null) { context = new FilterChainContext(); } context.setConnection(connection); context.setCloseable(closeable); context.getTransportContext().isBlocking = connection.isBlocking(); return context; } public static final int NO_FILTER_INDEX = Integer.MIN_VALUE;
Cached NextAction instance for "Invoke action" implementation
/** * Cached {@link NextAction} instance for "Invoke action" implementation */
private static final NextAction INVOKE_ACTION = new InvokeAction();
Cached NextAction instance for "Stop action" implementation
/** * Cached {@link NextAction} instance for "Stop action" implementation */
private static final NextAction STOP_ACTION = new StopAction();
Cached NextAction instance for "Suspend action" implementation
/** * Cached {@link NextAction} instance for "Suspend action" implementation */
private static final NextAction SUSPEND_ACTION = new SuspendAction();
Cached NextAction instance for "Rerun filter action" implementation
/** * Cached {@link NextAction} instance for "Rerun filter action" implementation */
private static final NextAction RERUN_FILTER_ACTION = new RerunFilterAction(); final InternalContextImpl internalContext = new InternalContextImpl(this); final TransportContext transportFilterContext = new TransportContext();
Context task state
/** * Context task state */
private volatile State state; private Operation operation = Operation.NONE;
CompletionHandler, which will be notified, when operation will be complete. For WRITE it means the data will be written on wire, for other operations - the last Filter has finished the processing.
/** * {@link CompletionHandler}, which will be notified, when operation will be * complete. For WRITE it means the data will be written on wire, for other * operations - the last Filter has finished the processing. */
protected CompletionHandler<FilterChainContext> operationCompletionHandler; private final Runnable contextRunnable;
Context associated message
/** * Context associated message */
private Object message;
The Closeable object associated with the filter chain processing
/** * The {@link Closeable} object associated with the filter chain processing */
private Closeable closeable;
Context associated event, if EVENT operation
/** * Context associated event, if EVENT operation */
protected FilterChainEvent event;
Holder, which contains address, associated with the current IOEvent processing.
/** * {@link Holder}, which contains address, associated with the * current {@link org.glassfish.grizzly.IOEvent} processing. */
private Holder<?> addressHolder; NextAction predefinedNextAction;
Index of the currently executing Filter in the FilterChainContext list.
/** * Index of the currently executing {@link Filter} in * the {@link FilterChainContext} list. */
private int filterIdx; private int startIdx; private int endIdx; private final StopAction cachedStopAction = new StopAction(); private final InvokeAction cachedInvokeAction = new InvokeAction(); private final List<CompletionListener> completionListeners = new ArrayList<CompletionListener>(2); private final List<CopyListener> copyListeners = new ArrayList<CopyListener>(2); public FilterChainContext() { filterIdx = NO_FILTER_INDEX; contextRunnable = new Runnable() { @Override public void run() { try { if (state == State.SUSPEND) { state = State.RUNNING; } ProcessorExecutor.execute(FilterChainContext.this.internalContext); } catch (Exception e) { logger.log(Level.FINE, "Exception during running Processor", e); } } }; }
Suspend processing of the current task
/** * Suspend processing of the current task */
public Runnable suspend() { internalContext.suspend(); this.state = State.SUSPEND; return getRunnable(); }
Resume processing of the current task
/** * Resume processing of the current task */
public void resume() { internalContext.resume(); getRunnable().run(); }
Resume processing of the current task starting from the Filter, which follows the Filter, which suspend the processing.
/** * Resume processing of the current task starting from the Filter, which * follows the Filter, which suspend the processing. */
public void resumeNext() { resume(getInvokeAction()); }
Resume the current FilterChain task processing by completing the current Filter (the Filter, which suspended the processing) with the passed NextAction.
Params:
/** * Resume the current FilterChain task processing by completing the current * {@link Filter} (the Filter, which suspended the processing) with the * passed {@link NextAction}. * * @param nextAction the {@link NextAction}, based on which {@link FilterChain} * will continue processing. */
public void resume(final NextAction nextAction) { internalContext.resume(); try { if (state == State.SUSPEND) { state = State.RUNNING; } predefinedNextAction = nextAction; ProcessorExecutor.execute(internalContext); } catch (Exception e) { logger.log(Level.FINE, "Exception during running Processor", e); } }
This method invocation suggests the FilterChain to create a copy of this FilterChainContext and resume/fork its execution starting from the current Filter.
/** * This method invocation suggests the {@link FilterChain} to create a * copy of this {@link FilterChainContext} and resume/fork its execution * starting from the current {@link Filter}. */
public void fork() { fork(null); }
This method invocation suggests the FilterChain to create a copy of this FilterChainContext and resume/fork its execution starting from the current Filter.

If nextAction parameter is not null - then its value is treated as a result of the current Filter execution on the forked FilterChain processing. So during the forked FilterChain processing the current Filter will not be invoked, but the processing will be continued as if the current Filter returned nextAction as a result. For example if we call fork(ctx.getInvokeAction()); the forked FilterChain processing will start with the next Filter in chain.
/** * This method invocation suggests the {@link FilterChain} to create a * copy of this {@link FilterChainContext} and resume/fork its execution * starting from the current {@link Filter}. * <p/> * If <code>nextAction</code> parameter is not null - then its value is treated * as a result of the current {@link Filter} execution on the forked * {@link FilterChain} processing. So during the forked {@link FilterChain} * processing the current {@link Filter} will not be invoked, but * the processing will be continued as if the current {@link Filter} * returned <code>nextAction</code> as a result. * For example if we call <code>fork(ctx.getInvokeAction());</code> the forked * {@link FilterChain} processing will start with the next {@link Filter} in * chain. */
public void fork(final NextAction nextAction) { try { predefinedNextAction = getForkAction(nextAction); ProcessorExecutor.execute(internalContext); } catch (Exception e) { logger.log(Level.FINE, "Exception during running Processor", e); } }
Get the current processing task state.
Returns:the current processing task state.
/** * Get the current processing task state. * @return the current processing task state. */
public State state() { return state; } public int nextFilterIdx() { return ++filterIdx; } public int previousFilterIdx() { return --filterIdx; } public int getFilterIdx() { return filterIdx; } public void setFilterIdx(int index) { this.filterIdx = index; } public int getStartIdx() { return startIdx; } public void setStartIdx(int startIdx) { this.startIdx = startIdx; } public int getEndIdx() { return endIdx; } public void setEndIdx(int endIdx) { this.endIdx = endIdx; }
Get FilterChain, which runs the Filter.
Returns:FilterChain, which runs the Filter.
/** * Get {@link FilterChain}, which runs the {@link Filter}. * * @return {@link FilterChain}, which runs the {@link Filter}. */
public FilterChain getFilterChain() { return (FilterChain) internalContext.getProcessor(); }
Get the Connection, associated with the current processing.
Returns:Connection object, associated with the current processing.
/** * Get the {@link Connection}, associated with the current processing. * * @return {@link Connection} object, associated with the current processing. */
public Connection getConnection() { return internalContext.getConnection(); }
Set the Connection, associated with the current processing.
Params:
  • connection – Connection object, associated with the current processing.
/** * Set the {@link Connection}, associated with the current processing. * * @param connection {@link Connection} object, associated with the current processing. */
void setConnection(final Connection connection) { internalContext.setConnection(connection); }
Get the Closeable, associated with the current processing. The Closeable object might be used to close/terminate an entity associated with the FilterChain processing in response to an error occurred during the processing. If not customized the Closeable object represents a Connection associated with the FilterChain processing.
Returns:Closeable object, associated with the current processing.
/** * Get the {@link Closeable}, associated with the current processing. * The {@link Closeable} object might be used to close/terminate an entity * associated with the {@link FilterChain} processing in response to an * error occurred during the processing. * If not customized the {@link Closeable} object represents a {@link Connection} * associated with the {@link FilterChain} processing. * * @return {@link Closeable} object, associated with the current processing. */
public Closeable getCloseable() { return closeable; }
Set the Closeable, associated with the current processing. The Closeable object might be used to close/terminate an entity associated with the FilterChain processing in response to an error occurred during the processing. If not customized the Closeable object represents a Connection associated with the FilterChain processing.
Params:
  • closeable – Closeable object, associated with the current processing. If null the getConnection() value will be assigned
/** * Set the {@link Closeable}, associated with the current processing. * The {@link Closeable} object might be used to close/terminate an entity * associated with the {@link FilterChain} processing in response to an * error occurred during the processing. * If not customized the {@link Closeable} object represents a {@link Connection} * associated with the {@link FilterChain} processing. * * @param closeable {@link Closeable} object, associated with the current processing. * If <tt>null</tt> the {@link #getConnection()} value will be assigned */
void setCloseable(final Closeable closeable) { this.closeable = closeable != null ? closeable : getConnection(); }
Get message object, associated with the current processing. Usually FilterChain represents sequence of parser and process Filters. Each parser can change the message representation until it will come to processor Filter.
Returns:message object, associated with the current processing.
/** * Get message object, associated with the current processing. * * Usually {@link FilterChain} represents sequence of parser and process * {@link Filter}s. Each parser can change the message representation until * it will come to processor {@link Filter}. * * @return message object, associated with the current processing. */
@SuppressWarnings("unchecked") public <T> T getMessage() { return (T) message; }
Set message object, associated with the current processing. Usually FilterChain represents sequence of parser and process Filters. Each parser can change the message representation until it will come to processor Filter.
Params:
  • message – message object, associated with the current processing.
/** * Set message object, associated with the current processing. * * Usually {@link FilterChain} represents sequence of parser and process * {@link Filter}s. Each parser can change the message representation until * it will come to processor {@link Filter}. * * @param message message object, associated with the current processing. */
public void setMessage(Object message) { this.message = message; }
Get a Holder, which contains address, associated with the current IOEvent processing. When we process IOEvent.READ event - it represents sender address, or when process IOEvent.WRITE - address of receiver.
Returns:Holder, which contains address, associated with the current IOEvent processing.
/** * Get a {@link Holder}, which contains address, associated with the * current {@link org.glassfish.grizzly.IOEvent} processing. * * When we process {@link org.glassfish.grizzly.IOEvent#READ} event - it represents sender address, * or when process {@link org.glassfish.grizzly.IOEvent#WRITE} - address of receiver. * * @return {@link Holder}, which contains address, associated with the * current {@link org.glassfish.grizzly.IOEvent} processing. */
public Holder<?> getAddressHolder() { return addressHolder; }
Set address, associated with the current IOEvent processing. When we process IOEvent.READ event - it represents sender address, or when process IOEvent.WRITE - address of receiver.
Params:
  • addressHolder – Holder, which contains address, associated with the current IOEvent processing.
/** * Set address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. * When we process {@link org.glassfish.grizzly.IOEvent#READ} event - it represents sender address, * or when process {@link org.glassfish.grizzly.IOEvent#WRITE} - address of receiver. * * @param addressHolder {@link Holder}, which contains address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. */
public void setAddressHolder(final Holder<?> addressHolder) { this.addressHolder = addressHolder; }
Get address, associated with the current IOEvent processing. When we process IOEvent.READ event - it represents sender address, or when process IOEvent.WRITE - address of receiver.
Returns:address, associated with the current IOEvent processing.
/** * Get address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. * When we process {@link org.glassfish.grizzly.IOEvent#READ} event - it represents sender address, * or when process {@link org.glassfish.grizzly.IOEvent#WRITE} - address of receiver. * * @return address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. */
public Object getAddress() { return addressHolder != null ? addressHolder.get() : null; }
Set address, associated with the current IOEvent processing. When we process IOEvent.READ event - it represents sender address, or when process IOEvent.WRITE - address of receiver.
Params:
  • address – address, associated with the current IOEvent processing.
/** * Set address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. * When we process {@link org.glassfish.grizzly.IOEvent#READ} event - it represents sender address, * or when process {@link org.glassfish.grizzly.IOEvent#WRITE} - address of receiver. * * @param address address, associated with the current {@link org.glassfish.grizzly.IOEvent} processing. */
public void setAddress(final Object address) { addressHolder = Holder.staticHolder(address); } protected final Runnable getRunnable() { return contextRunnable; }
Get the TransportFilter related context.
Returns:TransportFilter.
/** * Get the {@link TransportFilter} related context. * * @return {@link TransportFilter}. */
public TransportContext getTransportContext() { return transportFilterContext; }
Get the general Grizzly Context this filter context wraps.
Returns:the general Grizzly Context this filter context wraps.
/** * Get the general Grizzly {@link Context} this filter context wraps. * @return the general Grizzly {@link Context} this filter context wraps. */
public final Context getInternalContext() { return internalContext; } Operation getOperation() { return operation; } void setOperation(Operation operation) { this.operation = operation; }
Get NextAction implementation, which instructs FilterChain to process next Filter in chain. Normally, after receiving this instruction from Filter, FilterChain executes next filter.
Returns:NextAction implementation, which instructs FilterChain to process next Filter in chain.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. * * Normally, after receiving this instruction from {@link Filter}, * {@link FilterChain} executes next filter. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. */
public NextAction getInvokeAction() { return INVOKE_ACTION; }
Get NextAction implementation, which instructs FilterChain to process next Filter in chain. Normally, after receiving this instruction from Filter, FilterChain executes next filter.
Params:
  • unparsedChunk – signals, that there is some unparsed data remaining in the source message, so FilterChain could be rerun.
Returns:NextAction implementation, which instructs FilterChain to process next Filter in chain.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. * * Normally, after receiving this instruction from {@link Filter}, * {@link FilterChain} executes next filter. * * @param unparsedChunk signals, that there is some unparsed data remaining * in the source message, so {@link FilterChain} could be rerun. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. */
public NextAction getInvokeAction(final Object unparsedChunk) { if (unparsedChunk == null) { return INVOKE_ACTION; } cachedInvokeAction.setUnparsedChunk(unparsedChunk); return cachedInvokeAction; }
Get NextAction implementation, which instructs FilterChain to process next Filter in chain. Normally, after receiving this instruction from Filter, FilterChain executes next filter.
Params:
  • incompleteChunk – signals, that there is a data chunk remaining, which doesn't represent complete message. As more data becomes available but before FilterChain calls the current Filter, it will check if the Filter has any data stored after the last invocation. If a remainder is present it will append the new data to the stored one and pass the result as the FilterChainContext message.
  • appender – the Appender, which knows how to append chunks of type <E>.
Throws:
Returns:NextAction implementation, which instructs FilterChain to process next Filter in chain.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. * * Normally, after receiving this instruction from {@link Filter}, * {@link FilterChain} executes next filter. * * @param incompleteChunk signals, that there is a data chunk remaining, * which doesn't represent complete message. As more data becomes available * but before {@link FilterChain} calls the current {@link Filter}, * it will check if the {@link Filter} has any data stored after the * last invocation. If a remainder is present it will append the new data * to the stored one and pass the result as the FilterChainContext message. * * @param appender the {@link org.glassfish.grizzly.Appender}, which knows * how to append chunks of type <code>&lt;E&gt;</code>. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} to * process next {@link Filter} in chain. * * @throws IllegalArgumentException if appender is <code>null</code> and * remainder's type is not {@link Buffer} or {@link Appendable}. */
@SuppressWarnings("unchecked") public <E> NextAction getInvokeAction(final E incompleteChunk, org.glassfish.grizzly.Appender<E> appender) { if (incompleteChunk == null) { return INVOKE_ACTION; } if (appender == null) { if (incompleteChunk instanceof Buffer) { appender = (Appender<E>) Buffers.getBufferAppender(true); } else if (!(incompleteChunk instanceof Appendable)) { throw new IllegalArgumentException("Remainder has to be either " + Buffer.class.getName() + " or " + Appendable.class.getName() + " but was " + incompleteChunk.getClass().getName()); } } cachedInvokeAction.setIncompleteChunk(incompleteChunk, appender); return cachedInvokeAction; }
Get NextAction implementation, which instructs FilterChain to stop executing phase.
Returns:NextAction implementation, which instructs FilterChain to stop executing phase.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} * to stop executing phase. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} * to stop executing phase. */
public NextAction getStopAction() { return STOP_ACTION; }
Get NextAction implementation, which instructs FilterChain stop executing phase.
Params:
  • incompleteChunk – signals, that there is a data chunk remaining, which doesn't represent complete message. As more data becomes available but before FilterChain calls the current Filter, it will check if the Filter has any data stored after the last invocation. If a remainder is present it will append the new data to the stored one and pass the result as the FilterChainContext message.
Throws:
Returns:NextAction implementation, which instructs FilterChain to stop executing phase.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} * stop executing phase. * * @param incompleteChunk signals, that there is a data chunk remaining, * which doesn't represent complete message. As more data becomes available * but before {@link FilterChain} calls the current {@link Filter}, * it will check if the {@link Filter} has any data stored after the * last invocation. If a remainder is present it will append the new data * to the stored one and pass the result as the FilterChainContext message. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} * to stop executing phase. * * @throws IllegalArgumentException if remainder's type is not {@link Buffer} or * {@link Appendable}. */
public NextAction getStopAction(final Object incompleteChunk) { if (incompleteChunk instanceof Buffer) { return getStopAction((Buffer) incompleteChunk, Buffers.getBufferAppender(true)); } return getStopAction(incompleteChunk, null); }
Get NextAction implementation, which instructs FilterChain stop executing phase.
Params:
  • incompleteChunk – signals, that there is a data chunk remaining, which doesn't represent complete message. As more data becomes available but before FilterChain calls the current Filter, it will check if the Filter has any data stored after the last invocation. If a remainder is present it will append the new data to the stored one and pass the result as the FilterChainContext message.
  • appender – the Appender, which knows how to append chunks of type <E>.
Throws:
Returns:NextAction implementation, which instructs FilterChain to stop executing phase.
/** * Get {@link NextAction} implementation, which instructs {@link FilterChain} * stop executing phase. * * @param incompleteChunk signals, that there is a data chunk remaining, * which doesn't represent complete message. As more data becomes available * but before {@link FilterChain} calls the current {@link Filter}, * it will check if the {@link Filter} has any data stored after the * last invocation. If a remainder is present it will append the new data * to the stored one and pass the result as the FilterChainContext message. * * @param appender the {@link org.glassfish.grizzly.Appender}, which knows * how to append chunks of type <code>&lt;E&gt;</code>. * * @return {@link NextAction} implementation, which instructs {@link FilterChain} * to stop executing phase. * * @throws IllegalArgumentException if appender is <code>null</code> and * remainder's type is not {@link Buffer} or {@link Appendable}. */
public <E> NextAction getStopAction(final E incompleteChunk, final org.glassfish.grizzly.Appender<E> appender) { if (incompleteChunk == null) { return STOP_ACTION; } if (appender == null && !(incompleteChunk instanceof Appendable)) { throw new IllegalArgumentException("Remainder has to be either " + Buffer.class.getName() + " or " + Appendable.class.getName() + " but was " + incompleteChunk.getClass().getName()); } cachedStopAction.setIncompleteChunk(incompleteChunk, appender); return cachedStopAction; }
Returns:NextAction implementation, which suggests the FilterChain to forget about the current FilterChainContext, create a copy of it and continue/fork FilterChain processing using the copied FilterChainContext starting from the current Filter.
/** * @return {@link NextAction} implementation, which suggests the {@link FilterChain} * to forget about the current {@link FilterChainContext}, create a copy of it * and continue/fork {@link FilterChain} processing using the copied * {@link FilterChainContext} starting from the current {@link Filter}. */
public NextAction getForkAction() { return getForkAction(null); }
Returns:NextAction implementation, which suggests the FilterChain to forget about the current FilterChainContext, create a copy of it and continue/fork FilterChain processing using the copied FilterChainContext starting from the current Filter.

If nextAction parameter is not null - then its value is treated as a result of the current Filter execution on the forked FilterChain processing. So during the forked FilterChain processing the current Filter will not be invoked, but the processing will be continued as if the current Filter returned nextAction as a result. For example if we call fork(ctx.getInvokeAction()); the forked FilterChain processing will start with the next Filter in chain.
/** * @return {@link NextAction} implementation, which suggests the {@link FilterChain} * to forget about the current {@link FilterChainContext}, create a copy of it * and continue/fork {@link FilterChain} processing using the copied * {@link FilterChainContext} starting from the current {@link Filter}. * <p/> * If <code>nextAction</code> parameter is not null - then its value is treated * as a result of the current {@link Filter} execution on the forked * {@link FilterChain} processing. So during the forked {@link FilterChain} * processing the current {@link Filter} will not be invoked, but * the processing will be continued as if the current {@link Filter} * returned <code>nextAction</code> as a result. * For example if we call <code>fork(ctx.getInvokeAction());</code> the forked * {@link FilterChain} processing will start with the next {@link Filter} in * chain. */
public NextAction getForkAction(final NextAction nextAction) { final FilterChainContext contextCopy = copy(); // Copy doesn't copy address contextCopy.addressHolder = addressHolder; contextCopy.predefinedNextAction = nextAction; return new ForkAction(contextCopy); }
Returns:NextAction implementation, which instructs the FilterChain to suspend the current FilterChainContext and invoke similar logic as instructed by StopAction with a clean FilterChainContext.
Deprecated:use getForkAction()
/** * @return {@link NextAction} implementation, which instructs the {@link FilterChain} * to suspend the current {@link FilterChainContext} and invoke similar logic * as instructed by {@link StopAction} with a clean {@link FilterChainContext}. * * @deprecated use {@link #getForkAction()} */
public NextAction getSuspendingStopAction() { return getForkAction(); }
Get NextAction, which instructs FilterChain to suspend filter chain execution.
Returns:NextAction, which instructs FilterChain to suspend filter chain execution.
/** * Get {@link NextAction}, which instructs {@link FilterChain} to suspend filter * chain execution. * * @return {@link NextAction}, which instructs {@link FilterChain} to suspend * filter chain execution. */
public NextAction getSuspendAction() { return SUSPEND_ACTION; }
Get NextAction, which instructs FilterChain to rerun the filter.
Returns:NextAction, which instructs FilterChain to rerun the filter.
/** * Get {@link NextAction}, which instructs {@link FilterChain} to rerun the * filter. * * @return {@link NextAction}, which instructs {@link FilterChain} to rerun the * filter. */
public NextAction getRerunFilterAction() { return RERUN_FILTER_ACTION; }

Performs a blocking read.

Throws:
Returns:the result of the read operation.
/** * <p> * Performs a blocking read. * </p> * * @return the result of the read operation. * * @throws IOException if an I/O error occurs. */
public ReadResult read() throws IOException { final FilterChainContext newContext = getFilterChain().obtainFilterChainContext(getConnection()); newContext.closeable = closeable; newContext.operation = Operation.READ; newContext.transportFilterContext.configureBlocking(true); newContext.startIdx = 0; newContext.filterIdx = 0; newContext.endIdx = filterIdx; getAttributes().copyTo(newContext.getAttributes()); final ReadResult rr = getFilterChain().read(newContext); newContext.completeAndRecycle(); return rr; } public void write(final Object message) { write(null, message, null, null, null, transportFilterContext.isBlocking()); } public void write(final Object message, final boolean blocking) { write(null, message, null, null, null, blocking); } public void write(final Object message, final CompletionHandler<WriteResult> completionHandler) { write(null, message, completionHandler, null, null, transportFilterContext.isBlocking()); } public void write(final Object message, final CompletionHandler<WriteResult> completionHandler, final boolean blocking) { write(null, message, completionHandler, null, null, blocking); } public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler) { write(address, message, completionHandler, null, null, transportFilterContext.isBlocking()); } public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final boolean blocking) { write(address, message, completionHandler, null, null, blocking); } @Deprecated public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler) { write(address, message, completionHandler, pushBackHandler, transportFilterContext.isBlocking()); } @Deprecated public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler, final boolean blocking) { write(address, message, completionHandler, pushBackHandler, null, blocking); } public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final MessageCloner cloner) { write(address, message, completionHandler, null, cloner, transportFilterContext.isBlocking()); } @Deprecated public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler, final MessageCloner cloner) { write(address, message, completionHandler, pushBackHandler, cloner, transportFilterContext.isBlocking()); } public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final MessageCloner cloner, final boolean blocking) { write(address, message, completionHandler, null, cloner, blocking); } @Deprecated public void write(final Object address, final Object message, final CompletionHandler<WriteResult> completionHandler, final org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler, final MessageCloner cloner, final boolean blocking) { final FilterChainContext newContext = getFilterChain().obtainFilterChainContext(getConnection()); newContext.operation = Operation.WRITE; newContext.transportFilterContext.configureBlocking(blocking); newContext.message = message; newContext.addressHolder = address == null ? addressHolder : Holder.staticHolder(address); newContext.closeable = closeable; newContext.transportFilterContext.completionHandler = completionHandler; newContext.transportFilterContext.pushBackHandler = pushBackHandler; newContext.transportFilterContext.cloner = cloner; newContext.startIdx = filterIdx - 1; newContext.filterIdx = filterIdx - 1; newContext.endIdx = -1; getAttributes().copyTo(newContext.getAttributes()); ProcessorExecutor.execute(newContext.internalContext); } public void flush(final CompletionHandler completionHandler) { final FilterChainContext newContext = getFilterChain().obtainFilterChainContext(getConnection()); newContext.operation = Operation.EVENT; newContext.closeable = closeable; newContext.event = TransportFilter.createFlushEvent(completionHandler); newContext.transportFilterContext.configureBlocking(transportFilterContext.isBlocking()); newContext.addressHolder = addressHolder; newContext.startIdx = filterIdx - 1; newContext.filterIdx = filterIdx - 1; newContext.endIdx = -1; getAttributes().copyTo(newContext.getAttributes()); ProcessorExecutor.execute(newContext.internalContext); } public void notifyUpstream(final FilterChainEvent event) { notifyUpstream(event, null); } public void notifyUpstream(final FilterChainEvent event, final CompletionHandler<FilterChainContext> completionHandler) { final FilterChainContext newContext = getFilterChain().obtainFilterChainContext(getConnection()); newContext.setOperation(Operation.EVENT); newContext.event = event; newContext.closeable = closeable; newContext.addressHolder = addressHolder; newContext.startIdx = filterIdx + 1; newContext.filterIdx = filterIdx + 1; newContext.endIdx = endIdx; getAttributes().copyTo(newContext.getAttributes()); newContext.operationCompletionHandler = completionHandler; ProcessorExecutor.execute(newContext.internalContext); } public void notifyDownstream(final FilterChainEvent event) { notifyDownstream(event, null); } public void notifyDownstream(final FilterChainEvent event, final CompletionHandler<FilterChainContext> completionHandler) { final FilterChainContext newContext = getFilterChain().obtainFilterChainContext(getConnection()); newContext.setOperation(Operation.EVENT); newContext.event = event; newContext.closeable = closeable; newContext.addressHolder = addressHolder; newContext.startIdx =filterIdx - 1; newContext.filterIdx = filterIdx - 1; newContext.endIdx = -1; getAttributes().copyTo(newContext.getAttributes()); newContext.operationCompletionHandler = completionHandler; ProcessorExecutor.execute(newContext.internalContext); } public void fail(final Throwable error) { getFilterChain().fail(this, error); }
{@inheritDoc}
/** * {@inheritDoc} */
@Override public AttributeHolder getAttributes() { return internalContext.getAttributes(); }
Add the CompletionListener, which will be notified, when this FilterChainContext processing will be completed.
Params:
/** * Add the {@link CompletionListener}, which will be notified, when * this {@link FilterChainContext} processing will be completed. * * @param listener the {@link CompletionListener}, which will be notified, when * this {@link FilterChainContext} processing will be completed. */
public final void addCompletionListener(final CompletionListener listener) { completionListeners.add(listener); }
Remove the CompletionListener.
Params:
Returns:true, if the listener was removed from the list, or false, if the listener wasn't on the list.
/** * Remove the {@link CompletionListener}. * * @param listener the {@link CompletionListener} to be removed. * @return <tt>true</tt>, if the listener was removed from the list, or * <tt>false</tt>, if the listener wasn't on the list. */
public final boolean removeCompletionListener(final CompletionListener listener) { return completionListeners.remove(listener); }
Add the CopyListener, which will be notified, right after this copy() is called.
Params:
/** * Add the {@link CopyListener}, which will be notified, right after * this {@link FilterChainContext#copy()} is called. * * @param listener the {@link CopyListener}, which will be notified, right * after this {@link FilterChainContext#copy()} is called. */
public final void addCopyListener(final CopyListener listener) { copyListeners.add(listener); }
Remove the CopyListener.
Params:
Returns:true, if the listener was removed from the list, or false, if the listener wasn't on the list.
/** * Remove the {@link CopyListener}. * * @param listener the {@link CopyListener} to be removed. * @return <tt>true</tt>, if the listener was removed from the list, or * <tt>false</tt>, if the listener wasn't on the list. */
public final boolean removeCopyListener(final CopyListener listener) { return copyListeners.remove(listener); }

A simple alias for FilterChainContext.getConnection().getMemoryManager().

Returns:the MemoryManager associated with the Connection of this FilterChainContext.
/** * <p>A simple alias for <code>FilterChainContext.getConnection().getMemoryManager()</code>. * * @return the {@link MemoryManager} associated with the {@link Connection} * of this <code>FilterChainContext</code>. */
public final MemoryManager getMemoryManager() { return getConnection().getMemoryManager(); } public FilterChainContext copy() { final FilterChain p = getFilterChain(); final FilterChainContext newContext = p.obtainFilterChainContext(getConnection()); newContext.setOperation(getOperation()); newContext.setCloseable(getCloseable()); internalContext.softCopyTo(newContext.internalContext); newContext.setStartIdx(getStartIdx()); newContext.setEndIdx(getEndIdx()); newContext.setFilterIdx(getFilterIdx()); getAttributes().copyTo(newContext.getAttributes()); notifyCopy(this, newContext, copyListeners); return newContext; }
Release the context associated resources.
/** * Release the context associated resources. */
public void reset() { cachedInvokeAction.reset(); cachedStopAction.reset(); message = null; closeable = null; event = null; addressHolder = null; filterIdx = NO_FILTER_INDEX; state = State.RUNNING; operationCompletionHandler = null; operation = Operation.NONE; internalContext.reset(); transportFilterContext.reset(); copyListeners.clear(); predefinedNextAction = null; } public void completeAndRecycle() { notifyComplete(this, completionListeners); reset(); ThreadCache.putToCache(CACHE_IDX, this); } public void completeAndRelease() { notifyComplete(this, completionListeners); } @Override public String toString() { StringBuilder sb = new StringBuilder(384); sb.append("FilterChainContext ["); sb.append("connection=").append(getConnection()); sb.append(", closeable=").append(getCloseable()); sb.append(", operation=").append(getOperation()); sb.append(", message=").append(String.valueOf((Object) getMessage())); sb.append(", address=").append(getAddress()); sb.append(']'); return sb.toString(); } static Operation ioEvent2Operation(final IOEvent ioEvent) { switch(ioEvent) { case READ: return Operation.READ; case WRITE: return Operation.WRITE; case ACCEPTED: return Operation.ACCEPT; case CONNECTED: return Operation.CONNECT; case CLOSED: return Operation.CLOSE; default: return Operation.NONE; } } @SuppressWarnings("deprecation") public static final class TransportContext { private boolean isBlocking; CompletionHandler completionHandler; @Deprecated org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler; MessageCloner cloner; public void configureBlocking(boolean isBlocking) { this.isBlocking = isBlocking; } public boolean isBlocking() { return isBlocking; } public CompletionHandler getCompletionHandler() { return completionHandler; } public void setCompletionHandler(CompletionHandler completionHandler) { this.completionHandler = completionHandler; } @Deprecated public org.glassfish.grizzly.asyncqueue.PushBackHandler getPushBackHandler() { return pushBackHandler; } @Deprecated public void setPushBackHandler(org.glassfish.grizzly.asyncqueue.PushBackHandler pushBackHandler) { this.pushBackHandler = pushBackHandler; } public MessageCloner getMessageCloner() { return cloner; } public void setMessageCloner(final MessageCloner cloner) { this.cloner = cloner; } void reset() { isBlocking = false; completionHandler = null; pushBackHandler = null; cloner = null; } } static void notifyComplete( final FilterChainContext context, final List<CompletionListener> completionListeners) { final int size = completionListeners.size(); for (int i = size - 1; i >= 0; i--) { completionListeners.get(i).onComplete(context); } completionListeners.clear(); } static void notifyCopy( final FilterChainContext srcContext, final FilterChainContext copiedContext, final List<CopyListener> copyListeners) { final int size = copyListeners.size(); for (int i = 0; i < size; i++) { copyListeners.get(i).onCopy(srcContext, copiedContext); } }
The interface, which represents a listener, which will be notified, once FilterChainContext processing is complete.
See Also:
/** * The interface, which represents a listener, which will be notified, * once {@link FilterChainContext} processing is complete. * * @see #addCompletionListener(org.glassfish.grizzly.filterchain.FilterChainContext.CompletionListener) */
public interface CompletionListener {
The method is called, when passed FilterChainContext processing is complete.
Params:
  • context –
/** * The method is called, when passed {@link FilterChainContext} processing * is complete. * * @param context */
void onComplete(FilterChainContext context); }
The interface, which represents a listener, which will be notified, after FilterChainContext.copy() is called.
See Also:
/** * The interface, which represents a listener, which will be notified, * after {@link FilterChainContext#copy()} is called. * * @see #addCopyListener(org.glassfish.grizzly.filterchain.FilterChainContext.CopyListener) */
public interface CopyListener {
The method is called, when passed FilterChainContext is copied.
Params:
  • srcContext – source Context
  • copiedContext – copied Context
/** * The method is called, when passed {@link FilterChainContext} * is copied. * * @param srcContext source Context * @param copiedContext copied Context */
void onCopy(FilterChainContext srcContext, FilterChainContext copiedContext); } }