3

The question might seem stupid/trivial and might be, but I simply cannot understand how to achieve my goal. (Sorry if the title is misguiding, couldn't think of a better one)

I have a webpage on a App Engine server which uses GWT. I got client code and server code. The client code can call RPC methods without any problem (my problem has nothing to do with the "gwt-client" at all).

I got the following classes:

//MyClassService.java - client package
@RemoteServiceRelativePath("myService")
public interface MyClassService extends RemoteService{
   public doSomething();
}

//MyClassServiceAsync.java - client package
public interface MyClassServiceAsync{
   public void doSomething(AsyncCallback<Void> callback);
}

//MyClassServiceImpl.java - server package
public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
   @Override
   public void doSomething()
   {
      //does something
   }
}

A scenario and what I want to do: I've got a remote client, in other words, a client who's not connecting through the page via the "GWT-interface", it's a client who's simply making GET, POST requests to a path on the server (from elsewhere). This remote client is not "using" GWT at all. The client is connecting through an HttpServlet, inside this servlet I want to reuse the RPC mechanics so that i don't have to rewrite the interfaces, who are on the client side and using client-dependent code (the implementation is already server-side).

To reuse the existing methods on the server-side I could create an instance of MyClassServiceImpl.java and just use those. BUT as you can see above, they are implemented as synchronous methods, since GWT-RPC automatically makes the calls asyncronous when using the GWT-RPC.

How would i go about to reuse the MyClassServiceImpl on the server-side and also get them as asynchronous?

Also if I'm wrong with the approach I'm taking, please suggest some other solution. For example, one solution might be for the remote client to directly communicate with the RemoteServiceServlet instead of creating a HttpServlet which the client connects through, but I don't know if that's possible (and if it is, please tell me how)!

Thank you!

EDIT (thanks to some answers below I got some insight and will try to improve my question):

The server-side implementation of the methods is SYNCHRONOUS. Meaning they will block until results a returned. When invoking these method from the gwt-client code, they are 'automatically' made ASYNCHRONOUS one can call them by doing the following:

MyClassServiceAsync = (MyClassServiceAsync) GWT.create(MyClassService.class);
ServiceDefTarget serviceDef = (ServiceDefTarget) service;
serviceDef.setServiceEntryPoint(GWT.getModuleBaseURL() + "myService");

service.doSomething(new AsyncCallback<Void>() {
 @Override
 public void onSuccess(Void result) {
   //do something when we know server has finished doing stuff
 }

 @Override
 public void onFailure(Throwable caught) {
 }
});

As you can see from the above code, there is support for the doSomething method to take an AsyncCallback, without even having the implementation for it. This is what I wanted on the server-side so i didn't have to use threads or create a new implementation for "async-usage". Sorry if I was unclear!

Whyser
  • 2,187
  • 2
  • 20
  • 40
  • HTTP protocol is based on request-response principle. So in essence every request is "blocking" - client opens a connection, sends request, waits for reply and then server closes connection. Note that servers are multi-threaded and can process multiple requests at the same time (= creating parallel threads and calling the servlet methods in parallel), so there is little need to make things async on the server side. What problem are you actually trying to solve? – Peter Knego Nov 06 '13 at 16:13
  • Note that you must explicitly enable multi-threading on GAE by enabling concurrent requests: https://developers.google.com/appengine/docs/java/config/appconfig#Java_appengine_web_xml_Using_concurrent_requests – Peter Knego Nov 06 '13 at 16:15
  • Thank you for your input! It's more of a "keep code clean"-problem, then an actual problem. As you can see in the edited part of the question. What I'm really after was to keep the code the same on the server and client as much as possible, so I didn't have to create an implementation for the AsyncCallback-version of the method on the server. I might have been too quick to use the word "asynchronous" when I really meant the AsyncCallback-version of the method. – Whyser Nov 07 '13 at 08:53

2 Answers2

1

1) Any client can call MyClassServiceImpl.doSomething() with the current configuration. MyClassServiceImpl is a servlet and properly exposed. In order to achieve communication this way, the client must be able to "speak" the GWT dialect for data transportation. Google may provide you with libraries implementing this. I haven't used any, so I cannot make suggestions.

An example, proof-of-concept setup: Check the network communications with Firebug to get an idea of what is going on. Then try calling the service with curl.

2) If you do not want to use the GWT dialect, you can easily expose the same service as REST (JSON) or web services (SOAP). There are plenty of libraries, e.g. for the REST case RestEasy and Jersey. You do not mention any server-side frameworks (Spring? Guice? CDI?), so the example will be simplistic.

I'd suggest implementing your business method in a class independent of transportation method:

public class MyBusinessLogic {
    public void doSomething() {
        ...
    }
}

Then, the transport implementations use this business logic class, adding only transport-specific stuff (e.g. annotations):

GWT:

public class MyClassServiceImpl extends RemoteServiceServlet implements MyClassService{
    @Override
    public void doSomething() {
        MyBusinessLogic bean = ... // get it from IoC, new, whatever
        bean.doSomething();
    }
}

JAX-RS:

@Path("myService")
public class MyResource {
    @GET
    public void doSomething() {
        MyBusinessLogic bean = ... // get it from IoC, new, whatever
        bean.doSomething();
    }
}

So the transport endpoints are just shells for the real functionality, implemented in one place, the class MyBusinessLogic.

Nikos Paraskevopoulos
  • 39,514
  • 12
  • 85
  • 90
  • Thanks for your answer and suggestion for using some REST-implementation! My logic is already separated as per how GWT-RPC works. I was hoping for a solution that "automatically" could make my server-side methods async as they are when the gwt-client invokes them, but as Peter Knego pointed out in his comment, this is only client-side "magic", that I probably can't make use of on the server-side. I will try to update my question to maybe more reflect what I was after so that I might still get a better solution. – Whyser Nov 06 '13 at 15:32
0

Is this a real example? Your method takes no arguments and returns no data.

Anyhow you can create a new servlet and invoke it via normal HTTP request. The servlet then just invokes the target method:

public class MyNewServlet extends HttpServlet{
    protected void doGet(HttpServletRequest request, HttpServletResponse response){
       MyBusinessLogic bean = ... // get it from IoC, new, whatever
       bean.doSomething();
   }
}
Peter Knego
  • 79,991
  • 11
  • 123
  • 154
  • Not sure if I was unclear, but I think I was pretty clear when I wrote the following: "To reuse the existing methods on the server-side I could create an instance of MyClassServiceImpl.java and just use those. BUT as you can see above, they are implemented as synchronous methods, since GWT-RPC automatically makes the calls asyncronous when using the GWT-RPC." - After that I asked HOW I could make them asyncronous as they are when the gwt-client invokes them. – Whyser Nov 06 '13 at 15:06
  • Sorry, mistake in code - edited. In fact you would directly call the business logic. – Peter Knego Nov 06 '13 at 15:11
  • Methods are async on the client side: when an RPC invocation is in progress the javascript code can continue executing, then when RPC response is available the provided callback is invoked. This is needed since JS in single threaded. All this has nothing to do with server side - just a normal HTTP servlet request. – Peter Knego Nov 06 '13 at 15:14
  • So, basically, I can't achieve "async" invokation of the method (on the server-side) unless I explicitly create an implementation for them? – Whyser Nov 06 '13 at 15:21