Synchronous RPC Calls in GWT
Asked Answered
B

2

9

(That title alone should cause people to come out of the woodwork to bash me with clubs, but hear me out).

I have a use case where I need to return a value from a asynchronous call. (I'm using GWT-Platform, but the concepts are the same.) I declared a final JavaScriptObject array, then assigned the value within the AsyncCallback. However, I need to return the value, and the method returns before the AsyncCallback completes. Therefore, I need to block somehow until the AsyncCallback completes. I need the returned value in another method, or I'd just do what I need to in onSuccess().

I've tried loops, Timers, and a few other methods with no luck. Can anyone help?

@Override
public JavaScriptObject doGetWhereAmIMarker(final double lng, final double lat) {

    final JavaScriptObject[] markerArray = new JavaScriptObject[1];  // ugly hack, I know
    dispatch.execute(new GetLocationDescriptionsAction(lng, lat), new AsyncCallback<GetLocationDescriptionsResult>() {
        @Override
        public void onFailure(Throwable caught) {
            caught.printStackTrace();
        }

        @Override
        public void onSuccess(GetLocationDescriptionsResult result) {
            Map<String, Location> resultMap = result.getResult();
            StringBuffer message = new StringBuffer();
            for (String key : resultMap.keySet()) {
                message.append(key).append(": ").append(resultMap.get(key)).append("\n");
            }

            Map tempMap = new HashMap();
            tempMap.put("TITLE","Location Information");
            tempMap.put("LAT", lat);
            tempMap.put("LNG", lng);
            tempMap.put("CONTENTS", message.toString());

            JavaScriptObject marker = GoogleMapUtil.createMarker(tempMap);
            markerArray[0] = marker;
            if (markerArray[0] != null) {
                GWT.log("Marker Array Updated");
            }

        }
    });

    return markerArray[0];
}

UPDATE: As requested, here is the code that calls doGetWhereIAmMarker(). I've tried having a separate native method with the Google Map object (as a JavaScriptObject) as a parameter, but it appears that passing that object between native methods kills the ability to update said object.

public native void initMap(JavaScriptObject mapOptions, JavaScriptObject bounds, JavaScriptObject border, JsArray markerArray, Element e) /*-{

    // create the map and fit it within the given bounds
    map = new $wnd.google.maps.Map(e, mapOptions);
    if (bounds != null) {
        map.fitBounds(bounds);
    }

    // set the polygon for the borders
    if (border != null) {
        border.setMap(map);
    }

    // set up the info windows
    if (markerArray != null && markerArray.length > 0) {
        var infoWindow = new $wnd.google.maps.InfoWindow({
            content:"InfoWindow Content Goes Here"
        });

        for (var i = 0; i < markerArray.length; i++) {
            var marker = markerArray[i];
            marker.setMap(map);
            $wnd.google.maps.event.addListener(marker, 'click', function() {
                infoWindow.setContent(marker.content);
                infoWindow.open(map, this);
            });
        }
    }

    // need to reference the calling class inside the function(), so set a reference to "this"
    var that = this;

   $wnd.whereAmI=function(lng, lat) {
        [email protected]::whereAmI(DD)(lng,lat);
   }

    $wnd.google.maps.event.addListener(map, 'click', function(event) {
        var lat = event.latLng.lat();
        var lng = event.latLng.lng();
        $wnd.whereAmI(lng, lat);
    });

}-*/;
Brooksbrookshire answered 8/9, 2011 at 19:18 Comment(3)
Can you show some more code? I am interested in the parts that call this code, and also the parts that consume the JavaScriptObject that is returned from doGetWhereAmIMarker(...).Wanwand
Added the calling native method. GoogleMapUtil is at github.com/dartmanx/mapmaker/blob/master/src/main/java/org/…, but isn't commited with the createMarker() method. It's similar to the createMarkerArray() method, however.Brooksbrookshire
Why does it not work then if you just put a while(asyncIsDone){sleep}. that seems like the most simple thing to do... or make it a for(){sleep} that will continue after a certain time has passed?Microorganism
C
3

At some point I had to do something similar but eventually I eliminated that code in favor of asynchronous stuff. Therefore, I can't give exact code that you need to use but only few pointers on how to approach it.

  • Firstly, this blog describes how to do synchronous AJAX using javascript.
  • Second, you must provide support for sync calls. The problem is that GWT does not support the parameter that provides synchronous AJAX calls. Most likely is that they don't want to encourage its use. Therefore you would need to use JSNI to add appropriate method to XMLHttpRequest (which you probably would extend) and then to RequestBuilder (also should extend it).
  • Finally, amend your service using extended RequestBuilder. Something like

((ServiceDefTarget)service).setRpcRequestBuilder(requestBuilder);

And in conclusion - from the same blog post (slightly out of context):

Because of the danger of a request getting lost and hanging the browser, synchronous javascript isn't recommended for anything outside of (onbefore)unload event handlers.

Concessive answered 8/9, 2011 at 20:2 Comment(3)
I've done manual synchronous AJAX before, but since this is GWT I'm stuck with GWT's limitations. I'm using GWT-Platform's DispatchAsync for getting data, and I'm not seeing anything in there using RequestBuilder.Brooksbrookshire
You should be able to use any Javascript code with GWT using JSNI. RequestBuilder is used internally when you deal with RPC. Once you have your service, you can assign your custom RequestBuilder using snippet that I provided.Concessive
I'm going to accept your answer as it's interesting and might be something I need to try someday. However, I found the answer to my original problem that was preventing me from using the async request.Brooksbrookshire
S
0

I Think its all fate....
We cannot do in Gwt to catch the Response and Send it, because immediately after the request is send the next method starts executing, neither bothering the response Still however they satisfy us to use the Timers, is what i think...

 Timer t = new Timer() {
      @Override
      public void run() {
        Window.alert("Nifty, eh?");
      }
    };
    t.schedule(5000);
Splutter answered 27/9, 2013 at 10:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.