Tuesday, December 18, 2007

Implement Your Own Connection Pool

Most large database-oriented applications use a technique called connection pooling to optimize database accessibility. Pooling is basically having a bunch of prepared connections available (already authenticated and ready for use), and leasing them out as needed. Rather than terminate the connection after use, it is returned to the pool for reuse.
Almost all vendors of JDBC drivers implement some sort of connection pooling, and there are many libraries out there that provide this functionality. However, if you want to customize database access with little overhead, it might make sense to implement your own connection pooling. Here is one simple way to do it. This code is built from ideas I came across all over the Internet ...

You can find the source code here. Apart from being efficient, the code also serves to make your data layer portable - can be used with any web server. All you have to do is ensure that the appropriate JDBC driver is available in the classpath, and that the database URL, password, user, and driver class are correct. In NetBeans or Eclipse, you add the JDBC driver by importing the JAR via project properties (libraries). Some IDEs allow you to package the additional libraries in the portable client, so take advantage of it.

The package includes a connection, a driver, and a pool implementation. You can then access them like this:

public class Database {
// Database connection settings
public static String DB_URL = "jdbc:mysql://localhost:3306/timeaccounting";
public static String DB_USER = "root";
public static String DB_PWD = "adminadmin";

public Database() {}

private static SConnectionDriver driver = null;

public static synchronized Connection getConnection() throws SQLException {
if(driver == null) {
try{
driver = new SConnectionDriver(
com.mysql.jdbc.Driver.class.getCanonicalName(),
DB_URL, DB_USER, DB_PWD);
} catch(Exception e){}
}
return DriverManager.getConnection("jdbc:strive:jdcpool");
}

public static void main(String[] args) {
Connection conn = null;
try {
// Obtain a connection from the pool
conn = getConnection();
// Use the connection somehow
if(conn == null) {
System.out.println("Bad connection ...");
} else {
System.out.println("Good connection ...");
}
System.exit(0);
} catch (SQLException ex) {
Logger.getLogger("global").log(Level.SEVERE, null, ex);
} finally {
// Return the connection to the pool
try { conn.close(); } catch (Exception e) {}
}
}
}

In this example, I have a MySQL database called "timeaccounting" that I am interested in accessing, so I set the url, user, and password as shown. I use the singleton approach to determine whether an initial driver has been initialized. Initializing the first driver also creates a pool and is the first connection available. The pool can create more copies as needed, and keep then after use.
It's probably no longer a good practice to use DriverManager (JDBC 1.0, old school), so I'll consider adapting this code to use JNDI soon. Andrew, perhaps you could complete this piece? That one project will need to move to this code ... it's painfully slow because it doesn't use pooling. With this code, your client's desire of database flexibility can be maintained.

Monday, December 17, 2007

Annoying NetBeans IDE Failure ...

I could be the only one experiencing this problem, but while working in NetBeans 6.0, it suddenly disappears on me without warning! It just unceremoniously closes down, almost like its process is suddenly terminated. It's not a JVM crash - that usually leaves traces I can find, but all instances of the JVM are well and running before and after the crash. That means I lose unsaved work and settings - NOT acceptable for a professional IDE! I'm really hoping it's just my environment because this wouldn't be a good testament to the IDE's stability. .
I've seen this issue 3 times in a 2 week span. There are no clues anywhere (not in logs, no popups, nothing ... no trace of what the cause could be), so it is hard to trace this issue to its root. I had seen this issue with beta versions (6.x), but I dismissed it because of the nature of beta software.
I'll keep an eye out for a pattern of failure and see if we can pin this to some issue somewhere. Whether it is on my end or in the IDE, it's not good news.

Saturday, December 01, 2007

Selection Sort With Comparator

Selection sort works by finding the smallest unsorted element in the collection and swapping it with an item in the position that's to be filled next. Because swaps don't happen all the time, this algorithm is a little but more efficient than bubblesort (about 60% better).
The algorithm is a ϑ(n2) complexity computation, efficient enough for small problem sizes. Here's a Java implementation of the algorithm that uses a comparator to specify more complex ordering criteria.

package com.strive.research.algorithms.sorting;

import java.util.Comparator;
import com.strive.research.algorithms.lists.List;
import com.strive.research.algorithms.util.Utilities;

@SuppressWarnings("unchecked")
public class SelectionsortListSorter implements ListSorter {
private final Comparator comparator;

public SelectionsortListSorter(Comparator comparator) {
assert(comparator != null): "Comparator cannot be null";
this.comparator = comparator;
}

@Override
public List sort(List list) {
assert(list != null): "List cannot be null";
int size = list.size();
for(int slot = 1; slot < size - 1; ++slot) {
int smallest = slot;
for(int check = slot + 1; check < size; ++check) {
if(comparator.compare(list.get(check), list.get(smallest)) < 0) {
smallest = check;
}
}
Utilities.swap(list, smallest, slot);
}
return list;
}
}

Bubblesort With Comparator

Bubblesort works by iterating over items in a list and swapping adjucent elements into the required order. Iteration continues until no more swaps are required.
You can make sorting more generic by using comparators. This allows a sorter to sort any collection of data using more complex criteria specified in a comparator. Here's a simple implementation:


package com.strive.research.algorithms.sorting;

import java.util.Comparator;
import com.strive.research.algorithms.lists.List;
import com.strive.research.algorithms.util.Utilities;

@SuppressWarnings("unchecked")
public class BubblesortListSorter implements ListSorter {
private final Comparator comparator;

public BubblesortListSorter(Comparator comparator) {
assert(comparator != null): "Comparator cannot be null";
this.comparator = comparator;
}

@Override
public List sort(List list) {
assert(list != null): "List cannot be null";
int size = list.size();
for(int pass = 1; pass < size; ++pass) {
for(int left = 0; left < (size - pass); ++left) {
int right = left + 1;
if(comparator.compare(list.get(left), list.get(right)) > 0) {
Utilities.swap(list, left, right);
}
}
}
return list;
}
}


The meat of the algorithm is public List sort(List list), which all implementors of my custom ListSorter interface must implement. This algorithm does in-place sorting, so there is no need to return the list really. Bubblesort is a ϑ(n2) complexity computation, efficient enough for small problem sizes.

Thursday, November 29, 2007

Filter Iterators Using Predicates

Processing arrays is a simple affair: you can access elements directly by using their indexes, or iterate these simple data structures from start to end. Pretty soon though, you'll begin wishing for more flexibility with the use of more complex data structures and business rules. For example, if you wish to process only elements with a certain attribute, or exclude elements based on some selection criteria, or write applications that do not need to copy entire contents into arrays before processing, simple arrays are not what you need.
The solution is to write customized iterators that can manipulate your basic array without creating duplicate data, minimize having to write duplicate code if you wish to process the array in more than one place, and really separate logic for selecting data from code that processes the data. The easy way is to couple an iterator with a predicate: the iterator can visit any of the elements of the array, while the predicate evaluates whether the elements visited meet some criteria for selection.

Here's an implementation of this idea: this driver class shows how you can filter elements of an array based on a simple criterion. The program generates randomly an array of graph coordinates, and uses a predicate iterator to select only coordinates in the first quadrant.


package com.strive.research.algorithms.iteration;

public class PredicateIteration {

/**
* Generates an array of coordinates.
* @param number Number of coordinates to generate.
* @return Array of coordinates.
*/
public Coordinate[] generateCoordinates(int number) {
Coordinate[] array = new Coordinate[number];
for(int i = 0; i < array.length; i++) {
array[i] = new Coordinate();
}
return array;
}

/**
* Prints the contents of an iterator by calling elements' toString() method.
* @param label Label to prefix ahead of iterator contents.
* @param iterator The iterator with contents to print
*/
public void print(String label, Iterator iterator) {
String contents = "{";
boolean comma = false;
for(iterator.first(); !iterator.isDone(); iterator.next(), comma = true) {
if(comma) {
contents += ", ";
}
contents += iterator.current().toString();
}
contents += "}";
System.out.println(label + ": " + contents);
}

/**
* Demo and test ...
* @param args (Not used).
*/
public static void main(String[] args) {
PredicateIteration prediter = new PredicateIteration();
// How many test items to use
int number = 10;
// Generate the coordinates
Coordinate[] coordinates = prediter.generateCoordinates(number);
// Print the generated list
Iterator general = new ArrayIterator(coordinates);
prediter.print("Original", general);
// Use predicate to show only coordinates in first quadrant
FilterIterator filtered = new FilterIterator(general, new FirstQuadrantPredicate());
prediter.print("Filtered", filtered);
// Exit
System.exit(0);
}
}


These projects are built using Eclipse 3.3.x (Europa) with JDK 1.6.x. You can find complete source code here:
Base project (AlgorithmsInJava) = defines the interfaces and base implementations that largely implement the idea above.
Demo project (IterationWithPredicates) = references the base project and implements a class the shows how to use iterators and predicates to filter data in arrays.

Monday, November 26, 2007

My "New" Bass Guitar

I don't own a new bass guitar, but it sure feels like it. I had it restrung and set up last week, an exercise that involved re-trussing the neck, using a much lighter string gauge, pickup tuning, and general cleaning. It sounds as good as new, as a result, much punchier and much cleaner.
It feels like a new beginning: suddenly I'm practicing more and trying new things on the bass. For a long time, I had not been able to slap/pick on this bass, but it seems I should be able to do it now. For slap/funk, I used another (4-string Aria Pro II) bass guitar, my first one ever. After four years, it still has a great sound.
I need to stop a very bad habit with the bass: not changing strings often enough. My mentor Dan Cervone always advocated for a monthly change of strings, but both my bass guitar can go a full year without fresh strings, even when I play somewhere every week. With this tune up, I also lost "tune retention", my term for when my bass guitar used to stay in tune for a long time. It might be weather changes too, but now I have to tune every time I play the bass. I'm in love with my bass guitar once again.



My bass is a Peavey Grind Bass Guitar 5 BXP NTB series, 5 string neck-through of mahogany wood. It comes as a passive bass, but I installed electronics to make it an active bass. These basses have a great sound, better than many bass guitars I have tried at music shops. The downside is that they are quite heavy, so after a 4-hour gig, your shoulders may complain. Which reminds me - it tends to get ungrounded often, giving off an ugly hiss; I should have remembered to have that checked into.
I'm still looking for a rig: an amp head (350-watts or more) and speaker cabinets (preferably a 4x10 and 1x18 or something within that combination range).
What all this means? I'm almost back to play my regular gigs. Three months off have been wonderful. I'll be up for grabs around the Christmas season.
This fine work on my bass was done at Pro Sound, Colorado Springs. The bass guitar specialist there is very knowledgeable, and prices are reasonable.

Saturday, November 10, 2007

Bernoulli Trials

When you toss a coin, the chances that a head shows are 50/50. But using Bernoulli Trials, we can repeats the coin tosses any number of times to obtain a spread of probabilities - the bell curve we all know. Below is the Java implementation of this idea. The algorithm likely runs in O(n2) time, so it is not efficient for large experiments.


/**
* Prints a histogram showing the results of tossing a coin many times
* and the probability that either heads or tails will be shown. This is
* generally known as the sequence of Bernoulli Trials in probability theory.
* @param trials Number of times to repeat the experiment.
* @param flips Number of coin flips per experiment.
*/
public static void bernoulliTrials(int trials, int flips) {
int i, j, cnt;
int[] f = new int[flips + 1];
for (j = 0; j <= flips; j++)
f[j] = 0;
for (i = 0; i < trials; i++, f[cnt]++)
for (cnt = 0, j = 0; j <= flips; j++)
if (Math.random() < 0.5)
cnt++;
// Drawing the histogram
for (j = 0; j <= flips; j++) {
if (f[j] == 0)
System.out.print(".");
for (i = 0; i < f[j]; i += 10)
System.out.print("*");
System.out.println();
}
}

Friday, November 09, 2007

Sieve of Eratosthenes

The Sieve of Eratosthenes is an ancient algorithm for determining prime numbers less than a given maximum number. Prime numbers have become suddenly important to me, especially in scenarios where events must not collide. In that case, staggering timeouts minimizes the chances when primes are used.
This is the Java implementation of the algorithm, the quick and dirty way. Of course there's more complex and efficient algorithms out there. This one is good enough for small maximums and runs in O(n lg n) time. Beyond a certain number, the system will run out of memory and begin taking longer to determine the next prime.:
/**
* Prints a list of prime numbers less than the max given.
* @param max Prime numbers will be less than this maximum.
*/
private static void printPrimes(int max) {
// Create max-sized array
boolean[] a = new boolean[max];
// Initially assume all numbers are not non-prime
for (int i = 2; i+=1)
a[i] = true;
}
// Sieve of Eratosthenes algorithm
for (int i = 2; i+=1)

if (a[i] != false) {
for (int j = i; j * i < max; j+=1)
a[i * j] = false;
}
}
}
// Print the primes, 0 and 1 are not
for (int i = 2; i+=1)
if (a[i]) {
System.out.print(" " + i);
}
}
System.out.print("\n");
}

Tuesday, November 06, 2007

JPA Connections In Invalid State

Using Glassfish or the Sun Java System Application Server (SJSAS), you will occassionally get the following error:

javax.resource.spi.LocalTransactionException: Connection.close() has already been called. Invalid operation in this state.

It's more prevalent when using JPA with EJB 3.0 in your applications. The solution is surprisingly simple: stop the application server, restart the database (in my case the MySql service), and restart the application server. Simple!

Thursday, November 01, 2007

EJB3.0 Persistence Relationships

The EJB 3.0 persistence relationships via annotations always elude me, so I figured I should take note of them here now that I got it right (finally).
Suppose you want to express the idea that an activity is done on one task at a time by one user. Three objects are involved: Activity, User, Task. To build a database relation between these:
Activity(n)<->(1)User = @ManyToOne in Activity, @OneToMany in User. :: Activity can be associated with only one user while User can be associated with many activities.
Activity(n)<->(1)Task = @ManyToOne in Activity, @OneToMany in Task. :: Activity can be associated with only one task while Task can be associated with many activities.
User(1)<->(n)Task = @OneToMany in User, @ManyToOne in Task. :: A user can have many tasks, but a task can be owned by at most one user.
@ManyToMany is trivial and the commonest used.

For a person without the mental picture of database relationships, these simple rules will help.

Tuesday, October 30, 2007

Glassfish V2 Not Ready

Glassfish V2 comes bundled with NetBeans 6.0 Beta versions, and it will be disappointing to find out that it will fail to compile JSPs when you deploy a simple web application. The exception it throws is:

java.lang.NoSuchMethodError: javax.tools.ToolProvider.getSystemJavaCompiler()Ljavax/tools/JavaCompiler

This is solely as Glassfish issue. Calling "java" from the command line shows a Java compiler is available systemwide. Moving the application to an existing SJSAS9 is successful - no such issue is experienced. So, if you have NetBeans 6.0 Beta 2, you should use the Sun Java System Application Server 9.x (separate install) for your Java EE 5 applications. No need to try and troubleshoot. I think a ticket has been logged with Glassfish developers.

Saturday, September 29, 2007

Stale MySql Connections In SJSAS

If you use the Sun Java System Application Server (SJSAS) with the MySQL database application, you will eventually notice that communication between the two products "goes to sleep" after prolonged periods of inactivity. I've traced this to the following root cause:
: Communications link failure due to underlying exception:

java.io.IOException: An established connection was aborted by the software in your host machine
at sun.nio.ch.SocketDispatcher.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:33)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:104)
at sun.nio.ch.IOUtil.write(IOUtil.java:75)
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:334)
at com.sun.enterprise.server.ss.provider.ASOutputStream.write(ASOutputStream.java:138)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:2637)

Something goes stale during down time and it can't be revived until you restart the server itself. Restarting the database doesn't help. For servers always being accessed, the issue won't be seen. I'd most likely blame the application server if it were up to me, but I'm not conclusive on that, since it may also mean that a socket connection to MySQL's port failed. Just not sure!
An easy workaround is to implement a thread in the application that keeps exercising the connection if it hasn't been used in a specified period of time. When I did this, my problem disappeared.

Friday, September 28, 2007

Weird Windows

Thursday, August 16, 2007

Debugging - Best Practices ...

For the coders among us, long live the debugger! Today's IDEs not only can profile and optimize your code, they come with top-class debuggers at no additional cost. The best also allow you to change values of variables, backtrack from a breakpoint, review the heap (and save it if you wish), and hot-replace code when it changes during a debug session. I can't even imagine developing software without such a tool.
But a debugger is as good as the programmer that uses it: if you are not skilled in using it, it's not worth the cost. A debugger is your first line in finding and fixing bugs. Here are other tips I've relied on over the years:
  1. Know your IDE's debugger limitations and features, and how to run it well. Only then can it be reliable and feasible.
  2. The obvious places may not be the culprits! After developing for a while, you start building a mental list of possible failure points and such, and develop a tendency of focusing too much on those areas when bugs do manifest themselves. Throw that mentality out and analyze issues from a "big picture" standpoint.
  3. Revert to the last working code and increment towards the the failure until you may find which additions cause the bug to happen. To this, you need a good versioning system. I've used Subversion, CVS, and Superversion - all free, of course.
  4. If there is a chunk of code causing the problem, contain the bug by using try/catch statements around it, and get a full error log. Then start walking that chunk, checking whether expected values are being set properly, and what is missing-in-action.
  5. Befriend the specification documents for insight. If you've debugged programs that use Windows system calls alot, you obviously don't have Windows source code to walk through, so MSDN (as scant as it is) will help some. Knowing what the WinAPI expects will help. Language forums are great help - chances are that you ain't the first person seeing this.
  6. Learn to read memory dumps, especially if you write C/C++ programs, or have to use JNI. Java hides these details from you, but Java debuggers should allow you to review entire data structures.
  7. Walk away from the code - take a hike, sleep, talk to your dog - whatever you do to take your mind off the issue. You won't believe how many times I've returned to the code and seen the problem right away - and felt so dumb.
  8. The blame game should start from inside out - first yourself, then the design, then the compiler, then the OS, and if you want - the language.
  9. Rewrite the offending chunk of code, perhaps using a different technique or even technology. Sometimes to understand C program issues, I've re-written chunks in Java and analyzed them from that standpoint. If you've fixed the same section nearly 5 times, it's time to re-write that piece afresh.
  10. Output messages - usually the first thing everyone does. I'm moving away from this - one of the 9 steps above will get me to the bug much faster.
Of course the art (notice it's not a "science") of debugging is different for everyone, but once you find a few good methodologies of finding bugs, work on making them better. Everyone should have a few tried and true ones, and then ask for help when bugs persist.

Wednesday, August 15, 2007

Testing Web-Based Applications

In my 4 years as a software developer, I've worked on a sizable number of web-based applications, and I thought I should share some insights - even as I am in the middle of yet another web-based project at this writing. Once in great while, I come across a website that is not pleasant to visit, and I wonder what kind of testing such a website might have undergone. Even more common are ActiveX or Javascript issues that litter websites on the Internet - ones that when you visit a page, an error is displayed and asks you whether you want to debug (dumb!!). These are signs of poor testing for a web application.
Comprehensive testing can improve the quality of web apps and lead to better long-term support for the application. Before deployment, functional and performance testing must be done, including security and accessibility certification of the web application. All this testing is done by testers, automated scripts, and a representative group of end users. Developers of the web application should only participate to provide expert support.

TESTERS:
Tester selection depends on testing needs, complexity of the application, time needed to learn the application, number of test scripts and scenarios, and total time available for testing. Choose testers with a goal to provide a diverse skill set and experience levels. You will need 3 kinds of testers: functional testers, performance testers, and scenario/script testers (differences will be seen in testing description). Obviously individual testers can do all these, but it's advisable to separate the roles.

TEST MANAGEMENT SYSTEMS:
Helps organize test resources such as documentation and requirements, scripts or scenarios, defects, and test results. Such a system is easily accessible by all groups for progress reports and task or defect tracking. The system also provides traceability and can be harnessed to lighten the load of documentation.

TESTING:

(1) Functional testing
determines if the web application works as designed, satisfying the requirements. Testers need to have an eye for anomalies and inconsistencies during such testing. Testing is manual, requiring a live person.
Automated tests should be applied to repeatable tasks that don't necessarily need human decision or observation skills. Scripts can help test more configurations in a consistent and predictable way, usually their course drawn from experiences of live testers. Functional testing also covers ideas like users entering bad data, no data, or unreasonably unrealistic data into the application.

(2) Performance testing for web applications focuses on response times. Tests may include spike (worst-case scenarios), stress (determine the failure conditions by subjecting it to increasing loads), and load (running 72-hour tests at near-breaking point - sustained high volume).

(3) Security testing
tests user authentication and verification, and accessibility to restricted content. It also tests session management issues, user privacy, and the protection of user transactions. Banking applications, for example, need to make sure they support SSL and TLS for secure communication.

(4) Integration testing
involves running the web application on various operating systems and web browsers. This is where the real difference between web browsers begins to show, and we've often had to write workarounds for web browsers that do not adhere to standards (IE is notorious for this ...). Also, all scripts and plugins are tested in more configurations at this point, resolving issues of when a browser doesn't support certain plugins, or the OS has to be configured to handle what we need.

(5) Accessibility and usability testing is geared towards those with disabilities. This is a much overlooked area of testing, but web applications should be able to support alternative input and output methods such as audio instructions, scanner input, and special keyboards. In fact, there exists laws on the books requiring government websites to support this feature (see Section 508 of the 1973 Rehabilitation Act).

TESTPLANS:
With all the testing considerations above, it is possible to write a comprehensive testplan that can cover all the aspects discussed. Just remember this plan should be adaptable enough for any changes to requirements and needs of the application.
Testcases should be prioritized such that when a regression needs to be done, high-priority and must-always-test testcases are done. Regression testing should always happen whenever a fix is applied to the application, patches are done to the environment, or new builds are deployed. The regression testplan should be more automated than regular testing, the results of which would guide live testers to focus on specific areas.

BEYOND DEPLOYMENT:
Ownership of the web application does not end after you hand it off to the client. At that point, you transition into a support role. In support, you deal with training the application's user community, providing help desk support, and facilitating knowledge transfer (documentation, knowledge base).
At a minimum, every website should have a help section that includes a user manual of sorts, frequently asked questions, application tips, and work-arounds for known inconveniences.

Monday, August 13, 2007

Practical Limits of File Sharing


A recent survey of teenagers and college students about file sharing revealed that despite threats of lawsuits from the RIAA, file sharing is thriving. In my opinion, file sharing will never end - not all of it is illegal. And as long as the networks exist, files will always be shared.
Though, there are limits that will curtail the file sharing phenomenon:

(1) You'll need more and more hard disk space to store all the files you download. A full (uncompressed) movie requires 9GB. A regular DVD rip requires 4GB, and many TV downloads are about 350MB large. A music album is about 125MB. With such space requirements, you computer will soon fill up, and that alone will slow down the file downloading habit. This is a weak argument though, as hard drive prices keep coming down sizes increase. Right now, you can buy hard drives at about 70 cents/GB. Small cost.

(2) A lot of file sharing utilities are advertisement-supported, which install malware and ad engines on your computer. Some of these utilities know how to disable antivirus programs and firewalls, and can turn your computer into a zombie. For fear of such a nightmare, people will stay away from file sharing. However, a new breed of no-ad download utilities is thriving. Some even check the authenticity of the files you download.

(3) Internet speeds will always deter whether downloading is worth your time. Presently, you can download a TV show in 30 minutes, and a full album in 11 minutes or so, depending on availability. ISPs can now detect whether you are downloading by monitoring traffic trends on your connection. If you suddenly start using consistently high bandwidth, their software can automatically throttle you down to a trickle.

(4) Software you need to rip DVDs, capture TV shows, and extract albums is getting more and more complex. It takes more than a few tries to get things right. This complexity will keep a lot of people away from file sharing activities. In addition, as ripping and sound/video capture from HDTV and such becomes more popular, there will be fewer software that's available for free. And as encryption schemes get harder, the activity will naturally decrease.

(5) Threats of lawsuits: a lot of people just hate to be tangled up in lawsuits they can necessarily avoid. The RIAA doesn't make sense when they try to charge you $750/song! But it'd be time wasting for you to want to defend yourself - the RIAA is a company of lawyers that pretend to watch out for artists' rights. I don't think that they care when their cases are without merit.

(6) Poorly designed file-sharing software: you don't want it to take over your internet. Some just hog your entire connection and expose to the world more than they should. If you can't surf normally because you are downloading or sharing files, it's a bad experience that'll discourage the activity.

(7) Burden of proof: anyone that sues you for illegally downloading their stuff has to prove that it is indeed their stuff that you downloaded. They have to find it on your computer, statistically show that it is a copy of what they have, and prove the means that you got it. It's not easy to get a warrant to seize someone's computer because you think they stole your source code or software - more proof is needed.

(8) Not all file sharing is illegal: so networks cannot be shut down and technologies absolved. For example, owning DVD-ripping software is legal and so is backing up your DVD movies. Problem is that a lot of people rip rented movies, and that's the vice. The laws being unclear will keep the world of file-sharing alive.

(9) US laws do not apply to other countries. Although most of the content being shared back and forth originates from the US, our laws don't apply to citizens elsewhere. If their governments are lazy about enforcing anti-piracy laws, more loss to US producers.

(10) Availability of files will always be sketchy. Files available for download depend on the season really - most people have the latest shows and music, partly because they have to clean up eventually (see #1 above). It's a rotating cycle that cannot be relied on. In addition, only about 30% of computer users leave their computers on the internet "all the time".

(11) Sharing stingy-ness: because share seeds can be tracked and because seeding files makes your computer a server, most people don;t share after they download files. That's selfish, by the way. Others share for a few minutes a day, which is hardly enough to broadcast your content to even the most popular trackers (talking BitTorrent here).

(12) It's geek activity to file-share and download. Those who think it's that bad an image won't do it. Beyond that, you need a certain levels of technical savvy to know which software, processes and places to go to for these services. About 60% of internet users have no idea about such things, or it's too tedious to be worth it.

Some of the points are limits against organizations such as the RIAA and their cohorts. I don't even know what will happen to file-sharing when non-DRM music begins to outsell copy-protected versions, or when digital TV becomes so popular you can watch it from your computer or even save shows directly to your computer. As we say in the programming world, if it's software, it's hackable. If it runs on my machine, I can rip it. If I can hear or see it, I can record it. And as long as I have friends, I shall share with them.

Wednesday, August 08, 2007

Data Converters for JSF Components

It is inevitable that when users fill forms in their web browsers, data arrives at the server as a bunch of strings. Then it's up to the server to convert the string to appropriate objects. To facilitate this conversion in JSF, you can write your own data converters.

Supposing we have an input field in which a user is expected to enter time, such as "08:45 am", and we need to convert this data to a Date object. Begin by defining the converter class:

public class TimeConverter implements Converter{
public TimeConverter() {}
public Object getAsObject(FacesContext context, UIComponent uiComp, String timeStr) {
try {
String displayFormat = "hh:mm a";
return new SimpleDateFormat(displayFormat).parse(timeStr);
} catch (ParseException ex) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "ParsingError", "");
throw new ConverterException(message);
}
}
public String getAsString(FacesContext context, UIComponent uiComp, Object date) {
String displayForma = "hh:mm a";
return new SimpleDateFormat(displayFormat).format((Date)date);
}
}

The class must implement the javax.faces.convert.Converter interface, and its getAsObject() method must throw a javax.faces.convert.ConverterException. getAsObject() returns a Date, while getAsString() returns a string. Then you must register the converter with JSF:
<converter>
<converter-id>timeConverter</converter-id>
<converter-class>com.strive.research.timecard.converters.TimeConverter</converter-class>
</converter>

The JSP/JSF page should be able to utilize the converter when you attach an instance to any component, in this case, an input field:
<h:inputText styleClass="timeentrytext" value="#{timecardbean.tue_lunchout}">
<f:converter converterId="timeConverter"/>
</h:inputText>

The component above uses values from a managed bean. In that bean, the getter and setter look like this:
public Date getTue_lunchout() {
// return a date object;
}
public void setTue_lunchout(Date tue_lunchout) {
// some code
}
As shown, the task of conversion is no longer the managed bean's reponsibity. Earlier we had a utility class who's job was to convert dates; we don't really need (most of) it in this scenario.

Potential issues you might run into:
java.lang.ArrayStoreException: java.lang.Float = just means wherever you are storing objects must be generic enough to take casts of what you are storing. I got a similar exception when my double-subscripted Object array is instantialized as a String[][]. Dumb - I just forgot that's how I was doing it.
java.lang.IllegalArgumentException: Illegal pattern character 'o' = the pattern you are sending SimpleDateFormat is not correct. My patterns are generated based on browser language, and I had a bug in the algorithm. Simply fixed.

Tuesday, August 07, 2007

Detect Browser Language In JSF

The webapp developed so far (build 0.0.5) allows users to select from a dropdown list which language they would like the website to exhibit - English (default), French, and Spanish. However, language selection can be automated by reading the default language of the client's web browser.
In JSF application, you'll most probably do request processing in a managed bean, so that's where language detection should happen. Every web request arrives with information about the web browser in a request header. This information is available to the application via an ExternalContext object:

// Get the application context
FacesContext facescontext = FacesContext.getCurrentInstance();
// Get the request headers
Map requestHeaders = facescontext.getExternalContext().getRequestHeaderMap();
// Read the supported languages
String languages = (String) requestHeaders.get("Accept-Language");
String lang = Options.INTL_ENGLISH;
if(languages != null) {
if(languages.contains("es"))
lang = Options.INTL_SPANISH;
else if(languages.contains("fr"))
lang = Options.INTL_FRENCH;
else // default
lang = Options.INTL_ENGLISH;
}

To change the default language for Firefox, open the options dialog (Tools | Options...) and click the Advanced tab. Select Languages and choose which language to use. You need to restart Firefox for the changes to take effect. Most websites should then begin to detect your preferred language and present data in that language (if they are internationalized). Try Google, for example.

Monday, August 06, 2007

Free Stuff Better Be Free!

Whatever happened to just giving free things freely without arm-twisting and manipulation? I'm hating website that purport to give free services and products at the expense of your time, personal information, and headache! This is nothing new on the web, but I think websites should be more honest about a simple matter like this.

Case in point: I needed a download of RadView's WebLOAD web application test and performance suite. On their website, they advertise both a free (open source) and a professional ($) version. All over their main website, there's download links for the professional version, but none for the free version - not even on the downloads page. To get to this, you have to browse via product overviews, where you discover that there is another website dedicated to the open-source community version. Cool beans - so I follow the links to get the latest stable version, and it mentions I need to be a member to download. So I register, of course, and then it takes me to SourceForge! Wtf?? You don't need registration to download software from SF.

At that point, you know you just got swung: they collected your information, wasted your time (20 min), and generated some traffic for their websites (page views). Fortunately, I've been here before, so I can waste their resources in "revenge" - I give them bogus email and contact information. Here's what sucks even more - required fields for registration include a phone number and address - like I need them to call about this free thing? Why do they need this? Most people visit this category of website exactly once and may end up re-registering when they return next time. Well, they won't use what I gave them ... it's an airport address, and the phone number is a Hawaii area code with a California city code. Their databases will fill up with unusable information - payback.

See the point? I think if something is free, just provide a link, perhaps with a disclaimer, and let people get it as anonymously as can be. It's almost as if there's mouseprint all over the web that says: if you want free things, be prepared to lose something personal. How free does that sound?
Despite this vent, I'll still review their application with all fairness, including this story. Sorry folks.

Sunday, July 29, 2007

Make Your Webapp Speak French

Whenever you create a web application that has global implications, you always need to internationalize it. This means it should be able to interact with the user in their browser or selected language. Our latest requirement for the timecard utility is for usability in both English and French. It demonstrates how to internationalize a JSF application using message bundles.

Message bundles are resources provided through properties files. The java.util.ResourceBundle is a convenient class used to access resources availed to the application. Properties files hold key/value pairs of strings.
Creating internationalization property files is typically a manual process: you identify what text on the UI needs to be in alternative languages, create key/value pairs for them in a properties file, then copy the whole set to other properties files - providing translated text in those files. As you can already tell, to change a single text element, you need to update all other files as well. Also, if you change the key, you need to manually update the classes that use that key directly. NetBeans 6.0 does not provide context-sensitive code completion between properties files and Java classes.

To implement the requirement specified, you create two property files - one for English and the other for French, then populate them accordingly. So, if I put in the english.properties title = Timecard Utility, then I need to also put in the french.properties title = Utilité de Carte de Pointage. The application will only look for the title key in the appropriate properties file and print out its string value. In the JSP, you'd need to call the french properties file with:
<f:loadBundle basename="com.strive.research.intl.french" var="lang"/>
(assuming it is in com/strive/research/intl package).

While this strategy works well, it doesn't update strings generated in the application itself and the propery file to use cannot be set dynamically. The solution is to use your managed bean to set which file the JSP should used. To do this, you create an additional variable in the managed bean that can be set based on the user's selection. When the selection is made, an appropriate locale and properties file are set before the page is redisplayed. To be able to print language-appropriate dates and times, you'd need to take advantage of the java.util.Locale class. The image below shows the result of selecting the French language option.



The big advantage of this implementation is that you don't have to change much code to support additional languages. Also, text changes can be made without having to recompile the application.
JSF also provides a mechanism for automatically applying the correct language based on the browser language. You'd need to set that up in faces-config.xml.

Brandon, let me know if you need the source code for this - pretty minor changes - and I'll send it to you. This application is growing bigger and bigger codebase-wise.

A Break On The Bass

This is an Overwater 6-string bass similar to something I'd like to own someday. Reviews of this bass are favorable, but the $2000 price tag is a bummer for most of us.
With a bass guitar like that, you need a stack that includes a cabinet such as this 1500-watt Epifani UL2-610 (about $1500) and a matching amp head (some 900+ watt box from Carvin or GK). O, and don't forget the cool multi-effects pod (like the Boss GT6B) that comes in handy on solo gigs. With equipment like this, I know I'd crank out bass tunes that'd surprise even myself. You begin looking professional at that level.

I've hang out with some bass players that are fond of bragging about their tools or which lengendary bass player they are trying to emulate, and yet when they set up to play, they stink. There's another breed of bass players that use the lowest end equipment (no bragging rights) and yet produce the sweetest grooves. That's the camp I'd rather be in - purely good skill and style. Granted, any good musician should invest in good equipment, but you don't have to go overboard.

I'm probably the weirdest bass player anyone will ever meet: I don't know how to read music (play by feel and ear), don't know who the great bass players and pioneers are, don't even know what equipment I should have, don't practice for my gigs (you'd think I'd be good at improvising, but nah!), don't maintain my equipment well (I haven't changed strings on one of my bass guitar in over a year), and don't play by the rules much. I have my own sound that sometimes works as bass (because I play it on a bass guitar). I'm a little better than a generic bass player, about average in fact, the experience (of 6 years come September) having helped me add some salt to my playing. I think one of my biggest handicaps is my interest in diverse kinds of music. Granted, I don't like opera or metal/hard rock or certain pointless R&B/Hip-hop/Rap music, but I can handle all kinds of music from all over the world based on thei artistic merit. If it has a beat and bass, I'll probably listen to it. That exposure leaves we wanting to learn everything about those kinds of music - so I end up having no influence or specific style. The question "who are your influences?" is often answered with "Hmmmm ...".

But with 2 records under my belt, a couple of recurring studio gigs, several opportunities to play in worship bands, and a few side projects with local artists and musicians, I suppose I don't stink after all. Though, I know there's much more I can do with this skill. Virtuoso players like Victor Wooten get me on fire - a challenge to improve my game. Though I'll probably never play like him, I can learn a lot from his style and technique. My dream would be to have the ability to take a common song and reinvent it from a bass perspective - give it some fresh air and new taste. There's always a danger of "going flat" once you start playing well and often, where you begin to overuse the technique you have with no new skills. That's the runt I want to get out of ... it's a catalyst for burnout if one is ot careful.

When you are busy as I have been, there's not much time to focus on your talent and improve. So in September, I'm dropping most of my engagements to embark on a learning trail - to explore ways I can be a better musician and bass player, add some professionalism to my game, and develop a character that's more consistent with a serious bass player. I'd like to learn new things and implement many of the suggestions and critique I've received over the last few years. Because music is only a hobby at this time, I'd also like to explore what it'd take to become a professional bass player.

My good friend Dave Taylor (a good drummer) had asked me once: "if you were given $1million to just play music and quit your job, would you take it?" The answer may surprise many, but I said "no". The reason is this: I don't care how much I make as long as the tasks keep me challenged enough that I don't get bored to death. For me to stay "alive", I need constant challenges and things to figure out. I could learn some serious grooves that make me a celebrity, but I'm not satisfied if I can never improve on them. With music, there's nothing "unknown" about music in this age, so creativity rests in composing and arranging with what we have now. My day job is n technology research, and the challenges are endless - which keeps me excited and looking forward to what the day may bring. Besides, I'd be a lazy bum if all I had to do was make music (all bills paid for). I think I'd start making bad music eventually just because I have the expectation to make music. This is a weakness in Hollywood studios: they sign a director and ask him to produce 5 movies a year. The pressure will cause him to produce crappy movies sometimes, just to fulfill his end of the bargain.

In any case, I think it's high time I returned to the basics, took a break, learned a few new things meanwhile. If I've made commitments to you already, I'll still honor them. Just don't be surprised when strange (read experimental) sounds come from me .... Also, I continue to be a backup on occasion. They say you never really abandon your talent, but I'm going to try and chill out the public aspect of it.

Saturday, July 28, 2007

Selection Input for JSF Forms

Supposing the client for the timecard utility sends us two new requirements - that users should have an option of entering time as 24-hour or 12-hour format, and be able to review and modify up to 4 previous weeks in addition to the current week. In HTML, this would mean using radio buttons for the time format and a dropdown list for which week is being viewed/modified.
In JSF, you can use any of <h:selectBooleanCheckBox>, <h:selectManyCheckBox>, <h:selectBooleanListBox>, <h:selectManyMenu>, <h:selectOneListBox>, <h:selectOneMenu>, or <h:selectOneRadioButton>. To implement the requirements specified, we use <h:selectOneRadioButton> for radio buttons and <h:selectOneMenu> for the dropdown list.
Fortunately, JSF has the same mechanism for using these components. You create a class that returns SelectItem[] objects, and use it in both the JSP (to populate the components) and the managed bean. The thing to be careful about is to put components that are supposed to be updated together in their own form elements. Only those elements are updated when a button is clicked.

To start with, we create a new Java class in our project that holds the options. Here's the source code for Options.java. It declares the options we need and appropriate getters/setters. It also has a temporary routine to generate the 5 weeks needed. This method can be extended to read this data from a database.
The managed bean can then add attributes that use the options selected in the form. Here's the sources for Timecard2.java. The JSF configuration file would need to be updated with navigation rules (new faces-config.xml) for the options, and the main display JSP updated to show the appropriate components (here's index.java). After you deploy the application, you should have something that looks like this:

With this new build, a user can choose what format to enter time as, and which week to view by selecting the appropriate. This example demonstrates how easily a JSF application can be extended. It also begins cracking at the power of the JSF framework - there's much much more you can do with this technology.

Using Subversion for NetBeans on Windows XP

Any programmer by now knows the value of having a source versioning and change management facility. A day comes when you mess up existing programs or lose your work, and that's where you can check out the latest working version from a repository somewhere. Beyond that, other benefits of using SCM include source code control and configuration management.
Because of simplicity and cost (free), I decided to use Subversion as the SCM solution. Subversion is designed to replace CVS, which I've had some trouble with. My latest aggravation comes from CVS's popular error message "cvs [server aborted]: Couldn't chdir to working directory : Invalid argument" (2.0.51d). Rather than try to resolve the issue, I decided it was time to find another solution, thus Subversion.

We've come to a point in development where we are making a lot of changes to the timecard utility. In order to preserve all our work, we should start checking it into a repository. This will also allow us to branch the application and merge changes from various contributors.
Here's the process for installing Subversion n Windows XP and to use it in NetBeans 6.0 (M10).
  1. Download Subversion from http://subversion.tigris.org/project_packages.html. Choose the binary executables under the Windows section. I'm using version 1.4.4.
  2. Run the executable and note the install directory (C:\Program Files\Subversion).
  3. Add environment variables: SVN_EDITOR = C:\Windows\notepad.exe (to use Notepad as the log editor), and to PATH += C:\Program Files\Subversion\bin (NetBeans needs this).
  4. Create a database directory that'll hold your versioned projects (J:\Subversion). Use the usual Windows Explorer for this.
  5. I want all my NetBeans projects to be versioned under the NetBeans directory in the SVN database. So we create a repository as such - at command prompt, svnadmin create "J:\Subversion\NetBeans". A directory should appear under your SVN database (#4).
  6. The repository in #5 above has a conf directory. Open the svnserv.conf and uncomment anon-access = read, auth-access = write, and password-db = passwd. Save that file.
  7. Open the passwd file with a text editor and add a user under [users] in the form username = password. Save the file.
  8. Create a windows service for SVN: at the command prompt, run sc create svnserver binPath= "\"C:\Program Files\Subversion\bin\svnserve.exe\" --service --root J:\Subversion --listen-port=6043 --listen-host=localhost" DisplayName= "Subversion Repository" depend= Tcpip. Startup is manual, so visit the Services applet and set how you want it to start, and start it.
In NetBeans, import the project into SVN:
  1. Right-click the project -> Versioning | Import Into SVN Repository ...; repository url = svn://localhost:6043/NetBeans, enter the username and password specified earlier. [Next].
  2. Repository folder defaults to the project folder name. I'd leave it like that. [Finish].
That's all! At the completion of each task, you should check your work in. If multiple developers work on the project, synchronize your local workspace with the latest from SVN.

Wednesday, July 25, 2007

Basic UI Design With JavaServer Faces (Pt. I)

In May, I wrote a post about getting JSP-based webapps to use JSF. Based on that post, we will convert our existing timecard utility to a JSF-based web application. The steps in the JSF post are largely good enough, with exceptions that I mention in here.

Be prepared to write a whole lot more code. The coding isn't hard - it's the repetitiveness and time you spend doing it that takes the steam out of it.
Beyond changes required by JSF (config files), we only change the JSP (add JSF markup) and bean (make it managed). In the end, we still get the same look and the application accomplishes the same things as before.
This implementation has 60+ components (areas, fields) on the page that need to be updated dynamically. The bulk of them are in the display table itself, and the rest are the various total and summary fields. We keep it simple in this example and use only <h:view>, <h:form>, <h:inputText>, <h:outputText>, and <h:commandButton> for JSF markup, although we could have just as easily implemented a <h:panelGrid> for the table.
You have to start worrying about session management. Case in point, if the view expires (either because the application was restarted or the session expired), you start getting exceptions like "javax.servlet.ServletException: viewId:/index.faces - View /index.faces could not be restored" caused by javax.faces.application.ViewExpiredException. That means you have to start over, as JSF emphasizes navigation/page flow (you need to start at the beginning).
JSF does not cure issues you already had in the JSP solution - all the bottlenecks and inefficiencies in algorithms will still be there. In fact, you might end up tossing lots of code, such as those that depend on parameters and field names passed from the client. It's true that pure HTML is generated by the JSF framework, but fields never have consistent names, especially when the view is regenerated.
I might add that JSF introduces its own issues - hints that designing a JSP app can be quite different from JSF - the need to plan everything and stick to the plan. They just behave differently.

Source code:
# The JSF-aware JSP file (index.jsp).
# The overhauled bean to support JSF (TimecardBean2.java).
# The other classes and pages remain the same.

After deploying the webapp, it's now available at <domain>:<port>/<webapp>/index.faces (as opposed to the usual <domain>:<port>/<webapp>/, which would have called index.jsp). Even with the <welcome-file> element set in the deployment descriptor to open the *.faces page, SJSAS web server does not get it right. Though, you can set NetBeans to open the page specifically (debug/run).

Some NetBeans 6.0 (M9) quirks:
(1) You don't get the option to reset encapsulated attributes' access levels when generating setters/getters, so remember to precede them with 'private' during declaration.
(2) The IDE no longer has a means to select all variables [Select All button] for which you are generating setters/getters. In fact, it also no longer allows you to select which getters or setters you want on one screen - how it was done in version 5.5].
(3) Whenever you add breakpoints in debug mode, you have to "debug project" again = compiling and deploying to a debug-mode server. Quite inconvenient, as some may wonder why breakpoints are not working.
(4) Code completion is case sensitive. The whole idea of this feature should be to reduce having to remember variables in your classes/pages. Now I have to remember whether I capitalized something or not?

Monday, July 23, 2007

Dynamic Web Content With JavaServer Pages (JSP)

Anytime you go to a website and it knows who you are, or asks you to log in, or you can do tasks on it, etc., that site is no longer static. Such dynamic websites run at least one web application to accomplish all those tasks. It doesn't have to be complicated really - a simple mechanism that responds autonomously to user requests can be considered a "web application". The previous timecard utility application was not dynamic. If you hit [Update], nothing happens. In this post, I describe a strategy to give that button some life. The result is shown above.

There're several ways to create dynamic web applications, including ASP and PHP, but I chose to use JavaServer Pages (JSP) to implement this functionality. The idea is simple: when a user clicks the update button, send all the data entered into the page to the server and update totals (lunch/work hours and week summary on the right).
This arena takes a basic web designer into the world of programming. Several tutorials exist on the web, including Sun's JSP Tutorial and the Java Tutorial. With these two resources, I've never really needed to buy reference books.

My implementation here simply uses JSP in its most popular form - mixing scriptlets and HTML code. When the page is called, it checks for a required session object and if none exists, creates one. That session object holds the dynamic data we need in parts of the page.
The session object is written along JavaBean conventions, but since we do not use it as such in this example, it can be any POJO. That class does the actual calculation of the times. The strategy is to use the principles of OOP for most server-side programming. Here, the timecard object depends on a Day object (which represents a typical day's hours - a column in our table), and a Week object (which represents all the Days of a week - the whole table). Each Day knows how to add up its own hours, and the week knows how to add up the computed hours from its Days to create a summary.

In NetBeans:
(1) Update the JSP code.
(2) Add new Java classes: TimecardBean.java, Day.java, Week.java, and a utility/helper class for formatting and parsing times and dates - DateTime.java.
(3) Deploy to the web server.

# As the code show, we are now naming fields of the form dynamically so that we'll be able to read them back easily. Also, business rules are implemented concerning the accumulation of work hours. For example, all day hours are rounded to the nearest quarter hour, and a mandatory lunch period is deducted if someone works more than 4 hours (and doesn't take lunch).

It's as simple as that - and you have a dynamic web application. Our code now also reports any errors it encounters and catches a few exceptions.
Possible problems so far with this kind of solution include a slow user experience because whenever the update button is clicked, the web server clears the timecard object and repopulates it with data sent from the client, recalculates all values, and regenerates the HTML to send to your browser.

Skills Needed: Basic Java and JSP programming.
Technologies So Far: HTML, CSS, Java.
IDE: NetBeans 6.0 (M9)
Web/App Server: Sun Java System Application Server 9.
JDK: 1.6+

Friday, July 20, 2007

Dress Up HTML With CSS

So far, our basic web designer knows how to write HTML and can run web applications on a web server. He has designed a mockup UI for the timecard utility, and although it doesn't do anything yet, it can be used to polish requirements. This is a followup to Simple Applications On Basic Web Servers. The prototype so far doesn't offer much visually and does not look that professional, so our goal here is to make it somewhat visually appealing. You do this with CSS.

You'll be surprised how many web designers and programmers out there have no idea or do not know how to use Cascading Style Sheets (CSS). I was one of them - I was comfortable doing database and business logic programming that I did not care much for how content was presented - that was another team's responsibility. However, as I began owning whole projects, I found it necessary to understand the presentation of content. It not only makes me a more well-rounded developer, but has affected how I do development. Thanks to my friend Ben who helped me get started. [By the way, Ben runs the BenTedder.com web design business].

Basically, CSS defines how HTML elements are displayed. All major web browsers support rendering web pages with style using CSS. There's several tutorials and books on CSS - it might be advisable to invest in a current desk reference, although you can find pretty much everything you want by simply searching the web. Theres even websites that have complete templates and programs you can use to generate CSS code for you. Although they make work easy, sometimes it's better to know how things work under the hood - whole reason to read up on CSS and learn to manually write code. The W3C CSS Tutorial is a good place to start; reference books you buy should be advanced beyond the basics on that site.

Here are some advantages of using CSS, including ability to make layout and visual changes for multiple pages from a single point, reduction of HTML code base, separation of style from content, and ease on search engines (find content rather than style). You should always know though that different browsers behave a little differently to CSS. Your best bet is Firefox to do better, as it is more compliant to standards than Internet Explorer is.

There are several CSS Editors on the Internet, most of them free or open-source. There are applications too that can generate both HTML and CSS through a visual design process (Adobe Dreamweaver MX??). The NetBeans 6.0 (M10) IDE also includes a CSS editor, which we will use to dress up our timecard application.
  1. Add a CSS file: File | New File. Web -> Cascading Style Sheet [Next]. Name the file (maintimecard), and specify a folder (style) [Finish]. Will be accessible as style/maintimecard.css.
  2. Edit the CSS: NetBeans' editor has quite a lot of features including code highlighting, code completion, macro recording, style builder, and preview. At this stage, we don't need to be looking for another editor.
  3. Link the CSS to the HTML file and update the HTML: you'll have to manually edit index.jsp to link to the CSS file and the HTML to use CSS styles specified. Here is the CSS and HTML code.
  4. Deploy the application.
When you display the application now in a browser, it looks like this. (IE shows a slightly different look, especially that it misses showing the dotted line right below "work hours" line).


How about that? We even add the idea of displaying messages to the user right in the form. Visually, this is a far cry from the basic HTML look we did before.
When I do development though, visual appeal is the last thing I worry about. Usually, you design your business logic first, then the database, and finally the presentation (HTML and such) when you know everything else works. In some projects, visual components are not polished until a later version of the software.

Thursday, July 19, 2007

Simple Applications On Basic Web Servers

Perharps the single most important implementation decision a web programmer must deal with is their choice of platform. When you start coding, the server-side components are usually specific to a language or platform. As an example, if you choose IIS, you'll initially be stuck with Microsoft technologies; if you choose Apache Tomcat, you are choosing the Java path. Of course plugins abound that enable additional features, such as Tomcat behaving like an IIS server, or to run PHP scripts, etc. But this decision usually determines what "camp" you belong to.

A basic web server simply responds to HTTP requests and socket connections. Since we are leaning towards implementing our solution in Java, there are plenty of servers - as listed here on Java-Source - that are free/open-source. Apache Tomcat is perhaps the most popular web server on the Internet today. Though in this exercise, we'll be using the Sun Java System Application Server, which comes bundled with the NetBeans IDE. As usual, I choose web servers based on how easy they are to configure, if my favorite IDEs support them, if they can be debugged on, level of complexity to extend, ease of deployment, and industry reviews that may suggest their performance is production grade. Later as your application grows, you start worrying about clustering and load balancing, response times under pressure, security, etc.

A scenario was presented in a previous post: the need to implement a simple timecard utility. To be able to do "live mockups", you need to have a real web server to which is deployed a foundational prototype. To start with, we'll create a simple application that dishes out HTML representing a basic UI. Instead of using plain HTML files, we'll take advantage of JavaServer Pages to generate the HTML. It also sets us up to use servlet technologies to respond to HTTP requests and ability to dynamically generate content. Many other server-side technologies do the same thing, including ASP, PHP, and ColdFusion, for example.

Often when you do web design, you start with mockups of how the final product might look like. Along with requirements from your client, you might then come up with use cases and such. We'll use NetBeans 6.0 (M10) to create a simple HTML based mockup:
  1. Create a new web project: File | New Project. Choose Project = Web -> Web Application. Project name and location = TimecardWebApp; context path /Timecard. [Finish].
  2. Design your page: index.jsp should be open in the IDE. Just code HTML into this page. Here's HTML code of what's needed to produce a mockup. NetBeans includes a palette that allows you to generate code for basic components using simple drag-and-drop onto the page.
  3. Run the application: right-click the web application -> Run Project. This will start up SJSAS, which is our web server in this context, deploy the web application to it, and open up the page in your default web browser. It should open at http://localhost:8080/Timecard/.
That's all for this step, and you should have something that looks like this:

Of course this page does not do anything yet. We are only interested in the look of the application in order to visually show the client what we will be able to do. The idea is that a user will enter the hours they came to work, took their lunch, left for the day, and any holiday or sick hours awarded. When they hit [Update], it should update the totals. That's all for now - additional features will be added later as the client specifies them (in future posts).

As you can see, IDEs such as NetBeans make web development a snap. Beware with v6.0 M10 though: the full package install take upwards of a minute to get started, and code completion/JIT is still painfully slow. But the advantage with using this IDE is its simplicity of use, available features, and how quickly you can get applications done. Of course whenever we need to implement something, we'll try it first in NetBeans; if it's not possible or there's a better way, we don't want to feel stuck in this IDE.