Arvind@Sun

Tuesday Jan 27, 2009

Web Server Internals

A couple of weeks ago, Sun open sourced a lot of the code in Sun Java System Web Server 7.0. Having worked on the product for a number of years, I'm happy to see the code out in open source. One of the reasons for releasing the code under the BSD license was to evangelize the technology to any other open source projects/communities that might be interested in it.

While the source code is available for browsing at http://src.opensolaris.org/source/xref//webstack/webserver/ I suspect that most of you don't have the time to dig through all that code to find the bits that may be of interest to you! What I propose to spend some time doing over the next few weeks is to take features of the Web Server implementation that I think are interesting/innovative and write up some technical documentation (annotated with source code references) that explain how the feature is implemented in Web Server.

I propose to start by blogging about the following sub-systems in Web Server:

  • Configuration Management - How Web Server seamlessly installs configuration changes without having to restart the server process
  • Connection Management - The internals of Web Server's massively scalable connection-handling subsystem

If there are other areas that you would like information about, please let me know.


Friday Jan 02, 2009

Graphically Challenged? JavaFX to the rescue!

Need nifty icons and buttons for your RIA but can't draw them yourself? If you're like me and

  • want cool looking icons/buttons/graphics for your GUI
  • are quite hopeless at using tools like Adobe® Photoshop®, GIMP
  • waste hours (if not days!) googling for and unsuccessfully trying out  the various Photoshop/GIMP tutorials that are on the Internet
  • can't find somebody willing to do your dirty (graphics) work
  • prefer programming to drawing

then JavaFX might just be what the doctor ordered!

After (quite) a few unsuccessful attempts, I finally succeeded at following the 8 steps in Jesse Norell's well written tutorial on creating 3D buttons using GIMP. When I tried to emulate the same steps using JavaFX, I was surprised by how easy it was to do. Here's what I did to create my first 3D button using JavaFX!

Table 1: Translating GIMP into JavaFX

Step GIMP JavaFX Result

1.

Draw a perfect circle

Group {
    var radius = 40
    content: [
        Circle {
            centerX: 50
            centerY: 50
            radius: radius
            stroke: Color.BLACK
            strokeWidth: 1
            fill: Color.WHITE
        }
    ]
};
RingButton - Step 1

2.

Fade from white to black within the circle using either a linear or a radial fade. At the same time, remove the outline of the circle (strokeWidth: 0).


The code to the right fills the circle with a linear gradient going from the south-west to the north-east.
            strokeWidth: 0
            fill: LinearGradient {
                startX: 0
                startY: 1
                endX: 1
                endY: 0
                stops: [
                    Stop {
                        offset: 0.0
                        color: Color.WHITE
                    },
                    Stop {
                        offset: 1.0
                        color: Color.BLACK
                    }
                ]
            }
RingButton - Step 2

3.

Draw an inner circle and fill it with a linear fade in the opposite direction


Instead of changing the start and end points of the gradient, I've just swapped the start and end colors.
        Circle {
            centerX: 50
            centerY: 50
            radius: radius - 4
            stroke: Color.BLACK
            strokeWidth: 0
            fill: LinearGradient {
                startX: 0
                startY: 1
                endX: 1
                endY: 0
                stops: [
                    Stop {
                        offset: 0.0
                        color: Color.BLACK
                    },
                    Stop {
                        offset: 1.0
                        color: Color.WHITE
                    }
                ]
            }
        }
RingButton - Step 3

4.

Draw another smaller circle and fill it with any colour

        Circle {
            centerX: 50
            centerY: 50
            radius: radius - 8
            stroke: Color.BLACK
            strokeWidth: 0
            fill: Color.BLACK
        }
RingButton - Step 4

5.

Smoothen out the sharp edges in the image

        effect: GaussianBlur {radius: 2}
RingButton - Step 5

That's all there is to creating a spiffy looking graphic using a programming language that is intuitively easy!

Wouldn't it be cool if the 3D ring could be put around an arbitrary line of text or graphic such as an icon? To do so, we'd have to dynamically calculate the radius of the ring based on the size of the object that it "embeds". The rest of this blog describes the implementation of a custom node named SpiffyRing that draws a 3D ring around an user-specified node.

Here's the code for the SpiffyRing node:

package foobar.gui;

import java.lang.Math;
import javafx.scene.CustomNode;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;

/**
 * A class that draws a 3-dimensional ring around a specified node. You can
 * customize the thickness of the ring, the colors used for the ring itself.
 */
public class SpiffyRing extends CustomNode {

    /**
     * The node around which to draw the ring
     */
    public var content: Node;

    /**
     * Specifies the color used to fill the inside of the ring i.e. the space
     * between the ring and the embedded content
     */
    public var fill: Color = Color.BLACK;

    /**
     * Specifies the thickness of the ring in pixels.
     */
    public var thickness:Integer = 8;

    /**
     * Specifies the gap (in pixels) between the ring and the embedded content
     */
    public var gap:Integer = 2;

    /**
     * Specifies the two colors to use for coloring the ring itself with a
     * 3D gradient
     */
    public var color1:Color = Color.WHITE;
    public var color2:Color = Color.BLACK;

    // Calculate the radius of the ring using the dimensions of the embedded
    // node as well as the thickness of the ring itself.
    var radius = bind ((Math.hypot(content.boundsInLocal.width, content.boundsInLocal.height))/2 + thickness + gap);

    public override function create(): Node {
        var ring = Group {
            // Center the ring with respect to the embedded node
            translateX: bind content.boundsInLocal.width/2 - 1
            translateY: bind content.boundsInLocal.height/2 - 1

            content: [
                // Draw the outer circle of the ring fading from color1-->color2
                Circle {
                    centerX: 0
                    centerY: 0
                    radius: bind radius
                    stroke: Color.BLACK
                    strokeWidth: 0
                    fill: LinearGradient {
                        startX: 0
                        startY: 1
                        endX: 1
                        endY: 0
                        stops: [
                            Stop {
                                offset: 0.0
                                color: color1
                            },
                            Stop {
                                offset: 1.0
                                color: color2
                            }
                        ]
                    }
                },
                // Draw the inner circle of the ring, fading in the opposite
                // direction
                Circle {
                    centerX: 0
                    centerY: 0
                    radius: bind (radius - thickness/2)
                    stroke: Color.BLACK
                    strokeWidth: 0
                    fill: LinearGradient {
                        startX: 0
                        startY: 1
                        endX: 1
                        endY: 0
                        stops: [
                            Stop {
                                offset: 0.0
                                color: color2
                            },
                            Stop {
                                offset: 1.0
                                color: color1
                            }
                        ]
                    }
                },
                // Create the ring by filling the interior with the specified
                // fill color
                Circle {
                    centerX: 0
                    centerY: 0
                    radius: bind (radius - thickness)
                    stroke: bind fill
                    strokeWidth: 0
                    fill: bind fill
                }
            ]
            effect: GaussianBlur {  // smoothen the sharp edges
                radius: 2
            }
        };

        // Put the ring and the embedded node together, adjusting their
        // positions to account for the drawing radius of the ring itself
        return Group {
            translateX: bind (radius - content.boundsInLocal.width/2 + 2)
            translateY: bind (radius - content.boundsInLocal.height/2 + 2)
            content: [ ring, content ]
        };
    }
}

As you can see from the public attributes of SpiffyRing, there are several properties of the ring that you can customize including the thickness of the ring itself, the colors used to shade the ring and the node that you want to embed in the ring. Some aspects of the code are discussed below.

  • The radius of the ring itself is calculated using the hypotenuse of the embedded content and the properties of the ring itself such as its thickness.

var radius = bind ((Math.hypot(content.boundsInLocal.width, content.boundsInLocal.height))/2 + thickness + gap);
  • When drawing the circles that comprise the ring, their coordinates are adjusted so that the ring is drawn around the mid-point of the embedded node.

        var ring = Group {
            // Center the ring with respect to the embedded node
            translateX: bind content.boundsInLocal.width/2 - 1
            translateY: bind content.boundsInLocal.height/2 - 1
  • Hardcoded values from the listing in Table 1 have now been replaced using the dynamic attributes of the SpiffyRing custom node.
  • And finally, when putting the ring and embedded content together, their coordinates are adjusted to account for the fact that the ring needs to be positioned such that it appears to be drawn all around the content.

        return Group {
            translateX: bind (radius - content.boundsInLocal.width/2 + 2)
            translateY: bind (radius - content.boundsInLocal.height/2 + 2)
            content: [ ring, content ]
        };

Let's see what SpiffyRing can do!

JavaFX

Result

SpiffyRing {
    fill: Color.YELLOW
    content: ImageView {
        image: Image {
            url: "https://duke.dev.java.net/images/iconSized/duke.gif"
        }
    }
};
SpiffyRing around Duke
SpiffyRing {
    fill: Color.CYAN
    thickness: 4
    content: Text {
        textOrigin: TextOrigin.TOP
        fill: Color.BLACK
        content: "JavaFX"
        font: Font { embolden: true }
    }
};⁞
SpiffyRing around some text
SpiffyRing {
    color1: Color.RED
    color2: Color.WHITE
    fill: Color.BLACK
    gap: 0
    content: Rectangle {
        height: 20
        width: 20
        stroke: Color.RED
        strokeWidth: 1
        fill: LinearGradient {
            startX: 0  startY: 0
            endX: 0.5  endY: 0.5
            stops: [
                Stop { offset: 0.0 color: Color.WHITE },
                Stop { offset: 0.5 color: Color.RED }
            ]
        }
    }
};
SpiffyRing around a shape

This was my first try at dynamically sizing and positioning JavaFX nodes and I found it to be quite straightforward. I enjoy dabbling with JavaFX and hope that JavaFX has a great 2009!

Calendar

Feeds

Search

Links

Navigation

Referrers