I had a really strange bug yesterday that we found that I thought it would be good to share. We had recently launched a new application to production. Long story short, there is a screen that gets the next ID for a report, and it had been working fine for a few days. All of the sudden though, about noon yesterday it stopped working. Nothing had changed in the code and our first instinct was a network problem. But what we found out was that it really was the code.
continue reading...Entries for Tag: 'flex'
Do not communicate by sharing memory. Instead, share memory by communicating.This is a very succinct and eloquent way of saying something that I have been stressing for years when talking to web developers. OO principles teach this by way of saying that your apps should be loosely coupled, but there are too many people that do not get what this means. I usually try to describe it as "Only let this object or method work with what it is given". Never act on data that you are not explicitly given. You cannot be sure it will always be there, and you cannot be guaranteed that it will be in the proper form for you to work with.
I have talked about sparklines before and this seems to be a very well done implementation of them in Flex. Putting this out there for me as much as anyone else. See also: Flex Spinner.
I am sure this is written in flex; It is a very compelling layered photo editor. Lots of brushes, lots of options. And it seems pretty snappy considering what it all it does. Its not going to replace photoshop for any serious users, but for the casual user, yeah, I think it would.
package com.util
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
[Event(name="complete",type="ConfigLoaderEvent")]
[Event(name="fault",type="ConfigLoaderEvent")]
public class ConfigLoader extends EventDispatcher
{
private var _configXMLPath:String;
private var _configLoaded:Boolean = false;
private var _configXML:XML;
//our favorite constructor...
public function ConfigLoader(configXMLPath:String, target:IEventDispatcher=null)
{
super(target);
_configXMLPath = configXMLPath;
}
//here lies the meat and potatoes of this class
public function load () : void
{
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE,loadConfigXML_complete_handler);
loader.addEventListener(IOErrorEvent.IO_ERROR,loadConfigXML_ioError_handler);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,loadConfigXML_securityError_handler);
//clear the config in case it has been loaded before
_configXML = null;
//set that the config hasn't been loaded
_configLoaded = false
try
{
trace("loading config: " + _configXMLPath);
loader.load( new URLRequest(_configXMLPath) );
}
catch ( e:Error )
{
//trace out the error, but it will be caught below
trace("an error occurred loading the config file");
}
}
public function loadConfigXML_ioError_handler ( e:IOErrorEvent ) : void
{
//woops, something went wrong with the transfer, create and dispatch an event letting everyone know
var cle:ConfigLoaderEvent = new ConfigLoaderEvent(ConfigLoaderEvent.FAULT);
cle.message = "I/O Error";
dispatchEvent(cle);
}
public function loadConfigXML_securityError_handler ( e:SecurityErrorEvent ) : void
{
//looks like someone is trying to access something they aren't supposed to be able to see.
var cle:ConfigLoaderEvent = new ConfigLoaderEvent(ConfigLoaderEvent.FAULT);
cle.message = "Security Error";
dispatchEvent(cle);
}
private function loadConfigXML_complete_handler ( e:Event ) : void
{
try
{
//convert the text to xml
_configXML = new XML( e.target.data );
//set the flag that the config has been loaded.
_configLoaded = true;
//create and dispatch the complete event for a job well done.
var completeEvent:ConfigLoaderEvent = new ConfigLoaderEvent(ConfigLoaderEvent.COMPLETE);
completeEvent.data = _configXML;
dispatchEvent(completeEvent);
trace('configLoader complete');
}
catch ( e:TypeError )
{
var faultEvent:ConfigLoaderEvent = new ConfigLoaderEvent(ConfigLoaderEvent.FAULT);
faultEvent.message = "Could not convert config to xml, document may be malformed.";
dispatchEvent(faultEvent);
}
}
public function get configXML () : XML
{
return _configXML;
}
public function set configXMLPath ( value:String ) : void
{
_configXMLPath = value;
}
public function get configXMLPath () : String
{
return _configXMLPath;
}
public function set configLoaded ( value:Boolean ) : void
{
_configLoaded = value;
}
public function get configLoaded () : Boolean
{
return _configLoaded;
}
}
}
and a custom event for it, ConfigLoaderEvent:
package com.util
{
import flash.events.Event;
public class ConfigLoaderEvent extends Event
{
public static const COMPLETE:String = 'Complete';
public static const FAULT:String = 'Fault';
private var _data:XML;
private var _message:String;
public function ConfigLoaderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
public function set data ( value:XML ) : void
{
_data = value;
}
public function get data () : XML
{
return _data;
}
public function set message ( value:String ) : void
{
_message = value;
}
public function get message () : String
{
return _message;
}
}
}
just stick these in a com/util/ directory under source and you should be off to the races. So here is an example of how to use these classes:
import com.util.ConfigLoader;
import com.util.ConfigLoaderEvent;
[Bindable]
public var configXML:XML;
//a variable to keep track if we are loaded or not
public var configLoaded:Boolean = false;
//create the configloader and tell it where the config.xml file is relative to src.
public var configLoader:ConfigLoader = new ConfigLoader("config.xml");
// I use the initialize event on application to set up these event handlers
//and load the configuration file because it does not
//require any UIComponents to function.
public function application_initialization_handler ( e:Event ) : void
{
//configLoader will broadcast an event on load complete or fault...
configLoader.addEventListener(ConfigLoaderEvent.COMPLETE,configLoader_complete_handler);
configLoader.addEventListener(ConfigLoaderEvent.FAULT,configLoader_fault_handler);
//call load() to actually load in the file and parse it.
configLoader.load();
}
public function configLoader_complete_handler ( e:ConfigLoaderEvent ) : void
{
configXML = e.data;
useConfig(configXML);
}
public function configLoader_fault_handler ( e:ConfigLoaderEvent ) : void
{
Alert.show(e.message);
}
public function useConfig( configXML ) : void
{
// so here you can now use the configXML to pull out whatever values you need.
}
Now this code is a work in progress of course so make sure you look over it and understand it before using it. Hope someone finds it useful.
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.InvokeEvent;
import mx.messaging.Channel;
import mx.messaging.channels.AMFChannel;
import mx.messaging.ChannelSet;
import flash.events.Event;
import mx.controls.Alert;
public function onCreationComplete () : void
{
//create the remote objects first
createRemoteObjects();
//set the AMF Channel on the remote objects
setUpAmfChannel();
}
public function createRemoteObjects () : void
{
ro = new RemoteObject();
ro.destination = "ColdFusion";
ro.source = "path.to.cfc";
ro.addEventListener("fault",ro_fault_handler);
//You probably want and need a result handler...
ro.methodName.addEventListener("result",methodName_result_handler);
//You may need this if you need to do something when a method is called
ro.methodName.addEventListener("invoke",methodName_invoke_handler);
//You may need this if you need to catch and handle errors differently
ro.methodName.addEventListener("fault",methodName_fault_handler);
//This is just sugar, you really dont need it unless you want it.
ro.methodName.showBusyCursor = true;
}
/* You can call the following method anytime to set the amf channel for a remote object on the fly */
public function setUpAmfChannel () : void
{
var amfChannel:Channel = new AMFChannel("my-cfamf","http://server/flex2gateway/");
amfChannelSet = new ChannelSet();
amfChannelSet.addChannel(amfChannel);
//repeat the following line for all remoteObjects
this.ro.channelSet = amfChannelSet;
}
public function ro_fault_handler ( event:FaultEvent ) : void
{
Alert.show( event.fault.faultString, 'Error');
}
public function call_methodName () : void
{
//use this to call the method
ro.methodName(/*pass arguments here*/);
}
public function methodName_invoke_handler ( event:InvokeEvent ) : void
{
//this will fire when the method is invoked
}
public function methodName_fault_handler ( event:FaultEvent ) : void
{
//this will fire when the method throws an error
}
public function methodName_result_handler ( event:ResultEvent ) : void
{
//this will fire when a result comes back from the method
}
You can see how the remote object is created, the methods are defined along with the actionscript methods that handle faults, invokes and results, and you can also specify the amf-channel on the fly, which is quite nice. This gives you far more flexibility when calling your remote object methods than the mxml does in my opinion.
