|
|
|
1.Introduction. |
|
This document describe how to use the framework's components.
|
2. Embedded database use. |
|
2.1 Database creation |
|
There are two ways to create a database.
The first one uses the FastObjectDB.open(dbdirpath, dbname) method that returns an instance of the created db. If the db already exists, the method opens it instead of creating it.
In order to facilitate the use of the db object reference we provide a singleton constructor FastObjectDBManager.getCurrentFODB() that uses the ResouceManager property fastobjectdb.database.path and fastobjectdb.database.name to create the db.
The dbdirpath or fastobjectdb.database.path indicates the path to the directory where FODB stores its files. One subdirectory is created per db name.
|
2.2 Db object collection creation |
|
To store objects, an FODB collection must be created. A collection has to be created one time in the life cycle of the database. This means that collection creation informations are persistent inside the db, so collections are reloaded when the db is opened. To see if a collection has been created, use the method db.isCollectionExist(collectionName) . To create a collection use the method db.createCollection(collectionName, ObjectClass.class); . CollectionName is the name of the collection and ObjectClass.class is the class of the object to be stored. All objects in the collection must inherit or be of the specified class.
|
2.3 Adding index to the collection |
|
To retrieve object from the collection, index must be added. Index can index methods or fields of the stored objects.
Indexed methods or fields must be of the type String, long, int. More index type can be added depending on the needs.
Index can be Unique or Multiple. Unique index is similar to primary key, one key per object. Multiple indexes can associate one key to several objects.
When indexes are created, unique index must be added first.
To add an index, first an IndexDescriptor must be created to define index properties. Then the descriptor is added to the collection.
This code creates a unique string index with 12 of btree order and 15 characters key length. Btree order can vary from 10 to 20 depending on the collection size. It is preferable to increase it when the collection increases. 12 is a good order for collection containing less than 10 000 objects.
FODBStringIndexDescriptor KeyDescriptor =
new FODBStringIndexDescriptor
("KEY", FODBIndexDescriptor.UNIQUE, "getKey()", 12, 15);
db.addIndex("TESTDATA", KeyDescriptor);
For multiple indexes you have to specify the multiple index increment. Key index are store in an array of db object reference. If this array is too small to store all object references for one key, a new one is created increased by the multiple index increment. So to optimize the index size it is preferable to specify the average size of this array.
FODBStringIndexDescriptor debKeyDescriptor =
new FODBStringIndexDescriptor
("DEBKEY", FODBIndexDescriptor.MULTIPLE
, "getDebKey()", 10
,TestData.NB_BEGIN_KEY_LETTER, 5);
db.addIndex("TESTDATA", debKeyDescriptor);
|
2.4 Adding/replacing object to the FODB |
|
To add an object to the database, use the method db.add (collectionname, object); . The object must not already exist if a unique index is associated to the collection. In this case an exception is thrown. To replace an object use the db.replace(collectionname, object); instead.
|
2.5 Collection query |
|
To retrieve object from a collection, FODB provides query facilities. First a query must be created with the method db.query() and a collection must be associated to the query. Query can only request objects inside one collection. To associate a collection use the method q.constrain(object.class); . object.class is the object class associated to the collection at the creation time. Instead of the object.class, the name of the collection can be used.
Then indexes that participate to the query are specified with operand and operator.
To execute the query use the q.execute(); which return an ObjectSet that contains all object found in the collection.
Query examples:
Simple select query SELECT * FROM TESTDATA
Query q = db.query();
q.constrain(TestSearchData.class);
//specify an index to request.
Query subq = q.descend("getKey()");
//execute with no constrain to get all objects
ObjectSet set = q.execute();
Other examples:
Query : SELECT * FROM TESTSEARCH where getKey<14
q = db.query();
q.constrain(TestSearchData.class);
subq = q.descend("getKey()");
subq.constrain(new Integer(14)).smaller();
set = q.execute();
Query: SELECT * FROM TESTSEARCH where getkey<16 OR getDizaine=2
q = db.query();
q.constrain(TestSearchData.class);
subq = q.descend("getKey()");
c = subq.constrain(new Integer(16)).smaller();
subq2 = subq.descend("getDizaine()");
d = subq2.constrain(new Integer(2)).equal();
c.or(d);
set = q.execute();
|
2.6 Delete object from collection |
|
To delete an object from a collection use the method db.delete(collectionname, objecttodelete);.
The Delete method uses the first added unique index of the collection to retrieve the db object and delete it. If the collection doesn't have a unique index, objects can't be deleted.
The method deleteWithId is the same but you specify the key of the first unique index added to the database instead of the object to delete.
|
3. Embedded Web Server |
|
3.1 Starter class |
|
OpenMobileIS provides a "Starter" to run it's embedded web server. The "Starter" class is : org.openmobileis.embedded.webserver.StartWebServer. It's main method starts the web server, looking for it's configuration file ('properties/webserver.properties'). Depending on the jvm used, the 'properties/webserver.properties' will or will not be found in the classpath. If the jvm doesn't look for files into its classpath (as it's the case with IBM's j9), the StartWebServer main method accepts a parameter, which is the absolute path to the directory containing 'properties/webserver.properties'.
|
3.2 Configuration files |
|
3.2.1 Main configuration file |
|
When starting, the embedded webserver parses it's main configuration file (properties/webserver.properties). It can contain three properties :
|
3.2.2 Servlet configuration file |
|
This servlet configuration file is much simpler than the one from Tomcat. It can only take to types of arguments :
These arguments have to be repeated for each servlet declared.
In order to run Open Mobile IS, we need to declare the openmis servlet, with the right init arguments. We also need to declare the file servlet, provided by the project, as the default servlet. Indeed, Open Mobile IS' embedded web server doesn't have any default action to do when no servlet is found. Declaring the file servlet as the default servlet allows us to retrieve files (images for exemple) on the server. The servlet file then looks like :
servlet.services.code=org.openmobileis.services.servlet.OpenMISServlet
servlet.services.initArgs=org.openmis.services.conffile=/WEB-INF/conf/properties/openmis.properties
servlet.defaultServlet.code=org.openmobileis.services.servlet.FileServlet
servlet.defaultServlet.initArgs=htdocs=/htdocs
The argument taken by the file servlet (htdocs=<htdocs-dir>) defines the base directory where the servlet will look for files. If not defined, the base directory will be <installPath>, as defined in the server's main configuration file. Otherwise, it will be <installPath>/<htdocs-dir>. The arguments taken by openmis servlet will be detailed in the next part.
To request a servlet the URI is constitued as follow: /<servlet-name>. For example these servlet properties :
servlet.myservlet.code=org.openmobileis.services.servlet.MyServlet
servlet.myservlet.initArgs=
can be request with the URI: /myservlet
|
4. OpenMIS Servlet & Services |
|
4.1 Open Mobile IS Servlet |
|
4.1.1 Init parameters |
|
org.openmobileis.services.servlet.OpenMISServlet is the servlet class, to be declared to the web server. It can take two Init Parameters : one of them being required :
|
4.1.2 Application directory (user.dir) |
|
Let's talk a bit more about the application directory (user.dir). As exposed before, this property is initialized by the servlet to its context path, (+ extra-path, if defined by the init parameter 'org.openmis.services.installpath').
The use of this variable isn't an obligation for developpers. They absolutely can ignore it, and refer to all files and directories by their absolute path (these paths may not have anything to do with the user.dir). Nevertheless, it is highly recommended to put all datas used by the application into that directory (or sub-directories). If all files and directories are present in the user.dir (and its sub-directories), they can all be referred to as : $user.dir/path_to_file_or_direcotry. Acting this way, makes it really easy to move the application from a machine to an other. Indeed, even if the context path are different, the application will find all its files and directories, with no need for the developper to modify the path referring them.
|
4.1.3 Main configuration file |
|
Once started, the servlet parses it's property file (org.openmis.services.conffile) where it finds informations required for it's execution. We'll now call this file the MainPropertyFile. It contains a list of properties respecting the following syntax :
<option1>=<value1>
<option2>=<value2>
It mostly looks as follows :
# OpenMobileIS properties.
# server version
serve.version=1.0
# force pass management if declared
serve.service.forcepass=false
# default local to use if no local are defined.
serve.intl.defaultinitlocal=fr
# properties path
propsDir=$user.dir/WEB-INF/conf/properties/
# logs path
LOGFILE=$user.dir/WEB-INF/logs/openmis.log
#templates path
templatesDir=$user.dir/WEB-INF/templates/
# List Services
listServicesFile=$user.dir/WEB-INF/conf/properties/listServices.properties
Its content will be detailed later, but we can notice the last property called listServicesFile. This property defines a file where the application will find a list of services (we'll now call this file ListServicesFile). Indeed, OpenMobileIS servlet, works as a service manager. We talk about it in the comming part.
|
4.2 Open Mobile IS Services |
|
OpenMobileIS servlet, works as a service manager, redirecting all requests to the appropriate service. All these services are identified by a unique service path. The ListServicesFile must have the following syntax :
<service-path-1>=<service-class-1>
<service-path-2>=<service-class-2>
It can look like :
/HelloWorld=com.ecare.group.testwebserver.embedded.services.HelloWorld
/service/path=com.ecare.group.testwebserver.embedded.services.test
/service/path2=com.ecare.group.testwebserver.embedded.services.test2
In this case, the request URI are tokenized as follows :
Request URI
|
Service path
|
/services/HelloWorld
|
/HelloWorld
|
/services/service/path
|
/service/path
|
/services/service/path2
|
/service/path2
|
All Services extend the abstract class org.openmobileis.embedded.services.Service and must implement the method 'public void run(HttpServletRequest req, HttpServletResponse res)' . In our exemple, when the URI /openmis/HelloWorld is called, the run method of the class HelloWorld is called. It receives as parameters, the HttpServletRequest and the HttpServletResponse as defined in the Servlet API. The developper can retreive parameters from the request and generate an answer, just as he would with a normal servlet.
To make it easier, OpenMobileIS provides a Special service that uses a template engine. The template engine used is freemarker (http://freemarker.sourceforge.net/). This service is called TemplateService : org.openmobileis.embedded.services.common.TemplateService . All services extending this class must implement the method :
'public String runTemplate(HttpServletRequest req, HttpServletResponse res, TemplateModelRoot templateData)' .
As in a normal Service, the TemplateService receives a HttpServletRequest and a HttpServletResponse, but it receives a third argument : a TemplateModelRoot. The TemplateModelRoot is part of freemarker's API. It is the structure used to store the variables that will be replaced in the template. We can notice that the runTemplate method returns a String. This string indicates the path of the template file, in which variables stored in the TemplateModelRoot will be replaced.
The way freemarker replaces variables in a template is very simple : freemarker recognises variables because of there special syntax : ${variable}. Thus, when the TemplateModelRoot stores a variable called 'toto', freemarkers looks for all occurences of ${toto} in the template, and replaces them with its value, stored in the TemplateModelRoot.
|
|
|
|