Tutorial1-PluginHowTo-Part3
Tutorial1-PluginHowTo-Part3
Now is (finally!) time to implement our second main class, the “WhoisPluginProvider” class for which we
already have a stub nicely prepared for us by Eclipse. As you remember, all we have to do is to follow the
“TODO” task trail and implement each method one after the other. Or so it seems…
But first, we need to take a good look at the IScriptObject interface that our WhoisPluginProvider class is
going to implement, so let’s browse to the public API and click on the relevant link to get the interface
definition:
1/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
We’re in luck because this interface doesn’t extend any other, so we only have to implement the methods
above.
Now, let’s look at them in details:
¾ getAllReturnedTypes() should return a Class array (“Class” is a java class that defines the type of
class). I particularly like the comment here which is ambiguous and quite misleading:
“If the returned class has a default constructor and is instanceof IScriptObject move sample will work.”
What the hell are they talking about?
In fact, what they really mean is that you can return here an array of all the types of objects that the
scripting methods of this object will return. This is useful if the returned objects need to be accessed by the
scripting environment too (Servoy).
Just imagine that you write a scripting method that, when invoked by the client using the plugin, would
return another object and that this object itself has useful methods that you want to expose to the client.
For an example of this, look at the http plugin for example, and see in the Servoy’s Solution Explorer how
you can deploy it in the tree to reveal 2 “inner” objects: “Poster” and “Cookie”, now if you look at the
sources of this plugin (they are in the jar!), you will see that the getAllReturnedTypes() method of the
HttpProvider class returns an array of Poster and Cookie classes:
public Class[] getAllReturnedTypes() {
return new Class[] { Poster.class, Cookie.class };
}
Note the construct that looks a lot like JavaScript: you create an array by filling it with values (only that they
are enclosed by parenthesis), and note too how you can access the Class object of any class.
Now one interesting thing to add is that even if the misleading comment above tells you that the returned
classes need to be instances of (instanceof is the operator that can test what an object’s class, superclasses
or interfaces are), this is not true at all. You can try it yourself, and return a String.class in your Class[]
array, and you will see that it will appear in the Explorer node under your plugin, exposing all its methods to
innocent JavaScripters ;-)
This is what I would call the “naked object technique” - if you ever need to access a java object directly,
you can do a plugin that will return an object of this type, and you will find that all its methods will be
exposed! Now the IScriptObject interface in this case is actually acting as some kind of opaque underwear to
hide the facts of life in java to the JavaScript children ;-)
Now this is true with the latest (as of today) version of Servoy v4.1.3, I cannot guarantee that it will still be
the case in the next major releases, but right now it can be convenient, something to keep in mind anyway.
Now since the client (Servoy) is giving you when it calls this method which method name it is, you will have
to test the methodName and return an array depending on it. Look at the HttpProvider class and you will see
that there is a few methods and that the implementation of the method getParameterNames() is testing the
methodName with a series of if…else if construct. And look at the getMediaData test for example and you
will see that the method returns
new String[] { "url", "[http_clientname]" };
2/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Note the [] inside the string for the second parameter and you will be able to deduce that these strings will
be inserted verbatim inside the tooltip
Because in fact before coding these methods you really need to think about what your plugin is going to do.
You need to define what methods will be useful to your users, what parameters you are going to allow, and
basically what you plugin is doing for a living.
Now, I’m not going to go too deep in the details of that, just a few hints because this is the kind of code that
you will find in many java IO tutorials. You can find information on the internet about how to access a server
using a Socket object, how to read and write using InputStream and OutputStream or Reader and Writer
objects.
Basically to communicate to a server using any protocol, we need to create a Socket. If we look at the
definition of a Socket in the java API, it states that “A socket is an endpoint for communication between two
machines.” – just what we need.
Now to create a Socket, there are lots of constructors, but basically the one we need is the one were we can
specify a remote server (our whois server) and a port (the default port used by whois servers –default being
43). So it will be something like that:
Socket socket = new Socket(server, port);
Then we also need to define a timeout, because we don’t want to wait forever, right?
Our user might prove very impatient if for any reason the network is not responsive enough. So we setup a
timeout like this (the unit is milliseconds):
socket.setSoTimeout(timeout);
3/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Now to be able to communicate on a socket, java use the IO API, and the base interfaces to read/write on
IO endpoint (whatever they are, sockets, files, etc.) are InputStream/OutputStream and Reader/Writer – just
look in the java API for these. So let’s create a Reader to read from like this:
It’s always good practice to encapsulate your streams into a buffered implementation (after all you don’t
know how big the stuff to read will be, you wouldn’t want to load a huge amount of data in memory, now a
buffered implementation (of InputStream/OutputStream or Reader/Writer) just guarantee that if needed it
will use some caching to deal with it.
Now that we can read from our socket using our Reader, we also need to be able to write onto it (to send
the domainName query), so we create an OutputStream like this:
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
This time we don’t really need a buffer since there is going to be a very little amount of data to send (a
simple String).
Now we are all set, let’s call the whois server with the domainName query:
We terminate with a carriage return to tell the distant server that our name ends here.
We define a string to receive each line, and a StringBuffer to concatenate the lines received (StringBuffer is a
way to optimize String creation in java, you will find many examples of its use, it is an essential base class
for String manipulation, see the java API for more info).
Now we can iterate for each line received and fill our StringBuffer. Once finished, the readLine() method will
return null, so we can exit our loop.
To wrap up, we need to clean our mess by closing everything we opened (in the reverse order to what they
were opened), so we write:
// close our stream and reader
out.close();
in.close();
// close the socket
socket.close();
And finally we will return the result of our query like that:
return buffer.toString();
No need to test for null here, we know our buffer isn’t since we created it ourselves a few lines earlier!
4/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
To be on the safe side, though we will need to wrap all of this code into a try/catch block, to trap all the
nasty Exceptions that can happen when dealing with the network – you know that one day or another they
will!
There is 2 set of catch blocks because you might want to do different things if the error is an IOException
(network problem) or any other Exception – here it does the same thing return the message of the exception
to the caller of our method
That’s it. That’s our implementation of a method to query the whois server. Now those who are still awake
might have noticed that I haven’t used any String for the “server” and domainName nor did I put any int for
the port and timeout parameters.
5/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
There is more than meets the eye to that method signature, and especially its name.
First, notice that it is “public”, meaning that any java object with a reference to an object of this class will be
able to call it. After all, we want the Servoy JavaScript environment to be able to call it, so that’s fine!
And of course it returns a String, hopefully the response from the whois server or an Exception message if
something went wrong.
But the name? You would think that you can name you method anything you want as long as it is public.
To a certain extent that is true, AS LONG AS IT STARTS WITH THE MAGIC “js_” PREFIX.
In fact, any public method of an IScriptObject that starts with this “js_” prefix will immediately be available
to the Servoy JavaScript environment.
For those of you who don’t buy magic, I would explain that in java there is a way to discover what’s in any
class (what properties, what constructors and methods and with what arguments). It is one of the most
powerful feature of the language and it’s hidden in an API called “reflection” – see
http://java.sun.com/docs/books/tutorial/reflect/index.html for an in-depth explanation of what Reflection is,
how powerful it is and how you should use it wisely if you want to avoid performance problems.
Basically, even if I don’t know the exact way Servoy has implemented it, I know that there is a fair chance
that it’s using the Reflection API on the IScriptObjects found to know what kind of methods to display in the
Solution plugin tree and to give you access to them in the scripting environment.
Now if you want to have some fun, you can try deploying your whois plugin as-is, with just this one method
and deploy it as a jar (see further on) into the /plugins folder of Servoy. If you do that, even without having
implemented any of the IScriptObject interface (other than the empty stubs that Eclipse did for you, you
would find that you plugin is totally operational, already!), to prove it, I have made a version of the plugin
with only this method and a few aliases method (see further on) and packaged it into a plugin.
You can find it here:
http://servoy-stuff.net/tutorials/utils/t01/whois-v00.jar
If you use Internet Explorer and it insists on saying that the download is a zip file, all you need to do is to
rename it after the download from whois-v0.zip to whois-v0.jar again – I guarantee you IT IS a jar file!
6/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Put it into your “/plugins” folder and restart Servoy developer, you will see that our little plugin is here
already, and more important our js_query method has been recognized and appear in the tree under the
label “query”:
And call your method in any developer’s client (smart or web), it will output the response from the server in
your console panel, a big stream of information starting wit something like that:
NOTICE AND TERMS OF USE: You are not authorized to access or query our WHOIS
database through the use of high-volume, automated, electronic processes. The
Data in Network Solutions' WHOIS database is provided by Network Solutions for
information
purposes only, and to assist persons in obtaining information about or related
…
Proving that we just made a perfectly functional Servoy plugin, smart and web client compatible!
You can call a JavaScript function with any number of arguments. You can’t do that in Java (unless you use
some special constructs introduced with java 1.5 – know as “varargs” – look for it on the internet).
But varargs have some constraints too:
- Method with varargs is called only when no other method signature matches the invocation.
- Only one varargs per method can be declared.
- Varargs should be the last argument (set) for a method. So
public void varargTest(int i, String … args) is valid, but
public void varargTest(String … args, int i) is not.
- Zero or more arguments can be passed for varargs unlike an array where at least a null has to
be provided.
I prefer not to use varargs in Java (you can call me old school) if I can avoid them. And anyway you cannot
use varargs for a mix of object types like we have: in our method signature we have String and int.
Meaning that we would need either to have two varargs (which is a no-no in Java - see above), or to have a
signature like public String js_query(Object… arguments) which would force us to do some casting to
retrieve usable objects, a waste of time and a lot of code in perspective, I don’t think it’s worth it.
There is another way to deal with “optional” parameters, and this is overloading our method.
Basically we will do some alias method of method with less parameters, and these alias methods are going
to call our “core” method providing it with always the same set of parameters coming from default values.
Let’s see how.
First we need to provide the “default” values for all the arguments that are going to be optional. So let’s
define some private variables at the top of the class:
Note that it could be nice to create some accessors (get and set methods) to these properties, in case the
user would want to set up its own default values, so let’s add the getters and setters. In Eclipse there is an
easy way to do it.
8/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Once you have typed your private variables in the class, save it and go to the menu “Source > Generate
Getters and Setters…”
The following dialog will show you all the private properties (variables) that Eclipse discovered in your class.
Check all the properties for which you want Eclipse to generate the accessors, choose a place to put them (I
usually put them at the end of the class, this are not really interesting/essential code as such), and click OK.
9/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
You will see that Eclipse has generated a set of methods like this:
/**
* @return the server
*/
public String getServer() {
return this.server;
}
/**
* @param server the server to set
*/
public void setServer(String server) {
this.server = server;
}
I will not explain why this is better than having your properties simply set as “public”, it goes with the whole
idea of encapsulation, and if you’ve never heard of it, you should look for it on the internet… Anyway for
now, suffice to say that this is useful, this is cleaner, this is secure, and in the future this will help you
manage your code.
10/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
So now that we have getters and setters for all the properties that might be changed, what if we made so
that users can access them from the scripting interface?
You should have guessed by now that to be available by the interface, all you need to do is provide methods
starting by the “js_” prefix, so let’s do that. Rename all the getXXX and setXXX that Eclipse just created for
you in js_getXXX and js_setXXX.
Since we have a pair of getter and setter for each variable, Servoy will understand that this is really
properties and it will allow users from the scripting environment to use this kind of syntax:
plugins.whois.server = “whois.internic.net”;
I have made a jar of this intermediate version for you to test it:
http://servoy-stuff.net/tutorials/utils/t01/whois-v01.jar
If you put it in your /plugins (get rid of the previous one first, of course!), when restarting Servoy, you
should be able to see 3 new properties in the Solution explorer’s plugin node, like that:
As you can see, these are marked with a little “P” icon. So, now we know how to make “Properties” for our
plugins, let’s get back to smoothing the edges of our plugin, this time by adding the capabilities to deal with
optional parameters.
I already said that, unless you are using varargs (which will not do in our case) you cannot use optional
arguments in java methods. So how are we going to allow for users to call our method with only one, 2 or 3
arguments when our core method needs 4?
11/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
The answer to that is called operator “overloading”. Basically, the principle of overloading is that for one
method with a certain set of parameters, you write some other methods with another set of parameters but
with the SAME NAME.
Remember that our core method (the one really doing the job) was using this “signature”:
public String js_query(String domainName, String server, int port, int timeout) {…}
As long as the set of parameters (arguments) of our method is different from any other, the compiler will be
happy (because he will be able to recognize it as different from any other), and will not complain that “a
method with the same name already exists”.
But are you going to copy the content of our core method into each of these new methods, changing the
content slightly so as to use your default variables? Of course not, all you have to do is to call the “core”
method from within the “alias” or “overloaded” methods, like so:
As you can see above, each method is really just passing the call to our “core” method, providing our already
set “default” value by using the inner variables of our class (the this keyword here is really optional, but it
is just a way of making clear – for you, later - that the variables are the inner variables of our class, the
compiler knows that already).
So with this set of alias methods we are now able to use these kinds of calls from the scripting environment:
plugins.whois.query("servoy.com");
plugins.whois.query("servoy.com", "whois.networksolutions.com");
plugins.whois.query("servoy.com", "whois.networksolutions.com", 43);
plugins.whois.query("servoy.com", "whois.networksolutions.com", 43, 30000);
12/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Remember them?
First one is:
public Class[] getAllReturnedTypes()
Here we can return null (get rid of the // TODO Auto-generated method stub to indicate that we
finished implementing the method).
You remember the construct? We create a static String array, and give back the name of all the parameters
of our method. Note that to indicate that some parameters are optional, we enclose the parameter name
String with square brackets, and this is how it will appear in the signature tooltip of our method in Servoy.
This time we are going to send back a useful sample usage of our method (this is the one which will be
pushed into the scripting editor when using the “move sample” command of Servoy.
Note that I used a StringBuffer (always good practice when you need to concatenate Strings) and returned
the string with the toString() method.
Note also that I use \t before each line, so that the inserted code lines up cleanly in the JavaScript editor.
And finally each line is finished by a newline character \n.
And the final method, easily enough, is already done for us, just get rid of the // TODO comment to mark it
as done:
public boolean isDeprecated(String methodName) {
return false;
}
13/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
This is because our method is not deprecated yet, we just wrote it!
So we just answer “false” to Servoy’s inquiry about the freshness of our code here. ;-)
We can go to our “Tasks” view to confirm that it is empty. If not, go to the tasks by double-clicking on it and
verify that you got rid of the // TODO comments and implemented the code correctly.
This time all the code needed for our little plugin to function nicely in the Servoy environment is done.
Now all we need to do is to wrap our plugin into a nice little jar and put it in the /plugins folder, and build a
little test solution to go with it…
This is not strictly true. Servoy 3.5 is built “against” Java 1.4.x and above while Servoy 4.1 is built “against”
Java 1.5.x and above. Now you should know that java changed a lot between 1.4 and 1.5, so you need to
set up your target JRE for one version or the other. And since the current JRE is actually 1.6.x it is essential
that you choose a target for your compilation, otherwise your source class might not work and your plugin
will fail with a “java.lang.UnsupportedClassVersion – Error: Bad version number in class file”.
So how do you target a specific JRE for your project within the Eclipse IDE?
Go to the menu “Project > Properties” while your project is still selected in the Package Explorer:
14/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
You get the properties dialog specific to your project, now click on the “Java Compiler Node” and check the
“JDK compliance panel”:
15/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
If it says “6.0” that’s bad, we need to check the “Enable project specific settings” to allow a specific target
for our project. Let’s check it and choose “1.4” in the “Compiler compliance level dropdown”, then click “OK”:
You will see that a dialog informs you that Eclipse noticed that you wanted to change the target for your
project, so it says that it needs to rebuild, answer “Yes” to that prompt.
16/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
But now what happened to our project? When we look at it in the Package explorer view, it displays like this:
The truth is that in the WhoisPlugin the code that was generated by Eclipse in the first place was done
according to the level of compliance which was 6.0. And Java since 1.5 had added some new options to the
language, namely (in our case) what is known as “annotations”. You will see in the “problems” view of
Eclipse that the errors are all related to the fact that “annotations are only available if source level is 5.0”,
since we changed our level to 1.4 annotations are no longer valid.
17/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
So basically all we need to do is to get rid of them: they are these lines (currently with a squiggly red
underline) like that:
@Override
Go ahead! Delete all these pesky annotations for good. Once you are done, your class will compile and you
will no longer have errors anywhere!
If you still have some warnings (little x on red background attached to our .java files) check your code!
If in doubt, download the 2 classes I have put on the Servoy Stuff site.
To create a jar file for our plugin, right-click on the project folder in the Package Explorer and choose
“Export…”:
18/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
In the export dialog, expand the “Java” node and choose “JAR file”, then click next:
19/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
In the JAR Export dialog, the project should already be selected, (if not, select it :), and you can deselect the
“.classpath” and the “.project” files (to avoid polluting you jars with unwanted files only used by Eclipse)
Check the “Export generated class files and resources”, leave the other one unchecked (see Eclipse doc for
more information about these options)
You can choose to export the jar directly into your /$servoy_install_dir$/application_server/plugins directory,
just use the browse button to navigate to it, and give it a name (let’s use “whois.jar”) – you can choose to
locate it somewhere else. Personally, I like to put it directly there, so that if I want to test it, all I have to do
is restart Servoy developer.
In any case it won’t break your Servoy install, so I consider it safe to copy it directly there, it’s a nice
shortcut.
Finally, check the “Compress the contents of the JAR file” to make it lighter, and leave the other options
unchecked (again for more details, see the Eclipse doc).
20/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Click the “Next >” button, you are now faced with the “JAR Packaging Options” dialog:
Leave the 2 “Export class files…” checked, and check the “Save the description of this JAR in the
workspace”. You will need to use the browse button to navigate to your “WhoisPlugin” project, and give a
name to your definition, I chose “whois” and Eclipse automatically added the “jardesc” extension.
NOTE: What is nice about this option is that the next time you will want to deploy your jar (with modified
sources for examples), all you will have to do is right-click on the file “whois.jardesc” in the Package explorer
and choose “Create JAR” in the menu. A great time saver that will dispense you to go through all the Export
dialogs each time you change something in your plugin.
21/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Now, when we click “Next >”, we are faced with the final Dialog, the JAR Manifest dialog:
We can leave it like it is above. Eclipse will generate a default “MANIFEST.MF” file into a folder “META-INF”
which is supposed to contain information about the compiler used, the java version, the version of the jar,
etc… It can also tell java which class contains a main() method (for standalone programs), and in case of
Java Beans, it can tell which class to look for beans.
In our case, since we are building a plugin and not a bean, we can use the default and let Eclipse deal with
that.
Now click “Finish” on our dialog, our whois.jar should have been copied right into the Servoy plugins/ folder
and all you need to start using your plugin is to restart Servoy!
That’s it. You’ve done it! Congratulations! Let’s just wrap this tutorial by building a small test solution.
Let’s add a “test” form, you can build it on any table you want, we are not going to use the table anyway!
22/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Then put two fields based on the forms variables and lay them out on the form, this is how mine looks like:
Download (rename to WhoisTest.servoy if IE insisted it is a zip file), and import via the servoy-admin
“Solutions” page.
23/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Working great!
24/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
Success!
I hope you enjoyed following along this walkthrough tutorial, that you learned a few things here and there,
and that now you feel more curious about this “dark side” of Servoy, that is not so dark really ;-)
I also hope that now you feel ready to create some new and exciting plugins for Servoy that you will
hopefully release as Open Source, so that others will be able to use them and contribute to them for the
better of the Servoy community.
Send them to me and I will place them on the Servoy Stuff site if you want, with due recognition of your
contribution. Feel also free to send me your comments/questions/suggestions about these tutorial or other
Java/Servoy topics, on the Servoy forum of by using the contact form of the Servoy stuff website.
http://www.servoy-stuff.net/contact.php you can also post comments on the blog, it is a free space for
everyone to give their free opinions : http://www.servoy-stuff.net/blog
Patrick Talbot
Servoy Stuff
2009-06-14
25/26
How to build a plugin for Servoy - A step by step tutorial brought to you by Servoy Stuff
PS: I will share the whole project as well as the finished jar in the "downloads/plugins" section of the Servoy
Stuff site, (you can simply use the “File > Import…” menu and choose “Import existing project into
Workspace”:
And then in the next dialog, check “Select archive file” and browse to the downloaded zip project:
Etc…
26/26