Construction of an original aspect
Construction of an original aspect
Hifive aspects are objects with three attributes; target, interceptors and pointCut.
The basic structure is as follows.
target: {String | RegExp},
interceptors: {Function | Function[]},
pointCut: {String | RegExp}
};
Target and Pointcut
The target property defines which controller or logic the aspect will apply to. On the other hand, the pointcut property defines which methods the aspect will apply to.
- Target is compared to the __name property, which is a required property in the controller’s or logic’s constructor.
- Pointcut will be compared to method names, but only those of controllers / logic that first match the target property.
- The interceptor will only be applied when both the target and the pointcut match.
- Target and pointcut are not required parameters, if they are omitted it is taken to mean "All Controllers / Logic" and "All Methods" respectively.
You can define target and point-cut as a regular expression or a "character string".
Using Regular Expressions
The defined regular expression will be used to evaluate the target or pointcut as it is.
Using Character Strings
- By using the wild-card * you can match just parts of a string, i.e. a “string within a string”.
- Meta-characters (such as . or ^) have a special meaning in regular expressions and are automatically escaped, excepted for *.
- Regular expression evaluation is called implicitly (the passed value is converted to a regular expression like so : /^{your_strings}$/)
- For example, if we used "jp.co.nssol.sample.controller" as the target,
- then a controller with the __name property of "jp.co.nssol.sample.controller.TestController" would be matched
- but a controller with the __name property of "jp.co.nssol.sample2.controller.TestController" would not match.
Interceptor
You can define the desired processing in the interceptor
var interceptor = function(invocation) {};
Interceptors are defined as a function that will receive the argument invocation. Using this inside an interceptor will refer to the controller when the interceptor is applied to a controller, and the logic itself when applied to logic.
The method properties for invocation are as follows:
args
- The arguments passed to the original method are contained in args, it is of type Arguments.
funcName
- This contains the original method name
proceed
- Using this method you can call the next interceptor or the original method.
h5.u.createInterceptor
As interceptors are often used in fixed execution Hifive has a utility class called h5.u.createInterceptor.
- “pre” is the function that will be called before the original intercepted function begins.
- “post” is the function that will be called after the original intercepted function finishes.
- For more details please click here.
The following is an example of an interceptor that displays an alert before and after calling a function.
alert('before');
return invocation.proceed();
}, function(invocation, data) {
alert('after');
});
Usage
The aspect is defined as an h5.settings.aspects in the h5preinit events
var aspect = {
interceptors: function() { console.log('aspect execute.'); }
};
h5.settings.aspects = aspect;
});
The Order of Interceptor Operation
- The aspects, and the interceptors property of an aspect, can be ordered.
*For example, when defining an aspect in the following way:
var aspect1 = {
interceptors: [func1, func2]
};
var aspect2 = {
interceptors: func3
};
h5.settings.aspects = [aspect1, aspect2];
});
the resulting execution order will be :
func1 -> func2 -> func3 -> original method
As you can see, the execution order for the interceptor is the same as the order in which it was defined.
- Of course, the interceptor won't be called at all if the target and point-cut are not matched.
Example
Let's create the following sample application. The application has a button, and if the button is clicked the start and end of a logic method that is called 1,000,000 times through a loop is output to the console.
- HTML
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="-1">
<script src="jquery.js"></script>
<script src="ejs-1.0.h5mod.js"></script>
<script src="jquery.blockUI.js"></script>
<!-- For processing the hifive preinit event, h5preinit.js must be loaded before h5.js is loaded. –>
<script src="h5preinit.js"></script>
<!-- load the JS for each module -->
<script src="../../archives/current/h5.js"></script>
<!-- load the newly created JS file -->
<script src="step13-2.js"></script>
<title>Applying hifive Aspects</title>
</head>
<body>
<div class="browserNotification">
* Please use the most recent version of your browser <br>
In particular, Internet Explorer 7 & 8 may not function correctly.
</div>
<div id="container">
<input type="button" id="btn" value="click"/>
</div>
</body>
</html>
The HTML just contains an input button
- Aspects
var aspect = {
target: /^loop.*$/i,
interceptors: function(invocation) {
this.log.info(invocation.funcName + 'started');
invocation.proceed();
this.log.info(invocation.funcName + 'finished');
},
pointCut: 'lo*'
};
h5.settings.aspects = aspect;
});
Before and after each execution (invocation.proceed()) of the invocation the message will be output to the console. Target in this case is a regular expression. The meaning of this particular regular expression is “match any words starting with ‘loop’ regardless of case.
Point-cut is a string in this example. By using the wild-card * we can match just parts of the word. The meaning in this case is “Anything that starts with ‘lo’”
- Logic
__name: 'LoopLogic',
loop: function() {
for (var i = 0; 0 < 1000000; i++) {
if (i % 10000 === 0) h5.log.info(i);
}
}
};
The loop method loops one million times, outputting to the console on every 10000th iteration.
- Controller
__name: 'LoopController',
loopLogic: loopLogic,
'#btn click': function() {
this.loopLogic.loop();
}
};
h5.core.controller('#container', loopController);
Clicking on the button will call the LoopLogic#loop.