$application

Global object for defining and managing a Myna application.  See Application Overview

Summary
$applicationGlobal object for defining and managing a Myna application.
Application OverviewGeneral Description of application configuration
Application Template
Properties
appnameString application name.
displayNameString application name for displaying to humans Default appname.
descriptionShort description of this application
authorName of the author of this application
authorEmailemail of the author of this application
websiteWebsite associated with this application
versionApplication version
minMynaVersionMinimum version of Myna this application is likely to work with
postInstallUrlURL that should be visited first after deployment, relative to the application’s install directory
appStartIs this the startup request for this app?
idleMinutesMax time in minutes between application data access before app memory is recovered Default 60.
rightsArray of Myna.Permissions.Right definitions
directoryMynaPath of directory of closest application.sjs CALCULATED
urlURL path of closest application.sjs CALCULATED
closeArrayArray of resources onwhich we should cal close() on request end.
Functions
addOpenObjectAdd an object to $application to be closed at the end of the thread.
getReturns the application variable associated with the supplied key
getDataReturns a read-only object representing all of the application’s data set via set
setSet the application variable associated with the supplied key, returns value
clearClears any data in the $application cache
reloadClears any data in the $application cache, and re-runs onApplicationStart
initCalled before any processing of the request
onApplicationStartCalled when a new application scope is created, before $application.onRequestStart.
onBeforeRequestStartCalled before any parent request start functions.
onRequestStartCalled before processing a request, but after and parent onRequestStart functions.
onRequestEndCalled after processing a request.
onErrorCalled when a an error occurs.
onError404Called when a request for a non-existent file occurs.
onSessionStartCalled when a new session is created, before $application.onRequestStart.

Application Overview

General Description of application configuration

What is an application?

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

$application and application.sjs

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:

  • declare application specific variables
  • execute functions
  • append or prepend $application.onXXX() event functions.  See Object.before and Object.after and examples below

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.

Named or Anonymous?

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.

Nested applications

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.

Note

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.

Examples

//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>

See

See also

Application Template

The application.sjs file should conform to this template

{
//--------- 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
}

Properties

appname

String application name.

Detail

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

Example

..
appname:"myna_admin",
..

displayName

String application name for displaying to humans Default appname.

Detail

This should be a single line title for the application as you might display in you page title

Example

..
displayName:"Myna Administrator",
..

description

Short description of this application

Example

..
description:"Manages Myna server settings",
..

author

Name of the author of this application

Example

..
author:"Mark Porter",
..

authorEmail

email of the author of this application

Example

..
authorEmail:"mark@porterpeople.com",
..

website

Website associated with this application

Example

..
website:"http://www.mynajs.org",
..

version

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)

Example

..
version:"1.0_beta_5-1",
..

minMynaVersion

Minimum version of Myna this application is likely to work with

Example

..
website:"1.0_beta_5-1",
..

postInstallUrl

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.

Example

..
website:"1.0_beta_5-1",
..

appStart

Is this the startup request for this app?

Detail

When an application startup is detected, this property is set to true

idleMinutes

Max time in minutes between application data access before app memory is recovered Default 60.

Detail

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.

rights

Array of Myna.Permissions.Right definitions

Detail

Any rights defined here will be created/updated before $application.onApplicationStart.  The “appname” property is set to this app’s name:

Example

...
rights:[{
name:"edit_posts",
description:"Allows editing of existing posts"
},{
name:"create_posts",
description:"Allows creating new posts"
}]
...

directory

MynaPath of directory of closest application.sjs CALCULATED

Detail

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

URL path of closest application.sjs CALCULATED

Detail

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.

Example

/servlet-context/my_app/

closeArray

Array of resources onwhich we should cal close() on request end.

Detail

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.

See

addOpenObject

Functions

addOpenObject

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.

Parameters

objan object with a close() function

Example

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

get:function(key)

Returns the application variable associated with the supplied key

Parameters

keyString variable name

Returns

The application variable associated with the supplied key.

Note

application variables are deleted after idleMinutes of inactivity Example:

var lastUser = $application.get("lastUser")||$cookie.getAuthUser();

getData

getData:function(key)

Returns a read-only object representing all of the application’s data set via set

Parameters

keyString variable name

Returns

The application variable associated with the supplied key.

set

set:function(key,
value)

Set the application variable associated with the supplied key, returns value

Parameters

keyString variable name
valuevalue to set

Note

application variables are deleted after idleMinutes of inactivity Example:

$application.set("lastUser",$cookie.getAuthUser());

clear

clear:function()

Clears any data in the $application cache

This causes the next load of a page in this application to trigger onApplicationStart

Warning

This might causes errors if other threads are currently accessing the $application cache.  To reduce the chances of this, see reload

Example

$application.clear();

reload

reload:function()

Clears any data in the $application cache, and re-runs onApplicationStart

Warning

This might causes errors if other threads are currently accessing the $application cache, and they try to access a parameter not set in onApplicationStart.

Example

$application.reload();

init

Called before any processing of the request

Detail

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.

Example

//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

onApplicationStart:function()

Called when a new application scope is created, before $application.onRequestStart.

Detail

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

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

onRequestStart:function()

Called before processing a request, but after and parent onRequestStart functions.

Detail

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.

Example

//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

onRequestEnd:function()

Called after processing a request.

Detail

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

onError:function()

Called when a an error occurs.

Parameters

exceptiona caught exception object

Detail

This function is executed before the default error handler.  Return true to cancel the default error handler.

onError404

onError404:function()

Called when a request for a non-existent file occurs.

Detail

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

onSessionStart:function()

Called when a new session is created, before $application.onRequestStart.

Detail

This function does nothing unless it is appended or replaced in an application.sjs file.

Provides access to Right specific actions.
addOpenObject:function(obj)
Add an object to $application to be closed at the end of the thread.
get:function(key)
Returns the application variable associated with the supplied key
getData:function(key)
Returns a read-only object representing all of the application’s data set via set
set:function(key,
value)
Set the application variable associated with the supplied key, returns value
clear:function()
Clears any data in the $application cache
reload:function()
Clears any data in the $application cache, and re-runs onApplicationStart
onApplicationStart:function()
Called when a new application scope is created, before $application.onRequestStart.
onRequestStart:function()
Called before processing a request, but after and parent onRequestStart functions.
onBeforeRequestStart:function()
Called before any parent request start functions.
onRequestEnd:function()
Called after processing a request.
onError:function()
Called when a an error occurs.
onError404:function()
Called when a request for a non-existent file occurs.
onSessionStart:function()
Called when a new session is created, before $application.onRequestStart.
General Description of application configuration
Object.prototype.before=function(functionName,
functionObj)
Prepends supplied function to the event chain of this object.
Object.prototype.after=function(functionName,
functionObj)
Appends supplied function to the event chain of this object.
Function.createChainFunction=function(initialChain)
returns a function that will execute a chain of functions when called.
Myna.loadAppProperties=function Myna_loadProperties(filepath)
loads an application.sjs file and returns the parsed app object
String.compareNatural = function(a,
b)
Static A static sort function that will compare two strings in a natural way.
Max time in minutes between application data access before app memory is recovered Default 60.