Author: david.lloyd(a)jboss.com
Date: 2009-10-16 16:52:24 -0400 (Fri, 16 Oct 2009)
New Revision: 5557
Added:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java
Log:
Additional type-safe request API for clients
Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java
===================================================================
---
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-09
20:35:17 UTC (rev 5556)
+++
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/Client.java 2009-10-16
20:52:24 UTC (rev 5557)
@@ -94,6 +94,32 @@
O invoke(I request) throws IOException, CancellationException;
/**
+ * Send a reqest and block until a reply is received, requiring the reply to be of a
specific type.
+ * Otherwise this method functions identically to {@link #invoke(Object) invoke(I)}.
+ *
+ * @param request the reqest to send
+ * @param expectedResultType the expected result type
+ * @return the result of the request
+ * @throws IOException if an I/O error occurred while sending the request
+ * @throws CancellationException if the operation was cancelled asynchronously
+ * @see #invoke(Object) invoke(I)
+ */
+ <T extends O> T invoke(I request, Class<T> expectedResultType) throws
IOException, CancellationException;
+
+ /**
+ * Send a typed request and block until a reply is received. If, for some reason,
the given typed request object
+ * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown.
Otherwise this method functions
+ * identically to {@link #invoke(Object) invoke(I)}.
+ *
+ * @param request the request
+ * @param <T> the specific reply subtype
+ * @return the result of the request
+ * @throws IOException if an I/O error occurred while sending the request
+ * @throws CancellationException if the operation was cancelled asynchronously
+ */
+ <T extends O> T invoke(TypedRequest<? extends I, T> request) throws
IOException, CancellationException, ClassCastException;
+
+ /**
* Send a request asynchronously. If the remote side manipulates a stream, it
* may use a local policy to assign one or more thread(s) to handle the local end of
that stream, or it may
* fail with an exception (e.g. if this method is called on a client with no threads
to handle streaming).
@@ -112,4 +138,32 @@
* @throws IOException if some other I/O error occurred while sending the request
*/
IoFuture<? extends O> send(I request) throws IOException;
+
+ /**
+ * Send a request asynchronously, requiring the reply to be of a specific result
type.
+ * Otherwise this method functions identically to {@link #send(Object) send(I)}.
+ *
+ * @param request the request to send
+ * @param expectedResultType the expected result type class
+ * @param <T> the expected result type
+ * @return a future representing the result of the request
+ * @throws ObjectStreamException if marshalling some part of the request failed
+ * @throws IOException if some other I/O error occurred while sending the request
+ * @see #send(Object) send(I)
+ */
+ <T extends O> IoFuture<? extends T> send(I request, Class<T>
expectedResultType) throws IOException;
+
+ /**
+ * Send a typed request asynchronously. If, for some reason, the given typed request
object
+ * is not a subtype of {@link #<I>}, a {@code ClassCastException} is thrown.
Otherwise
+ * this method functions identically to {@link #send(Object) send(I)}.
+ *
+ * @param request the request to send
+ * @param <T> the expected result type
+ * @return a future representing the result of the request
+ * @throws ObjectStreamException if marshalling some part of the request failed
+ * @throws IOException if some other I/O error occurred while sending the request
+ * @see #send(Object) send(I)
+ */
+ <T extends O> IoFuture<? extends T> send(TypedRequest<? extends I,
T> request) throws IOException;
}
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java
===================================================================
---
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-09
20:35:17 UTC (rev 5556)
+++
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/ClientImpl.java 2009-10-16
20:52:24 UTC (rev 5557)
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.util.concurrent.Executor;
+import java.util.concurrent.CancellationException;
import org.jboss.remoting3.spi.RemoteRequestContext;
import org.jboss.remoting3.spi.ReplyHandler;
import org.jboss.remoting3.spi.RequestHandler;
@@ -65,45 +66,61 @@
}
public O invoke(final I request) throws IOException {
- if (! isOpen()) {
- throw new IOException("Client is not open");
- }
- log.trace("Client.invoke() sending request \"%s\"",
request);
- final I actualRequest = castRequest(request);
- final QueueExecutor executor = new QueueExecutor();
- final FutureReplyImpl<O> futureReply = new
FutureReplyImpl<O>(executor, replyClass);
- final ReplyHandler replyHandler = futureReply.getReplyHandler();
- final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest,
replyHandler);
- futureReply.setRemoteRequestContext(requestContext);
- futureReply.addNotifier(IoUtils.attachmentClosingNotifier(), executor);
- executor.runQueue();
- try {
- final O reply = futureReply.getInterruptibly();
- log.trace("Client.invoke() received reply \"%s\"",
reply);
- return reply;
- } catch (InterruptedException e) {
- try {
- futureReply.cancel();
- throw new IndeterminateOutcomeException("The current thread was
interrupted before the result could be read");
- } finally {
- Thread.currentThread().interrupt();
- }
- }
+ return invoke(request, replyClass);
}
+ public <T extends O> T invoke(final I request, final Class<T> replyClass)
throws IOException, CancellationException {
+ if (! isOpen()) {
+ throw new IOException("Client is not open");
+ }
+ log.trace("Client.invoke() sending request \"%s\"", request);
+ final I actualRequest = castRequest(request);
+ final QueueExecutor executor = new QueueExecutor();
+ final FutureReplyImpl<T> futureReply = new
FutureReplyImpl<T>(executor, replyClass);
+ final ReplyHandler replyHandler = futureReply.getReplyHandler();
+ final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest,
replyHandler);
+ futureReply.setRemoteRequestContext(requestContext);
+ futureReply.addNotifier(IoUtils.attachmentClosingNotifier(), executor);
+ executor.runQueue();
+ try {
+ final T reply = futureReply.getInterruptibly();
+ log.trace("Client.invoke() received reply \"%s\"",
reply);
+ return reply;
+ } catch (InterruptedException e) {
+ try {
+ futureReply.cancel();
+ throw new IndeterminateOutcomeException("The current thread was
interrupted before the result could be read");
+ } finally {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ public <T extends O> T invoke(final TypedRequest<? extends I, T>
typedRequest) throws IOException, CancellationException {
+ return invoke(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ }
+
public IoFuture<? extends O> send(final I request) throws IOException {
+ return send(request, replyClass);
+ }
+
+ public <T extends O> IoFuture<? extends T> send(final I request, final
Class<T> replyClass) throws IOException {
if (! isOpen()) {
throw new IOException("Client is not open");
}
log.trace("Client.send() sending request \"%s\"", request);
final I actualRequest = castRequest(request);
- final FutureReplyImpl<O> futureReply = new
FutureReplyImpl<O>(getExecutor(), replyClass);
+ final FutureReplyImpl<T> futureReply = new
FutureReplyImpl<T>(getExecutor(), replyClass);
final ReplyHandler replyHandler = futureReply.getReplyHandler();
final RemoteRequestContext requestContext = handler.receiveRequest(actualRequest,
replyHandler);
futureReply.setRemoteRequestContext(requestContext);
return futureReply;
}
+ public <T extends O> IoFuture<? extends T> send(final TypedRequest<?
extends I, T> typedRequest) throws IOException {
+ return send(requestClass.cast(typedRequest), typedRequest.getReplyType());
+ }
+
/**
* Since type is erased, it's possible that the wrong type was passed.
* @param request
Modified:
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java
===================================================================
---
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java 2009-10-09
20:35:17 UTC (rev 5556)
+++
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/FutureReplyImpl.java 2009-10-16
20:52:24 UTC (rev 5557)
@@ -35,11 +35,11 @@
final class FutureReplyImpl<O> extends AbstractIoFuture<O> {
private final Executor executor;
- private final Class<O> replyType;
+ private final Class<? extends O> replyType;
private final ReplyHandler replyHandler = new Handler();
private volatile RemoteRequestContext remoteRequestContext;
- FutureReplyImpl(final Executor executor, final Class<O> replyType) {
+ FutureReplyImpl(final Executor executor, final Class<? extends O> replyType) {
this.executor = executor;
this.replyType = replyType;
}
@@ -65,7 +65,7 @@
private final class Handler implements ReplyHandler {
public void handleReply(final Object reply) {
- final Class<O> replyType = FutureReplyImpl.this.replyType;
+ final Class<? extends O> replyType = FutureReplyImpl.this.replyType;
final O actualReply;
try {
actualReply = replyType.cast(reply);
Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java
(rev 0)
+++
remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/TypedRequest.java 2009-10-16
20:52:24 UTC (rev 5557)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.jboss.remoting3;
+
+/**
+ * A request whose replies should be of a specific type. Request classes may choose to
implement this interface
+ * in order to provide additional type checking and convenience to Remoting API users by
causing the reply type
+ * to be chosen based upon the request type.
+ *
+ * @param <I> the request type
+ * @param <O> the reply type for this request type
+ */
+public interface TypedRequest<I extends TypedRequest<I, O>, O> {
+
+ /**
+ * Get the reply type for this request type.
+ *
+ * @return the reply type's class
+ */
+ Class<O> getReplyType();
+}