Posts Tagged flex

Flex 4 ModuleManager & CSS Inheriting Styles

A client I’m working with has a Flex 3.5 app that’s being migrated to 4.5 and one of the immediate issues we ran into (after we got it compiling successfully) was that the modules didn’t inherit the styles from the main app…worked fine in 3.5, but not in 4.5, so what gives?

So I created a simple PoC with a ModuleLoader and it did indeed pick up on the main apps styles as expected. Next I changed my PoC to resemble the client’s architecture a bit more and used a ModuleManager to load the module — low and behold, the module didn’t inherit the main app’s styles.

After some reading on Adobe’s docs I found the following as the key fix:

Using the ModuleManager class to load modules

You can use the ModuleManager class to load the module. This technique is less abstract than using the tag, but it does provide you with greater control over how and when the module is loaded.

To use the ModuleManager to load a module in ActionScript:

  1. Get a reference to the module’s IModuleInfo interface by using the ModuleManager getModule() method.
  2. Call the interface’s load() method.
  3. The application that loads the module should pass in its moduleFactory property. This lets the module know who its parent style manager is. When using the load() method, you can specify the application’s moduleFactory with the fourth parameter, as the following example shows:

    info.load(null, null, null, moduleFactory);
  4. Use the factory property of the interface to call the create() method and cast the return value as the module’s class. If you are adding the module to a container, you can cast the return value as an IVisualElement (for Spark containers) or a DisplayObject (for MX containers) so that they can be added to the display list.

So the key is passing in a reference to the moduleFactory when calling the ModuleManager.load() method. The 4th parameter is the moduleManager. If you don’t have a reference the main app lying around, just use:

info.load(null, null, null, FlexGlobals.topLevelApplication.moduleFactory);

Link to Adobe’s Docs on this.

Post to Twitter Tweet This Post

, , , , , ,

3 Comments

Swiz EventHandler Filtering With Pub/Sub Topics - Part 1

We tend to build many Flex applications with modules, so having the ability to broadcast and listen for messages based on the scope attribute for both Dispatchers and EventHandlers is essential in Swiz.

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

If you don’t know about Swiz Event Scoping, then read on; otherwise, skip to the section labeled Filtering With Topics below.

Background

You can read the actual documentation from Swiz in the last link, but the gist is that you can tell Swiz to either broadcast events on a “global” level (using the highest level Application object) or on a “local” level (using the Module itself) and then listen to those events in the same fashion. This allows you to tell modules to listen to events only from themselves and not other modules (that might have the same events) or to listen to all events from your main, shell application and/or all other modules. Let’s look at a quick example by assuming the dispatching code is in LoginViewMediator and the handling code is in LoginController in a Module.

Local Event Dispatching

Local Event Dispatching From LoginViewMediator

/**
 * Allows this class to dispatch local events. Only methods using an
 * EventHandler metatadata tag with the property of scope="local" can
 * handle this event.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="local")]
public var localDispatcher:IEventDispatcher;
...
public function login(userName:String, password:String):void
{
	logger.debug("login");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SERVICE_LOGIN);
	appEvt.username = userName;
	appEvt.password = password;
	this.localDispatcher.dispatchEvent(appEvt);
}

Local Event Handling in LoginController

[EventHandler(event="AppEvent.SERVICE_LOGIN", properties="username, password", scope="local")]
public function login(username:String, password:String):void
{
	logger.debug("login: username = " + username + ", password = " + password);
}

If we had other Modules with this same EventHandler statement in their LoginController they would not fire because we specified the scope as local. If we change the scope property to global and the AppEvent is in a common library that all Modules can use, then they would each hear this event and all fire, which in many cases is not what you want. Just so we have a full understanding of what’s going on, let’s show an example of broadcasting global events in a similar fashion:

Global Event Dispatching

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function hello(hello:String):void
{
	logger.debug("hello = " + hello);
}

Filtering With Topics

Again, this is awesome…but what if you want to broadcast a message that you only want some of the modules to hear? You could obviously put in some simple logic in the event handler that determines if your Module was supposed to listen to the event based on a parameter passed in the EventHandler MetaData, but this could potentially become a large and unwieldy task that you’ll need to apply to all new modules…so what if we introduce filtering of Swiz events via a topic attribute in the EventHandler metadata and a corresponding topic property in our dispatched event?

To do this, we’ll need to do some quick monkey patching to Swiz (by creating the same package structure and adding the same classes we want to change that exist in the Swiz SWC). First, let’s add the topic property to the org.swizframework.metadata.EventHandlerMetadataTag. Add the topic property:

protected var _topic:String;
public function get topic():String
{
	return _topic;
}

Then add the following to the method override public function copyFrom( metadataTag:IMetadataTag ):void

if( hasArg( "topic" ) )
    _topic = getArg( "topic" ).value;

Next we’ll edit the method public function handleEvent( event:Event ):void in org.swizframework.utils.event.EventHandler. Add the following right after the first if() statement:

// look for a topic -- if the one exists in the EventHandler MeataData and
// the event does not have one or the value does not equal the EventHandler's
// then we'll filter out this event and not allow it
if(metadataTag.topic != null)
{
	if(event["topic"] == null)
	{
		return;
	}
	else if(event["topic"] != metadataTag.topic)
	{
		return;
	}
}

That’s it. Let’s give it a whirl by using a global dispatcher again, but adding a topic property to the event and a topic attribute to the EventHandler metadata.

Global Event Dispatching From ModuleA

/**
 * Allows this class to dispatch global events. Only methods using an
 * EventHandler metatadata tag with the property of scope="global" can
 * handle this event. This means other modules and even the shell application
 * can handle this event if we want.
 *
 * <p>
 * The event dispatcher is injected by Swiz due to the [Dispatcher] metadata
 * and the class member's type of IEventDispatcher.
 * </p>
 */
[Dispatcher(scope="global")]
public var globalDispatcher:IEventDispatcher;
...
public function sayHello():void
{
	logger.debug("sayHello");

	var appEvt:AppEvent;

	appEvt = new AppEvent(AppEvent.SAY_HELLO);
	appEvt.hello = "Hello World!";
        appEvt.topic = "wasiTopic";
	this.globalDispatcher.dispatchEvent(appEvt);
}

Global Event Handling in Module B

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="wasiTopic")]
public function helloWithTopic(hello:String):void
{
	logger.debug("hello = " + hello); // WORKS
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

[EventHandler(event="AppEvent.SAY_HELLO", properties="hello", scope="global", topic="fooTopic")]
public function helloWithOutTopic(hello:String):void
{
	logger.debug("hello = " + hello); // NOPE
}

UPDATE: Part 2 has Swiz framework code changes and a more robust solution.

Post to Twitter Tweet This Post

, , , , ,

1 Comment

Flex & ActionScript Regex List

I’m not great with regex since I don’t use it a ton so I constantly find myself looking up simple, reusable regex statements…thought I’d just start listing them as I use them in case someone else finds them useful. This will start with just a couple examples that we’ll continue to add to.

Assume the following vars:

var myString:String;
var pattern:RegExp;
var resultString:String;
var isSuccess:Boolean;

Remove All Spaces

myString = "The quick brown fox.";
pattern = /\s+/g;
resultString = myString.replace(pattern, "");
trace(resultString); // Thequickbrownfox.

Remove Special Characters & Spaces

myString = "The 123 quick 456 brown !@#$% fox.";
pattern = /\W/g;
resultString = myString.replace(pattern, "");
trace(resultString); // The123quick456brownfox

Remove Special Characters & Numbers & Spaces

myString = "The 123 quick 456 brown !@#$% fox.";
pattern = /[^a-zA-Z]+/g;
resultString = myString.replace(pattern, "");
trace(resultString); // Thequickbrownfox

Test URL String

myString = "http://yahoo.com";
pattern = /^http(s)?:\/\/((\d+\.\d+\.\d+\.\d+)|(([\w-]+\.)+([a-z,A-Z][\w-]*)))(:[1-9][0-9]*)?(\/([\w-.\/:%+@&=]+[\w- .\/?:%+@&=]*)?)?(#(.*))?$/i;
isSuccess = pattern.test(myString);
trace(isSuccess); // true
myString = "htt://yahoo.com";
isSuccess = pattern.test(myString);
trace(isSuccess); // false

Trim String (With Tabs & Returns): Courtesy of Jeff Channel

myString = myString = "The quick brown fox.                   		";
pattern = /^\s+|\s+$/gs;
resultString = myString.replace(pattern, "");
trace(resultString); // "The quick brown fox."

Post to Twitter Tweet This Post

, , ,

4 Comments

WASI AIR Logging Console v0.1.3.0 & Logging Util Tools UPDATE

Introduction

While there are several updates and changes I made to the underlying implementation, the overall functionality remains the same so please read my original post WASI AIR Logging Console & Logging Util Tools for a general overview.

See It In Action!

  • Logging Test Application — Small test app that uses the logging framework and spits out log statements every second. I have a link to the console below for quick testing.
  • Logging Console Test Application — Allows you to see the Console in action when you run it and the Logging Test Application at the same time.

Assets

Updates & Changes

  • The name of the SWC has changed from WASILogConsoleLibrary.swc to  WASILoggingLibrary.swc.
  • The LocalConnection Logger is no longer a wrapper class, but now an actual logging target called LocalConnectionTarget.
  • Added a Firebug (FireFox extension) Logging Target that outputs the same log message as the LocalConnectionTarget.
  • Created a base WASILoggingTarget with several, common helper methods for creating targets.

Since I mentioned that some of the actual impl changed a bit I’m going to show some code illustrating the changes.

Setting Up in Main App :: Example Code

The difference between this one and last version I shared has to do with the use of targets as opposed to a wrapper class. I also put all of my logging specifics into a helper class for the Test App called Logging — I could’ve just as easily put this all into the main app file, but I decided to move it into a new class for better organization.

<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	creationComplete="this.init()">

	<mx:Script>
		<![CDATA[
			import com.webappsolution.controller.FilterControllerTest;
			import com.webappsolution.delegate.FilterDelegateTest;
			import com.webappsolution.logging.Logging;

			private static var loggerSetup:* = Logging.setupLogging();

			private function init():void
			{
				var filterDelegateTest:FilterDelegateTest = new FilterDelegateTest();
				var filterControllerTest:FilterControllerTest = new FilterControllerTest();
			}

		]]>
	</mx:Script>

</mx:Application>

The line to make note of is

private static var loggerSetup:* = Logging.setupLogging();

which calls my helper Logging class that actually creates the logging targets, levels, and filters.

Helper Logger Class (Not Required)

/**
 * Web App Solution Confidential Information
 * Copyright 2010, Web App Solution, Inc.
 *
 * @date Apr 26, 2010
 */
package com.webappsolution.logging
{
	import com.webappsolution.logging.LoggingUtils;
	import com.webappsolution.logging.target.FirebugTarget;
	import com.webappsolution.logging.target.LocalConnectionTarget;

	import mx.logging.LogEventLevel;
	import mx.logging.targets.TraceTarget;

	public class Logging
	{
		/**
		 * Create your list of targets here.
		 */
		public static function setupLogging():void
		{
			var level:int = LogEventLevel.ALL;
			var filters:Array = createFilters();
			var targets:Array = createTargets();

			// set up logging for the application
			LoggingUtils.setupLogging(level, filters, targets);
		}

		/**
		 * Create your list of compile-time filters here.
		 */
		public static function createFilters():Array
		{
			var filters:Array = ["*"];

			return filters;
		}

		/**
		 * Create your list of targets here.
		 */
		public static function createTargets():Array
		{
			var traceTarget:TraceTarget;
			var firebugTarget:FirebugTarget;
			var lcTarget:LocalConnectionTarget;
			var targets:Array;

			traceTarget = new TraceTarget();
			traceTarget.level = LogEventLevel.ALL;
			traceTarget.includeDate = true;
			traceTarget.includeTime = true;
			traceTarget.includeCategory = true;
			traceTarget.includeLevel = true;

			firebugTarget = new FirebugTarget();
			firebugTarget.level = LogEventLevel.ALL;
			firebugTarget.includeDate = true;
			firebugTarget.includeTime = true;
			firebugTarget.includeCategory = true;
			firebugTarget.includeLevel = true;

			lcTarget = new LocalConnectionTarget();
			lcTarget.level = LogEventLevel.ALL;
			lcTarget.includeDate = true;
			lcTarget.includeTime = true;
			lcTarget.includeCategory = true;
			lcTarget.includeLevel = true;

			// create a list of targets
			targets = [traceTarget, firebugTarget, lcTarget];

			return targets;
		}
	}
}

Here I’m just creating the specific logging targets for my application:

  • TraceTarget — ouputs to your Flex IDE’s console
  • FirebugTarget — ouputs to your FireFox’s Firebug plugin’s console
  • LocalConnectionTarget — ouputs to WASI AIR Logging Console

The other change to make note of is the actual definition of the logger in each class you’re implementing logging. Let’s take a quick look here.

New Logger Instantiation

The OLD way was like this:

private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);;

The NEW way was like this:

private static const logger:ILogger = Log.getLogger(LoggingUtils.getFullyQualifiedClassName(FilterControllerTest));

The new design decouples the logging from our custom wrapper class LocalConnectionLog and now uses the out of the box mx.logging.Log to create a category for each logger instantiation. Notice the use of LoggingUtils.getFullyQualifiedClassName(clazz:Class):String to get the fully qualified string name for the object; one can also just pass in a string category of their choice instead of using the class name.

Post to Twitter Tweet This Post

, , , , ,

1 Comment

WASI AIR Logging Console & Logging Util Tools

Introduction

About a year ago I revisited an old friend — a simple SWF with a TextArea that outputs log messages from another SWF via the LocalConnection. I wrote it for Xcelsius since it’s a black box when you’re running custom Flex Connectors and UI Components and I needed a way to not only see the errors in the Flash Debug Player, but get more info…thus, the reemergence of my old-school Flash Logger that I originally wrote in Flash 5. You can read more about it here.

Recently, however, I realized that this simple tool was actually much more valuable than I had remembered, as I’ve had several clients that have had some difficulties logging in or running the app as expected for the first time…you know the schpeel…it’s all hooked up and ready to go and you’ve been logging into the app for months from your dev machine and it works great…but then suddenly the client tries to run it and nada…and since they don’t have a Flash/Flex Builder IDE all ready to rock with debugging, you might be stuck wondering why they can’t get in…ah-ha, just fire up the good-ole WASI Logging Console and suddenly your mystery is solved.

See It In Action!

  • Logging Test Application — Small test app that uses the logging framework and spits out log statements every second. I have a link to the console below for quick testing.
  • Logging Console Test Application — Allows you to see the Console in action when you run it and the Logging Test Application at the same time.

Assets

Quick Explanation…How Does it Work?

The WASI LocalConnection (LC) Logger  consists of 2 parts:

  1. A SWF with a LC that receives messages — ie, logs statements — and displays them in a simple Flex List.
  2. A Logging Framework that provides basic logging methods you’d expect (debug, info, warn, error, and fatal) with a LC sender that pushes these messages to the receiving SWF.

Logger Basics

The WASI Logger outputs log statements to both the Flex/Flash builder IDE and the WASI AIR Logging Console with the same-old, friendly Flex logging sytax you;d expect. Here’s some sample code using it in an application:

logger.debug("entering myMethod"); // log statement in myMethod

And here’s what the output looks like to both the IDE’s console and the AIR Console:

4/12/2010 07:03:57 PM [DEBUG] com.webappsolution.controller.FilterControllerTest myMethod // output to the Flex IDE console

Compile-Time & Run-Time Logging Configuration

The Logging Framework also provides the ability to set up logging configuration for log levels and log filters at both compile-time and run-time. To configure logging for Compile time, simply add the following import and variable to your main application’s script block:

import com.webappsolution.logging.LoggingUtils;
private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

In the previous example, the logger is set up with log level of All and sets the filters to include all classes (even the Flex SDKs basic messaging classes for HTTPService so you might want to consider using a package level that’s appropriate to your application.)

To configure logging for Run-time, simply add the following query string to your application’s debug configuration or URL in the browser window:

http://wasi.com/app.swf?logLevel=error&logFilters=com.webappsolution.controller.*,com.webappsolution.delegate.*

Note the 2 parameters in bold; the following depicts their use and possible values:

  • logLevel — The desired log level for logging with the following values (must be in lowercase):
    • debug
    • info
    • warn
    • error
    • fatal
  • logFilters — The desired package and/or class names you’d like to see in the logger. Examples include fully qualified class names or packages with asterisks at the end.
    • Class; eg com.webappsolution.controller.MyController — Will only show log statements for the class MyController.
    • Packages; eg com.webappsolution.controller.* – Will show the log statements for all the classes in the package “com.webappsolution.controller”

You can apply multiple filters in the url by comma separating them: com.webappsolution.controller.*,com.webappsolution.delegate.*,com. webappsolution.MyClass

Using Run-time configs will override whatever was specified in the Compile-time configs.

NOTE: You must run the application from a web server in order for runtime log configs to work since Flash/Flex Builder throws an error when you try to create debug configurations with a query string at the end (again unless running from a web server).

NOTE: applying log levels and filters only effect the log statements in the IDE — all log statements are sent to the WASI AIR Logging Console as it has it’s own set of tools to do the same filtering.

WASI AIR Logging Console Features - Top Tool Bar

Since the Console receives all the logging messages, we’ll review its set of tools that help developers achieve the same functionality as aforementioned.

Log Level ComboBox — Contains a list of all log levels and allows developers to filter the list of log messages in the console by selecting these levels.

Log Filter AutoComplete Field — Allows developers to search for classes and packages to filter the list by; the list of possible filters is automatically generated for the developer at runtime once the console starts receiving messages and sorts them by alphabetical order. Smply start tpying in the full qualified name of a class or package and you’ll be presented with all matches.

To the right of the Log Filter AutoComplete Field is a helper ComboBox that allows the developer to sort the list of filters by class name, packages, or both — this is incredibly useful if you are logging to of classes. You can delete and/or remove filters by backspace the selected item in the AutoComplete field or clicking on the “Clear Filters” button.

NOTE: You can apply both log level and log filters to the list at the same time in any order.

Right-click — Developers can right-click on an item in the list and filter directly by selecting “Filter by Item” in the context menu. Coming soon — copy the individual log message with right-click.

WASI AIR Logging Console Features - Bottom Tool Bar

Clear Log Button — Simply click this to clear the entire log list.

Copy to Clipboard Button — Clicking this copies the entire list of log messages to your clipboard for easy cut and paste.

Auto Scroll CheckBox — Selecting the checkbox forces the list of log messages to scroll automatically to the bottom o the list. This can be useful if you’re watching real-time messages with logs.

Pretty Colors CheckBox — Selecting the checkbox color codes the log levels in the log list.

What it Does NOT

  • Can’t currently accept log messages over 40k — this can easily happen if you’re trying to log a large amount of data like, XML. I’ll push this out shortly by splitting up the chunks I’m sending across the wire to be < 40k.
  • Can’t run more than one of these suckers at a time (since the LC relies on a unique ID). Could allow the developer to enter in a unique ID for each version of the console and app, but I don’t think this is necessary at the moment.
  • Can’t enter multiple filters. This wouldn’t be too hard and is scheduled to come out soon.
  • No AIR badge…I’m being lazy right now and wanted to get the bare bones out for some quick feedback.
  • Not currently on Google Code but will be by EOW as an open source project.

Getting Started

This thing is pretty simple really and requires very little setup or modification to your code:

  1. Download the WASILogConsoleLibrary.swc and drop it into the libs folder of your project.
  2. In your project add the following, imports:
    1. import com.webappsolution.logging.LoggingUtils;
    2. import mx.logging.LogEventLevel;
  3. In your main application file, add the logging setup: private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);
  4. In classes you want to log, create the following:
    1. import com.webappsolution.logging.LocalConnectionLog;
    2. import mx.logging.ILogger;
    3. private static const logger:ILogger = LocalConnectionLog.getLogger(FilterDelegateTest);
    4. Call some log methods like:
      1. logger.debug(”we are logging”);
  5. Download the WASI Logger Air Console (WASILogConsoleAIR.air).
  6. Install the AIR application, run it, and then run your project that you just added logging to.

Setting Up in Main App :: Example Code

Again, the key thing to note here is the line where we set up the logger with LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

<mx:Application
	xmlns:mx="http://www.adobe.com/2006/mxml"
	creationComplete="this.init()">

	<mx:Script>
		<![CDATA[
			import com.webappsolution.controller.FilterControllerTest;
			import com.webappsolution.delegate.FilterDelegateTest;
			import com.webappsolution.logging.LoggingUtils;

			import mx.logging.LogEventLevel;

			private static var loggerSetup:* = LoggingUtils.setupLogging(LogEventLevel.ALL, ["*"]);

			private function init():void
			{
				var filterDelegateTest:FilterDelegateTest = new FilterDelegateTest();
				var filterControllerTest:FilterControllerTest = new FilterControllerTest();
			}

			protected function button1_clickHandler(event:MouseEvent):void
			{
				var urlRequest:URLRequest = new URLRequest("http://www.webappsolution.com/air/wasi-logging-console/WASILogConsole.html");
				navigateToURL(urlRequest, "_blank");
			}

		]]>
	</mx:Script>

</mx:Application>

Using the Logger :: Example Code

Here you should note the instantiation of the logger as a static constant, private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);, as well as the use thereof with normal logging syntax, logger.debug("Constructor");.

Just pass in the name of the class you’re implementing logging in in the method LocalConnectionLog.getLogger(); and you’re good to go!

package com.webappsolution.controller
{
	import com.webappsolution.logging.LocalConnectionLog;

	import flash.events.TimerEvent;
	import flash.utils.Timer;

	import mx.logging.ILogger;

	public class FilterControllerTest
	{
		private static const logger:ILogger = LocalConnectionLog.getLogger(FilterControllerTest);

		public function FilterControllerTest()
		{
			// all log levels
			logger.debug("Constructor");
			logger.info("Constructor");
			logger.warn("Constructor");
			logger.error("Constructor");
			logger.fatal("Constructor");

			var timer:Timer = new Timer(5000);
			timer.addEventListener(TimerEvent.TIMER, onTimer);
			timer.start();
		}

		private function onTimer(e:TimerEvent):void
		{
			logger.debug("Constructor");
			logger.info("Constructor");
			logger.warn("Constructor");
			logger.error("Constructor");
			logger.fatal("Constructor");
		}
	}
}

NOTE: You can also fire up this Logging Test Application that allows you to play with various filters and log levels. It has a timer that spits out logs messages every second. Simply open this link up and then open up the WASI AIR Logging Console and you should see some messages start to populate the list.

Special Thanks

  • Abdul Qabiz — I used your com.abdulqabiz.utils.QueryString class to nab the parameters out of the query string.
  • Hillel Coren — I used your AutoComplete component to create the package and class filter AutoComplete Search Field.
  • Jesse Warden — We’ve been rapping back and forth about the fact that we both had one so we decided to combine some of the functionality between the two into this final tool.
  • Final Thoughts

    We’ll continue to update this enhancement requests and fix any bugs that y’all find, so let’em fly!

    Post to Twitter Tweet This Post

, , , , ,

5 Comments

Unable to export SWC oem

Been switching environments a bit lately from Flash Builder to Flex Builder and back and using different SDKs.

When importing a new project that someone had checked in from a different version, the .flexLibProperties file was causing this issue.

After much scouring, I found something that worked.

Open .flexLibProperties and find the section <includeResource/>. Remove everything in that section.

Made the problem disappear.

Post to Twitter Tweet This Post

, , ,

No Comments

FlexUnit 4 Testing Services In Flash Player Issue

We’ve created a number of FlexUnit 4 (FU4) tests for our current, large project and the suite of tests that seems to be of the most importance to both us and our client is the one that tests the services. Our client’s back-end services are simple JSPs that return XML payloads for a number of CRUD operations on various objects in the system, so we’d like to test sending good required data as well as bad required data to our delegate before hitting the service directly.

The issue we ran into was quite frustrating and it took me some time to figure it out — I actually had to explain the system of tests to my partner before it dawned on me what was going wrong. In order to actually hit the services and get data back, you need to be logged into our client’s system…except this isn’t done through a Flex login, but rather via the larger application’s HTML login in which our smaller app lives (SSO)…once you’re logged in, a cookie is sent back and forth between the client and server…such is the security design of our client’s application framework and there wasn’t any wiggle room to change this.

SWF Browser Association

Change SWF to Open With Browser

Now think about FU4 and how it actually runs the tests (when using Ant and not building and running with FlexBuilder)…it simply opens up a TestRunner.swf in the Flash Player to execute it’s tests…this means no browser wrapper for our SWF and thus no access to cookies…and ultimately no working services in my tests…grrrr.

So here’s a simple solution (on Mac)…open up Finder and locate your TestRunner.swf, right-click on it and select “Get Info”. Find the section “Open with” and change the application to your browser (I use FireFox), but don’t click the button change for all, as we just want to change this for this file and this file only. Voila! Now your TestRunner.swf will run in thr browser when your Ant buld runs and you will have access t cookies (assuming you’ve already logged into the system you need access to in the same browser session).

Post to Twitter Tweet This Post

, , , , , , ,

6 Comments