[Annoucement] Busy plugin now Web compatible

I have worked on Scott Buttler’s busy plugin again, this time to release a web compatible version.

This version uses jQuery and the jQuery-blockUI plugin for the wicket implementation (in the web client).
To be able to do that, the plugin has been refactored quite a lot and you will find that the 3 previous methods (busy(), ready() and isAvailable()) have been deprecated. - meaning that they should still work in your old solutions, but that I will stongly advise to make use of the new methods: block() and unblock(), and of the prepare() method in the onShow event of the form you want to use it for the web client (when application.getApplicationType() == 5). See related code in the sample solutions.

See this wiki page on the google code site for more instructions.

You can download the new version, as well as sample solutions (one for Servoy 3.5.x and one for 4.1.x) on the google code download page

And you will be able to download the source code and project for Eclipse from the svn server of google code.

Thanks to Scott Buttler to make these sources available in the first place.

Enjoy!

Great job Patrick!

Thanks! But it all happened because you made it Open Source.

Hi

The plugin is fantastic, it works well on both smart and web clients but there is one issue; then again, maybe we haven’t fully understood its proper functionality.

We use a navigation module where all forms are loaded in a tab panel. In such situations where the form with the “busy process” belogs to a tab panel, the fuction defined under “processFunctionName” doesn’t get invoked. Hence, the “intended operation” doesn’t happen and also the “busy state” never gets exited unless “Cancel” is pressed.

Can you please help us with this problem? Are we doing something incorrect?

Thanks in advance.

Best Regards,

Hareendra

hareendra:
The plugin is fantastic, it works well on both smart and web clients but there is one issue; then again, maybe we haven’t fully understood its proper functionality.

We use a navigation module where all forms are loaded in a tab panel. In such situations where the form with the “busy process” belogs to a tab panel, the fuction defined under “processFunctionName” doesn’t get invoked. Hence, the “intended operation” doesn’t happen and also the “busy state” never gets exited unless “Cancel” is pressed.

Can you please help us with this problem? Are we doing something incorrect?

Hi Hareendra,

I’m glad you like it! And I don’t think that you didn’t understand the process: I just tested it and effectively when placed in a tab panel, it doesn’t call the process function of the form…

This is all because it relies on the getCurrentForm() of the IFormMamager to find the form it is placed on and execute the method on it.
But the getCurrentForm() in that case returns the form containing the tabPanel (the parent form), which is not the one you have your method in.

I will see if I can find a way to get a hold of the form inside the tabPanel, and if I don’t maybe I will add a parameter to the plugin’s javascript objet so that you can tell him which one to look for by its name…

In the meantime, what you can do as a workaround is use a global function for the processFunctionName parameter (this function could pass the call to the function of the correct form if needed) so you would have for example:
funtionName: ‘globals.process’ where your globals process() function would be:

function process() {
    forms.theTabForm.process();
}

Hope this helps,

Freaking AWESOME! Thanks very much guys for making this web-compatible!! That’s a really HUGE addition - and will make several of my customer VERY happy!

Nice to know that it will make your users happy Bob!

For the tabPanel issue, I just updated the sources and bean on the google code site, please replace your version with the new one if you want to use the new parameter.

I added a “form” parameter which allows to give the plugin the form that contains the “process” function, so in the form contained in the tabPanel calling the plugin you will fill your parameters object like this:

var params = {
processFunctionName: ‘process’,
form: this,
message: ‘Lengthy process… please wait!’,
opacity: 0.5,
paneColor: ‘#000000’,
showCancelButton: true,
cancelButtonText: ‘Stop this now!’,
callBackFunction: callBack
};

Meaning that the process() function will be called (and the callBack() function) from the form itself.

Enjoy!

if i look at your code (is that really the latest code? i dont see block or unblock?)

then i see that you keep references to FormScopes and Functions

please be very very carefull with that. How long stuff lives is not defined.

For functions you should use the FunctionDefinition class that will also take care of the form scopes or globals
so when you call FunctionDefinition.execute() it will do it on the right form and with the right objects.

by the way, how does cancel work?

jcompagner:
if i look at your code (is that really the latest code? i dont see block or unblock?)

then i see that you keep references to FormScopes and Functions

please be very very carefull with that. How long stuff lives is not defined.

For functions you should use the FunctionDefinition class that will also take care of the form scopes or globals
so when you call FunctionDefinition.execute() it will do it on the right form and with the right objects.

by the way, how does cancel work?

Hi Johan!

Thanks for looking into this stuff.

If you found a reference to a FormScope then this means that you have the latest code, since it was only added yesterday to address the problem of calling back the process function from the correct form.

The block() and unblock() functions are really js_block() and js_unblock() of course and they are calling busy() - with a bunch of parameters, coming from the Scriptable object - and ready() respectively on the “provider” object (either a Swing or Wicket implementation).

Thanks for calling my attention on the fact that FormScope and Function objects can be released.
I’m using FormScope only because that’s the object that is passed by Servoy when I pass a form as parameter - I was expecting an object of type IForm but got ClassCastException which leads me to that object instead…
But it’s true that I don’t really need to hold a reference to it, so I will modify the call to busy() to also pass it in parameter, so that in the end it will be used by the callProcessByName() method if not null.

As to using Function, I actually use a similar call as the one Sean Devlin is using in its web_client_utils plugin: a call to

function.call(context, function.getParentScope(), function, args);

That’s how the call back of the “cancel” function is called, directly, using Rhino, since I don’t need this one to be asynchronous. I thought that it was safe since Sean is doing it this way without problems! Are you telling me it’s not safe?

But what is puzlling me is that I didn’t find any reference in my classpath to FunctionDefinition (it is not in the servoy jars, nor the Rhino jars as shipped with 4.1.3!) So what is this class?
Is it going to be there in the next version of Servoy? Could you tell me its fully qualified path? What is it and how can I use it?

Thanks in advance for a little bit more explanations,

ahh sorry… FunctionDefinition is something from Servoy 5.0

We already have that (it is gotten promoted) because our TreeBean uses it

Add the dbtreeview.jar to your classpath and then you have FunctionDef those are sort of the same thing we have introduced as public api in 5.0

i wasnt talking about the cancel function when i talked about function objects.

its just that everything that comes from a form, thats the formscope or function object shouldnt be kept as hard references in plugins.
Because we could just already have destroyed the formscope and then you are referencing garbage.

About the cancel i just was wondering that.
If i have a long process method. Hows does cancel work? because that will not work. Your cancel method will only be called after the process method is done and returned.
wicket doesnt support multi threaded access to pages.

First wicket ajax part in the browser will only call 1 async method at one time. And if you would call the server at the same time then wicket should block the page access
And even if your method would be called at the same time. Then the process method should really test constantly a variable that the cancel method will be set
Big problem here that this is multi threaded access then to a variable. And the scriptengine doesnt support that.

jcompagner:
ahh sorry… FunctionDefinition is something from Servoy 5.0

We already have that (it is gotten promoted) because our TreeBean uses it

Add the dbtreeview.jar to your classpath and then you have FunctionDef those are sort of the same thing we have introduced as public api in 5.0

i wasnt talking about the cancel function when i talked about function objects.

its just that everything that comes from a form, thats the formscope or function object shouldnt be kept as hard references in plugins.
Because we could just already have destroyed the formscope and then you are referencing garbage.

About the cancel i just was wondering that.
If i have a long process method. Hows does cancel work? because that will not work. Your cancel method will only be called after the process method is done and returned.
wicket doesnt support multi threaded access to pages.

First wicket ajax part in the browser will only call 1 async method at one time. And if you would call the server at the same time then wicket should block the page access
And even if your method would be called at the same time. Then the process method should really test constantly a variable that the cancel method will be set
Big problem here that this is multi threaded access then to a variable. And the scriptengine doesnt support that.

Thanks for your insight and the detailed answer!

I will have a look at FunctionDef of the TreeViewBean.
But I suppose that for 5.0, I will need to change it to FunctionReference from the Servoy jars?

And about keeping hard references, this means that the web_client_utils should also be revised because it holds a whole Hashtable of callback Functions!

I call the “process” method from the browser with an async call with IClientPluginAccess.executeMethod(), yes - that is why I need the name of a function (and scope) and not the Function.
The cancelFunction is a call to the Rhino Function itself, from an ajax call in Wicket, yes, but synchronously this time.
And yes, the user needs to check a “cancel” variable constantly in the process method, so the whole script involved in a form to make this work is:
[attachment=0]busyScripting.gif[/attachment]
(Sorry about the capture, but I can’t get the “Code” BBCode to work correctly on the forum anymore!)

What you are saying is that if the process navigates to other pages then the callback will not work?
Then yes, of course, you are right, and users should be informed about that.

But as for multi threaded access to a variable, I’m not sure I understand because the variable is not held in the plugin, it is in the form and the access is done by Servoy, not by the plugin, so I guess (I hope) that each session holding its own form variable there is no concurrency problem here, apart from 2 different plugin calling cancel at the same time, bit I don’t see how it could happen.

I’m sure you will understand from the code above how it is working, really.

i was talking about that “cancel” variable in scripting

If you would be able to set that variable in another thread then the thread (the js script) that test for that cancel variable doesnt have to see it…

But you shouldnt be able to set that cancel variable at all when the “process” method is running.
Because wicket shouldnt allow you to do that (on multiply levels first in the browser and then on the server) so the callback function is only executed after the http request that handles the process function is done.

jcompagner:
i was talking about that “cancel” variable in scripting

If you would be able to set that variable in another thread then the thread (the js script) that test for that cancel variable doesnt have to see it…

But you shouldnt be able to set that cancel variable at all when the “process” method is running.
Because wicket shouldnt allow you to do that (on multiply levels first in the browser and then on the server) so the callback function is only executed after the http request that handles the process function is done.

Maybe the thread that test the cancel variable doesn’t have to see it, but it does!

You said that Wicket shouldn’t allow to do set that cancel variable, but it actually does.
The code above does work and the cancel variable is updated DURING the process method and the process method “sees” it, so how is it possible?

So I don’t know what I’m doing wrong here but that seem to bypass what wicket doesn’t allow to do!

Johan,

following your advice, I have changed the use of the FormScope so as not to keep a hard reference to it, I just pass it directly as received by Servoy to the method that call the process method back (using IClientPluginAccess.executeMethod() asynchronously, testing for null in any case).

As for the reference to the Function, I will change it if Sean is updating his plugin with a “safer” code too, for now I don’t see a problem, but I do see a problem with a dependency to the dbtreeview.jar because it is not the same in Servoy 3.5.x vs 4.1.x: the FunctionRef is not present in the Servoy 3.5.x version of the bean!

Later, when 5.0 will be released, I will probably use the FunctionReference you talked about (hopefully it will be public?), but then it will not be compatible with 3.5 anymore.

So, I commited the changes to the google code SVN server so you will be able to get it, and I recompiled the busy.jar for more convenience and immediate use for everyone.
I also updated the Servoy 4.1 solution because the previous example was using global methods which you would say is cheating, and didn’t show the proper use “in a form” (even in a tabPanel).
This time, I added the same mechanism but in a form (see the “start_form” script), so you will be able to test this in Swing AND Wicket.

If you can download this version + the sample solution that is on the google code downloads section Google Code Archive - Long-term storage for Google Code Project Hosting., you will be able to see that the cancel variable updated by the callback method is perfectly seen from the process method DURING the process, which proves that the callback is occuring DURING the process when you click on the cancel button in the browser.

Maybe you will understand what is going on, and if anything is wrong here, what it is exactly…
Personally I am at lost as to understand how this can work at all if the callback is not occurring during the process!
So for now, I can only believe that there is nothing wrong and that everything is working as I expect it to work.

I also need to make clear that I tested the solution not only in developer but on a server as well, in smart client and web client, with IE 7 and Firefox.
Each time it worked perfectly!

So maybe using the solution and looking at the code, you will be able to clarify this mystery ;-)

Cheers,

ok i have checked out your code and see what you are doing.

Your plugin does a asyn execute of the process method.
And then the web request is done and the process method executes in a background thread.

Then when cancel is coming in wicket will not block it because nothing is busy on the webpage.
so your cancel is coming through just fine. And you call i guess function.call() directly on the cancel method, because i dont see that call coming through IClientPluginAccess.executeMethod()

I did backport FunctionDefinition to 4.1 and added it to the api doc. So that plugin developers can use it from 4.1 version on.

Problem for you is. If you would use 2 FunctionDefinitions, 1 for the process and 1 for the cancel. then your cancel will not work anymore because we now make sure
that every execute is serialized… So for this you have to keep using your hack with calling the function call directly, but do know that this is not supported by Servoy…

Problem is that you set and access a variable over 2 threads… This can go right 99% of the cases you test. But in 1% the second thread doesnt have to see the update of that variable at all

You can go around this by not using a javascript at all but having a variable inside your plugin that people need to access and test.

so in the process:

while(plugin.busy.isCancelled())
{
// do work
}

and make sure that in your plugin you use synchronized or Atomic access (AtomicBoolean) to that cancel variable.

Then kill the whole cancel callback method. In your plugin you do only 1 thing when cancel is pressed and that is setting that cancel variable that you have inside your plugin
This way you have a thread safe plugin and you can use FunctionDefinition to execute that process function async.

Thanks Johan for your detailed reply and for taking the time to clear out this mystery!

jcompagner:
ok i have checked out your code and see what you are doing.

Your plugin does a asyn execute of the process method.
And then the web request is done and the process method executes in a background thread.

That’s what I said I was doing, first async using execute calls the process function, then the cancel method is called directly by Function.call()

jcompagner:
Then when cancel is coming in wicket will not block it because nothing is busy on the webpage.
so your cancel is coming through just fine. And you call i guess function.call() directly on the cancel method, because i dont see that call coming through IClientPluginAccess.executeMethod()

I did backport FunctionDefinition to 4.1 and added it to the api doc. So that plugin developers can use it from 4.1 version on.

I’m not sure of what is a “busy” page as such since user interaction is blocked, so it would mean that the process is doing something to make the page “busy”.
But anyway, that’s great news for the FunctionDefinition in the 4.1 api!

jcompagner:
Problem for you is. If you would use 2 FunctionDefinitions, 1 for the process and 1 for the cancel. then your cancel will not work anymore because we now make sure
that every execute is serialized… So for this you have to keep using your hack with calling the function call directly, but do know that this is not supported by Servoy…

What I have trouble with is when you say this “hack” is not supported by Servoy when Sean Devlin’s web_client_utils plugin is using it, is it not Servoy’s code done by a Servoy’s engineer?

jcompagner:
Problem is that you set and access a variable over 2 threads… This can go right 99% of the cases you test. But in 1% the second thread doesnt have to see the update of that variable at all

You can go around this by not using a javascript at all but having a variable inside your plugin that people need to access and test.

so in the process:

while(plugin.busy.isCancelled())
{
// do work
}

and make sure that in your plugin you use synchronized or Atomic access (AtomicBoolean) to that cancel variable.

Then kill the whole cancel callback method. In your plugin you do only 1 thing when cancel is pressed and that is setting that cancel variable that you have inside your plugin
This way you have a thread safe plugin and you can use FunctionDefinition to execute that process function async.

OK, that would work too, so I will go back to that way of doing, I just thought that using a callback would be better but then the users still need to check for cancel during their process, so there is actually little advantages in it.

I had one last question for you: what kind of reference does Servoy keep on plugins/beans? It seems that the same instance is reused over and over (even if it’s not a singleton): the load and the initialize functions are only called once from what I have been able to deduce.
Does this mean you initialize the plugin once and then keep a single instance all over a solution?
If not, when do you create a new instance? What triggers the creation of the object? Or, from your point of view, when does getScriptObject() gets called?

ptalbot:
What I have trouble with is when you say this “hack” is not supported by Servoy when Sean Devlin’s web_client_utils plugin is using it, is it not Servoy’s code done by a Servoy’s engineer?

You only have to look at the plugins servoy ships in the install package. Those are the plugins that count.
We have

public Object executeMethod(String context, String methodname, Object arguments,boolean async) throws Exception;

for quite some time now, and it is not by accident that we have that where you have to give the context and the methodname as strings instead of objects/functions.

FunctionDefinition just needs a servoy function object and it can extract all that for you
But before FD you should just ask the user for the method name and context (form)name if it isnt a global.

ptalbot:
OK, that would work too, so I will go back to that way of doing, I just thought that using a callback would be better but then the users still need to check for cancel during their process, so there is actually little advantages in it.

I had one last question for you: what kind of reference does Servoy keep on plugins/beans? It seems that the same instance is reused over and over (even if it’s not a singleton): the load and the initialize functions are only called once from what I have been able to deduce.
Does this mean you initialize the plugin once and then keep a single instance all over a solution?
If not, when do you create a new instance? What triggers the creation of the object? Or, from your point of view, when does getScriptObject() gets called?

beans are created if a form ask for them. So you have 1 per form that displays the bean.

plugins are singletons for a user. Not real singletons ofcourse because the webclients are sharing the same machine and they all have 1 instance of a plugin.

jcompagner:
You only have to look at the plugins servoy ships in the install package. Those are the plugins that count.
We have

public Object executeMethod(String context, String methodname, Object arguments,boolean async) throws Exception;

for quite some time now, and it is not by accident that we have that where you have to give the context and the methodname as strings instead of objects/functions.

FunctionDefinition just needs a servoy function object and it can extract all that for you
But before FD you should just ask the user for the method name and context (form)name if it isnt a global.

OK, I will update the plugin with the next Servoy minor release since I guess FD will be there then.

jcompagner:
beans are created if a form ask for them. So you have 1 per form that displays the bean.

plugins are singletons for a user. Not real singletons ofcourse because the webclients are sharing the same machine and they all have 1 instance of a plugin.

Thanks for the clarification!

For plugins that’s what I was expecting.

But for beans does this mean that if you have more than one of the same bean on the same form they will share the same instance?
I will need to check that straight away. My impression was that there was one separate instance per object on a form.

no 1 bean per design element

I was just explaining that you have different bean instances per form. But you also have different instances if you have more then 1 on a form

How I can do work the busy plugin in a Form showed in Dialog mode?, I’m using the
latest version of busy.jar