Extension API

Suggest edits
Documentation > Developers

Contents

While OpenMOLE's core code is not intended to be directly accessible to most users, an easy-to-use transparent and flexible API has been developed for simple development of user extensions to the core. This API allows the user to implement new tasks, methods, samplings.

Concepts of the API 🔗

The primitives for the API are imported by importing contents of package org.openmole.core.dsl.extension. These primitive provide constructors for
  • tasks
  • samplings
  • hooks

Task extensions 🔗

To define a new task, use Task(name: String)(process: FromContext => Context). What the task does is defined by the provided closure, which transforms a FromContext into a Context. You can add implicits in your apply method to get advanced services (mole services, network services, etc.). Validation is provided with the validate method which transforms validation parameters into a sequence of throwables. For example
object MyTask {
  def apply(taskparam: Double,taskval: Val[Double])(implicit moleService: MoleServices,workspace: Workspace, networkService: NetworkService) =
    Task("MyTask"){
      parameters =>
        // do something with from context parameters : here add a constant to a double prototype
        Context(taskval -> parameters.context(taskval) + taskparam)
    } validate {vp => vp.map{proto => if(proto.v < 0) new Throwable("double proto should be positive") }} set (
      (inputs,outputs) += (taskval)
    )
}

Sampling extensions 🔗

To implement a sampling, the constructor Sampling takes a function transforming a FromContext into a sampling results, which is an Iterator[Iterable[Variable[_]]]. For example the following sampling assigns uniformally a sequence of doubles to some prototypes :
object MySampling {
  def apply(values: FromContext[Array[[Double]]],prototypes: Val[_]*) = Sampling {
   p =>
    values.from(p.context).map{ value => prototypes.toList.map{ proto => Variable(proto,value)}}.toIterator
  } validate { _ => Seq.empty} inputs {prototypes} prototypes {prototypes}
}

Integrating your extension into the build 🔗

OpenMOLE uses OSGI bundles to integrate its different components into a single application. This allows for example loading bundle in a dynamical way, what is done when adding user plugins through the GUI. To integrate your module into the build process of OpenMOLE, several steps have thus to be performed:
  • Add your module as an Osgi project into the main build file build.sbt. For example, in the case of a new sampling, the syntax would be similar to the sobol sampling:
    lazy val quasirandomSampling = OsgiProject(pluginDir, "org.openmole.plugin.sampling.quasirandom", imports = Seq("*")) dependsOn(exception, workflow, workspace, openmoleDSL) settings (
          libraryDependencies += Libraries.math
          ) settings (pluginSettings: _*)
    
    . Note that you need to specify the bundles you use in your code, and the external libraries dependencies. You also need to add your module to the integrated ones, by adding the project to allSamplings for example. If your library dependency requires specific resolvers, these can be added to defaultSettings or only locally to your project.
  • Add your library dependencies to the Libraries object in the file openmole/project/Libraries.scala. For the code above, you would have to specify the Libraries.math value, which in this particular case is the apache common math library: lazy val math = "org.openmole.library" %% "org-apache-commons-math" % "3.6.1". The library is defined as a bundle under the organisation org.openmole.library. The construction of this bundle is detailed in the next step.
  • Transform the required library dependencies into OSGI bundles. This step is done during the library publishing step of OpenMOLE compilation: you have thus to modify libraries/build.sbt by adding a new OSGI project, for example
    lazy val math = OsgiProject(dir, "org.apache.commons.math", exports = Seq("org.apache.commons.math3.*"), privatePackages = Seq("assets.*")) settings (
    libraryDependencies += "org.apache.commons" % "commons-math3" % mathVersion, version := mathVersion) settings(settings: _*)
    
    . At this stage, the exports statement is important since it is thanks to it that the classes will be visible to other OSGI bundles and more particularly your plugin.
  • A last step may be necessary in the case your dependencies have themselves dependencies which are already OSGI bundle. In that case, a conflict will occur and they must be added to a bundle filter used during the final assembly of OpenMOLE. This filter is defined as bundleFilter in main build. Add the names of the offending libraries in the bundleFilter.exclude function.