<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Jayson Falkner&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/" />
<modified>2008-02-19T19:51:08Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/jfalkner/98</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2008, jfalkner</copyright>
<entry>
<title>Lazy coder&apos;s mapping of DNS prefix to a sub-directory in a web application.</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2008/02/lazy_coders_map.html" />
<modified>2008-02-19T19:51:08Z</modified>
<issued>2008-02-19T19:50:56Z</issued>
<id>tag:weblogs.java.net,2008:/blog/jfalkner/98.9231</id>
<created>2008-02-19T19:50:56Z</created>
<summary type="text/plain">The Servlet specification provides a really elegant mechanism for packaging up a whole website in to a single WAR file and deploying that file as a website. Multiple websites can be mapped to different domain name prefixes, such as &apos;www.proteomecommons.org&apos; versus &apos;tranche.proteomecommons.org&apos;. This blog explains a hack to map the domain prefix to a sub directory of the same web application. </summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>J2EE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>The Servlet specification provides a really elegant mechanism for packaging up a whole website in to a single WAR file and deploying that file as a website. Multiple websites can be mapped to different domain name prefixes, such as 'www.proteomecommons.org' versus 'tranche.proteomecommons.org'. This blog explains a hack to map the domain prefix to a sub directory of the same web application.</p>

<p>Why use this hack? Well, I had two good reasons. First is that when I first helped make the website we didn't put it in a proper build system. Thus it grew in to a hodgepodge of JSP, HTML, and Java code. Second, the domain prefix that we were using 'tranche.proteomecommons.org' wouldn't easily fit into its own web application because it relies on a <a href="http://www.proteomecommons.org/data.jsp">shared in-memory database</a>. Sure, I could invest a significant chunk of time refactoring the code and binding the database to a local, protected socket, but that'd take a lot more time than the ten minutes that it would take to hack out a URL mapping filter.</p>

<p>Here is the filter's source-code in full. I'll discuss how it works after.</p>

<pre style="background:#dddddd;">
package org.proteomecommons;

import java.io.File;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author Jayson Falkner - jfalkner@umich.edu
 */
public class TrancheRedirectFilter implements Filter {
    // save the filter config -- needed later
    FilterConfig config = null;
    // the domain to match
    String domain = "tranche.proteomecommons.org";
    // uri to pre-append
    String preAppend = "/dev/dfs";
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        // check the URL for the domain name
        String url = req.getRequestURL().toString();
        if (url.contains(domain)) {
            // get the resource
            String uri = tweak(url);
            // forward to the resource
            req.getRequestDispatcher(uri).forward(req, res);
        } else {
            chain.doFilter(req, res);
        }
    }
    
    // dynamically change the URL
    private String tweak(final String url) {
        String uri = url.split("proteomecommons.org|\\?")[1];
        // if it starts with 'tranche.proteomecommons.org' move to /dev/dfs directory
        if (url.contains(domain)) {
            uri = preAppend+uri;
            
            // check if this is a real file and a directory
            String path = config.getServletContext().getRealPath(uri);
            File pathFile = new File(path);
            if (!uri.endsWith("/") && pathFile.exists() && pathFile.isDirectory()) {
                uri += "/";
            }
        }
        return uri;
    }
    
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
    }
    
    public void destroy() {
    }
}</pre>

<p>The code assumes that you want to map all URLs that start with a certain prefix to a sub-directory of your website. For example, 'www.proteomecommons.org' goes to the normal <a href="http://www.proteomecommons.org">website</a>. The <a href="http://tranche.proteomecommons.org">Tranche Project</a> website was developed in the '/dev/dfs' folder of the website, thus by default making its URL <a href="http://www.proteomecommons.org/dev/dfs">http://www.proteomecommons.org/dev/dfs</a>. However, Tranche grew up quickly and we wanted to give it a proper, top level domain 'tranche.proteomecommons.org' while not breaking any of the old '/dev/dfs' links. In short, we wanted to make all URLs starting with 'tranche.proteomecommons.org' automatically go to the '/dev/dfs' folder without redirecting to a ugly URL starting with www and /dev/dfs at the end.</p>

<p>The Filter is generic. The first two variables will swap any domain name prefix with a folder location. In this case, 'tranche.proteomecommons.org' is swapped with '/dev/dfs'.</p>

<pre style="background:#dddddd;">    // the domain to match
    String domain = "tranche.proteomecommons.org";
    // uri to pre-append
    String preAppend = "/dev/dfs";
</pre>

<p>If you want to copy/paste the above code, simply swap these variables to be the domain name and local directory of files to map to. If you are up for it, you might abstract them to variables in the Filter's web.xml declaration.</p>

<p>Only the tweak() method of the filter merits more discussion. The other code causes the Filter to invoke or skip tweak() based on if the URL has the domain name specified. In the tweak() method, the code does the swapping.</p>

<pre style="background:#dddddd;">   private String tweak(final String url) {
        String uri = url.split("proteomecommons.org|\\?")[1];
        // if it starts with 'tranche.proteomecommons.org' move to /dev/dfs directory
        if (url.contains(domain)) {
            uri = preAppend+uri;
            
            // check if this is a real file and a directory
            String path = config.getServletContext().getRealPath(uri);
            File pathFile = new File(path);
            if (!uri.endsWith("/") && pathFile.exists() && pathFile.isDirectory()) {
                uri += "/";
            }
        }
        return uri;
    }
</pre>

<p>First, the URL is split to remove the domain name with prefix, 'tranche.proteomecommons.org' and replace it with the default domain name,  'www.proteomecommons.org'. Next, the URL is padded to include the proper sub-directory, "/dev/dfs". Finally, the Filter forwards the request and response to the appropriate page. A little File check is made to handle a fringe case where a URLs go to a directory.</p>

<p>That is it! If it still isn't clear why the above is handy, note that the two URLs now work exactly the same:</p>
<ul>
  <li><a href="http://www.proteomecommons.org/dev/dfs">http://www.proteomecommons.org/dev/dfs</a></li>
  <li><a href="http://tranche.proteomecommons.org">http://tranche.proteomecommons.org</a></li>
</ul>

<p>Also, the two links go to the same exact file on the server. All of our old links work fine. All of the new links starting with 'tranche.proteomecommons.org' work. Best of all the whole hack took about 10 minutes...well, a half hour if you count writing this blog.</p>]]>

</content>
</entry>
<entry>
<title>Controlling Lego Mindstorms with Java (Lejos)</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2008/02/controlling_leg_1.html" />
<modified>2008-02-09T00:08:55Z</modified>
<issued>2008-02-03T05:02:30Z</issued>
<id>tag:weblogs.java.net,2008:/blog/jfalkner/98.9122</id>
<created>2008-02-03T05:02:30Z</created>
<summary type="text/plain">I just had the chance to play around with my friend&apos;s Lego Mindstorms robotics kit. Installing Java was easy, and in about an hour we were hacking out programs for the NXT brick. Here is a quick summary of how we got Lejos on the NXT via USB.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>Community: Robotics</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>I just had the chance to play around with <a href="http://freerssfreerss.blogspot.com/">Bryan E. Smith's</a> <a href="http://www.mindstorms.com">Lego Mindstorms</a> robotics kit. We installed <a href="http://lejos.sourceforge.net/">Lejos</a> and I was coding programs directly from Netbeans. It was a lot of fun and surprisingly easy to use Java to control the robot. I've just added a Lego Minstorms kit to my wishlist, but I'm not sure that I'd spend $250 to buy a new kit versus another <a href="http://weblogs.java.net/blog/jfalkner/archive/2007/12/java_and_the_no.html">Nokia n810</a>.</p>

<p>We started with a standard NXT brick, a lego mindstorms kit assembled in to the standard sumo bot, and my laptop running Ubuntu. The robot was already running a program where it'd guard an area and push any intruders away. Originally the program was coded using Lego's GUI; however, it was clear that it would be much easier if we could hack around in Java syntax. The choice was made to see if we could install Lejos and crank out some Java code to replicate the robot's original program. We were successful and the whole process took about an hour. Here is how we did it.</p>

<ol>
  <li>Make sure you have the following (Ant and JDK)</li>
  <li>Compile Lejos (you'd think that they'd do this?)</li>
  <li>Install Lejos to the NXT brick</li>
  <li>Setup Netbeans to code</li>
  <li>Hack out a Java program for the robot</li>
</ol>

<p><b>Make sure that you have the following</b></p>
<p>The <a href="http://lejos.sourceforge.net/">Lejos project</a> is going to need <a href="http://ant.apache.org">Ant</a> to compile itself, which means that you'll also need an install of <a href="http://java.sun.com">Java</a>. I'm not entirely clear if you need the JDK or not, but I used JDK 1.5. When compiling Lejos code you do not use the standard Java compiler. Instead you use Lejos's nxj tool -- it might use javac behind the scenes.</p>


<p><b>Compiling Lejos</b></p>
<p>Compiling the code is theoretically easy. Simply go to the ./build directory and run 'sudo ant'. It'll auto compile everything and you'll be ready to go. Of course, if you are like me, you will have glossed over the Lejos install instructions and have some GCC errors appear. Here are the two that I had. I've copied and pasted a large chunk of the error message so that Googlers will easily find this blog.</p>

<p><b>The Problem:</b> My Java Native Interface (JNI) header files weren't in the compilers include path.</p>

<pre style="background:#dddddd;">
[...]
jlibnxt:
       [cc] 1 total files to be compiled.
       [cc] In file included from /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/libnxt/main_jlibnxt.c:29:
       [cc] /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/libnxt/jlibnxt.h:2:17: error: jni.h: No such file or directory
[...on and on with some jni.h related compile errors...]
</pre>

<p>Solution: Inlude jni.h and jni_md.h in the C compiler's path. This can be done a few ways. I chose possibly the least elegant way: hard coding in the path to the Ant 'cc' action. That is where the C compiler is invoked. You can find out where to look for the <cc> element by reading the Ant error message</p>

<pre style="background:#dddddd;">BUILD FAILED
/home/jfalkner/Desktop/mindstorms/lejos_nxj/build/build.xml:65: The following error occurred while executing this line:
/home/jfalkner/Desktop/mindstorms/lejos_nxj/src/libnxt/build.xml:144: gcc failed with return code 1</pre>

<p>The above lines are stating that the first build.xml invoked another build.xml in the ./src/libnxt directory. On line 144 is where the &lt;ltcc&gt; action threw the error. That is where I hard coded the following (well actually at line 154).</p>

<pre style="#dddddd">&lt;includepath&gt;
  &lt;pathelement location="."/&gt;
  &lt;!-- next 2 line added by jayson --&gt;
  &lt;pathelement location="/opt/jdk1.5.0_11/include"/&gt;
  &lt;pathelement location="/opt/jdk1.5.0_11/include/linux"/&gt;
&lt;/includepath&gt;
</pre>

<p>Recompile the code. It might work, or if you have my luck, you'll get another missing header exception. This time because the bluetooth.h header file is missing.</p>

<pre style="background:#dddddd;">[...]
jbluez:
       [cc] 1 total files to be compiled.
       [cc] /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/jbluez/jbluez.c:8:33: error: bluetooth/bluetooth.h: No such file or directory
       [cc] /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/jbluez/jbluez.c:9:27: error: bluetooth/hci.h: No such file or directory
       [cc] /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/jbluez/jbluez.c:10:31: error: bluetooth/hci_lib.h: No such file or directory
       [cc] /home/jfalkner/Desktop/mindstorms/lejos_nxj/src/jbluez/jbluez.c:11:30: error: bluetooth/rfcomm.h: No such file or directory
[...compile errors go on and on...]
 </pre>

<p>This time the fix is slightly different. My computer doesn't actually have bluetooth, which is why Ubuntu didn't install the libraries and header files that are missing in the error message. Tell Ubuntu to add these libraries by launching Synaptic Package Manager and searching for 'libbluetooth-dev'. After installing, you can recompile without having to edit Lejos's build.xml scripts. Note, if you don't have 'libusb-dev' installed, grab that too!</p>

<p>Back to installing Lejos....</p>
<p>At about this point in time I realized that if I hadn't previously been a C/C++ coder I might have been lost. I expected the build script to simply work, but it ended up taking a good 15 minutes to fix it. The above errors weren't at all related to Java, and my friend was amazed that I knew how to fix them. Honestly, it was mostly my fault that they occurred because I didn't really read the Legos install guide. Hopefully you won't hit similar snags, but if you do, at least you'll know how to fix them.</p>


<p><b>Install Lejos to the NXT Brick</b></p>

<img alt="plugin-nxt.jpg" src="http://weblogs.java.net/blog/jfalkner/archive/lejos/plugin-nxt.jpg" width="400" height="358" />

<p>After compiling Lejos you need to flash the NXT brick. We weren't sure if this would replace the normal Lego Mindstorms software on the NXT brick. It does, which seems obvious after the fact. Don't expect to keep any programs that you have on the brick. In order to flash the brick you must plug in the USB cable and run <code>sudo ./nxjflash</code> from the ./bin directory. It'll flash the NXT brick. Make sure that you run 'sudo' or else you won't be able to write to the USB device. You might get a failure message stating that the brick needs to be in "RESET" mode. We did. After reading up on the subject, this means that you have to hit the NXT brick's reset button. It is possibly the most well hidden button ever made. You'll find it on the back side of the brick in one of the connector holes. See the picture.</p>

<img alt="NXT brick reset button" src="http://weblogs.java.net/blog/jfalkner/archive/lejos/reset-button.jpg" width="400" height="300" />

<p>If you need to, press the reset button with a paper clip and wait for the brick to start beeping. That is when you can flash the NXT brick using 'sudo ./nxjflash'. The brick will only beep for about 30 seconds. If it stops before you can flash, press the reset button again.</p>

<p>That is it. You are now set. Try running the Tune.java program from the included ./samples/Tune folder. You can do this by typeing './nxjc Tune.java' followed by 'sudo ./nxj -r Tune'. Your ears will thank you.</p>


<p><b>Setup Netbeans for Coding</b></p>
<p>I'm a big fan <a href="http://www.netbeans.org">Netbeans.org</a> and I use it to code most every project I work on. You can certainly use any other program, including any text editor, to code a Java program and compile it with the <code>nxjc</code> command. On my computer I already had Netbeans installed and I realized that it'd be easy to map the Lejos source code to a new project. This made it trivial to code because Netbeans then provided the standard syntax highlighting, error checking, dot completion, and whatnot.</p>

<p>Make a new project in Netbeans for your Java code that will use the Lejos NXTj API. I picked a normal Java application as the project type. Go in to the properties of the project and get rid of the existing source-code directory mappings. Add in a mapping for each of the four sub-directories in the './src/java/classes' folder of your Lejos download. Also map the directory that you'd like to keep your Java code in. I made up a new directory in the './samples' folder of the Lejos download and named it "MotorTest". From here on out you can create and code directly from Netbeans. If you find yourself missing any libraries, map the .jar files from the './lib' directory in the Lejos download.</p>
 

<p><b>Hack out some Java code to control the robot</b></p>
<p>Remember that Bryan had brought over his preassembled sumo bot. Our goal was to leave the robot alone and attempt to reprogram it in Java to do what it was previously doing. The benefit to this was that originally it took forever to try and drag and drop program using Lego's GUI. Coding in Java would surely be much quicker and let us actually have the robot do what we wanted. Given that the robot was assembled and that we could compile and run Java syntax code on it, the time had come to replicate the sumo bot's behavior.</p>

<p>Telling the robot what to do is relatively straight forward. The NXT brick isn't that complex. It has three motor ports (A, B, and C) and four sensor ports (S1, S2, S3, and S4). You can easily access any of these parts by using static helper members in either the Motor or Sensor class of the <a href="http://lejos.sourceforge.net/p_technologies/nxt/nxj/api/index.html">Lejos API</a>. Browse <a href="http://lejos.sourceforge.net/p_technologies/nxt/nxj/api/index.html">the Javadocs</a> and you'll find that you should be able to quickly hack away. For example, to make the wheel connected to Motor A turn the following code is used.</p>

<pre style="background:#dddddd;">Motor.A.forward();
Motor.A.setSpeed(200);</pre>

<p>Simple, no? Remeber that the NXT brick isn't any smarter than your code is. If you have set a wheel to spin forwards and cranked up the speed, next time you use the wheel it'll go in the same direction at the same speed. You should always explicitly initialize the motors and sensors to the setting that you expect them to have.</p>

<p>Moving on to hacking out the sumo bot's logic. Here is the final code. Read the in-line comments -- I bet you can guess exactly what is going on.</p>

<pre style="background:#dddddd;">import lejos.nxt.*;

public class MotorTest {
    
    public static void main(String [] args) {
        final int pushTime = 3000;
        final int guardDistance = 75;
        
        // wait three seconds
        for (int i=0;i<6;i++) {
            Sound.beep();
            // wait for a little while
            try { Thread.sleep(500); } catch (InterruptedException e) {}
        }

        // ultra sensor
        UltrasonicSensor uss = new UltrasonicSensor(SensorPort.S2);
        // get the LCD
        LCD lcd = new LCD();
        // register a listener
        while (Button.readButtons() == 0) {
            // rotate in opposite ways
            Motor.C.forward();
            Motor.B.backward();
            // set speeds
            Motor.B.setSpeed(200);
            Motor.C.setSpeed(200);
            // ping
            uss.ping();
            try { Thread.sleep(20); } catch (InterruptedException e) {}
            // check for an object
            int dist = uss.getDistance();
            lcd.clear();
            lcd.drawInt(dist, 0, 0);
            if (dist <= guardDistance) {
                // attack!
                Motor.B.backward();
                Motor.C.backward();
                // set speeds
                Motor.B.setSpeed(800);
                Motor.C.setSpeed(800);
                // wait for a little while
                try { Thread.sleep(pushTime); } catch (InterruptedException e) {}
                // attack!
                Motor.B.forward();
                Motor.C.forward();
                // wait for a little while
                try { Thread.sleep(pushTime); } catch (InterruptedException e) {}
            }
            // wait for a little while
            try { Thread.sleep(100); } catch (InterruptedException e) {}
        }
        // stop the motor
        Motor.C.stop();
        Motor.B.stop();

    }
}</pre>

<p>I've been programming in Java for quite a long time, and the above code is some of the most fun I've had while programming. I couldn't help but admire the simplicity of the Lejos API. Nor could I resist imagining how awesome it'd be to watch $250 worth of plastic legos, motor, and sensors twirl around and guard my office. The little bot did not disappoint! Check out the video.</p>

<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/Z1YqZDAfGuc"></param><embed src="http://www.youtube.com/v/Z1YqZDAfGuc" type="application/x-shockwave-flash" width="425" height="350"></embed></object>

<p>P.S. Does anyone have the optional "Deathray" accessory? I can't find it on Lego's website....</p>




<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2844794-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>]]>

</content>
</entry>
<entry>
<title>Java and the Nokia n810</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2007/12/java_and_the_no.html" />
<modified>2008-02-03T05:40:55Z</modified>
<issued>2008-01-01T04:17:20Z</issued>
<id>tag:weblogs.java.net,2007:/blog/jfalkner/98.8906</id>
<created>2008-01-01T04:17:20Z</created>
<summary type="text/plain">I just picked up a pair of Nokia n810s. One for me and one for the significant other. They are pretty amazing -- dare I say much cooler than the iPod touch? I also quickly discovered coding apps for the n810 in Java is trivial. Here is how I made a simple SWT (i.e. GUI app. You&apos;ll have to use GTK instead of Swing) app.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>Community: Mobile &amp; Embedded</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>The Nokia n810 is pretty fantastic, but I'll let you look that up elsewhere. Plenty of places do a good job showing it off. I'll focus on how easy it was to set up and make a graphical Java program.</p>

<p>Before getting started, I must thank both the developers at the <a href="http://www.jalimo.org">Jalimo project</a> for porting a JVM and the <a href="http://www.eclipse.org/swt/">Eclipse SWT</a> developers. Those two projects really do all of the work. Hopefully I can help the Jalimo folks update their wiki a bit.</p>

<p>Here is how you can start hacking out your own Java apps on the Nokia n810.</p>

<ol>
  <li>Install Jalimo using Maemo's point-and-click installer.</li>
  <ol type="a">
    <li>Add the Jalimo repository to Application Manager. Use the following info:</li>
    <ul>
      <li><b>Catalog Name: </b>Jalimo</li>
      <li><b>Web Address: </b>http://jalimo.evolvis.org/repository/maemo/</li>
      <li><b>Catalog Name: </b>chinook</li>
      <li><b>Catalog Name: </b>user</li>
    </ul>
    <li>Browse your installable applications and install the ones that say'Jalimo'.</li>
  </ol>
  <li>Drop to command-line and type 'cacao'. You'll see the familiar JVM options scroll by. At this point you can run Java apps, but if you want to run Graphical programs, you'll have to include the SWT/GTK libraries in the '/usr/share/java/' folder.</li>
  <li>Edit and test code under your favorite IDE. I used <a href="http://www.netbeans.org">Netbeans</a>, and here is what I did.</li>
  <ol type="a">
    <li>Created a new Java Application project.</li>
    <li>Added 'swt.jar' from the Eclipse SWT release (can also copy from the n810 directly).</li>
    <li>Copied and pasted the Jalimo SWT example code.</li>
  </ol>
  <li>Finally, compile your code and copy it over to the n810 via the USB cable. It appears as a regular USB disk, and this step is as easy as copying and pasting.</li>
</ol>

<p>That is it. Sorry not to include some screenshots, but I'm a bit to excited to hack out some serious code. Perhaps I'll port <a href="http://tranche.proteomecommons.org">Tranche</a> to the n810 or maybe I'll try to figure out how to play around with the GPS....</p>

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2844794-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>]]>

</content>
</entry>
<entry>
<title>Building a Java applet-based game -- why don&apos;t we see more of them?</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2007/11/building_a_java_1.html" />
<modified>2008-02-03T05:42:19Z</modified>
<issued>2007-11-02T02:35:56Z</issued>
<id>tag:weblogs.java.net,2007:/blog/jfalkner/98.8545</id>
<created>2007-11-02T02:35:56Z</created>
<summary type="text/plain">My younger brother and I decided to try and make a viral video game. The sort of game that can suck hours away from your life. The type of game that passes the boring times at work. The type of game that normally seems to be coded in Flash.... Here we&apos;ll document how successful Java seemed to be in making this game.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>Community: Java Games</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>My brother and I decided to try and make a <a href="http://www.falkemup.com">viral video game</a>. The sort of game that can suck hours away from your life. The type of game that passes the boring times at work. The type of game that normally seems to be coded in Flash/ActionScript....</p>

<p>The only problem is that neither of us knows how to code Flash/ActionScript. After some thought, we wondered if this was actually a problem. We do know how to code in Java, and Java does have applets. This page is to document our efforts and hopefully provide some information for other Java game programmers that want to use applets. What this blog won't provide is any information about how to make a fun game -- we're not even sure if we've done that ourselves.</p>

<p>Please do post any questions or comments that you think would be helpful. If you know something we've missed, I'll gladly add it to this page.</p>

<p><b>Lessons Learned From Coding a Java Applet-based Game</b></p>
<ol>
  <li><a href="#about">About the game</a></li>
  <li><a href="#swing">Applets are easy to code, but Swing wasn't terribly helpful</a></li>
  <ul>
    <li><a href="#aatext">Anti-alias text or it'll look bad</a></li>
  </ul>
  <li><a href="#applet">The &lt;applet&gt; tag only sort of works</a></li>
  <ul>
    <li><a href="#javacheck">Prompting to install required Java version</a></li>
  </ul>
  <li><a href="#profiler">Profiling your game can really speed things up</a></li>
  <ul>
    <li><a href="#bufferedimage">Recycle a BufferedImage object all the time. Always double buffer!</a></li>
  </ul>
  <li><a href="#online">The game seems to work...feedback will be posted</a></li>
</ol>

<p><a name="about"></a><b>About the game</b></p>
<p>This is the only place that you'll find information about the game. It is nice that we'll get a link to it, but this entry is intended to convey what we've learned about using Java to make a simple game.</p>

<p style="padding-left:20px;"><b>Link to Game:</b> <a href="http://www.falkemup.com/rotr/">Rise of the Robots (RotR)</a></p>

<p><u>Please don't post non-Java related comments about this game in this blog's discussion section</u>.</p>

<p><a name="swing"></a><b>Applets are easy to code, but Swing wasn't terribly helpful</b></p>
<p>Something I like about Java is that tools like <a href="http://www.netbeans.org">Netbeans</a> and <a href="http://eclipse.org">Eclipse</a> make coding relatively easy. They are free to download and use. The IDEs also making coding, compiling, and deploying a JAR a breeze. The rate limiting step seems to be figuring out how to actually code what you want to code.</p>

<p>We knew a good deal about Swing before starting to code this project. This resulted in the initial program only took a weekend worth of work. All of the graphics are 2D and are drawn essentially in one massive override of the paintComponent() method. Initially, we tried to be clever with JButton, JLabel, JPanel, and such; however, it quickly became clear that it was far easier to make most every bit of text a PNG graphic. The result looked much better, and it only took a few minutes to whip up some graphics via <a href="http://inkscape.org">Inkscape</a> and <a href="http://gimp.org">GIMP</a>.</p>

<p>After adding in a few graphics we did realize that the size of the final JAR was starting to grow. In the end we ended up with a JAR that was about 200 KB in size. Not bad at all in my opinion, and well worth the time saved on messing around with Java fonts and cleverly positioned JButtons.</p>


<p><b>Anti-alias text or it'll look bad</b></p>
<p>In the end, we did use standard Java fonts to draw some text in the game. In every case it was clear that anti-aliasing is a must. Otherwise the text looks awful. You can easily do this by adding the following to your code in the paint() or paintComponent() method.</p>

<pre>
// conver to graphics 2D for anti-alias
Graphics2D g = (Graphics2D)frame.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);</pre>

<p><a name="applet"></a><b>The applet tag only sort of works</b></p>
<p>It turns out that the intuitively named HTML tag &lt;applet&gt; doesn't do what you think. It used to, but these days you are expected to use a more generic tag for embedding content in to a HTML page. Sun's JDK documentation explains it pretty well. <a href="http://java.sun.com/j2se/1.5.0/docs/guide/plugin/developer_guide/using_tags.html#object">Here</a> is the page of interest.</p>

<p><a name="javacheck"></a><b>Prompting to install required Java version</b></p>
<p>If you do not include information regarding the required Java install, your game might not work. We discovered this after compiling our code with Java 1.5. Most users could play the game perfectly fine; however, several users reported that the applet simply didn't work. Java 1.5 bytecode isn't compatible with earlier Java releases, and the applet's classloader was throwing an incompatible version error.</p>

<p>The solution was relatively easy. Set the type parameter to be "application/x-java-applet;version=1.5" and replace the 1.5 with whatever is the appropriate version. Here are two examples. One with the &lt;embed&gt; tag (Firefox/Netscape) and one for the &lt;object&gt; tag (MSIE).</p>

<pre>  &lt;embed code="feu.td.Game.class" 
         archive="./Game.jar"
         width="500"
         height="490"
         type="application/x-java-applet;version=1.5"&gt;&lt;/embed&gt;</pre>

<p>Above is the &lt;embed&gt; tag example. Below is the &lt;object&gt; tag example.</p>

<pre>&lt;OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
        width="500"
        height="490"&gt;
        &lt;PARAM name="archive" value="./Game.jar"&gt;
        &lt;PARAM name="code" value="feu.td.Game.class"&gt;
        &lt;PARAM NAME="type" VALUE="application/x-java-applet;version=1.5"&gt;
&lt;/OBJECT&gt;</pre>

<p><a name="profile"></a><b>Profiling the game can really speed things up</b></p>
<p>Profiling is an important part of any Java project. It will tell you how much time each portion of your code is taking. Thus, if your code is slow or maxing out the processor, you can profile to try and discover where optimizations are required in the source-code. The <a href="http://profiler.netbeans.org">Netbeans profiler</a> is awesome. It is free and easily installs. After you install it you can simply right-click on your code and "Profile".</p>

<p>I strongly suggest trying it out. The initial version of my game would take up to 50% of the processor on my 2.0Ghz machine when about two dozen sprites were walking on the screen. After a few hundred sprites, the game would be noticeably jumpy and not much fun to play. A few rounds with the profiler and it was clear where I unnecessarily wasted processor cycles. Post profiling the game now takes less than 10% of my CPU, even when the screen is full of sprites.</p>


<p><a name="bufferedimage">Recycle a BufferedImage object all the time. Always double buffer!</a><b></b></p>
<p>It is very expensive to constantly use the Graphics object to draw on the screen. Never do this. Instead draw absolutely everything to a in-memory BufferedImage object. Also, only make one object and recycle it every time you need to draw a frame of the game.</p>

<p>Here is how you can make a BufferedImage object. Be sure to make it the same size as the game's display.</p>
<pre>
// make and buffer the map background
BufferedImage bufferedBackground = new BufferedImage(Game.BOARD_WIDTH, Game.BOARD_HEIGHT, BufferedImage.TYPE_INT_RGB);

// in the paintComponent() method use the buffered graphics
public void paintComponent(Graphics graphics) {
 // draw on the bufferedBackground ...
 Graphics2D g = (Graphics2D)bufferedBackground.getGraphics();

 // use g instead of graphics...
}</pre>

<p>After an entire frame of the game is drawn in-memory. Draw once to the actual screen of the game. Here is a code snippet showing how this is done with the Graphics object.</p>
<pre>
public void paintComponent(Graphics graphics) {
 // draw on the bufferedBackground ...

 // draw the final image
 graphics.drawImage(bufferedBackground, 0, 0, null);

 ...
}</pre>

<p><a name="online"></a><b>The game seems to work...feedback will be posted</b></p>
<p>It seems that the first version of the game looks fine. For two Java coders that are moderately artistic, we made the game not look like garbage. Plus it seems to play fine.</p>

<p>It'll be interesting to see if this followup section ends up being boring. In the least, I'll follow up with a comment saying that the game seems to be fine. There is no great reason that a Java-based viral video game can't work.</p>

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2844794-5");
pageTracker._initData();
pageTracker._trackPageview();
</script>]]>

</content>
</entry>
<entry>
<title>MEM Java Fun</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2007/10/mem_java_fun.html" />
<modified>2007-11-02T23:03:26Z</modified>
<issued>2007-10-29T19:00:37Z</issued>
<id>tag:weblogs.java.net,2007:/blog/jfalkner/98.8508</id>
<created>2007-10-29T19:00:37Z</created>
<summary type="text/plain">This is material for the MEM Java developers. I hope you all had fun!</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[This is a summary of links and information we talked about at MEM.

<ul>
  <li><a href="http://java.sun.com">Sun's Java Homepage</a></li>
  <li><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification (Bathroom reading material!)</a></li>
  <ul>
    <li><a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.5">Escape character reference (and related String/char info)</a></li>
    <li><a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3">Float/Double spec link</a>, i.e. why doesn't 5.0/0 throw a divide by zero error?</li>
  </ul>
  <li>Helpful Java Tools (Ant, JUnit, and Clover)</li>
  <ul>
    <li><a href="http://ant.apache.org">Jakarta Ant:</a> automates building and running code tests.</li>
    <li><a href="http://junit.org">JUnit:</a> popular framework for writing unit tests.</li>
    <li><a href="http://www.atlassian.com/software/clover/">Clover:</a> shows code coverage.</li>
    <li><a href="https://glassfish.dev.java.net/">GlassFish:</a> a web container designed to hose all of Java Enterprise Edition (JEE)</li>
    <li><a href="http://labs.jboss.com/">JBoss:</a> another option for doing what GlassFish does</li>
  </ul>
  <li><a href="http://dev.proteomecommons.org/">Link to the page Jayson showed</a> with example reports (ProteomeCommons.org's Tranche Dev build)</li>
  <li>IO Examples (File IO Included)</li>
  <ul>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/mem/IOExamples.java">Buffered IO Examples</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/mem/TextTwistScrambleReader.java">TextTwist File Reading/Writing Code</a></li>
  </ul>
  <li>Playing with JDBC</li>
  <ul>
    <li>Download <a href="http://hsqldb.org">HSQLDB</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/mem/Database.java">core.Database.java</a>
</li>
  </ul>

  <li>Specifications of Interest</li>
  <ul>
    <li><a href="">HTTP Specification</a></li>
    <li><a href="http://stax.codehaus.org/">Streaming API for XML (STaX)</a></li>
    <li><a href="http://xml.org">Simple API for XML (SAX)</a></li>
  </ul>

  <li>Tutorials</li>
  <ul>
    <li><a href="http://java.sun.com/webservices/reference/tutorials/index.jsp">Java XML/WebServices Tutorials</a></li>
  </ul>
</ul>

<h2>TextTwist Challenge (<a href="http://get.games.yahoo.com/proddesc?gamekey=texttwist">Link to Game</a>)</h2>
<p>Our first challenge will be to use the scrabble dictionary to efficiently play the TextTwist game offered by Yahoo! This challenge will have two parts: correctly unscrambling anagrams and efficiently unscramble thousands of words. Formal rules.</p>

<ol>
  <li>Correctly unscramble the following names to a single word: "Al Kaline", "Al Green", "Eric Clapton", "Liam Brady", "Lou Reed", "Tom Cruise"</li>
  <li>Score at least 10k on TextTwist and send Jayson a screenshot.</li>
  <li>Correctly unscramble the list of words Jayson provides in a file (will provide later in the week)</li>
  <ul>
     <li>Whitespace might be included with the words. Be sure to remove it.</li>
     <li>Capitalization might be used with the words. Be sure to handle it.</li>
  </ul>
</ol>

<p>The fastest code to correctly unscramble the list of words that Jayson provides wins the challenge. Remember that you can use buffered file I/O, multiple threads, and the profiler to speed up your code.</p>

<p>Files you'll need</p>
<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/WORD.LST">Enable 2k Word List</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/Dictionary.java">Dictionary.java</a>: Loads words from a file and gives you an array of Strings.</li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/Main.java">Main.java</a>: template for the main code.</li>
</ul>

<h2>Wednesday TextTwist Challenge Scrambled Words</h2>
<p>The scrambled words are in the file linked below. Each word is delimited by a comma and no new-line spaces are provided.</p>

<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/mem/scrambled-words.txt">scrambled-words.txt</a></li>
  <li>If you are interested, <a href="#scramble-code">here is the code</a> that was used to make the above.</li>
</ul>

<p>Provide your results in a file that has one line for each scrambled word. On that line specify the scrambled word followed by a comma and any words that can be made from using all letters. If more than one word is possible, delimit possible words with a comma. For example:</p>

<pre>
folo,fool,loof
otps,opts,stop,pots
</pre>

<h2>Rock-Paper-Scissors Challenge</h2>
<p>Prepare yourself for an intense battle of wit. Not only are we learning Java, but we're practicing for the Rock-Paper-Scissors world championships. In this challenge you must create up to two players for a Rock-Paper-Scissors tournament.</p>

<p>Download the ZIP file below to get started.</p>

<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/rpc.zip">The Rock, Paper, Scissors Packages</a></li>
  <li><b>Tuesday's Players:</b> <a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsPlayers.jar">RockPaperScissorsPlayers.jar</a> (only .class files, no source!)</li>
  <li><b>Wednesday's Players:</b> <a href="http://weblogs.java.net/blog/jfalkner/archive/mem/WednesdayRockPaperScissorsPlayers.jar">WednesdaysRockPaperScissors.jar</a> (only .class files, no source!)</li>
</ul>

<p>Make a sub-class of Player that plays our your ideal strategy for Rock-Paper-Scissors. Send in this player to Jayson, and he'll add it to the grand tournament that everyone is playing in.</p>

<p>Remember. Rock beats scissors. Paper beats rock. Scissors beats paper.</p>

<h2>Tuesday's Rock-Paper-Scissors Player Standings</h2>
<p>Regular player standings without including Jayson's learning player.</p>
<pre style="font-family:monospace;">
*** Statistics after playing 10000 tournaments ***
BadMoe: 4939 wins or 49.39%
RickPlayer: 1785 wins or 17.85%
FooPlayer: 1379 wins or 13.79%
RandomForTheWin: 1114 wins or 11.14%
PlayerThomas: 678 wins or 6.78%
BeatRepeaters: 72 wins or 0.72%
RockForTheWin: 21 wins or 0.21%
PaperForTheWin: 14 wins or 0.14%
ScissorsForTheWin: 7 wins or 0.07%

*** Tables of Wins/Loses/Ties versus a particular opponent ***
                   BadMoe             BeatRepeaters      FooPlayer          PaperForTheWin     PlayerThomas       RandomForTheWin    RickPlayer         RockForTheWin      ScissorsForTheWin  
BadMoe             0/0/0              2699/96/152        2797/1250/406      2004/0/0           3962/242/444       1549/1645/551      4534/806/472       2063/0/0           2027/0/0           
BeatRepeaters      96/2699/152        0/0/0              254/1556/242       1246/107/51        68/1771/268        768/800/252        95/2184/194        1198/86/49         1228/94/64         
FooPlayer          1250/2797/406      1556/254/242       0/0/0              1498/0/0           618/1592/514       1065/1125/371      872/1713/691       1517/0/0           1553/0/0           
PaperForTheWin     0/2004/0           107/1246/51        0/1498/0           0/0/0              0/1549/0           630/547/220        0/1748/0           1170/0/0           0/1250/0           
PlayerThomas       242/3962/444       1771/68/268        1592/618/514       1549/0/0           0/0/0              1149/1142/338      328/2471/593       1604/0/0           1558/0/0           
RandomForTheWin    1645/1549/551      800/768/252        1125/1065/371      547/630/220        1142/1149/338      0/0/0              1235/1260/433      581/600/209        663/583/204        
RickPlayer         806/4534/472       2184/95/194        1713/872/691       1748/0/0           2471/328/593       1260/1235/433      0/0/0              1704/0/0           1690/0/0           
RockForTheWin      0/2063/0           86/1198/49         0/1517/0           0/1170/0           0/1604/0           600/581/209        0/1704/0           0/0/0              1138/0/0           
ScissorsForTheWin  0/2027/0           94/1228/64         0/1553/0           1250/0/0           0/1558/0           583/663/204        0/1690/0           0/1138/0           0/0/0              
</pre>

<p><u>With</u> Jayson's learning player. Ack, dynamic strategy is still dominating!</p>
<pre style="font-family:monospace;">
*** Statistics after playing 10000 tournaments ***
LearningRockPaperScissors: 7417 wins or 74.17%
RandomForTheWin: 1005 wins or 10.05%
BadMoe: 862 wins or 8.62%
RickPlayer: 310 wins or 3.1%
FooPlayer: 244 wins or 2.44%
PlayerThomas: 121 wins or 1.21%
BeatRepeaters: 31 wins or 0.31%
PaperForTheWin: 8 wins or 0.08%
ScissorsForTheWin: 8 wins or 0.08%
RockForTheWin: 4 wins or 0.04%

*** Tables of Wins/Loses/Ties versus a particular opponent ***
                           BadMoe                     BeatRepeaters              FooPlayer                  LearningRockPaperScissors  PaperForTheWin             PlayerThomas               RandomForTheWin            RickPlayer                 RockForTheWin              ScissorsForTheWin          
BadMoe                     0/0/0                      1878/79/95                 1638/577/255               261/6099/215               1453/0/0                   2188/106/331               1167/1143/410              2185/350/296               1430/0/0                   1431/0/0                   
BeatRepeaters              79/1878/95                 0/0/0                      207/1228/180               113/2474/103               1154/48/13                 70/1439/172                728/684/229                61/1596/142                1207/66/22                 1142/51/17                 
FooPlayer                  577/1638/255               1228/207/180               0/0/0                      29/4213/21                 1334/0/0                   453/1128/272               811/887/290                630/921/485                1284/0/0                   1311/0/0                   
LearningRockPaperScissors  6099/261/215               2474/113/103               4213/29/21                 0/0/0                      1669/0/0                   4124/9/2                   1604/1544/522              4678/141/111               1709/0/0                   1669/1/0                   
PaperForTheWin             0/1453/0                   48/1154/13                 0/1334/0                   0/1669/0                   0/0/0                      0/1350/0                   533/515/160                0/1349/0                   1159/0/0                   0/1092/0                   
PlayerThomas               106/2188/331               1439/70/172                1128/453/272               9/4124/2                   1350/0/0                   0/0/0                      905/870/278                252/1473/390               1220/0/0                   1270/0/0                   
RandomForTheWin            1143/1167/410              684/728/229                887/811/290                1544/1604/522              515/533/160                870/905/278                0/0/0                      960/941/311                532/553/193                616/505/196                
RickPlayer                 350/2185/296               1596/61/142                921/630/485                141/4678/111               1349/0/0                   1473/252/390               941/960/311                0/0/0                      1353/0/0                   1296/0/0                   
RockForTheWin              0/1430/0                   66/1207/22                 0/1284/0                   0/1709/0                   0/1159/0                   0/1220/0                   553/532/193                0/1353/0                   0/0/0                      1143/0/0                   
ScissorsForTheWin          0/1431/0                   51/1142/17                 0/1311/0                   1/1669/0                   1092/0/0                   0/1270/0                   505/616/196                0/1296/0                   0/1143/0                   0/0/0                      
</pre>



<h2>Scrambling Code</h2>
<p>This is the code that I used to scramble words. You don't need to run this code! It is only intended so that you can have an example of file input/output and so that you can see that I'm not using any fancy tricks.</p>
<pre>
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;

/**
 * This is the code that makes the random file with scrambled string values.
 */
public class MakeRandomList {
    
    public static void main(String[] args) throws Exception {
        ArrayList<Character> chars = new ArrayList();
        
        // the output file
        FileWriter fw = new FileWriter("C:/scrambled-words.txt");
        
        
        // read all of the words
        InputStream is = Dictionary.class.getClassLoader().getResourceAsStream("WORD.LST");
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        for (String s= br.readLine(); s != null; s = br.readLine()) {
            // randomly keep a word
            if (Math.random() < 0.3) continue;
            
            // sramble
            char[] ca = s.trim().toCharArray();
            for (char c : ca) {
                chars.add(c);
            }
            
            // optionally capitalize
            if (Math.random() > 0.5) {
                char c = chars.remove((int)(Math.random()*chars.size()));
                chars.add(Character.toUpperCase(c));
            }
            
            // optionally add some white space
            if (Math.random() > 0.8) {
                chars.add(' ');
            }
            
            // scramble
            Collections.shuffle(chars);
            
            // print out the word
            String output = "";
            for (char c : chars) {
                output += c;
            }
            fw.write(output+",");
            System.out.print(output+",");
            
            // clear/recycle the buffer
            chars.clear();
        }
        br.close();
        isr.close();
        is.close();
        
        // close the file writer
        fw.flush();
        fw.close();
    }
}
</pre>]]>

</content>
</entry>
<entry>
<title>Blarg#27: Don&apos;t use finalize() as your only teardown method.</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2007/07/blarg27_dont_us.html" />
<modified>2007-08-01T00:19:53Z</modified>
<issued>2007-08-01T00:17:35Z</issued>
<id>tag:weblogs.java.net,2007:/blog/jfalkner/98.7952</id>
<created>2007-08-01T00:17:35Z</created>
<summary type="text/plain">This is a classic problem that I see over and over again. The finalize() method is nice, but you shouldn&apos;t use it as your only tear-down method, especially when cleaning up files. Hopefully this posting will turn up when someone is trying to figure this out.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>In short, don't rely on the finalize() method as your only cleanup method, especially if it is deleting files. Instead make up a cleanup method (cleanup() works nicely) that lazy deletes things. Here is an example.</p>

<pre>
public class Example {
  boolean isCleanedUp = false;
  
  public synchronized void cleanup() {
    if (isCleanedUp) return;
    // flag as cleaned up
    isCleanedUp = true;
    // put your clean up code here.
    // delete files, close DB connections, etc.
  }

  public void finalize() {
    cleanup();
    super.finalize();
  }
}
</pre>

<p>Wait...why do the above if the garbage collector will always call finalize before freeing up memory associated with an object? The reason is because the garbage collector doesn't always get a chance to clean up objects before the JVM terminates. This can be problematic, particularly in cases where you've made a temporary file or a socket connection that needs to be properly cleaned up.</p>

<p>By using an explicit cleanup() method as shown above you have an explicit method for cleaning up resources associated with an object the moment you are done using the object. Additionally, the boolean flag protects your code from accidentally trying to clean up the resource twice. The term "lazy delete" is used loosely because this approach is like lazy loading. The delete will occur only once and only when the code actually needs to do it.</p>

<p>Do note that the cleanup() method also nicely works in a try-finally block.</p>

<pre>
Example example = null;
try {
  example = new Example();
  //  do whatever logic you need to
}
finally {
  example.cleanup();
}
</pre>

<p>And one last trick copied from <a href="http://www.java2s.com/Code/Java/Language-Basics/Usingfinalizetodetectanobjectthathasntbeenproperlycleanedup.htm">Bruce Eckel</a>. If you are worried that portions of your code aren't cleaning up resources properly, simply tweak the finalize() method to check the isCleanedUp boolean and report finalize() calls that occur before any explicit call to cleanup().</p>]]>

</content>
</entry>
<entry>
<title>Blarg #26: Latest Java 6 snapshot fixes xgl/Compiz rendering problems</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2007/02/latest_java_6_s_1.html" />
<modified>2007-02-11T08:22:45Z</modified>
<issued>2007-02-11T08:21:23Z</issued>
<id>tag:weblogs.java.net,2007:/blog/jfalkner/98.6526</id>
<created>2007-02-11T08:21:23Z</created>
<summary type="text/plain">I just installed xgl/Compiz/Beryl and am loving it; however, I noticed that Swing apps don&apos;t render. Sun has the bug report and the fix, but you have to download the latest Java binaries to get it.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>I just installed xgl/Beryl and am loving it; however, I noticed that Swing apps don't render. Sun has the bug report and the fix, but you have to download the latest Java binaries to get it.</p>

<p>Download Java 6u1 or better:</p>

<a href="http://download.java.net/jdk6/binaries/">http://download.java.net/jdk6/binaries/</a>

<p>Now go enjoy that sweet Linux eye candy...Beryl baby, burn.</p>]]>

</content>
</entry>
<entry>
<title>Apple: Java, JDBC, and JSP Course</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/07/apple_java_jdbc_1.html" />
<modified>2006-07-23T17:42:05Z</modified>
<issued>2006-07-17T22:47:30Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.5200</id>
<created>2006-07-17T22:47:30Z</created>
<summary type="text/plain">This is a blog page for the folks at Apple in Sacramento. We had a good time talking about Java, and here are some of the things that we&apos;ve done.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This is a blog page for the folks at Apple in Sacramento. We had a good time talking about Java, and here are some of the things that we've done.</p>


<p><b>Interesting Links and Info</b></p>
<ul>
  <li>Jayson's E-mail: jfalkner@umich.edu</li>
  <li><a href="http://java.sun.com/j2se/1.5.0/docs/api/">On-line Java 5 SE JavaDocs</a></li>
  <li><a href="http://java.sun.com/j2se/1.5.0/search.html">Sun's Java Docs Search Box</a></li>
 <li><a href="http://java.sun.com/performance/reference/whitepapers/5.0_performance.html">Java Performance White Paper</a></li>
  <li><a href="http://dada.perl.it/shootout/">Win32 Language Performance Shootout</a></li>
  <li>JAVA_OPTS is the system property that you can use to set JVM parameters, e.g. try "JAVA_OPTS=-Xmx512m" to have the JVM use 512 os RAM.</li>
  <li>Some examples of optimization</li>
  <ul>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/MemoryMonster.java">Stressing the garbage collector: MemoryMonster.java</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/performance/NonBufferedIO.java">Non-Buffered File IO (~3 seconds to read Enable2k)</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/performance/BufferedIO.java">Basic Buffered IO (~50 milliseconds)</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/performance/ManualBufferedIO.java">Buffered IO, bulk byte reading (~0 milliseconds)</a></li>
  </ul>

  <li>ClassLoader Example (for Alberto)</li>
  <ul>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/myclassloader.zip">Project 1: The URLClassLoader</a></li>
    <li><a href="hhttp://weblogs.java.net/blog/jfalkner/archive/myclient.zip">Project 2: Code that is used by the URLClassLoader</a></li>
  </ul>

  <li>Netbeans OSX Keyboard Shortcuts</li>
  <ul>
    <li><b>auto-format code:</b> CMD + SHIFT + f</li>
    <li><b>auto-import packages:</b> CTRL + SHIFT + f</li>
    <li><b>renaming class (all uses of it, including uses in other classes):</b> CTRL+Click on the .java file->Refactor->Rename</li>
    <li><b>renaming package (also auto-updates all package declarations):</b> CTRL+Click on the package->Refactor->Rename</li>
    <li><b>renaming a variable (auto-updates all uses of that variable):</b> Highlight the variable->CTRL+Click->Refactor->Rename</li>
    <li><b>auto-generate getters and setters:</b> Highlight the class fields->CTRL+Click->Refactor->Encapsulate Fields</li>
    <li><b>comment out multiple lines simultaneously:</b> Highlight the lines->CTRL+SHIFT+t</li>
    <li><b>uncomment multiple lines simultaneously:</b> Highlight the lines->CTRL+SHIFT+d</li>

  </ul>
</ul>

<p><b>Anagram Challenge Example</b></p>
<p>If you rearrange the names of "Al Kaline", "Al Green", "Eric Clapton", "Liam Brady", "Lou Reed", "Tom Cruise", what words from the English dictionary can you make. Each name will make at least one word.</p>
<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/WORD.LST">Enable2k Dictionary</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/Dictionary.java">Dictionary.java</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/Main.java">Main.java (incomplete, you add the methods)</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/AnagramSolver.java">Solution: AnagramSolver.java</a></li>
</ul>

<p><b>Text Twist Challenge</b></p>
<p>The Tuesday morning challenge is to modify your Anagram code to find all words that you can make, i.e. all the scrabble words that you could play or all of the words needed to win at <a href="http://games.yahoo.com/games/downloads/tx.html">Text Twist</a>.</p>

<p>If you send in a screenshot of your high-score I'll put it on this page for others to see. We'll keep the best score posted on-line as the winner.</p>
<p><b>Current Text Twist High Score:</b> Bill Newcomb</p>
<img alt="texttwist-highscore.jpg" src="http://weblogs.java.net/blog/jfalkner/archive/text-twist-highscore.jpg" width="500" height="400" />

<p><b>Tuesday Scrabble Challenge</b></p>
<p>We're getting closer to playing a full game of scrabble. For today's challenge you are asked to write code that attempts to find the highest scoring word from a rack of scrabble letters. You'll be given a full bag of scrabble letters, and your code will be tested to see how highly it can score using those letters.</p>

<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/TuesdayScrabble.zip">TuesdayScrabble.zip</a></li>
</ul>

<p><b>Wednesday Scrabble Challenge</b></p>
<p>We're now playing real scrabble. Your class must return an array of PlacedScrabbleLetter objects, which represents both a word and the location on the board that the word is placed. Several helper method have been added to the ScrabbleBoard class, and be sure to take a look at the two example scrabble players: ChooseFirstWordScrabblePlayer and ExtendUsingFirstWordScrabblePlayer.</p>

<p>Note that the board now also has letter and word multipliers same as a normal scrabble board. Finding the longest word is no longer the best bet! Be sure to consider what placed word would score the highest using the ScrabbleBoard class's calculateRealWordValue() method. </p>

<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/WednesdayScrabble.zip">WednesdayScrabble.zip</a></li>
</ul>

<p>Results from Wednesday scrabble are here. Out of 1000 games played John Morgan dominated, winning 84% of the matches. Here is a summary of the results and <a href="http://weblogs.java.net/blog/jfalkner/archive/scrabble.zip">here is a link to a log of all 1000 games (~1MB download)</a>.</p>

<pre style="background:#eeeeee;border-style:1px;border-color:black;border-style:solid;">
Average Scores:
  Morgan: 195
  Andy Masuo: 119
  DukeNukem: 43
Win Percentage:
  Morgan: 845 out of 1000; 84%
  Andy Masuo: 146 out of 1000; 14%
  DukeNukem: 9 out of 1000; 0%
</pre>


<p><b>Friday Links: JDBC, JSP, and Servlets</b></p>
<p>Here are a bunch of links for the last day of class. These are all related to JDBC, JSP, and Servlets.</p>

<ul>
  <li><a href="http://tomcat.apache.org/tomcat-4.1-doc/printer/jndi-datasource-examples-howto.html#MySQL%20DBCP%20Example">Howto configure the MySQL JDBC driver on Tomcat 4.x</a></li>
  <li><a href="http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html#Database%20Connection%20Pool%20(DBCP)%20Configurations">Tomcat 5.5 MySQL JDBC DataSource configuration</a></li>
  <li><a href="http://dev.mysql.com/downloads/connector/j/3.1.html">MySQL JDBC Driver</a></li>
   <li><a href="http://www.w3.org/MarkUp/">HTML Specification</a></li>
   <li><a href="http://www.w3.org/Style/CSS/">Cascading Styles Sheets Specification</a></li>
   <li><a href="http://java.sun.com/products/servlet/">Servlet Specification</a></li>
   <li><a href="http://java.sun.com/products/jsp">JavaServer Pages Specification</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/topcall-webapp.zip"><b>Example Webapp: TopCall</b></a><br/>This example shows uses of JDBC both with the original Class.forName() mechanism of creating a connection and the JDBC 2+ DataSource method (i.e. connection pooling in Tomcat). The example also happens to be generic code that you can use to do any SQL query and display the results as both a HTML table or a tab-delimited file.</li>
  <ul>
    <li>Unzip and set the folder as your project's folder in Netbeans.</li>
    <li>The 'src/java' folder contains all the Java sources including the helper code that uploads data to MySQL.</li>
    <li>The 'web' folder contains the webapp with everything, but the compiled source and the JSTL JAR files</li>
    <li>Under the project's properties add the JSTL JAR files</li>
  </ul>
  
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/ExampleWebapplication.zip"><b>JSP, Servlet, and Threading Example:</b></a><br/>This is an example web application showing both a servlet and  JSP. The JSP starts up a background process and presents a progress bar that updates when the page is refreshed. The servlet provides an example of generating binary output. The servlet can dynamically add signatures to an existing image and send the contents to a user as a JPG.</li>
  <ul>
    <li>Unzip the archive and set it as the project directory for a Netbeans.org web application.</li>
     <li>Java source-code and web app files are split same as the above project. Load them in to netbeans as 'existing sources'.</li>
     <li>A copy of the WAR is include and it is an easy way to drop the code in to Tomcat and see it work.</li>
  </ul>
  <li><a href="http://www.theserverside.com/tt/books/addisonwesley/ServletsJSP/index.tss">Download page for my book, "Servlets and JavaServer Pages; the J2EE Web Tier"</a></li>
</ul>]]>

</content>
</entry>
<entry>
<title>Blarg #25: A JSP that shows Request Headers</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/07/blarg_25_a_jsp.html" />
<modified>2006-07-04T02:33:02Z</modified>
<issued>2006-07-04T02:32:55Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.5145</id>
<created>2006-07-04T02:32:55Z</created>
<summary type="text/plain">This code as been shown many times before, including in my book. This is exactly what the title says: a JSP that will display the request headers sent by your browser. It is also a good example of how to use the JSP EL and the JSTL core tags to make an incredibly simple JSP.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>J2EE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This code as been shown many times before, including in <a href="http://www.jspbook.com/index.jsp">my book</a>. This is exactly what the title says: a JSP that will display the request headers sent by your browser. It is also a good example of how to use the JSP EL and the JSTL core tags to make an incredibly simple JSP.</p>

<p>Here is the code. Simply copy and paste it in to a JSP, ideally one that you are editing in <a href="http://www.netbeans.org">Netbeans</a>. You must have the JSTL JARs in your classpath.</p>

<pre style="background:#dddddd;border-style:solid;border-color:black;border-width:1px;padding:5px;">
&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;

&lt;html&gt;
&lt;head&gt;&lt;title&gt;HTTP Request Headers&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;h2&gt;This is a list of the HTTP request headers sent by your browser.&lt;/h2&gt;

&lt;c:forEach var="v" items="${header}"&gt;
    &lt;b&gt;${v.key}&lt;/b&gt;: ${v.value}&lt;br /&gt;
&lt;/c:forEach&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>]]>

</content>
</entry>
<entry>
<title>PWC Java Course 06/12/06</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/06/pwc_java_course.html" />
<modified>2006-06-18T00:15:21Z</modified>
<issued>2006-06-12T14:18:34Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.5003</id>
<created>2006-06-12T14:18:34Z</created>
<summary type="text/plain">This is reference page for the Java course I taught for PWC. We&apos;ll put links and notes here for things that we talk about in the course. You can also leave comments for anything that I miss.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>J2SE</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This is reference page for the Java course I taught for PWC. We'll put links and notes here for things that we talk about in the course. You can also leave comments for anything that I miss.</p>

<p>Links for the tools that we use.</p>
<ul>
  <li><a href="http://java.sun.com/j2se/1.5.0/download.jsp">Java Development Kit (JDK) 5.0</a>: This is the code that will compile and execute Java. Remeber to set your classpath to include the "/bin" directory and you may have to include the "-cp ." flag when running code.</li>
  <li><a href="http://www.netbeans.org">Netbeans IDE</a>: This is the tool that we used to develop code. You can also download the profiles from here.</li>
  <li><a href="http://java.sun.com/j2se/1.5.0/docs/api/">JavaDocs</a>: Your best buddy when programming. This code comes with "the Java platform" and it can make life easy when coding. Knowing what classes exist in the JavaDocs and how to use them is what makes for a great Java programmer.</li>
</ul>

<p>Links for the tools that we use.</p>
<ul>
  <li><a href="http://java.sun.com/j2se/1.5.0/download.jsp">Java Development Kit (JDK) 5.0</a>: This is the code that will compile and execute Java. Remeber to set your classpath to include the "/bin" directory and you may have to include the "-cp ." flag when running code.</li>
  <li><a href="http://www.netbeans.org">Netbeans IDE</a>: This is the tool that we used to develop code. You can also download the profiles from here.</li>
  <li><a href="http://java.sun.com/j2se/1.5.0/docs/api/">JavaDocs</a>: Your best buddy when programming. This code comes with "the Java platform" and it can make life easy when coding. Knowing what classes exist in the JavaDocs and how to use them is what makes for a great Java programmer.</li>
</ul>

<p>Links for the course games.</p>
<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsChallenge.html">Rock, Paper, Scissors Challenge</a></li>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsChallenge.zip">RockPaperScissorsChallenge.zip</a>
</li>
<li>Rock, Paper, Scissors Snapshots of Opponent's Code</li>
<ul>
  <li><a href="http://weblogs.java.net/blog/jfalkner/archive/TuesdayChallengers.jar">Tuesday's Challengers</a>: This JAR file includes the compiled code for the players on Tuesday. We won't look at the source-code until Friday. Here are the player names so that you can add them to your local tournment.<br/><br/>
<pre style="background-color:#dddddd;">
            "rockpaperscissorschallenge.JoeTuesday",
            "rockpaperscissorschallenge.JoeZinziTuesday",
            "rockpaperscissorschallenge.JaysonWalkerTuesday",
            "rockpaperscissorschallenge.MaheshTuesday",
            "rockpaperscissorschallenge.MartinTuesday",
            "rockpaperscissorschallenge.RoyLawsonTuesday",
            "rockpaperscissorschallenge.ScottDeBoerTuesday",
            "rockpaperscissorschallenge.SteveTuesday",
            "com.jirawat.JirawatUttayayaTuesday"
</pre>
</li>
<li><a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsChallengersWednesday.jar">Wednesday's Challengers</a>: This JAR file includes the compiled code for the players on Wednesday. We won't look at the source-code until Friday. Here are the player names so that you can add them to your local tournment.<br/><br/>
<pre style="background-color:#dddddd;">
            "rockpaperscissorschallenge.wednesday.Joe",
            "com.joezinzi.wednesday.JoeZinzi",
            "rockpaperscissorschallenge.wednesday.JaysonWalkerForTheWin",
            "rockpaperscissorschallenge.wednesday.MaheshForTheWin",
            "rockpaperscissorschallenge.wednesday.Martin",
            "com.roy.rpc.wednesday.RoyLawsonRPS",
            "rockpaperscissorschallenge.wednesday.ScottDeBoer",
            "PackageTest.wednesday.SteveRockPaperScissors4",
            "com.jirawat.wednesday.JirawatUttayayaRps"
</pre>
</li>
<li><a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsChallengersThursday.jar">Thursday's Challengers</a>:
<pre style="background-color:#dddddd;">
            "rockpaperscissorschallenge.thursday.Joe",
            "com.joezinzi.thursday.JoeZinzi",
            "com.jaysonwalker.rpc.thursday.JaysonWalkerForTheWin",
            "rockpaperscissorschallenge.thursday.MaheshForTheWin",
            "com.martinrokicki.thursday.MartinRockPaperScissors",
            "com.roy.rpc.thursday.RoyLawsonRPS",
            "rockpaperscissorschallenge.thursday.ScottDeBoer",
            "PackageTest.thursday.SteveRockPaperScissors4",
            "com.jirawat.thursday.JirawatUttayayaRps"
</pre> 
</li>

<li><p><a href="http://weblogs.java.net/blog/jfalkner/archive/RockPaperScissorsChallengeFriday.jar">Friday's Challengers + Jayson's Learning Player</a>: This is the final JAR file for Friday's code. Congrats to Joe Zinzi for coming out with the best code. You'll have to also include Thursday's JAR and the players from the original challenge code in order to include all the players in the list.</p>
<p>I've included one more player: LearningRockPaperScissors. This player learns how to play based on how everyone else is playing -- behold the power of static variables! You'll note that this code wins 60% of the time after 1,000 tournaments, 75% of the time after 10,000 tournaments, and 80%+ of the time with 100,000 tournaments. It seems to handily beat any hard-coded strategy. Take a peek at the code. I've e-mailed it to everyone in the class with the final source-code ZIP.</p>
<pre style="background-color:#dddddd;">
            // default players
            "rockpaperscissorschallenge.RockForTheWin",
            "rockpaperscissorschallenge.ScissorsForTheWin",
            "rockpaperscissorschallenge.PaperForTheWin",
            "rockpaperscissorschallenge.BeatRepeaters",
            "rockpaperscissorschallenge.RandomForTheWin",
            // class players
            "rockpaperscissorschallenge.JoeTuesday",
            "com.joezinzi.JoeZinzi",
            "com.jaysonwalker.rpc.wednesday.JaysonWalkerForTheWin",
            "rockpaperscissorschallenge.thursday.MaheshForTheWin",
            "com.martinrokicki.thursday.MartinRockPaperScissors",
            "com.roy.rpc.thursday.RoyLawsonRPS",
            "rockpaperscissorschallenge.thursday.ScottDeBoer",
            "PackageTest.SteveRockPaperScissors5",
            "com.jirawat.thursday.JirawatUttayayaRps",
            "rockpaperscissorschallenge.LearningRockPaperScissors"
</pre> 

<p>And here is a printout of the class's final results:</p>

<pre style="background-color:#dddddd;">
*** Statistics after playing 10000 tournaments ***
JoeZinzi: 2445 wins or 24.45%
MartinRockPaperScissors: 2133 wins or 21.33%
SteveRockPaperScissors5: 1811 wins or 18.11%
JaysonWalkerForTheWin: 807 wins or 8.07%
RandomForTheWin: 752 wins or 7.52%
RoyLawsonRPS: 752 wins or 7.52%
MaheshForTheWin: 681 wins or 6.81%
JirawatUttayayaRps: 479 wins or 4.79%
ScottDeBoer: 142 wins or 1.42%
BeatRepeaters: 8 wins or 0.08%

*** Tables of Wins/Loses/Ties versus a particular opponent ***
                         SteveRockPaperScissors5  JaysonWalkerForTheWin    JirawatUttayayaRps       JoeZinzi                 MartinRockPaperScissors  RoyLawsonRPS             BeatRepeaters            JoeTuesday               PaperForTheWin           RandomForTheWin          RockForTheWin            ScissorsForTheWin        MaheshForTheWin          ScottDeBoer              
SteveRockPaperScissors5  0/0/0                    2641/0/0                 1444/232/478             682/2302/462             1524/1239/355            1293/661/497             941/212/194              0/0/0                    1021/0/0                 879/842/307              962/0/0                  980/0/0                  764/766/778              1265/283/218             
JaysonWalkerForTheWin    0/2641/0                 0/0/0                    628/611/619              307/1543/889             662/1709/260             1967/18/72               1217/57/5                0/0/0                    956/0/0                  759/749/284              998/0/0                  1015/0/0                 2104/0/0                 645/678/222              
JirawatUttayayaRps       232/1444/478             611/628/619              0/0/0                    805/1372/141             695/1207/279             440/845/564              1196/0/0                 0/0/0                    967/0/0                  664/664/230              992/0/0                  1010/0/0                 0/1727/0                 471/0/995                
JoeZinzi                 2302/682/462             1543/307/889             1372/805/141             0/0/0                    1137/1619/782            1614/768/255             1377/0/0                 0/0/0                    1038/0/0                 930/928/309              1096/0/0                 1082/0/0                 1342/965/191             1990/0/0                 
MartinRockPaperScissors  1239/1524/355            1709/662/260             1207/695/279             1619/1137/782            0/0/0                    1758/513/265             1314/37/64               0/0/0                    995/0/0                  949/938/298              1018/0/0                 1008/0/0                 1645/606/239             1132/304/349             
RoyLawsonRPS             661/1293/497             18/1967/72               845/440/564              768/1614/255             513/1758/265             0/0/0                    973/72/179               0/0/0                    995/0/0                  744/707/248              925/0/0                  931/0/0                  1907/0/0                 1035/173/386             
BeatRepeaters            212/941/194              57/1217/5                0/1196/0                 0/1377/0                 37/1314/64               72/973/179               0/0/0                    0/0/0                    837/0/0                  472/457/171              829/0/0                  899/0/0                  50/1098/72               0/1095/0                 
JoeTuesday               0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    0/0/0                    
PaperForTheWin           0/1021/0                 0/956/0                  0/967/0                  0/1038/0                 0/995/0                  0/995/0                  0/837/0                  0/0/0                    0/0/0                    406/370/128              804/0/0                  0/810/0                  0/970/0                  0/978/0                  
RandomForTheWin          842/879/307              749/759/284              664/664/230              928/930/309              938/949/298              707/744/248              457/472/171              0/0/0                    370/406/128              0/0/0                    384/423/141              392/368/128              734/740/266              561/564/186              
RockForTheWin            0/962/0                  0/998/0                  0/992/0                  0/1096/0                 0/1018/0                 0/925/0                  0/829/0                  0/0/0                    0/804/0                  423/384/141              0/0/0                    794/0/0                  0/1029/0                 0/887/0                  
ScissorsForTheWin        0/980/0                  0/1015/0                 0/1010/0                 0/1082/0                 0/1008/0                 0/931/0                  0/899/0                  0/0/0                    810/0/0                  368/392/128              0/794/0                  0/0/0                    0/922/0                  0/901/0                  
MaheshForTheWin          766/764/778              0/2104/0                 1727/0/0                 965/1342/191             606/1645/239             0/1907/0                 1098/50/72               0/0/0                    970/0/0                  740/734/266              1029/0/0                 922/0/0                  0/0/0                    1544/0/0                 
ScottDeBoer              283/1265/218             678/645/222              0/471/995                0/1990/0                 304/1132/349             173/1035/386             1095/0/0                 0/0/0                    978/0/0                  564/561/186              887/0/0                  901/0/0                  0/1544/0                 0/0/0                    
BUILD SUCCESSFUL (total time: 14 seconds)
</pre>

<p>And here is a printout when the LearningRockPaperScissors class enters the mix.</p>

<pre style="background-color:#dddddd;">
*** Statistics after playing 10000 tournaments ***
LearningRockPaperScissors: 7687 wins or 76.87%
RandomForTheWin: 724 wins or 7.24%
MartinRockPaperScissors: 528 wins or 5.28%
JoeZinzi: 313 wins or 3.13%
SteveRockPaperScissors5: 263 wins or 2.63%
RoyLawsonRPS: 150 wins or 1.5%
JaysonWalkerForTheWin: 112 wins or 1.12%
MaheshForTheWin: 106 wins or 1.06%
JirawatUttayayaRps: 69 wins or 0.69%
ScottDeBoer: 38 wins or 0.38%
BeatRepeaters: 21 wins or 0.21%

*** Tables of Wins/Loses/Ties versus a particular opponent ***
                           SteveRockPaperScissors5    JaysonWalkerForTheWin      JirawatUttayayaRps         JoeZinzi                   MartinRockPaperScissors    RoyLawsonRPS               BeatRepeaters              JoeTuesday                 LearningRockPaperScissors  PaperForTheWin             RandomForTheWin            RockForTheWin              ScissorsForTheWin          MaheshForTheWin            ScottDeBoer                
SteveRockPaperScissors5    0/0/0                      1794/0/0                   1044/165/338               383/1300/300               959/810/246                898/469/370                773/197/171                0/0/0                      0/4117/4                   866/0/0                    705/684/240                856/0/0                    946/0/0                    548/583/525                986/251/144                
JaysonWalkerForTheWin      0/1794/0                   0/0/0                      475/461/477                216/965/567                416/1167/197               1443/10/39                 1089/50/3                  0/0/0                      0/3392/1                   888/0/0                    608/669/199                883/0/0                    876/0/0                    1554/0/0                   555/563/211                
JirawatUttayayaRps         165/1044/338               461/475/477                0/0/0                      566/899/85                 521/876/231                318/647/414                1077/0/0                   0/0/0                      8/2705/5                   853/0/0                    608/597/176                829/0/0                    891/0/0                    0/1417/0                   409/0/818                  
JoeZinzi                   1300/383/300               965/216/567                899/566/85                 0/0/0                      684/1019/454               1122/469/176               1185/0/0                   0/0/0                      11/4612/14                 867/0/0                    739/758/250                922/0/0                    887/0/0                    939/647/137                1506/0/0                   
MartinRockPaperScissors    810/959/246                1167/416/197               876/521/231                1019/684/454               0/0/0                      1185/354/177               1090/26/59                 0/0/0                      345/3984/165               873/0/0                    773/750/248                924/0/0                    872/0/0                    1137/442/162               933/218/300                
RoyLawsonRPS               469/898/370                10/1443/39                 647/318/414                469/1122/176               354/1185/177               0/0/0                      807/72/155                 0/0/0                      94/3078/85                 884/0/0                    601/629/213                904/0/0                    852/0/0                    1431/0/0                   763/155/293                
BeatRepeaters              197/773/171                50/1089/3                  0/1077/0                   0/1185/0                   26/1090/59                 72/807/155                 0/0/0                      0/0/0                      142/1185/131               805/0/0                    420/427/158                804/0/0                    768/0/0                    42/1018/52                 0/949/0                    
JoeTuesday                 0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      0/0/0                      
LearningRockPaperScissors  4117/0/4                   3392/0/1                   2705/8/5                   4612/11/14                 3984/345/165               3078/94/85                 1185/142/131               0/0/0                      0/0/0                      976/0/1                    1230/1226/417              992/1/0                    954/0/1                    3107/5/0                   2029/51/33                 
PaperForTheWin             0/866/0                    0/888/0                    0/853/0                    0/867/0                    0/873/0                    0/884/0                    0/805/0                    0/0/0                      0/976/1                    0/0/0                      391/367/115                788/0/0                    0/788/0                    0/939/0                    0/829/0                    
RandomForTheWin            684/705/240                669/608/199                597/608/176                758/739/250                750/773/248                629/601/213                427/420/158                0/0/0                      1226/1230/417              367/391/115                0/0/0                      352/342/106                380/348/139                607/654/214                501/532/183                
RockForTheWin              0/856/0                    0/883/0                    0/829/0                    0/922/0                    0/924/0                    0/904/0                    0/804/0                    0/0/0                      1/992/0                    0/788/0                    342/352/106                0/0/0                      764/0/0                    0/853/0                    0/840/0                    
ScissorsForTheWin          0/946/0                    0/876/0                    0/891/0                    0/887/0                    0/872/0                    0/852/0                    0/768/0                    0/0/0                      0/954/1                    788/0/0                    348/380/139                0/764/0                    0/0/0                      0/901/0                    0/834/0                    
MaheshForTheWin            583/548/525                0/1554/0                   1417/0/0                   647/939/137                442/1137/162               0/1431/0                   1018/42/52                 0/0/0                      5/3107/0                   939/0/0                    654/607/214                853/0/0                    901/0/0                    0/0/0                      1282/0/0                   
ScottDeBoer                251/986/144                563/555/211                0/409/818                  0/1506/0                   218/933/300                155/763/293                949/0/0                    0/0/0                      51/2029/33                 829/0/0                    532/501/183                840/0/0                    834/0/0                    0/1282/0                   0/0/0                      
BUILD SUCCESSFUL (total time: 15 seconds)
</pre>

</li>
</ul>

<li><a href="http://weblogs.java.net/blog/jfalkner/archive/SudokuChallenge.html">Sudoku Challenge</a></li>
<li><a href="http://weblogs.java.net/blog/jfalkner/archive/SudokuChallenge.zip">SudokuChallenge.zip</a></li>

</ul>

<p>Other helpful links we talked about.</p>
<ul>
  <li><a href="http://jakarta.apache.org/commons/fileupload/">This</a> is the file upload code I was showing.</li>
  <li><a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">Sun's recommended coding conventions</a></li>
  <li><a href="http://java.sun.com/docs/books/jls/index.html">The Java Language Specification (i.e. bathroom reading material)</a></li>
</ul>
]]>

</content>
</entry>
<entry>
<title>Blarg #20: The talk you probably won&apos;t hear at JavaOne 2006</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/05/blarg_20_the_ta.html" />
<modified>2006-05-24T00:53:16Z</modified>
<issued>2006-05-17T18:07:25Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.4294</id>
<created>2006-05-17T18:07:25Z</created>
<summary type="text/plain">J1 this year has been interesting. On my way over to the conference I found out that my technical session talk had been changed from &quot;alternate status&quot; to a scheduled time. Unfortuneately the time was Friday afternoon at the same time as my flight out of San Fran. So they cancelled it, but a few hundred of you had already signed up for the talk. I suggested switching to any other tech slot or to a BOF. I ended up with a 9:30pm BOF-timed but still named &quot;technical&quot; section. At the current moment, I&apos;m not sure if I should consider this a talk or not, but I&apos;m pretty sure that you probably won&apos;t be there. Here is a summary of what was presented.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>
<dc:subject>JavaOne</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>J1 this year has been interesting. On my way over to the conference I found out that my technical session talk had been changed from "alternate status" to a scheduled time. Unfortuneately the time was Friday afternoon at the same time as my flight out of San Fran. So they cancelled it, but a few hundred of you had already signed up for the talk. I suggested switching to any other tech slot or to a BOF. I ended up with a 9:30pm BOF-timed but still named "technical" section. At the current moment, I'm not sure if I should consider this a talk or not, but I'm pretty sure that you probably won't be there. Here is a summary of what was presented.</p>

<p>The presentation is geared toward the working person who needs to set up a single server, Java-powered web application. Similar to the no-fluff style talks, I'm sticking to cost effective, time effective tricks so that you can quickly set up a website that works and if required, can avoid most all of the common growing pains.<p>

<p>Did you know that you can get and use a production quality Java web server, codebase, build tools, IDE, and database without paying a dime or having to learn all that is the J2EE beast? You probably won't be hearing this at JavaOne. I'll post the links and summary after the talk!</p>

<p>The talk went well, and a surprisingly large number of people showed up even after last-minute time change. We didn't have many questions, to record and present in this blog. No surprise since it was 10pm! Here are the links and tools I mentioned during the talk.</p>
<dl>
  <dt><a href="http://tomcat.apache.org">Tomcat</a></dt>
  <dd>The reference implementation for Servlets and JavaServer Pages. This is a alternative to using a full-fledged J2EE server, particularly helpful if you are not using EJB.</dd>

  <dt><a href="http://ant.apache.org">Ant</a></dt>
  <dd>A cross-platform build tool that can compile code, package WAR files, manipulate Tomcat, and more. A must have when developing web applications.</dd>

  <dt><a href="http://netbeans.org">Netbeans</a></dt>
  <dd>A Java-based IDE supported by Sun Microsystems. Free to use and it provides both Ant and Tomcat as built-in components for easy development of web applications. Netbeans also provides dot-completion, syntax highlighting, and more for both your Java code and JSP code.</dd>

  <dt><a href="http://hsqldb.org">HSQLDB</a></dt>
  <dd>A free, open-source database authored completely in Java that complies with the SQL 92 and 200 standards. Installation of this database is as trivial as dropping it in your classpath (i.e. WEB-INF/lib), which makes it a great choice for quickly setting up a website.</dd>
</dl>

<p>Here is a collection of other links that related to minor points made during the presentation.</p>

<ul>
  <li><a href="http://java.sun.com/products/servlet/">Servlet Specification</a></li>
  <li><a href="http://java.sun.com/products/jsp">JavaServer Pages Specification</a></li>
  <li><a href="http://www.w3.org/MarkUp/">HTML Specification</a></li>
  <li><a href="http://www.w3.org/Style/CSS/">Cascading Styles Sheets Specification</a></li>

  <li><a href="http://tomcat.apache.org/tomcat-5.5-doc/ssl-howto.html">Tomcat SSL Setup Tutorial</a></li>
</ul>

<p>Those are all the links I could dig up. If I missed something please let me know and I'll add it to the blarg.</p>]]>

</content>
</entry>
<entry>
<title>Blard #24: An image rollover JSP .tag</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blard_24_an_ima.html" />
<modified>2006-03-28T07:05:43Z</modified>
<issued>2006-03-28T07:05:11Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.4394</id>
<created>2006-03-28T07:05:11Z</created>
<summary type="text/plain">This is an example of a good use of JSP .tag files, a DHTML widget for making image rollovers. As with all my stuff, it is free for commercial and non-commercial use. If you like it, please remember to mention who originally wrote the code.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This is an example of a good use of JSP .tag files, a DHTML widget for making image rollovers. It was originally encoded as an example during a <a href="http://www.develop.com">Develop Mentor</a> Java Web Tier course I taught. As with all my stuff, it is free for commercial and non-commercial use. If you like it, please remember to mention who originally wrote the code.</p>

<p>Here is the code. Save it in your WEB-INF/tags directory.</p>
<pre>&lt;%@ tag isELIgnored="false" %&gt;
&lt;%@ attribute name="image1" required="true" %&gt;
&lt;%@ attribute name="image2" required="true" %&gt;
&lt;%@ attribute name="link" required="true" %&gt;
&lt;%@ attribute name="name" required="true" %&gt;

&lt;a href="${link}"&gt;
&lt;image src="${image1}" border="0"
  name="${name}" 
  onmouseover="document.${name}.src='${image2}'"
  onmouseout="document.${name}.src='${image1}'"&gt;&lt;/a&gt;</pre>

<p>Using the code requires importing the taglib and setting attributes for the <b>name</b>, <b>image1</b>, <b>image2</b>, and <b>link</b> attributes. The name can be anything, but it must be unique out of all the other tags on the page. The two image attributes are the images to show initially and when the mouse is over respectively. The link attribute is for setting a hyperlink.</p>

<p>Here is an example JSP.</p>
<pre>&lt;%@ taglib prefix="x" tagdir="/WEB-INF/tags" %&gt;
&lt;html&gt;
&lt;h1&gt;HelloWorld&lt;/h1&gt;

&lt;x:Rollover
  name="news"
  image1="http://www.proteomecommons.org/archive/1129421002687/news.jpg"
  image2="http://www.proteomecommons.org/archive/1129421002687/news-bite.jpg"
  link="http://www.google.com"/&gt;&lt;br/&gt;
  
&lt;/html&gt;</pre>]]>

</content>
</entry>
<entry>
<title>Blarg #23: Can&apos;t use the back button filter.</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blarg_23_cant_u.html" />
<modified>2006-03-28T06:53:02Z</modified>
<issued>2006-03-28T06:52:20Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.4393</id>
<created>2006-03-28T06:52:20Z</created>
<summary type="text/plain">This is an example Filter that uses JavaScript to try and ensure that people can&apos;t click the back button to revisit pages on your website. It was originally encoded as an example during a Develop Mentor course I taught. It is a nice example of a servlet filter that buffers a response, locates the body tag using a simple regular expression, and inserts a call to &apos;history.forward()&apos;. As with all my stuff, it is free for commercial and non-commercial use. If you like it, please remember to mention who originally wrote the code.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This is an example Filter that uses JavaScript to try and ensure that people can't click the back button to revisit pages on your website. It was originally encoded as an example during a Develop Mentor course I taught. It is a nice example of a servlet filter that buffers a response, locates the body tag using a simple regular expression, and inserts a call to 'history.forward()'. As with all my stuff, it is free for commercial and non-commercial use. If you like it, please remember to mention who originally wrote the code.</p>

<p>The code. Remember each filter has three parts: the Filter, ServletResponseWrapper, and ServletOutputStream sub-class.</p>
<ul>
  <li><a href="#filter">CantGoBackFilter.java</a></li>
  <li><a href="#wrapper">CantGoBackResponseWrapper.java</a></li>
  <li><a href="#outputstream">CantGoBackResponseStream.java</a></li>
</ul>

<h2><a name="filter"></a>CantGoBackFilter.java</h2>
<p>This filter wraps the HttpServletResponse in order to buffer text sent out to a client.</p>

<pre>package example.cgb;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CantGoBackFilter implements Filter {
    ServletContext sc = null;
    
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        // check that it is a HTTP request
        if (req instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            
            // nonce encode the normal output
            CantGoBackResponseWrapper wrappedResponse = new CantGoBackResponseWrapper(
                    response, sc);

            chain.doFilter(req, wrappedResponse);
            // finish the respone
            wrappedResponse.finishResponse();
        }
    }
    
    public void init(FilterConfig filterConfig) {
        // reference the context
        sc = filterConfig.getServletContext();
    }
    
    public void destroy() {
        // noop
    }
}</pre>

<h2><a name="wrapper"></a>CantGoBackResponseWrapper.java</h2>
<p>This wrapper sends back a custom ServletOutputStream object in order to buffer all text that is being sent to the client.</p>

<pre>package example.cgb;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class CantGoBackResponseWrapper extends HttpServletResponseWrapper {
    protected HttpServletResponse origResponse = null;
    protected ServletOutputStream stream = null;
    protected PrintWriter writer = null;
    ServletContext sc;
    
    public CantGoBackResponseWrapper(HttpServletResponse response, ServletContext sc) {
        super(response);
        this.sc = sc;
        origResponse = response;
    }
    
    public ServletOutputStream createOutputStream() throws IOException {
        return (new CantGoBackResponseStream(origResponse, sc));
    }
    
    public void finishResponse() {
        try {
            if (writer != null) {
                writer.close();
            } else {
                if (stream != null) {
                    stream.close();
                }
            }
        } catch (IOException e) {}
    }
    
    public void flushBuffer() throws IOException {
        stream.flush();
    }
    
    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException("getWriter() has already been called!");
        }
        
        if (stream == null)
            stream = createOutputStream();
        return (stream);
    }
    
    public PrintWriter getWriter() throws IOException {
        if (writer != null) {
            return (writer);
        }
        
        if (stream != null) {
            throw new IllegalStateException("getOutputStream() has already been called!");
        }
        
        stream = createOutputStream();
        // BUG FIX 2003-12-01 Reuse content's encoding, don't assume UTF-8
        writer = new PrintWriter(new OutputStreamWriter(stream, origResponse.getCharacterEncoding()));
        return (writer);
    }
    
    public void setContentLength(int length) {}
}
</pre>

<h2><a name="outputstream"></a>CantGoBackResponseStream.java</h2>
<p>This response stream buffers all text that is send to the client and uses a regular expression to locate the body tag and inject a JavaScript call to 'history.forward()', which fools most users in to thinking that they can't use the back button.</p>

<pre>package example.cgb;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 *
 * @author Jayson Falkner - jayson@jspinsider.com
 */
public class CantGoBackResponseStream extends ServletOutputStream {
    // abstraction of the output stream used for compression
    protected OutputStream bufferedOutput = null;
    
    // state keeping variable for if close() has been called
    protected boolean closed = false;
    
    // reference to original response
    protected HttpServletResponse response = null;
    
    // reference to the output stream to the client's browser
    protected ServletOutputStream output = null;
    
    // default size of the in-memory buffer
    private int bufferSize = 50000;
    
    ServletContext sc;
    
    public CantGoBackResponseStream(HttpServletResponse response, ServletContext sc) throws IOException {
        super();
        closed = false;
        this.sc = sc;
        this.response = response;
        this.output = response.getOutputStream();
        bufferedOutput = new ByteArrayOutputStream();
    }
    
    public void close() throws IOException {
        // make up a nonce
        String nonce = Integer.toString((int)(Math.random()*Integer.MAX_VALUE));
        // set the nonce in app scope
        sc.setAttribute("nonce", nonce);
        
        // get the content
        ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
        
        // make a string out of the response
        String pageText = new String(baos.toByteArray());
        
        // use regex to find the links
        Pattern p = Pattern.compile("<body[^>]*");
        Matcher m = p.matcher(pageText);
        
        String newText = "";
        int offset = 0;
        while (m.find(offset)) {
            // update the text
            newText += pageText.substring(offset, m.start());
            // update the offset
            offset = m.end();
            // get the matching string
            String match = pageText.substring(m.start(), m.end());
            // replace the body tag
            newText += "<body onload=\"history.forward();\"";
        }
        // add the final text
        newText += pageText.substring(offset, pageText.length());
        
        
        
        // set appropriate HTTP headers
//        response.setContentLength(compressedBytes.length);
        output.write(newText.getBytes());
        output.flush();
        output.close();
        closed = true;
        
    }
    
    public void flush() throws IOException {
        if (closed) {
            throw new IOException("Cannot flush a closed output stream");
        }
        bufferedOutput.flush();
    }
    
    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // write the byte to the temporary output
        bufferedOutput.write((byte) b);
    }
    
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }
    
    public void write(byte b[], int off, int len) throws IOException {
        System.out.println("writing...");
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // write the content to the buffer
        bufferedOutput.write(b, off, len);
    }
    
    public boolean closed() {
        return (this.closed);
    }
    
    public void reset() {
        //noop
    }
}</pre>]]>

</content>
</entry>
<entry>
<title>Blarg #22: A Filter that auto-encodes session IDs on relative page links.</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blarg_22_a_filt.html" />
<modified>2006-03-28T06:43:56Z</modified>
<issued>2006-03-28T06:43:49Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.4392</id>
<created>2006-03-28T06:43:49Z</created>
<summary type="text/plain">This is an example Filter that auto-encodes all relative links on a website using the HttpServletResponse.encodeURL() method. As with all my stuff, it is free for commercial and non-commercial use. If you like it, please remember to mention who originally wrote the code.</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>This is an example Filter that auto-encodes all relative links on a website using the HttpServletResponse.encodeURL() method. It was originally encoded as an example during a <a href="http://www.develop.com">Develop Mentor</a> course I taught. It is a nice example of a servlet filter that buffers a response, locates links using a simple regular expression, and replaces links with encoded links.</p>

<p>The code. Remember each filter has three parts: the Filter, ServletResponseWrapper, and ServletOutputStream sub-class.</p>
<ul>
  <li><a href="#filter">EncodeSessionInURLFilter.java</a></li>
  <li><a href="#wrapper">EncodeSessionInURLResponseWrapper.java</a></li>
  <li><a href="#outputstream">EncodeSessionInURLResponseStream.java</a></li>
</ul>

<h2><a name="filter"></a>EncodeSessionInURLFilter.java</h2>
<p>This filter does nothing more than wraps the HttpServletResponse in order to buffer text sent out to a client.</p>

<pre>package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class EncodeSessionInURLFilter implements Filter {
    ServletContext sc = null;
    
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
        // check that it is a HTTP request
        if (req instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            
            // nonce encode the normal output
            EncodeSessionInURLResponseWrapper wrappedResponse = new EncodeSessionInURLResponseWrapper(
                    response, sc);
            
            // make sure a session exists
            HttpSession session = request.getSession(true);
            
            chain.doFilter(req, wrappedResponse);
            // finish the respone
            wrappedResponse.finishResponse();
        }
    }
    
    public void init(FilterConfig filterConfig) {
        // reference the context
        sc = filterConfig.getServletContext();
    }
    
    public void destroy() {
        // noop
    }
}</pre>

<h2><a name="wrapper"></a>EncodeSessionInURLResponseWrapper.java</h2>
<p>This wrapper sends back a custom ServletOutputStream object in order to buffer all text that is being sent to the client.</p>

<pre>package example;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class EncodeSessionInURLResponseWrapper extends HttpServletResponseWrapper {
    protected HttpServletResponse origResponse = null;
    protected ServletOutputStream stream = null;
    protected PrintWriter writer = null;
    ServletContext sc;
    
    public EncodeSessionInURLResponseWrapper(HttpServletResponse response, ServletContext sc) {
        super(response);
        this.sc = sc;
        origResponse = response;
    }
    
    public ServletOutputStream createOutputStream() throws IOException {
        return (new EncodeSessionInURLResponseStream(origResponse, sc));
    }
    
    public void finishResponse() {
        try {
            if (writer != null) {
                writer.close();
            } else {
                if (stream != null) {
                    stream.close();
                }
            }
        } catch (IOException e) {}
    }
    
    public void flushBuffer() throws IOException {
        stream.flush();
    }
    
    public ServletOutputStream getOutputStream() throws IOException {
        if (writer != null) {
            throw new IllegalStateException("getWriter() has already been called!");
        }
        
        if (stream == null)
            stream = createOutputStream();
        return (stream);
    }
    
    public PrintWriter getWriter() throws IOException {
        if (writer != null) {
            return (writer);
        }
        
        if (stream != null) {
            throw new IllegalStateException("getOutputStream() has already been called!");
        }
        
        stream = createOutputStream();
        // BUG FIX 2003-12-01 Reuse content's encoding, don't assume UTF-8
        writer = new PrintWriter(new OutputStreamWriter(stream, origResponse.getCharacterEncoding()));
        return (writer);
    }
    
    public void setContentLength(int length) {}
}
</pre>

<h2><a name="outputstream"></a>EncodeSessionInURLResponseStream.java</h2>
<p>This response stream buffers all text that is send to the client and uses a regular expression to locate and replace links with encoded links.</p>

<pre>package example;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 *
 * @author Jayson Falkner - jayson@jspinsider.com
 */
public class EncodeSessionInURLResponseStream extends ServletOutputStream {
    // abstraction of the output stream used for compression
    protected OutputStream bufferedOutput = null;
    
    // state keeping variable for if close() has been called
    protected boolean closed = false;
    
    // reference to original response
    protected HttpServletResponse response = null;
    
    // reference to the output stream to the client's browser
    protected ServletOutputStream output = null;
    
    // default size of the in-memory buffer
    private int bufferSize = 50000;
    
    ServletContext sc;
    
    public EncodeSessionInURLResponseStream(HttpServletResponse response, ServletContext sc) throws IOException {
        super();
        closed = false;
        this.sc = sc;
        this.response = response;
        this.output = response.getOutputStream();
        bufferedOutput = new ByteArrayOutputStream();
    }
    
    public void close() throws IOException {
        // make up a nonce
        String nonce = Integer.toString((int)(Math.random()*Integer.MAX_VALUE));
        // set the nonce in app scope
        sc.setAttribute("nonce", nonce);
        
        // get the content
        ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;
        
        // make a string out of the response
        String pageText = new String(baos.toByteArray());
        
        // use regex to find the links
        Pattern p = Pattern.compile(" href=\"[^\"]*|action=\"[^\"]*");
        Matcher m = p.matcher(pageText);
        
        String newText = "";
        int offset = 0;
        while (m.find(offset)) {
            // update the text
            newText += pageText.substring(offset, m.start());
            // update the offset
            offset = m.end();
            // get the matching string
            String match = pageText.substring(m.start(), m.end());
            // get the URL
            String[] split = match.split("\"");
            String url = split[1];
            // encode the match
            String encoded = response.encodeURL(url);
            
            // add the match to the new text
            newText += split[0]+"\""+encoded;
        }
        // add the final text
        newText += pageText.substring(offset, pageText.length());
        
        
        
        // set appropriate HTTP headers
//        response.setContentLength(compressedBytes.length);
        output.write(newText.getBytes());
        output.flush();
        output.close();
        closed = true;
        
    }
    
    public void flush() throws IOException {
        if (closed) {
            throw new IOException("Cannot flush a closed output stream");
        }
        bufferedOutput.flush();
    }
    
    public void write(int b) throws IOException {
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // write the byte to the temporary output
        bufferedOutput.write((byte) b);
    }
    
    public void write(byte b[]) throws IOException {
        write(b, 0, b.length);
    }
    
    public void write(byte b[], int off, int len) throws IOException {
        System.out.println("writing...");
        if (closed) {
            throw new IOException("Cannot write to a closed output stream");
        }
        // write the content to the buffer
        bufferedOutput.write(b, off, len);
    }
    
    public boolean closed() {
        return (this.closed);
    }
    
    public void reset() {
        //noop
    }
}</pre>]]>

</content>
</entry>
<entry>
<title>Blarg #21: DevelopMentor JWT links that need to be on-line</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blarg_21_develo.html" />
<modified>2006-03-28T07:08:48Z</modified>
<issued>2006-03-20T18:08:34Z</issued>
<id>tag:weblogs.java.net,2006:/blog/jfalkner/98.4353</id>
<created>2006-03-20T18:08:34Z</created>
<summary type="text/plain">For those of you at DevelopMentor&apos;s Java Web Tier course, here are the links we used in class. If you weren&apos;t at this class and you want to learn about making websites with Java....</summary>
<author>
<name>jfalkner</name>

<email>jayson@jspinsider.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/jfalkner/">
<![CDATA[<p>For those of you at <a href="http://www.develop.com">DevelopMentor's</a> <a href="http://develop.com/us/training/course.aspx?id=202">Java Web Tier</a> course, here are the links we used in class. If you weren't at this class and you want to <a href="http://develop.com/us/training/course.aspx?id=202">learn about making websites with Java...</a>. Ha, I bet DM loves me now!</p>

<p>Here are those links.</p>

<ul>
  <li>Specifications: These are the documents you should use as references.</li>
  <ul>
    <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">HTTP Specification</a></li>
    <li><a href="http://java.sun.com/products/servlet/download.html">Servlet Specification</a></li>
    <li><a href="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/index.html">Servlet API JavaDocs</a></li>
    <li><a href="http://java.sun.com/products/servlet/download.html">Servlet Specification</a></li>
    <li><a href="http://java.sun.com/products/jsp/reference/api/index.html">JSP Specification</a></li>
    <li><a href="http://tomcat.apache.org/tomcat-5.5-doc/jspapi/index.html">JSP API JavaDocs</a></li>
    <li><a href="http://java.sun.com/products/jsp/jstl/reference/api/index.html">JSTL References</a></li>
    <ul>
      <li><a href="http://java.sun.com/products/jsp/jstl/1.1/docs/tlddocs/index.html">Docs for the tags that looks similar to JavaDocs (very helpful)</a></li>
      <li><a href="http://java.sun.com/products/jsp/jstl/1.1/docs/api/index.html">JavaDocs for the reference implementation code (not so helpful)</a></li>
    </ul>
  </ul>
  <li><a href="http://ant.apache.org/">Jakarta Ant</a>: The build tool</li>
  <ul>
    <li>To install: unzip the Ant code and set two system property values. One for "ANT_HOME" and one for "PATH". "ANT_HOME" should be the directory that has all the Ant files. The "PATH" variable should be the same as it was before but with a semi-colon ";" and "%ANT_HOME%/bin" appended.</li>
  </ul>
  <li><a href="http://tomcat.apache.org/">Jakarta Tomcat</a>: The reference Servlet/JSP. Not a bad choice at all for production use.</li>
  <li><a href="http://jakarta.apache.org/struts">Jakarta Struts</a>: one of the first MVC frameworks for Servlets/JSP.</li>
  <li><a href="http://jakarta.apache.org/commons/httpclient/">Jakarta Commons HTTP Client</a>: the slick web browser API that we used to develop HTTP tests and to spoof web requests.</li>
<li><a href="http://jakarta.apache.org/commons/httpclient/">Jakarta Commons File Upload</a>: An API that makes it trivial to do file uploads from HTML forms.</li>
  <li><a href="http://netbeans.org">Netbeans</a>: The tool I like to use when editing code. You can also <a href="http://profiler.netbeans.org">download and use that awesome profiler</a>.</li>
  <li><a href="http://mysql.com">MySQL</a>: The database we used in class. It is very easy to install and connect to your web application. Don't forget to get the <a href="http://dev.mysql.com/downloads/connector/j/5.0.html">JDBC driver</a>.</li>
  <li>Some code snippets from class</li>
  <ul>
    <li><a href="#sessionListener">The HttpSessionListener for counting the number of current users.</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blarg_23_cant_u.html">A servlet filter that doesn't let users click the back button of their web browser.</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blarg_22_a_filt.html">A servlet filter that auto-encodes jsessionid information in relative links on the the page.</a></li>
    <li><a href="http://weblogs.java.net/blog/jfalkner/archive/2006/03/blard_24_an_ima.html">The example .tag file for making an image rollover effect.</a></li>
  </ul>
</ul>

<h2>SessionCountListener.java</h2>
<p>This class counts the number of current sessions. When one is created, the count goes up. When one is destroyed, the count goes down. This is not a hit tracker. It is a count of "live" users.</p>

<pre>
package example;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 *A listener class that counts the number of concurent sessions.
 * @author Jayson Falkner - jfalkner@umich.edu
 */
public class SessionCountListener implements HttpSessionListener {
    int count = 0;
    
    /**
     *When a session is destroyed, decrement the counter.
     */
    public void sessionDestroyed(HttpSessionEvent se) {
        // increment the count
        count--;
        // set the attribute
        setAttribute(se);
    }
    
    /**
     *When a session is created, increment the counter.
     */
    public void sessionCreated(HttpSessionEvent se) {
        // decrement the count
        count++;
        // set the attribute
        setAttribute(se);
    }
    
    // helper method to set the attribte in 'application' scope
    private void setAttribute(HttpSessionEvent se) {
        // get the session
        HttpSession hs = se.getSession();
        // get the servlet context
        ServletContext sc = hs.getServletContext();
        // set the attribute on the servlet context
        sc.setAttribute("userCount", Integer.toString(count));
    }
}</pre>

<p>And don't forget that you must register this class via web.xml</p>
<pre>&lt;web-app&gt;
    &lt;listener&gt;
        &lt;listener-class&gt;example.SessionCountListener&lt;/listener-class&gt;
    &lt;/listener&gt;
    &lt;!-- rest of your web.xml stuff... --&gt;
&lt;/web-app&gt;
</pre>

<p>Finally, you can show the count from any JSP or serlvet that has access to the ServletContext object. Here is an example JSP.</p>
<pre>
&lt;html&gt;
    &lt;h1&gt;JSP Page ${userCount}&lt;/h1&gt;
&lt;/html&gt;
</pre>]]>

</content>
</entry>

</feed>