Architecture

Config class

Config class located in WEB-INF/classes/framework/Config.js represents configuration information for TROIKA.ASP framework. It parses WEB-INF/config.xml file when web application starts up, see global.asa:



function Application_OnStart() {
     
  var root = Server.MapPath("/") + "/../";    
  var config = new Config("/WEB-INF/config.xml", root);
  
    Application.Contents(FrontController.APP_CONFIG) = config.toString();
    Application.Contents(ApplicationAdapter.APP_ROOT) = root;
    Application.Contents("debug") = 1;
}

The framework then stores the JSON representation of the Config class in the application repository under

FrontController.APP_CONFIG
key. The JSON string can be retrieved later and desterilised back to Config instance.

JSON (JavaScript Object Notation) is JavaScript's object literal format.

In TROIKA.ASP framework we override the default behaviour of Object’s toString() method so that it returns JSON string serializing all properties. For example, we define a new TestObject like this:



function TestObject() {
    this.prop1 = "hi there";
    this.prop2 = 200;
  }

Call to toString() method


var obj1 = new TestObject();
var jsonStr = 
out(obj1.toString());

will produce output like this:


{"prop1":"hi there","prop2":200}

In order to deserialize the object you would write code like this:


var obj2 =  new TestObject().valueOf(jsonStr);

out(obj2.prop1);

Please see WEB-INF/classes/base/Object.js for other methods available for all objects in the framework.

The config.xml file can be used to define the following aspects of TROIKA.ASP framework:

Defining database connection strings

You can optionally define database connections string for your application by using <db-connection> element inside <db-connections> element. In the example below I am using SQL server and MS Access database connection strings:


<db-connections>
  <db-connection name="sql-data"
    conn-string="Driver={SQL Server};Server=localhost;Address=localhost,1433;Network=DBMSSOCN;Database=mydata;Uid=myuser;Pwd=pass;" />
  <db-connection name="access-data"
    conn-string=" Driver={Microsoft Access Driver (*.mdb)};Dbq=c:/troika-asp/WEB-INF/data/helloworld.mdb;" />
</db-connections>

The Config class has a map property dBConnections which contains all connection strings.

In your Command execute() method you would have code like this to access it:


var connStr = this.config.dBConnections[“access-data”];

There is a convenience method on basic Command object to do the same:



var connStr = this.getConnectionString(“access-data”);

Defining Logger configurations

<logger> element defines Logger information.



<logger>
  <file-name>${root}/WEB-INF/logs/application.log</file-name>
  <max-size>512</max-size>
  <generations>3</generations>
  <log-level>FILTER_INFO</log-level>
</logger>

  • <file-name> - specifies the name of the file. ${root} variable is expanded with the full path to your web application location.
  • <max-size> - tell the maximum size of the file before it rolls in kilobytes.
  • <generations> - numbers of files to keep before rolling them removing the oldest. For example:
    
    
    application.log
    application.log.1
    application.log.2
    application.log.3  the oldest
    
  • <log-level> - element indicating the logging level, can be one of the following string:
    
    FILTER_NONE
    FILTER_ERROR
    FILTER_WARNING
    FILTER_INFO
    
    

    For more information please see Logger class

You can always access logger in your classes like this:


Logger.log.info(msg);
Logger.log.warn(msg);
Logger.log.error(msg);

For convenience the basic Command object defines the following helper methods:



this.logError(error)

Where, error can be an object or a simple string. If it is an object logError() method concatenates key/value pairs with “|” character and writes the resulting string into the log file.


this.logWarn(warning)
this.logInfo(info)

Defining RequestContext mappings

RequestContext defined by a simple <req-ctx-map> element:


<req-ctx-maps>
  <req-ctx-map name="pageForm" type="PageForm" />
  <req-ctx-map name="loginForm" type="LoginForm" />
  <req-ctx-map name="joinForm" type="JoinForm" />
  <req-ctx-map name="memberForm" type="MemberForm" />
  <req-ctx-map name="searchForm" type="SearchForm" />
  <req-ctx-map name="changePassForm" type="ChangePassForm" />
  <req-ctx-map name="messageForm" type="msg/MessageForm" />
</req-ctx-maps>

<req-ctx-map> element attributes (all required):

  • name – alias that is used by Command mappings.
  • typeRequestContext class name relative to WEB-INF/classes/forms folder.

For example, messageForm RequestContext mapping points to a class located here:

WEB-INF/classes/forms/msg/MessageForm.js

Defining Command mappings

The Command mappings control the flow of the application. They are simple to defined by <cmd-map> element within <cmd-maps> tag.


<cmd-maps>
  <cmd-map action="helloworld" validate="true">
    <name>helloForm</name>
    <type>HelloAction</type>
    <input redirect="false" path="/views/error.xsl" />
    <forwards>
      <forward name="action-error" redirect="false"
        path="/views/error.xsl" />
      <forward name="success" redirect="false"
        path="/views/hello.xsl" />
    </forwards>
  </cmd-map>
</cmd-maps>

<cmd-map> attributes:

  1. actionCommand name. Required. This is how get request might look like to be routed to this Command:
    http://your.server.com/troika.asp?cmd=helloworld
    
  2. validate – Determines whether we want execute validate() method on our RequestContext object (helloForm alias in this example). Optional, Default value “false”.

Element <name> is optional; if it is omitted we will have an empty RequestContext with only one property (action) set to name of the command. Also, the form validation will not be performed. Though, if you have validate="true" and define no <name> element an error will occur.

For example, if you have the following CommandMap declaration:



<cmd-maps>
  <cmd-map action="helloworld">
    <type>HelloAction</type>
    <forwards>
      <forward name="success" redirect="false"
        path="/views/hello.xsl" />
    </forwards>
  </cmd-map>
</cmd-maps>

And user submitted the request like that:

http://your.server.com/troika.asp?cmd=helloworld&visitorName=name1

In our Command execute() method we can still access value of visitorName through ASP request adapter (see RequestAdapter class) as the following code shows:


HelloAction.prototype.execute = function (environment, helloForm) {

  var result =  new ResponseContext(this.findForward(helloForm, "success"));

  var visitorName = environment.request.get(“visitorName”);

  Logger.log.info("Visitor name is: " + visitorName);

  return result;
};

If we had full definition including <name> element the equivalent code might look like this:



HelloAction.prototype.execute = function (environment, helloForm) {

  var result =  new ResponseContext(this.findForward(helloForm, "success"));

  Logger.log.info("Param1 value is: " + helloForm.visitorName);

  return result;
};

If the RequestContext alias (<name> element) is defined and validate="true" and if the validation fails <input> element will be used, typically to return user to the original form displaying validation error message.

<input> element attributes (all required):

  • redirect – Whether we would like to redirect browser to URI specified by path attribute. For instance, <input redirect="true" path="/validation_errors.html" />. If redirect set to “false” then AppController forwards the response to the URI.
  • path – URI where to forward the response.

Element <forward> nested within <forwards> element defines the name that the Forward will be referenced by and path request should be forwarded to.

<forward> element attributes (all required):

  • name – canonical name for the Forward so that it can be located by Command.
  • redirect - Whether we would like to redirect browser to URI specified by path attribute.
  • path – URI to forward response to – XSL stylesheet typically

In your Command class you can use the following code to locate predefined Forward:



var forward = this.findForward(helloForm, "success");

Or you can create Forward object from scratch:


var redirect = false;
var forward = new Forward(redirect, “/views/hello.xsl”);

Security constraints

TROIKA.ASP framework has declarative security configurable with config.xml.


<security-constraints>
  <constraint>
    <login-form-path>/troika.asp?cmd=login</login-form-path>
    <url-patterns>
      <url-pattern request-ctx-xpath="//action">
        <match-pattern>secretAction</match-pattern>
        <return-path>/troika.asp?cmd=secretAction</return-path>
      </url-pattern>
    </url-patterns>
    <authenticate>
      <role>admin</role>
      <role>guest</role>
    </authenticate>
  </constraint>
</security-constraints>

You can define as many security constraints as you need nested within <security-constraints> element.

Element <login-form-path> specifies the login form URL when authentication fails. By default all users are assigned guest user role. When a user enters valid username and password with the login form the session variable security.role will be set to actual user role. You can have a table in a database where you would map user to security role.

Element <url-pattern> defines what resource to protect. Attribute request-ctx-xpath sets xpath of RequestContext XML to search.

For example we have the following RequestContext:



function SecretForm(action) {

  if (arguments.length) {

    this.init(action);
  }

  this.secretInfo = null;
}

And the request will be something like this:

http://www.yourserver.com/troika.asp?cmd=secretAction&secretInfo=top%20secret

When the framework calls toXML() method on SecretForm the XML will look like this:



<requestCtx>
  <action>secretAction</action>
  <secretInfo>top secret</secretInfo>
</requestCtx>

We match the //action xpath which will give us secretAction string against <match-pattern> element. If there is a match then the framework checks to see if user’s security role is on the list of the all allowed roles, see <authenticate> element.

If not, the request will redirect to URL specified by <login-form-path>. If user successfully logs in, the framework returns to the URL specified by <return-path> element.

Search

FAQ

Bookmarks

AddThis Social Bookmark Button

Support This Project