Here, waste some time!

Funny or annoying, you decide!

This is a game concept that my brother and I started work on, soon to be a facebook app.
Right now, it isn’t much more than a memory leak. It gets really annoying after about 15 minutes.

Scientifically, it may say a lot about Flex and Flash Player’s ability to process objects and sprites. After about 100-200 chickens (depending on your hardware/OS etc) it really starts to slow down. Interesting data for those developing complex UI’s.

Naturally it has a lot of work to be done at this point, but we’ll get there as we are still throwing ideas around.

Flex and the ‘tab’ key

Ran into another pickle not too long ago involving the tab key. By default, the tab key cycles through text inputs and buttons et cetera based on the tab order you define. But what if you want the tab key to do something different? If anyone out there has tried to prevent the default behavior of the tab button with Flex before, they will know that it is not as easy as you’d think.

With every other keyDown or keyUp event, you can usually capture the event and call a preventDefault() in order to prevent the default behavior. However, for some odd reason, the keyDown event behaves differently when the tab key is pressed. Why only the tab key? I don’t know. I suppose that is a question for Adobe.

Either way, I managed to hack my way around the limitations and capture the tab keyDown anyway. Now, try to stay with me here, because what I ended up having to do still doesn’t quite make complete sense to me.

With my specific example, I was using a custom item renderer inside a DataGrid. Normally the tab key would highlight the next object to the DataGrid in the canvas, but I really wanted it to go to the next (or what I considered “next”) element inside the DataGrid. However, I imagine that this solution could be used in other places as well.

As close as I can tell, as soon as the tab key goes up the inner workings of flex change the focus to the next object in the tab order. This seems to happen before any sort of keyDown handler is called, so the following does NOT work:

<mx:TextInput keyDown="myKeyDownHandler(event)" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
    public function myKeyDownHandler(event:KeyboardEvent):void {
        if (event.keyCode == 9) {
            // tab key
            event.preventDefault();
            ....

The only reason I can figure as to why this doesn’t work is because by the time myKeyDownHandler() gets called, the default event actions have already been executed… i.e. the damage has been done.Trying the same thing on the keyUp handler yields the same results. Stepping through Flex source leads me to believe that it is not a KeyboardEvent that actually makes the ‘tab’ happen, but a FocusEvent, but the keyFocusChange event doesn’t even get fired on the current object when the tab key is hit (Adobe bug?) so that is out of the question also. So how can I trap an event that seems to be phantom?

I finally managed to figure out how to get it to work, and it was really weird what ended up working. I found out (through a lot of debugging and various different wild-guesses) that I can capture the FocusEvent on the tab keyDown through doing a combination of things:
1) First, I had to trap the keyDown that is fired when the tab key is pressed.
2) In that same event, I had to call a (some object).setFocus() to trigger a FocusEvent (this.setFocus() was called in this example)
3) Finally, in the onKeyFocusChange event of the object that the setFocus() was called on in step two, call an event.preventDefault()

It seems as though by calling a setFocus() while in a keyDown event handler, I triggered an “early” FocusEvent that I can then catch myself. The FocusEvent that gets captured by the onKeyFocusChange event in step three for some reason IS that tab event. Through Flex voodoo and wizardry I managed to prematurely cause the tab FocusEvent myself, and then prevent it. Weird, right?

I really have no idea why, but it works. If somebody can explain it to me, be my guest. I imagine it has something to do with the way Flex’s event queue works. In the meantime, enjoy the solution. View source is turned on for your pleasure.

Making Flex Behave with Web Services

So, you go through the process of creating a web service in Flex. Wow, this is going to be easy! Look at all these wizards!
You import your WSDL, and Flex generates all sorts of neat ActionScript classes for you to use. It seems almost automatic.

That is, until you try to actually do anything, and you get the following error:

TypeError: Error #1034: Type Coercion failed: cannot convert (some object) to QName

This problem had me pulling my hair out for a couple days straight. If it seems so automatic, why isn’t it working? Well, as it turns out, Flex’s SOAP encoder (the part that serializes the object into XML) currently has quite a few limitations. It works great if your web service only wants simple objects, but if you want an array or some other complex object, forget about it!

The solution: you need to override the SOAPEncoder that Flex is using for the web service.
First, create the new SOAPEncoder class. For this example, I’ve created one that just takes XML. I know what the XML is supposed to look like for the web service call, so why don’t I just create the XML myself?

package
{
	import mx.rpc.soap.SOAPEncoder;

	public class SimpleEncoder extends SOAPEncoder
	{
		public function SimpleEncoder()
		{
			super();
		}

		override public function encode(value:*, name:QName = null, type:QName = null, definition:XML = null):XMLList {
			return new XMLList(value);
		}

	}
}

Now that I have my own SOAPEncoder, I can just pass the send() function straight XML! For example, let’s say you have a web service function called “addList” that takes a list of items as it’s payload. You could do the following:

var xml:String = "";
xml += "<list>\n";
xml += "\t<item>one!</item>\n";
xml += "\t<item>two!</item>\n";
xml += "\t<item>three!</item>\n";
xml += "</list>";
var o:mx.rpc.soap.mxml.Operation = service.addList;
o.encoder = new SimpleEncoder();
o.send(xml);

The beauty of this is, it doesn’t really matter what you are trying to do. Overriding the encoder means you can build the XML yourself, instead of just trusting that Flex is going to do it properly.

XML Deserialization using Axis

SOAP web services are supposed to be easy with Axis.  Sometimes, when you’re really lucky it is.  Most of the time though I’m not so lucky.

My problem was this: I had a SOAP web service (probably written in .NET) with literally hundreds of objects.  My goal was to take XML of those objects (just a String input of XML) and turn them into Axis-generated objects so I could properly make web service calls.

My first approach was dead wrong.  I started by trying to parse out the XML myself and call all the associated get/set methods by hand.  I soon realized that writing that much code for hundreds of objects was not an option.

knew there had to be a better way.  As it turns out, there is.

While Axis doesn’t have any “built-in” exposed methods to “turn this XML into an object”, I knew that on some level the code had to exist.  So I started stepping through code and figuring out how Axis did it itself… and as it turns out, what I wanted to do could be accomplished with a few lines of code:

	/**
	 * Reads in the Axis stubbed-out deserializer and turns raw XML into it's associated java object.
	 * @param xmlInput
	 * @param qName
	 * @param javaType
	 * @return Object
	 * @throws Exception
	 */
	public java.lang.Object deserializeObject(String xmlInput,javax.xml.namespace.QName qName, java.lang.Class javaType) throws Exception {
		try {
			// add the SOAP envelope since we we aren't expecting a SOAP object
			String temp = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body>" + xmlInput + "</soapenv:Body></soapenv:Envelope>";
			org.apache.axis.server.AxisServer server = new org.apache.axis.server.AxisServer();
			server.setOption(AxisEngine.PROP_DOMULTIREFS, true);
			MessageContext msgContext = new MessageContext(server);
			java.io.Reader reader = new java.io.StringReader(temp);
			DeserializationContext dser = new DeserializationContext(new org.xml.sax.InputSource(reader),msgContext,org.apache.axis.Message.REQUEST);
			dser.parse();
			SOAPEnvelope env = dser.getEnvelope();
			RPCElement rpcElem = (RPCElement)env.getFirstBody();
			MessageElement struct = rpcElem.getRealElement();
			Object result = struct.getValueAsType(qName,javaType);
			return result;
		} catch (Exception e) {
			throw new Exception("Could not deserialize the XML object:" + e.getMessage());
		}
	}

Going back the other direction is a little easier:

	/**
	 * Turns an object into XML using the Axis-generated serializer
	 * @param object
	 * @param qName
	 * @return String
	 * @throws Exception
	 */
	public String serializeObject(Object object,javax.xml.namespace.QName qName) throws Exception {
		try {
			MessageElement me = new MessageElement(qName, object);
			return me.getAsString();
		} catch (Exception e) {
			throw new Exception("Could not serialize the object:" + e.getMessage());
		}
	}

Welcome!

This is a blog I intend to use for software development discussion.

I come from a extremely diverse programming background, but lately I’ve been doing most of my work with Java and Flex (ActionScript 3).  The things I’ll be posted are going to generally be what you may call “undocumented solutions”.

Stay tuned, lots of good stuff to come!