001: /*
002: * $Id: FutureMessageResult.java 10489 2008-01-23 17:53:38Z dfeist $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.api;
012:
013: import org.mule.DefaultMuleMessage;
014: import org.mule.api.transformer.TransformerException;
015: import org.mule.util.concurrent.DaemonThreadFactory;
016:
017: import java.util.List;
018:
019: import edu.emory.mathcs.backport.java.util.concurrent.Callable;
020: import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
021: import edu.emory.mathcs.backport.java.util.concurrent.Executor;
022: import edu.emory.mathcs.backport.java.util.concurrent.Executors;
023: import edu.emory.mathcs.backport.java.util.concurrent.FutureTask;
024: import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
025: import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException;
026:
027: /**
028: * <code>FutureMessageResult</code> is an MuleMessage result of a remote invocation
029: * on a Mule Server. This object makes the result available to the client code once
030: * the request has been processed. This execution happens asynchronously.
031: */
032: // @ThreadSafe
033: public class FutureMessageResult extends FutureTask {
034: /**
035: * This is a simple default Executor for FutureMessageResults. Instead of
036: * spawning a Thread for each invocation it uses a single daemon Thread with an
037: * unbounded queue, so "truly" concurrent operation of multiple Futures or
038: * otherwise customized execution behaviour requires calling the
039: * {@link #setExecutor(Executor)} method and passing in a custom {@link Executor}.
040: * This is strongly recommended in order to provide better control over
041: * concurrency, resource consumption and possible overruns.
042: * <p>
043: * Reasons for these defaults:
044: * <ul>
045: * <li> a daemon thread does not block the VM on shutdown; lifecycle control
046: * should be done elsewhere (e.g. the provider of the custom ExecutorService),
047: * otherwise this class would become too overloaded
048: * <li> a single thread provides for conservative & predictable yet async
049: * behaviour from a client's point of view
050: * <li> the unbounded queue is not optimal but probably harmless since e.g. a
051: * MuleClient would have to create a LOT of Futures for an OOM. Cancelled/timed
052: * out invocations are GC'ed so the problem is rather unlikely to occur.
053: * </ul>
054: */
055: private static final Executor DefaultExecutor = Executors
056: .newSingleThreadExecutor(new DaemonThreadFactory(
057: "MuleDefaultFutureMessageExecutor"));
058:
059: // @GuardedBy(this)
060: private Executor executor;
061:
062: // @GuardedBy(this)
063: private List transformers;
064:
065: public FutureMessageResult(Callable callable) {
066: super (callable);
067: this .executor = DefaultExecutor;
068: }
069:
070: /**
071: * Set an ExecutorService to run this invocation.
072: *
073: * @param e the executor to be used.
074: * @throws IllegalArgumentException when the executor is null or shutdown.
075: */
076: public void setExecutor(Executor e) {
077: if (e == null) {
078: throw new IllegalArgumentException(
079: "Executor must not be null.");
080: }
081:
082: synchronized (this ) {
083: this .executor = e;
084: }
085: }
086:
087: /**
088: * Set a post-invocation transformer.
089: *
090: * @param t UMOTransformers to be applied to the result of this invocation. May be
091: * null.
092: */
093: public void setTransformers(List t) {
094: synchronized (this ) {
095: this .transformers = t;
096: }
097: }
098:
099: public MuleMessage getMessage() throws InterruptedException,
100: ExecutionException, TransformerException {
101: return this .getMessage(this .get());
102: }
103:
104: public MuleMessage getMessage(long timeout)
105: throws InterruptedException, ExecutionException,
106: TimeoutException, TransformerException {
107: return this
108: .getMessage(this .get(timeout, TimeUnit.MILLISECONDS));
109: }
110:
111: private MuleMessage getMessage(Object obj)
112: throws TransformerException {
113: MuleMessage result = null;
114: if (obj != null) {
115: if (obj instanceof MuleMessage) {
116: result = (MuleMessage) obj;
117: } else {
118: result = new DefaultMuleMessage(obj);
119: }
120:
121: synchronized (this ) {
122: if (transformers != null) {
123: result.applyTransformers(transformers);
124: }
125: }
126:
127: }
128: return result;
129: }
130:
131: /**
132: * Start asynchronous execution of this task
133: */
134: public void execute() {
135: synchronized (this) {
136: executor.execute(this);
137: }
138: }
139:
140: }
|