AJS_DefMgr

Introduction

As the AJS_DefMgr overview states, you do not need to know how this AspectJS component operates, as the AJS client-components handle all the details of working with their definition manager objects internally and automatically. Indeed, all you need to do in respect of AJS_DefMgr when using AJS_Validator, AJS_Logger or AJS_ODL is to pass to the corresponding factory-functions that create those clients a reference to the createAJS_DefMgr function. This means that, if you are using one of the AspectJS client-components, then you need read-on no further here, and you should turn your attention instead to the user and API documentation for the component in question.

However, AJS_DefMgr does not depend on any other elements of the AspectJS library, and you may have your own application of the AJS object in mind (or even something entirely unrelated to method-call interception), where your design cleaves to the same paradigm as the client components, and thus entails working with definition objects of your own specification. Given this, this page gives a brief guide to the use of AJS_DefMgr.

Contents Introduction
AJS_DefMgr Defined
Creating a Definition Manager
Definition Manager Methods
Method Arguments
Call-Back Arguments

AJS_DefMgr Defined

An AJS_DefMgr object is an 'operation-object manager', and can be viewed simply as an object that maintains a set of those object-methods to which some kind of 'operation object' has been applied, along with a set of operation objects that have yet to be applied. An AJS_DefMgr object knows nothing about the concept of method-call interception, and in the context of AJS_Validator, AJS_Logger or AJS_ODL, an 'operation object' is a definition object, or a ValidationDef, LogDef or LoadDef respectively.

An AJS_DefMgr object does not define what it means for a definition object to be 'applied' to a method owner (that issue falls within the remit of a given client component), nor does it define 'definition object', with the exception that a definition may possess an array property called MethodNames, which, if present, must contain a set of one or more method-name strings (see below).

Note that your applications may create as many AJS_DefMgr objects as you wish.


 // -- AJS_DefMgr Interface (pseudo code) ----------------------------------
 //
 //    See the API documentation for formal property-definitions.
 //

 var AJS_DefMgr       =
    {
    pushToPending     : function (MethodOwner, Def, MethodOwnerName,                   ClientMethodName, StackOffset) { ... },
    applyDef          : function (MethodOwner, Def, MethodOwnerName, applyDefToMethod, ClientMethodName, StackOffset) { ... },

    applyAllPending   : function (applyDefToMethod,                                    ClientMethodName, StackOffset) { ... },

    onDefUnapplied    : function (MethodOwner, MethodName, StackOffset)                                               { ... },

    forAllApplied     : function (action)                                                                             { ... },

    //-------------------------------------

    Version           : "1.0",
    AJS_Validator_Tag : "AJS_DefMgr"

    };
            

Creating a Definition Manager

To create an AJS_DefMgr object, call createAJS_DefMgr, passing:

  1. A human-readable string that identifies the client object that is using the manager in question.
  2. A human-readable string that describes type of definition object that the client will be passing to the manager.
  3. A reference to an exception-handler function that, when called, will respond appropriately by, say, throwing an exception on behalf of whatever calls it (thus affording the potential for call-stack analysis).

Example 1 demonstrates these points.

Note that the onException reference need refer only to a function that possesses the same signature that the throwException or throwException_Remote components that are bundled with the AspectJS distribution set, which means that you can use those resources or an equivalent function of your own design.

Note also that the MyClient and MyDefinitionType string-arguments in Example 1 are used solely in the generation of meaningful, human-readable exception notifications. To this end, AJS_Validator passes 'AJS_Validator', AJS_Logger objects pass 'AJS_Logger' and AJS_ODL passes 'AJS_ODL' as the value for the ClientName argument, and in the case of the DefType argument: AJS_Validator passes 'Validation', AJS_Logger objects pass 'Log', and AJS_ODL passes 'Load', to give 'ValidationDef', 'LogDef' and 'LoadDef' respectively in any exception messages (see below for more on this).


 <!-- Example 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->

 <html>
    <head>
       <script src = "AJS_DefMgr.js"    ></script>
       <script src = "ThrowException.js"></script>  <!-- Or ThrowException_Remote.js, or your own exception   -->
                                                                <!-- handler. Note that ThrowException_Remote.js requires -->
                                                                <!-- ThrowException.js                                    -->
       <script>

       "use strict";

       var MyDefMgr = createAJS_DefMgr ("MyClient", "MyDefinitionType", throwException);


       // Other code that uses MyDefMgr hereon.


       </script>

    </head>

    <body> ... </body>

 </html>
            

Definition Manager Methods

AJS_DefMgr objects support five methods, descriptions of which are given in the table. They expect nothing of a given definition object, so the properties those objects possess fall entirely within the remit of whatever client object is using the definition manager in question. This is with the exception of any MethodNames property that the definition carries, which is optional, but, if present, must be an array that carries at least one string-object or string-literal.

Method-Name DescriptionReturns
pushToPending Accepts an object reference and a definition object (along with other arguments), and pushes the definition to the pending-definitions queue. undefined
applyDef Accepts an object reference and a definition object, along with a user-defined function-reference argument in the fourth place. If the definition carries a MethodNames property, applyDef iterates through that array, checking that each member corresponds to a function-property of the MethodOwner, and calling the function that was passed as the fourth argument (applyDefToMethod). That function's signature is discussed in the main text. If the definition does not carry a MethodNames property, applyDef iterates through all methods in the target object, calling the function-reference for each. An array containing the objects that were returned from calling the applyDefToMethod function for a given method-name.
applyAllPending Accepts a function reference that plays the same role as that passed as the third argument to applyDef, and removes each definition from the pending-definitions queue (on a first-in first-out basis), calling the function passed as the first argument for each (after performing the same checks as applyDef). In, essence, this method is an iterative user of applyDef. The number of definition objects that were applied.
forAllApplied Accepts a single user-defined function-reference argument, and iterates through the list of applied definitions, calling that function for each definition, passing it the definition object in question. It is this method that underlies AJS_Validator's and AJS_Logger's suspend and resume functionality. undefined
onDefUnapplied Accepts a MethodOwner object-reference and a MethodName string as the first two arguments, and removes the corresponding object from the applied-definitions queue. Throws an exception if no corresponding object can be located for the MethodOwner/MethodName arguments provided, which means that the MethodOwner/MethodName combination in question is incorrect. undefined

Method Arguments

The arguments that the DefMgr methods accept are given in the API documentation, and their meaning is described in the table. All arguments are mandatory.

Note that some of the arguments are used solely in the construction of verbose and meaningful exception notifications. That is to say: when AJS_Validator creates its definition-manager object, it passes 'AJS_Validator' and 'Validation' as the ClientName and DefType arguments respectively, and when it calls its definition manager's pushToPending method it passes 'pushValidationDef' as the ClientMethodName argument. In line with this, and where an object called 'MyObj' possesses a method called 'someMethod', to which a ValidationDef must be applied, it will pass to pushToPending 'MyObj' and 'someMethod' as the MethodOwnerName and MethodName arguments respectively.

If MyObj.someMethod is already subject to a ValidationDef, the definition manager will generate an exception notification that (when its name and message properties are concatenated, along with a colon) yields the following message, where the values given above for the various arguments are rendered in italics:

   AJS_Validator_Exception: cannot accept the ValidationDef passed to
   AJS_Validator.pushValidationDef, because a ValidationDef that covers
   MyObj.someMethod is waiting in the pending-ValidationDefs
   queue.

....Which goes a long way towards diagnosing a problem.

Name Class Description
action Function reference Called by forAllApplied, and is passed a Definition Control object. Should perform a user-defined action for each DefCtrl object it receives.
applyDefToMethod Function reference Called by applyDef and applyAllPending, and is passed the MethodOwner, MethodName and MethodOwnerName arguments that those methods received, along with a reference to the definition object in question, and a correctly-adjusted StackOffset.
ClientMethodName String-Literal/String Used in exception notifications, and describes the method of the definition manager's client. For example, AJS_Validator.applyValidationDef passes "AJS_Validator.applyValidationDef", whereas applyValidationDefQueue passes "AJS_Validator.pushValidationDef previously".
Def Object reference Refers to a definition object that should be pushed or applied.
MethodName String-Literal/String
MethodOwner Object reference The object to which the definition in question should be applied
MethodOwnerName String-Literal/String Used in exception notifications...
StackOffset Non-negative integer Used in exception notifications. Operates in the same way as the StackOffset arguments passed to Pre-/Post-Validators in the context of AJS_Validator (and in the context of the ancillary methods that that object supports).

Call-Back Arguments

When calling applyDef, applyAllPending, and forAllApplied, your code must pass a call-back function, along with any other arguments that are required. In the case of applyDef and applyAllPending, this function, which is denoted by applyDefToMethod in the API documentation, must possess the same calling signature, which looks like this:

   function (MethodOwner, MethodName, MethodOwnerName, Def, StackOffset) { }

The arguments for which are as follows:

  1. MethodOwner – an object reference (the one supplied in a call to applyDef or applyAllPending), indicating the owner of the method to which the definition must be applied.
  2. MethodName – the name of the function-property possessed by the MethodOwner to which the definition must be applied.
  3. MethodOwnerName – the same string-argument passed in calls to applyDef or applyAllPending. This is passed in order to enable the call-back to construct meaningful exception-notifications.
  4. Def – a reference to the definition object to be applied.
  5. StackOffset – a non-negative integer, which plays exactly the same role as all other StackOffset arguments in the AspectJS library.

In the case of the AspectJS client-components, AJS_Validator, AJS_Logger and AJS_ODL all use the MethodOwner/MethodName arguments to apply affixes to the method in question, and return the corresponding Affix- or Wrapper-Ctrl that was generated (those affix functions operate subsequently in accordance with the nature of the corresponding definition-object). However, if you have a use for definition-manager objects in a design of your own, the way you use those arguments, and the value that your call-back returns, is entirely up to you.

In the case of forAllApplied, the call-back that that method accepts must take the following form:

   function (CtrlObj) { ... }

Where CtrlObj is the value that was returned by the applyDefToMethod call-back, as described above. Given that your implementation of an applyDefToMethod call-back may return anything you desire, it follows that your implementation of the forAllApplied call-back can do what it likes with the CtrlObj argument that it receives. Note that forAllApplied ignores any return value from the call-back function it invokes.