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);
