org.curjent.agent
Class Agent

java.lang.Object
  extended by org.curjent.agent.Agent

public final class Agent
extends Object

Agent creation and configuration. See the Description in org.curjent.agent for an overview of agent concepts and usage.

Creating an Agent

Agents are created using this class's newInstance static method. A best practice is to hide the details of creating an agent in a static class method or in a factory class:
 interface Auditor {
     void audit(String message);
        
     interface Factory {
         Auditor newAuditor();
     }
        
     Factory FACTORY = new Factory() {
         public Auditor newAuditor() {
             return Agent.newInstance(Auditor.class, new AuditorTask());
         }
     };
 }
 
Agent types are uniquely identified by a ClassLoader, an ordered list of interfaces, and a task type. The newInstance method returns an instance of the identified agent type. The returned object implements the interfaces in the order given.

Custom classes are generated for each agent type in order to avoid the overhead of reflection and boxing. The generated classes are cached and only created the first time an agent of that type is instantiated. The cache uses WeakReference to allow garbage collection of the supplied ClassLoader and any generated classes.

Classes are generated in the same package as the given task type. The generated classes can therefore access a package-private or protected task and/or methods.

Due to the synchronous nature of hashCode, equals, and toString calls, these methods are not generated unless they are explicitly included in one of the given interfaces.

Configuring an Agent

The newInstance method creates a new agent with the essential information provided. The getConfig method provides additional post-creation configuration options. See AgentConfig for details.

A best practice is to configure an agent's exception handler for unhandled exceptions in the agent's factory method or class. The factory pattern above could, for example, be extended to include configuration of the agent's exception handler in the newAuditor method that would log unhandled exceptions using the application's standard logging mechanism. See AgentConfig.setUnhandledExceptionHandler(ExceptionHandler) for details.


Constructor Summary
private Agent()
          Singleton class of static methods only.
 
Method Summary
static void await(Object... agents)
          Waits for a list of agents to finish executing all prior calls.
static void await(Object agent)
          Waits for an agent to finish executing all prior calls.
static boolean await(Object agent, long timeout, TimeUnit unit)
          Waits a specified period for an agent to finish executing all prior calls.
static void awaitAll(Object... agents)
          Waits in parallel for a list of agents to finish executing all prior calls.
static AgentConfig getConfig(Object agent)
          Returns configuration options for an agent.
static AgentConfig getConfig(Object agent, Object oldKey, Object newKey)
          Returns configuration options for an agent.
static Executor getDefaultExecutor()
          Returns the Executor used for all new agents.
static
<V> AgentCall<V>
getLastCall(Object agent)
          Returns a reference to the last call made to an agent by the current thread.
static AgentStats getStats(Object agent)
          Returns a snapshot of statistics for an agent.
static
<V> AgentCall<V>
getThisCall()
          Returns a reference to the call executing by the current thread.
static AgentMark mark(Object agent)
          Creates a synthetic mark to trace the progress of prior agent calls.
static Object newInstance(AgentLoader loader, Class<?>[] interfaces, AgentTasks tasks, Class<?> taskType)
          Creates and returns a new agent.
static
<T> T
newInstance(Class<T> intrface, AgentTasks tasks)
          Creates and returns a new agent with one or more tasks.
static
<T> T
newInstance(Class<T> intrface, Object task)
          Creates and returns a new agent with one background task.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

Agent

private Agent()
Singleton class of static methods only.

Method Detail

newInstance

public static <T> T newInstance(Class<T> intrface,
                                Object task)
Creates and returns a new agent with one background task. Equivalent to calling:
    Agent.newInstance(
        new DelegatingLoader(task), 
        new Class[]{intrface},
        new SingletonTask(task), 
        task.getClass());
 

Parameters:
intrface - The agent's interface.
task - The task that implements the interface.
Returns:
An agent implementing the interface.
Throws:
NullPointerException - An argument is null.
IllegalArgumentException - An argument is invalid.
AgentException - Wraps a checked exception as the cause.
See Also:
newInstance(AgentLoader, Class[], AgentTasks, Class), DelegatingLoader, SingletonTask

newInstance

public static <T> T newInstance(Class<T> intrface,
                                AgentTasks tasks)
Creates and returns a new agent with one or more tasks. Acquires and releases a task from tasks. Using the acquired task, this method is equivalent to the following:
    Agent.newInstance(
        new DelegatingLoader(task), 
        new Class[]{intrface},
        tasks, 
        task.getClass());
 

Parameters:
intrface - The agent's interface.
tasks - Source for one or more tasks.
Returns:
An agent implementing the interface.
Throws:
NullPointerException - An argument is null.
IllegalArgumentException - An argument is invalid.
AgentException - Wraps a checked exception as the cause.
See Also:
newInstance(AgentLoader, Class[], AgentTasks, Class), DelegatingLoader, SingletonTask

newInstance

public static Object newInstance(AgentLoader loader,
                                 Class<?>[] interfaces,
                                 AgentTasks tasks,
                                 Class<?> taskType)
Creates and returns a new agent. See Creating an Agent in the class comments for details.

Parameters:
loader - Used to create, load, and cache custom-generated classes for the agent. See AgentLoader for details. DelegatingLoader is a good default choice (see also newInstance(Class, AgentTasks)).

interfaces - The returned proxy implements the provided interfaces in the order given. At least one interface is required. All interfaces must be accessible by the supplied ClassLoader. Duplicate interfaces are not allowed, and all interface methods must have assignment compatible return types and exceptions. Only the raw types for parameters, results, and exceptions are evaluated. Generics are not evaluated.

tasks - Source for one or more objects that implement the interfaces' methods. The maximum number of worker threads the agent will use concurrently to execute tasks is equal to the number of acquirable tasks. See AgentTasks for details. (The agent may occasionally and very briefly require additional threads for timing and efficiency reasons.) SingletonTask is a good default choice (see also newInstance(Class, Object)).

taskType - Class of the tasks. Custom agent classes are generated in the same package as the task type, so tasks and/or their methods can be package-private or protected. Furthermore, it is sufficient for the task type to implement all of the agent's interface methods; the tasks are not required to explicitly include the agent's interfaces in their class implements clauses. See Futures and Exceptions in org.curjent.agent for scenarios where this may be useful.

Returns:
An agent implementing the given interfaces.
Throws:
NullPointerException - An argument is null.
IllegalArgumentException - An argument is invalid.
AgentException - Wraps a checked exception as the cause.

mark

public static AgentMark mark(Object agent)
Creates a synthetic mark to trace the progress of prior agent calls. Use the returned mark to configure the call, and call the mark's AgentMark.call() method to add the call to the agent's queue.

await(Object) implements a common idiom for marks. It is functionally equivalent to the following:

    Agent.mark(agent).call().await();
 

Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.

await

public static void await(Object agent)
                  throws InterruptedException
Waits for an agent to finish executing all prior calls. Functionally equivalent to the following:
    Agent.await(agent, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
 

Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.
See Also:
await(Object, long, TimeUnit)

await

public static boolean await(Object agent,
                            long timeout,
                            TimeUnit unit)
                     throws InterruptedException
Waits a specified period for an agent to finish executing all prior calls. In the following example, a list of files is copied asynchronously using a copier agent:
    for (Copy copy : copies) {
        copier.copy(copy.source, copy.target);
    }
    Agent.await(copier);
 
The copier agent in this example utilizes multiple tasks and is therefore potentially many times faster than using a non-agent synchronous implementation. However, the caller wants to wait for all files to finish copying before proceeding. The Agent.await(copier) call accomplishes this.

Whereas the Agent.await(Object agent) method waits forever until interrupted or until the agent has finished executing all calls, the await(Object agent, long timeout, TimeUnit unit) method can also timeout. It returns true if the agent finished, or false if the timeout period expired. If the timeout value is 0 or negative, it times out immediately without waiting. It never times out if the timeout value is Long.MAX_VALUE.

This method is functionally equivalent to the following:

    Agent.mark(agent).call().await(CallState.FINISHED, timeout, unit);
 

Parameters:
agent - An agent returned from a newInstance method.
timeout - The timeout period. 0 to timeout immediately. Long.MAX_VALUE to never timeout.
unit - The timeout units. May be null if value is 0 or Long.MAX_VALUE.
Returns:
true if the agent finished executing all calls. false if the agent was still executing calls when the timeout period expired.
Throws:
NullPointerException - agent is null or unit is required and null.
ClassCastException - agent was not created with newInstance.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.

await

public static void await(Object... agents)
                  throws InterruptedException
Waits for a list of agents to finish executing all prior calls. Waits for each agent in the order given. Functionally equivalent to the following:
    for (Object agent: agents) {
        Agent.await(agent);
    }
 

Throws:
NullPointerException - agents or one of its members is null.
ClassCastException - A member of agents was not created with newInstance.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.
See Also:
await(Object, long, TimeUnit)

awaitAll

public static void awaitAll(Object... agents)
                     throws InterruptedException
Waits in parallel for a list of agents to finish executing all prior calls. Whereas await(Object...) waits for each agent in sequence, one after the other, this method adds a mark (see mark(Object)) to all agents at once and then waits for each mark to finish. Use await(Object...) when the order of completion is significant, such as when the first agent calls a second agent, and the second agent calls a third agent, etc., in a pipelined manner. Use awaitAll(Object...) for independent agents that are not calling each other.

Throws:
NullPointerException - agents or one of its members is null.
ClassCastException - A member of agents was not created with newInstance.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.
See Also:
await(Object...)

getConfig

public static AgentConfig getConfig(Object agent)
Returns configuration options for an agent. Equivalent to calling getConfig(Object, null, null).

Parameters:
agent - An agent returned from a newInstance method.
Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.
ConfigLockedException - agent configuration is locked.
See Also:
newInstance(AgentLoader, Class[], AgentTasks, Class), getConfig(Object, Object, Object)

getConfig

public static AgentConfig getConfig(Object agent,
                                    Object oldKey,
                                    Object newKey)
Returns configuration options for an agent. Agent designers can restrict access with a key. Calls fail if the oldKey value is not the same as the current key, where key comparison is performed using ==. Initially the configuration key is null. To change the key, pass the current key as the oldKey and the new key as the newKey. To keep the same key on subsequent calls, pass in the same value for both the oldKey and the newKey.

Examples:

    key = new Object(); // create and save a new key
    Agent.getConfig(agent, null, key); // lock configuration with the key
 
    Agent.getConfig(agent, key, key); // get the configuration
 
    Object key = this.key;
    this.key = new Object();
    Agent.getConfig(agent, key, this.key); // change the key
 

Parameters:
agent - An agent returned from a newInstance method.
oldKey - Reference to the current key.
newKey - Reference to a new key object.
Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.
ConfigLockedException - agent configuration is locked and oldKey is not the correct key.
See Also:
newInstance(AgentLoader, Class[], AgentTasks, Class), getConfig(Object)

getStats

public static AgentStats getStats(Object agent)
Returns a snapshot of statistics for an agent. The returned statistics are static and do not change. Call this method again to get updated statistics.

Parameters:
agent - An agent returned from a newInstance method.
Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.
See Also:
newInstance(AgentLoader, Class[], AgentTasks, Class)

getLastCall

public static <V> AgentCall<V> getLastCall(Object agent)
Returns a reference to the last call made to an agent by the current thread. Multiple threads can make calls concurrently. This method returns the last call this thread of execution made independent of what other threads are doing. Returns null if this thread has not yet made any calls to the given agent.

In the following example, the caller waits until an asynchronous call to print a document finishes executing, simulating the behavior of a synchronous call:

    printer.print(document);
    AgentCall print = Agent.getLastCall(printer);
    print.await();
 

Parameters:
agent - An agent returned from a newInstance method.
Throws:
NullPointerException - agent is null.
ClassCastException - agent was not created with newInstance.

getThisCall

public static <V> AgentCall<V> getThisCall()
Returns a reference to the call executing by the current thread. This gives executing agent tasks access to the current call context.


getDefaultExecutor

public static Executor getDefaultExecutor()
Returns the Executor used for all new agents. The default executor is not configurable, but the executor for individual agents is.

See Also:
getConfig(Object), AgentConfig.setExecutor(Executor)


Copyright 2009-2011 Tom Landon
Apache License 2.0