Realizing an extension
Index
- Introduction
- From the beginning
- Maven
- Building ST
- Getting ready
- Client side
- Server side
- The final countdown
- FAQs
Introduction
Here we show how to realize an extension for Semantic Turkey.
First, the document will guide the developer step-by-step on how to configure the development environment
(system and development tools) in order to achieve this goal. Then, a simple
extension will be realized to provide a lively example for the developer.
From the beginning
As a Semantic Turkey's aspiring developer, you should have already read some documentation about the generic information of the system, and an overview of its architecture, in particular about the “extension points”. If not, please take a look at the extension development page.
The first thing you have to do is download the source code of Semantic Turkey from google code. Follow the “GUI and IDE access” instructions there to discover how you can download the project using “subversion”.
As usual in subversioning, there could be some official code release (associated to a given version of the tool), these are represented as "tagged" versions in SVN (this page allows you to browse different tagged versions of Semantic Turkley code), while the main trunk always contains the last nightly build. You can decide yourself if it is better to develop your extension for an existing official version or to get the last build and make your extension compatible with it. If in doubt, ask the ST developers (the semantic cooks) when the last build will become a new official release.
After completing the download, annotate somewhere your tagged version or, in case of a nightly build from the main trunk, look for the revision number of the source code (if you have used the command line you'll see that number prompted on it).It is important to remember which ST revision you are working on, so you can guarantee that your extension will be compatible until that revision.
In the downloaded folder you can find the following sub-folders:
- SemanticTurkeyBM
- SemanticTurkeySE
- SemanticTurkeyUI
- SemanticTurkeyTS
- ST_EXT-R_Sesame2ImplExtension
By now, you need to know how to work using Maven.
If you already know and are proficient with Maven, you can skip the next steps, otherwise...don''t worry!
Just follow our instructions and you will be able to work on your extension in just 15 minutes.
Maven
<Maven, a Yiddish word meaning accumulator of knowledge, was originally started as an attempt to simplify the build processes in the Jakarta Turbine project. There were several projects each with their own Ant build files that were all slightly different and JARs were checked into CVS. We wanted a standard way to build the projects, a clear definition of what the project consisted of, an easy way to publish project information and a way to share JARs across several projects. The result is a tool that can now be used for building and managing any Java-based project. We hope that we have created something that will make the day-to-day work of Java developers easier and generally help with the comprehension of any Java-based project>
First, download Maven and follow the installation instructions on that
website. To make it short, you must put the unzipped folder where you want to install Maven and set some
environment variables.
The setting-up of this last step need to be permanent. To do so under Linux you have to modify the file
“.bashrc” in your home directory inserting at the end the instructions “export variable_name=new_value” for
every variable, otherwise under Windows you have to “right click on Computer->click on Properties->Advanced
System Settings->Advanced->Environment Variables” and modify the values or add new variables as needed.
Also Maven works with Java, so it is necessary to have a JDK on your own system (but we hope that it is already the case because you are going to work with a Java project).
From now on, when we say: "install <project-name> in Maven", we mean "build that project and deploy its jar inside Maven local repository". The local repository is a sort of local mirror of libraries, which are accessed by your Maven projects to materialize jars specified in library dependencies. More information again in the Maven site.
This guide shows how to invoke some Maven goals, but the full list can be obtained from the Maven website.
Note that you can run maven goals from the command line, or use available plugins for your IDE which may support you in using Maven through user friendly interfaces. The how-to-build-semantic-turkey guide provides useful insights for using the M2Eclipse plugin inside the Eclipse IDE.
A general advice on third party libraries you need to use in your extension: these may have been already included in the Maven Central repository, or may be provided by third party Maven repositories (in this case the vendor should report the site of their Maven repository so that you can update your POM accordingly) or, as a last choice, you need to provide information for installing it. The Maven goal for installing a local copy of a 3rd party JAR into the local repository can be invoke by typing this on the commad line:
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>
If the library has no pom where you can find the groupid, artifactid, version, then you can
choose them by your own.
Pay attention that the mvn install command has spaces between the symbol '-' and the previous word and no
spaces in the assignments with '=' . Otherwise the command will have a wrong syntax!
Building ST
You can find ST building instructions and replies to frequent questions in the how-to-build-semantic-turkey guide.
Note that the ant build file does not Maven-compiles the SemanticTurkeySE project, instead it plainly produces a jar from it, so, for the purposes of extension development, it's better to build in Maven even this project.
type (from the SemanticTurkeySE project folder) on the command line:
mvn clean install
to build the SE project and install it in Maven (that is, the jar is added to your Maven local repository).
It can be useful for you to have a list of frequent Maven goals (and combination of them) you will use.
- clean the project:
mvn clean - the simplest Maven command to build (obtaining the jar) and install a library from its source code
into the local repository:
mvn clean install - full build, deployment to local Maven repository of main jar, test-jar, sources for both and
javadocs
mvn source:jar source:test-jar javadoc:jar
- build and achieve the project package type specified in its pom.xml (default is .jar with a generic
MANIFEST.MF ):
mvn clean package
- full build (main jar, test, srcs and javadocs) + creation of a Maven bundle (useful for submitting
libraries to Maven Central)
source:jar source:test-jar javadoc:jar repository:bundle-create - build an OSGi bundle file (if the maven-bundle-plugin is not installed on first launch, it will be
downloaded, so be sure you are connected to internet at that time):
mvn clean install org.apache.felix:maven-bundle-plugin:bundle - obtain the MANIFEST.MF for the bundle (a previous building is needed):
mvn clean package org.apache.felix:maven-bundle-plugin:manifest
or
mvn clean install org.apache.felix:maven-bundle-plugin:manifest
Now it's time to set-up our work environment.
Getting ready
We'll use the Eclipse IDE for Java EE Developers to work with the project, so all the IDE related tips and the settings we're going to show, are specific for the Eclipse platform (again, see MavenEclipse section of the how-to-build-ST document for info on using Maven facilities in Eclipse). However you can find on the Web other ways to work with other IDEs using Maven.
Now...let's get ready!
Just download Eclipse EE from the official website and set
the workspace. Now install the m2eclipse Maven plugin for
Eclipse following this link
instructions.
Now you have everything, m2eclipse already contains an embedded
Maven installation and is already configured to be usable in Eclipse. However, we recommed to set Eclipse to
use the Maven distribution you installed during the first step of this guide.
In order to do this, from Eclipse, go to: Window->Preferences, then open the tree root on Maven, and click on Installations. In the opened tab add a new installation path inserting the path where the bin folder of the Maven program you installed is located. Then switch from the embedded one to the one you installed.
Now, just pay attention to the instructions already present in the MavenEclipse section of the how-to-build-ST guide.
Building your first Extension: the mass istance creation extension
Now you can start with the creation of your first extension. In this tutorial, you will develop an extension for allowing users to add more than one instance at the same time to a given class
Extension Development: Client side
As you know Semantic Turkey consists of two parts: one of them is a "simple" Firefox extension that implements the Client side of the whole architecture. In the following steps you will learn how to build your own Semantic Turkey client side extension.
Note that Semantic Turkey extensions are - conceptually - extensions of a browser (Firefox) extension, though, from the point of view of Firefox, they are actually direct Firefox's extensions with a dependency on a another Firefox extension (Semantic Turkey).
We assume that you are familiar with Firefox extension development; if this is not the case, please
refer to Mozilla Extension Development site and
take an overview about the Firefox extension.
Installation and registration of files
The goal of this step is to add a button to the main extension allowing us to insert multiple instances to the ontology. Before starting we are going to give you some basic suggestions to improve your development knowledge:
- ST provides a very verbose output for debugging purposes on the Firefox javascript console, you can enable it opening the Firefox "about:config" tab and setting the "extensions.semturkey.log" to the "debug" value;
- Developing a Firefox extension makes us dealing with XUL code. In this sense it can result a very useful instrument to “inspect” this code using the extension DOM Inspector, that lets you read ("inspect") the code related to a particular interface element by simply clicking on it.
The first step for realizing the extension is to create the project structure.
Consider that there are a few Eclipse plugins supporting XUL (and Mozilla extension) development: xulbooster and Orangevolt EclipseXUL are two of them.
In this section, we however report detailed instructions for doing it manually:
First of all, you need to create the folder tree for the project (as specified in the Mozilla Firefox extension website),
<ext path>\ install.rdf chrome.manifest chrome\ content\ sample.xuland, as you can see, to populate it with the right files:
- install.rdf
- chrome.manifest
The first one is used by Firefox to install the extension, while the second one is used to load the extension every time Firefox starts, inserting a reference into the chrome registry [ detailed information at https://developer.mozilla.org/en/Chrome_Registration ].
Writing the code for them is quite simple: advising you that more detailed information can be retrieved at https://developer.mozilla.org/en/Chrome_Registration and https://developer.mozilla.org/en/Install_Manifests, we'll give you some basic knowledge sufficient to fill these files.
Since it can be boring to write the install.rdf due to its syntax, what's better than copying it from
a similar one and modifying it?
So go to the .xpi of ST you created or look at the install.rdf of our sample
extension, copy the install.rdf and make the required changes (it consists only in modifying the
extension-description tags like names, version, creator, paying attention to let unchanged the “em:type”
tag and the “em:targetApplication” one).
Otherwise it is simpler to write the chrome.manifest:
you only need to write the first line like (remember the final '/' !)
“content packagename uri/to/files/”
and (as you can read on the mozilla link above): < < this will register a location to use when
resolving the URI
chrome://packagename/content/...
The URI may be absolute or relative to the location of the manifest file > > .
The second line must refer to the .xul file you are going to overlay and it needs to have the
following syntax:
“overlay chrome://URI-to-be-overlaid chrome://overlay-URI”
The order in which you write these lines in the manifest is not so important. It is more prominent to respect the right syntax. An helpful plugin to verify that your manifest is correctly written (and so your extension is loaded by Firefox), can be retrieved here https://addons.mozilla.org/it/firefox/addon/4453/
The browser's overlaying
If you have already filled the tree folder with the necessary files, open the overlay.xul one
(otherwise create and put it into the “content” folder).
This file contains the graphical elements you want to add (overlaying) to ST. In our case we want to add a
simple button in the proper menu. To reach this aim we wrote this code in our extension:
< popup id="clipmenu" > < menuitem id="menuItemCreateMultiple" flex="1" insertafter="menuItemCreateIndividual" > < menuitem-iconic flex="1" > < image src="../images/multiple.png" flex="0"/> < label value="Create Multiple" flex="0"/> </menuitem-iconic > </menuitem > </popup >The clipmenu id has been found by using the DOM Inspector.
It is important to use instructions that overlay and do not override an existing .xul . As you can see, we used the insertafter value in the “menuitem” tag, so that the button is simply added to the list. If you do not do so your extension will be dangerous and may make it impossible to use ST.
Note that there is no Javascript code in the XUL file, not even to specify the action to associate with the click of the mouse. In fact we recommend to NOT include in this file anything that is not traceable to XUL. Of course this choice doesn't involve the final result, it's just a way to have a cleaner and more understandable code and above all to let the XUL file take different Javascript files simply changing the ones it is importing.
In fact the only duty of the XUL file is to import a Javascript file (through the tag < script >), to give dynamics to the static graphical elements created by the XUL file itself.
Keep in mind that all the windows you let appear must be modal ones. It means that when the window is opened it is possible to interact only with that window and the other task of ST can't be used. It prevents the user to create inconsistency in ST, like creating an instance of a class and deleting the class before the instance is created.
The Javascript file begins by checking the existence of the variable “art_semanticturkey”: it's used as a namespace! In fact every Javascript function name has this prefix, in order to avoid conflicts between our functions and the other ones. This is only a “first level” namespace, used by every function implemented in Semantic Turkey, and we recommend to use a second level too, extending the first one:
if (typeof art_semanticturkey == 'undefined') var art_semanticturkey = {}; if (!art_semanticturkey.multiple) art_semanticturkey.multiple = {};
The first line only checks whether the first namespace is undefined or not; the second one define our
second level namespace. In this case we have used a simple and easy and short name, but in general it's
preferable to use an URI to ensure its uniqueness.
Remember that we refer to these variables as namespaces only for convenience, but they are no more than
simple variables.
The main code lines to open the desired window are below here
var parameters = new Object(); parameters.name = treecell.getAttribute("label"); parameters.parentWindow = window; window.openDialog("chrome://multiple/content/createMultiple.xul", "_blank", "modal=yes,resizable,centerscreen", parameters);
The last line just open a new window passing it two parameters: the class name of the instances we are
going to create and the parent window; the necessity of the first parameter is quite evident, the second one
will be explained later.
The above code lines are contained into the onMenuItemCommand function, and this last is registered
into the onLoad function, adding it to the functions list associated with the event click.
Note that the third parameter explicitly requires a modal window, and that the parameters are passed
to this windows as fields of an object.
What we have showed is surely the most important part of the file, but it will never work until we notify to
ST that it has to manage the click event on our new button; it can be done by the onLoad function, but for
this to be called we have to insert a last statement at the end of file:
window.addEventListener("load", art_semanticturkey.multiple.onLoad, true);
The last step of this “graphical” design is to define characteristics and behavior of the window in which we will insert the names of the instances we want to add to the ontology. Once again you need a XUL file and its related Javascript file; the first one is very simple, just read it to understand its structure and meaning. The Javascript file is similar to the one introduced few lines above: it will contain, among other things, the function that directly implements the way of communicating with the server. This communication is based on the HTTP protocol (request side) and on the XML language (response side), and we encourage you to use the proper functions exported by ST modules by importing it in your code:
Components.utils.import("resource://stmodules/SemTurkeyHTTP.jsm");
This module contains two similar functions that forward the request to ST server: the first one using
the GET method of the protocol, the second one using the POST method. In order to complete this last step you
have to choose between these two methods, taking into account that the length of the request is limited for
the GET while it is unlimited for the POST.
In our case we have chosen the POST because a string composed of ten names can be very long:
var responseXML = HttpMgr.POST("multiple", "createMultipleInstances", ("clsame="+window.arguments[0].name), ("instancesName="+instanceNames));
The parameters of the POST method (the GET one is similar) are:
- multiple, the name of the service you implemented and registered using Felix;
- createMultipleInstances, name of a request offered by your service;
- the parameters you want to send to the service, in this case they are the name of the class involved in the operation and the names of the instances to add
Note that the GET method allow you to immediately test the server side of your extension:
you can just paste the HTTP request in the Firefox address bar and it will affect the ontology in the same
way of the ST interface. To read an example of the address just take a look at the Firefox error console
(make sure you have set the extensions.semturkey.log parameter to debug in the about:config
Firefox panel) immediately after (for example) the creation of an instance. Keep in mind to remove the first
part (up to http://...) and the last one (from async to end) of what you read there before pasting it
in the address bar.
Finished? Almost! Do you remember the parentWindow parameter we have met in the previous lines? It is
fundamental for the proper running of your extension to refresh after the operation of the user interface of
ST (to put it in a consistent state with respect to the below ontology):
parentWindow.art_semanticturkey.createInstance_RESPONSE(responseXML);
That’s all! Now just save your work, compress the directory tree in zip format and rename it with the the xpi extension.
Server side
Remember that the server-side project of your extension will be a Maven project. If you've chosen Eclipse as your integrated development environment (IDE) as we suggested, you have to install the m2eclipse plugin (probably you already did it following previous instructins in this tutorial). From now on, we will assume that you're using Eclipse and that you followed every single step that was stated above. If you're having trouble following the next sections, please
- check again if you've executed all the previous steps correctly
- if the problem persist check the FAQs session for a valid answer
- as a third chance, try to contact the authors or, even better, send a mail to the Semantic Turkey Developers' group
Server side: setting-up
First of all open Eclipse and load your personal workspace. If you go to New and choose the Other
option you'll see that thanks to the plugin installed you have now Maven as one of your possible
option. You have to choose Maven Project under the Maven section.
The project you are about to create is a simple Maven project so you can skip the archetype selection by
ticking the combo box with this option. It is rather insignificant where you place your new project but we
suggest you to keep it in the workspace location so you won't be having problem finding your project folder
on your file system when needed. You can simply ignore all the other option and go forward to the next
screen.
In this second screen you have to enter some data regarding your artifact such as yout group id, the
artifact id, the artifact version and the type of packaging. It is quite simple to guess what this few fields
means but in any case, the first field, the group id, is a name or a code needed for identifying the creators
of the extension, for us it was STEDoc Team. The second field is needed for identifying the extension, it is
always better to use a name related to the extension capabilities and use. The version is needed for a more
organized upgrade of the extension(remember that the SNAPSHOT suffix is useful to imply that the released
version is not completed).
As the type of packaging you have to use bundle. The parent project field can be always be leaven
blank without any relevant consequences.
In this screen you don't need to do anything and you can simply press finish and create your new Maven project.
The project has the classical Maven directory layout. In the folder named src /main/java (i.e. the section for java code related to the application you are developing) you can start to build your extension package/namespace. Fo our one, we use the standard one for semantic turkey, but you can use the one related to your company/organization:
it/uniroma2/art/semanticturkey/
To do so, you have to right click on the src/main/java folder in the Eclipse environment and
create a new package. We suggest you using it.uniroma2.art.semanticturkey and as path #project_name#/src/main/java/it/uniroma2/art/semanticturkey/
. Naturally every new source file must be created inside the new package you've created.
Now browse the project and open the pom.xml file inside eclipse.
Here you can see a simple user interface where you can insert data about your extension. Particularly
you need to select the second tab labelled “Dependencies” in the bottom of the window and add all the
library to which you depend on. To do so click on the “Add” button in the section on the top-left of
the main window, and begin to type the path of the library you installed in the Maven repository (the path is
not an absolute one: it begins from the first folder of the library, i.e. for ST is
“it.uniroma2.art.semanticturkey.semanticturkey”). If the package you are looking for does not appear, you can
create manually the dependency clicking on “Create” and filling the section “Dependency Details”
on the right. The first dependency you have to set is the one relative to SemanticTurkeyBM: it was inserted
in your local repository when you built ST during the first steps of this guide.
If you need to create the dependency with the create button (for the above reason), you may want to know
which are the strings you need to insert in the boxes. Well, to discover it, you have to look at the pom.xml
file of the relative jar library, so:
go to your local Maven repository and follow the path to the desired jar, then open the jar and look for the
pom.xml (generally it is in the “META-INF” folder). The only tags you need are: groupid, artifactid,
version. So use them to fill the boxes and terminate the setting of the dependency. Be sure that the symbol
near the dependency-name is not a folder. If it's not, refer to the last part of this webpage. After setting all the
dependencies you can save the pom of your extension and, if needed, update all the dependencies (right click
on the project->Maven->UpdateDependencies). You can see that a background process is working for you and it
is catching all the libraries that are not in your local repository but in Maven-central. If some libraries
you specified in the dependencies are neither in your local repository nor in Maven-central, you can see an
error on the console, so you need to download and install it manually because it isn't in any repository.
As a second step in setting-up the pom you need to specify the maven bundle plugin useful to obtain your
bundle. Select the tab “plugin” in the pom window and add the plugin clicking on “Add” button
on top-left of that window, type “org.apache.felix” and then select “maven bundle plugin” and
when it is inserted tick the checkbox “Extensions” in the top-right to automatically insert the
extension tag in the pom. You could specify other configuration tags for this plugin like the “bundleName”,
“bundleDescritpion”, “bundleVendor”, … . The most relevant for the extension is the “Bundle-Activator”
tag, that is used to specify the path of the bundle activator class. Another important tag could be the “Import-Package”
one used to specify in the future MANIFEST.MF which packages are needed by the extension (and, eventually,
which not). To do so check the packages you are using and insert them in this tag (be aware to insert
the name package but not the class path!). However if you do not specify any tag the default will be used and
the packages to import will be all the dependencies, the dependencies of the dependencies, and so
on...[further information clicking here
]. Also modify the “org.apache.maven.plugins:maven-compiler-plugin” in the pom, but specifying as
further tags the following:
< configuration > < source > 1.5 < /source > < target > 1.5 < /target > < /configuration >
keeping in mind that 1.5 is the version of the jdk you are using or you are forcing to use with this project (be aware that until jdk 1.3 generics are not supported).
Moreover verify that the tag “packaging” with value “bundle” is present into the “project” tag (you should have inserted it before into “Packaging” list in the overview tab) so that the command “mvn package” will export a jar file containing a MANIFEST.MF specific for a bundle.
If these steps were tedious for you, think about on configuring manually the pom, writing yourself the xml code resulting in the tab “pom.xml” of Eclipse. We think you should be thankful to Eclipse plugin for helping you.
After this last setting-up, you can begin coding your classes, keeping in mind that if you need to add other dependencies or plugins you have only to add them in the pom.xml (as it is specified above), and let Maven worry about it.
Server side: generic implementation
Now that everything is ready for creating the server side let's see how it works. We are trying to add a new
request, or possibly more than one.
A request is a new method available for the ST's plugin on Firefox once it has been extended with the client
side of our extension, which will call the new request in the server side. If you want ST to cope with your
new requests you have to extend ST with a new service.
A service can be seen as a container for new requests: all the requests are contained into a service, and
since we have more than one service registered on the platform we can have multiple requests with the same
name defined in different services (be aware that is also possible to register more than one service in the
same activator class). As you've seen while making the client side of your extension, the HTTP request
contains both the field service and request. Thanks to these fields we can identify the code that must be
executed when ST's server side receives the message.
You have to create a class that will be used to register the service when ST is started (this is usually
called the activator class) and another class that will contain the code to be executed when the registered
service will be asked from the client side.
This structure is necessary because ST uses an OSGi platform, in particular the Apache Felix implementation, to make the services, and thus their
relative requests, available.
So, create two new java classes: the first one will be used to register (automatically) the bundle on
Felix and consequently its service on that platform service-registry, while the second one will manage the
service.
In both cases it is strongly recommended to give them names recalling the service. Generally, for the bundle
activator class, this name is followed by the “Activator” suffix(for example we used
“CreateMultipleActivator”) while the second class carries the same name as the first one without the
“Activator” suffix.
As we said above the activator class will allow the service to be registered on the Felix platform. To do so
it must implements BundleActivator interface and so it will have to contain the two methods stated in the
interface: “start” and “stop” each of them throwing Exception to prevent any single exception
that your extension could generate.
We will concentrate on the start method leaving the stop empty because, at this moment, ST does not support
stopping a service.
The method that you must call in start is:
context.registerService(ServiceInterface.class.getName(), new *class managing the requests*(String *service name*), null)
where the first parameter is the string that will identify the class that managing the service, while
the second one is an instance of the second class you created.
It is important that you use a unique name for the service. In fact ST uses a map data structure to manage a
table “service-serviceID”, and since the services are registered sequentially, a serviceID (the service name)
may overlap a registered one and the following behaviour may be undefined. It is so necessary that you check
the existing services (looking at the source code of ST or other ST-extensions) and be sure to never use an
already used name.
There is no need for you to add anything else inside this class. In fact this one must be as simpler as
possible: it might only register the services and might not include any other instructions, because the
registering of the services might take too much time and fail, making impossible to use the extension. If you
need you can at most put in it a print method to verify that the services has been registered, but it is
recommended to remove it after debugging.
Now we're going to talk about the second class.
As we suggested before use a name similar to the service you are creating. Usually it is named as the bundle
activator class without the “Activator” suffix. This class will manage your new service and so all the
requests defined in it.
This new class you created has to extend ServiceAdapter.
It is greatly recommended to declare a few useful static final variables for a better reading of the code by
other programmers, declaring this variables will make the code easier to understand, easier to adapt to
another request, more general.
Adopting the scheme used on the original ST project you should divide these variables in groups according to
what they stand for. A good division could be:
- requests: can be divided in smaller groups identified by the type of the requests (as get, add, create... ). This group shall contain strings that will identify the names of every single request inside your service. It is suggested to make all of them both final and static and leave them public so the request list may be accessed from the outside but not modified.
- parameters: this group should contain the list of all the parameters of every single request in this service, naturally two or more request can share the same parameters so it may be more difficult to divide them in subgroups. This variables should be public final static as the previous ones.
- values: this group should contain all other useful variables needed to fulfil the requests. The Logger variable is very useful for posting messages on the java console.
public Response getResponse()
This method will be called when the service registered by the activator will be specified in the HTTP
message sent to ST's server side.
It is then necessary to make a sequence of controls to understand which request has been made and be ready to
get the parameters of the request.
To do so we need two local variables: a new ServletUtilities object and a string in with you can put the
request specified in the HTTP message thanks to the method setHttpPar(“request”). Now comparing the
string containing the received request with the various strings that you should have created beforehand
regarding the various requests, you can identify which request was forwarded in the HTTP message.
Once you've recognized which request was received you have to get the parameters from the HTTP message and
then execute the request.
For retrieving the parameters from the HTTP message we can use the method of the class ServletUtilities (you
should have created an object of this class already):
String removeInstNumberParentheses( setHttpPar( *parameter variable* ) )
< parameter variable > is one of the variable you should have created beforehand containing a
string reporting the tag of the parameter inside the HTTP message.
Naturally if the request is not specified in our service we need to return an error of the type
createNoSuchHandlerExceptionResponse as the response.
Before returning the response it is also important, if the response is created correctly, to execute the
method:
void fireServletEvent()this method should communicate to the other listener who registered for this event that the request was computed
Now we can't possibly know what kind of extension you want to make so we will continue describing our extension as an example hoping that it may be helpful.
Server side: implementation of the "create multiple service"
After taking the parameters from the HTTP message we had to separate the various instances names that were passed with this logic:
instancesName=name1,name2,name3,...,name10
We created a method that returns an ArrayList
The method that will create and return the Response object is:
Response createMultipleInstancesOption(ArrayList, String)
We passed to the method the ArrayList containing the various names of the instances and the class name. Of course we control if the user has inserted at least one instance name, if not there is nothing to add to the ontology.
Inside the createMultipleInstancesOption method (it was called like this recalling the method of the
single instance creation in the original ST project) we had to create several objects for instantiate the
ontology model and the various resources such as the class and the many instances to be created. Using the
existing methods from the original ST's project we added the instances inside the ontology if they are not
already existing inside it.
The method updateClassesOnTree takes the class name and the new instances names as well but has the duty of
building the XML response to send back to the client side. The XML message we created is as similar as it
could be to the one that the original ST's project uses.
It is not the role of this guide to illustrate how to create an XML message but since creating a correct
response for the client side is one of the key points of the extension on the server side, we are going to
provide some general notices.
First of all we can use an object of the class ResponseREPLY to contain the response. Is has to be initialized correctly, for example we used:
ResponseREPLY response = servletUtilities.createReplyResponse(request, RepliesStatus.ok);
The first think you can note is that the constructor has two parameters, the first one will specify
which request has been answered to, and the second one will specify the status of the message.
In the XML response elements can be added. It is possible to create many types of elements just instantiating
the Element objects in different ways. One of the most useful is creating an Element referring to a specific
tag in the XML like the data tag. To obtain “control” of the data tag we instantiated the Element object with
the following method:
Element dataElement = response.getDataElement();
Using this Element we could include other XML elements inside the data part of the XML message. To create a basic XML element we used:
Element clsElement = XMLHelp.newElement(dataElement, "Class");
with this instruction we obtain a new XML element of the type “Class” contained in the data section of the XML message. After having created the instance the attribute of the XML element must be initialized:
clsElement.setAttribute("clsName", *value* );
Once all the XML element are created we had to simply return the ResponseReply object and the ST's code on the server side will send it back to the client side.
We are aware that this example doesn't cover all there is to know about the making of the XML file and the creations of elements, but we leave it to the reader to learn more about the XML from other sources in order to create more advanced features.
The final countdown
Once, you coded the client side you should be ready to make your own .xpi and install it in Firefox.
But if your extension needs a server side (so it's not only a graphical extension), then you need to create a
bundle containing the service provided by the server side of your extension.
As we mentioned above, if you set-up correctly the pom.xml, you need just to use the command
mvn clean package
and get you packaged jar bundle file (be sure that the MANIFEST.MF inside is correct!).
To create your full client-side extension put the bundle jar into the “extensions/service” folder of the main folder, so that you will have the following folder tree<ext path>\ install.rdf chrome.manifest chrome\ content\ sample.xul (& related .js) extensions\ service\ your_OSGi_bundlethen select all the folders inside the main one and zip them into a file. Now simply rename the file into .xpi and drag it into Firefox to install it.
If it works fine, well done! You reach your goal!
If it's not, don't panic! It is easy to forgot doing some steps or to make some mistakes. So read your code
and verify to have followed our instructions.
If you have any other questions please refer to the FAQs or contact us.
Have a nice coding!
FAQs
- Why do I get an error like: < < Unresolved references to [org.w3c.dom] by class(es) on the
Bundle-Classpath[Jar:dot]... > > ?
You probably imported the class (instead of the package) into the pom. Look at the pom.xml, remove the final reference to that class and importing the package only - Why do I get an error like: < < Error building bundle
it.uniroma2.art.semanticturkey.ontology:sesame2ontmanager:bundle:1.0.2 : Class in different directory than
declared. Path from class name is it/uniroma2/art/owlart/sesame2impl/MultiIndexedMap.class but the path in
the jar is lib/classes/it/uniroma2/art/owlart/sesame2impl/MultiIndexedMap.class from Jar:dot > > ?
Please refer to the last part of this page: http://semanticturkey.uniroma2.it/documentation/building.jsf - Why in my MANIFEST.MF does my package export all the packages it depends on?
If you do not want this to happen insert the tag Export-Package in the instruction tag of the maven bundle plugin and type inside: " !my_package_name ". So doing, no packages will be exported - Why is the MANIFEST.MF of my package a generic one instead of a bundle specific?
Maybe you forgot to insert the tag "packaging" into the “project” tag - What is the scope tag?
Refer to: http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html - How can I see the reporting errors/messages on the Java Console?
You have to activate the Java Console when a Java application is running to see the System output inserted in the code.
Instead, to set the log messages visible you have to modify the file log4j.properties changing the assignment “log4j.rootLogger=ERROR” to “log4j.rootLogger=DEBUG” (Remember to set back it when you finish debugging). This file can be retrived at “.mozilla/firefox/firefox_user_id/extensions/semanticturkey@art.uniroma2.it/components/lib/resources” on Linux, or “C:\Users\User_name\AppData\Roaming\Mozilla\Firefox\Profiles\firefox_user_id\extensions\semanticturkey@art.uniroma2.it\components\lib\resources” on Windows - Which are the constraints to write a MANIFEST.MF for an OSGi bundle?
If you use correctly the user interface provided by the Maven plugin in Eclipse, do not worry about it. Instead if you want to write it by yourself, you have not to overflow a maximum number of bytes for each line. If you need to do so, keep in mind that you have to stop writing before the 72th byte, and continue writing on the line below leaving a space at the beginning of the line. Moreover you have to insert a blank line at the end of the file. (For more information about the constraints surf the web). - Can I avoid to every time restarting Firefox after any edit to the javascript/xul code of my
extension?
Type “about:config” in the address bar, then right click on the opened tab and insert a new boolean value. The parameter name is "nglayout.debug.disable_xul_cache", set it to TRUE. - When to use the "window.onload" statement and when the "window.addEventListener" one
at the end of Javascript files?
These statements are generally useful for initializing our components (such as a button) and enabling the managing of an event (such as a mouse click). If these things can be done by a personalized function, on the other side we need someone to call this function; it can be done by "onload" and "addEventListener", so we use the first one in files that are related to our components (such as a window) and the second one for components you can't control (such as when directly overlaying ST), in order to do not overwrite the previous EventListener list