Project

General

Profile

jWt equivalent of Wt::Http::Client, or ... background/async tasks in general

Added by Daniel G over 7 years ago

I'm probably (definitely) missing something obvious here ... but let's say I need to do some HTTP requests behind the scenes to interact with external APIs.

Is there something nice and easy like Wt's Http::Client ? Or do I need to write my own to mask the complexity of spawning a separate thread, notifying the UI thread, etc?

(Also wouldn't a full thread be kind of a bad idea from an overhead point of view? Pardon my ignorance but I don't understand the internals of jWt, or Java servlets for that matter :) But if it's some kind of Node-esque event-driven IO under the surface, a real thread wouldn't be required just to fetch an external URL, correct?)


Replies (5)

RE: jWt equivalent of Wt::Http::Client, or ... background/async tasks in general - Added by Jeremiah Jahn over 7 years ago

If you don't want your UI to freeze or timeout you'll need to enable updates and make a new thread.

With Java 8 lambdas it's pretty simple.

WApplication.getInstance().enableUpdates(true);

https://github.com/jahnje/delcyon-capo/blob/master/java/com/delcyon/capo/webapp/widgets/WWorker.java

The update method more or less calls the WApplication.triggerUpdate() method which causes JWT's magic to happen between threads.

Here's an example using this WWorker class to run a pdf report and trigger progress bar changes wile it loads.

private void runReport()
    {
        if (worker.isRunning())
        {
            worker.interrupt();
            return;
        }
        DocketWarrantsReport rptWarrants = new DocketWarrantsReport();
        btnRun.setText("Cancel");
        prgBar.setHidden(false);
        anchorResults.setHidden(true);
        prgBar.setValue(prgBar.getMinimum());
        WCursorState.wait.setCursourStateOn(WApplication.getInstance().getRoot());
        worker.run(() -> {
            try
            {
                prgBar.valueChanged().addListener(prgBar, () -> worker.update());
                bosWarrantReport = rptWarrants.getWarrantsForHearingsPDF(dtpBeginDate.getIntegerDate(), dtpEndDate.getIntegerDate(), chkInCounty.getBooleanValue(), chkMayAppear.getBooleanValue(), prgBar);                
                prgBar.setValue(prgBar.getMaximum());
                anchorResults.setHidden(true);
                anchorResults.open();
                worker.update();
            }
            catch (InterruptedException e)
            {
                // Do nothing, it's just the user hitting cancel
            }
            catch (Exception e)
            {
                JOApplication.exception(Level.WARNING, e.getMessage(), e, worker.getOwnerApplication());
            }
            prgBar.setHidden(true);
            btnRun.setText("Run");
            WCursorState.initial.setCursourStateOn(WApplication.getInstance().getRoot());
            worker.update();
        });

    }

RE: jWt equivalent of Wt::Http::Client, or ... background/async tasks in general - Added by Jeremiah Jahn over 7 years ago

also, apache has an httpClient you can use that pretty popular for access external web resources. Or you can use the built in HttpURLConnection if it's not too complicated.

RE: jWt equivalent of Wt::Http::Client, or ... background/async tasks in general - Added by Daniel G over 7 years ago

Ah, nice --- thank you! Will give your WWorker a try this weekend.

RE: jWt equivalent of Wt::Http::Client, or ... background/async tasks in general - Added by Daniel G over 7 years ago

Just a little followup for anybody else who visits this thread in the future. (Thanks again for your assistance, Jeremiah)

Since I'm using Groovy, I decided to use the Http Builder NG library: https://github.com/dwclark/http-builder-ng .

I made a method in my WApplication object:

    def getJSON(String url, Map<String, String> params, Closure<Object> callback) {
        Thread.start {
            http.get {
                request.uri.path = url
                request.uri.query = params
                response.success { res, Object data ->
                    def lock = getUpdateLock()
                    try {
                        callback(data)
                        triggerUpdate()
                    } finally {
                        lock.release()
                    }
                }
            }
        }
    }

And here is an example of calling it, such as in a button click listener:

        getJSON("https://api.giphy.com/v1/gifs/random", [api_key: "xxxxxx", tag: "cats"]) { result ->
            // change UI here, based on converted JSON 'result'
        }

Of course I'll eventually have to add a way to handle API failures / network exceptions properly, but for my current experiments this will do.

RE: jWt equivalent of Wt::Http::Client, or ... background/async tasks in general - Added by Wim Dumon over 7 years ago

One of the reasons there's no httpclient in jwt, is that there's a ton of libraries in java that handle this pretty well. We felt that there wasn't an easy solution for C Wt yet.

Wim.

    (1-5/5)