-
Notifications
You must be signed in to change notification settings - Fork 77
Analyzer plugins
We support two models of importing analyzer results. The older model, which we are phasing out, has the code for importing analyzer results as part of the core of OpenELIS. The newer model which all new analyzers should use is a plugin model.
There is a directory /plugin in OpenElis. Any jar file in this directory will be processed and if it is a valid analyzer plugin it will be added to the application. If the plugin is later removed any imported data will be retained but the analyzer will no longer appear in the menu and openELIS will not accept analyzer files meant for that analyzer.
The plugins are loaded during the application startup. A future feature will be to enable/disable them during runtime.
Plugins can be developed completely independently of OpenELIS or they can be checked into https://github.com/openelisglobal/openelisglobal-plugins. Currently we are only supporting plugins for analyzers but we expect to also support plugins for electronic and paper reports. The analyzer plugins should be added under "analyzer". There is an example called WeberAnalyzer which can be used as a template. Note that it also includes a SMALL input file sample as well as contact information.
If you want to modify an existing analyzer written by a different organization please contact the creator of the analyzer and work with them to make sure that your changes do not break their imports. You should also include the core group with confirmation that you have the right to modify the work from a different organization or else we will not allow the change to be made in repository. An alternative is to make a copy of the other persons work. Note that you should honor the copyright notice and name yourself as a contributor, not as the creator.
If you no longer are using a particular analyzer and do not care if the work is modified please note that in the contact file.
The plugins are in a separate repository from the core but the IDE is only tracking the core repository. When you do a commit from within the IDE you are only committing what is in openelisglobal-core, not anything from openelisglobal-plugin. To maintain that repository you will need to either work from the command line or use a tool such as SourceTree.
The JDK that is being used to compile the plugin MUST be as old or older than the Java version under which tomcat is running. i.e. If tomcat is using JRE 1.7 and the plugin was compiled with JDK 1.8 then bad things will happen
Creation Steps
- Create a new Java project. Accept all of the defaults. The name of the project should match the name of the analyzer.
- Open up the properties for the project
- Select the Java build path (left hand side of the dialog)
- Select projects tab and add (right hand side of the dialog) openElisGlobal
- Click ok
Jar'ing Steps
- Select project
- Right click and select export
- Select type java->jar
- Select next
- Select the project as the resources to export
- Select the destination as tomcatRoot/webapps/openElisGlobal/plugin/.jar
The overarching unit of work in IntelliJ is a project. Each project is made up of one or more modules and each module is made up of one or more artifacts.
We are assuming that openelis-global is already a project in IntelliJ and just the analyzer part needs to be set up.
Steps:
- If you have not done so already clone the repository with the analyzer you want to work on.
- From the project view open Module Settings (F4)
- On the left hand side click on modules
- Click on the green plus button
- Click new module
- On the New module dialog box select Java as the module type
- On the second widget down select the content root. As an example for the Weber analyzer select ...\openelisglobal-plugins\analyzers\weberAnalyzer
- This should automatically create the correct name
- Uncheck "create source root" at the bottom of the dialog
- Click on next and then finish.
- You now have the module set up.
- On the left hand side now click on artifacts
- Click on the green plus button
- Click on add jar -> with modules and dependencies
- On the module dropdown select the new module name
- Leave everything else as is and click ok
- The output layout will include a huge number of jar files and app compile and the analyzer compile listing.
- Delete everything accept the analyzer compile listing
- Set the output to the output of the app module, it should be something like ...\openelisglobal-core\app\out\artifacts\app_war_exploded\plugin
- Make sure the build on make checkbox is selected
- Change to the app artifact
- Select the Output layout tab
- Select the green plus button
- Select the artifact icon
- Select the analyzer jar file
- Highlight the jar file in the list
- Select the green plus button
- Select module output
- Select the analyzer module
The next time you do a complete build the analyzer jar file should be in the ...\openelisglobal-core\app\out\artifacts\app_war_exploded\plugin directory and it should be loaded into the application
It is assumed that openelisglobal-core is already a project in NetBeans.
Setting the correct JDK:
netbeans_jdkhome paramenter in netbeans.conf files needs to be modified to make the JDK default.
e.g. netbeans_jdkhome="/usr/lib/jvm/java-1.7.0-openjdk-amd64" (this is just an example, do not just copy and paste)
Steps:
-
Fork https://github.com/openelisglobal/openelisglobal-plugins to your own github account
-
Clone openelisglobal-plugins from your github account to your local machine
-
Add the plugins at the level of the analyzer, not at the level of the project. In other words: if you are working on the WeberAnalayzer then the location of the plugin-project should be openelisglobal-plugins\analyzers\weberAnalyzer. There will be one project per analyzer
-
If you are creating a new analyzer plugin add as a java application as a child of openelisglobal-plugins/analyzers directory
-
The project for openelisglobal-core should be built. Right click on the project and on the pop-up menu select "clean and build"
-
Change to the output directory <project root>\build\web\WEB-INF\classes
-
Create a jar file from the class files.
"c:\Program Files\Java\jdk1.7.0_13\bin\jar.exe" cf oe.jar .\us\*
(note the path to your jdk may differ) -
copy the oe.jar file to the root of your plugin project or some well known place on your file system
-
DO NOT ADD THE JAR FILE TO THE REPOSITORY
-
Add the oe.jar file to the library of the plugin directory
- Right click the plugin project
- Select "Properties" at the bottom of the pop-up
- Select "Libraries" from the dialog
- Select "Add JAR/Folders"
- Find the oe.jar file and add it
- Click OK
- At this point the code for the analyzer should be able to build
-
This previous step will only need to be done once except if any dependent code in openelisglobal-core has changed The safest course would of course be to repeat it every time you do a pull from the upstream repository
-
There are two ways to use the resulting jar file from building the analyzer code
-
The simplest is to copy the jar file from dist directory to the build/web/plugin directory every time you edit the plugin code
-
This can be automated by editing the build.xml file of the analyzer
-
Add
<target name="-post-jar" >
<copy file="dist/weberAnalayzer.jar" todir="../../../openelisglobal-core/app/build/web/plugin" />
</target>
- weberAnalyzer is the name of the analyzer project
- ../../../openelisglobal-core/app/build/web/plugin is the path to the plugin directory of the deployed openelisglobal-core project from the analyzer build.xml file location
-
-
Redeploy openELIS or restart the Tomcat server.
This file configures the plugin parts to be added to OpenElis Under src create a xml file. Name it something meaningful
Contents
<?xml version="1.0" encoding="UTF-8"?>
<openElisGlobalPlugin>
<version>1.0</version>
<analyzerImporter>
<extension_point path="us.mn.state.health.lims.plugin.AnalyzerImporterPlugin" >
<extension path="<fully qualified path i.e. oe.plugin.analyzer.WeberAnalyzer>" />
<description value="<description of Analyzer" />
</extention_point>
</analyzerImporter>
<menu>
<extension_point path="us.mn.state.health.lims.plugin.MenuPlugin" >
<extension path="<fully qualified path i.e. oe.plugin.analyzer.WeberMenu>" />
<description value="Menu for Weber Analyzer" />
</extention_point>
</menu>
<permission>
<extension_point path="us.mn.state.health.lims.plugin.PermissionPlugin" >
<extension path="<fully qualified path i.e. oe.plugin.analyzer.WeberPermission>" />
<description value="Weber Analyzer permission" />
</extension_point>
</permission>
</openElisGlobalPlugin>
This file adds the needed elements to the database and registers itself to create the runtime objects needed This should be in the source in the package indicated in analyzerImporter section in xml file
public class <Name>Analyzer implements AnalyzerImporterPlugin {
public boolean connect(){
List<PluginAnalyzerService.TestMapping> nameMappinng = new ArrayList<PluginAnalyzerService.TestMapping>();
//Mappings between the name in the analyzer results file and the test name as known to OpenElis
nameMappinng.add(new PluginAnalyzerService.TestMapping("CD4_PER", "CD4 Compte en %"));
nameMappinng.add(new PluginAnalyzerService.TestMapping("CD3_PER", "CD4 Compte Absolu"));
//The name of the analyzer as it will appear in the database, the description of the analyzer and the name mappings
getInstance().addAnalyzerDatabaseParts("WeberAnalyzer", "Plugin for weber analyzer",nameMappinng);
getInstance().registerAnalyzer(this);
return true;
}
@Override
public boolean isTargetAnalyzer(List<String> lines) {
//This will depend on finding a unique identifier in the analyzer results file which will be found in that file and for no other analyzer
return lines.get(1) != null && lines.get(1).contains("MugelSET");
}
@Override
public AnalyzerLineInserter getAnalyzerLineInserter() {
//The object which will actually interpret the contents of the results file.
return new WeberAnalyzerImplementation();
}
}
This file adds the elements needed to add the analyzer to the menu and provide for localization of the name. This should be in the source in the package indicated in menu section in xml file
public class <Name>Menu extends MenuPlugin {
@Override
protected void insertMenu() {
PluginMenuService service = PluginMenuService.getInstance();
Menu menu = new Menu();
menu.setParent(PluginMenuService.getInstance().getKnownMenu(KnownMenu.ANALYZER, "menu_results"));
//The order this analyzer will show on the menu relative to other analyzers
menu.setPresentationOrder(5);
//The id needs to be unique in the system
menu.setElementId("weber_analyzer_plugin");
//This will always be "/AnalyzerResults.do?type=<The name of the analyzer in the database as specified in then Analyzer class call to addAnalyzerDatabaseParts(....)
menu.setActionURL("/AnalyzerResults.do?type=WeberAnalyzer");
//The key used for the name of the analyzer on the menu. Should not already exist in MessageResource.properties.
menu.setDisplayKey("banner.menu.results.weber");
menu.setOpenInNewWindow(false);
service.addMenu(menu);
//Analyzer name in English
service.insertLanguageKeyValue("banner.menu.results.weber","Weber 4000", ConfigurationProperties.LOCALE.ENGLISH.getRepresentation());
//Analyzer name in French
service.insertLanguageKeyValue("banner.menu.results.weber","La Weber 4000", ConfigurationProperties.LOCALE.FRENCH.getRepresentation());
}
}
##Permission File public class extends PermissionPlugin{ @Override protected boolean insertPermission(){ PluginPermissionService service = new PluginPermissionService(); //The name of the action followed by the action type followed by the description of the module SystemModule module = service.getOrCreateSystemModule( "AnalyzerResults", "WeberAnalyzer", "Results->Analyzer->WeberAnalyzer" ); //The name of role. If it does not exist it will be created. Note: the hierarchical permissions such as at RetroCI are currently not supported Role role = service.getSystemRole( "Results entry" ); return service.bindRoleToModule( role, module ); } }
This file does the heavy lifting of parsing the results file and adding the tests to the database. However because of the variety of the results files there is more variation than can be handled here. There are some interpreters which were added before we changed to a plugin model and they can be seen in the us.mn.state.health.lims.analyzerimport.analyzerreaders package to get a sense of how they will work.