The DoKS Scripting API

From DoKSwiki

In your scripts you can use specific DoKS objects and functions, e.g. to access inputs, write output, find, create or update records.

Table of contents

General Objects

All available objects are programmed in the execute methods of ScriptManager.java.

user

The current user's UserDTO.

DoKS Facade Objects

folderFacade
recordFacade
userFacade
storageFacade
sdiFacade
accessControlFacade

_scriptManager

The ScriptManager object itself, useful to execute other scripts from within a script.

params

A Map containing input values and return values.

Input

To get an array of the input arguments that are filled in on the script page in DoKS use:

args = params.get(Constants.ARGS);

Then check your inputs if they are mandatory:

//for 1 expected argument
if (args==null || args.length < 1 || args[0].trim().length()==0) {
    throw new Exception("you must specify Arg 0 !");
}

//for 2 expected arguments
if (args==null || args.length < 2 || args[0].trim().length()==0 || args[1].trim().length()==0){
    throw new Exception("you must specify Arg 0 and Arg 1 !");
}

//for 3 expected arguments
if (args==null || args.length < 3 || args[0].trim().length()==0 || args[1].trim().length()==0 || args[2].trim().length()==0){
    throw new Exception("you must specify Arg 0, Arg 1 and Arg 3 !");
}


To get other input parameters use:

inputParam = params.get("myParam");


Output

To the browser

To show script output in the browser after execution, append this to your code:

output = "This string contains my output. <p>It can contain HTML tags to format the output.</p>";
params.put(Constants.SCRIPT_OUTPUT, output);
params.put(Constants.FORWARD, null);
To Velocity templates or to other scripts

Set your own self defined outputs:

//set an object parameter
list= new LinkedList();
list.add("item1");
list.add("item2");
params.put("result", list);

//set a primitive parameter
params.put("pricePerCopy",  3.35);

These outputs can then be accessed in Velocity templates or in other scripts.

//first execute the script
execute("pricePerCopy", params);

//then get the output
pricePerCopy= params.get("pricePerCopy");
To a stream

E.g. output an XML-stream that can be saved from the browser:

response=params.get(Constants.HTTP_RESPONSE);
response.setContentType("application/xml");

text="<xml>This is a test</xml>";

ByteArrayInputStream is = new ByteArrayInputStream(text.getBytes());
org.apache.commons.io.CopyUtils.copy(is, response.getOutputStream());
is.close();
response.getOutputStream().flush();

Forward

You can forward to another DoKS page after executing the script:

//forward to empty page
params.put(Constants.FORWARD, null);
//forward to the view page of a certain record
params.put(Constants.RECORD_DTO, recordDto);
params.put(Constants.FORWARD, Constants.RECORD_VIEW);
//forward to the edit page of a record in a specified folder
params.put(Constants.RECORD_DTO, recordDTO);
params.put(Constants.FOLDER_DTO, folderDTO);
params.put(Constants.FORWARD, Constants.RECORD_EDIT);


Parse Velocity Template

parse a Velocity template and show the generated page in the browser.

params.put(Constants.FORWARD, Constants.PARSE_VM);
params.put(Constants.VM_PATH, "local/KHK_ETD/Front.vm");


logger

The Log4J logger object can be used for debugging and logging.
For debugging in a standard DoKS installation the WARN level will show you messages in doks.log or console window, if it doesn't try the ERROR level:

logger.warn("my message");

For pure logging purposes choose the level that is appropriate:

logger.debug("my message");
logger.info("my message");
logger.warn("my message");
logger.error("my message");

Configuration settings of the logging object are in log4j.properties.
You can also change the log level of a specified class programatically for debugging purposes:

//change logging level for RecordManager class to DEBUG
org.apache.log4j.Logger.getLogger(RecordManager.class).setLevel(org.apache.log4j.Level.DEBUG);

Change it back to the WARN or ERROR level afterwards because too much logging can slow down the application and generates a very large doks.log file.

_session

The current database session.
Can be used e.g. to directly query the database:

List list = _session.find("from doks.record.Record where description='my description'");

Normally you should NOT use this method.
Instead use the appropriate find methods on the Facade objects:

List list = recordFacade.findRecords("ETD", "description='my description'");


DoKS API Objects

  • folderFacade
  • recordFacade
  • userFacade
  • storageFacade
  • sdiFacade

are described in DoKS API

Execute a script from another script

A script without input and output:

executeScript("calculate_copies");

A script with input and/or output:

params.put("myInput", 123);
execute("myscript", params);

You can add as many inputs as you need. Output parameters of the executed script can be accessed directly from the params variable, see output

Execute a script from a Velocity template (vm)

First set the input parameters in a map if needed. Then execute the script with its name and the parameters map.

#set($params= $doks.createMap("cvDto", $recordDto))
#set($success=$doks.executeScript("setCVPermissions", $params))

Execute a script from a webpage (html)

With a link:

<a href='$linktool.setAction("/script")?dispatch=executeScript&name=MyScript&recordId=$recordDto.id'>Execute MyScript</a>

With a form:

<form name="executeScriptForm" method="post" action="$linktool.setAction("/script")" >
    	<input type= "hidden" name="dispatch" value="executeScript" >
       	<input type= "hidden" name="name" value="MyScript" >
       	<input type= "hidden" name="recordId" value="$recordDto.id">
        <input type= "hidden" name="input" value="xxx">
       	<input type="submit" value="Execute MyScript" >
</form>

The field named "input" can contain any extra values that you want to pass to the script, like the value from an HTML input field for instance (using javascript in the onclick event of the submit button to fill in the value of the "input" field). Access the value in the script with:

input = params.get(Constants.SCRIPT_INPUT);


Adding the recordId parameter enables you to access the current record in the script with this code (see also see input):

recordDto = params.get(Constants.RECORD_DTO);

Auto-executed event-bound scripts

If they exist these scripts are executed on key events in an object's lifetime (creation, update, deletion).
Naming convention for the scripts: <object type>_<eventname>
The objects "recordDto" resp. "userDto", the current RecordDTO/UserDTO is available through:

recordDto=params.get("recordDto");
userDto=params.get("userDto");

_init

Script executed when you click on a "New Record" link/button (or with a link like this: .../do/record/Get?dispatch=create&structureName=Document). This is before anything is created in the database (the new record is not yet saved). The purpose of this script is to fill the fields of a structure with an initial value. This script is only executed once in the lifetime of a record.

In more technical terms: it can be used to assign default values to the fields of a DTO, but keep in mind that there is no corresponding record in the database yet so it can not be used to set permissions for instance.

Can be used for all types defined in structures.xml. E.g. ETD_init

_create

Script executed when you click "save" for the first time on a new record (or with a link like this: .../do/Document/Edit?dispatch=save). In this script you can set permissions or attach other structures or do anything, the record completely exists. This script is only executed once in the lifetime of a record.

Can be used for all types defined in structures.xml and for User objects. E.g. ETD_create or User_create

_update

Script executed on every save action on an existing record (or with a link like this: .../do/Document/Edit?dispatch=save). You can do anything with the record.

Can be used for all types defined in structures.xml and for User objects. E.g. ETD_update or User_update

_delete

Script executed when you click "delete" (or with a link link like this: .../do/record/Get?dispatch=delete&recordId=SDoc43bf17093f9ba2010943c8766494)

Can be used for all types defined in structures.xml. E.g. ETD_delete

_index

Script executed when a record is indexed by the search engine. Depending on your configuration that could mean on every save action and/or only when you explicitly index records from the administrator section. [only available in versions higher than 1.2.4]

The purpose of this script is to allow for specific search fields for each record type. By default the contents of all fields are indexed and can be accessed for search through the field name used in structures.xml.

In this script you can create extra search fields that can be a combination or processed version of other fields or that contain information of attached records or any other information.

Another use can be to ensure that certain search fields always exist because they are displayed in the search results (abstract e.g.). Other examples are "hasFullText", a field that tells if a record has a file attachment; or "authors", a field that contains a list of the names of Author records attached to this record.

Can be used for all types defined in structures.xml. E.g. ETD_index

Queries

Use the appropriate find methods on the Facade objects, they take a filter (this is the 'where' clause of a SQL query) in Hibernate (http://www.hibernate.org)'s SQL-like query language HQL (http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html).
There are a few approaches for filters:
preferred method:

  • Use "record.<field name>":
filter= "record.publicationDate=2005 AND record.code like 'LT%'";
list= recordFacade.findRecords("ETD", filter);

An example of a more complex filter with an 'ORDER BY' clause (args[x] are input arguments):

filter= "record.status='TITLE_AVAILABLE' AND record.code like '" + args[1].trim() + 
         "%' AND record.publicationDate=" + args[0].trim() + " ORDER BY record.thesisNumber";
list= recordFacade.findRecords("ETD", filter);

Other methods:

  • Use "<field name>x" (this is the literal column name in the database):
filter= "publicationDatex=2005 AND codex like 'LT%'";
list= recordFacade.findRecords("ETD", filter);
  • Use a query with bind parameters. Binding an array of values to "?" parameters in the query string:
list = recordFacade.findRecords("ETD", 
                                "record.degreeName=?", 
                                new Object[] {"Bachelor"}, new net.sf.hibernate.type.Type[] {net.sf.hibernate.Hibernate.STRING});

//this is actually the same as recordFacade.findRecords("ETD", "record.degreeName='Bachelor'")


What to do with the results?
A query returns an ArrayList containing RecordLink objects, you have to create DTO's from the RecordLinks to access all fields:

iter = list.iterator();
while (iter.hasNext()){
   recordLink = iter.next();
   etdDTO = recordFacade.getRecordDTO(recordLink.id);
   
   //here your code that uses etdDTO

}


If you want to find all records of a specific structure then set filter to null:

filter= null;
theses= recordFacade.findRecords(Constants.LOCALSTRUCTURE, filter);