my problem was, as more and more ZTL contributions were created by me - I had a feeling this is a kind of blind editing, recompilation, restart and trying to imagine what was wrong.. then I was searching for a way how to analyze and inspect the parameters in the scripts to see what are the current values at least.
Here the outputs...
First, you have to install the Design Studio SDK: BIAL and ZTL Debugger Code Inspector Tool.
Then, we have to understand what we can inspect at the point of time when we have the context.
Global Variables
As the code runs in Rhino engine, there is a global context which can be read and inspected. by this you can see at any point what are values of global variables.
Owner Properties
All properties of the component are accessible on "this" object, therefor a loop on it will give you the values. In this area small extension is done, when the property starts with "[" or "{" I assume (hopefully positive) that it is a JSON string and try to parse as JSON.
Local Variables
This is a bit tricky topic, but after some search in google I could fins an acceptable workaround which allows parsing of local defined variables. For this, the ZTL script notation of your component needs to be adjusted a bit.
Instead:
var myVariable = "some text here";
You need following:
var l = {}; // define a local JSON object, I use the small L letter -> "l" to have quick access.
l.myVariable = "some text here"; // now all local variables must be bound to the "l" object
And, finally the methods on the debugger component allow passing of this "l" object, which can be dynamically parsed.
Important
You need to place the DEBUGGER component in the application, then you can give it any name which you want (default is DEBUGGER_1) - BUT...
the component name must be used also in your ZTL script
Why? I use the fact that ZTL can call other components if you know the name, like:
APPLICATION.createWarningMessage("- your message here -");
So, name "DEBUG" must be used as component name in my example below.
Example:
- Name: DEBUG
- line in ZTL: if(this.isDebug()) { DEBUG.openZtl(that, l)};
Which methods can be used?
There are few methods to allow the inspection:
How to write your ZTL script?
Based on the facts above, I have prepared following method statement:
void mySomeZtlMethod(String mySomeInput) {*
/* entering general block*/
var that = this;
var l = {}; // define before try to have the values in exception case
try{
l._firstProperty = mySomeInput;
if(this.isDebug()) { DEBUG.openZtl(that, l)}; // in this case the component name is "DEBUG" and the method checks this
/* entering general block*/
// your code....
l.localValue = "NO";
if(this.isDebug()) { DEBUG.inspectZtl(that, l)};
// your another code....
/* exiting general block*/
if(this.isDebug()) { DEBUG.exitZtl(that, l)};
} catch (e) {
if(this.isDebug()) { DEBUG.processZtlException(that, l, e)};throw e;
}
/* exiting general block*/
*}
with this part, you can inspect your input parameters, you can define some local parameters and all those will be printed out. In addition, when exception will occur all information will be logged.
Explanation to Snippets Above
in the "entering block"
in between, you can place as many inspects as you want ... but, as the debugger is printing the content out, placements in loops is not best idea - you can get timeouts on execution as there is some maximal processing time in ZTL (5 secs or so), perhaps you can place there something like:
if(this.isDebug("DEBUG_LOOP")) { DEBUG_LOOP.inspectZtl(that, l)};
and then place second DEBUGGER component in the application with DEBUG_LOOP. Then you can activate this only if really required.
in the "closing block"
Required extension in the component (isDebug() method)
My initial thought with simple check "if(DEBUG)" is not working as the Rhino is throwing exception at the access, therefore I had to rewrite this part. First, two methods are used:
/**
* DO NOT USE, ONLY FOR DEBUG ACTIVATION
*/
@Visibility(private)
boolean isDebug(optional String componentName) {*
// quick check here
if(componentName == undefined) {
if(this._dbgDEBUG == "+") { return true; }
if(this._dbgDEBUG == "-") { return false; }
componentName = "DEBUG";
} else {
if(this["_dbg" + componentName] == "+") { return true; }
if(this["_dbg" + componentName] == "-") { return false; }
}
internal_assureGlobalAccess ();
var something = this.getGlobal()[componentName];
if(something != undefined) {
this["_dbg" + componentName] == "+";
return true;
} else {
this["_dbg" + componentName] == "-";
return false;
}
*}
/**
* Internal function to read return global scope
*/
@Visibility(private)
void internal_assureGlobalAccess () {*
if(this.getGlobal == undefined) {
this.getGlobal = function () {
return (function() {
return this;
}).call(null);
}
}
*}
The idea is here to keep always the statements in code, but check once if the component is exisiting and then cache the information in the component.
you can copy those 2 methods to your component if you do not want to uncomment the DEBUG statements - or you can just use your own local propery.
Example
Some example has been made in the FacetFilter component, you can check up the internal ZTL methods, eg this one:
void reloadDataSource(/*Data Source which should be used for member selection, in case not the linked Data Source*/optional DataSourceAlias memberAccessSource) {*
/* entering general block*/
var that = this;
try{
if(this.isDebug()) { DEBUG.openZtl(that)};
var l = {};
/* entering general block*/
l.elementsJson = [];
l.DS = this.getDataSource();
if(!memberAccessSource) {
memberAccessSource = l.DS;
}
if(l.DS) {
l.dimensions = undefined;
if(this.DContentMode == "Only from Result Set") {
l.dimensionsRows = DS.getDimensions(Axis.ROWS);
l.dimensionsColumns = DS.getDimensions(Axis.COLUMNS);
l.dimensions = [];
l.dimensionsRows.forEach(function(dimension, indexD) {
l.dimensions.push(dimension);
});
l.dimensionsColumns.forEach(function(dimension, indexD) {
l.dimensions.push(dimension);
});
} else {
l.dimensions = DS.getDimensions();
}
if(this.isDebug()) { DEBUG.inspectZtl(that, l)};
l.dimensionKeys = "";
l.dimensions.forEach(function(dimension, index) {
l.dimensionKeys = l.dimensionKeys + dimension.name;
});
if(this.oldDimensionKeys != l.dimensionKeys) {
l.dimensions.forEach(function(dimension, index) {
l.members = memberAccessSource.getMembers(dimension, that.getMaxMembers());
l.dimensionJson = {};
l.dimensionJson.name = dimension.name;
l.dimensionJson.text = dimension.text;
l.dimensionJson.isMeasuresDimension = dimension.isMeasuresDimension;
l.dimensionJson.hierarchyActive = DS.isHierarchyActive(dimension);
l.dimensionJson.filterExt = ";" + DS.getFilterExt(dimension);
l.dimensionJson.members = l.members;
l.elementsJson.push(l.dimensionJson);
});
this.DElements = JSON.stringify(l.elementsJson);
this.oldDimensionKeys = l.dimensionKeys;
if(this.isDebug()) { DEBUG.inspectZtl(that, l)};
}
}
/* exiting general block*/
if(this.isDebug()) { DEBUG.exitZtl(that, l)};
} catch (e) {
if(this.isDebug()) { DEBUG.processZtlException(that, l, e)};throw e;
}
/* exiting general block*/
*}
Print Out
In the stack view, you can see always the method and line number, like this:
The first question was "how to count the line number?"
Obviously, the Rhino engine is counting the method declaration as first line and then also empty lines are counted. But you should be able to quickly find the inspected line.
Variables
The variables re printed out with properties, like here:
and as the properties can be "big" I have also created a field below to see the content - which is again re-escaping JSON strings (very primitive and not performant way, but it works!), so you can see complex properties like here:
and use ti for copy and paste and formatting via URL http://jsonformatter.curiousconcept.com/
Work in Real Applications
As the component has a flag "active" and the code is checking on existence via IF:
if(this.isDebug()) { DEBUG.exitZtl(that, l)};
or
if(this.isDebug("DEBUG_CUSTOM")) { DEBUG_CUSTOM.exitZtl(that, l)};
you can easily leave such statements in the ZTL code, those will be only executed when the component "DEBUG" is in application, and also then you can always switch it ON / OFF to assure there is no performance impact.
Closing Words
Hope this will be helpful for many of you in the coding area. Also for users coding only in BIAL scrips, the method "inspectNow" should bring some lights into the context.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
33 | |
25 | |
10 | |
7 | |
7 | |
7 | |
6 | |
6 | |
5 | |
4 |