MattHicks.com

Programming on the Edge

Showing posts with label jseamless. Show all posts
Showing posts with label jseamless. Show all posts

Still Alive!

Published by Matt Hicks under , , , , , , , , , , on Saturday, May 01, 2010
Well, this is a great title for this post not only as it's the first blog post I've made here in seven months, but I've also had the song from Portal stuck in my head lately. :)

Looking at my blog it would be easy to classify me as MIA but I've actually been quite busy in the open-source and have even been blogging quite a bit lately, just not here, but I'll get to that in a minute.

First of all, my very basic last post talking about the entry-level learning I was doing with Scala was quite fitting as my last post as very shortly after that post I made a complete shift from Java to Scala programming. With this came the abandoning of lots of open-source projects I've either created (like jSeamless) or been a developer on (like jMonkeyEngine). I believe so strongly in Scala that I've shifted everything I possibly can to Scala.

Second, with the shift I've made to Scala and all the projects I've abandoned as a result, one new project has come to being that, in many ways, embodies much of the vision I've had for several projects I've left behind. That project is called "sgine" (Scala Engine). I've been developing on it for a while now and have made some major strides recently and finally wanted to make a re-appearance on my blog to hopefully start posting here again.

Now, at the beginning of this post I said that I've been blogging elsewhere. If you go to http://www.sgine.org you'll see that it's a blog filled up with posts regarding updates to the engine I've been developing. I'm really excited about this project and though many people have accused me of abandoning Java...and realistically that's pretty much what I've done...I haven't a regret for switching to Scala, it's such an incredibly powerful language and has renewed my vigor in programming. For anyone considering looking into a new language I cannot recommend it enough.

jSeamless 2.0 is Coming!

Published by Matt Hicks under , , , , , , , , , , , , on Thursday, August 13, 2009
From the outside looking in it would appear that jSeamless is all but dead, but if you've been paying attention to SVN commits you'll notice there's been quite a lot of activity for the past several months. I have somewhat abandoned what small community I had with jSeamless 1.0 in an effort to "start over" with what I believe is the next generation of UI development. I know there seem to be more web frameworks these days than there are developers using them, but I believe that jSeamless 2.0 has several things going for it that goes outside the scope of any UI framework available today. I know that's an ambitious statement, and I hope in this post to back it up enough to push the point home.

So, from a high-level, here are a few of the major features to look forward to in jSeamless 2.0:

Properties
As discussed in previous blog entries the plain old java beans ideology is one that does not lend itself to extensibility and re-use, so the introduction of Properties into the UI framework creates some amazing possibilities with surprisingly elegant results.
Binding
Binding is one of those buzz-word features that both Flex and JavaFX boast and one of the major reasons JavaFX claims to need its own language is because binding is just plain ugly in Java. However, in jSeamless, with the use of Properties, to bind the 'x' position of component2 to the 'x' position of component1 this can be accomplished with the following single-line elegant line of code:
component1.location.x.bind(component2.location.x);

Yes, that's all you have to do to get real-time property binding.
OpenGL
One of the biggest reasons jSeamless 1.0 delved into the realm of Flash/Flex was because Swing was so incredibly slow and lacked many of the niceties professional developers have come to expect from their frameworks. OpenGL not only solves this problem, but laughs in the face of any other competing graphical framework as it boasts FPS rates in the thousands when Flash struggles for framerates in the hundreds. OpenGL is by far the fastest graphical API available on all the major operating systems. Beyond the fact it spits on all the competition, it adds complete 3D capabilities to the landscape of capabilities people can utilize in their UIs. I could spend several pages elaborating on the features that OpenGL brings to the table, but the best example is just to look at the capabilities of any modern game.

States
Similar to the States support in Flex, jSeamless introduces a similar, but far more powerful, concept in its framework. There are default states associated with basic components like Button (over, pressed, focused, etc.) but they can be modified, removed, and since they use Property references the activation of a State in one Component can modify the appearance of another Component.

No Effects
Yes, this sounds like a disadvantage rather than an advantage, but through my extensive use of Flex in jSeamless 1.0 it became very evident that Effects in their common state add more complexity and frustration than benefit to any complex application. The primary cause of this is what is known as "effect fighting". This occurs when you have two effects that are attempting to modify the same values on the same component toward different ends. In an environment where you want modularity this can be a common occurrence because you have no way of easily determining whether an effect is currently being enacted on the property you wish to enact an effect on, nor do you have the ability to gracefully handle that scenario. You end up with a component jumping around like it can't really decide where it wants to be on the screen. Beyond that, having to create an instance of an effect per scenario leads to a lot of code and having to monitor different scenarios (effect causing something to change, or a direct modification). Finally, you run the risk of something concurrently simply trying to set the value and it being overridden by an Effect in progress. After careful consideration the decision was made to leave Effects out entirely in favor of a new concept associated with every Property called PropertyAdjusters.

Property Adjusters
PropertyAdjusters, as the previous point states, is the alternative to Effects in jSeamless. This offers a simple, concise, and asynchronously mindful methodology of "adjusting" a property to some target. For example, rather than creating something like a MoveEffect, setting the start and end values, setting a duration, and playing it upon a Component you simply do something like this:
component.location.x.setAdjuster(new EasingPropertyAdjuster(Easing.LINEAR_IN, 5.0f));
component.location.x.set(500.0f);
That will apply an EasingPropertyAdjuster for every time the "set" method is invoked on that Property until the PropertyAdjuster is removed. This allows you to style your animations completely independent of the programmatic changes that happen elsewhere. Also, if you ever want to bypass a PropertyAdjuster you can simply invoke "setNow" on the Property to get you immediately to your destination regardless of any PropertyAdjuster that might be set. What's particularly nice about this is if half-way to 500.0f you make a call "set" passing 100.0f it will smoothly take the change and apply it to the animation in progress thus eliminating effect fighting and reducing the complexity of animations in programmatic UI development.

Easings
Simply put, easings are an algorithm that defines the path from one numeric value to another given a specific length of time. Rather than moving a box from left to right smoothly easings give you the ability to have it bounce into the new location.

For example, Easings simply add a polish to animations to move your application's effects from cheesy to professional. jSeamless supports all easings that Flex currently supports along with the ability to create your own with a simple to use interface to define the algorithm.

JMC Support / Media
If you are not familiar with JMC (Java Media Components) it is because it's not really talked about very often by itself. It is a media framework for Java that allows playing video and audio in many formats (FLV, H264, WMV, etc). Sun has blindly been pushing JavaFX which contains this very awesome new API, but they seem to be doing their best to block people from taking advantage of the functionality without buying into JavaFX lock, stock, and barrel. A few people like myself have spent a lot of time finding ways to make use of JMC in Java without the JavaFX dependencies and I have to say it has been very much worth the effort.

Swing Integration
It would be foolish to assume such a small endeavor like jSeamless could really garner the capabilities of a long-lived UI framework like Swing in the short-run. To that end there has been a lot of work done to provide Swing integration directly in jSeamless so all those custom components your application may need to take advantage of can still be used if you should decide to make the switch.

100% Java Framework
In jSeamless 1.0 the viability of Applets was nil, the ability to use OpenGL in the application was problematic (the whole Security Trust dialog), and the performance of Swing was lacking to put it mildly. All these things led to the decision to use Java on the back-end as a remote controller to a Flex front-end. The developer using jSeamless 1.0 only ever had to write Java code, but everything displayed in a Flex client. This was a cool idea, but in the years since that decision was made Java has come a long way. Applets have had new life breathed into them, Sun is magically trusted (JOGL signed JARs), and the world is our playground with the use of OpenGL. All of this was done in Java 1.6 update 10. It was this release of Java that made me have to rethink the whole concept of Java in the browser and Java on the desktop. jSeamless 2.0 has abandoned any ties to anything but straight Java (excepting of our JNI bindings to OpenGL via JOGL of course).

Scalable UI
With the introduction of OpenGL we now have the ability to define a "working resolution" that is not the same as the actual resolution. What this means is that you define your UI as an 800x600 statically defined UI and via the use of vector graphics (one of the very powerful features of jSeamless) have the content dynamically scale up to much higher resolutions "seamlessly" to the user. To them it appears that the UI was developed specifically for their screen size, but to you the development was much easier as you can utilize static pixel values that will get scaled dynamically to the proper resolution.

FXG and SVG Support
If you've never heard of FXG don't feel bad, it's a new feature Adobe has introduced with the new CS4 versions of their applications. It is designed as an XML-based format to portray vector and raster graphics exactly the same as they appear in Illustrator, Photoshop, etc. What is particularly cool about this is that not only does jSeamless have the ability to import FXG files, but the layer names and vector graphics are kept intact during the import. This means a graphical designer can create elements and name them in Illustrator, export it to FXG, you can then import the FXG file, and access the elements by their names and manipulate them directly.

Though not quite as cool, a still very useful feature is the ability to import SVG paths into jSeamless vector graphics.

Size and Location Support Percentages
A big frustration in Swing layout management has always been the pixel values you must put into location and size to determine where and how large your Component should be. This leads to a lot of boilerplate code to center, right-align, or arbitrarily place a component at a specific position based on percentage rather than pixel.

Flex did a much better job here by defining the ability to size components with a pixel or percentage. However, in jSeamless we're going for something much more powerful. We not only give size pixel and percentage values, we also allow defining of x and y location as pixel or percentages. Beyond that, we define an "alignment" to determine what point the percentage should be snapped to. Take this example:
component.location.x.set("50%");
component.location.x.align.set(HorizontalAlign.CENTER);
This sets the x location of the component to be 50% of it's parents size and then uses the CENTER alignment to make 50% represent where the component's "center" is giving us the ability to perfectly center the component within the parent without any boilerplate code.

Advanced Event System
One of the most powerful features of jSeamless 1.0 was the extremely powerful and flexible event system. It took many of the new concepts introduced in Flex, coupled them with a powerful multi-threaded ideology, and threw in a lot of new concepts nobody else had ever seen before to create what I humbly consider to be the best UI event system ever created. :)

Okay, yes, that's a pretty bold statement, but it's at least the most powerful event system I've ever seen in use anywhere...and I've used a lot of UI frameworks. With jSeamless 2.0 the same system was largely kept, but updated, performance improved significantly, and some additional features were added to hopefully take a great event system to the next level.

I would really like to get into specific details about the event system here, but as this post is already running long I'm going to have to make a special post to talk just about the event system in jSeamless as it's just too broad.

Vector Shapes
I've alluded to this already a few times, but jSeamless 2.0 is very centralized around vector graphics to allow scalable UI development, which is particularly beneficial in a 3D environment as content may scale up or down significantly depending on the current usage and perspective.

Suffice it to say, the support for vector graphics required to fully support the FXG format is a pretty broad range of features.

Fully Thread-Safe UI Framework
One of the major goals of jSeamless all along has been thread-safety. This is one area where Swing has always been a big disappointment. The need to use a SwingUtilities.invokeLater any time you want to make any changes to a component made code ridiculously ugly and frustrating to work with. Further, the single-threaded event system leading to a locked UI thread (by ignorant coders of course) is one of the primarily reasons people still think Swing responsiveness is poor at best. jSeamless 2.0 ran the same potential problems with OpenGL as it is required to be run in a single-thread, but all of jSeamless has been written to be thread-safe and hide any single-threaded functionality that must be handled directly in the OpenGL thread. To that end, we also introduce some very interesting multi-threaded rendering capabilities that allow components to render themselves in separate threads before pushing into the OpenGL stack.


jSeamless Google Code Project:
http://code.google.com/p/jseamless/

jSeamless 2.0 Branch in SVN:
http://jseamless.googlecode.com/svn/framework/branches/2.0/

jSeamless Forum:
http://forum.captiveimagination.com/index.php/board,14.0.html

This is definitely not an exhaustive list of features and functionality that jSeamless 2.0 provides. This is simply the functionality already being provided in the pre-alpha version of the framework. My goal in this post is hopefully to garner some interest and potentially some developers who might be interested in joining the project. The project is coming along quite well, but it is largely developed by a lone developer...me. I can always use another perspective and more help to bring this framework to its logical conclusion.

If you have any interest in joining the jSeamless project please contact me.

Java Media Components (JMC) in Swing

Published by Matt Hicks under , , , , , on Sunday, May 03, 2009
If you're like me and have been really excited by all the hype of JMC, but think of yourself as a Java developer and not a fly being beckoned to the newest scripting framework with its bright and illuminating glow (JavaFX that is) then JMC comes as something of a disappointment. After all, every article on the web referencing JMC seems to inseparably link JavaFX and JMC as if they absolutely *MUST* go together.

However, this is not the case. I've blogged before about the evils of JavaFX and how Java developers can leverage the functionality without selling your soul to the scripting demons:

http://www.matthicks.com/2009/02/i-hate-javafx-i-love-javafx.html

Someone else has taken this another step by taking the same approach for JMC:

http://nishimotz.com/2009/03/10/using-jmc-from-java/

Now, though what Takuya wrote is fully functional, I hate the idea of having to include JavaFX just to use JMC. After a bit of digging I have come to find what seems to be a hidden feature (maybe Sun just thinks the idea of someone using it outside of JavaFX is ridiculous and not worth mentioning?), the jmc.jar file you get with JavaFX has some interesting classes in it that you can take advantage of in your own Swing applications without any hackery at all:


package test;

import java.io.File;

import javax.swing.JFrame;

import com.sun.media.jmc.JMediaPlayer;

public class TestJMC {
public static void main(String[] args) throws Exception {
JFrame frame = new JFrame("Testing JMC"); {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);

JMediaPlayer player = new JMediaPlayer(new File("trailer_1080p.mov").toURI()); {
frame.add(player);
}

frame.setVisible(true);
}
}
}


I hate it when people give references like this and don't give any mention of a test file that can be used along with it, so to let you know what I used, I simply grabbed the trailer for "Big Buck Bunny" here:

http://www.bigbuckbunny.org/index.php/trailer-page/

What's awesome is that any one of them should work fine. Now, the player controls kind of suck, but in that same package there are other, probably more useful Swing classes: JMediaPane and JMediaView.

One last note. You need to include the jmc.dll (or the correct native lib for your OS) file in your library path to be able to play or you'll get unfriendly errors.

Have fun being able to leverage full video playing in your Swing applications.

I Hate JavaFX; I Love JavaFX!

Published by Matt Hicks under , , , , , on Friday, February 27, 2009
I've posted a few places and gotten into more than a few rants publicly about how awful I think it is that Sun has been pushing JavaFX to the Java community. This has not been based on what JavaFX provides, because I think that's absolutely spectacular, but rather that they created a whole new language (JavaFX Script) that they force you into using rather than Java code itself. I've heard all the well reasoned arguments for why this is from the binding support to simplified UI design concepts, but as a professional ActionScript developer as well as a professional Java developer, I believe that using a language that stinks of ActionScript is a major step backwards for the Java community. However, like I said, JavaFX has done an absolutely wonderful job of adding to the UI power of the Java arsenal though, and I want to use it. Since I know that the JavaFX Script compiles into Java byte-code, I knew there had to be some level of access to the underlying API structure directly from Java, but nobody seems to know how or where to do it. After quite a bit of digging I stumbled upon these two pages:

http://blogs.sun.com/javafx/entry/how_to_use_javafx_in

http://forums.sun.com/thread.jspa?threadID=5354921&tstart=1

They looked pretty ugly to me, but put me on the track to actually using JavaFX directly in Java without scripting. I sort of combined those two together to come up with what I think is a little bit more concise example:


package test;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGNode;

import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;

public class TestJFX {
public static void main(String[] args) throws Exception {
Group group = new Group(); {
}
Rectangle rect = new Rectangle(); {
rect.$width.setAsFloat(200.0f);
rect.$height.setAsFloat(200.0f);
rect.$fill.set(Color.$BLUE);
}
Text text = new Text(); {
text.$x.setAsFloat(20.0f);
text.$y.setAsFloat(20.0f);
text.$content.set("Greetings Earthling!");
text.$fill.set(Color.$WHITE);
}
group.$content.insert(rect);
group.$content.insert(text);
SGNode node = group.getSGGroup();
JSGPanel sgPanel = new JSGPanel();
sgPanel.setScene(node);

JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(sgPanel, BorderLayout.CENTER);

JFrame frame = new JFrame("Test JavaFX");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setSize(800, 600);
frame.setVisible(true);
}
}


This isn't the prettiest or most efficient way to code, but it's a start. Next I decided that I'd like to reproduce the Clock example that JavaFX shows here:

http://java.sun.com/javafx/1/tutorials/build-javafx-nb-app/

This gave me a much more practical run through JavaFX from the programmatic perspective and allowed me to verify that it is in fact possible to write a complete application using Java making calls to JavaFX:


package test;

import java.awt.BorderLayout;
import java.io.IOException;
import java.util.Calendar;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.sun.javafx.functions.Function0;
import com.sun.javafx.runtime.location.FloatBindingExpression;
import com.sun.javafx.runtime.location.FloatVariable;
import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGNode;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.lang.Duration;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.ArcTo;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;

/**
* @author Matt Hicks (matt@matthicks.com)
*/
public class Clock {
private float radius;
private float centerX;
private float centerY;

private Calendar calendar;
private int hours;
private int minutes;
private int seconds;

private FloatVariable hoursVariable;
private FloatVariable minutesVariable;
private FloatVariable secondsVariable;

public Clock() throws IOException {
// Initial setup
calendar = Calendar.getInstance();
radius = 77;
centerX = 144;
centerY = 144;

nextTick();

// Build JavaFX clock
Group group = new Group(); {
ImageView imageView = new ImageView(); {
Image image = new Image(); {
image.$bufferedImage.set(ImageIO.read(getClass().getClassLoader().getResource("resource/clock_background.png")));
}
imageView.$image.set(image);

group.$content.insert(imageView);
}

Group face = new Group(); {
Translate translate = new Translate(); {
translate.$x.setAsFloat(centerX);
translate.$y.setAsFloat(centerY);
}
face.$transforms.insert(translate);

// Every third hour
for (int i = 3; i <= 12; i += 3) {
Text text = new Text(); {
translate = new Translate(); {
translate.$x.setAsFloat(-5.0f);
translate.$y.setAsFloat(5.0f);
}
text.$transforms.insert(translate);

text.$font.set(Font.font("Arial", 16));

text.$x.setAsFloat(radius * ((i + 0) % 2 * (2 - i / 3)));
text.$y.setAsFloat(radius * ((i + 1) % 2 * (3 - i / 3)));
text.$content.set(String.valueOf(i));
}
face.$content.insert(text);
}

// Black circle for the rest of the hours
for (int i = 1; i < 12; i++) {
if (i % 3 == 0) {
continue; // Don't show a circle on every third hour
}

Circle circle = new Circle(); {
Rotate rotate = new Rotate(); {
rotate.$angle.setAsFloat(30.0f * i);
}
circle.$transforms.insert(rotate);
circle.$centerX.setAsFloat(radius);
circle.$radius.setAsFloat(3.0f);
circle.$fill.set(Color.$BLACK);
}
face.$content.insert(circle);
}

// Center circles
Circle circle = new Circle(); {
circle.$radius.setAsFloat(5.0f);
circle.$fill.set(Color.$DARKRED);
}
face.$content.insert(circle);
circle = new Circle(); {
circle.$radius.setAsFloat(3.0f);
circle.$fill.set(Color.$RED);
}
face.$content.insert(circle);

// Second hand
Line line = new Line(); {
Rotate rotate = new Rotate(); {
FloatBindingExpression exp = new FloatBindingExpression() {
public float computeValue() {
return seconds * 6;
}
};
secondsVariable = FloatVariable.make(exp);
rotate.$angle.bind(false, secondsVariable);
}
line.$transforms.insert(rotate);

line.$endY.setAsFloat(-radius - 3.0f);
line.$strokeWidth.setAsFloat(2.0f);
line.$stroke.set(Color.$RED);
}
face.$content.insert(line);

// Hour hand
Path path = new Path(); {
Rotate rotate = new Rotate(); {
FloatBindingExpression exp = new FloatBindingExpression() {
public float computeValue() {
return (hours + minutes / 60) * 30 - 90;
}
};
hoursVariable = FloatVariable.make(exp);
rotate.$angle.bind(false, hoursVariable);
}
path.$transforms.insert(rotate);

path.$fill.set(Color.$BLACK);

MoveTo e1 = new MoveTo(); {
e1.$x.setAsFloat(4.0f);
e1.$y.setAsFloat(4.0f);
}
path.$elements.insert(e1);
ArcTo e2 = new ArcTo(); {
e2.$x.setAsFloat(4.0f);
e2.$y.setAsFloat(-4.0f);
e2.$radiusX.setAsFloat(1.0f);
e2.$radiusY.setAsFloat(1.0f);
}
path.$elements.insert(e2);
LineTo e3 = new LineTo(); {
e3.$x.setAsFloat(radius - 15.0f);
e3.$y.setAsFloat(0.0f);
}
path.$elements.insert(e3);
}
face.$content.insert(path);

// Minute hand
path = new Path(); {
Rotate rotate = new Rotate(); {
FloatBindingExpression exp = new FloatBindingExpression() {
public float computeValue() {
return minutes * 6 - 90;
}
};
minutesVariable = FloatVariable.make(exp);
rotate.$angle.bind(false, minutesVariable);
}
path.$transforms.insert(rotate);

path.$fill.set(Color.$BLACK);

MoveTo e1 = new MoveTo(); {
e1.$x.setAsFloat(4.0f);
e1.$y.setAsFloat(4.0f);
}
path.$elements.insert(e1);
ArcTo e2 = new ArcTo(); {
e2.$x.setAsFloat(4.0f);
e2.$y.setAsFloat(-4.0f);
e2.$radiusX.setAsFloat(1.0f);
e2.$radiusY.setAsFloat(1.0f);
}
path.$elements.insert(e2);
LineTo e3 = new LineTo(); {
e3.$x.setAsFloat(radius);
e3.$y.setAsFloat(0.0f);
}
path.$elements.insert(e3);
}
face.$content.insert(path);

group.$content.insert(face);
}
}

Timeline timeline = new Timeline(); {
timeline.$repeatCount.setAsFloat(Timeline.$INDEFINITE);

KeyFrame kf = new KeyFrame(); {
kf.$time.set(Duration.valueOf(1000.0f));
kf.$canSkip.set(true);
kf.$action.set(new Function0() {
public Void invoke() {
nextTick();
return null;
}
});
}
timeline.$keyFrames.insert(kf);
}

// Display in Swing
SGNode node = group.getSGGroup();
JSGPanel sgPanel = new JSGPanel();
sgPanel.setScene(node);

JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(sgPanel, BorderLayout.CENTER);

JFrame frame = new JFrame("JavaFX Clock Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setSize(800, 600);
frame.setVisible(true);

timeline.play();
}

public void nextTick() {
calendar.setTimeInMillis(System.currentTimeMillis());
seconds = calendar.get(Calendar.SECOND);
minutes = calendar.get(Calendar.MINUTE);
hours = calendar.get(Calendar.HOUR_OF_DAY);

if (secondsVariable != null) {
secondsVariable.invalidate();
minutesVariable.invalidate();
hoursVariable.invalidate();
}
}

public static void main(String[] args) throws Exception {
new Clock();
}
}


Now, I did make some slight alterations as the original example uses java.util.Date calls that are deprecated, so I updated to using Calendar instead. Also, I had a little trouble with the binding functionality and had to make calls to invalidate in the nextTick() method. Other than that I stayed quite true to the example and the code works quite nicely.

This is the first step in what I'm ultimately planning as a wrapper around Swing and JavaFX to make more powerful UIs without using a crappy scripting language. :)

See this re-output as an Applet:
http://captiveimagination.com/download/clock/clock.html

Flex WebBrowser Component

Published by Matt Hicks under , , , , , on Wednesday, February 18, 2009
I've been working on an acceptable solution to display web pages within my Flex applications and as any of you know that have done any research on it will find, it's frustrating how lacking Flex is in support for this. The ideal solution would be for Flex to provide a fully functional component that renders web pages utilizing the native web browser. Alas, it would seem that it's far too complicated for them to leverage the browser they are already running in. Instead, their solution is to create components that support just enough HTML to be completely annoying since you can't get anything really useful to display well. Alright, so enough of that, like most of my posts, I try to mix rant and useful information, so lets get to the latter.

Okay, so the first thing that I discovered is that the only way to display web pages within my Flex content was to use IFrames. There are other possibilities, but after investigation with each they all come up with major flaws (primarily centered around lacking functionality) and IFrame support seems to be the best solution out of a bunch of bad solutions.

Yes, I'm sure if you've spent any time looking into this you'll already know that there are plenty of people that have already written IFrame support components in Flex and they work moderately well. However, there are some major pitfalls they have not resolved that I find unacceptable:
  1. Clipping - Because IFrames float above the Flash context they float above EVERYTHING. So not only do not get proper clipping of an Alert or anything else appearing above the component, you don't get proper clipping when it's inside of a container with scrollbars. This extremely limits the usefulness of the component and makes it almost useless in many sites
  2. Size and location updates. So many of these implementations of IFrame support do such an awful job of properly sizing and adjusting the frame as the Flex container is adjusted.
  3. Multiple components on the same page. In many cases I would like to have several IFrames being displayed on the page at one time and very few of the implementations have support for multiple being displayed at any time.
Yes, all of those are valid, but there are solutions available for all but #1. For a while I wondered if it was even possible to solve, but have since proven otherwise. :)

The first hurdle was figuring out a way to clip IFrame content. This was actually a lot easier than I expected it to be. I simply create a DIV, use absolute positioning, overflow to hidden, and add an iframe to it using relative positioning. From there it's just a simple matter of updating the location and size of the "visible area" for the DIV and adjusting the IFrame within it to clip the relevant areas. This does leave us without a perfect solution as we can obviously only show a single rectangular clipping area, but it's a lot better than no clipping at all.

Here's the code for the webbrowser.js file:
// WebBrowser specific code
function verifyCreated(id) {
var div = document.getElementById('div' + id);
if (div == null) {
div = document.createElement('div');
div.setAttribute('id', 'div' + id);
div.style.position = 'absolute';
div.style.visibility = 'hidden';
div.style.overflow = 'hidden';
var body = document.getElementsByTagName("body")[0];
body.appendChild(div);
}
var iframe = document.getElementById('iframe' + id);
if (iframe == null) {
iframe = document.createElement('iframe');
iframe.setAttribute('id', 'iframe' + id)
iframe.style.position = 'relative';
iframe.style.backgroundColor = 'white';
iframe.style.borderStyle = 'none';
iframe.setAttribute('frameborder', '0');
div.appendChild(iframe);
}
return iframe;
}

function updateBrowser(id, x, y, width, height, clipX, clipY, clipWidth, clipHeight) {
if ((width <= 0) || (height <= 0)) {
hideBrowser(id);
return;
}
var iframe = verifyCreated(id);
iframe.style.left = -clipX;
iframe.style.top = -clipY;
iframe.style.width = width;
iframe.style.height = height;
iframe.style.display = '';

var div = document.getElementById('div' + id);
div.style.left = x + clipX;
div.style.top = y + clipY;
div.style.width = clipWidth;
div.style.height = clipHeight;
div.style.visibility = 'visible';
div.style.display = '';
}

function loadURL(id, url) {
var iframe = verifyCreated(id);
iframe.src = url;
}

function hideBrowser(id) {
var div = document.getElementById('div' + id);
div.style.visibility = 'hidden';
div.style.display = 'none';
}
So that solves the dilema of clipping. The next hurdle, which I was quite surprised was a hurdle at all, was the of determining the visible bounds of a Flex component. You see, I wrote a WebBrowser Flex component that represents the IFrame within Flex and receives all the events for changes to size, location, visibility, etc. and then relays them to the IFrame it manages. However, Flex seems to have absolutely no support for finding the visibles bounds on a Component. So, as my solution to most things, I wrote my own:

        public static function getVisibleBounds(component:UIComponent):Rectangle {
var r:Rectangle = new Rectangle();

var step:Number = 50;

var best:Rectangle = new Rectangle();

var yOffset:Number = 0;

// Find largest bounding area
do {
nextBounds(component, yOffset, step, r);
yOffset += r.y + r.height + step;

if (r.width * r.height > best.width * best.height) {
best.x = r.x;
best.y = r.y;
best.width = r.width;
best.height = r.height;
}
} while (r.x != -1);

// Expand bounds broadly
expandBounds(component, best, step, step);

// Expand bounds narrowly
expandBounds(component, best, 1, step);

component.graphics.clear();
component.graphics.beginFill(0xffffff);
component.graphics.drawRect(best.x, best.y, best.width, best.height);
component.graphics.endFill();

return best;
}

private static function expandBounds(component:UIComponent, r:Rectangle, step:int, stepJump:int):void {
// Look up
while (validateHorizontal(component, r.x, r.y - step, r.width, stepJump)) {
r.y -= step;
r.height += step;
}

// Look down
while (validateHorizontal(component, r.x, r.y + r.height + step, r.width, stepJump)) {
r.height += step;
}

// Look left
while (validateVertical(component, r.x - step, r.y, r.height, stepJump)) {
r.x -= step;
r.width += step;
}

// Look right
while (validateVertical(component, r.x + r.width + step, r.y, r.height, stepJump)) {
r.width += step;
}
}

private static function validateHorizontal(component:UIComponent, x:int, y:int, width:int, step:int):Boolean {
for (var i:int = x; i <= width; i += step) {
if (!isUnderPoint(component, i, y)) {
return false;
}
}
if (isUnderPoint(component, x, y)) {
if (isUnderPoint(component, x + width, y)) {
return true;
}
}
return false;
}

private static function validateVertical(component:UIComponent, x:int, y:int, height:int, step:int):Boolean {
for (var i:int = y; i <= height; i += step) {
if (!isUnderPoint(component, x, i)) {
return false;
}
}
if (isUnderPoint(component, x, y)) {
if (isUnderPoint(component, x, y + height)) {
return true;
}
}
return false;
}

private static function nextBounds(component:UIComponent, yOffset:Number, step:int, r:Rectangle):Rectangle {
r.x = -1;
r.y = -1;
r.width = -1;
r.height = 0;

var p:Point = findFirstVisible(component, yOffset, step);
if (p != null) {
r.x = p.x;
r.y = p.y;
for (var y:int = p.y + step; y <= component.height; y += step) {
var currentWidth:Number = 0;
for (var x:int = p.x + step; x <= component.width; x += step) {
if (isUnderPoint(component, x, y)) {
currentWidth += step;
}
}
if (r.width == -1) {
r.width = currentWidth;
} else if (r.width > currentWidth) {
return r;
}
r.height += step;
}
}

return r;
}

private static function findFirstVisible(component:UIComponent, yOffset:Number, step:int):Point {
for (var y:int = yOffset; y <= component.height; y += step) {
for (var x:int = 0; x <= component.width; x += step) {
if (isUnderPoint(component, x, y)) {
return new Point(x, y);
}
}
}
return null;
}

private static var underPoint:Point = new Point();
public static function isUnderPoint(component:UIComponent, localX:Number, localY:Number):Boolean {
underPoint.x = localX + 1;
underPoint.y = localY;
underPoint = component.localToGlobal(underPoint);
var a:Array = Application.application.stage.getObjectsUnderPoint(underPoint);
for (var i:int = a.length - 1; i >= 0; i--) {
var c:UIComponent = getComponent(a[i]);
if (c != null) {
if (c.mouseEnabled) {
return c == component;
}
}
}
return false;
}

public static function getComponent(obj:DisplayObject):UIComponent {
while (obj != null) {
if (obj is UIComponent) {
return UIComponent(obj);
}
obj = obj.parent;
}
return null;
}


Yes, that's an awful lot of code, but it does work, and it works quite well. I find the largest bounding visible rectangular area for the Component and return a Rectangle representing it. I work in large steps (50 pixels at a time) to increase the performance and then make minor adjustments at the end to correct for the margin of precision loss.

The only thing still necessary to post is the WebBrowser Flex component:

    import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.external.ExternalInterface;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Timer;

import mx.containers.Canvas;
import mx.core.Application;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.events.MoveEvent;
import mx.events.ResizeEvent;

public class WebBrowser extends Canvas {
private static var ID_GENERATOR:int = 0;

[Inspectable(defaultValue=null)]
private var pageUrl:String = null;
private var initted:Boolean = false;

private var changed:Boolean;
private var lastChanged:Number;
private var hidden:Boolean;

private var lastX:Number = -1;
private var lastY:Number = -1;
private var lastW:Number = -1;
private var lastH:Number = -1;

public function WebBrowser() {
super();
id = String(++ID_GENERATOR);
this.addEventListener(FlexEvent.CREATION_COMPLETE, onFlex, false, 0, true);

var timer:Timer = new Timer(15);
timer.addEventListener(TimerEvent.TIMER, update);
timer.start();

setStyle('borderThickness', 0);
clipContent = false;

changed = false;
hidden = true;

lastChanged = -1;
}

private function onEvent(event:Event):void {
if (event.target is UIComponent) {
if (event.target.owns(this)) {
if (event.type == 'remove') {
// Hide it
visible = false;
}
validateWindow();
}
}
}

private function onFlex(event:FlexEvent):void {
validateWindow();
if (pageUrl != null) ExternalInterface.call('loadURL', id, pageUrl);
systemManager.addEventListener(FlexEvent.HIDE, onEvent, true, 0, true);
systemManager.addEventListener(FlexEvent.SHOW, onEvent, true, 0, true);
systemManager.addEventListener(MoveEvent.MOVE, onEvent, true, 0, true);
systemManager.addEventListener(ResizeEvent.RESIZE, onEvent, true, 0, true);
systemManager.addEventListener(FlexEvent.REMOVE, onEvent, true, 0, true);
systemManager.addEventListener(FlexEvent.ADD, onEvent, true, 0, true);
initted = true;
}

private function onHide(event:FlexEvent):void {
ExternalInterface.call('hideBrowser', id);
}

private function isVisible():Boolean {
var obj:DisplayObjectContainer = this;
while (obj != Application.application) {
if (obj == null) {
// Removed from container
return false;
}
if (!obj.visible) {
return false;
}
obj = obj.parent;
}
return true;
}

public function validateWindow():void {
if (!isVisible()) {
onHide(null);
return;
}
changed = true;
}

private function update(evt:TimerEvent):void {
var time:Number = new Date().time;

var p:Point = new Point(0, 0);
p = localToGlobal(p);
if ((p.x == 0) && (p.y == 0)) {
return;
}
if ((lastX != p.x) || (lastY != p.y) || (lastW != width) || (lastH != height)) {
changed = true;
} else if (isVisible() == hidden) {
changed = true;
} else if ((lastChanged != -1) && (time - lastChanged > 500)) {
changed = true;
}

if (changed) {
changed = false;
lastChanged = time;

if (isVisible()) {
hidden = false;
lastX = p.x;
lastY = p.y;
lastW = width;
lastH = height;

var rect:Rectangle = FlexUtilities.getVisibleBounds(this);
ExternalInterface.call('updateBrowser', id, p.x, p.y, width, height, rect.x, rect.y, rect.width, rect.height);
} else {
hidden = true;
onHide(null);
}
}
}

public function set source(_pageUrl:String):void {
pageUrl = _pageUrl;
if (initted) {
ExternalInterface.call('loadURL', id, pageUrl);
}
}

[Bindable(event="changeUrl")]
public function get source():String {
return pageUrl;
}
}
Well, that does it. I hope you found this useful and proof that IFrame support can actually be done moderately well in Flex. The biggest problem I still have is that it can still be moderately slow, but that's an underlying flaw of the IFrame displaying in Flex and not something I can do anything about unfortunately.

Java Delegates

Published by Matt Hicks under , , , , on Tuesday, July 01, 2008
If you're searching the internet for the title of this post you'll see a lot of people ranting about how Java doesn't have Delegate support. Though I have been one of these people, and continue to be frustrated that there is no native solution, that is not the purpose of this post.

I write this to say I've created what I would consider to be a pretty clean alternative to native delegates in Java using reflection. I created this as a feature in jSeamless and have been using it heavily for a while, but after a few people asking about support in non-jSeamless applications for my friendly Delegate support I decided I would remove it from jSeamless and make it a stand-alone API that anyone can use.

The Delegate implementation I find myself using more than anything else is MethodDelegate. It provides the ability to reference a specific method on a specific object that can be invoked. For example:

Flash/Flex URLRequest Upload Security Hack

Published by Matt Hicks under , , , , on Friday, December 28, 2007
It's been a while since I posted and after dealing with this horrid bug in Flash I figured it would be a great topic to get me back on track.

So, apparently there's this nifty little bug in Flash/ActionScript with the URLRequest object when you attempt to do a file upload, it uses a completely different browser session than the web browser or any other requests made from within Flash (image loading, sound loading, resource loading, etc.). This isn't a problem unless you care anything about security...and unfortunately most of us do. So the project I'm currently working on uses JCIFS (http://jcifs.samba.org/) for SSO, which is actually very nice by the way, and it uses a servlet filter configured in the web.xml to authenticate the user before they ever hit the page, so by the time they reach the Servlet they've properly been authenticated and I don't have to worry about rogue users.

Okay, so that all works well and good until I try to do a file upload. I try to establish a URLRequest to my JSLServlet (of course this is jSeamless) that I use for everything else, but this time I get a nifty little login prompt using basic authentication. Now, this is of course bad, but what makes it even worse is that Flash simply prompts you and then disregards it and streams the upload into the outer darkness (where there is weeping and gnashing of teeth) so the upload from the Flash perspective worked and uploaded fully (note, before I even enter anything into the login prompt) but the server never receives the upload at all. If I enter my credentials it accepts it and then disappears, but really doesn't care anything about it.

Okay, now for the hack. Now, for you programmers that are faint of heart, don't try this at home. For the rest of us that have to do the job no matter how dirty it might get, please forgive me for what follows...if there were another way I would have done it.

Alright, so I create a new Servlet filter called UploadOverrideFilter (yes, you see where this is going) that gets put in the filter order before the NtmlHttpFilter (JCIFS filter for SSO) that detects if the reference is made to an upload (endswith("jslupload") in my case). Now, what took me a bit of work to figure out is that all mechanism for referencing directly to the Servlet that the filter can pass off to is either barred or deprecated (from ServletContext there are methods for getting a Servlet, but they always return null since deprecation) so I pull out my ugly stick and turn JSLServlet into an evil beast by maintaining a static reference to "instance" that is the initted reference to the currently context JSLServlet instance. Then I simply reference that static JSLServlet instance and explicitly call doPost(...) instead of passing off to the filter chain. See the source code for yourself:

public class UploadOverrideFilter implements Filter {
public void init(FilterConfig config) {
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (((HttpServletRequest)request).getRequestURI().endsWith("jslupload")) {
JSLServlet.instance.doPost((HttpServletRequest)request, (HttpServletResponse)response);
} else {
chain.doFilter(request, response);
}
}

public void destroy() {
}
}

Yep, it's having to write code like this that will be the death of me...a very good reason why I prefer to stick with 100% Java whenever possible is so I don't have to write hacks like this.

Well, I guess it wasn't as bad as it could have been, but it's still a hack and it's things like this that keep me up at night in the cold sweats.

Flash/Flex URLRequest Upload Security Hack - Part 2

Published by Matt Hicks under , , , , on Friday, December 28, 2007
So I lied, apparently my hackery wasn't enough to appease IE even though Firefox happily worked going forward. Apparently in IE it determines, "Oh, I've been authenticated on this URL before...so lets send broken authentication information instead of an upload", and then no matter what you respond back to the request with it just ignores it an on the Flash side acts like it sends the file (very quickly), but never actually comes across.

So now we must expand the previous hackery to not only ignore authentication on uploads, but we have to send to a different "url" in order to keep Flash from thinking it needs to authenticate. I originally tried doing a variation on the directory structure (ie. /authenticated and /unauthenticated), but it's a tricksy URLRequest and decided that it was the same host so it really wanted to send broken authentication information.

My solution? Make Tomcat listen on another port by adding the following line to my server.xml:


<Connector connectionTimeout="20000" maxThreads="150" port="15000" protocol="HTTP/1.1" redirectPort="8443"/>


Then I told my upload to send to the exact same URL except on a different port. I still had to have my security hackery to keep it from requesting authentication, but that did the trick. Now both IE and Firefox can upload files in a JCIFS protected container and the client is none the wiser...unless of course a firewall is blocking that port for which they are trying to upload to....but such are the hacks we must work with when dealing with Flash.

On a side note I will say that Flex 3 has functionality built-in (apparently they got enough rocks through their windows from 2.01 to make them realize they needed to fix it) to tell it to handle authentication or not via a boolean flag. None of this would have been necessary if they would have had the fore-sight to implement that in the first place, but alas, mine is not to reason why...

Applet Roadblock

Published by Matt Hicks under , , , , , on Friday, December 28, 2007
My massive hack for native drag-and-drop in jSeamless Flex implementation is functional, but only in Firefox. Apparently there is an interesting "feature" in IE that even though you may sign your Applet and the user grants that they way to trust said Applet, it still never gives you read access to the file system.

That being said, here is my outlined approach for another hack that avoids the use of an Applet in favor of Java Web Start. I know Java Web Start can do what I want to do, but to my knowledge there is no way to communicate directly between the client-side web site and the JWS instance.

  1. Load the JWS application that stays hidden

  2. Load the Flex content page

  3. Listen via JavaScript to the mouse cursor entering the browser window - throw an event to the server upon entry

  4. Server sends event back to JWS (either socket or delayed Ajax necessary for both JWS and Flex)

  5. JWS application triggers the single-pixel-at-mouse-position-window that is listening for dragging

  6. If JWS doesn't receive a drag enter event it goes back to sleep and hides our friendly, yet scary, window

  7. If a drag enter is thrown it continues to follow the mouse until either the mouse exits the window (another event thrown by JavaScript to Flex to the Server and back to JWS) or a drop event is triggered in the window.

  8. If JWS receives a window exit event it goes back to sleep.

  9. If JWS receives the drop event a new event is sent down to the server with the list of files dropped.

  10. Server sends an event to Flex requesting the current component the mouse is over and temporarily stores the list of files dropped via a request id.

  11. Flex determines the current component the mouse is over and sends an event back to the server with that id.

  12. Server triggers internal jSeamless event for file dnd with the list of files and the component id (if the component accepts the drop).

  13. Upon server-side accept of a file an event is sent to JWS to stream the file

  14. JWS receives file stream request and streams the file to the server.


How's that for evil? I thought the original hack was bad, but this is just downright insane. However, it would seem this is the only plausible way to get native drag and drop support.

Flex Native Drag-and-Drop: The Massive Hack

Published by Matt Hicks under , , , , , , on Friday, December 28, 2007
I had made the commitment a while back that I was going to add complete and perfect drag-and-drop support to jSeamless. The Flex Implementation proclaims support for DnD so I've just pushed off the investigation up until recently. However, now that I've come to implement this great functionality I realize that there is absolutely no support for native DnD. What I refer to as "native DnD" is the ability to drag a file or any other "draggable" content from outside of the application into the application and allow it to pick up and use that content.

Okay, so I figure I'll just do the same type of JavaScript hacks I've done all along to get missing functionality into Flash. To my surprise HTML/JavaScript has no native DnD support either. At this point I'm not only surprised, but afraid my dream of a beautiful drag-and-drop solution for jSeamless is in danger of never reaching fruition.

So I spent the day brainstorming with a colleague about how this can be done. Honestly, there was never a viable solution that wasn't a massive hack, and what we ended up with was actually far better than expected. The solution consisted of using a signed Java Applet to display a single pixel JWindow linked to the cursor when the cursor enters the browser window, it is able to use this as a check to see if the cursor is dragging a droppable item. If it is not carrying something into the browser it then disables itself until the cursor leaves the browser and re-enters again. However, if it is carrying something it remains locked to the tip of the cursor and accepts the droppable wherever they drop it in the application. This JWindow intercepts the drop event, passes an event to JavaScript, JavaScript passes an event to the Flash content and is handled appropriately from there. The event is assigned an ID that can be referenced back from the Flash, to the JavaScript, to the Applet in order to initiate the download at any point in the future.

Yes, this is a massive hack, but does provide a solution that is quite seamless to the user apart from the nasty, "Would you like to grant access to this application to do whatever it wants to your hard drive?" (okay, so it's a little friendlier than that) prompt that must be displayed for the Applet to be able to know pointer location and be able to actually read the file contents from the hard drive.

Fortunately internal drag-and-drop is quite easy to write into Flex. If all goes well, this will all be finished and useful in jSeamless next week. However, for reasons of the aforementioned "evil prompt" it will be disabled by default and will have to be specified to be turned on to be used.

Today was massive hack day. ;)

jSeamless: The Conspiracy

Published by Matt Hicks under , , , , , , on Tuesday, September 18, 2007
Okay, so this probably doesn't par up to the JFK assassination, those crop circles, or how in the world John Locke can survive a bullet in the chest, but it's starting to really bother me.

I developed jSeamless with the intent of "seamlessly" bringing technologies together to make life easier on the developer. However, I'm starting to realize that the people that make these technologies would rather not see this happen. I never considered that anyone could understand the concepts of what I'm trying to do and actually put in some extra effort to stop me. I figured at worst people would just not care and let it pass by without another look, but that's not what seems to be happening.

First Point - Java.net

Now that jSeamless has become much more stable and has the majority of features necessary to release I thought java.net would be the place to go to get some good advertising. So I filled out a form requesting that jSeamless be featured along with an article I had written hoping to get some additional developer interest in the framework. After a couple weeks I e-mailed the editor and asked about it. The basic summation was that it would be a conflict of interest to post anything on their site about jSeamless since it directly competes with Swing because it uses Flash as the reference implementation. Now, I can understand if the purpose of jSeamless was to only do Flash development, but jSeamless is about abstraction and it just so happens the only currently completed implementation uses Flash content. I was told to send them another e-mail when there's a completed Swing implementation...we'll see how that goes.

Point Two - FlexCoders

I hang out on the FlexCoders Yahoo! Group to find answers to problems I'm having with Flex integration into jSeamless and to find out new extensions that are being written to Flex that I might be able to integrate or derive ideas from for jSeamless. I decided to post a message to the group asking for feedback from the Java developers that are also developing in Flex to get some ideas of what features they would look for in an API like jSeamless. I actually got some really good responses, I messaged back with additional information and then suddenly all the posts disappeared without a trace.

There was no e-mail letting me know I had violated some rule of the group or anything. I know the group is run primarily by people that work at Adobe, so I can only assume it had to do with marketing a framework that could take away revenue from their commercial products.

There actually several other scenarios that have had similar results, but I'm really starting to feel a lot of resistance for this system. I never imagined that I was developing something controversial or even something that would get anything worse than indifference about. This causes some problems since I was hoping to get some support from companies like Adobe or Sun in the long-run, but it would seem they don't really want such a project to succeed.

I guess this doesn't really classify as real conspiracy, but it bugs me so I figured I would share my annoyance with the world. :)

Stressing

Published by Matt Hicks under , , on Wednesday, August 15, 2007
No, in a good way. :)

We've been working through a lot of stress testing at work for jSeamless to prove that it can stand up to an unreasonable load only exceeded by getting "slashdotted. We have faired quite well and we're currently working to get the document released for public "consumption". This will be a really great proof of the stability of jSeamless and put to rest a lot of the fears people have of its viability in a heavy traffic scenario.

Multiplayer Sudoku

Published by Matt Hicks under , , on Tuesday, July 03, 2007
I've been trying to think of some good examples of jSeamless that wouldn't take too much time to write, but would show the power of jSeamless and some of its capabilities. To that end I've started developing a multiplayer Sudoku game. The puzzle is generated and displayed to all connected players. As each person provides a correct number they get points and that field is "solved" on all other player's board as well. If you get a number wrong you lose points. A winner is decided by how whoever had the most correct numbers in that puzzle. I'm creating a whole account management system, scoring system, database logging and statistics, and internal chat. This should be a pretty fun game when it's finished.

Here's an early screenshot:

screenshot012.png

Flex: Love and Hate

Published by Matt Hicks under , on Thursday, June 21, 2007
Adobe Flex 2.01 is a very good framework and it is so much better than practically any other web-based UI framework in existence today, but there are so many bugs in the code and so many restrictions that are very difficult to get around I'm locked into a love and hate relationship with it.

I'm using Flex for the reference implementation of jSeamless and it is going quite well over-all, but I'm finding myself re-writing component after component because of either bugs or lack of features. The good thing about this though is that the entire Flex source code is available within the SDK, so I can see exactly what they are doing and how they are restricting me or causing bugs to occur.

My single biggest complaint about Flex is their complete lack of threading "support". That is not to say it is single-threaded. Quite the contrary. Everything is asynchronous in Flex, but thread-safety is an unknown term to the Flex team I believe. There is no way to synchronize, lock, or maintain good concurrency in the system and many a crash has been due to this. In jSeamless I have a full system I wrote to offer some concept of synchronization and though extremely limited because of ActionScript 3 support not being there, it works pretty well.

I'm about to completely re-write the way Effects are called in the Flex implementation of jSeamless because it is causing errors to occur and also offers no way of disabling effects. I'm a Java developer and writing in ActionScript 3 is really not my idea of a good time, so every line of code increases my frustration.

On the bright side, jSeamless has far exceeded the capabilities of what Flex can do because of its "flexibility" and for that I'm extremely thankful.

Is Success Good?

Published by Matt Hicks under , on Tuesday, June 19, 2007
I know that seems like a strange question to ask, but it's one I often ask myself. In many ways I've been extremely successful throughout my life, and it occurs to me that many of those successes were good successes, and many of them were bad successes. Most of the time it's easy to tell the difference. Sometimes, however, it's very difficult to discern.

I've been feeling this way recently regarding jSeamless. I believe it's one of the greatest development endeavors of my life thus far and have no intention of abandoning it, but it is now beginning to develop a following of users, which is great, but the majority of these users simply use the API and then post when something is missing or broken. Don't get me wrong, I have no problem with this, but I'm getting extremely bogged down with providing functionality for these users instead of them helping and committing to the project themselves. I believe in the long-run it will get better and eventually I'll have some strong developers that are willing to help. For now though, it's draining to spend all day at work writing code to support them, and then coming home and writing code to support the jSeamless community.

I guess a project has to catch on at its own pace, I just wish there were more people interested in helping. jSeamless is becoming a large project and I'm just one person. I often brag about how much this one person can do, but I realize as well as anyone that my limitations are definitely there.