{{{ #!docbook MOLGENIS 3.0.3 manual How to quickly generate your own biodatabase using the MOLGENIS suite. University of Groningen Morris Swertz et al molgenis-users@lists.sourceforge.net 2001-2008 MOLGENIS is the 'holistic' model-driven database platform that allows you to store and query any (biological) data you want .... as long as you tell it in a model how your data looks like ;-) This manual helps you to get started. With MOLGENIS you can compactly model the structure of your data, and the way you want to see it on screen, using a simple XML language. At the push of a button, the MOLGENIS generators automatically produce all the program code of your desired software instance. With each MOLGENIS instance you get 'for free' : a generated user interface to upload and query data in a web browser; a R-projectinterface to connect your favorite statistical tools; the web service interface to integrate e.g. NCBI, Ensembl, KEGG, using Taverna; and a plug-in mechanism so you can easily add your custom programs to the generated software. And if you don't like what you see, or if your experiments change, you can quickly re-run the generator to accomodate. Thus in quick iterations you can produce the databases biologists want to have. MOLGENIS has been born from the demanding domain of life sciences (although it is not limited to that domain). Currently, MOLGENIS has been succesfull for microarray experiments, proteomics experiments, genetical genomics experiments, animal observations and first initatives have been started towards biobanking. MOLGENIS is open-source and free for use by academics, we only ask that you cite our work: Swertz & Jansen:Beyond standardization: dynamic software infrastructures for systems biology. Nature Reviews Genetics 8: 235-243. Swertz et al: Molecular Genetics Information System (MOLGENIS) alternatives in developing local experimental genomics databases. Bioinformatics 20: 2075-83 We are happy to collaborate and help you generate interesting MOLGENIS instances for your research domain and co-author publications on these systems together. For commercial use of MOLGENIS we have a separate license. Using the MOLGENIS generator Getting started This chapter describes what software and procedures are needed to get started using MOLGENIS. The next chapters explain you how to configure MOLGENIS to your needs. Install the necessary software (only once) MOLGENIS is known to run happily at Windows, Linux and Mac. To get going, download and install the following: Java 6 JDK http://java.sun.com/javase/downloads/ Just install with standard options. Tomcat >=5 web server http://tomcat.apache.org/ Rember the root password you are asked! Don't run Tomcat as a service; we will start and stop it ourself. Mysql >=5.1 database http://dev.mysql.com/downloads/mysql/5.1.html During installation of the windows version you need to tick 'innodb'. Remember your root password! Eclipse Integrated Development Environment http://www.eclipse.org/downloads/ You need to install the J2EE version (which allows you to start/stop tomcat) (Optional) MOLGENIS autogenerates documentation for your application. This includes a graphical representation your model in UML format. This requires GraphViz to work: Download and install graphviz from http://www.graphviz.org/Download.php Make sure your PATH is set to run 'dot.exe' from the commandline. The latest 'molgenis_workspace.zip' from http://molgenis.sourceforge.net and unzip Just download and unzip. A directory 'molgenis_workspace' is created. Create a database in mysql and give molgenis permission to populate it. Open mysql.exe as root user Under windows in "C:\Program Files\MySQL Server 5.1\bin\mysql.exe - u root -p Remember your root password from step 3! Type the following to create a database 'molgenis' and provide rights to the molgenis generator to change it using password 'molgenis': create database molgenis; grant all privileges on molgenis.* to molgenis@localhost identified by 'molgenis'; flush privileges; use molgenis; Generating your custom MOLGENIS database Start eclipse and open the molgenis workspace (as downloaded above). All that you need is in project 'molgenis_distro'. Edit the design files. A MOLGENIS typically has two design files, in this case: molgenis_db.xml containing the structure of your data and molgenis_ui.xml containing a blueprint of your user interface You can edit them to adapt MOLGENIS to your needs, see other chapters. Generate the MOLGENIS as blueprinted Go to the folder 'handwritten/java' and right-click 'MolgenisGenerate' Choose 'run as' and then 'run as java application' The generator will be started and its progress shown on Console. Eclipse has to be told new code has been generated: right-click on project 'molgenis' and choose 'refresh'. Next time you can choose the green 'play' button on the toolbar to run the generator and/or database updater. Update the database with the newly generated structure You can either copy-paste the file 'generated/sql/createTables.sql into mysql' or right-click the class 'handwritten/java/MolgenisUpdateDatabase' and select 'run as application' do it automatically The database update program will overwrite any data in your database. The program will ask you 'y' or 'n' whether you really want to overwrite the existing database.. Don't use this on a database already filled. Instead change the database by hand using 'alter table' commands as described at http://dev.mysql.com/doc/refman/5.0/en/alter-table.html Run the MOLGENIS and see if you like it already. Right-click the 'molgenis' project folder and choose 'run as' and ' run on server (First time only) you have to choose the server (Apache Tomcat) and set the path (e.g. C:\Program Files\Apache Software Foundation\Tomcat 5.5). Now Tomcat will be started and a browser shown with your MOLGENIS. Alternatively you can view molgenis in your favorite browser at http://localhost:8080/molgenis That is all there is too it :-) Frequently asked questions Changing the database Obviously, when generating more than one MOLGENIS one might want to change e.g. database location (to allow for multiple). These options can be set in the file 'molgenis.properties'. MOLGENIS is a standard Tomcat/Servlet application. Hence, when changing the database settings also need to be changed in WebContent/META-INF/context.xml. The MOLGENIS generator does this automatically Does MOLGENIS also work on Postgresql Experimentally yes. When you change in molgenis.properties also the driver to use 'org.postgresql.Driver' then the generator assumes Postgresql and generates suitable code. Remember to give your MOLGENIS user suitable privileges. Can I split my models over multiple XML files Yes you can. Actually this is a great way to make reusable modules from your models to in alternative combinations. Inside the molgenis.properties file you can specify this: # xml file with entity descriptions model_database = model_part1.xml, model_part2.xml, model_part3.xml You can use the 'module' syntax to make these modules also visible in the documentation. See <module> Can I set login and authorization No, not yet. This is back on the drawing board. Can I add my own 'trigger' when 'add', 'update' or 'delete' is called When an entity object is saved it goes through a so-called mapper that translates the object to e.g. the mySql database. It is possible to plug-in a decorator to change that behaviour, e.g. to check certain contraints, or to automatically process the data. In the XML you can use the 'decorator' tab. Then a plugin will be generated in the folder handwritten/java with in the example the name 'my.decorators.MyEntityMapperDecorator'. To this class you can add extra code. See the section on how to write a MappingDecorator plugin for details. <entity name="MyEntity" decorator="my.decorators.MyEntityMapperDecorator"> ... </entity> Example MOLGENIS instance How to build a MOLGENIS variant in three steps Step 1: what do you want to have? Say, for example you are just starting genetical genomics experiments. You start sketching and you decide that you want to see on your screen an input box for (1) experiments, with beneat it input boxes to edit your (2) traits (e.g. probes/genes/markers), (3) subjects (e.g. mice), and (4) assays (e.g. microarray hybridizations, qtl profiles) with (5) data (e.g. probe intensities, genotypes). Conceptually, that is something as you see below:
Example of an bio-experimental data structure
Step 2: what you want to see? We assume you started Eclipse as described above. In eclipse you describe your user interface in a simple xml file using MOLGENIS user interface description language', i.e., in the project 'molgenis' you edit 'molgenis_ui.xml'. The screenshot belows show how you can describe the userinterface, that consists of a “form” to show “Experiment” entities. This form has a submenu (ExperimentMenu) showing showing the “Traits” and “Subjects” and “Assay” entities. And underneath “Assay” we want to see yet another subform with the related data:
Example of a user interface description
Step 3: how is your data structured? In eclipse you describe your user interface in a simple xml file using MOLGENIS user interface description language', i.e., in the project 'molgenis' you edit 'molgenis_db.xml'. Below we detail how the data structure can be described in the domain specific language of MOLGENIS. Most of it is self-explanatory but we highlight some statements: Implements=”Identifiable” means that the entity has the same properties as ‘Identifiable’, i.e. each entity has and auto-generated Id and a Name. This allows easy reuse of data structures. Note that 'Identifiable' itself is abstract, meaning that it is just used for modeling purposes only. type=”xref” and xref_field=”Experiment.Id” indicates that the field Experiment of Subject should cross reference (x ref) to an existing Experiment, using Id to uniquely identify this Experiment. Cross references are used to automatically link forms together, i.e. when viewing experiments only the related Subjects are shown using the subject.experiment to experiment.id cross references.
Example of a data structure description
Result. Generate and run your MOLGENIS as described in Chapter 1, section 2. The expected result will now look like shown in the figure below (without the example data that we added to show how it works): [TODO replace with example showing also R and webservices interface]. And of course, if you don't like it yet you can edit the files above and regenerate in a few minutes.
Example of a generated MOLGENIS
MOLGENIS little language reference The data model language Description of XML elements and their usage. <application> Application contains the blueprint for the whole system. For example: Using <application>. <molgenis name="myfirstdb" label="My First Database"> <menu name="mainmenu"> ... <entity name="firstentity"/> <module name="mymodule"/> ... </molgenis> Optional attributes: name="name": name of your MOLGENIS blueprint. This will be used by the generator to generate java packages. label="your label": Label of your MOLGENIS system. This will be shown on the screen as well as heading in the generated documentation. Can contain: Exactly one <menu> or one <form> as main screen. Zero or one <description> elements describing the application Many <entity> elements describing the data structure. See <entity> Many <module> elements describing the data structure. These are containers to group <entity>.See <module> <entity> A entity defines the structure of a biological dat entity (i.e., a table in the database). For example: Using <entity>. <entity name="unique_name"> <description>Thisis my first entity.</description> <field name="name" type="string"/> <field name="investigation" type="string"/> <unique fields="name,investigation"/> </entity> Required attributes: name="name": globally unique name for this entity (within this blueprint). Optional attributes: label="Nice screen name": an user-friendly alias to show as form header (default: copied from name). extends="other_entity": you can use inheritance to make your entity inherit the fields of its 'superclass' using extends. abstract="true": you define what programmers call 'interfaces'. This are abstract objects that you can use as 'contract' for other entities to 'implement'.. implements="abstract_entity": you can use inheritance to make your entity inherit the fields of its 'interface' using implements and refering to 'abstract' entities. The implemented fields are copied to this entity. decorator="package.class": you can add custom code to change the way entities are added, updated and removed. See the section on how to write aMappingDecoratorMappingDecorator plugin. Using inheritance: implements and extends <entity name="bicycle"> <description>This my general entity</description> <field name="name" type="string"/> </entity> <entity name="mountainbike" extends="bicycle"> <description>This type of bicycle has a name, but also number of gears</description> <field name="numberOfGears" type="int"/> </entity> Application can contain: Zero or one <description> to describe this entity. One or more <field> that detail entity structure. Zero or more <unique> indicating unique constraints on field(s). <field> A field defines one property of an entity (i.e., a table column). For example: Using <field>. <field name="unique_name" type="string" description="this is my first field"/> <field name="unique_name" type="xref" xref_field="entity_name.field_name"/> <field name="unique_name" type="enum" enum_options="[option1,option2]"/> Required attributes: name="name": locally unique name for this entity (within this entity). type="type": define the type of data that can be stored in this field, either: type="string": a single line text string of variable length, max 255 chars. type="int": a natural number. type="boolean": a boolean. type="decimal": a decimal number. type="date": a date. type="datetime": a date that includes the time. type="file": attaches a file to the entity. type="text": a multiline textarea of max 2gb. type="xref": references to a field in another entity specified by xref_field attribute (required for xref). This will be shown as variable lookup-list. type="mref": many-to-many references to a field in another entity specified by xref_field attribute (required for mref). This will be shown as multiple select lookup-list. (Under the hood, a link table is generated) type="enum": references to a fixed look-up list options, specificed by enum_options attribute (required for enum) Optional attributes: label="Nice screen name": an user-friendly alias to show as form header (default: copied from name). unique="true": values of this field must be unique within the entity (default: "false") nillable="true": this field can be left blank (default: "false") readonly="true": this field cannot be edited once they are saved (default: "false") length="n" (string only): limits the length of a string to 1<=n<=255 (default: "255"). xref_field="entityname.fieldname": specifies a entity and field that this xref field must reference to, separated by '.' (default: required for xref) xref_label="{afield} {anotherfield}": makes labels for the xref options based on fields of the referenced entity, indicated between '{}' (default: copied from xref_field). enum_options"[value1,value2]": the fixed list of options for this enum (default: required for enum). description="One line description": describes this field which the user can see when (s)he mouses over the field (default: ""). Field can contain no other elements: <unique>. A unique defines which properties of an entity (i.e., table columns) should be unique. There are two ways to make a field unique. A single column is unique: Using <unique> on single columns. <molgenis> <entity name="entity1"> <field name="f1" type="string" unique="true"/> <field name="f2" type="string"/> <field name="f3" type="string"/> </entity> </molgenis> Explanation: field "f1" is made unique via unique="true". This means that there cannot be two entities with f1="x" The combination of two or more columns is unique: Using <unique> over multiple columns. <molgenis> <entity name="entity1"> <field name="f1" type="string"/> <field name="f2" type="string"/> <field name="f3" type="string"/> <unique fields="f1,f2"/> </entity> </molgenis> Explanation: The combination of "f1" and "f2" is unique. This means that there can be two entities with f1="x" but only if the values for f2 differ. Required attributes: field="field1,field2": a comma separated list of unique fields. Note: You can add as many unique constraints you like. <module> A module can be used to group entities in your model. This will show up in the generated documentation. Using <module> to group entities. <molgenis> <module name="module1"> <description>This is my first module</description> <entity name="entity1"> <field name="f1" type="string" unique="true"/> <field name="f2" type="string"/> <field name="f3" type="string"/> </entity> <entity name="entity2"> <field name="f1" type="string" unique="true"/> <field name="f2" type="string"/> <field name="f3" type="string"/> </entity> </module> </molgenis> The user interface language <form> A form shows the records of its entity on screen. A form may have tabbed (menu) or un-tabbed (form) subscreens. For example: Using <form>. <form name="myname" entity="myentity"> <form name="myname" entity="mysubentity"/> </form> <form name="myname" entity="myentity" viewtype="list" limit="10"/> Required attributes: name="name": locally unique name for this screen element (within its container). entity="myentity": which data entity will be loaded (i.e., points to a <entity name="myentity"/>). Optional attributes: label="Nice screen name": an user-friendly alias to show as form header (default: copied from name). viewtype="record" or viewtype="list": whether the form should start with a list or per-record (default: "record"). limit="10": how many records must be shown in the list (default: "5"). readonly="true": can the records be edited or is the form readonly (default: "false"). Application can contain: Zero or more <menu> as subscreen(s). Zero or more <form> as subscreen(s). <menu> A menu shows tabs on screen for each contained subscreen (menu,form). For example: Using <menu>. <menu name="menuname"> <form name="myfirsttab" entity="formentity"/> <menu name="mysecondtab">... <form name="mythirdtab" entity="formentity"/> </menu> Required attibutes: name="menuname": locally unique name for this screen element (within its container). Optional attributes: startswith="mysubelement": subscreen tab that is selected when menu is first shown (default: first subscreen). Application can contain: Zero or more <menu> as subscreen(s). Zero or more <form> as subscreen(s). <plugin> A entity defines the structure of a biological dat entity (i.e., a table in the database). For example: Using <plugin> example. <plugin name="MyPlugin" type="plugins.myplugin.MyPluginScreen"/> Required attributes: name="name": globally unique name for this entity (within this blueprint). type="package.class": reference to a java class in your handwritten/java folder. If it doesn't exist a boilerplate class will be auto-generated for you. See the section on Plugin screens to see how to edit this file. Optional attributes: label="Nice screen name": an user-friendly alias to show as form header (default: copied from name). Adding custom plug-ins to the generated software Introduction See the examples in the molgenis distro. At the moment there are two types of plug-ins. Plugin of a screen MapperDecorator to change what happens when 'add', 'update' or 'delete' is called Alternatively, you can also move generated code to the handwritten section and edit that (advanced users). Adding a plug-in screen This feature allows you to produce a custom screen that does whatever you want it to do. The procedure consists of three steps: Add the plugin to the model. Describe where you want to put your plugin in the MOLGENIS 'UI' XML. The plugin 'type' points to a java class that is typically stored in handwritten/java. <molgenis> <plugin name="MyPlugin" type="plugins.myplugin.MyPluginScreen" /> </molgenis> When you now run the generator an 'boilerplate'' screen plugin class will be generated inside the folder handwritten/java (unless the file allready consists). In this case a class called 'plugins.myplugin.MyPluginScreen.java'. Next to that also a layout template is generated to layout the contents of your plugin in 'plugins.myplugin.MyPluginScreen.ftl'. Edit the plugin class. The following empty plugin class is generated for you to change to make it do whatever you want (its name depends on you plugin class name): package plugins.myplugin; import org.molgenis.assets.screen.Screen; import org.molgenis.assets.screen.plugin.PluginScreen; import org.molgenis.util.Tuple; public class MyPluginScreen extends PluginScreen { public MyPluginScreen(String name, Screen parent) { super(name, parent); } @Override public String getViewName() { return "plugins_myplugin_MyPluginScreen"; } @Override public String getViewTemplate() { return "plugins/myplugin/MyPluginScreen.ftl"; } @Override public void handleRequest(Tuple request) { try { Database db = this.getDatabase(); //String action = request.getString("__action"); // //if( action.equals("do_add") ) //{ // Experiment e = new Experiment(); // //read the request directly into the entity using matching field/input names // e.set(request); // db.add(e); //} } catch(Exception e) { //... } } @Override public void reload() { try { Database db = this.getDatabase(); //Query q = db.query(Experiment.class); //q.like("name", "test"); //List<Experiment> recentExperiments = q.find(); // ////do something } catch(Exception e) { //... } } } Edit the function 'handleRequest' to process user requests. A simple 'helloWorld' example is commented out. Edit the function 'reload' to indicate what needs to be done if the page is reloaded by the user (so, after a handleRequest). This function is typically us ined to retrieve data from the database. Again, a simple 'helloWorld' example is in the comments. Edit the plugin layout.The following empty layout template is generated for you. This template is written using the Freemarker language (http://freemarker.org/docs/index.html) and allows you to change to layout it in the way you like (its name depends on you plugin class name): <#macro plugins_myplugin_MyPluginScreen> <#assign model = screen.model> <!-- normally you make one big form for the whole plugin--> <form method="post" enctype="multipart/form-data" name="${screen.name}"> <!--needed in every form: to redirect the request to the right screen--> <input type="hidden" name="__target" value="${screen.name}"" /> <!--needed in every form: to define the action. This can be set by the submit button--> <input type="hidden" name="__action" /> <!-- this shows a title and border --> <div class="formscreen"> <div class="form_header" id="${screen.getName()}"> ${screen.label} </div> <div class="screenbody"> <div class="screenpadding"> <#--begin your plugin--> <input name="myinput" value="${screen.getMyValue()}"> <input type="submit" value="Change name" onclick="__action.value='do_myaction';return true;"/> <#--end of your plugin--> </div> </div> </div> </form> </#macro> Notice that an html form is already generated for you, including some basic layout. In MOLGENIS, a form must always have two hidden parameters called __target and __action: The __target parameter routes any user request back to you plugin class (using the screen name, in this example 'MyPlugin'). The __action parameter is not actually required but has been a good design pattern to simplify event handling when your plugin has multiple buttons. Then, each action button has a small piece of 'onclick' javascript to set the value of the action before submit (return true makes the submit go forward. For example here: <input type="submit" value="Change name" onclick="__action.value='do_myaction';return true;"/> Adding a mapping decorator Sometimes you want to slightly alter the default behavior of the MOLGENIS add, update and delete functions, e.g. to check certain contraints, or to automatically process a attached file of data. In MOLGENIS, when an entity object is saved it goes through a so-called mapper that translates the object to e.g. the mySql database. Using 'MappingDecorator' is possible to plug-in a decorator to change that behaviour.The procedure consists of two steps: Add the plugin to the model. Describe which entity you want to decorate in the MOLGENIS 'DB' XML. The 'decorator' attribute' points to a java class should be stored iin handwritten/java. <molgenis> ... <entity name="MyEntity" decorator="my.decorators.MyEntityMapperDecorator"> ... </entity> ... </molgenis> When you now run the generator an 'empty' decorator plugin class will be generated inside the folder handwritten/java (unless the file allready consists). In this case a class called 'my.decorators.MyEntityMapperDecorator'. Edit the plugin class. The following empty plugin class is generated (its name depends on you plugin class name as stated in 'decorator' above). Just add code before or after the 'super' calls to change the pre/post update behavior of your database. The commented sections give pointers on how that can work:public class MyEntityMapperDecorator extends MappingDecorator<example.data.types.MyEntity> { //JDBCMapper is the generated class that we change in this plugin public MyEntityMapperDecorator(JDBCMapper generatedMapper) { super(generatedMapper); } @Override public int add(List<example.data.types.MyEntity> entities) throws SQLException, DatabaseException { // add your pre-processing here, e.g. // for (example.data.types.MyEntity e : entities) // { // e.setTriggeredField("Before add called!!!"); // } // here we call the standard 'add' int count = super.add(entities); // add your post-processing here // if you throw and exception the previous add will be rolled back return count; } @Override public int update(List<example.data.types.MyEntity> entities) throws SQLException { // add your pre-processing here, e.g. // for (example.data.types.MyEntity e : entities) // { // e.setTriggeredField("Before update called!!!"); // } // here we call the standard 'update' int count = super.update(entities); // add your post-processing here // if you throw and exception the previous add will be rolled back return count; } @Override public int remove(List<example.data.types.MyEntity> entities) throws SQLException { // add your pre-processing here // here we call the standard 'remove' int count = super.remove(entities); // add your post-processing here, e.g. // if(true) throw new SQLException("Because of a post trigger the remove is cancelled."); return count; } } Java API basics TODO
}}}