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.
Related
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.
To avoid users clicking repetitively on the same button and by the same token send multiple requests to server, I have used the following pattern:
In button ClickHandler.onClick, disable the button.
In call back, re-enable the button.
See pattern in code below. The "rpcCall" function below basically is the core implementation of the Button onClick(final ClickEvent event).
private void rpcCall(final ClickEvent event)
{
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
final Button source = (Button) event.getSource(); // Dev mode isLive assertion failure.
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
final Button source = (Button) event.getSource();
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
final Button source = (Button) event.getSource();
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}
I just noticed a "This event has already finished being processed by its original handler manager, so you can no longer access it" exception caused by an isLive assertion failure in dev mode when the onSuccess async function calls event.getSource().
It seems to work in production/javascript mode though.
This dev mode assertion failure makes me question this pattern.
Is it a good pattern? Why do I get the exception only in dev mode? What would be a better pattern?
Obviously, I could bypass the call to event.getSource() by passing the source Button as an argument of the rpc wrapper call function, but it seems redundant with the event object already carrying such a reference.
Historically, the way you got the event object in IE was to use window.event, which only lasted the time to process the event. GWT's Event object therefore had to put guards so you're discouraged to keep a hold on an event instance, as it could suddenly reflect another event being processed, or no event at all (weird!)
Fortunately, Microsoft has since fixed their browser, and this is why it works when you test it (I bet you didn't test in IE6 ;-) ).
The correct way to handle that situation is to extract all the data you need from the event and keep them in final variables:
private void rpcCall(final ClickEvent event)
{
final Button source = (Button) event.getSource();
final AsyncCallback<Void> callback = new AsyncCallback<Void>()
{
#Override
public void onSuccess(Void result)
{
source.setEnabled(true);
// Process success...
}
#Override
public void onFailure(Throwable caught)
{
source.setEnabled(true);
// Process error...
}
};
// Disable sender.
source.setEnabled(false);
// RPC call.
final RpcAsync rpcAsync = getRpcAsync();
RpcAsync.rpcCall(..., callback);
}
My problem is that in the main class I have some osgi references that work just fine when the class is call. But after that all the references became null. When I close the main windows and call shutdown method, the hubService reference returns null. What do I do wrong here?
private void shutdown() {
if(hubService == null) {
throw new NullPointerException();
}
hubService.shutdownHub(); // why is hubService null?
}
// bind hub service
public synchronized void setHubService(IHubService service) {
hubService = service;
try {
hubService.startHub(PORT, authenticationHandler);
} catch (Exception e) {
JOptionPane.showMessageDialog(mainFrame, e.toString(), "Server", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
// remove hub service
public synchronized void unsetHubService(IHubService service) {
hubService.shutdownHub();
hubService = null;
}
If a field can be read and written by multiple threads, you must protect access to read as well as write. Your first method, shutdown, does not protect the read of hubService so that the value of hubService can change between the first read and the second read. You don't show the declaration of the hubService field. You could make it volatile or only read when synchronized (on the same object used to synchronized when writing the field). Then your shutdown implementation could look like:
private volatile IHubService hubService;
private void shutdown() {
IHubService service = hubService; // make a copy of the field in a local variable
if (service != null) // use local var from now on since the field could have changed
service.shutdownHub();
}
I assume your shutdown method is the DS deactivate method? If so, why do you shutdown in the unset method as well in the shutdown method?
Overall the design does not seem very sound. The IHubService is used as a factory and should return some object that is then closed in the deactivate method. You made the IHubService effectively a singleton. Since it must come from another bundle, it should handle its life cycle itself.
Since you also do not use annotations, it is not clear if your set/unset methods are static/dynamic and/or single/multiple. The following code should not have your problems (exammple code with bnd annotations):
#Component public class MyImpl {
IHubService hub;
#Activate
void activate() {
hubService.startHub(PORT, authenticationHandler);
}
#DeActivate
void deactivate() {
hubService.shutdown();
}
#Reference
void setHub(IHubService hub) { this.hub = hub; }
}
I have the following utility:
class Worker
{
public void DoWorkAsync(Action callback)
{
Action work = () => Thread.Sleep(3000);
AsyncCallback asyncCallback = (result) => callback();
work.BeginInvoke(asyncCallback, null);
}
}
I use it like the following:
static void Main(string[] args)
{
var worker = new Worker();
worker.DoWorkAsync(() => Console.WriteLine("Completed."));
Console.WriteLine("Hello world!");
Console.ReadKey();
}
This will of course print Hello world! before Completed., since the worker works asynchronously.
My question is how can I block my thread so it should wait until the action is completed, then move on.
I know I can do it like this:
static void Main(string[] args)
{
var worker = new Worker();
worker.DoWorkAsync(() =>
{
Console.WriteLine("Completed.");
MoveOn();
});
Console.ReadKey();
}
static void MoveOn()
{
Console.WriteLine("Hello world!");
}
But since I have a bunch of cascaded async callbacks that should be executed one after the other (conditionally), I want them all to execute synchronously, so is there a more elegant way to wait for an async method that takes a callback as a param?
Note: Just to make sure, I cannot alter the behavior of the Worker class, its an external utility and I don't have access to its code.
Update
In my particular scenario I'm trying to interact with user from the ViewModel and get responses from him. My code is executed in the view-model and there is a method controlling a chain of cascaded interactions, I want this method should decide whether to fire a certain interaction or not. I tried SLaxs' answer, and also tried this but it doesn't seem to work, any ideas on how to make the main method the only controller of the interactions?
Create a ManualResetEvent, call Set() in the callback, and call WaitOne() to wait for the operation to finish.
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.