Showing posts with label flex. Show all posts
Showing posts with label flex. Show all posts

Thursday, August 24, 2006

Flex: Debug Flash Player on OS X

As noted in "Building and Deploying Flex2 Applications" (Live Docs), the output of trace statements can be configured in the standalone debug version of the Flash player. The documentation describes the location of the mm.cfg file on Mac OS X using Mac-style (non-Unix) path notation with colons to separate directories.

I set up a config file, but for the life of me, I couldn't find the output file. Then, I found an old, pre-Flex2 blog post by Christian Cantrell which fills in two missing parts of the documentation. First of all, if no TraceOutputFileName directive is given, the trace output will go to flashlog.txt in the same directory as the config file - fair enough. Once I removed the directive, I found the output file.

Also, if a path name is given, the path must be specified in the old Mac-style notation (with colons) rather than Unix-style (with slashes). I suppose that's why they specified the location of the config file in that notation, but the significance of the colons was lost on me. One totally trivial tidbit correctly noted in Christian's blog post is that the directory name is "Macromedia" not "macromedia", as indicated by the docs. (Since the Mac's HFS+ file system is basically case insensitive, it doesn't really matter.)

Once I figured that stuff out, I could get my trace output and get on to fixing my bugs.

I do have (at least) one gripe with the debug Flash player on the Mac compared to the PC - it doesn't keep a history of recent URLs. So, every time you go to open an URL, you have to type it in again (or paste it from a browser, which does keep history.) Even if you keep the player running, it still doesn't remember the last URL it opened.

Enjoy,
Charles.

Wednesday, July 19, 2006

Flex: Sending Messages from Server-Side Java Code

I've been trying to figure out how to send messages from the depths of my Java application out to Flex clients. I'm not talking about messages that originate on a client, pass through the Java server, and then head back to the clients - that stuff is documented in the manual. I mean there is a process going on in the server that needs to send messages to the clients.

Of course, JMS and the JMS adapter would work, but I've been really leery of the complexity of JMS since it came out years ago. It has the advantage that it would allow my application to be separated from the Flex server, which would work well in terms of scaling. I may yet try JMS, but for the moment, I'm looking to avoid JMS.

So, I was thinking that writing a message service adapter would be the key. Adobe has a brief example of creating a custom Message Service adapter. It seems to be a complete example, but it left me with lots of questions. For example Message is an interface, which concrete class do we use? How do we construct it? What all can we do with the MessageService? What value are we returning from invoke?

After some digging around in the sample code, I came across a couple of Java classes associated with the dashboard sample application. So, I've taken the code from that example, paired it down a bit, and wrote a very simple, Soviet-style (butt-ass ugly but functional) Flex interface for it.

Below is the server-side Java code.

import java.util.*;
import flex.messaging.MessageBroker;
import flex.messaging.messages.AsyncMessage;
import flex.messaging.util.UUIDUtils;

public class FmsDateFeed
{
private static FeedThread thread;
public FmsDateFeed()
{
System.out.println("FmsDateFeed.ctor: " + this);
}

public static void main(String[] args)
{
FmsDateFeed feed = new FmsDateFeed();
feed.toggle();
}

public void toggle()
{
if (thread == null)
{
System.out.println("FmsDateFeed.toggle: starting...");
thread = new FeedThread();
thread.start();
}
else
{
System.out.println("FmsDateFeed.toggle: stopping...");
thread.running = false;
thread = null;
}
}
public static class FeedThread extends Thread
{
public boolean running = true;
public void run()
{
MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
String clientID = UUIDUtils.createUUID(false);
System.out.println("FmsDateFeed.run: msgBroker=" + msgBroker + ", clientID=" + clientID);

Random random = new Random();
while (running)
{
Date now = new Date();

AsyncMessage msg = new AsyncMessage();
msg.setDestination("time_msgs");
msg.setClientId(clientID);
msg.setMessageId(UUIDUtils.createUUID(false));
msg.setTimestamp(System.currentTimeMillis());
HashMap body = new HashMap();
body.put("userId", "daemon");
body.put("msg", now.toString());
msg.setBody(body);
System.out.println("sending message: " + body);
msgBroker.routeMessageToService(msg, null);
try
{
long wait = random.nextInt(8000) + 3000;
System.out.println("sleeping: " + wait);
Thread.sleep(wait);
}
catch (InterruptedException e) { }
}
}
}
}


The toggle method is called from the client to turn the message stream on or off. When messages are turned on, a thread is created and the run method is called. It just loops creating Java Date objects and putting the String representation of the date into Flex messages - instances of AsynchMessage. The key for me was the routeMessageToService method on the MessageBroker class. When you have the class compiled, install the Java class file in samples/WEB_INF/classes.

The client is pretty simple, by comparison. It has two features: a button for turning the message stream on and off (via a RemoteObject call) and an event handler to process the incoming messages.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#FFFFFF"
creationComplete="initComp()">
<mx:Script>
public function initComp():void {
consumer.subscribe();
}
public function toggle():void {
feeder.toggle();
}
import mx.rpc.events.ResultEvent;
import mx.messaging.events.MessageEvent;
public function messageHandler(event:MessageEvent):void {
var body:Object = event.message.body;
output.text += body.userId + ": " + body.msg + "\n";
}
</mx:Script>

<mx:RemoteObject id="feeder" destination="time_msgs">
<mx:method name="toggle"/>
</mx:RemoteObject>
<mx:Consumer id="consumer" destination="time_msgs" message="messageHandler(event)"/>

<mx:Form>
<mx:FormItem>
<mx:Button label="Toggle Date Feed" click="toggle()"/>
</mx:FormItem>
<mx:FormItem label="Output Message">
<mx:TextArea id="output" width="250" height="150" />
</mx:FormItem>
</mx:Form>
</mx:Application>

The interesting features are the configuration information for the RemoteObject and the message Consumer. These correspond to destinations configured on the server (see below). When the toggle button is pressed, we just call the toggle ActionScript method, which make a call on our RemoteObject, feeder; we don't care about a return value, which simplifies things.

We configure the Consumer to call our messageHandler method when new messages arrive. It just gets the message body and appends it to our text box. Install this file in somewhere in the samples directory - I created my own subdirectory for the dumb, little programs like this.

To configure the server, edit messaging-config.xml in samples/WEB-INF/flex and clone the destination for "dashboard_chat" and call the new version "time_msgs". You could change the Java and MXML to use the existing dashboard_chat destination (which is what I did initially), but a) you could end up with a conflict with the Flex demos, and b) writing to messaging-config.xml (or any of those other config files) is a convenient way to get the server to restart and see your new Java class.

Oh yeah, you also need to edit remoting-config.xml to contain a RemoteObject destination also called "time_msgs". (You could use separate names for the two destinations, and it would probably be less confusing, but I was too unimaginative.)

If all goes well, you should get messages with the current time showing up randomly in the Flash client.


Enjoy,
Charles.

Wednesday, July 12, 2006

Flex: The Second Simplest Example of RemoteObject

(Update: I wrote this some time ago, and I don't have access to the source code any more. Therefore, I can't send it to you. And, I don't know about newer versions of Flex.)

In a previous post, we developed what I claim to be the world's simplest example of using the RemoteObject facility in Flex 2 to invoke a method on a Java object using the RPC services. In that example, we just had a button on a Flash application that called a method on the server. All the method did was print a message. Although we passed a message into the server method, that message was hard-coded in the ActionScript, and no results were passed back.

In this post, we will build on that to pass some user data into the server and get a response back. In theory, this ought to be very simple: the user data just comes from an input box, and the result will just be displayed in a text box.

Java Code


Below is a simple function that you can add to the SimpleRemoteObject from the previous example:

public String echoMessage(String msg)
{
System.out.println("SimpleRemoteObject.echo: " + msg);
return "The RemoteObject says: " + msg;
}

As you can see, the method writes the message to the console (like before), and returns the message with a little text prepended to it. Pretty simple.

Flash Client


The user interface is pretty simple, and I just added it to the form in the previous example. We have a TextInput to enter data, a Button to invoke the method, and TextArea to display the result from the server.

<mx:FormItem label="Input Message">
<mx:TextInput id="input"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Echo Message" click="echoMessage()"/>
</mx:FormItem>
<mx:FormItem label="Output Message">
<mx:TextArea id="output"/>
</mx:FormItem>

So far, so good. The button calls an ActionScript method (echoMessage) to call the server - just like the previous example:

public function echoMessage():void {
remoteObj.echoMessage(input.text);
}


We just get the text from the TextInput object (input) and call the method on the server. (Note that although I named the ActionScript method the same as the Java method - echoMessage - this isn't necessary; I'm just not creative enough to think of anything else.) But wait, something is missing: what about the message coming back from the server? Based on my experience with Java (and dozens of other languages), I would expect to see code that looks like:

output.text = remoteObj.echoMessage(input.text);

But, that's not how it works in Flash. Flash makes RPC calls asynchronously. This means that Flash doesn't wait for the result to come back from the server, and that's actually "a good thing." Without asynchronous server calls, the Flash client would hang during a (potentially long) server call, and that would be a bad thing.

OK, so how do we get the result back from the server? This introduces some additional complexity, but it's still tractable. It begins in the MXML to describe the server method:

<mx:method name="echoMessage" result="displayResponse(event)"/>

This says that when the echoMessage method on the Java server object is called, and the result arrives at some later time, the displayResponse ActionScript method will be called.

This method is pretty simple, too:

import mx.rpc.events.ResultEvent;
public function displayResponse(event:ResultEvent):void {
output.data = event.result;
}

That's all there is. Note that we don't even have to update the remoting-config.xml file on the server. This is because we are not creating a new destination; we're just using the same Java class - SimpleRemoteObject.

When you run the application in the browser, enter a message in the input area, click the button, and the response will eventually appear in the output area.

If you need the complete code, let me know - post a comment. At the moment, I'm too busy to put together a zip file and post it somewhere.

enjoy,
Charles.

Flex: The World's Simplest Example of RemoteObject

Here is a very, very simple example of using the RemoteObject RPC services in Flex 2 to invoke methods on a Java object. I came up with this because I was struggling to figure out all the stuff needed to do this. In theory, it's pretty simple, but there are a number of components to deal with, and they all get put in different places on the server, and a bunch of those places look very similar to other places on the server.

Introduction


It was especially difficult for me because I'm new to Flex, and I'm coming at it from a server-side background in Java. I don't care about making pretty user interfaces (that's someone else's job) - I'm the guy who has to make the server code work. However, most of the documentation assumes that you're coming at it from the other end - the client side.

I couldn't find any simple examples of using RPC in Flex 2.0. I foolishly started with Flex 1.5 example and wasted a bunch of time updating the syntax in it in order to get it to compile.

After I got that to compile (from the command line - I'm old school), it wouldn't run. After I got the Flash debugger working, I could see that the messaging destination didn't exist, but I couldn't figure out why. So far as I could tell, I had configured it correctly, but there was no indication that things were making it to the server. Finally, I gave up my command line and put the MXML file on the server, and just let the web-tier compiler do it for me.

And, it just worked! The documentation makes reference to using the SDK compiler versus the web-tier compiler, but it just didn't click with me. But, it was still more complicated than I needed. So, I created the following, to prove that I could do it, and that I knew all the voodoo needed.

I will assume that you have the Flex Data Services demo server with Jrun installed an running. I will specify all paths from the root of the jrun server.

Java Code


Let's start with the simplest function in a Java file - basically, "hello world."


public class SimpleRemoteObject
{
public void writeToConsole(String msg)
{
System.out.println("SimpleRemoteObject.write: " + msg);
}
}


This will just write a message to the server console window. (We don't even have to use any fancy Java logging.)

Compile that file and put the SimpleRemoteObject.class file in the directory jrun4/servers/default/samples/WEB-INF/classes on the server. (Note that since the class is in the unnamed, default package, we put the class file in classes, not a subdirectory.)

Flash Client


Now, we need a simple Flash app. Here's a simple MXML file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="#FFFFFF"
initialize="initApp()">
<mx:Script>
public function initApp():void {
}

public function writeToConsole():void {
remoteObj.writeToConsole("hello from Flash client");
}
</mx:Script>

<mx:RemoteObject id="remoteObj" destination="sro">
<mx:method name="writeToConsole"/>
</mx:RemoteObject>

<mx:Form>
<mx:FormItem>
<mx:Button label="Write To Server Console" click="writeToConsole()"/>
</mx:FormItem>
</mx:Form>
</mx:Application>

Create a directory called sro under jrun4/servers/default/samples and put the MXML file there.

Now, we can compile the file by loading it in the browser with a URL like:
http://192.168.123.130:8700/samples/sro/SimpleRemoteObject.mxml
(The key is that the file is under /samples/sro based on where we copied the file.)

Don't click the button yet! We still have to configure the FMS destination. Just make sure it compiles correctly.

Configure the Server


Add the following XML code to jrun4/servers/default/samples/WEB-INF/flex/remoting-config.xml. Just put it within the service tag for the remoting-service - e.g., near one of the other FMS destinations.

<destination id="sro">
<properties>
<source>SimpleRemoteObject</source>
</properties>
</destination>

And now, if you press the "Write to Server Console" button, the message, "hello from Flash client" will appear in the Jrun server window.

That's it. It really is as easy as Adobe says it is...
once you figure it all out.

enjoy,
Charles.