How to save/edit object and refresh datagrid using request factory - gwt

I started with dynatableref example of Request Factory. I read request factory document. but still I am unclear about life cycle or flow of client to server.
I want to make a call to server. Insert data and update grid also. It is easy with RPC call. But I don't understand how to do with Request Factory.
This is one method of request factory. It call persist method automatically of server. It refresh grid also automatically. can I anybody tell how is it working?
context.fire(new Receiver<Void>() {
#Override
public void onConstraintViolation(Set<ConstraintViolation<?>> errors) {
// Otherwise, show ConstraintViolations in the UI
dialog.setText("Errors detected on the server");
editorDriver.setConstraintViolations(errors);
}
#Override
public void onSuccess(Void response) {
// If everything went as planned, just dismiss the dialog box
dialog.hide();
}
});
I want to edit some data in to grid also. is this method help me? or I have to write other method.
I wrote other method like
requestFactory.schoolCalendarRequest().savePerson(personProxy).fire(new Receiver<PersonProxy>() {
#Override
public void onSuccess(PersonProxy person) {
// Re-check offset in case of changes while waiting for data
dialog.hide();
}
});
This is not refreshing grid. why?

The flow client-server of the RuequestFactory is similar to RPC or any XMLHTTP request
1) You invoke a remote method on the server.
2) You receive a response in the Receiver object (which is the Callback object). In onSeccess Method you get the returned object if everything went well. onFailure you get an error if something went wrong.
So to populate the Person table from data retrieved from the server the code should look something like this
requestFactory.schoolCalendarRequest().getPersonList(param1).fire(new Receiver<List<PersonProxy>>() {
#Override
public void onSuccess(List<PersonProxy> personList) {
personTable.getDataProvider().setList(personList);
}
});
Now when you edit a Person (e.g. name ) it's important to initialize and use the same RequestContext until you call fire on the request. So the part where you update the Person's name should look something like this
column.setFieldUpdater(new FieldUpdater<Person, String>() {
#Override
public void update(PersonProxy personProxy, String value) {
RequestContext requestContext = requestFactory.schoolCalendarRequest()
PersonProxy personProxy= requestContext.edit(personProxy);
personProxy.setName(value);
requestFactory.schoolCalendarRequest().savePerson(personProxy).fire(new Receiver<PersonProxy>() {
#Override
public void onSuccess(PersonProxy person) {
//Do something after the update
}
});
}
});
The interaction with the RequestFactory should be placed in a Presenter, so you should probably consider implementing a MVP pattern.

Related

Using HeaderResponseContainer: No FilteringHeaderResponse is present in the request cycle

I'm trying to add a custom HeaderResponseContainer in my wicket application. The tutorial looks quite simple (see Positioning of contributions), but when I add these lines and run the application I alwas get an IllegalStateException:
java.lang.IllegalStateException: No FilteringHeaderResponse is present in the request cycle. This may mean that you have not decorated the header response with a FilteringHeaderResponse. Simply calling the FilteringHeaderResponse constructor sets itself on the request cycle
at org.apache.wicket.markup.head.filter.FilteringHeaderResponse.get(FilteringHeaderResponse.java:165)
at org.apache.wicket.markup.head.filter.HeaderResponseContainer.onComponentTagBody(HeaderResponseContainer.java:64)
at org.apache.wicket.markup.html.panel.DefaultMarkupSourcingStrategy.onComponentTagBody(DefaultMarkupSourcingStrategy.java:71)
...
Yes, I already saw the note about FilteringHeaderResponse. But I am not sure where I should call the constructor. I already tried to add it in renderHead before calling response.render but I still get the same exception:
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
FilteringHeaderResponse resp = new FilteringHeaderResponse(response);
resp.render(new FilteredHeaderItem(..., "myKey"));
}
You can create a decorator that wraps responses in a FilteringHeaderResponse:
public final class FilteringHeaderResponseDecorator implements IHeaderResponseDecorator {
#Override
public IHeaderResponse decorate(IHeaderResponse response) {
return new FilteringHeaderResponse(response);
}
}
And that set it during application initialization:
Override
public void init() {
super.init();
setHeaderResponseDecorator(new FilteringHeaderResponseDecorator());
}
I just ran into this same problem and found that the Wicket In Action tutorial leaves out the part about setting up a custom IHeaderResponseDecorator in your main Wicket Application init. The Wicket guide has a more thorough example:
Apache Wicket User Guide - Put JavaScript inside page body
You need something like this in your wicket Application:
#Override
public void init()
{
setHeaderResponseDecorator(new JavaScriptToBucketResponseDecorator("myKey"));
}
/**
* Decorates an original IHeaderResponse and renders all javascript items
* (JavaScriptHeaderItem), to a specific container in the page.
*/
static class JavaScriptToBucketResponseDecorator implements IHeaderResponseDecorator
{
private String bucketName;
public JavaScriptToBucketResponseDecorator(String bucketName) {
this.bucketName = bucketName;
}
#Override
public IHeaderResponse decorate(IHeaderResponse response) {
return new JavaScriptFilteredIntoFooterHeaderResponse(response, bucketName);
}
}

How to resend a GWT RequestFactory request

Is it possible to resend a RequestFactory transmission? I'd like to do the equivalent of this: How to resend a GWT RPC request when using RequestFactory. It is fairly simple to resend the same payload from a previous request, but I also need to place a call to the same method. Here's my RequestTransport class, and I am hoping to just "refire" the original request after taking care of, in this case, a request to the user for login credentials:
package org.greatlogic.rfexample2.client;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport;
/**
* Every request factory transmission will pass through the single instance of this class. This can
* be used to ensure that when a response is received any global conditions (e.g., the user is no
* longer logged in) can be handled in a consistent manner.
*/
public class RFERequestTransport extends DefaultRequestTransport {
//--------------------------------------------------------------------------------------------------
private IClientFactory _clientFactory;
//==================================================================================================
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
} // RFERequestCallback()
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
} // onError()
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
_clientFactory.login();
}
else {
_clientFactory.setLastPayload(null);
_clientFactory.setLastReceiver(null);
_requestCallback.onResponseReceived(request, response);
}
} // onResponseReceived()
} // class RFERequestCallback
//==================================================================================================
#Override
protected void configureRequestBuilder(final RequestBuilder builder) {
super.configureRequestBuilder(builder);
} // configureRequestBuilder()
//--------------------------------------------------------------------------------------------------
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
} // createRequestCallback()
//--------------------------------------------------------------------------------------------------
void initialize(final IClientFactory clientFactory) {
_clientFactory = clientFactory;
} // initialize()
//--------------------------------------------------------------------------------------------------
#Override
public void send(final String payload, final TransportReceiver receiver) {
String actualPayload = _clientFactory.getLastPayload();
TransportReceiver actualReceiver;
if (actualPayload == null) {
actualPayload = payload;
actualReceiver = receiver;
_clientFactory.setLastPayload(payload);
_clientFactory.setLastReceiver(receiver);
}
else {
actualReceiver = _clientFactory.getLastReceiver();
}
super.send(actualPayload, actualReceiver);
} // send()
//--------------------------------------------------------------------------------------------------
}
Based upon Thomas' suggestion I tried sending another request, and just replaced the payload and receiver in the RequestTransport.send() method, and this worked; I guess there is no further context retained by request factory, and that the response from the server is sufficient for RF to determine what needs to be done to unpack the response beyond the request and response that are returned to the RequestCallback.onResponseReceived() method. If anyone is interested in seeing my code then just let me know and I'll post it here.
It's possible, but you have a lot to do.
I had the same idea. And i was searching for a good solution for about 2 days. I tried to intercept the server call on RequestContext.java and on other classes. But if you do that you have to make your own implementation for nearly every class of gwt requestfactories. So i decided to go a much simpler approach.
Everywhere where I fired a Request, i handled the response and fired it again.
Of course you have to take care, that you don't get in to a loop.

GWT Callbacks Implementation

I'm maintaining software that contains a bunch of user groups. When an Admin clicks "Remove" on a user of a group, two things should happen:
delete the group member (involves updating cache, db, etc.)
reload a list of group members (the user sees this list when he/she deletes a user)
It turns out that #2 finishes before #1 - race condition. As a result, I want to add a callback so that #2 does not execute until #1 is successful.
Is this code acceptable for GWT to ensure #2 occurs before #1?
doTask1();
GWT.runAsync(new RunAsyncCallback()
{
public void onFailure(final Throwable reason)
{
}
public void onSuccess()
{
doTask2();
}
});
GWT#runAsync() is used for GWT's "code splitting" feature, which allows deferred loading of code (and other runtime resources) until they are needed. You need to use GWT's asynchronous operation patterns (i.e. AsyncCallback or Command) to pass a callback to doTask1() that is invoked once the asynchronous operations there complete. For example, if doTask1() executes a GWT RPC method:
public void doTask1(final Command onCompletion) {
myRpcService.doTask1(new AsyncCallback<Void>() {
#Override
public void onFailure(Throwable caught) {
// Error handling
}
#Override
public void onSuccess(Void ignored) {
onCompletion.execute();
}
});
}
public void doTask2() {
// Perform task 2
}
public void doTasks1And2() {
doTask1(new Command() {
#Override
public void execute() {
doTask2();
}
});
}
No, you can still have a race condition with that style of control flow. Instead, you want something like this:
doTask1(new MyCallback() {
public void onTask1Complete() {
doTask2();
}
}
doTask1() needs to accept a callback so that once it is complete, it will execute the next operation.
To see why, let's assume that both doTask1() and doTask2() are making HTTP calls. You have no guarantee what order the server might receive these two connections unless you wait until the doTask1()'s request has returned . In your example code, you make the request in doTask1() (which immediately returns while the request is asynchronously made), and then make the second call without waiting for the first.

How to intercept the onSuccess() method in GWT

I need to do method interception for the onSuccess method in GWT.
I need to add some code before and after the calling of the onSuccess method in GWT? (I have many calls to the onSuccess method and I need to do this dynamically)
EDIT:
I need to add a progress bar in the right corner of the screen, that appears when the code enters the onsuccess method and disappears on the exit of onsuccess method.
From a visual perspective
void onSuccess(Value v) {
showProgressBar();
doLotsOfWork(v);
hideProgressBar();
}
will be a no-op. Browsers typically wait for event handlers to finish executing before re-rending the DOM. If the doLotsOfWork() method takes a noticeable amount of time to execute (e.g. >100ms) the user will notice the browser hiccup due to the single-threaded nature of JavaScript execution.
Instead, consider using an incrementally-scheduled command to break the work up. It would look roughly like:
void onSuccess(Value v) {
showProgressBar();
Scheduler.get().scheduleIncremental(new RepeatingCommand() {
int count = 0;
int size = v.getElements().size();
public boolean execute() {
if (count == size) {
hideProgressBar();
return false;
}
processOneElement(v.getElements().get(count++));
setProgressBar((double) count / size);
return true;
}
});
}
By breaking the work across multiple pumps of the browser's event loop, you avoid the situation where the webapp becomes non-responsive if there's a non-trivial amount of work to do.
Well, it is a generic non-functional requirement, I have done some research on this item, I have implemented a solution that Thomas Broyer has suggested on gwt group.. This solution has distinct advantage over other suggested solutions, You dont have to change your callback classes, what you have to do is just add a line of code after creation of async gwt-rpc service...
IGwtPersistenceEngineRPCAsync persistenceEngine = GWT.create(IGwtPersistenceEngineRPC.class);
((ServiceDefTarget) persistenceEngine).setRpcRequestBuilder(new ProgressRequestBuilder());
import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.RpcRequestBuilder;
public class ProgressRequestBuilder extends RpcRequestBuilder {
private class RequestCallbackWrapper implements RequestCallback {
private RequestCallback callback;
RequestCallbackWrapper(RequestCallback aCallback) {
this.callback = aCallback;
}
#Override
public void onResponseReceived(Request request, Response response) {
Log.debug("onResposenReceived is called");
// put the code to hide your progress bar
callback.onResponseReceived(request, response);
}
#Override
public void onError(Request request, Throwable exception) {
Log.error("onError is called",new Exception(exception));
// put the code to hide your progress bar
callback.onError(request, exception);
}
}
#Override
protected RequestBuilder doCreate(String serviceEntryPoint) {
RequestBuilder rb = super.doCreate(serviceEntryPoint);
// put the code to show your progress bar
return rb;
}
#Override
protected void doFinish(RequestBuilder rb) {
super.doFinish(rb);
rb.setCallback(new RequestCallbackWrapper(rb.getCallback()));
}
}
You cant do that. The rpc onSuccess() method runs asynchronously (in other words, depends on the server when it completes, the app doesnt wait for it). You could fire code immediately after the rpc call which may/ may not complete before the onSuccess for RPC calls.
Can you explain with an eg why exactly do u want to do that? Chances are you might have to redesign the app due to this async behavior, but cant say till you provide a use case. Preferably any Async functionality should be forgotten after the rpc call, and actioned upon only in the onSuccess.

GWT MVP - retriving custom event parameters problem

I am developing a GWT application with presenter, dispatcher and Gin.
I have a presenter which is retrieving an ArrayList<JobPosting> from
server and firing a ManageJobsEvent.
dispatcher.execute(new GetJobPostings(userId), new
DisplayCallback<GetJobPostingsResult>(display) {
#Override
protected void handleFailure(Throwable e) {
e.printStackTrace();
Window.alert(SERVER_ERROR);
}
#Override
protected void handleSuccess(GetJobPostingsResult value) {
eventBus.fireEvent(new ManageJobsEvent(value.getUserId(),
value.getJobPostings()));
}
});
I get the callback to onPlaceRequest(PlaceRequest request) of my
another presenter
but how do i get the ArrayList<JobPostings> set in the event.
I'm not sure I understand your problem correctly, but since you are passing the ArrayList<JobPostings> to the constructor of the ManageJobsEvent, why not just add a getter to retrieve it?