code


Background Primer:

Logging. As developers we all need to do this, especially for deployments where it’s entirely unreasonable to ask our end clients to use / maintain / notify us of crash events, and even if they did it gives us a needle’s-eye view of the problem. So while interim development usually starts off with good ole trace it’s potential for releasing sensitive data into the stream is greatly amplified by either the type of application you are writing and it’s complexity. Just having a debugger running, we’ve all seen every one else’s trace statements.

Security:

So AIR helps take the LogLogger from the SDK and gives us the potential to write log files, typically in the application storage area. While this can and does help the alpha and beta stages of release to end-clients it significantly increases their exposure of sensitive data because now you are writing it in area where only the user needs privilege – not admin.

The Better Approach:

Because we want to use the ILogger interface along with standard LogEvents (because Targets use these), the LogLogger is easy enough to re-write. With each message being ultimately broadcast in the event – this is the most appropriate domain to intercept, scramble, and resend. I started with each defined interface method and before each dispatch, a new method is used to build/construct the message. With the help of an implementation of a secure logger (composition goes a long way to help swap parts out instead of inheritance), this class is tasked with doing the actual work of rewriting or removing selected properties from objects we need to keep secure.

The Implementation:

The key with the build method is not only to introspect top level objects as part the …rest parameters, but also to see if anything is an array and to iterate that list to make sure the class type is or isn’t the type that needs to be secured. Any object which needs to be secured is then sent through the secure logger, otherwise a straight obj.toString() is used.

 

LogLogger

public class LogLogger extends EventDispatcher implements ILogger
{

private var _secureLogger:SecureLogger;
private var _category:String;
private var resourceManager:IResourceManager = ResourceManager.getInstance();

public function LogLogger(category:String)
{
super();
_category = category;
}

public function get category():String { return _category; }

public function log(level:int, msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, level));
}

public function debug(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.DEBUG));
}

public function error(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.ERROR));
}

public function fatal(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.FATAL));
}

public function info(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.INFO));
}

public function warn(msg:String, … rest):void
{
if (!hasEventListener(LogEvent.LOG)) return;
msg = build(msg, rest);
dispatchEvent(new LogEvent(msg, LogEventLevel.WARN));
}

private function get secureLogger():SecureLogger { return _secureLogger ||= new SecureLogger(); }

private function build(msg:String, params:Array):String
{
var repl:String =”;
for (var i:int = 0; i < params.length; i++)
{
var obj:Object = params[i];
if (!obj) repl = ‘null’;
else if (secureLogger.hasReplacementRule(obj))
{
if (obj is Array)
{
var n:int = (obj as Array).length;
for (var j:int = 0; j < n; j++)
{
var child:Object = obj[j];
repl += secureLogger.getReplacement(child);
}
}
else repl = secureLogger.getReplacement(obj);
}
else repl = obj.toString();

msg = msg.replace(new RegExp(“\\{“+i+”\\}”, “g”), repl);
}
return msg;
}
}

SecureLogger

public class SecureLogger
{
public function SecureLogger()  { super(); }

public function hasReplacementRule(obj:Object):Boolean
{
if (validateReplacementRule(obj)) return true;
if (obj is Array)
{
for each (var child:Object in obj)
{
if (validateReplacementRule(child)) return true;
}
}
return false;
}

private function validateReplacementRule(obj:Object):Boolean
{
if (obj is Account) return true;
if (obj is LoginCredentials) return true;
return false;
}

public function getReplacement(obj:Object):String
{
var str:String;
if (obj is Account) str = secureAccount(Account(obj));
else if (obj is LoginCredentials) str = ‘[LoginCredentials]‘;
else str = obj.toString(); return str;
}

//An example of using regex to re-write sensitive data
//Since it’s working with direct string manipulation, it must know about it’s format
private function secureAccount(obj:Account):String
{
var str:String = obj.toString();
str = str.replace(/number=\d+/, ‘number=’+ obj.id +’ ‘);
str = str.replace(/name=.*?(?=type)/, ‘name=Account ‘+ obj.id +’ ‘);
str = str.replace(/institutionName=.*?(?=institutionWebsite)/, ‘institutionName= Institution ‘+ obj.id +’ ‘);
str = str.replace(/institutionWebsite=.*?(?=status)/, ‘institutionWebsite= ‘); return str;
}

}

The entire OLAP package in Flex has sparse API documentation, but there are several ‘how-to’ examples out in the land of live-docs. This usually doesn’t bode well, because it generally means a tech-writer never talked to the development team to figure out what all the dependencies are on the various properties. We have the source, but chasing it down ourselves sucks.

 

A precursor into what doesn’t work:

  • OLAPAttribute.displayName does NOT work on subsequent dimensions. It will only work on your first dimension which is usually the ROW_AXIS. However, the OLAPLevel.attributeName will always expect to look up the OLAPAttribute.name.
  • The allMemberName even though it’s defined on the OLAPHierarchy, it must be actually set on an OLAPAttribute which is displayed for that dimension.

Now onto the real problem:

Generally to sort your cube, you do a 2-dimensional sort to the original flat dataprovider then assign this to the cube dataprovider.  And in most cases this seems to work OK, until your CATEGORY_AXIS is based on anything to do with Time (which is a lot of the time actually). In most cases you’ll have a two-tier hierarchy of year and month / quarter, but the problem appears to be most prevalent with months. Even though your original source is sorted correctly, some months will be placed out of order, especially if you’re using the allMember level which it builds on the fly in the query.

The Fix:

So the fix involves re-arranging the member IList in building the OLAPQuery to the appropriate OLAPSet. In addition to fixing the sort issue, now is the time to re-arrange the allMember level to where it seems logical for your application. Accounting applications generally read left-to-right, so summary total’s are generally shown on the right hand side.

The way know if you’re working with the allMember level that it created for you in the sort method, is to look for the OLAPMember.hierarchy.allMemberName and compare that to the current OLAPMember.name

The way to correctly resort months involves a bit of kludgery but I haven’t found a more elegant way around it. In the OLAPAttribute for the dimension you specify the dataField to the integer of the month (generally this is string from a formatter), and assign a displayNameFunction to use a DateFormatter to turn this into something meaningful at the UI level. Even though the name of the OLAPMember is a string, it’s actually a string cast of the original value to the dataField (hence the actual integer value). You can then re-cast this back to an int to do a numeric sort (so you don’t end up with 0, 1, 10, 11, 2, 3, etc).

Now you might think an easier way to do this is to just use a SortField, however since you’re original Object is transformed to a flash_proxy and lost in the process relative to the OLAPGrid, the internal numeric sort method to Sort will throw an error that it can’t find the property that you originally wanted to sort on (eg month).

This should get your columns back in the order in which they were meant to be in.

private function getQuery(cube:IOLAPCube):IOLAPQuery
{
… //Setup the rest of the dimensions / sets to associate to the correct axis

var list:ArrayCollection = cube.findDimension(“timeDimension”).findAttribute(“Month”).members as ArrayCollection;
list.sort = new Sort();
list.sort.compareFunction = compareSortMonth;
list.refresh();

var moSet:OLAPSet = new OLAPSet();
moSet.addElements(list);

private function compareSortMonth(a:OLAPMember, b:OLAPMember, fields:Array = null):int
{
if (a.name == a.hierarchy.allMemberName) return 1;
else if (b.name == b.hierarchy.allMemberName) return -1;

var aMonth:int = parseInt(a.name);
var bMonth:int = parseInt(b.name);

if (aMonth < bMonth) return -1;
else if (bMonth < aMonth) return 1;
else return 0;
}

In some instances when JSON is the only available communication protocol, we all know full well about it’s limitations especially when it comes to preserving type or saving state. But what if you were in a closed-loop system where you could simply save what the front-end end would send? In a Flex environment this is still somewhat trivial since you can still use the [RemoteClass] metatag even without an RPC-based mediary like LCDS.

In Flex 4.5 using the Adobe extension to JSON the following will work. In 4.6+ it gets a little harder since the JSON class is now a top-level object – which makes overriding private / modifying protected and/or static methods nearly impossible.

Modifying the encoder entails when encountering complex types that are not just anonymous Objects, if that’s the case then we can prefix the fully qualified class name before the bracket, and do the reverse in the decoder.

package
{

import JSONPlusEncoder;
import JSONPlusDecoder;

public class JSONPlus
{

public static const FQCN_IDENTIFIER:String = ‘fqcn’;

public static function encode(o:Object):String
{
return new JSONPlusEncoder(o).getString();
}

public static function decode(o:String, strict:Boolean = true):*
{
return new JSONPlusDecoder(o, strict).getValue();
}

}
}

 

package
{
import JSONPlus;
import com.adobe.serialization.json.JSONEncoder;
import flash.utils.getQualifiedClassName;
import flash.utils.describeType;

/**
* Note this implementation depends on monkey patching Adobe’s
* implementation (changing access type to protected)
* – big surprise – yet again a public facing
* API riddled with private methods.
* I wish they would learn to use protected.
*
*/
public class JSONPlusEncoder extends JSONEncoder
{

public function JSONPlusEncoder(value:*)
{
super(value);
}

override protected function objectToString(o:Object):String
{
var classInfo:XML = describeType( o );
if ( classInfo.@name.toString() == “Object” ) return super.objectToString(o);

//strip off the last bracket and insert the fully quallfied class name
var str:String = super.objectToString(o);
str = str.substring(0, str.length – 1);
str += ‘,”‘+ JSONPlus.FQCN_IDENTIFIER +’”:”‘+ getQualifiedClassName(o) +’”}’;

return str;
}
}
}

 

package
{
import JSONPlus;
import JSONDecoder;

import flash.utils.getDefinitionByName;

/**
* Note this implementation depends on monkey patching Adobe’s
* implementation – big surprise – yet again a public facing
* API riddled with private methods.
* I wish they would learn to use protected.
*
*/
public class JSONPlusDecoder extends JSONDecoder
{
private static var map:Object = {};

public function JSONPlusDecoder(value:String, strict:Boolean)
{
super(value, strict);
}

override protected function parseObject():Object
{
var o:Object = super.parseObject();
if (!o.hasOwnProperty(‘fqcn’)) return o;

var className:String = o.fqcn;
var cls:Class = getDefinitionByName(o.fqcn) as Class;

var instance:* = new cls();
for (var key:String in o)
{
if (key !=JSONPlus.FQCN_IDENTIFIER) instance[key] = o[key];
}
return instance;
}
}
}

As Flex Architects / Team Leads can attest (at least those of us who do the proper preparation for a project), choosing an architecture to base your code upon isn’t an easy task since many good ones are out there, however each is like a relationship that leaves just a little off the table to be truly a desirable solution. However as with any framework worth it’s work, most of them are highly extensible without the need to modify the original to achieve the characteristics you need / want.

RobotLegs: Mediating sub-content to a Spark NavigatorContent pane.
Turns out there is a ‘bug’ and/or limitation when using the spark-based layout framework, and thankfully it’s a relatively easy one to over come. It has to do with the <s:NavigatorContent /> and how those children are built according to it’s creationPolicy as set by an appropriate container (TabNavigator, Accordion, and so on). Because the mediator is triggered on the FlexEvent.CREATION_COMPLETE event, it doesn’t take into consideration that while additional containers will be put on the stage, their containing children will not be instantiated since it’s part of the deferred process. This leaves the mediator in ‘limbo’ land since we obviously want to setup the user gestures for all the guts of the container (combos, buttons, data grids, etc). (more…)

The problem domain: An issue exists where in a modular application you want to be able to share events from different modules without creating a dependency between the two. Deeply nested objects make this even more apparent when you realize you can’t use bubbling since they don’t reside within the same branch line down to the root trunk.

(more…)

I’m putting this out there as a give back to other Flash-Flex developers that want to use Joomla! as a data repository for any projects, in part because Rune Skjoldborg Madsen has taken the time to build specific component views in php to change the transport layer to XML.

(more…)

Sometimes you start on a project, and get far enough into it, that it just seems like it shouldn’t be that hard. For me, this was precisely the case with recreating a child past-time favorite game of mine: Elevator Action. This started off in Flash 7, and the reasoning behind it at the time was to create a complex environment scroller and to release the source for other developers to see how things like this are programmed. Getting bogged down by work, and generally life itself, not to mention the frustrating limitations of AS2 at the time; I put it down for awhile thinking I’d get back to it.

Well, Flash 9 is now here and it’s probably been 2 years or so since I last touched this (like dogs, it’s at least 14+ programming years). AS3 has finally brought us more into line with what the rest of the OOP world expects with new initializers, additional accessors and the such, but this now means I’m faced with the same problem everyone else has in revisiting old projects: Do I try to monkey patch the old code, or start over? (more…)

Using XML-RPC as the data gateway:

WordPress as of 2.2 already offers xml-rpc based access, so this cuts down the amount of outside code you need to write, however for anyone who has gone digging through the php will notice that while they include several different API’s, there is some key functionality that is missing in order to really take advantage of Flex – Flash based RIA solutions. (more…)

Generating Runtime Revision Control Between Dependent Applications

If there is one general weakness with the Flash Player technology as a whole, it is that it does not have very good capabilities, much less the tools, to detect runtime collisions: intentional or otherwise.

While this kind of problem is probably more rare than it is common, there is one issue that greatly increases the likelihood of encountering this problem: multi-packaged .swf files to a given project, and rises to the ranks of practically a given especially if any of those files use any of the same classes.

(more…)

With just about every SDK in a programming language there are some components while useful just get lost and squirreled away and never really get the glorified attention it deserves. The Repeater element is one of those in the Flex language, where of all the examples I see from other bloggers and the Flex community at large it just never shows up. This is an attempt to bring this little cockroach into the light to show off its skills and why it’s survived all this time.
(more…)