Global object for defining and managing a Myna application. See Application Overview
| $application | Global object for defining and managing a Myna application. |
| Application Overview | General Description of application configuration |
| Application Template | |
| Properties | |
| appname | String application name. |
| displayName | String application name for displaying to humans Default appname. |
| description | Short description of this application |
| author | Name of the author of this application |
| authorEmail | email of the author of this application |
| website | Website associated with this application |
| version | Application version |
| minMynaVersion | Minimum version of Myna this application is likely to work with |
| postInstallUrl | URL that should be visited first after deployment, relative to the application’s install directory |
| idleMinutes | Max time in minutes between application data access before app memory is recovered Default 60. |
| rights | Array of Myna.Permissions.Right definitions |
| directory | MynaPath of directory of closest application.sjs CALCULATED |
| url | URL path of closest application.sjs CALCULATED |
| closeArray | Array of resources onwhich we should cal close() on request end. |
| Functions | |
| addOpenObject | Add an object to $application to be closed at the end of the thread. |
| get | Returns the application variable associated with the supplied key |
| getData | Returns a read-only object representing all of the application’s data set via set |
| set | Set the application variable associated with the supplied key, returns value |
| clear | Clears any data in the $application cache |
| reload | Clears any data in the $application cache, and re-runs onApplicationStart |
| init | Called before any processing of the request |
| onApplicationStart | Called when a new application scope is created, before $application.onRequestStart. |
| onBeforeRequestStart | Called before any parent request start functions. |
| onRequestStart | Called before processing a request, but after and parent onRequestStart functions. |
| onRequestEnd | Called after processing a request. |
| onError | Called when a an error occurs. |
| onError404 | Called when a request for a non-existent file occurs. |
| onSessionStart | Called when a new session is created, before $application.onRequestStart. |
General Description of application configuration
A Myna application is any collection of content whose top level folder contains an application.sjs file. This file defines $application variables and workflow event handlers. It is possible for applications to overlap and override each other. In the case of web applications that are intended to be complete and stand-alone, the application.sjs will define properties such as appname and version. However, application.sjs file can also be used to set defaults and/or alter the behavior of applications in subfolders. This is considered an anonymous application and does not declare an appname. An example might be if you wanted to set a global error handler. You could place an anonymous application.sjs file in the webroot with an onError function defined that returns true to override the default error handler. Any nested applications that also define an onError handler can optionally override this global handler
The $application object is initialized via an application.sjs file in the current directory or any parent directory. When a Myna file is requested, Myna examines every directory between the web root and the requested file, and includes any application.sjs file it finds, in the order found. Each of these files has an opportunity to:
Once all the application.sjs files have been included, $application.onRequestStart is called. $application.onApplicationStart and $application.onSessionStart may be called as well.
Next, the originally requested Myna file is executed.
Finally $application.onRequestEnd is called.
Applications can be named or anonymous. Named applications are registered in the permissions system and also have a variable cache accessed through $application.set/get. Named applications can be imported/exported/installed as Myna Eggs via the “Manage Applications” section of the Myna Adminstrator.
Anonymous applications allow you to define or override variables and alter the workflow of nested applications, i.e. any content in or below the folder that contains the anonymous application.sjs file.
When there are multiple application.sjs file between the webroot and the requested Myna file, they are applied from the webroot inward such that each inner application.sjs overrides its parent. However, the workflow functions are handled a little differently. The workflow functions are actually chains (see <Function.createChainFunction> and <Object.before>/after). This means that if onRequestStart is defined in both an inner and outer application.sjs file, both functions will be executed. The onAfterXX and onRequestStart are executed from the outside-in and all other workflow functions are executed from the inside-out. Like so
onRequestStart:outer
onRequestStart:inner
somefile.sjs
onRequestEnd:inner
onRequestEnd:outer
The order is somewhat more complicated if the onBeforeXX and onAfterXX variants are used
onBeforeRequestStart:inner
onBeforeRequestStart:outer
onRequestStart:outer
onRequestStart:inner
somefile.sjs
onRequestEnd:inner
onRequestEnd:outer
onAfterRequestEnd:outer
onAfterRequestEnd:inner
It is possible to terminate a chain early by calling arguments.callee.chain.exit() See Function.createChainFunction for more detail on manipulating function chains.
To maintain compatibility with older Myna code, an application.sjs file may contain plain JS. In this case it will internally be converted into an “init” function and executed.
//from the Myna Adminstrator
{
appname:"myna_admin",
displayName:"Myna Adminstrator",
noAuthFuses:["login","auth", "logout"],
defaultFuseAction:"login",
mainFuseAction:"main",
onRequestStart:function(){
if (!$req.data.fuseaction) $req.data.fuseaction=this.defaultFuseAction;
//is the user authenticated?
if (this.noAuthFuses.indexOf($req.data.fuseaction.toLowerCase()) != -1) return;
if ( !$cookie.getAuthUserId() ){
$req.data.fuseaction=this.defaultFuseAction;
} else { //is the the user authorized for this fuseaction?
if ($cookie.getAuthUserId() == "myna_admin") return;
var user = $cookie.getAuthUser();
if (user.hasRight("myna_admin","full_admin_access")) return;
$req.data.fuseaction="no_access";
throw new Error("You do not have access to that feature")
}
},
onApplicationStart:function(){
var props =new Myna.File("/WEB-INF/classes/cron.properties")
if (!props.exists()){
props.writeString("")
}
//Load datasource driver properties
var propFiles = new Myna.File("/shared/js/libOO/db_properties").listFiles("sjs");
var db_props={}
propFiles.forEach(function(propFile){
if (!/[\w]+.sjs$/.test(propFile.getFileName())) return;
var vendor = propFile.getFileName().split(/\./)[0];
var obj={};
Myna.include(propFile,obj);
if (obj.dsInfo){
db_props[vendor] = obj.dsInfo;
}
});
$application.set("db_properties",db_props);
},
rights:[{
name:"full_admin_access",
description:"Full access to all Administrator functions"
}]
}
// an example of anonymous applications and altered workflow.
// parent folder
{
//$application.directory and $application.url are calcularted automatically
layoutFile:$application.directory +"layout/outer_template.ejs"
init:function(){
// This wraps all content generated in a layout file.
// By using "before" in this init function, we are reversing the
// execution order to "inside-out" instead of the default "outside-in"
$application.before("onRequestEnd",function(){
if (Page.includeLayout) {
Myna.includeOnce(this.layoutFile,{content:$res.clear()})
}
})
},
onRequestStart:function(){
//decalres global variable that the request page can access
Page={
includeLayout:true,
title:"Parent content",
breadCrumbs:[{
url:$application.url,
label:"Parent"
}],
}
},
}
//child folder
{
layoutFile:$application.directory +"layout/inner_template.ejs"
init:function(){
// This wraps all content generated in a layout file, before the parent wrap.
// By using "before" in this init function, we are reversing the
// execution order to "inside-out" instead of the default "outside-in"
$application.before("onRequestEnd",function(){
if (Page.includeLayout) {
Myna.includeOnce(this.layoutFile,{content:$res.clear()})
}
})
},
onRequestStart:function(){
//override page defaults
Page.title = "Child content"
Page.breadCrumbs.push({
url:$application.url,
label:"Child"
})
},
}
//outer_template layout file
<html>
<head><title><%=Page.title%></title></head>
<body>
<!-- Breadcrumbs -->
<div class="header-breadcrumbs">
<ul>
<@loop array="Page.breadCrumbs" element="bc">
<li><a href="<%=bc.url%>"><%=bc.label%></a></li>
</@loop>
</ul>
</div>
<div id="main_content"><%=this.content%></div>
</body>
</html>
//inner_template layout file
<div id="inner_content">
<h1> Here is the inner layout </h1>
<%=this.content%>
</div>
{
//--------- properties -----------------------------------------------
// you can access these properties from another app via Myna.loadAppProperties()
appname:"",// unique variable name of this application, omit this for anonymous applications
idleMinutes:60,// Lifetime of Application variable cache
//--------- app package properties
displayName:"",// "pretty" name used in labels and titles
description:<ejs>
</ejs>,//short description of application
author:"", //name of app author
authorEmail:"",// email of app author
website:"",//website associated with this app
version:"", //app version. This should be a dot notation
minMynaVersion:null,// Minimum version of Myna the app might run on
postInstallUrl:null,// URL that should be visited first after deployment, relative to app install dir
//--------- local properties -----------------------------------------
myProp:"",
//--------- init method ----------------------------------------------
init:function(){ // this is run before any workflow methods to setup the application.
},
//--------- workflow methods -----------------------------------------
onApplicationStart:function(){ // run if application cache has expired
},
onRequestStart:function(){ // run directly before requested file
},
onRequestEnd:function(){ // run directly after requested file
},
onSessionStart:function(){ // run before a call to $session.get/set when session is expired
},
onError:function(){ //run when an error occurs. Return true to cancel default.
},
onError404:function(){ //run when a call to a non-existent file is made. Return true to cancel default.
},
rights:[], // an array of Myna.Permissions.Right definitions to be created
}String application name.
Should only contain letters, numbers and the underbar (_) character. If set, an application cache is created. Variables can be set and retrieved from this scope via $application.set and $application.get. Setting an appname also registers this application in the permissions system
..
appname:"myna_admin",
..
String application name for displaying to humans Default appname.
This should be a single line title for the application as you might display in you page title
..
displayName:"Myna Administrator",
..
Short description of this application
..
description:"Manages Myna server settings",
..
Application version
This should be in dot notation such that String.compareNatural will sort the version properly. Here is an example for testing a version scheme:
var v = [
"1.0_beta_5-1",
"1.0_beta_5-2",
"1.0_beta_6-1",
"1.0_alpha_5-1",
"1.0_rc_1-2",
"1.0_stable",
"1.1_alpha_1",
"1.1_beta_2",
"1.1_stable",
]
v.sort(String.compareNatural)
Myna.printDump(v)
v.sort(String.compareNaturalReverse)
Myna.printDump(v)
..
version:"1.0_beta_5-1",
..
Minimum version of Myna this application is likely to work with
..
website:"1.0_beta_5-1",
..
URL that should be visited first after deployment, relative to the application’s install directory
This should be null unless your application requires setup beyond copying files.
..
website:"1.0_beta_5-1",
..
Max time in minutes between application data access before app memory is recovered Default 60.
Any data set in the application scope should be expected to be destroyed at some point. Persistent data should be set in $application.onApplicationStart since that function is called before $application.onRequestStart when the application cache has timed out.
Array of Myna.Permissions.Right definitions
Any rights defined here will be created/updated before $application.onApplicationStart. The “appname” property is automatically added
MynaPath of directory of closest application.sjs CALCULATED
application.sjs files are loaded consecutively from the web root to the requested file. Inside an application.sjs file, this represents the directory of the currently executing application.sjs file. Because each consecutive application.sjs file overwrites this property, it will always represent the innermost application.
URL path of closest application.sjs CALCULATED
application.sjs files are loaded consecutively from the web root to the requested file. This property is the URL path of the last application.sjs file to run and generally represents the “home” directory of the application.
/servlet-context/my_app/
Array of resources onwhich we should cal close() on request end.
This is primarily to ensure the release of jdbc connection, statement, and resultSet objects, but anything with a close() function can be pushed onto this array.
addOpenObject:function( obj )
Add an object to $application to be closed at the end of the thread. Any object with a close() function can be added. Intended for resource cleanup.
| obj | an object with a close() function |
function getFileStream(path){
var fis = new java.io.FileInputStream(new File(scriptPath).javaFile);
// we can't be sure the caller will close this stream, so we'll register
// fis to be closed at the end of the thread
$application.addOpenObject(fis);
return fis;
}
get:function( key )
Returns the application variable associated with the supplied key
| key | String variable name |
The application variable associated with the supplied key.
application variables are deleted after idleMinutes of inactivity Example:
var lastUser = $application.get("lastUser")||$cookie.getAuthUser();
getData:function( key )
Returns a read-only object representing all of the application’s data set via set
| key | String variable name |
The application variable associated with the supplied key.
set:function( key, value )
Set the application variable associated with the supplied key, returns value
| key | String variable name |
| value | value to set |
application variables are deleted after idleMinutes of inactivity Example:
$application.set("lastUser",$cookie.getAuthUser());
clear:function()
Clears any data in the $application cache
This causes the next load of a page in this application to trigger onApplicationStart
This might causes errors if other threads are currently accessing the $application cache. To reduce the chances of this, see reload
$application.clear();
reload:function()
Clears any data in the $application cache, and re-runs onApplicationStart
This might causes errors if other threads are currently accessing the $application cache, and they try to access a parameter not set in onApplicationStart.
$application.reload();
Called before any processing of the request
This function is called after loading the $application.sjs file, but before any nested application.sjs files. This is intended for more complicated configuration of the $application object.
This function does nothing unless it is defined in an application.sjs file.
//in application.sjs
{
init:function(){
// Inits are always executed outside-in. This causes the DS to be
// set by the outermost folder
if (!$application.ds){
if ($server.properties.instance_purpose.toLowerCase() == "dev"){
$application.ds="hr_dev"
} else {
$application.ds="hr_prod"
}
}
}
}
onApplicationStart:function()
Called when a new application scope is created, before $application.onRequestStart.
A new application scope is typically created on server restart or the first request after a cache timeout.
This function does nothing unless it is appended or replaced in an application.sjs file.
onBeforeRequestStart:function()
Called before any parent request start functions.
Calling arguments.callee.chain.exit() will exit the chain and prevent any further request start functions from executing
onRequestStart:function()
Called before processing a request, but after and parent onRequestStart functions.
This function is called after all the initial request processing, but before executing the requested file.
This function does nothing unless it is appended or replaced in an application.sjs file.
//in application.sjs
{
onRequestStart:function(){
// create a DataManager with a datasource that
// has the same name as the application directory
dm = new Myna.DataManager(new Myna.File($application.directory).getFileName);
}
}
onRequestEnd:function()
Called after processing a request.
This function is called after executing the requested file, but before sending output to the browser.
This function does nothing unless it is appended or replaced in an application.sjs file.
onError:function()
Called when a an error occurs.
| exception | a caught exception object |
This function is executed before the default error handler. Return true to cancel the default error handler.
onError404:function()
Called when a request for a non-existent file occurs.
This function is executed before the default 404 error handler. You can Use this to provide your own “missing file” error handler.
Return true to cancel the default 404 error handler.
onSessionStart:function()
Called when a new session is created, before $application.onRequestStart.
This function does nothing unless it is appended or replaced in an application.sjs file.
Add an object to $application to be closed at the end of the thread.
addOpenObject:function( obj )
Returns the application variable associated with the supplied key
get:function( key )
Returns a read-only object representing all of the application’s data set via set
getData:function( key )
Set the application variable associated with the supplied key, returns value
set:function( key, value )
Clears any data in the $application cache
clear:function()
Clears any data in the $application cache, and re-runs onApplicationStart
reload:function()
Called when a new application scope is created, before $application.onRequestStart.
onApplicationStart:function()
Called before processing a request, but after and parent onRequestStart functions.
onRequestStart:function()
Called before any parent request start functions.
onBeforeRequestStart:function()
Called after processing a request.
onRequestEnd:function()
Called when a an error occurs.
onError:function()
Called when a request for a non-existent file occurs.
onError404:function()
Called when a new session is created, before $application.onRequestStart.
onSessionStart:function()
Prepends supplied function to the event chain of this object.
Object.prototype.before=function( functionName, functionObj )
Appends supplied function to the event chain of this object.
Object.prototype.after=function( functionName, functionObj )
returns a function that will execute a chain of functions when called.
Function.createChainFunction=function( initialChain )
loads an application.sjs file and returns the parsed app object
Myna.loadAppProperties=function Myna_loadProperties( filepath )
Static A static sort function that will compare two strings in a natural way.
String.compareNatural = function( a, b )