Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'JGRP-1141' (typed RpcDispatcher methods)

  • Loading branch information...
commit 63307a835da0a62bf271d2991393e9a7fffbd105 2 parents 492a6dc + a310c3f
Bela Ban authored

Showing 26 changed files with 360 additions and 613 deletions. Show diff stats Hide diff stats

  1. +46 0 doc/API_Changes.txt
  2. +25 21 src/org/jgroups/blocks/GroupRequest.java
  3. +14 10 src/org/jgroups/blocks/MessageDispatcher.java
  4. +0 378 src/org/jgroups/blocks/MultiRequest.java
  5. +1 1  src/org/jgroups/blocks/ReplCache.java
  6. +1 1  src/org/jgroups/blocks/Request.java
  7. +25 11 src/org/jgroups/blocks/RequestCorrelator.java
  8. +1 1  src/org/jgroups/blocks/RequestHandler.java
  9. +27 41 src/org/jgroups/blocks/RpcDispatcher.java
  10. +1 1  src/org/jgroups/blocks/RspCollector.java
  11. +18 17 src/org/jgroups/blocks/UnicastRequest.java
  12. +1 1  src/org/jgroups/blocks/mux/MuxMessageDispatcher.java
  13. +1 1  src/org/jgroups/blocks/mux/MuxRpcDispatcher.java
  14. +10 12 src/org/jgroups/demos/QuoteClient.java
  15. +1 1  src/org/jgroups/demos/RelayDemoRpc.java
  16. +43 13 src/org/jgroups/util/Rsp.java
  17. +38 40 src/org/jgroups/util/RspList.java
  18. +2 2 tests/junit-functional/org/jgroups/blocks/GroupRequestTest.java
  19. +1 1  tests/junit-functional/org/jgroups/tests/RspListTest.java
  20. +2 2 tests/junit/org/jgroups/blocks/MuxMessageDispatcherTest.java
  21. +2 2 tests/junit/org/jgroups/blocks/MuxRpcDispatcherTest.java
  22. +4 4 tests/junit/org/jgroups/blocks/RpcDispatcherSerializationTest.java
  23. +80 40 tests/junit/org/jgroups/blocks/RpcDispatcherTest.java
  24. +1 1  tests/junit/org/jgroups/tests/ChannelTestBase.java
  25. +13 9 tests/junit/org/jgroups/tests/Deadlock2Test.java
  26. +2 2 tests/other/org/jgroups/tests/UnicastTestRpcDist.java
46 doc/API_Changes.txt
@@ -49,6 +49,52 @@ API changes in 3.0.0
49 49
50 50 - Removed Address.isMulticastAddress(): a null address is a multicast address
51 51
  52 +- Rsp, RspList, RpcDispatcher.callRemoteMethodsXXX() and MessageDispatcher.cast/sendXXX() methods now use
  53 + generics, so the code below:
  54 +
  55 + RspList rsps=disp.callRemoteMethods(null, call, new RequestOptions(ResponseMode.GET_ALL, 5000));
  56 + for(Map.Entry<Address,Rsp> rsp: rsps.entrySet())
  57 + System.out.println(rsp.getKey() + ": " + rsp.getValue().getValue());
  58 +
  59 + has to be changed to:
  60 +
  61 + RspList<Date> rsps=disp.callRemoteMethods(null, call, new RequestOptions(ResponseMode.GET_ALL, 5000));
  62 + for(Map.Entry<Address,Rsp<Date>> rsp: rsps.entrySet())
  63 + System.out.println(rsp.getKey() + ": " + rsp.getValue().getValue());
  64 +
  65 +- RpcDispatcher.callRemoteMethod() now throws an exception if the target method threw an exception
  66 +
  67 +- RpcDispatcher.callRemoteMethods() return a RspList. If a member P threw an exception, then the Rsp for
  68 + P will have it in the field 'exception'. The 'result' field is *not* used for exceptions any longer !
  69 +
  70 + An example to check for exceptions is:
  71 +
  72 +
  73 + Multicast:
  74 +
  75 + RspList<Long> rsps=dispatcher.callRemoteMethods(null, "foo", null, null, new RequestOptions(...));
  76 + for(Rsp<Long> rsp: rsps.values) {
  77 + if(rsp.getException() != null) {
  78 + // we have an exception
  79 + }
  80 + else {
  81 + Long val=rsp.getValue();
  82 + // do something with the value
  83 + }
  84 + }
  85 +
  86 + Unicast:
  87 +
  88 + try {
  89 + Rsp<Long> rsp=disp.callRemoteMethod(target, "foo", null, null, new RequestOptions(...));
  90 + Long val=rsp.getValue();
  91 + // do something with the return value
  92 + }
  93 + catch(Throwable t) {
  94 + // "foo" threw an exception
  95 + }
  96 +
  97 +
52 98
53 99
54 100
46 src/org/jgroups/blocks/GroupRequest.java
@@ -48,11 +48,11 @@
48 48 *
49 49 * @author Bela Ban
50 50 */
51   -public class GroupRequest extends Request {
  51 +public class GroupRequest<T> extends Request {
52 52
53 53 /** Correlates requests and responses */
54 54 @GuardedBy("lock")
55   - private final Map<Address,Rsp> requests;
  55 + private final Map<Address,Rsp<T>> requests;
56 56
57 57 @GuardedBy("lock")
58 58 int num_received, num_not_received, num_suspected;
@@ -72,13 +72,13 @@
72 72 public GroupRequest(Message msg, RequestCorrelator corr, Collection<Address> targets, RequestOptions options) {
73 73 super(msg, corr, null, options);
74 74 int size=targets.size();
75   - requests=new HashMap<Address,Rsp>(size);
  75 + requests=new HashMap<Address,Rsp<T>>(size);
76 76 setTargets(targets);
77 77 }
78 78
79 79 public GroupRequest(Message m, RequestCorrelator corr, Address target, RequestOptions options) {
80 80 super(m, corr, null, options);
81   - requests=new HashMap<Address,Rsp>(1);
  81 + requests=new HashMap<Address,Rsp<T>>(1);
82 82 setTarget(target);
83 83 }
84 84
@@ -86,7 +86,7 @@ public GroupRequest(Message m, RequestCorrelator corr, Address target, RequestOp
86 86 public GroupRequest(Message m, Transport transport, Collection<Address> mbrs, RequestOptions options) {
87 87 super(m, null, transport, options);
88 88 int size=mbrs.size();
89   - requests=new HashMap<Address,Rsp>(size);
  89 + requests=new HashMap<Address,Rsp<T>>(size);
90 90 setTargets(mbrs);
91 91 }
92 92
@@ -111,18 +111,22 @@ public void sendRequest() throws Exception {
111 111 * Adds a response to the response table. When all responses have been received,
112 112 * <code>execute()</code> returns.
113 113 */
114   - public void receiveResponse(Object response_value, Address sender) {
  114 + public void receiveResponse(Object response_value, Address sender, boolean is_exception) {
115 115 if(done)
116 116 return;
117   - Rsp rsp=requests.get(sender);
  117 + Rsp<T> rsp=requests.get(sender);
118 118 if(rsp == null)
119 119 return;
120 120
121 121 RspFilter rsp_filter=options.getRspFilter();
122 122 boolean responseReceived=false;
123 123 if(!rsp.wasReceived()) {
124   - if((responseReceived=(rsp_filter == null) || rsp_filter.isAcceptable(response_value, sender)))
125   - rsp.setValue(response_value);
  124 + if((responseReceived=(rsp_filter == null) || rsp_filter.isAcceptable(response_value, sender))) {
  125 + if(is_exception && response_value instanceof Throwable)
  126 + rsp.setException((Throwable)response_value);
  127 + else
  128 + rsp.setValue((T)response_value);
  129 + }
126 130 rsp.setReceived(responseReceived);
127 131 }
128 132
@@ -155,7 +159,7 @@ public void suspect(Address suspected_member) {
155 159 return;
156 160
157 161 boolean changed=false;
158   - Rsp rsp=requests.get(suspected_member);
  162 + Rsp<T> rsp=requests.get(suspected_member);
159 163 if(rsp != null) {
160 164 if(rsp.setSuspected(true)) {
161 165 rsp.setValue(null);
@@ -204,10 +208,10 @@ public void viewChange(View new_view) {
204 208
205 209 lock.lock();
206 210 try {
207   - for(Map.Entry<Address,Rsp> entry: requests.entrySet()) {
  211 + for(Map.Entry<Address,Rsp<T>> entry: requests.entrySet()) {
208 212 Address mbr=entry.getKey();
209 213 if(!mbrs.contains(mbr)) {
210   - Rsp rsp=entry.getValue();
  214 + Rsp<T> rsp=entry.getValue();
211 215 rsp.setValue(null);
212 216 if(rsp.setSuspected(true)) {
213 217 num_suspected++;
@@ -231,14 +235,14 @@ public void viewChange(View new_view) {
231 235
232 236
233 237 /** Returns the results as a RspList */
234   - public RspList getResults() {
235   - Collection<Rsp> rsps=requests.values();
236   - return new RspList(rsps);
  238 + public RspList<T> getResults() {
  239 + Collection<Rsp<T>> rsps=requests.values();
  240 + return new RspList<T>(rsps);
237 241 }
238 242
239 243
240 244
241   - public RspList get() throws InterruptedException, ExecutionException {
  245 + public RspList<T> get() throws InterruptedException, ExecutionException {
242 246 lock.lock();
243 247 try {
244 248 waitForResults(0);
@@ -249,7 +253,7 @@ public RspList get() throws InterruptedException, ExecutionException {
249 253 return getResults();
250 254 }
251 255
252   - public RspList get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
  256 + public RspList<T> get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
253 257 boolean ok;
254 258 lock.lock();
255 259 try {
@@ -269,9 +273,9 @@ public String toString() {
269 273
270 274 if(!requests.isEmpty()) {
271 275 ret.append(", entries:\n");
272   - for(Map.Entry<Address,Rsp> entry: requests.entrySet()) {
  276 + for(Map.Entry<Address,Rsp<T>> entry: requests.entrySet()) {
273 277 Address mbr=entry.getKey();
274   - Rsp rsp=entry.getValue();
  278 + Rsp<T> rsp=entry.getValue();
275 279 ret.append(mbr).append(": ").append(rsp).append("\n");
276 280 }
277 281 }
@@ -282,13 +286,13 @@ public String toString() {
282 286 /* --------------------------------- Private Methods -------------------------------------*/
283 287
284 288 private void setTarget(Address mbr) {
285   - requests.put(mbr, new Rsp(mbr));
  289 + requests.put(mbr, new Rsp<T>(mbr));
286 290 num_not_received=1;
287 291 }
288 292
289 293 private void setTargets(Collection<Address> mbrs) {
290 294 for(Address mbr: mbrs)
291   - requests.put(mbr, new Rsp(mbr));
  295 + requests.put(mbr, new Rsp<T>(mbr));
292 296 num_not_received=requests.size();
293 297 }
294 298
24 src/org/jgroups/blocks/MessageDispatcher.java
@@ -236,18 +236,18 @@ else if (canReplace) {
236 236 * @return
237 237 * @since 2.9
238 238 */
239   - public RspList castMessage(final Collection<Address> dests, Message msg, RequestOptions options) {
240   - GroupRequest req=cast(dests, msg, options, true);
  239 + public <T> RspList<T> castMessage(final Collection<Address> dests, Message msg, RequestOptions options) {
  240 + GroupRequest<T> req=cast(dests, msg, options, true);
241 241 return req != null? req.getResults() : RspList.EMPTY_RSP_LIST;
242 242 }
243 243
244 244
245   - public NotifyingFuture<RspList> castMessageWithFuture(final Collection<Address> dests, Message msg, RequestOptions options) {
246   - GroupRequest req=cast(dests, msg, options, false);
  245 + public <T> NotifyingFuture<RspList<T>> castMessageWithFuture(final Collection<Address> dests, Message msg, RequestOptions options) {
  246 + GroupRequest<T> req=cast(dests, msg, options, false);
247 247 return req != null? req : new NullFuture<RspList>(RspList.EMPTY_RSP_LIST);
248 248 }
249 249
250   - protected GroupRequest cast(final Collection<Address> dests, Message msg, RequestOptions options, boolean block_for_results) {
  250 + protected <T> GroupRequest<T> cast(final Collection<Address> dests, Message msg, RequestOptions options, boolean block_for_results) {
251 251 List<Address> real_dests;
252 252
253 253 // we need to clone because we don't want to modify the original
@@ -289,7 +289,7 @@ protected GroupRequest cast(final Collection<Address> dests, Message msg, Reques
289 289 return null;
290 290 }
291 291
292   - GroupRequest req=new GroupRequest(msg, corr, real_dests, options);
  292 + GroupRequest<T> req=new GroupRequest<T>(msg, corr, real_dests, options);
293 293 if(options != null) {
294 294 req.setResponseFilter(options.getRspFilter());
295 295 req.setAnycasting(options.getAnycasting());
@@ -315,7 +315,7 @@ public void done(long req_id) {
315 315
316 316
317 317
318   - public Object sendMessage(Message msg, RequestOptions opts) throws TimeoutException, SuspectedException {
  318 + public <T> T sendMessage(Message msg, RequestOptions opts) throws Throwable {
319 319 Address dest=msg.getDest();
320 320 if(dest == null) {
321 321 if(log.isErrorEnabled())
@@ -329,7 +329,7 @@ public Object sendMessage(Message msg, RequestOptions opts) throws TimeoutExcept
329 329 msg.setScope(opts.getScope());
330 330 }
331 331
332   - UnicastRequest req=new UnicastRequest(msg, corr, dest, opts);
  332 + UnicastRequest<T> req=new UnicastRequest<T>(msg, corr, dest, opts);
333 333 try {
334 334 req.execute();
335 335 }
@@ -340,9 +340,13 @@ public Object sendMessage(Message msg, RequestOptions opts) throws TimeoutExcept
340 340 if(opts != null && opts.getMode() == ResponseMode.GET_NONE)
341 341 return null;
342 342
343   - Rsp rsp=req.getResult();
  343 + Rsp<T> rsp=req.getResult();
344 344 if(rsp.wasSuspected())
345 345 throw new SuspectedException(dest);
  346 +
  347 + if(rsp.getException() != null)
  348 + throw rsp.getException();
  349 +
346 350 if(!rsp.wasReceived())
347 351 throw new TimeoutException("timeout sending message to " + dest);
348 352 return rsp.getValue();
@@ -379,7 +383,7 @@ public Object sendMessage(Message msg, RequestOptions opts) throws TimeoutExcept
379 383
380 384
381 385 /* ------------------------ RequestHandler Interface ---------------------- */
382   - public Object handle(Message msg) {
  386 + public Object handle(Message msg) throws Throwable {
383 387 if(req_handler != null) {
384 388 return req_handler.handle(msg);
385 389 }
378 src/org/jgroups/blocks/MultiRequest.java
... ... @@ -1,378 +0,0 @@
1   -package org.jgroups.blocks;
2   -
3   -
4   -import org.jgroups.Address;
5   -import org.jgroups.Message;
6   -import org.jgroups.Transport;
7   -import org.jgroups.View;
8   -import org.jgroups.annotations.GuardedBy;
9   -import org.jgroups.util.Rsp;
10   -import org.jgroups.util.RspList;
11   -
12   -import java.util.*;
13   -import java.util.concurrent.ExecutionException;
14   -import java.util.concurrent.TimeUnit;
15   -import java.util.concurrent.TimeoutException;
16   -
17   -
18   -/**
19   - * Sends a request to multiple destinations. Alternative implementation when we have few targets: between UnicastRequest
20   - * with 1 target and GroupRequest with many destination members. Performance is about the same as for GroupRequest, but
21   - * this class should use less memory as it doesn't create hashmaps. Don't use with many targets as we have to do
22   - * a linear search through an array of targets to match a response to a request.<p/>
23   - * MultiRequest is currently not used
24   - *
25   - * @author Bela Ban
26   - * @since 2.9
27   - */
28   -public class MultiRequest extends Request {
29   - @GuardedBy("lock")
30   - private final Rsp[] responses;
31   -
32   - protected final int expected_mbrs;
33   -
34   - @GuardedBy("lock")
35   - int num_received, num_not_received, num_suspected;
36   -
37   -
38   -
39   - /**
40   - * @param m
41   - * The message to be sent
42   - * @param corr
43   - * The request correlator to be used. A request correlator
44   - * sends requests tagged with a unique ID and notifies the
45   - * sender when matching responses are received. The reason
46   - * <code>GroupRequest</code> uses it instead of a
47   - * <code>Transport</code> is that multiple
48   - * requests/responses might be sent/received concurrently.
49   - * @param mbrs
50   - * The initial membership. This value reflects the membership
51   - * to which the request is sent (and from which potential
52   - * responses are expected). Is reset by reset().
53   - * @param options The options to be passed to the request
54   - */
55   - public MultiRequest(Message m, RequestCorrelator corr, Collection<Address> mbrs, RequestOptions options, int expected_mbrs) {
56   - super(m, corr, null, options);
57   - this.expected_mbrs=expected_mbrs;
58   - responses=new Rsp[mbrs.size()];
59   - setTargets(mbrs);
60   - }
61   -
62   - public MultiRequest(Message m, RequestCorrelator corr, Address target, RequestOptions options, int expected_mbrs) {
63   - super(m, corr, null, options);
64   - this.expected_mbrs=expected_mbrs;
65   - responses=new Rsp[1];
66   - setTarget(target);
67   - }
68   -
69   -
70   -
71   - /**
72   - * @param timeout Time to wait for responses (ms). A value of <= 0 means wait indefinitely
73   - * (e.g. if a suspicion service is available; timeouts are not needed).
74   - */
75   - public MultiRequest(Message m, Transport transport, Collection<Address> mbrs, RequestOptions options, int expected_mbrs) {
76   - super(m, null, transport, options);
77   - this.expected_mbrs=expected_mbrs;
78   - responses=new Rsp[1];
79   - setTargets(mbrs);
80   - }
81   -
82   - void setTarget(Address mbr) {
83   - responses[0]=new Rsp(mbr);
84   - num_not_received++;
85   - }
86   -
87   - void setTargets(Collection<Address> mbrs) {
88   - int index=0;
89   - for(Address mbr: mbrs) {
90   - responses[index++]=new Rsp(mbr);
91   - num_not_received++;
92   - }
93   - }
94   -
95   - public boolean getAnycasting() {
96   - return options.getAnycasting();
97   - }
98   -
99   - public void setAnycasting(boolean anycasting) {
100   - options.setAnycasting(anycasting);
101   - }
102   -
103   -
104   -
105   - public void sendRequest() throws Exception {
106   - List<Address> targets=null;
107   - targets=new ArrayList<Address>(responses.length);
108   - for(Rsp rsp: responses)
109   - targets.add(rsp.getSender());
110   -
111   - sendRequest(targets, req_id, options);
112   - }
113   -
114   - Rsp findResponse(Address target) {
115   - for(Rsp rsp: responses) {
116   - if(rsp != null && target.equals(rsp.getSender()))
117   - return rsp;
118   - }
119   - return null;
120   - }
121   -
122   - /* ---------------------- Interface RspCollector -------------------------- */
123   - /**
124   - * <b>Callback</b> (called by RequestCorrelator or Transport).
125   - * Adds a response to the response table. When all responses have been received,
126   - * <code>execute()</code> returns.
127   - */
128   - public void receiveResponse(Object response_value, Address sender) {
129   - if(done)
130   - return;
131   - Rsp rsp=findResponse(sender);
132   - if(rsp == null)
133   - return;
134   -
135   - RspFilter rsp_filter=options.getRspFilter();
136   - boolean responseReceived=false;
137   - if(!rsp.wasReceived()) {
138   - if((responseReceived=(rsp_filter == null) || rsp_filter.isAcceptable(response_value, sender)))
139   - rsp.setValue(response_value);
140   - rsp.setReceived(responseReceived);
141   - }
142   -
143   - lock.lock();
144   - try {
145   - if(responseReceived)
146   - num_received++;
147   - done=rsp_filter == null? responsesComplete() : !rsp_filter.needMoreResponses();
148   - if(responseReceived || done)
149   - completed.signalAll(); // wakes up execute()
150   - if(done && corr != null)
151   - corr.done(req_id);
152   - }
153   - finally {
154   - lock.unlock();
155   - }
156   - if(responseReceived || done)
157   - checkCompletion(this);
158   - }
159   -
160   -
161   - /**
162   - * <b>Callback</b> (called by RequestCorrelator or Transport).
163   - * Report to <code>GroupRequest</code> that a member is reported as faulty (suspected).
164   - * This method would probably be called when getting a suspect message from a failure detector
165   - * (where available). It is used to exclude faulty members from the response list.
166   - */
167   - public void suspect(Address suspected_member) {
168   - if(suspected_member == null)
169   - return;
170   -
171   - boolean changed=false;
172   - Rsp rsp=findResponse(suspected_member);
173   - if(rsp != null) {
174   - if(rsp.setSuspected(true)) {
175   - rsp.setValue(null);
176   - changed=true;
177   - lock.lock();
178   - try {
179   - num_suspected++;
180   - completed.signalAll();
181   - }
182   - finally {
183   - lock.unlock();
184   - }
185   - }
186   - }
187   -
188   - if(changed)
189   - checkCompletion(this);
190   - }
191   -
192   -
193   - /**
194   - * Any member of 'membership' that is not in the new view is flagged as
195   - * SUSPECTED. Any member in the new view that is <em>not</em> in the
196   - * membership (ie, the set of responses expected for the current RPC) will
197   - * <em>not</em> be added to it. If we did this we might run into the
198   - * following problem:
199   - * <ul>
200   - * <li>Membership is {A,B}
201   - * <li>A sends a synchronous group RPC (which sleeps for 60 secs in the
202   - * invocation handler)
203   - * <li>C joins while A waits for responses from A and B
204   - * <li>If this would generate a new view {A,B,C} and if this expanded the
205   - * response set to {A,B,C}, A would wait forever on C's response because C
206   - * never received the request in the first place, therefore won't send a
207   - * response.
208   - * </ul>
209   - */
210   - public void viewChange(View new_view) {
211   - List<Address> mbrs=new_view != null? new_view.getMembers() : null;
212   - if(mbrs == null)
213   - return;
214   -
215   - boolean changed=false;
216   - if(responses == null || responses.length == 0)
217   - return;
218   -
219   - lock.lock();
220   - try {
221   - for(Rsp rsp: responses) {
222   - Address mbr=rsp.getSender();
223   - if(!mbrs.contains(mbr)) {
224   - rsp.setValue(null);
225   - if(rsp.setSuspected(true)) {
226   - num_suspected++;
227   - changed=true;
228   - }
229   - }
230   - }
231   - if(changed)
232   - completed.signalAll();
233   - }
234   - finally {
235   - lock.unlock();
236   - }
237   - if(changed)
238   - checkCompletion(this);
239   - }
240   -
241   -
242   - /* -------------------- End of Interface RspCollector ----------------------------------- */
243   -
244   -
245   -
246   - /** Returns the results as a RspList */
247   - public RspList getResults() {
248   - RspList list=new RspList();
249   - for(Rsp rsp: responses)
250   - list.put(rsp.getSender(), rsp);
251   - return list;
252   - }
253   -
254   -
255   -
256   - public RspList get() throws InterruptedException, ExecutionException {
257   - lock.lock();
258   - try {
259   - waitForResults(0);
260   - }
261   - finally {
262   - lock.unlock();
263   - }
264   - return getResults();
265   - }
266   -
267   - public RspList get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
268   - boolean ok;
269   - lock.lock();
270   - try {
271   - ok=waitForResults(unit.toMillis(timeout));
272   - }
273   - finally {
274   - lock.unlock();
275   - }
276   - if(!ok)
277   - throw new TimeoutException();
278   - return getResults();
279   - }
280   -
281   - public String toString() {
282   - StringBuilder ret=new StringBuilder(128);
283   - ret.append(super.toString());
284   -
285   - lock.lock();
286   - try {
287   - if(!(responses.length == 0)) {
288   - ret.append(", entries:\n");
289   - for(Rsp rsp: responses) {
290   - Address mbr=rsp.getSender();
291   - ret.append(mbr).append(": ").append(rsp).append("\n");
292   - }
293   - }
294   - }
295   - finally {
296   - lock.unlock();
297   - }
298   - return ret.toString();
299   - }
300   -
301   -
302   -
303   -
304   - /* --------------------------------- Private Methods -------------------------------------*/
305   -
306   - private static int determineMajority(int i) {
307   - return i < 2? i : (i / 2) + 1;
308   - }
309   -
310   -
311   -
312   -
313   - private void sendRequest(List<Address> targetMembers, long requestId, RequestOptions options) throws Exception {
314   - try {
315   - if(log.isTraceEnabled()) log.trace(new StringBuilder("sending request (id=").append(req_id).append(')'));
316   - if(corr != null) {
317   - corr.sendRequest(requestId, targetMembers, request_msg, options.getMode() == ResponseMode.GET_NONE? null : this, options);
318   - }
319   - else {
320   - if(options.getAnycasting()) {
321   - for(Address mbr: targetMembers) {
322   - Message copy=request_msg.copy(true);
323   - copy.setDest(mbr);
324   - transport.send(copy);
325   - }
326   - }
327   - else {
328   - transport.send(request_msg);
329   - }
330   - }
331   - }
332   - catch(Exception ex) {
333   - if(corr != null)
334   - corr.done(requestId);
335   - throw ex;
336   - }
337   - }
338   -
339   -
340   - @GuardedBy("lock")
341   - protected boolean responsesComplete() {
342   - if(done)
343   - return true;
344   -
345   - final int num_total=responses.length;
346   -
347   - switch(options.getMode()) {
348   - case GET_FIRST:
349   - if(num_received > 0)
350   - return true;
351   - if(num_suspected >= num_total)
352   - // e.g. 2 members, and both suspected
353   - return true;
354   - break;
355   - case GET_ALL:
356   - return num_received + num_suspected >= num_total;
357   - case GET_MAJORITY:
358   - int majority=determineMajority(num_total);
359   - if(num_received + num_suspected >= majority)
360   - return true;
361   - break;
362   - case GET_ABS_MAJORITY:
363   - majority=determineMajority(num_total);
364   - if(num_received >= majority)
365   - return true;
366   - break;
367   - case GET_NONE:
368   - return true;
369   - default :
370   - if(log.isErrorEnabled()) log.error("rsp_mode " + options.getMode() + " unknown !");
371   - break;
372   - }
373   - return false;
374   - }
375   -
376   -
377   -
378   -}
2  src/org/jgroups/blocks/ReplCache.java
@@ -423,7 +423,7 @@ public V get(K key) {
423 423
424 424 // 3. Execute a cluster wide GET
425 425 try {
426   - RspList rsps=disp.callRemoteMethods(null,
  426 + RspList<Object> rsps=disp.callRemoteMethods(null,
427 427 new MethodCall(GET, key),
428 428 new RequestOptions(ResponseMode.GET_ALL, call_timeout));
429 429 for(Rsp rsp: rsps.values()) {
2  src/org/jgroups/blocks/Request.java
@@ -99,7 +99,7 @@ public boolean execute() throws Exception {
99 99
100 100 protected abstract void sendRequest() throws Exception;
101 101
102   - public abstract void receiveResponse(Object response_value, Address sender);
  102 + public abstract void receiveResponse(Object response_value, Address sender, boolean is_exception);
103 103
104 104 public abstract void viewChange(View new_view);
105 105
36 src/org/jgroups/blocks/RequestCorrelator.java
@@ -381,8 +381,10 @@ public boolean receiveMessage(Message msg) {
381 381 break;
382 382
383 383 case Header.RSP:
  384 + case Header.EXC_RSP:
384 385 RspCollector coll=requests.get(hdr.id);
385 386 if(coll != null) {
  387 + boolean is_exception=hdr.type == Header.EXC_RSP;
386 388 Address sender=msg.getSrc();
387 389 Object retval;
388 390 byte[] buf=msg.getBuffer();
@@ -394,8 +396,9 @@ public boolean receiveMessage(Message msg) {
394 396 catch(Exception e) {
395 397 log.error("failed unmarshalling buffer into return value", e);
396 398 retval=e;
  399 + is_exception=true;
397 400 }
398   - coll.receiveResponse(retval, sender);
  401 + coll.receiveResponse(retval, sender, is_exception);
399 402 }
400 403 break;
401 404
@@ -452,6 +455,7 @@ protected void handleRequest(Message req, Header hdr) {
452 455 Object rsp_buf; // either byte[] or Buffer
453 456 Header rsp_hdr;
454 457 Message rsp;
  458 + boolean threw_exception=false;
455 459
456 460 // i. Get the request correlator header from the msg and pass it to
457 461 // the registered handler
@@ -469,7 +473,8 @@ protected void handleRequest(Message req, Header hdr) {
469 473 retval=request_handler.handle(req);
470 474 }
471 475 catch(Throwable t) {
472   - if(log.isErrorEnabled()) log.error("error invoking method", t);
  476 + // if(log.isErrorEnabled()) log.error("error invoking method", t);
  477 + threw_exception=true;
473 478 retval=t;
474 479 }
475 480
@@ -488,6 +493,7 @@ protected void handleRequest(Message req, Header hdr) {
488 493 catch(Throwable t) {
489 494 try { // this call should succeed (all exceptions are serializable)
490 495 rsp_buf=marshaller != null? marshaller.objectToBuffer(t) : Util.objectToByteBuffer(t);
  496 + threw_exception=true;
491 497 }
492 498 catch(Throwable tt) {
493 499 if(log.isErrorEnabled()) log.error("failed sending rsp: return value (" + retval + ") is not serializable");
@@ -510,7 +516,8 @@ protected void handleRequest(Message req, Header hdr) {
510 516 rsp.setBuffer((Buffer)rsp_buf);
511 517 else if (rsp_buf instanceof byte[])
512 518 rsp.setBuffer((byte[])rsp_buf);
513   - rsp_hdr=new Header(Header.RSP, hdr.id, false, this.id);
  519 +
  520 + rsp_hdr=new Header(threw_exception? Header.EXC_RSP : Header.RSP, hdr.id, false, this.id);
514 521 rsp.putHeader(this.id, rsp_hdr);
515 522 if(log.isTraceEnabled())
516 523 log.trace(new StringBuilder("sending rsp for ").append(rsp_hdr.id).append(" to ").append(rsp.getDest()));
@@ -543,8 +550,9 @@ protected void prepareResponse(Message rsp) {
543 550 * The header for <tt>RequestCorrelator</tt> messages
544 551 */
545 552 public static class Header extends org.jgroups.Header {
546   - public static final byte REQ = 0;
547   - public static final byte RSP = 1;
  553 + public static final byte REQ = 0;
  554 + public static final byte RSP = 1;
  555 + public static final byte EXC_RSP = 2; // exception
548 556
549 557 /** Type of header: request or reply */
550 558 public byte type;
@@ -579,12 +587,18 @@ public Header(byte type, long id, boolean rsp_expected, short corr_id) {
579 587 this.corrId = corr_id;
580 588 }
581 589
582   - /**
583   - */
584 590 public String toString() {
585 591 StringBuilder ret=new StringBuilder();
586 592 ret.append("id=" + corrId + ", type=");
587   - ret.append(type == REQ ? "REQ" : type == RSP ? "RSP" : "<unknown>");
  593 + switch(type) {
  594 + case REQ: ret.append("REQ");
  595 + break;
  596 + case RSP: ret.append("RSP");
  597 + break;
  598 + case EXC_RSP: ret.append("EXC_RSP");
  599 + break;
  600 + default: ret.append("<unknown>");
  601 + }
588 602 ret.append(", id=" + id);
589 603 ret.append(", rsp_expected=" + rsp_expected);
590 604 return ret.toString();
@@ -607,9 +621,9 @@ public void readFrom(DataInput in) throws IOException, IllegalAccessException, I
607 621
608 622 public int size() {
609 623 return Global.BYTE_SIZE // type
610   - + Global.LONG_SIZE // id
611   - + Global.BYTE_SIZE // rsp_expected
612   - + Global.SHORT_SIZE; // corrId
  624 + + Global.LONG_SIZE // id
  625 + + Global.BYTE_SIZE // rsp_expected
  626 + + Global.SHORT_SIZE; // corrId
613 627 }
614 628 }
615 629
2  src/org/jgroups/blocks/RequestHandler.java
@@ -6,5 +6,5 @@
6 6
7 7
8 8 public interface RequestHandler {
9   - Object handle(Message msg);
  9 + Object handle(Message msg) throws Throwable;
10 10 }
68 src/org/jgroups/blocks/RpcDispatcher.java
@@ -103,8 +103,8 @@ public void setMethodLookup(MethodLookup method_lookup) {
103 103
104 104
105 105
106   - public RspList callRemoteMethods(Collection<Address> dests, String method_name, Object[] args,
107   - Class[] types, RequestOptions options) {
  106 + public <T> RspList<T> callRemoteMethods(Collection<Address> dests, String method_name, Object[] args,
  107 + Class[] types, RequestOptions options) {
108 108 MethodCall method_call=new MethodCall(method_name, args, types);
109 109 return callRemoteMethods(dests, method_call, options);
110 110 }
@@ -119,7 +119,7 @@ public RspList callRemoteMethods(Collection<Address> dests, String method_name,
119 119 * @return RspList A list of return values and flags (suspected, not received) per member
120 120 * @since 2.9
121 121 */
122   - public RspList callRemoteMethods(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
  122 + public <T> RspList<T> callRemoteMethods(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
123 123 if(dests != null && dests.isEmpty()) { // don't send if dest list is empty
124 124 if(log.isTraceEnabled())
125 125 log.trace(new StringBuilder("destination list of ").append(method_call.getName()).
@@ -153,19 +153,19 @@ public RspList callRemoteMethods(Collection<Address> dests, MethodCall method_ca
153 153 if(options.getScope() > 0)
154 154 msg.setScope(options.getScope());
155 155
156   - RspList retval=super.castMessage(dests, msg, options);
  156 + RspList<T> retval=super.castMessage(dests, msg, options);
157 157 if(log.isTraceEnabled()) log.trace("responses: " + retval);
158 158 return retval;
159 159 }
160 160
161 161
162 162
163   - public NotifyingFuture<RspList> callRemoteMethodsWithFuture(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
  163 + public <T> NotifyingFuture<RspList<T>> callRemoteMethodsWithFuture(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
164 164 if(dests != null && dests.isEmpty()) { // don't send if dest list is empty
165 165 if(log.isTraceEnabled())
166 166 log.trace(new StringBuilder("destination list of ").append(method_call.getName()).
167 167 append("() is empty: no need to send message"));
168   - return new NullFuture<RspList>(RspList.EMPTY_RSP_LIST);
  168 + return new NullFuture<RspList<T>>(RspList.EMPTY_RSP_LIST);
169 169 }
170 170
171 171 if(log.isTraceEnabled())
@@ -193,20 +193,20 @@ public RspList callRemoteMethods(Collection<Address> dests, MethodCall method_ca
193 193 if(options.getScope() > 0)
194 194 msg.setScope(options.getScope());
195 195
196   - NotifyingFuture<RspList> retval=super.castMessageWithFuture(dests, msg, options);
  196 + NotifyingFuture<RspList<T>> retval=super.castMessageWithFuture(dests, msg, options);
197 197 if(log.isTraceEnabled()) log.trace("responses: " + retval);
198 198 return retval;
199 199 }
200 200
201 201
202   - public Object callRemoteMethod(Address dest, String method_name, Object[] args,
  202 + public <T> T callRemoteMethod(Address dest, String method_name, Object[] args,
203 203 Class[] types, RequestOptions options) throws Throwable {
204 204 MethodCall method_call=new MethodCall(method_name, args, types);
205   - return callRemoteMethod(dest, method_call, options);
  205 + return (T)callRemoteMethod(dest, method_call, options);
206 206 }
207 207
208 208
209   - public Object callRemoteMethod(Address dest, MethodCall call, RequestOptions options) throws Throwable {
  209 + public <T> T callRemoteMethod(Address dest, MethodCall call, RequestOptions options) throws Throwable {
210 210 if(log.isTraceEnabled())
211 211 log.trace("dest=" + dest + ", method_call=" + call + ", options=" + options);
212 212
@@ -220,10 +220,8 @@ public Object callRemoteMethod(Address dest, MethodCall call, RequestOptions opt
220 220 if(options.getScope() > 0)
221 221 msg.setScope(options.getScope());
222 222
223   - Object retval=super.sendMessage(msg, options);
  223 + T retval=(T)super.sendMessage(msg, options);
224 224 if(log.isTraceEnabled()) log.trace("retval: " + retval);
225   - if(retval instanceof Throwable)
226   - throw (Throwable)retval;
227 225 return retval;
228 226 }
229 227
@@ -255,7 +253,7 @@ protected void correlatorStarted() {
255 253 * Message contains MethodCall. Execute it against *this* object and return result.
256 254 * Use MethodCall.invoke() to do this. Return result.
257 255 */
258   - public Object handle(Message req) {
  256 + public Object handle(Message req) throws Throwable {
259 257 Object body;
260 258 MethodCall method_call;
261 259
@@ -269,43 +267,31 @@ public Object handle(Message req) {
269 267 return null;
270 268 }
271 269
272   - try {
273   - body=req_marshaller != null?
274   - req_marshaller.objectFromBuffer(req.getBuffer(), req.getOffset(), req.getLength())
275   - : req.getObject();
276   - }
277   - catch(Throwable e) {
278   - if(log.isErrorEnabled()) log.error("exception marshalling object", e);
279   - return e;
280   - }
  270 + body=req_marshaller != null?
  271 + req_marshaller.objectFromBuffer(req.getBuffer(), req.getOffset(), req.getLength()) : req.getObject();
281 272
282 273 if(!(body instanceof MethodCall)) {
283 274 if(log.isErrorEnabled()) log.error("message does not contain a MethodCall object");
284 275
285 276 // create an exception to represent this and return it
286   - return new IllegalArgumentException("message does not contain a MethodCall object") ;
  277 + throw new IllegalArgumentException("message does not contain a MethodCall object") ;
287 278 }
288 279
289 280 method_call=(MethodCall)body;
290 281
291   - try {
292   - if(log.isTraceEnabled())
293   - log.trace("[sender=" + req.getSrc() + "], method_call: " + method_call);
294   -
295   - if(method_call.getMode() == MethodCall.ID) {
296   - if(method_lookup == null)
297   - throw new Exception("MethodCall uses ID=" + method_call.getId() + ", but method_lookup has not been set");
298   - Method m=method_lookup.findMethod(method_call.getId());
299   - if(m == null)
300   - throw new Exception("no method found for " + method_call.getId());
301   - method_call.setMethod(m);
302   - }
303   -
304   - return method_call.invoke(server_obj);
305   - }
306   - catch(Throwable x) {
307   - return x;
  282 + if(log.isTraceEnabled())
  283 + log.trace("[sender=" + req.getSrc() + "], method_call: " + method_call);
  284 +
  285 + if(method_call.getMode() == MethodCall.ID) {
  286 + if(method_lookup == null)
  287 + throw new Exception("MethodCall uses ID=" + method_call.getId() + ", but method_lookup has not been set");
  288 + Method m=method_lookup.findMethod(method_call.getId());
  289 + if(m == null)
  290 + throw new Exception("no method found for " + method_call.getId());
  291 + method_call.setMethod(m);
308 292 }
  293 +
  294 + return method_call.invoke(server_obj);
309 295 }
310 296
311 297 /**
2  src/org/jgroups/blocks/RspCollector.java
@@ -7,7 +7,7 @@
7 7
8 8
9 9 public interface RspCollector {
10   - void receiveResponse(Object response_value, Address sender);
  10 + void receiveResponse(Object response_value, Address sender, boolean is_exception);
11 11 void suspect(Address mbr);
12 12 void viewChange(View new_view);
13 13 }
35 src/org/jgroups/blocks/UnicastRequest.java
@@ -25,25 +25,16 @@
25 25
26 26
27 27
28   - /**
29   - @param timeout Time to wait for responses (ms). A value of <= 0 means wait indefinitely
30   - (e.g. if a suspicion service is available; timeouts are not needed).
31   - */
32 28 public UnicastRequest(Message m, RequestCorrelator corr, Address target, RequestOptions options) {
33 29 super(m, corr, null, options);
34 30 this.target=target;
35   - result=new Rsp(target);
  31 + result=new Rsp<T>(target);
36 32 }
37 33
38   -
39   - /**
40   - * @param timeout Time to wait for responses (ms). A value of <= 0 means wait indefinitely
41   - * (e.g. if a suspicion service is available; timeouts are not needed).
42   - */
43 34 public UnicastRequest(Message m, Transport transport, Address target, RequestOptions options) {
44 35 super(m, null, transport, options);
45 36 this.target=target;
46   - result=new Rsp(target);
  37 + result=new Rsp<T>(target);
47 38 }
48 39
49 40
@@ -71,7 +62,7 @@ protected void sendRequest() throws Exception {
71 62 * Adds a response to the response table. When all responses have been received,
72 63 * <code>execute()</code> returns.
73 64 */
74   - public void receiveResponse(Object response_value, Address sender) {
  65 + public void receiveResponse(Object response_value, Address sender, boolean is_exception) {
75 66 RspFilter rsp_filter=options.getRspFilter();
76 67
77 68 lock.lock();
@@ -80,11 +71,21 @@ public void receiveResponse(Object response_value, Address sender) {
80 71 return;
81 72 if(!result.wasReceived()) {
82 73 boolean responseReceived=(rsp_filter == null) || rsp_filter.isAcceptable(response_value, sender);
83   - result.setValue((T)response_value);
  74 + if(is_exception && response_value instanceof Throwable)
  75 + result.setException((Throwable)response_value);
  76 + else
  77 + result.setValue((T)response_value);
84 78 result.setReceived(responseReceived);
85   - if(log.isTraceEnabled())
86   - log.trace(new StringBuilder("received response for request ").append(req_id)
87   - .append(", sender=").append(sender).append(", val=").append(response_value));
  79 + if(log.isTraceEnabled()) {
  80 + StringBuilder sb=new StringBuilder("received response for request ");
  81 + sb.append(req_id).append(", sender=").append(sender);
  82 + if(is_exception && response_value instanceof Throwable)
  83 + sb.append(", exception=");
  84 + else
  85 + sb.append(", val=");
  86 + sb.append(response_value);
  87 + log.trace(sb.toString());
  88 + }
88 89 }
89 90 done=rsp_filter == null? responsesComplete() : !rsp_filter.needMoreResponses();
90 91 if(done && corr != null)
@@ -155,7 +156,7 @@ public void viewChange(View new_view) {
155 156
156 157 /* -------------------- End of Interface RspCollector ----------------------------------- */
157 158
158   - public Rsp getResult() {
  159 + public Rsp<T> getResult() {
159 160 return result;
160 161 }
161 162
2  src/org/jgroups/blocks/mux/MuxMessageDispatcher.java
@@ -81,7 +81,7 @@ public void stop() {
81 81 }
82 82
83 83 @Override
84   - protected GroupRequest cast(Collection<Address> dests, Message msg, RequestOptions options, boolean blockForResults) {
  84 + protected <T> GroupRequest<T> cast(Collection<Address> dests, Message msg, RequestOptions options, boolean blockForResults) {
85 85 RspFilter filter=options.getRspFilter();
86 86 RequestOptions newOptions = new RequestOptions(options.getMode(), options.getTimeout(), options.getAnycasting(),
87 87 (filter != null) ? new NoMuxHandlerRspFilter(filter) : new NoMuxHandlerRspFilter(),
2  src/org/jgroups/blocks/mux/MuxRpcDispatcher.java
@@ -97,7 +97,7 @@ public void stop() {
97 97 }
98 98
99 99 @Override
100   - protected GroupRequest cast(Collection<Address> dests, Message msg, RequestOptions options, boolean blockForResults) {
  100 + protected <T> GroupRequest<T> cast(Collection<Address> dests, Message msg, RequestOptions options, boolean blockForResults) {
101 101 RspFilter filter = options.getRspFilter();
102 102 return super.cast(dests, msg, options.setRspFilter((filter != null) ? new NoMuxHandlerRspFilter(filter) : new NoMuxHandlerRspFilter()), blockForResults);
103 103 }
22 src/org/jgroups/demos/QuoteClient.java
@@ -3,7 +3,6 @@
3 3
4 4
5 5 import org.jgroups.*;
6   -import org.jgroups.blocks.Request;
7 6 import org.jgroups.blocks.RequestOptions;
8 7 import org.jgroups.blocks.ResponseMode;
9 8 import org.jgroups.blocks.RpcDispatcher;
@@ -134,7 +133,6 @@ public void windowOpened(WindowEvent e) {
134 133
135 134 public void actionPerformed(ActionEvent e) {
136 135 String command=e.getActionCommand();
137   - RspList rsp_list;
138 136
139 137 try {
140 138 if(command.equals("Get")) {
@@ -144,16 +142,16 @@ public void actionPerformed(ActionEvent e) {
144 142 return;
145 143 }
146 144 showMsg("Looking up value for " + stock_name + ':');
147   - rsp_list=disp.callRemoteMethods(null, "getQuote", new Object[]{stock_name},
148   - new Class[]{String.class},
149   - new RequestOptions(ResponseMode.GET_ALL, 10000));
  145 + RspList<Object> quotes=disp.callRemoteMethods(null, "getQuote", new Object[]{stock_name},
  146 + new Class[]{String.class},
  147 + new RequestOptions(ResponseMode.GET_ALL, 10000));
150 148
151 149 Float val=null;
152   - for(Rsp rsp: rsp_list.values()) {
153   - Object obj=rsp.getValue();
154   - if(obj == null || obj instanceof Throwable)
  150 + for(Rsp<Object> rsp: quotes.values()) {
  151 + Object quote=rsp.getValue();
  152 + if(quote == null || quote instanceof Throwable)
155 153 continue;
156   - val=(Float)obj;
  154 + val=(Float)quote;
157 155 break;
158 156 }
159 157
@@ -186,9 +184,9 @@ public void actionPerformed(ActionEvent e) {
186 184 if(command.equals("All")) {
187 185 listbox.removeAll();
188 186 showMsg("Getting all stocks:");
189   - rsp_list=disp.callRemoteMethods(null, "getAllStocks",
190   - null, null,
191   - new RequestOptions(ResponseMode.GET_ALL, 5000));
  187 + RspList<Object> rsp_list=disp.callRemoteMethods(null, "getAllStocks",
  188 + null, null,
  189 + new RequestOptions(ResponseMode.GET_ALL, 5000));
192 190
193 191 System.out.println("rsp_list is " + rsp_list);
194 192
2  src/org/jgroups/demos/RelayDemoRpc.java
@@ -68,7 +68,7 @@ public void start(String props, String name) throws Exception {
68 68 continue;