Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FutureMessageResult |
|
| 2.0;2 |
1 | /* | |
2 | * $Id: FutureMessageResult.java 7963 2007-08-21 08:53:15Z dirk.olmes $ | |
3 | * -------------------------------------------------------------------------------------- | |
4 | * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com | |
5 | * | |
6 | * The software in this package is published under the terms of the CPAL v1.0 | |
7 | * license, a copy of which has been included with this distribution in the | |
8 | * LICENSE.txt file. | |
9 | */ | |
10 | ||
11 | package org.mule.umo; | |
12 | ||
13 | import org.mule.impl.MuleMessage; | |
14 | import org.mule.umo.transformer.TransformerException; | |
15 | import org.mule.umo.transformer.UMOTransformer; | |
16 | import org.mule.util.concurrent.DaemonThreadFactory; | |
17 | ||
18 | import edu.emory.mathcs.backport.java.util.concurrent.Callable; | |
19 | import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException; | |
20 | import edu.emory.mathcs.backport.java.util.concurrent.Executor; | |
21 | import edu.emory.mathcs.backport.java.util.concurrent.Executors; | |
22 | import edu.emory.mathcs.backport.java.util.concurrent.FutureTask; | |
23 | import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; | |
24 | import edu.emory.mathcs.backport.java.util.concurrent.TimeoutException; | |
25 | ||
26 | /** | |
27 | * <code>FutureMessageResult</code> is an UMOMessage result of a remote invocation | |
28 | * on a Mule Server. This object makes the result available to the client code once | |
29 | * the request has been processed. This execution happens asynchronously. | |
30 | */ | |
31 | // @ThreadSafe | |
32 | public class FutureMessageResult extends FutureTask | |
33 | { | |
34 | /** | |
35 | * This is a simple default Executor for FutureMessageResults. Instead of | |
36 | * spawning a Thread for each invocation it uses a single daemon Thread with an | |
37 | * unbounded queue, so "truly" concurrent operation of multiple Futures or | |
38 | * otherwise customized execution behaviour requires calling the | |
39 | * {@link #setExecutor(Executor)} method and passing in a custom {@link Executor}. | |
40 | * This is strongly recommended in order to provide better control over | |
41 | * concurrency, resource consumption and possible overruns. | |
42 | * <p> | |
43 | * Reasons for these defaults: | |
44 | * <ul> | |
45 | * <li> a daemon thread does not block the VM on shutdown; lifecycle control | |
46 | * should be done elsewhere (e.g. the provider of the custom ExecutorService), | |
47 | * otherwise this class would become too overloaded | |
48 | * <li> a single thread provides for conservative & predictable yet async | |
49 | * behaviour from a client's point of view | |
50 | * <li> the unbounded queue is not optimal but probably harmless since e.g. a | |
51 | * MuleClient would have to create a LOT of Futures for an OOM. Cancelled/timed | |
52 | * out invocations are GC'ed so the problem is rather unlikely to occur. | |
53 | * </ul> | |
54 | */ | |
55 | 2 | private static final Executor DefaultExecutor = Executors.newSingleThreadExecutor( |
56 | new DaemonThreadFactory("MuleDefaultFutureMessageExecutor")); | |
57 | ||
58 | // @GuardedBy(this) | |
59 | private Executor executor; | |
60 | ||
61 | // @GuardedBy(this) | |
62 | private UMOTransformer transformer; | |
63 | ||
64 | public FutureMessageResult(Callable callable) | |
65 | { | |
66 | 10 | super(callable); |
67 | 8 | this.executor = DefaultExecutor; |
68 | 8 | } |
69 | ||
70 | /** | |
71 | * Set an ExecutorService to run this invocation. | |
72 | * | |
73 | * @param e the executor to be used. | |
74 | * @throws IllegalArgumentException when the executor is null or shutdown. | |
75 | */ | |
76 | public void setExecutor(Executor e) | |
77 | { | |
78 | 4 | if (e == null) |
79 | { | |
80 | 2 | throw new IllegalArgumentException("Executor must not be null."); |
81 | } | |
82 | ||
83 | 2 | synchronized (this) |
84 | { | |
85 | 2 | this.executor = e; |
86 | 2 | } |
87 | 2 | } |
88 | ||
89 | /** | |
90 | * Set a post-invocation transformer. | |
91 | * | |
92 | * @param t UMOTransformer to be applied to the result of this invocation. May be | |
93 | * null. | |
94 | */ | |
95 | public void setTransformer(UMOTransformer t) | |
96 | { | |
97 | 0 | synchronized (this) |
98 | { | |
99 | 0 | this.transformer = t; |
100 | 0 | } |
101 | 0 | } |
102 | ||
103 | public UMOMessage getMessage() throws InterruptedException, ExecutionException, TransformerException | |
104 | { | |
105 | 2 | return this.getMessage(this.get()); |
106 | } | |
107 | ||
108 | public UMOMessage getMessage(long timeout) | |
109 | throws InterruptedException, ExecutionException, TimeoutException, TransformerException | |
110 | { | |
111 | 2 | return this.getMessage(this.get(timeout, TimeUnit.MILLISECONDS)); |
112 | } | |
113 | ||
114 | private UMOMessage getMessage(Object obj) throws TransformerException | |
115 | { | |
116 | 2 | if (obj != null) |
117 | { | |
118 | 0 | if (obj instanceof UMOMessage) |
119 | { | |
120 | 0 | return (UMOMessage)obj; |
121 | } | |
122 | ||
123 | 0 | synchronized (this) |
124 | { | |
125 | 0 | if (transformer != null) |
126 | { | |
127 | 0 | obj = transformer.transform(obj); |
128 | } | |
129 | 0 | } |
130 | ||
131 | 0 | return new MuleMessage(obj); |
132 | } | |
133 | else | |
134 | { | |
135 | 2 | return null; |
136 | } | |
137 | } | |
138 | ||
139 | /** | |
140 | * Start asynchronous execution of this task | |
141 | */ | |
142 | public void execute() | |
143 | { | |
144 | 6 | synchronized (this) |
145 | { | |
146 | 6 | executor.execute(this); |
147 | 4 | } |
148 | 4 | } |
149 | ||
150 | } |