Geneious 2024.0.4 Public API

Geneious Public API Contents

Introduction

The Geneious Public API is a rich and powerful API that allows to create a wide variety of plugins. In fact most of the functionality provided by Geneious is actually just a set of plugins bundled with the Geneious distribution that interact with the core Geneious platform and with each other via the Public API. Examples of plugins in Geneious include the sequence viewer, sequence alignment operation, primer design, the sequence logo graph, the NCBI databases, agents, and even the user's local database.

The architecture of Geneious is centered around the concept of documents which are stored in either a local or shared database. Operations can modify documents or create derived documents using existing documents as input. Viewers provide a system for visualization and sometimes editing the contents of one or more documents.

Getting Started - Choosing your plugin type

The first thing to decide upon when writing a plug-in is what type of plug-in you want. All GeneiousPlugins fall under one of the following categories. There is an example plug-in for many of these categories included with the API distribution.
  • SequenceAnnotationGenerators integrate into the SequenceViewer to provide an entry in the tools popup menu to generate annotations on the currently selected sequence(s). The SequenceViewer plugin handles all associated necessary behaviour such as providing undo functionality and saving the generated annotations to disk.

    Examples of SequenceAnnotationGenerator plugins in Geneious include primer design, restriction analysis, ORF finding, and motif finding.
    Example Source Code: ExampleSequenceAnnotationGenerator

  • DocumentOperations allow the creation of a new document(s) from an existing document(s) (or from no documents). The DocumentOperation specifies its location in the menu or toolbar along with a signature specifying what type of documents it operates on and Geneious handles invoking the DocumentOperation and saving any generated documents to disk.

    Examples of DocumentOperation plugins in Geneious include Set Paired Reads and tree building.
    Example Source Code: ReverseSequence, BackTranslationPlugin

  • Assemblers allow the implementation of a read mapper, reference assembler or de novo assembler. Assemblers could be implemented as DocumentOperations but this API provides a simpler API tailored for assemblers.

    Examples of Assembler plugins in Geneious include Geneious Reference Assembler, Geneious De Novo Assembler and Velvet (on Geneious Server only)
    Example Source Code: ExampleAssembler

  • AlignmentOperations allow the implementation of an alignment algorithm. AlignmentOperations could be implemented as DocumentOperations but this API provides a simpler API tailored for alignment.

    Examples of AlignmentOperation plugins in Geneious include Geneious Aligner, Muscle and ClustalW
    Example Source Code: ExampleAlignmentOperation

  • DocumentViewers allow the viewing of 1 or more documents. DocumentViewers specify a signature of the types of documents they can view and Geneious displays the DocumentViewer each time the user selects documents matching it's signature.

    Examples of DocumentViewer plugins in Geneious include the sequence viewer, the tree viewer, and the dotplot viewer.
    Example Source Code: ExampleDocumentViewer

  • SequenceGraphs allow displaying of graphs on sequences inside the sequence viewer.

    Examples of SequenceGraph plugins in Geneious include the identity graph, the sequence logo graph, and the chromatogram graph.
    Example Source Code: ExampleSequenceGraph , ExampleSequenceGraph2

  • GeneiousServices allow entries in the sources panel on the left hand side of the main Geneious window. Typically these are databases providing access to local or external sequences.

    Examples of GeneiousService plugins in Geneious include the local database and the NCBI services.
    Example Source Code: ExampleGeneiousService

  • DocumentFileImporters provide support for importing various file formats into Geneious.

    Examples of DocumentFileImporter plugins in Geneious include the fasta importer, GenBank importer, and nexus importer.
    Example Source Code: ExampleFastaImporter , TextFiles

  • DocumentFileExporters provide support for exporting documents from Geneious into various file formats.

    Examples of DocumentFileExporter plugins in Geneious include the fasta exporter, GenBank exporter and nexus exporter.
    Example Source Code: ExampleFastaExporter , TextFiles

  • TreeViewerExtensions provide support for extending the functionality of the Tree Viewer.

    The standard Geneious distribution does not include plugins of this type, but the 3rd party Species Delimitation plugin available from the Preferences->Plugins window is an example of this.
    Example Source Code: ExampleTreeViewerExtensionPlugin

  • SequenceViewerExtensions provide support for extending the functionality of the Sequence/Alignment/Contig Viewer. For example with statistics, toolbar buttons or new components.

    Examples of SequenceViewerExtensions plugins in Geneious include the annotations table and many of the statistics in the sequence viewer.
    Example Source Code: ExampleSequenceViewerStatistics

Getting Started - Compiling and building your plugin

The easiest thing to do is run one of the examples using a supported IDE. More information about how to do this is available in the setup.html file that is included with the plugin development kit. Once you are comfortable with this choose an example plugin that most closely matches the plugin you want to create (see Getting Started - Choosing your plugin type), optionally rename the example using the copyPluginAndRename Ant task, and start modifying it to achieve the functionality you want.

More information on building and distributing your plugin can also be found in the setup file.

Documents in Geneious

A document is an item that appears in the table listing the contents of a folder. There are 2 super-classes in the API that are used when handling documents.

PluginDocument is the interface which most other document types such as SequenceDocument, TreeDocument or PublicationDocument extend. PluginDocuments are however not stored directly in the user's database. Instead these are wrapped in the top-level AnnotatedPluginDocument.

AnnotatedPluginDocument decorates all PluginDocuments with additional functionality, such as allowing custom notes to be added to documents, and allowing the user to edit displayed field values without the PluginDocument implementations needing to worry about providing this sort of functionality. A plugin never implements or subclasses AnnotatedPluginDocument.

In many situations, plugins can ignore the functionality provided by AnnotatedPluginDocument and instead just directly access the wrapped PluginDocument from an AnnotatedPluginDocument using AnnotatedPluginDocument.getDocument() or creating a AnnotatedPluginDocument from a PluginDocument using DocumentUtilities.createAnnotatedPluginDocument().

Defining your own document types

While the Geneious Public API provides a range of document interfaces and implementations, sometimes it is necessary to create your own document types or extend the functionality of the existing types. Usually this is only necessary if you are creating a plugin which provides multiple types of functionality - for example you wish to create a document operation that generates your own custom data types, and provide a document viewer to view those data types. Geneious allows you to do this by directly implementing the PluginDocument interface. A plugin can also define additional static properties (such as icons) associated with new PluginDocument types using GeneiousPlugin.getDocumentTypes().

Important classes in the API

In addition to the GeneiousPlugin and the various plugin type classes (see
choosing your plugin type), and the Geneious document system (see documents in Geneious), there are a number of important or widely used classes in the Geneious API you should become familiar with.
  • Options - Many types of plugins will need to use Options as the way of prompting for user input. Make sure you read the top-level documentation in this class to see what Options is capable of.
  • GeneiousActionOptions - The description, icon and location of a menu item or button to invoke a plugin or functionality within a plugin.
  • SequenceDocument - Any plugin that deals with nucleotide or amino acid sequences should be aware of this. Also see DefaultSequenceDocument which is the most widely used SequenceDocument implementation.
  • SequenceCharSequence - The nucleotides or amino acids in a SequenceDocument are often stored in a SequenceCharSequence instead of a String for both more efficient memory usage, and for efficient representation of end gaps in an alignment.
  • SequenceAnnotation - is used to represent features or annotations on a SequenceDocument
  • SequenceTrack - is used to represent a collection of SequenceAnnotations on a SequenceDocument
  • SequenceListDocument - SequenceDocuments are often grouped into a single SequenceListDocument. DefaultSequenceListDocument is the most widely used SequenceListDocument implementation
  • SequenceListOnDisk - The list of nucleotide sequences returned from SequenceListDocument.getNucleotideSequences() is often a SequenceListOnDisk where the sequences represent a large number of sequencing reads. The SequenceDocuments obtained from this list are loaded on demand and for optimal performance code should iterate over the list in order. Note that collections of chromosome sized sequences are usually not a SequenceListOnDisk. Instead the SequenceDocuments in these lists are loaded along with the SequenceListDocument, but the SequenceCharSequence and SequenceTracks within those sequences are loaded later on demand.
  • SequenceAlignmentDocument - Alignments and contigs are both represented using a SequenceAlignmentDocument which is most commonly implemented using a DefaultAlignmentDocument
  • ProgressListener - although this is from the JEBL package which Geneious depends on, it is very widely used throughout Geneious for operations to report progress and allow the user to cancel them.
As well as the above classes, some less frequently used classes and functionality that are of interest to more advanced users of the API include

FAQ

How do I add an item to the menu bar or toolbar?

This depends on what you will use it for. If it is intended for generating annotations on a sequence, use
SequenceAnnotationGenerator.getActionOptions(). Otherwise use DocumentOperation.getActionOptions(). If your menu item is not intended to apply an action to any documents, you should still use a DocumentOperation, except it should return an empty selection signature to indicate it accepts no input documents.
  DocumentOperation.getActionOptions() {
     return new GeneiousActionOptions("My Action").setMainMenuLocation(GeneiousActionOptions.MainMenu.Tools).setInMainToolbar(true).setInPopupMenu(true);
  }
 

How do I popup a dialog for user input?

This is usually done as part of a
SequenceAnnotationGenerator or DocumentOperation by returning Options from SequenceAnnotationGenerator.getOptions() or DocumentOperation.getOptions().
 public Options DocumentOperation.getOptions(AnnotatedPluginDocument... documents) throws DocumentOperationException {
     Options options=new Options(getClass());
     options.addBooleanOption("reverseComplement","Reverse Complement",false);
     options.addStringOption("name","Name","Default Name");
     return options;
 }
 
Alternatively, if you wish to popup a dialog independent of a SequenceAnnotationGenerator or DocumentOperation then do something like this
 Options options=new Options(getClass());
 Options.BooleanOption reverseComplement = options.addBooleanOption("reverseComplement", "Reverse Complement", false);
 Options.StringOption name = options.addStringOption("name", "Name", "Default Name");
 if (Dialogs.showOptionsDialog(options,"Title",true)) { // returns true if user clicked OK.
     if (reverseComplement.getValue()) {
         System.out.println("Reverse complement selected and name="+name.getValue());
     }

 }
 

How do I get all documents in the same folder as a given document?

 AnnotatedPluginDocument document;
 List<AnnotatedPluginDocument> documentsInSameFolder = document.getDatabase().retrieve(Query.Factory.createBrowseQuery(), ProgressListener.EMPTY);
 

How do I get all documents in the user's local database?

 WritableDatabaseService database= (WritableDatabaseService) PluginUtilities.getGeneiousService("LocalDocuments");
 List<AnnotatedPluginDocument> documentsInEntireDatabase = database.retrieve(Query.Factory.createQuery(""), ProgressListener.EMPTY);
 List<AnnotatedPluginDocument> documentsInRootFolderOnly = database.retrieve(Query.Factory.createBrowseQuery(), ProgressListener.EMPTY);
 

How do I export to any document format supported by Geneious?

 SequenceDocument sequence=new DefaultNucleotideSequence("Name","","GATTACA",null);
 AnnotatedPluginDocument document = DocumentUtilities.createAnnotatedPluginDocument(sequence);
 PluginUtilities.exportDocuments(new File("a.fasta"),document);
 

How do I import any document format supported by Geneious?

 List<AnnotatedPluginDocument> docs = PluginUtilities.importDocuments(new File("a.fasta"), ProgressListener.EMPTY);
 SequenceDocument sequence = (SequenceDocument) docs.get(0).getDocument();
 System.out.println("Sequence String="+sequence.getSequenceString());
 

How do I add a document to the user's database?

Normally you wouldn't do this directly. Instead use a
DocumentOperation to generate documents. But if this doesn't suit your plugin needs, you could do something like this which creates a folder in the user's database, adds a new document to it, and selects that document.
 SequenceDocument sequence=new DefaultNucleotideSequence("Name","","GATTACA",null);
 AnnotatedPluginDocument document = DocumentUtilities.createAnnotatedPluginDocument(sequence);
 WritableDatabaseService database= (WritableDatabaseService) PluginUtilities.getGeneiousService("LocalDocuments");
 WritableDatabaseService folder = database.createChildFolder("My Folder");
 document = folder.addDocumentCopy(document, ProgressListener.EMPTY);
 DocumentUtilities.selectDocument(document.getURN());
 

How do I add annotations to a sequence?

Normally you wouldn't do this directly. Instead use a
SequenceAnnotationGenerator which integrates creating annotations into the sequence viewer and manages undoing and saving. But if you need to do it yourself, here is how:
 AnnotatedPluginDocument document; // This is assumed to be an editable sequence document that is already in the user's database.
 SequenceAnnotation annotationToAdd = new SequenceAnnotation("Name", SequenceAnnotation.TYPE_CDS, new SequenceAnnotationInterval(3,10));
 EditableSequenceDocument sequence = (EditableSequenceDocument) document.getDocument();
 List<SequenceAnnotation> annotations= new ArrayList<SequenceAnnotation>(sequence.getSequenceAnnotations());
 annotations.add(annotationToAdd);
 sequence.setAnnotations(annotations);
 document.saveDocument();
 

How do I allow my plugin to depend on external libraries or resources?

For accessing external resources such as data files your plugin should be distributed as a zip file with extension .gplugin containing only a single folder named exactly the same as the fully qualified name of your GeneiousPlugin class. This folder must then contain your plugin jar file (can have any name) and any other files your plugin uses. This folder will be given to your plugin at runtime through the pluginDirectory parameter of the
GeneiousPlugin.initialize method. See ExampleGeneiousService plugin for an example that bundles a data file.

To depend on an external library jar file, also just bundle that alongside your plugin's jar file. Geneious automatically adds all jar files in your plugin's directory to your plugin's class-loader. However, in rare cases you may find this doesn't work as the external library may try to find classes using the system or thread class-loader instead of the class-loader they were created from. If the external library is using the current thread class-loader, wrapping calls to the external library from within your plugin like in the following code fragment may help:

 final ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
 try {
     Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
     // Code that calls a problematic external library method goes here.
 }
 finally {
     Thread.currentThread().setContextClassLoader(oldContextClassLoader);
 }
 

How do I create a log file from within my plugin?

You can use Java's standard logging system (see
java.util.logging). You can specify your logging properties file in the Geneious virtual machine options file.

  • On Windows, this is Geneious.vmoptions inside your Geneious installation directory. Each command line option should be separated by a new line. For example, your VM options file may contain:
     -Xmx500M
     -Djava.util.logging.config.file=c:\temp\logging.properties
     
  • On MacOS, this is Info.plist in the Contents folder inside the Geneious.app bundle (Ctrl+Click on Geneious and select Show package contents). Open Info.plist using the default program (Property List Editor.app) and go in to the Java then the Properties node. Change the key java.util.logging.config.file to contain the path to your logging properties file, eg:
    /Users/richard/logging.properties
Your logging.properties file may contain something like:
.level=WARNING
com.biomatters.level=INFO
your.package.name.level=FINE
handlers=java.util.logging.FileHandler
java.util.logging.FileHandler.append=true
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern=c:\\temp\\geneious.log
 
Replacing your.package.name with your package name. And in your source code you would use a line like:
 Logger.getLogger(getClass().getName()).fine("Hello World!");
 

How do I write unit test cases for my plugin?

Geneious provides the class
TestGeneious to facilitate writing test cases. If you add all Geneious libraries to your classpath, then you can use TestGeneious.initialize to initialize many of the methods in the public api that would otherwise only work from within the Geneious application. For example DocumentUtilities.createAnnotatedPluginDocument requires TestGeneious.initialize() to have been called. If your plugin test case itself needs to depend on other plugins, then TestGeneious.initializeAllPlugins initializes all plugins so that methods such as PluginUtilities.getDocumentOperation can be used to obtain references to other plugins. You may also find TestGeneious.isRunningTest useful.

In a rare case that you want to test your plugin when it is instantiated from the Geneious plugin loading environment (rather than just running from class files), then if you build and copy your plugin to the Geneious plugins folder then your test case could use TestGeneious.initializePlugin to load your plugin and can then use PluginUtilities.getClass to obtain a reference to your class and call any testing methods on it you need to.

How do I invoke other plugin operations?

Sometimes you may want to make use of functionality provided by other plugins when implementing your own plugin. First your plugin needs to get a reference to the functionality provided by another plugin using PluginUtilities and it can then proceed to make use of the plugin.
  1. Getting a reference to the other plugin.

    Each DocumentOperation and SequenceAnnotationGenerator has a unique ID. (DocumentOperation.getUniqueId() and SequenceAnnotationGenerator.getUniqueId()). As long as you know the uniqueID of the operation or annotation generator you can use PluginUtilities.getDocumentOperation() or PluginUtilities.getSequenceAnnotationGenerator() to get a reference to it.

    To view a list of all available uniqueIds, use the following code fragment:

     StringBuilder builder = new StringBuilder();
     builder.append("Document Operations:\n");
     for (DocumentOperation operation : PluginUtilities.getDocumentOperations()) {
         builder.append(operation.getActionOptions().getName()+" has id: "+operation.getUniqueId()+"\n");
     }
     builder.append("\n\nAnnotation Generators:\n");
     for (SequenceAnnotationGenerator generator : PluginUtilities.getSequenceAnnotationGenerators()) {
         builder.append(generator.getActionOptions().getName()+" has id: "+generator.getUniqueId()+"\n");
     }
     String message=builder.toString();
     Dialogs.showMessageDialog(message);
     
  2. Using the other plugin.

    Once you have a reference to your document operation or annotation generator, you could do something like this to use it:

     SequenceAnnotationGenerator primerDesign = PluginUtilities.getSequenceAnnotationGenerator("com.biomatters.plugins.primerDesign.PrimerDesignAnnotationGenerator");
    
     SequenceDocument sequence = new DefaultNucleotideSequence("Name","","GATTACA",null);
     AnnotatedPluginDocument sequenceDocument = DocumentUtilities.createAnnotatedPluginDocument(sequence);
     SequenceAnnotationGenerator.SelectionRange selectionRange = new SequenceAnnotationGenerator.SelectionRange(0, 0, 0, sequence.getSequenceLength() - 1);
    
     Options options = primerDesign.getOptions(selectionRange, sequenceDocument);
     options.setStringValue("MAXIMUM_NUMBER_OF_NON_MATCHING_SEQUENCES","2");
    
     List<SequenceAnnotation> annotationsList = primerDesign.generateAnnotations(selectionRange, ProgressListener.EMPTY, options, sequenceDocument).get(0);
     
    Calling Options.setStringValue() requires knowledge of what options are available. For a given Options instance, calling Options.getDescriptionAndState() lists all supported option values. For example,
     Dialogs.showMessageDialog(StringUtilities.escapeHtmlCharacters(options.getDescriptionAndState()));
     
    in the above example would list all the options you could set when generating primers.
Packages 
Package Description
com.biomatters.geneious.publicapi  
com.biomatters.geneious.publicapi.components
Provides useful GUI (graphical user interface) components, none of which are necessary for creating a plugin, but many plugin implentations will find these components useful.
com.biomatters.geneious.publicapi.databaseservice
Provides the interface and associated classes for defining a database service which is a service that appears on the left-hand side of the main Geneious window and provides the user with access to a database, for example NCBI or the local database for storing the user's documents.
com.biomatters.geneious.publicapi.documents
Provides interfaces and classes for defining documents in Geneious and related interfaces and classes for dealing with XMLSerialization.
com.biomatters.geneious.publicapi.documents.sequence
Provides interfaces specifying the types of sequence and alignment documents in Geneious, together with concrete classes used by sequence documents such as SequenceAnnotation and SequenceCharSequence.
com.biomatters.geneious.publicapi.documents.types
Provides interfaces specifying the types of documents available in Geneious.
com.biomatters.geneious.publicapi.implementations
Provides implementations for many of the document interfaces defined in the package com.biomatters.geneious.publicapi.documents.types together with some utility classes for dealing with some of these document types.
com.biomatters.geneious.publicapi.implementations.sequence
Provides SequenceDocument implementations for nucelotide, amino acid, and nucleotide graph (chromatogram) sequences.
com.biomatters.geneious.publicapi.implementations.structure
Provides MolecularStructureDocument implementations for many commonly used 3D structure documents.
com.biomatters.geneious.publicapi.laf  
com.biomatters.geneious.publicapi.plugin
Provides the GeneiousPlugin interface and plugin related interfaces.
com.biomatters.geneious.publicapi.utilities
Provides various utility methods and classes, none of which are necessary for creating a plugin, but many plugins implentations will find these methods useful.
com.biomatters.geneious.publicapi.utilities.xml