Tuesday, August 25, 2009

JavaFX onKeyTyped for a Scene [Update]

[Update]
Since javaFX 1.2 nodes have to set the "focusTraversable" property to "true" in order the receive key events.
[/Update]

keyTyped events are easy to use in JavaFX. Just add a function to onKeyTyped on a node and this node will be notified if a key is typed.

But what if you start with an empty scene. There are no nodes which can receive the event. And there is no onKeyTyped for a scene or stage.

I found two solutions for this problem. Both are some kind of a hack but they work:

1. Create a CustomNode without any graphics and just a onKeyTyped and add this to the scene content.

2. (my preferred solution) Use a Group which is empty at the beginning and later contains the scenes nodes. Groups do have onKeyTyped.

Here is an example:

var stage = Stage {
title: "Application title"
fullScreen: true
scene: Scene {
content: [
Group {
focusTraversable: true
content: [
]
onKeyTyped: function( e: KeyEvent) : Void {
System.out.println("Hello");
}
}
]
}
}

Monday, August 24, 2009

Restful AtomPub Services with HTTP Basic Authentication in Azure

Implementing a service with an AtomPub interface on Azure is quite easy. As a starting point I used the PictureRestService example from:

http://code.msdn.microsoft.com/wcfazure/Wiki/View.aspx?title=PictureRestService

Next step is to restrict the access to the interface methods to a set of authorized users.

As a starting point for this I used:

http://msdn.microsoft.com/en-us/library/dd203052.aspx

As mentioned in this guide the first thing to do is to check if the request contains an user authentication. For this the HTTP request has to contain an "Authorization" header. For a basic user name password authentication the value of this header has to be the string "basic" followed by the user name a ":" and the password. User name, ":" and password are stored in a Base64 encoded string.

Here is an example which checks if the user is "eggeral" or "sven":

private bool AuthenticateUser(out string userName)
{
userName = null;
WebOperationContext ctx = WebOperationContext.Current;
string authHeader = ctx.IncomingRequest.
Headers[HttpRequestHeader.Authorization];
if (authHeader == null)
{
return false;
}
if (!string.IsNullOrEmpty(authHeader))
{
if (authHeader.StartsWith("basic ",
StringComparison.InvariantCultureIgnoreCase))
{

string userNameAndPassword = Encoding.Default.GetString(
Convert.FromBase64String(authHeader.Substring(6)));
string[] parts = userNameAndPassword.Split(':');
userName = parts[0];
string password = parts[1];

if (userName == "eggeral" && password == "secret")
{
return true;
}
if (userName == "sven" && password == "sven")
{
return true;
}

}

}
return false;
}


If the request does not contain an "Authorization" header we have to request one from the client (for example Firefox or Internet Explorer). This is done be answering the request with the status 401 Unauthorized and a "WwwAuthenticate" header which specifies the authentication mechanism. The client will then prompt the user for user name and password and resend the request to the service.

Here is the code which handles this for the "PutEntry" method:

protected override SyndicationItem PutEntry(string collection,
string id,
SyndicationItem entry)
{
string userName;
if (!AuthenticateUser(out userName))
{
WebOperationContext.Current.OutgoingResponse.StatusCode =
HttpStatusCode.Unauthorized;
WebOperationContext.Current.OutgoingResponse.
Headers.Add(
HttpResponseHeader.WwwAuthenticate,
"Basic realm=\"Task Management\"");
return null;
}
// Do some stuff and return an entry.

}


Of course basic authentication is not secure, but its an easy way to get started. For production systems implement a more secure method as described in Microsofts guide for Restful web services (link above).

Tuesday, August 11, 2009

Using devenv.exe in MSBuild Files and TFS

I need to run devenv.exe on our team build (TFS) in order to compile certain projects (for example: setups).

If, like in our case, the tfsbuld.proj file is not only used on the TFS but also for local builds you have to find out here devenv.exe actually is (it depends on your Windows version an language).

The trick is that MSBuild can read registry information. So you can get the install directory for Visual Studio from the registry and then use an Exec task to run devenv.exe.

Here is how this works:


<Exec Command="&quot;$(Registry:HKEY_LOCAL_MACHINE\\Software\Microsoft\VisualStudio\9.0@InstallDir)\Common7\IDE\devenv&quot; &quot;$(SolutionRoot)\mysolution.sln&quot; /Build Release /project &quot;setupdir\setupproj.vdproj" /projectconfig Release"/>

Thursday, July 16, 2009

Multi-Tenant Systems (Mandantenfähigkeit)

I am currently searching for design patterns and good practices for developing multi-tenant systems.

The problem I try to solve is how to design a system so I do not have to add the tenant id to each and every method call.

The first resource I found was . This describes different approaches on how to design the data layer for multi-tenant systems. Basically you may choose between a database for each tenant, a schema for each tenant or a shared database with tenant ids stored in each table.

The second resource is a design pattern at which has a broader view on the topic and does not only discuss data but resources in general.

Accessing a resource is done using the following steps:

* Get the current users tenant
* Build a filter for the resource
* Get the resource using the filter

Of course this does not solve my parameter per method problem. But maybe it brings me a step closer.

Friday, May 22, 2009

Post JavaFX Applications on Blogger

There are several examples of blogs out there where people post JavaFX examples and applications as part of a blog post.

I wanted to do this on Blogger too but there are some problems with that.

The suggested method to deploy JavaFX applications via a web site is to upload the .jar and use some JavaScript which places an Applet tag into your page.

First problem: You can not upload .jar files to Blogger. (As far as I know).

Second problem: You can not use JavaScript in a blog post. You can add JavaScript to your template but that does not help with JavaFX applications.

I do not have a real solution for the first problem. But you can of course put your .jar on any website you want. I chose my Google Pages account to do so.

For the second problem I used Firebug. With Firebug you can extract the code added to your page by the JavaFX JavaScripts. I then just added this directly to my post which seams to work (well it does if you see Splash at the and of this post).

The code for my Splash example is:

<div id="deployJavaApplet1Overlay" style="background: white none repeat scroll 0% 0%; position: absolute; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; visibility: hidden;">
<table margin="0" padding="0" border="0" height="200" width="200">
<tbody>
<tr>
<td align="center" valign="middle">
<img imgheight="100" src="http://dl.javafx.com/javafx-loading-100x100.gif" width="100" />
</td>
</tr>
</tbody>
</table>
</div>
<div id="deployJavaApplet1" style="position: relative; left: 0px;">
<applet archive="http://alexander.egger.googlepages.com/Splash.jar,http://dl.javafx.com/applet-launcher__V1.1.1.jar,http://dl.javafx.com/javafx-rt__V1.1.1.jar,http://dl.javafx.com/fxdloader__V1.1.1.jar,http://dl.javafx.com/jmc__V1.1.1.jar,http://dl.javafx.com/emptyJarFile-1242958365842__V1.1.1.jar" code="org.jdesktop.applet.util.JNLPAppletLauncher" mayscript="" height="200" width="200">
<param name="subapplet.classname" value="com.sun.javafx.runtime.adapter.Applet">
<param name="MainJavaFXScript" value="eggeral.splash.Main">
</applet>
</div>


Well I don't know which tricks the JavaFX JavaScripts use to get around Browser compatibility problems and alike. So I think this method might not work everywhere.







Tuesday, February 10, 2009

JavaFX Scale and Rotate About Center

The transforms property of a JavaFX scene node use the default pivot point 0,0 for scaling or rotating. This means scaling a rectangle grows it to the right and down.

If you want to scale or rotate about the center you can use the scaleX, scaleY and rotate properties of a node which use the center point of the node as default pivot point:

The following example shows an animation of a rectangle growing and rotating about its center.

var scale : Number = 1.0;
var angle : Number = 10;
var animation = Timeline {
repeatCount: 50
keyFrames: [
KeyFrame {
time: 0.2s
canSkip: false
action: function() {
scale += 0.1;
angle += 5;
}
}
]
}

Stage {
title: "Scale Rectangle Over Center"
width: 300
height: 300
scene: Scene {
content: [
Rectangle {
translateX: 10,
translateY: 10,
scaleX: bind scale,
scaleY: bind scale,
rotate: bind angle,
width: 140,
height: 90
fill: Color.BLACK
}
]

}
}

animation.play()

Monday, February 9, 2009

Dynamically Adding UI Elements to JavaFX Scene Content

JavaFX is nice to statically describe your UI elements. But what if you have to add something to the UI dynamically. E.g. The user presses a button and a new text should be added to the scene.

Well this is easy too. Just create the new element in the action code of the button and add it to the content using JavaFX's sequential (list) handling operations.

Here is an example: (Note: You have to create a variable for the stage in order to be able to access it).

var myX : Number = 50;
var myY : Number = 50;

var stage : Stage = Stage {
title: "Add text"
width: 250
height: 250
scene: Scene {
content: [
SwingButton {
text: "Add char"
action: function() {
var myChar = Text {
x: myX += 10,
y: myY += 10
content: "A"
}
insert myChar into
stage.scene.content;
}
}
]
}
}

Monday, February 2, 2009

JavaFX onKeyTyped for a Scene

keyTyped events are easy to use in JavaFX. Just add a function to onKeyTyped on a node and this node will be notified if a key is typed.

But what if you start with an empty scene. There are no nodes which can receive the event. And there is no onKeyTyped for a scene or stage.

I found two solutions for this problem. Both are some kind of a hack but they work:

1. Create a CustomNode without any graphics and just a onKeyTyped and add this to the scene content.

2. (my preferred solution) Use a Group which is empty at the beginning and later contains the scenes nodes. Groups do have onKeyTyped.

Here is an example:

var stage = Stage {
title: "Application title"
fullScreen: true
scene: Scene {
content: [
Group {
content: [
]
onKeyTyped: function( e: KeyEvent) : Void {
System.out.println("Hello");
}
}
]
}
}

JavaFX fullScreen

Writing a JavaFX full screen application is easy. Just set the fullScreen property of a Stage to true.

Stage {
title: "Application title"
fullScreen: true
scene: Scene {
content: [
SwingButton {
text: "Exit"
action: function() {
System.exit(0)
}
}
]
}
}
There are some problems with that documented in the documentation of the fullScreen property.

Setting the property to true tries to set the application to full screen using various techniques. All of which you would have to write on your own if you want to support multiple platforms.

The consequence of that is that in the current version of JavaFx you can not switch an application to full screen and then switch it back again.

There is a workaround for that mentioned in the documentation of the fullScreen property. You have to use two stages. One for full screen one for windowed and switch between these two.

I have not tried out that but it seams to be easy.

Wednesday, January 14, 2009

Serializing Inputstreams

Obviously input streams can not be serialized, nevertheless I recently had a similar problem.

I had to read the contents of a file (some random bytes) and call a JEE remote method with this bytes as parameter.

Just calling the remote method with the FileInputStream as parameter is what you do without remoting but what to do in this case?

As I was lucky and the files are small I used the following trivial solution where I just read the file into a byte array call the method with this byte array.

FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];

int read = fis.read(buffer);

if (read != file.length())
{
throw new IOException("Error reading file. Only read " +
read + " bytes instead of "+ file.length());
}

sessionBean.remoteMethod(buffer);

This only works for small files that fit into a byte array. And I still look for a more general purpose solution. But for now it works.