Introduction: OSRead - Add a Module

Open Source Reading Education, Assessment, & Diagnosis, abbreviated as OSRead, is an open source system which allows learning and brain science researchers to design and assign reading curriculums to help students practice their reading skills. OSRead is an on-going project started in the University of Washington Computer Science and Engineering Department's Accessibility Capstone in Winter 2016. This project is in-development and can be found in it's most recent state here:

OSRead is designed around the concept of a module. A module is an activity or game developed by researchers to engage students in reading skills practice. Modules exists much like an independent web application, so they can be created to fit a specific need or curriculum. This Instructable will go through the process of creating a module that can be added to OSRead. This Instructable will assume the user is using the Grails Framework,, as it is a free platform to develop web applications.

Step 1: Step 1. Choose a Name Your New Module.

In this tutorial, we will use the name TYPE.

Step 2: Step 2. Create a Grails Plugin

Use the following command line input to have Grails generate scaffolding code for your new plugin:

$ grails create-plugin TYPE

Step 3: Step 3. Add Dependency on MetaFunctionality

In the build.gradle file, add the following lines.

repositories {

... maven { url "" } }

dependencies {

... compile "org.grails.plugins:MetaFunctionality:0.1" ... }

Step 4: Step 4. Create Input Domain

Note - The following classes must exist in a package named type (TYPE in all lower case)

In the domains folder create a domain class with name TYPE. This domain class must do the following: extend the ModuleInput class or define the module input data as fields in the domain. This is where you are able to define the input you want to take in when the module is assigned.


class FirstExample extends ModuleInput {

static hasMany = [words: String]

List words


Step 5: Step 5. Create FetchInputHeadersService

In the services folder create a new service named FetchInputHeadersService.

Within this service define a method that returns a Map that represents a mapping from the fields defined in the domain class to their respective data types.

The following data types are accepted as input: String, Integer, Double, Boolean or any arrays of the those types ([String], [Integer], [Double], [Boolean]).


class FetchInputHeadersService {

def getHeaders () {

Map headers = new LinkedHashMap<>()

headers.put("words", "[String]")

return headers



Step 6: Step 6. Create Start Controller

Create a controller to serve as the entry point of the module.

This controller must be named TYPEController.

The controller must have a method start()

This method will be passed the moduleID of the module through which can be used to get the associated Module object by calling Module.findByModuleID(


import firstexample.FirstExample

import metafunctionality.Module

import metafunctionality.ModuleOutput

class FirstExampleController {

def start() {

String inputID = Module.findByModuleId(

FirstExample input = FirstExample.findByModuleDataID(inputID)

List<String> rc = input.words

//Store Module in saveModuleService

[words: words]



Step 7: Step 7. Build Your Module

Now comes the fun part - creating your module. Here is you opportunity to get creative!

Here are a couple ideas to get you started:

  • Build a "Memory Game" where rather than matching similar pictures, student must match homonyms.
  • Create a multiple choice activity where student must match images of items that rhyme.
  • Build a game where students are given a word and must swap out one letter in the word for another letter to create a new word.

Use your own experience and knowledge to make something cool!

Step 8: Step 8. Save Output

At the end of the module you must save the output that you wish to pass out of the module with the Module object that was passed in.

To do so you must create a ModuleOutput object and store within it the desired headers and rows of comma-separated values.

Finally store the ModuleDataID of the ModuleOutput object in the Module object.

This ModuleOutput object will be translated into a .CSV file with the associated headers and comma-separated rows of data.


def submit() {

List valueRows = new ArrayList<String>()

ModuleOutput output = new ModuleOutput()

output.headers = ["word", "accuracy"]

output.valueRows =

Module m = //load from saveModuleServic

if (m.outputIDs != null) {


} else {

m.outputIDs = [output.moduleDataID]


output.type = "FirstExample" true) true)

//redirect to learner home

redirect(controller: "appforliteracy.FileOutput", action: "output", params: [id: output.moduleDataID])


Step 9: Step 9. Publish Plugin to Remote Maven Repository

Once you have completed your module you must publish it to the Maven repository.

There are several steps to do this:

1. Create an account with

2. Request to join the organization osreadplugins

3. Once your request is approved, add the following to your build.gradle file:

plugins { ... id "com.jfrog.bintray" version "1.2" }

bintray {

user = "username"

key = "apikey"

publications = ['maven']

publish = true

pkg {

userOrg = 'osreadplugins'

name = "TYPE"

issueTrackerUrl = ""

vcsUrl = ""

version {

attributes = ['grails-plugin': "org.osread:TYPE"]

name = 0.1




Your API Key can be found under 'Edit your profile'.

4. Publish your plugin
Enter the following command at your project root:

$ grails gradle bintrayUpload

5. Verify Upload

You should now be able to navigate to and see your plugin!

Step 10: Step 10. Add Dependencies Into the OSRead Main Application

Once you have published your plugin to the Maven repository you are now ready to integrate it into the main application!

Two things are required to do this:

1. Add Dependency

Add the following line to the AppForLiteracy/build.gradle file:

dependencies {


compile "org.grails.plugins:TYPE:version" //version is specified in the build.gradle file of your plugin under the name field of version



2. Add Your TYPE to ModuleListService

class ModuleListService {

static List getModuleNames() {

List names = new ArrayList<>()



//TODO: Add additional module names here

return names



You're new module should be completely functional! Test it by assigning the module with a module input file that matches your specified input plus name and type fields.



"type": "FirstExample",

"name": "Example Input",

"words": [






3. Specify the security level of the new module.

In "application.groovy", add:

[pattern: '/<ModuleName>/**', access: ['ROLE_USER']]

under: grails.plugin.springsecurity.interceptUrlMap


seamster (author)2016-03-17

Very interesting, thanks for sharing the details!