Arvind@Sun
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.
Posted at 03:34AM Jan 27, 2009 by arvindsrinivasan in WebServer | Comments[1]
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
}
]
};
|
![]() |
|
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
}
]
}
|
![]() |
|
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
}
]
}
}
|
![]() |
|
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
}
|
![]() |
|
5. |
Smoothen out the sharp edges in the image |
effect: GaussianBlur {radius: 2}
|
![]() |
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 {
fill: Color.CYAN
thickness: 4
content: Text {
textOrigin: TextOrigin.TOP
fill: Color.BLACK
content: "JavaFX"
font: Font { embolden: true }
}
};⁞
|
![]() |
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 }
]
}
}
};
|
![]() |
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!
Posted at 04:37AM Jan 02, 2009 by arvindsrinivasan in JavaFX | Comments[2]
Problems Using LinearGradients in Compiled JavaFX Script?
If you find that the javafx.ui.LinearGradient class in Compiled JavaFX Script is not working, then you are probably running into JFXC-531.
The tutorial demo that was part of the distribution for the interpreted version of the JavaFX language described a linear gradient as a color transition along a line given by two end points. The coordinates of the end points are specified as fractional values between 0 and 1. However, for the values of the startX, startY, endX and endY attributes of the javafx.ui.LinearGradient class (in Compiled JavaFX Script) you will need to specify geometric coordinates and not fractional values between 0 and 1.
The following examples illustrate how you can specify linear gradients in different directions:
| Description |
JavaFX |
Image |
|
A square that is simply filled with white colour.
The (x, y) coordinates (in the Group's coordinate system) of the four corners of the square (starting at the top-left corner and proceeding in a clockwise direction) are (20, 20), (120, 20), (120, 120) and (20, 120) |
import javafx.ui.*;
import javafx.ui.canvas.*;
Canvas {
content:
Group {
transform: Translate { x: 40 y: 20 }
content: [
Rect {
x: 20
y: 20
height: 100
width: 100
stroke: Color.BLACK
strokeWidth: 2
fill: Color.WHITE
}
]
}
};
|
![]() |
|
The same square filled with a horizontal (left-to-right) linear gradient that transitions from yellow to orange to red. The gradient starts at the top left corner (20, 20) of the square and ends at the top right corner (120, 20). |
fill: LinearGradient {
startX: 20
startY: 20
endX: 120
endY: 20
stops: [
Stop {
offset: 0.0
color: Color.YELLOW
},
Stop {
offset: 0.5
color: Color.ORANGE
},
Stop {
offset: 1.0
color: Color.RED
}
]
spreadMethod: SpreadMethod.PAD
}
|
![]() |
|
Horizontal (right-to-left) gradient fill (swap the start and end coordinates) |
fill: LinearGradient {
startX: 120
startY: 20
endX: 20
endY: 20
|
![]() |
|
Vertical (top to bottom) gradient fill |
fill: LinearGradient {
startX: 20
startY: 20
endX: 20
endY: 120
|
![]() |
|
Diagonal (south-west to north-east) gradient fill |
fill: LinearGradient {
startX: 20
startY: 120
endX: 120
endY: 20
|
![]() |
I plan on using gradients for drawing some cool JavaFX buttons/icons!
Posted at 09:09AM Jun 05, 2008 by arvindsrinivasan in JavaFX | Comments[1]
Timer Trouble
I wrote a simple GUI to test/demo my Timer class that I had blogged about previously. In doing so, I discovered a bug in my implementation.
![]() |
Figure 1a is a screenshot of the TimerDemo application that lets one configure the various attributes of the Timer class and test the timer by starting/stopping it. This TimerDemo application simply logs a couple of lines of text every time the timer action is invoked. The lines highlighted in grey show the timer action being invoked every 20 seconds.
![]() |
Figure 1b shows how the synchronized attribute of the Timer class affects when the first timer action is invoked. The highlighted portions in the above screenshot show that when a synchronized timer is used, the first invocation of the action occurs at the start of the next minute and thereafter when the configured interval expires.
The portion highlighted in yellow in Figure 1a shows a bug in my Timer implementation. It shows that the unsynchronized timer (incorrectly) invokes the action when the timer is started instead of after the expiry of the configured interval. The following diff fixes this bug:
--- Timer.fx.org 2008-05-31 23:52:40.000000000 +0530
+++ Timer.fx 2008-05-31 23:51:01.000000000 +0530
@@ -105,7 +105,6 @@
};
sync.start();
} else {
- alarm();
tick.start();
}
}
And now my Timer works better!
![]() |
Attachments:
-
TimerDemo.zip (consolidated source files)
Posted at 01:09AM Jun 02, 2008 by arvindsrinivasan in JavaFX | Comments[0]
A Timer written in JavaFX
I've been playing with JavaFX Script since the announcement at last year's JavaOne and I'm happy to report that my interest in dabbling with JavaFX hasn't waned! The declarative scripting syntax of JavaFX is very appealing to novice/weekend GUI programmers like myself.
For my JavaFX experiment, I needed a text-only display of the current time that would update itself every minute on the minute.
The first part was easy. I created TextClock.fx using my favourite JavaFX IDE - NetBeans. Here's a screenshot of TextClock.fx in action within NetBeans (using the Compiled JavaFX Script plugin).

The above program displays a timestamp but doesn't update it. I needed something that would update timestamp every minute. This is what I came up with.
foobar/util/Timer.fx:
package foobar.util;
import java.util.Calendar;
import javafx.lang.Duration;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
/**
* A Timer class that can be configured/extended to invoke an action after a
* specified number of seconds. It can optionally be configured to synchronize
* the timer to the system clock.
*/
public class Timer {
// Specifies the interval at which the timer should run
// (The default interval is 30 seconds)
public attribute interval: Number = 30;
// Specifies whether the timer should be synchronized to the system clock.
// This is useful when creating a timer that fires every minute on the
// minute, every hour on the hour etc.
public attribute synchronize: Boolean;
// Controls whether the timer is running or not. Setting it to true starts
// the timer, and setting this attribute to false terminates the timer.
public attribute active:Boolean
on replace {
if (initialized) {
if (active) {
start()
} else {
stop();
}
}
}
// User configurable action that is invoked when the specified
// interval expires. This can be used as an alternative to extending the
// Timer class to implement action2()
public attribute action: function():Void;
// Another user configurable action that is invoked when the specified
// interval expires. This operation can be implemented in the class that
// extends this Timer class
public function action2():Void {
// do nothing in this class
}
// Start the timer only after all attributes have been initialized
postinit {
initialized = true;
if (active) {
start();
}
}
// Prevents the timer from starting before all attributes are set
private attribute initialized = false;
// An internal counter used to synchronize this timer with the system clock
private attribute countdown: Duration;
// The "main" timer that invokes the user-specified action(s) every time the
// interval expires
private attribute tick: Timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames:
[
KeyFrame {
time: Duration {
millis: bind (interval * 1000)
}
action: function() {
alarm();
}
}]
};
// A timer that helps synchronize 'tick' to the next minute
private attribute sync: Timeline = Timeline {
repeatCount: 1
keyFrames:
[KeyFrame {
time: bind countdown
action: function() {
sync.stop();
alarm();
tick.start();
}
}]
};
// Starts the timer
private function start():Void {
var seconds = 0;
if (synchronize) {
var d: Calendar = Calendar.getInstance();
seconds = d.get(Calendar.SECOND);
}
if (seconds > 0) {
countdown = Duration {
millis: ((60 - seconds) * 1000)
};
sync.start();
} else {
alarm();
tick.start();
}
}
// Stops the timer
private function stop():Void {
sync.stop();
tick.stop();
}
// Invokes the user configured action(s)
private function alarm():Void {
if (action <> null) {
(action)();
}
action2();
}
}
The new animation APIs javafx.animation.Timeline, javafx.animation.KeyFrame were much easier to understand and use than the dur operator that exists in the interpreted version of the language (Previously, I had implemented the Timer class using Interpreted JavaFX Script. That version can be found here).
Hooking up the timer to my clock program was straightforward. The lines in bold below show how I enhanced TextClock.fx to automatically update timestamp every minute.
package foobar.samples;
import java.util.Date;
import java.text.SimpleDateFormat;
import javafx.ui.*;
import foobar.util.Timer;
var formatter = new java.text.SimpleDateFormat("EEE MMM dd, hh:mm aa");
var now = new java.util.Date();
var timestamp = formatter.<<format>>(now);
var timer = Timer {
interval: 60 // fire every minute
synchronize: true
active: true
action: function():Void {
now = new java.util.Date();
timestamp = formatter.<<format>>(now);
}
};
Frame {
visible: true
title: "Text Clock"
width: 200
content: SimpleLabel { text: bind timestamp }
};
That brings me to the end of my first JavaFX blog! I hope you found it useful.
Attachments:
-
TextClock.zip (consolidated source files)
Posted at 06:37AM May 30, 2008 by arvindsrinivasan in JavaFX | Comments[0]
Can I use Struts with Web Server 7?
When I was asked whether one could use the Apache Struts framework with Sun Java System Web Server 7, I was sure I would find an answer (confirming that one indeed could) if I searched the Internet. I was somewhat surprised and disappointed when I didn't any evidence either supporting or disproving the theory, so I decided to try it out myself.
I downloaded and unzipped the samples for both Struts 1(struts-1.3.8-apps.zip) and Struts 2(struts-2.0.9-apps.zip) from http://struts.apache.org/download.cgi. I then started the administration server of my Web Server 7 installation and deployed a few of the sample web applications to my test server.
| Sample web application | URI |
|---|---|
struts-1.3.8/apps/struts-blank-1.3.8.war |
/blank1 |
struts-1.3.8/apps/struts-cookbook-1.3.8.war |
/cookbook1 |
struts-1.3.8/apps/struts-examples-1.3.8.war |
/examples1 |
struts-2.0.9/apps/struts2-blank-2.0.9.war |
/blank2 |
struts-2.0.9/apps/struts2-showcase-2.0.9.war |
/showcase2 |
I started my server after deploying the above samples. If your server is already running you don't have to restart the server when you deploy web applications(the server can dynamically reload Java web applications).
% bin/startserv Sun Java System Web Server 7.0U1 B07/13/2007 16:10 info: CORE5076: Using [Java HotSpot(TM) Server VM, Version 1.5.0_12] from [Sun Microsystems Inc.] info: WEB0100: Loading web module in virtual server [test] at [/blank1] info: WEB0100: Loading web module in virtual server [test] at [/cookbook1] info: WEB0100: Loading web module in virtual server [test] at [/examples1] info: WEB0100: Loading web module in virtual server [test] at [/blank2] info: WEB0100: Loading web module in virtual server [test] at [/showcase2] (rest of output deleted)
All the samples worked! All I did was simply deploy the .war files to Web Server 7. Cool!
So, can Struts can be used with Sun Java System Web Server 7? Yes! Yes! Yes!
Posted at 04:43AM Jul 26, 2007 by arvindsrinivasan in WebServer | Comments[1]
Smart Reloading of Java Web Applications in Web Server 7.0
One of the cool new features in Sun Java System Web Server 7 is its ability to detect and dynamically reload (without having to restart the server) web applications that have changed. During web application development, it becomes very tedious and time consuming if one has to restart the server to test every change made. Requiring a server restart also prevents the ability to do web application development on a shared server without disruption to the other users of the server.
The ability to dynamically reconfigure many of the our web server's settings (including web applications) without having to restart the server was first introduced in iPlanet Web Server 6.0 and this feature was improved upon in the Sun ONE Web Server 6.1 release. Although both Web Server 6.0 and 6.1 didn't require that you restart the server to reload a web application, they did implicitly reload all web applications when the server was dynamically reconfigured. While this brute force approach to dynamically reloading web applications wasn't quite as expensive as restarting the server, it - i.e. dynamically reconfiguring the server - did have a few undesirable and unexpected side-effects namely,
- each web application was reloaded even if it hadn't changed
- all in-memory web application session data was lost
- one had to wait until all web applications had been reloaded in order to test any change made to a single web application
Web Server 7 has addressed all of the above limitations of the previous releases. Web Server 7 can intelligently detect which of the web applications have changed and only reload those that have. You can also deploy and undeploy web applications without restarting the server.
For example, if you have a Web Server 7 instance with 2 web applications deployed at /foo and /bar respectively, when you start the server you will see something similar to the following:
% bin/startserv Sun Java System Web Server 7.0U1 B05/07/2007 00:21 info: CORE5076: Using [Java HotSpot(TM) Server VM, Version 1.5.0_09] from [Sun Microsystems Inc.] info: WEB0100: Loading web module in virtual server [server] at [/foo] info: WEB0100: Loading web module in virtual server [server] at [/bar] info: HTTP3072: http-listener-1: http://server:7080 ready to accept requests info: CORE3274: successful server startup
If you reconfigure the instance without modifying either of the web applications, you will notice that the server does not reload either web application.
% bin/reconfig info ( 1170): CORE3276: Installing a new configuration info ( 1170): CORE3280: A new configuration was successfully installed
If you modify one of the web applications and reconfigure the instance, the server correctly reloads only the web application that was modified.
% touch web-app/foo/WEB-INF/web.xml % bin/reconfig info ( 1170): CORE3276: Installing a new configuration info ( 1170): WEB0100: Loading web module in virtual server [server] at [/foo] info ( 1170): CORE3280: A new configuration was successfully installed
By only reloading those web applications that have changed, in-memory session data for the other web applications is preserved across dynamic reconfigurations and the time taken to complete a dynamic reconfiguration is also less than was the case in previous releases of the web server.
You can dynamically reload a web application (that is deployed on a running Web Server 7 instance) without restarting the server when
- you make changes to any servlets in the application (changes to JSPs do not require that the web application be reloaded)
- you make changes to the web application deployment descriptors i.e.
WEB-INF/web.xml,WEB-INF/sun-web.xml - you make changes to the
<servlet-container>settings ininstance_dir/config/server.xml - you make changes to the global web deployment descriptor
instance_dir/config/default-web.xml
When you make a change that affects all web applications, the server detects this and reloads all the applications when the instance is reconfigured. For example, if you change the global web deployment descriptor that is common to all web applications and reconfigure the server you will see that the server reloads all the web applications.
% touch config/default-web.xml % bin/reconfig info ( 1170): CORE3276: Installing a new configuration info ( 1170): WEB0100: Loading web module in virtual server [server] at [/foo] info ( 1170): WEB0100: Loading web module in virtual server [server] at [/bar] info ( 1170): CORE3280: A new configuration was successfully installed
Changes to the following settings require that you restart the server
<jvm>element values ininstance_dir/config/server.xml- Java Security Manager policy in
instance_dir/config/server.policy <lifecycle-module>,<custom-resource>,<external-jndi-resource>,<jdbc-resource>and<mail-resource>element values ininstance_dir/config/server.xml
A web application deployed on Web Server 7 can be dynamically reloaded either by executing a command or at specific intervals or as per a specific schedule. You do not have to specify which web applications have been modified, the server automatically detects this.
Reload-on-demand: After making changes to the web application(s), you reconfigure the instance. Reconfiguring the instance instantly loads all the changes made to any/all web application(s). You can reconfigure the instance either from the Administration Graphical User Interface or by running instance_dir/bin/reconfig or by using the wadm reconfig-instance command.
Reload-at-intervals:Enable dynamic reloading of web applications. The dynamic reload interval that you specify determines that interval (in seconds) at which the web applications are checked for modifications and reloaded if necessary.
Reload-by-schedule: Schedule an event to reconfigure the instance. When the event is executed at the scheduled time/interval, the deployed web applications are checked for modifications and reloaded if necessary.
Thus, you can see that you have flexibility in configuring when your web applications should be checked for modifications and reloaded if necessary. I hope you find that the new and improved dynamic reloading feature of Sun Java System Web Server 7 improves your productivity as a developer and deployer of Java content. Please let me know if you have any feedback about this feature.
Posted at 12:48PM May 21, 2007 by arvindsrinivasan in WebServer | Comments[2]
Web Server 7: Type Less, Do More from the Command Line
The Sun Java System Web Server 7 Technology Preview release has many
new and cool features, one of which is its much improved command
line administration support. Previous releases of the web server had very
limited command line support for administration tasks. Web Server 7's primary command line administration tool is called wadm and it provides support for 280+ administration tasks!! I am very happy
with the extensive command line support in the new release.
I started using wadm (wadm is located in the bin subdirectory of your web server installation) without knowing anything about its syntax.
% wadm Usage: wadm [--user=admin-user] [--password-file=admin-pswd-file] [--host=admin-host] [--port=admin-port] [--no-ssl] [--rcfile=rcfile] [--no-prompt] [--help] [--commands-file=filename] CLI014 user is a required option.
This didn't really tell me a lot, so I tried
% wadm -help Usage: wadm [--user=admin-user] [--password-file=admin-pswd-file] [--host=admin-host] [--port=admin-port] [--no-ssl] [--rcfile=rcfile] [--no-prompt] [--help] [--commands-file=filename] CLI011 Invalid option, e
Still no luck. I then noticed that -- was used to specify options and so I tried
% wadm --help
Voila! About 20 pages of help documentation scrolled past my eyes! I used a pager to read the help documentation.
% wadm --help | more
To get extended help on a specific command, all I had to do was to specify the command and the --help option
% wadm list-webapps --help | more
Quite intuitive and easy.
I discovered that wadm required that the administration server be running, so I started the administration server.
I found that wadm's
command lines were quite long because of
the various parameters that had to be specified for each command. Even using the abbreviated command line options (e.g. -u instead of --user, -h instead of --host
etc.) I still felt that the amount of text that I had to type
repeatedly was too much! For example, this is the command I had to type
in order to list the Java web applications that were deployed on my
server.
% wadm list-webapps --vs test --config test --user admin --host foobar --port 8989 --passwordfile /home/foobar/admin.passwd
And this is the command to add a Java web application archive to my server configuration
% wadm add-webapp --vs test --config test --user admin --host foobar --port 8989 --password-file /home/foobar/admin.passwd --uri /foo foo.war
Instead of the above, wouldn't it be cool if I could just type
% wadm add-webapp --uri /foo foo.war
to add a Java web application, or type
% wadm list-webapps
to list the Java web applications deployed on my server? I don't
want to repeatedly type the parameter values that I know will never change and are common to
most commands.
It turns out that wadm provides some nifty ways to facilitate this. This is what I found from reading wadm's help documentation.
Any option can be supplied to wadm using shell variables. The variable name equivalent for an option is derived by prefixing wadm_ to the option name and replacing all hyphens(-) in the option name with underscores(_). For example
| Command Line Option Name | Shell Variable Name |
| user | wadm_user |
| password-file | wadm_password_file |
| receive-buffer-size | wadm_receive_buffer_size |
Shell variables can be set in the following ways in their increasing order of precedence:
- Using environment variables in the shell from which wadm is invoked
- From within a .wadmrc file residing in the user's home directory
- Using set/unset commands within the wadm shell
I prefer not to use environment variables and so did not consider option #1 above. Instead, I tried #2 and #3.
Specifying command line option values in .wadmrc (option #2)
I created a file called .wadmrc in my home directory with my favourite editor and added the following to it:
set wadm_user admin set wadm_password_file /home/foobar/admin.passwd set wadm_port 8989 set wadm_vs test set wadm_config test set wadm_host foobar
Now when I use wadm, I never have to specify --user or --password-file or --port or --vs or --config or --host to any of my wadm commands! wadm automatically picks up these values from my .wadmrc file. (If you call the .wadmrc file by some other name or put it somewhere other than in your home directory, you must use the --rcfile option of wadm to identify your .wadmrc file.)
Specifying command line option values in the wadm shell (option #3)
I found that if I used the wadm shell then I needn't even type wadm!
To invoke the wadm shell, I simply type wadm at the command line and
this enters the wadm shell. You can tell its the wadm shell because the
prompt changes from % to 'wadm> ' At the wadm> prompt, I simply type wadm commands. The shell allows me to override values specified in my .wadmrc file.
% wadm Sun Java System Web Server 7.0 B05/09/2006 18:10 wadm> wadm> help wadm> list-virtual-servers test wadm> list-webapps /foo /bar wadm> set wadm_vs foo wadm> list-webapps ADMIN3961: Specified virtual-server not found: foo wadm> add-<TAB> add-search-docs add-webapp wadm> set wadm_uri /test /test wadm> add-webapp foo.war CLI201 Command 'add-webapp' ran successfully wadm> list-webapps /foo /bar /test wadm> quit %
As you can see from the sample session above, the wadm shell is an interactive shell that is very easy to use. It also has quite a powerful command line editor. For example you can use the arrow keys to go up and down your command history or you can use the TAB key to complete commands or see the available options (see the add-<TAB> example above).
You can also do some pretty advanced Tcl scripting using wadm's --command-file option. I hope to write about this in a separate blog in the near future.
Overall, I had a pretty good experience using Web Server 7's wadm
tool and I hope that you too will find it equally useful. I hope you
will take Web Server 7 out for a test drive and send me feedback about
it.
Posted at 02:04AM May 17, 2006 by arvindsrinivasan in WebServer | Comments[5]















