/* * Task.java February 2007 * * Copyright (C) 2007, 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; import static org.simpleframework.transport.TransportEvent.ERROR; import java.io.IOException; import java.nio.channels.SelectableChannel; import org.simpleframework.transport.reactor.Operation; import org.simpleframework.transport.reactor.Reactor; import org.simpleframework.transport.trace.Trace; /** * The <code>Task</code> object is used to represent an asynchronous task that * interacts with the negotiation. This is typically used to either schedule an * asynchronous read or write when it can not be performed directly. It ensures * that the negotiation does not block the thread so that execution can be * optimized. * * @author Niall Gallagher * * @see org.simpleframework.transport.Handshake */ abstract class Task implements Operation { /** * This is the negotiation that this task will operate on. */ protected final Negotiation state; /** * This is the reactor that is used to schedule execution. */ protected final Reactor reactor; /** * This is the trace used to monitor the handshake socket. */ protected final Trace trace; /** * This is the required operation for the task to complete. */ protected final int require; /** * Constructor for the <code>Task</code> object. This is used to create an * operation that performs some action with respect the the negotiation. It * allows the negotiation to schedule the read and write operations so the * thread does not block. * * @param state * this is the negotiation this task works on * @param reactor * this is the reactor used to schedule the task * @param trace * the trace that is used to monitor the handshake * @param require * this is the required operation for the task */ public Task(Negotiation state, Reactor reactor, Trace trace, int require) { this.reactor = reactor; this.require = require; this.state = state; this.trace = trace; } /** * This is the <code>SelectableChannel</code> which is used to determine if * the operation should be executed. If the channel is ready for a given I/O * event it can be run. For instance if the operation is used to perform * some form of read operation it can be executed when ready to read data * from the channel. * * @return this returns the channel used to govern execution */ @Override public SelectableChannel getChannel() { return this.state.getChannel(); } /** * This is used to execute the task. It is up to the specific task * implementation to decide what to do when executed. If the task needs to * read or write data then it can attempt to perform the read or write, if * it incomplete the it can be scheduled for execution with the reactor. */ @Override public void run() { try { this.execute(); } catch (Exception cause) { this.trace.trace(ERROR, cause); this.cancel(); } } /** * This is used to cancel the operation if it has timed out. This is * typically invoked when it has been waiting in a selector for an extended * duration of time without any active operations on it. In such a case the * reactor must purge the operation to free the memory and open channels * associated with the operation. */ @Override public void cancel() { try { this.state.cancel(); } catch (Exception cause) { this.trace.trace(ERROR, cause); } } /** * This is used to execute the task. It is up to the specific task * implementation to decide what to do when executed. If the task needs to * read or write data then it can attempt to perform the read or write, if * it incomplete the it can be scheduled for execution with the reactor. */ protected void execute() throws IOException { boolean done = this.ready(); if (!done) { this.reactor.process(this, this.require); } else { this.state.resume(); } } /** * This method is used to determine if the task is ready. This is executed * when the select operation is signaled. When this is true the the task * completes. If not then this will schedule the task again for the * specified select operation. * * @return this returns true when the task has completed */ protected boolean ready() throws IOException { return true; } }