Hiển thị các bài đăng có nhãn Java (General). Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Java (General). Hiển thị tất cả bài đăng

Thứ Tư, 30 tháng 1, 2013

Hello Camel: Automatic File Transfer

Apache Camel is described on its main web page (and in the Camel User Guide) as "a versatile open-source integration framework based on known Enterprise Integration Patterns." The Camel framework is based on the book Enterprise Integration Patterns and provides implementations of the patterns described in that book. I look at a "Hello World" type example of using Camel in this post.

The Camel web page and Users Guide also reference the StackOverflow thread what exactly is Apache Camel? that includes several good descriptions of Apache Camel. David Newcomb has described Camel there:

Apache Camel is messaging technology glue with routing. It joins together messaging start and end points allowing the transference of messages from different sources to different destinations. For example: JMS->JSON, HTTP->JMS or funneling FTP->JMS, HTTP->JMS, JMS=>JSON.

In this post, I look at a simple use of Camel that doesn't require use of a JMS provider or even FTP or HTTP. Keeping the example simple makes it clearer how to use Camel. This example uses Camel to transfer files automatically from a specified directory to a different specified directory. Three cases will be demonstrated.

In the first case, files placed in the "input" directory are automatically copied to an "output" directory without affecting the source files. In the second case, the files placed in the "input" directory are automatically copied to an "output" directory and then the files in the "input" directory are stored in a special ".camel" subdirectory under the "input" directory. The third case removes the files from the "input" directory upon copying to the "output" directory (effectively a "move" operation). All three cases are implemented with almost identical code. The only difference between the three is in the single line specifying how Camel should handle the file transfers.

The next code listing shows the basic code needed to use Camel to automatically copy files placed in an input directory into a different output directory with Camel.


/**
* Simple executable function to demonstrate Camel file transfer.
*
* @param arguments Command line arguments; excepting duration in milliseconds
* as single argument.
*/
public static void main(final String[] arguments)
{
final long durationMs = extractDurationMsFromCommandLineArgs(arguments);
final CamelContext camelContext = new DefaultCamelContext();
try
{
camelContext.addRoutes(
new RouteBuilder()
{
@Override
public void configure() throws Exception
{
from("file:C:\\datafiles\\input?noop=true").to("file:C:\\datafiles\\output");
}
});
camelContext.start();
Thread.sleep(durationMs);
camelContext.stop();
}
catch (Exception camelException)
{
LOGGER.log(
Level.SEVERE,
"Exception trying to copy files - {0}",
camelException.toString());
}
}

The code above demonstrates minimal use of the Camel API and Camel's Java DSL support. A CamelContext is defined with an instantiation of DefaultCamelContext (line 10). Lines 13-21 add the Camel route to this instantiated context and line 22 starts the context with line 24 stopping the context. It's all pretty simple, but the most interesting part to me is the specification of the routing on line 19.

Because the instance implementing the RoutesBuilder interface provided to the Camel Context only requires its abstract configure method to be overridden, it is an easy class to instantiate as an anonymous class inline with the call to CamelContext.addRoutes(RoutesBuilder). This is what I did in the code above and is what is done in many of the Camel examples that are available online.

Line 19 shows highly readable syntax describing "from" and "to" portions of routing. In this case, files placed in the input directory ("from") are to be copied to the output directory ("to"). The "file" protocol is used on both the "from" and "to" portions because the file system is where the "message" is coming from and going to. The "?noop=true" in the "from" call indicates that nothing should be changed about the files in the "input" directory (the processing should have "noop" effect on the source files).

As just mentioned, Line 19 in the code above instructs Camel to copy files already in or placed in the "input" directory to the specified "output" directory without impacting the files in the "input" directory. In some cases, I may want to "move" the files rather than "copying" them. In such cases, ?delete=true can be specified instead of ?noop=true when specifying the "from" endpoint. In other words, line 19 above could be replaced with this to have files removed from the "input" directory when placed in the "output" directory. If no parameter is designated on the input (neither ?noop=true nor ?delete=true), then an action that falls in-between those occurs: the files in the "input" directory are moved into a specially created new subdirectory under the "input" directory called .camel. The three cases are highlighted next.

Files Copied from datafiles\input to datafiles\output Without Impacting Original Files

from("file:C:\\datafiles\\input?noop=true").to("file:C:\\datafiles\\output");
Files Moved from datafiles\input to datafiles\output

from("file:C:\\datafiles\\input?delete=true").to("file:C:\\datafiles\\output");
Files Copied from datafiles\input to datafiles\output and Original Files Moved to .camel Subdirectory

from("file:C:\\datafiles\\input").to("file:C:\\datafiles\\output");

As a side note, the uses of fluent "from" and "to" are examples of Camel's Java DSL. Camel implements this via implementation inheritance (methods like "from" and "to" are defined in the RouteBuilder class) rather than through static imports (an approach often used for Java-based DSLs.)

Although it is common to pass anonymous instances of RouteBuilder to the Camel Context, this is not a requirement. There can be situations in which it is advantageous to have standalone classes that extend RouteBuilder and have instances of those extended classes passed to the Camel Context. I'll use this approach to demonstrate all three cases I previously described. The next code listing shows a class that extends RouteBuilder. In many cases, I would have a no-arguments constructor, but in this case I use the constructor to determine which type of file transfer should be supported by the Camel route.

The next code listing shows a named standalone class that handles all three cases shown above (copying, copying with archiving of input files, and moving). This single extension of RouteBuilder takes an enum in its constructor to determine how to configure the input endpoint.


package dustin.examples.camel;

import org.apache.camel.builder.RouteBuilder;

/**
* Camel-based Route Builder for transferring files.
*
* @author Dustin
*/
public class FileTransferRouteBuilder extends RouteBuilder
{
public enum FileTransferType
{
COPY_WITHOUT_IMPACTING_ORIGINALS("C"),
COPY_WITH_ARCHIVED_ORIGINALS("A"),
MOVE("M");

private final String letter;

FileTransferType(final String newLetter)
{
this.letter = newLetter;
}

public String getLetter()
{
return this.letter;
}

public static FileTransferType fromLetter(final String letter)
{
FileTransferType match = null;
for (final FileTransferType type : FileTransferType.values())
{
if (type.getLetter().equalsIgnoreCase(letter))
{
match = type;
break;
}
}
return match;
}
}

private final String fromEndPointString;
private final static String FROM_BASE = "file:C:\\datafiles\\input";
private final static String FROM_NOOP = FROM_BASE + "?noop=true";
private final static String FROM_MOVE = FROM_BASE + "?delete=true";

public FileTransferRouteBuilder(final FileTransferType newFileTransferType)
{
if (newFileTransferType != null)
{
switch (newFileTransferType)
{
case COPY_WITHOUT_IMPACTING_ORIGINALS :
this.fromEndPointString = FROM_NOOP;
break;
case COPY_WITH_ARCHIVED_ORIGINALS :
this.fromEndPointString = FROM_BASE;
break;
case MOVE :
this.fromEndPointString = FROM_MOVE;
break;
default :
this.fromEndPointString = FROM_NOOP;
}
}
else
{
fromEndPointString = FROM_NOOP;
}
}

@Override
public void configure() throws Exception
{
from(this.fromEndPointString).to("file:C:\\datafiles\\output");
}
}

This blog post has demonstrated use of Camel to easily route files from one directory to another. Camel supports numerous other transport mechanisms and data formats that are not shown here. Camel also supports the ability to transform the messages/data being routed, which is also not shown here. This post focused on what is likely to be as simplest possible example of how to apply Camel in a useful manner, but Camel supports far more than shown in this simple example.

Thứ Hai, 14 tháng 1, 2013

Determining JDK Installation

I recently read in a book on a Java-based technology that one can determine if the JDK is installed by running java -version and looking for the the Strings "Client" or "Server" in the output of the version command. The authors of that book state that the presence of "Server VM" means the JDK is installed and the presence of "Client VM" means that the JDK is not installed (presumably implying that the JRE only is present because something is returned). Unfortunately, that is not a sufficient way to determine presence of the JDK. In this post, I look at how one can determine that the JDK is installed and on the path.

Before discussing approaches to determining if the JDK is installed, I first want to show why running java -version and looking for "Server" or "Client" to differentiate presence from absence of JDK is insufficient. The following screen snapshot (with yellow highlighting circles added to it) shows running java -version by itself, running java -client -version, and running java -server -version. The important take-away from this screen snapshot is that the it is the server versus client setting of the running JVM that truly determines whether the String "Server" or "Client" is present in the returned Java version information.

This screen snapshot indicates that the default VM is "Client" for this machine. This is not surprising given that the Server-Class Machine Detection page states that the "Default VM" for operating system "Microsoft Windows" on hardware architecture "i586" is "Default client VM." For most other "Sun-supported" architecture/OS combinations, the default tends to be "Server." On 64-bit architectures, the -client option is ignored and it is always the Server VM that is used, though the Java launcher documentation states that this last observation "is subject to change in a future release."

Running java -version does help determine if the Java application launcher is on the user's path. If it is not on the path, an error message indicating that "java" is a command not found would be expected. One can determine if some version of the JDK is on the path using javac -version. Because the Java compiler only comes with the JDK rather than the JRE, this is a simple test to make sure some version of the JDK is on your system and on your path. The -help flag could also be passed to javac to determine the presence of the JDK, but -version has the added benefit of telling the operator which version of the JDK is on the system and on the path. This is shown in the next screen snapshot.

If javac is not already on your path, running javac -version will return an error message stating that the command is not found. This could only mean that it's not on your path, but is still on your system. You can look for it by searching for the javac command using an operating system search tool (such as in Linux with whereis or find or in Windows with its directory/file search tools or via Control Panel's Uninstall/Change Programs tool). If javac -version is found and returns a version, you can determine which that is on Linux with whereis javac and on Windows with a command like grokster's recommendation:


for %i in (javac.exe) do @echo. %~$PATH:i

The next screen snapshot shows the Windows Control Panel approach for determining which versions of the JRE and JDK are on the Windows machine.

The "Java 7 Update 11" shown is the Java 7 JRE and does not include the JDK. The "Java SE Development Kit 7 Update 6" is a JDK as tipped off by the "Development Kit" portion.

For Windows machines, Java (whether JDK or JRE) might be installed in Program Files/Java and one can examine that directory to see which versions of Java are installed. This is shown in the next screen snapshot.

In the above screen snapshot, the three folders with "jdk" in their names are JDK installations and the folder with "jre" in its name is JRE only (no JDK).

Conclusion

I can understand why the authors of the book I was reading wanted to use presence of "Server" in the VM version information to indicate JDK and "Client" in the VM version to indicate JRE; this would be, if it worked, a much easier way for a reader relatively new to Java to make that determination. Unfortunately, it is not that easy as proven by the StackOverflow thread How to find where is JDK installed on my windows machine? and How do I know if I have Sun Java Development Kit installed? There are quite a few interesting ideas posted in both of those resources.

I didn't even look in this post at the complexity on Windows of multiple JRE deployments because my focus in this post was on finding installed JDKs. By the way, more information on the difference between the client VM and the server VM can be found in Real differences between "java -server" and "java -client"?, Java HotSpot VM Options, and JVM Server vs Client Mode.

Thứ Ba, 27 tháng 11, 2012

Type-safe Empty Collections in Java

I have blogged before on the utility of the Java Collections class and have specifically blogged on Using Collections Methods emptyList(), emptyMap(), and emptySet(). In this post, I look at the sometimes subtle but significant differences between using the relevant fields of the Collections class for accessing an empty collection versus using the relevant methods of the Collections class for accessing an empty collection.

The following code demonstrates accessing Collections's fields directly to specify empty collections.

Using Collections's Fields for Empty Collections

/**
* Instantiate my collections with empty versions using Collections fields.
* This will result in javac compiler warnings stating "warning: [unchecked]
* unchecked conversion".
*/
public void instantiateWithEmptyCollectionsFieldsAssigment()
{
this.stringsList = Collections.EMPTY_LIST;
this.stringsSet = Collections.EMPTY_SET;
this.stringsMap = Collections.EMPTY_MAP;
}

The code above compiles with javac, but leads to the warning message (generated by NetBeans and Ant in this case):


-do-compile:
[javac] Compiling 1 source file to C:\java\examples\typesafeEmptyCollections\build\classes
[javac] Note: C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java uses unchecked or unsafe operations.
[javac] Note: Recompile with -Xlint:unchecked for details.

Specifying -Xlint:unchecked as an argument to javac (in this case via the javac.compilerargs=-Xlint:unchecked in the NetBeans project.properties file) helps get more specific warning messages for the earlier listed code:


[javac] Compiling 1 source file to C:\java\examples\typesafeEmptyCollections\build\classes
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:27: warning: [unchecked] unchecked conversion
[javac] this.stringsList = Collections.EMPTY_LIST;
[javac] ^
[javac] required: List<String>
[javac] found: List
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:28: warning: [unchecked] unchecked conversion
[javac] this.stringsSet = Collections.EMPTY_SET;
[javac] ^
[javac] required: Set<String>
[javac] found: Set
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:29: warning: [unchecked] unchecked conversion
[javac] this.stringsMap = Collections.EMPTY_MAP;
[javac] ^
[javac] required: Map<String,String>
[javac] found: Map

NetBeans will also show these warnings if the appropriate hint box is checked in its options. The next three images demonstrate ensuring that the appropriate hint is set to see these warnings in NetBeans and provides an example of how NetBeans presents the code shown above with warnings.

Fortunately, it is easy to take advantage of the utility of the Collections class and access empty collections in a typesafe manner that won't lead to these javac warnings and corresponding NetBeans hints. That approach is to use Collections's methods rather than its fields. This is demonstrated in the next simple code listing.

Using Collections's Methods for Empty Collections

/**
* Instantiate my collections with empty versions using Collections methods.
* This will avoid the javac compiler warnings alluding to "unchecked conversion".
*/
public void instantiateWithEmptyCollectionsMethodsTypeInferred()
{
this.stringsList = Collections.emptyList();
this.stringsSet = Collections.emptySet();
this.stringsMap = Collections.emptyMap();
}

The above code will compile without warning and no NetBeans hints will be shown either. The Javadoc documentation for each field of the Collections class does not address why these warnings occur for the fields, but the documentation for each of the like-named methods does discuss this. Specifically, the documentation for Collections.emptyList(), Collections.emptySet(), and Collections.emptyMap() each state, "(Unlike this method, the field does not provide type safety.)"

Use of the Collections methods for empty collections shown in the last code listing provided type safety without the need to explicitly specify the types stored within that collection because type was inferred by use of the Collections methods in assignments to known and already declared instance attributes with explicitly specified element types. When type cannot be inferred, compiler errors will result when using the Collections methods without an explicitly specified type. This is shown in the next screen snapshot of attempting to do this in NetBeans.

The specific compiler error message is:


[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:62: error: method populateList in class Main cannot be applied to given types;
[javac] populateList(Collections.emptyList());
[javac] ^
[javac] required: List<String>
[javac] found: List<Object>
[javac] reason: actual argument List<Object> cannot be converted to List<String> by method invocation conversion
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:63: error: method populateSet in class Main cannot be applied to given types;
[javac] populateSet(Collections.emptySet());
[javac] ^
[javac] required: Set<String>
[javac] found: Set<Object>
[javac] reason: actual argument Set<Object> cannot be converted to Set<String> by method invocation conversion
[javac] C:\java\examples\typesafeEmptyCollections\src\dustin\examples\Main.java:64: error: method populateMap in class Main cannot be applied to given types;
[javac] populateMap(Collections.emptyMap());
[javac] ^
[javac] required: Map<String,String>
[javac] found: Map<Object,Object>
[javac] reason: actual argument Map<Object,Object> cannot be converted to Map<String,String> by method invocation conversion
[javac] 3 errors

These compiler errors are avoided and type safety is achieved by explicitly specifying the types of the collections' elements in the code. This is shown in the next code listing.

Explicitly Specifying Element Types with Collections's Empty Methods

/**
* Pass empty collections to another method for processing and specify those
* empty methods using Collections methods. This will result in javac compiler
* ERRORS unless the type is explicitly specified.
*/
public void instantiateWithEmptyCollectionsMethodsTypeSpecified()
{
populateList(Collections.<String>emptyList());
populateSet(Collections.<String>emptySet());
populateMap(Collections.<String, String>emptyMap());
}

The Collections class's methods for obtaining empty collections are preferable to use of Collections's similarly named fields for that same purpose because of the type safety the methods provide. This allows greater leveraging of Java's static type system, a key theme of books such as Effective Java. A nice side effect is the removal of cluttering warnings and marked NetBeans hints, but the more important result is better, safer code.

Thứ Tư, 24 tháng 10, 2012

Java/NetBeans: Overridable Method Call in Constructor

I wrote about the NetBeans hint "Overridable Method Call in Constructor" in the blog post Seven Indispensable NetBeans Java Hints. In this post, I look at why having an overridable method called from a parent class's constructor is not a good idea.

The next class, Employee, is a contrived example of a class in which the extensible class's constructor calls an overridable method (setSalaryRange()).

Employee.java

package dustin.examples.overridable;

/**
* Simple employee class that is intended to be a parent of a specific type of
* employee class. The main purpose of this class is to demonstrate the
* insidious dangers associated with a constructor calling an overridable method.
*
* @author Dustin
*/
public class Employee
{
private String lastName;
private String firstName;
private JobTitle jobTitle;
protected int minWeeklySalary;
protected int maxWeeklySalary;

public enum JobTitle
{
CHIEF_EXECUTIVE_OFFICER("CEO"),
COMPUTER_SCIENTIST("Computer Scientist");

private String displayableTitle;

JobTitle(final String newDisplayableTitle)
{
this.displayableTitle = newDisplayableTitle;
}

public String getDisplayableTitle()
{
return this.displayableTitle;
}
}

public Employee(
final String newLastName, final String newFirstName, final JobTitle newJobTitle)
{
this.lastName = newLastName;
this.firstName = newFirstName;
this.jobTitle = newJobTitle;
setSalaryRange();
}

public void setSalaryRange()
{
this.minWeeklySalary = 5;
this.maxWeeklySalary = 10;
}

@Override
public String toString()
{
return this.firstName + " " + this.lastName + " with title '"
+ this.jobTitle.getDisplayableTitle()
+ "' and with a salary range of $" + this.minWeeklySalary + " to $"
+ this.maxWeeklySalary + ".";
}
}

NetBeans flags the existence of an overridable method called from a constructor as shown in the next screen snapshot (NetBeans 7.3 in this case):

To demonstrate a common problem associated with overridable methods called in a constructor, a child class is needed. That is shown next with the code listing for ComputerScientist, which extends Employee.

ComputerScientist.java

package dustin.examples.overridable;

/**
* Class representing a specific type of employee (computer scientist), but its
* real purpose is to demonstrate how overriding a method called in the parent
* class's constructor leads to undesired behavior.
*
* @author Dustin
*/
public class ComputerScientist extends Employee
{
private final int MIN_CS_WEEKLY_SALARY_IN_DOLLARS = 1000;
private static final int MAX_CS_WEEKLY_SALARY_IN_DOLLARS = 60000;

private int marketFactor = 1;

public ComputerScientist(
final String newLastName, final String newFirstName, final int newMarketFactor)
{
super(newLastName, newFirstName, JobTitle.COMPUTER_SCIENTIST);
this.marketFactor = newMarketFactor;
}

@Override
public void setSalaryRange()
{
this.minWeeklySalary = MIN_CS_WEEKLY_SALARY_IN_DOLLARS * this.marketFactor;
this.maxWeeklySalary = MAX_CS_WEEKLY_SALARY_IN_DOLLARS * this.marketFactor;
}
}

Finally, a simple test driving application is required to run this example. That is shown in the next simple executable class (Main.java).

Main.java

package dustin.examples.overridable;

import dustin.examples.overridable.Employee.JobTitle;
import static java.lang.System.out;

/**
* Simple driver of the demonstration of why calling an overridable method in
* the constructor of an extendible class is a bad idea.
*
* @author Dustin
*/
public class Main
{
public static void main(final String[] arguments)
{
final ComputerScientist cs = new ComputerScientist("Flintstone", "Fred", 5);
final Employee emp = new Employee("Rubble", "Barney", JobTitle.CHIEF_EXECUTIVE_OFFICER);

out.println(cs);
out.println(emp);
}
}

One might expect the Computer Scientist, Fred Flintstone, to earn a weekly salary in the range of $1,000 to $60,000. However, that is not what is shown when the simple main application is executed (command line output and NetBeans output shown).

The reason the Computer Scientist's salary range is not correct is that the parent class's (Employee's) constructor must first be run before the extending class (ComputerScientist) is completely instantiated. The child class does override the setSalaryRange() method, but this overridden implementation depends on an instance variable (marketFactor) that is not yet initialized in the child instance when the parent's constructor calls this child class's overridden method.

There are multiple ways to avoid this problem. Perhaps the best and easiest approaches are those recommended by the NetBeans hint that flagged this issue.

As the screen snapshot above shows, NetBeans provides four easy and effective ways to deal with the issue of an overridable method called from the constructor of a class. Because the issue involves an "overridable" method and a child class that is not fully instantiated when that overridable method is invoked during parent's constructor, an obvious tactic is to make the parent class final so that it cannot be extended. This obviously will only work for new classes that don't have classes extending them. I have found that Java developers often don't put a lot of consideration into making a class final or planning for it to be extensible, but this is an example of where such consideration is worthwhile.

When it is not practical to make the parent class final, NetBeans offers three other approaches for addressing the problem of an overridable method called from the parent class constructor. Even if the class cannot be final, that method can have the final modifier applied to it so that the constructor is no longer calling an "overridable" method. This allows a child class to still extend the parent class, but it cannot override that method and so won't have an implementation that depends on instance level variables that have not yet been initialized.

The other two ways shown that NetBeans uses to handle the issue of an overridable method being called from a constructor likewise focus on making that invoked method not overridable. In these other two cases, this is accomplished by making the invoked method static (class level rather than instance level) or by making the method private (but then not accessible at all to the child class).

In my particular example above, another way to fix the specific issue would have been to convert the instance-level marketFactor variable into a class-level (static) variable because that would move its initialization forward enough to be used in the invocation of the overridden method. The problem with this method is that there is still an overridable method invoked from the parent constructor and that method can have more than one state issue to worry about.

In general, I try to be very careful about a constructor calling methods as part of an instance's instantiation. I prefer to use a static factory that constructs an object and calls static methods to set that instance appropriately. It is always wise to be cautious with implementation inheritance and this issue of overridable methods called from a constructor is just another in the list of reasons why caution is warranted.

My example shown in this post is relatively simple and it is easy to figure out why the results were not as expected. In a much larger and more complicated example, it might be more difficult to find this and it can lead to pernicious bugs. NetBeans helps tremendously by warning about overridable methods called from constructors so that appropriate action can be taken. If a class is not extended and there are no plans to extend it, then making the class final is easy and appropriate. Otherwise, NetBeans presents other options for ensuring that all methods called from a constructor are not overridable.

Thứ Năm, 18 tháng 10, 2012

The Checker Framework

One of the interesting tools I learned about at JavaOne 2012 is The Checker Framework. One of the Checker Framework's web pages states that the Checker Framework "enhances Java’s type system to make it more powerful and useful," allowing software developers "to detect and prevent errors in their Java programs." One way to look at the Checker Framework is as an implementation of what JSR 305 ("Annotations for Software Defect Detection") might have been had it not fallen into the Dormant stage.

The intention of JSR 308 ("Annotations on Java Types") is to "extend the Java annotation syntax to permit annotations on any occurrence of a type." Once JSR 308 is approved and becomes part of the Java programming language, annotations will be allowed in places they are not currently allowed. Although JSR 308 is still in Early Draft Review 2 stage, Checker Framework allows a developer to include commented-out annotation code in places not currently allowed until made available by JSR 308. It is important to note here that JSR 308 only makes annotations more generally available (specifies more types of source code against which they can be applied) and does not specify any new annotations.

The Checker Framework requires Java SE 6 or later. The Checker Framework can be downloaded as a single ZIP file at http://types.cs.washington.edu/checker-framework/current/checkers.zip. The downloaded file can be unzipped to the directory checker-framework and then an environmental variable called CHECKERS can be set to point to that expanded directory's subdirectory "checkers." For example, if the checkers.zip is unzipped to C:\checker-framework, then the environmental variable CHECKERS should be set to C:\checker-framework\checkers.

One the Checker Framework checkers.zip has been downloaded, expanded, and pointed to by the CHECKERS environmental variable, it is time to try the Checker Framework out. The "long way" of running the Checker Framework is shown next and is used with the -version tag to verify that Checker Framework is applied:

Windows

java -Xbootclasspath/p:%CHECKERS%/binary/jsr308-all.jar -jar %CHECKERS%/binary/jsr308-all.jar -version
Linux

java -Xbootclasspath/p:$CHECKERS/binary/jsr308-all.jar -jar $CHECKERS/binary/jsr308-all.jar -version

The above should lead to output that looks something like that shown in the next screen snapshot.

The installed Checker Framework can now be applied to compiling code. The next code listing shows a simple class that specifies that a method argument should not be null via the checkers.nullness.quals.NonNull (@NonNull) annotation.

Example of Using Checker Framework's @NonNull

package dustin.examples;

import checkers.nullness.quals.NonNull;
import static java.lang.System.out;

public class CheckersDemo
{
public void printNonNullToString(@NonNull final Object object)
{
out.println(object.toString());
}

public static void main(final String[] arguments)
{
final CheckersDemo me = new CheckersDemo();
final String nullStr = null;
me.printNonNullToString(nullStr);
}
}

The above code listing shows a null being passed to a method with the argument annotated with @NonNull. NetBeans 7.3 flags this with the yellow squiggles and warning if hovered over. This is shown in the next screen snapshots.

Although NetBeans flags the null setting of a parameter marked with the @NonNull annotation, the compiler builds that code without complaint. This is where the Checker Framework comes in. Because it's a pain to type in the long command I showed previously, I either run the command shown above with a script or set up an alias as described in the Checker Framework Installation Instructions. In this case, I'll use an alias like this:

Setting Windows Command Line Alias for Java Checker

doskey javachecker=java -Xbootclasspath/p:%CHECKERS%\binary\jsr308-all.jar -jar %CHECKERS%\binary\jsr308-all.jar $*

The setting of this alias and running it with the -version flag is demonstrated in the next screen snapshot.

It is far easier to apply this approach with the alias set. This can be used to compile the class in question as shown next (command using my 'javachecker' alias and image showing result).


javachecker -d classes src\dustin\examples\*.java

The above command demonstrates that I am able to use normal javac options such as -d to specify the destination directory for compiled .class files and pass along the Java source files to be compiled as normal. The example also demonstrates that without specifying the checker processor to run as part of the compilation, the @NotNull additional typing is not enforced during compilation.

Before showing how to specify a processor to force the @NonNull to be be enforced during compilation, I want to quickly demonstrate that this compilation approach will still report standard compiler errors. Just for this example, I have renamed the "nullStr" variable passed to the method of interest on line 17 to "nullStry" so that it is a compiler error. The next two screen snapshots show this change (and NetBeans's reported compilation error) and how the Checker Framework compilation approach also reports the javac error.

Having shown that this approach to compilation compiles compilable code normally, reports compiler errors normally, and shows version appropriately, it is time to apply it to stronger type enforcement. I fix the compiler error in my code by removing the extra "y" that I had added. Then, I need to pass -processor checkers.nullness.NullnessChecker as an additional flag and argument to the compilation process. Note that there are other processors besides NullnessChecker, but I am using NullnessChecker here to enforce the @NonNull at compile time.

The following shows the command along with the output window demonstrating that command in action. Note that the compilation process is not allowed to complete and an error based on violation of the @NonNull typing is reported.


javachecker -processor checkers.nullness.NullnessChecker -d classes src\dustin\examples\*.java

This blog post has introduced the Checker Framework and shown how to quickly apply it to stronger type enforcement in Java source code. I only focused on one type of stronger typing here, but the Checker Framework supplies other built-in type checks and supports the option of writing custom type enforcement checks.

Thứ Năm, 4 tháng 10, 2012

JavaOne 2012: Mastering Java Deployment

After grabbing an Italian Classic Combo for another JavaOne 2012 lunch, I headed to Hilton Imperial Ballroom B to see the presentation "Mastering Java Deployment." The speakers, both from Oracle, were Mark Howe and Igor Nekrestyanov.

Howe stated that a goal of the deployment team is to help Java developers deploy their applications to platforms of choice. He started by discussing "feature deprecation." In some cases, there are multiple ways to do the same thing. An example of this is jarjar and pack200. By deprecating redundant (especially older) approaches, they don't have to spend as much time supporting and fixing bugs on these seldom used things.

Howe showed a table of features being deprecated and removed in JDK 7, JDK 8, and JDK 9. In general, anything being deprecated and/or removed has alternatives and folks using the deprecated/removed features should start looking at which alternative works best for them.

As of JRE 7 Update 6, a totally Oracle-supported JRE will be issued for Mac OS X. Oracle's intention is to fix bugs and add features across JVMs for all deployment environments at the same time. The JRE 7 is "mostly compatible" with Apple's JRE 6. One change is to be more aligned with Oracle's JVM support for other platforms and have Oracle's updated update the JRE on Mac OS X rather than using the Mac "Software Update." One caveat is that "Chrome on Mac is currently unsupported (32-bit only)."

In continuing the theme of platform JVM feature polarity, JavaFX is now delivered with JRE for Linux. Howe's "Convergence of Java and JavaFX" slide showed a table indicating the progress of converging Java and JavaFX versions. The goal is for JavaFX to be one of the core libraries in the Java specification. Plans for JDK 8 include "Java launcher able to run JavaFX applications" and "jfxrt.jar on boot classpath for java and javac."

Howe introduced the Java Deployment Toolkit and described it as a "tool to simplify deployment of Java content in the browser." He contrasted deployJava.js ("original version") with dtjava.js ("better JavaFX support and portability"). The dtjava.js version "supports all deployment scenarios on all platforms" though there is no autostart on Mac or Linux.

Howe talked about WebStart and explained that "user experience is not quite as nice as you'd like it to be." He contrasted this with use of dtjava.js that allows developer to set parameters for control of launching from JavaScript. It makes for more control and better user experience. This also removes need for fixed code base. The code shown in a slide for using dtjava.launch requires JRE 7 Update 6 or later.

The goal of packaging tools is to "simplify deployment for application developers." The command-line tool bin/javfxpackager (or set of Ant tasks lib/ant-javafx.jar) can be used with JDK 7 Update 6. The "latest release of NetBeans" supports these.

Howe covered several motivations for completely self-contained applications. A self-contained applications contains "all the artifacts necessary to run your application." It has a private copy of the Java runtime and removes the dependency on the external JRE. Many of the motivations for self-contained applications revolved around issues of acquiring a current JRE to run the application.

Benefits of self-contained applications include the feeling of a native application, improved compatibility, easier deployment on a fresh system, optional administrative privileges, and support of newer distribution channels such as the Apple Apps Store. The caveats of self-contained applications include larger size (JRE included), "download and run" instead of WebStart's "click and launch," need to build package per platform, and other current limitations such as package needing to be built on the target platform and application updates being the responsibility of the developer."

To create a self-contained application, one needs JDK 7 Update 6 as well as optional third party tools such as WiX to build MSI on Windows. Howe showed a slide with Ant code for generating the self-contained application. The Developer Preview will allow a developer to select target version of JVM (current choices are JRE 7 Update 6 or JRE Update 10). The Developer Preview is expected to be available with JRE 7 Update 10. JDK 7 Update 10 is also anticipated to support Mac App Store support.

Like so many other presentations at JavaOne 2012, community feedback was solicited. In this case, the deployment team would like to know what people want and need for more effective web deployment of Java applications. Howe had a nice slide comparing executable JAR to WebStart to self-contained application.

Mac App Store does not allow applications to "rely on optionally-installed technology." Other requirements include need for application to "run in a sandbox" and "follow UI guidelines." Certain APIs (FileChooser) should be avoided. See JavaOne 2012 slides for "Deploy Your Application with OpenJDK 7 on Mac OS X" and future version of JavaFX Deployment Guide for more details.

Howe's "key points to remember" include merging of Java with JavaFX, new platforms for Java, new deployment options (self-contained application bundle and deployment to Mac App Store), and deprecation of old deployment features.

One of the attendees asked if there is a way to share a single JRE among multiple shared self-contained applications. The answer is that there currently is not a way to do this, but that a JRE can optionally not be included in the otherwise self-contained application.

In responses to another question, the speakers stated they are not aware of any plans to deprecate Swing. They also responded to yet another question that there is currently no Maven support for building self-contained applications (use Ant or NetBeans).

There were several good slides shown in this presentation that I'd like to look at more closely in the future. Fortunately, Howe stated that these will be made available. Much of what was covered in this session will be open source and audience members were encouraged to contribute to the open source projects.

Thứ Sáu, 17 tháng 8, 2012

NetBeans 7.2: Refactoring Constructor As Static Factory

In the post NetBeans 7.2: Refactoring Parameterized Constructor As Builder, I looked at how NetBeans 7.2 supports refactoring a constructor to a builder as described in Item 2 of the Second Edition of Effective Java. In this post, I look at how NetBeans 7.2 similarly supports refactoring constructors to factories as described in Item #1 of Effective Java.

I start with an Employee class that is largely the same as the one I used in my previous post on refactoring a constructor to a builder. There are some minor differences, the most significant being that the attributes of the version used here cannot be final as the factory initializer approach does not allow final class attributes because they are not set in the constructor with this approach.

Employee.java with Traditional Constructor

package dustin.examples;

/**
* Simple employee class intended to illustrate NetBeans 7.2 and refactoring
* constructor to use Factory initializer as discussed in Item #1 of Joshua
* Bloch's <em>Effective Java</em>.
*
* @author Dustin
*/
public class Employee
{
private String lastName;

private String middleName;

private String firstName;

private long id;

private int birthYear;

private int birthMonth;

private int birthDate;

private int hireYear;

private int hireMonth;

private int hireDate;

public Employee(
final String newLastName,
final String newMiddleName,
final String newFirstName,
final long newId,
final int newBirthYear,
final int newBirthMonth,
final int newBirthDate,
final int newHireYear,
final int newHireMonth,
final int newHireDate)
{
this.lastName = newLastName;
this.middleName = newMiddleName;
this.firstName = newFirstName;
this.id = newId;
this.birthYear = newBirthYear;
this.birthMonth = newBirthMonth;
this.birthDate = newBirthDate;
this.hireYear = newHireYear;
this.hireMonth = newHireMonth;
this.hireDate = newHireDate;
}

@Override
public String toString()
{
return this.firstName + " " + this.middleName + " " + this.lastName
+ " with ID " + this.id;
}
}

Right-clicking on the constructor of this class leads to the choices for refactoring including the highlighted choice to "Replace Constructor with Factory..."

When the "Refactor: Replace Constructor with Factory..." choice is selected, a window like that shown in the next screen snapshot appears. It has the name "create" for the factory method by default.

One of the advantages of these static initialization factories over constructors is the ability to name them as we like rather than always needing to use the class name. This can lead to them being more expressive and means potentially less reliance on overloading. The next screen snapshot shows my change of the name of the method to be generated.

When the above options are chosen, the class's source code is automatically changed to the code shown in the next code listing. Note that the constructor is changed from public to private and a new newInstance method is generated.

Refactored Employee.java (with White Space Adjustments Made Manually)

package dustin.examples;

/**
* Simple employee class intended to illustrate NetBeans 7.2 and refactoring
* constructor to use Factory initializer as discussed in Item #1 of Joshua
* Bloch's <em>Effective Java</em>.
*
* @author Dustin
*/
public class Employee
{
public static Employee newInstance(
final String newLastName, final String newMiddleName,
final String newFirstName, final long newId,
final int newBirthYear, final int newBirthMonth,
final int newBirthDate, final int newHireYear,
final int newHireMonth, final int newHireDate)
{
return new Employee(newLastName, newMiddleName, newFirstName,
newId, newBirthYear, newBirthMonth, newBirthDate,
newHireYear, newHireMonth, newHireDate);
}
private final String lastName;

private final String middleName;

private final String firstName;

private final long id;

private final int birthYear;

private final int birthMonth;

private final int birthDate;

private final int hireYear;

private final int hireMonth;

private final int hireDate;

private Employee(
final String newLastName,
final String newMiddleName,
final String newFirstName,
final long newId,
final int newBirthYear,
final int newBirthMonth,
final int newBirthDate,
final int newHireYear,
final int newHireMonth,
final int newHireDate)
{
this.lastName = newLastName;
this.middleName = newMiddleName;
this.firstName = newFirstName;
this.id = newId;
this.birthYear = newBirthYear;
this.birthMonth = newBirthMonth;
this.birthDate = newBirthDate;
this.hireYear = newHireYear;
this.hireMonth = newHireMonth;
this.hireDate = newHireDate;
}

@Override
public String toString()
{
return this.firstName + " " + this.middleName + " " + this.lastName
+ " with ID " + this.id;
}
}

There are multiple advantages to using static initialization factory methods rather than constructors. These include the ability to provide different and more meaningful names that do not necessarily require overloading because they can be different. I like to name these methods in such a way that some of their parameters are implied, resulting in the need to provide fewer arguments to that method than would be necessary for a constructor.

Other advantages of the static factory approach of acquiring an instance and two disadvantages of this approach are discussed in Item #1 of Effective Java. That item concludes, "Often static factories are preferable, so avoid the reflex to provide public constructors without first considering static factories." NetBeans 7.2 makes it easy to see how a constructor can be refactored into a static factory and will even do the basic work for the developer.

Thứ Sáu, 10 tháng 8, 2012

NetBeans 7.2: Refactoring Parameterized Constructor As Builder

Shortly after the Second Edition of Josh Bloch's Effective Java was released, I borrowed a colleague's copy to browse it and consider purchasing a copy of my own despite already owning a copy of the first edition. It did not take me long to realize that the Second Edition was worth purchasing. In particular, the usefulness of the first new item in the Second Edition (Item #2 "Consider a builder when faced with many constructor parameters") struck me. This item addressed many issues I had run into during my Java development in a nice fashion. In this post, I look at the approach described in that chapter and look at how NetBeans 7.2 provides refactoring support for this approach.

As outlined in Item #2 of the Second Edition of Effective Java, there are several disadvantages to using constructors with large parameter lists. To help illustrate, I include a code listing below.

Employee.java

package dustin.examples;

/**
* Simple employee class intended to illustrate NetBeans 7.2 and refactoring
* constructor to use Builder pattern as discussed in Item #2 of the Second
* Edition of Joshua Bloch's <em>Effective Java</em>.
*
* @author Dustin
*/
public class Employee
{
private final String lastName;

private final String middleName;

private final String firstName;

private final long id;

private final int birthYear;

private final int birthMonth;

private final int birthDate;

private final int hireYear;

private final int hireMonth;

private final int hireDate;

public Employee(
final String newLastName,
final String newMiddleName,
final String newFirstName,
final long newId,
final int newBirthYear,
final int newBirthMonth,
final int newBirthDate,
final int newHireYear,
final int newHireMonth,
final int newHireDate)
{
this.lastName = newLastName;
this.middleName = newMiddleName;
this.firstName = newFirstName;
this.id = newId;
this.birthYear = newBirthYear;
this.birthMonth = newBirthMonth;
this.birthDate = newBirthDate;
this.hireYear = newHireYear;
this.hireMonth = newHireMonth;
this.hireDate = newHireDate;
}
}

Employee's parameterized constructor includes numerous parameters and this presents a challenge to clients of this class that need to create a new instance of it. This particular constructor is particularly tricky for clients because it has three consecutive String parameters and numerous consecutive int parameters. It is all too easy for a client to mix up the order of these same-typed parameters in the invocation.

Suppose that business logic is such that an employee should be instantiable with only a last name, first name, and ID provided. In other words, suppose that all attributes of the class are optional except for the three just mentioned. In such a case, with only a constructor like that one above, the client would need to pass null for the middle name String and zeroes or some other number without meaning. The numeric types could be reference types rather than primitives, but the clients would still need to pass null for each optional argument.

One might argue that a three-argument constructor could accepting the three required attributes' values could be supplied and then appropriate set methods could be invoked to set each optional attribute. However, this approach has drawbacks. For one, it makes it easier for the client to accidentally instantiate an instance with a bad or partial state. In some cases, it is not desirable to change the state of the object after instantiation, but the presence of the set methods make it more mutable than desired. Indiscriminate supplying of set methods has several drawbacks in the world of concurrency and object-oriented interfaces.

An elegant approach that allows a client to only supply optional parameters that are meaningful without supplying otherwise unnecessary set methods is the Builder pattern. NetBeans 7.2 makes it easy to refactor the constructor with the long parameter list in the above example to take advantage of an instance of Builder. The next screen snapshot shows how I can use NetBeans 7.2 to accomplish this by hovering over the parameterized constructor, right-clicking on it, and selecting the option "Replace constructor with Builder...".

When this option is selected a popup similar to that shown in the next screen snapshot appears.

The refactoring tool only allows parameters passed to the constructor being refactored to be set in the builder. I can check the boxes of the optional attributes. When I make an attribute optional without supplying a default value, a warning appears as shown in the next screen snapshot.

If I supply default values (null for the String and zero for the integers that should never be zero for valid values), the warnings go away.

It is worth pointing out here that the refactor tool allows the refactor to continue when only warnings (no errors) are present. An error might be caused, for example, by declaring a package and class name of the builder to be generated with a name used by an existing class.

The "Preview" button can be clicked to see what the class would look like without actually creating the class file. When the "Refactor" button is clicked, a new Java class with the package and class name indicated in the "Builder Class Name" text field is created. The result in this case is shown in the next screen snapshot with the generated code listed in a listing following the snapshot.

NetBeans 7.2-Generated EmployeeBuilder.java

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package dustin.examples;


public class EmployeeBuilder
{
private String newLastName;
private String newMiddleName = null;
private String newFirstName;
private long newId;
private int newBirthYear = 0;
private int newBirthMonth = 0;
private int newBirthDate = 0;
private int newHireYear = 0;
private int newHireMonth = 0;
private int newHireDate = 0;

public EmployeeBuilder()
{
}

public EmployeeBuilder setNewLastName(String newLastName)
{
this.newLastName = newLastName;
return this;
}

public EmployeeBuilder setNewMiddleName(String newMiddleName)
{
this.newMiddleName = newMiddleName;
return this;
}

public EmployeeBuilder setNewFirstName(String newFirstName)
{
this.newFirstName = newFirstName;
return this;
}

public EmployeeBuilder setNewId(long newId)
{
this.newId = newId;
return this;
}

public EmployeeBuilder setNewBirthYear(int newBirthYear)
{
this.newBirthYear = newBirthYear;
return this;
}

public EmployeeBuilder setNewBirthMonth(int newBirthMonth)
{
this.newBirthMonth = newBirthMonth;
return this;
}

public EmployeeBuilder setNewBirthDate(int newBirthDate)
{
this.newBirthDate = newBirthDate;
return this;
}

public EmployeeBuilder setNewHireYear(int newHireYear)
{
this.newHireYear = newHireYear;
return this;
}

public EmployeeBuilder setNewHireMonth(int newHireMonth)
{
this.newHireMonth = newHireMonth;
return this;
}

public EmployeeBuilder setNewHireDate(int newHireDate)
{
this.newHireDate = newHireDate;
return this;
}

public Employee createEmployee()
{
return new Employee(newLastName, newMiddleName, newFirstName, newId, newBirthYear, newBirthMonth, newBirthDate, newHireYear, newHireMonth, newHireDate);
}

}

As the screen snapshot and code listing above indicate, NetBeans 7.2 generated a builder based on the constructor. This was easily done, but there are a few things I don't like about it as much as the builders I have generated by hand. For the builders I have built by hand, I have chosen to have required attributes be part of the builder's constructor so that they must be supplied (I had expected this to happen for the parameters that I did not check the box for optional on). This is shown in the next code listing, which is an adaptation of the generated code shown above. The only thing changed from above is the builder's constructor. It now takes parameters for the Employee class's required attributes.

Adapted EmployeeBuilder.java

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package dustin.examples;


public class EmployeeBuilder
{
private String newLastName;
private String newMiddleName = null;
private String newFirstName;
private long newId;
private int newBirthYear = 0;
private int newBirthMonth = 0;
private int newBirthDate = 0;
private int newHireYear = 0;
private int newHireMonth = 0;
private int newHireDate = 0;

public EmployeeBuilder(
final String newBldrLastName, final String newBldrFirstName, final String newBldrMiddleName)
{
this.newLastName = newBldrLastName;
this.newFirstName = newBldrFirstName;
this.newMiddleName = newBldrMiddleName;
}

public EmployeeBuilder setNewLastName(String newLastName)
{
this.newLastName = newLastName;
return this;
}

public EmployeeBuilder setNewMiddleName(String newMiddleName)
{
this.newMiddleName = newMiddleName;
return this;
}

public EmployeeBuilder setNewFirstName(String newFirstName)
{
this.newFirstName = newFirstName;
return this;
}

public EmployeeBuilder setNewId(long newId)
{
this.newId = newId;
return this;
}

public EmployeeBuilder setNewBirthYear(int newBirthYear)
{
this.newBirthYear = newBirthYear;
return this;
}

public EmployeeBuilder setNewBirthMonth(int newBirthMonth)
{
this.newBirthMonth = newBirthMonth;
return this;
}

public EmployeeBuilder setNewBirthDate(int newBirthDate)
{
this.newBirthDate = newBirthDate;
return this;
}

public EmployeeBuilder setNewHireYear(int newHireYear)
{
this.newHireYear = newHireYear;
return this;
}

public EmployeeBuilder setNewHireMonth(int newHireMonth)
{
this.newHireMonth = newHireMonth;
return this;
}

public EmployeeBuilder setNewHireDate(int newHireDate)
{
this.newHireDate = newHireDate;
return this;
}

public Employee createEmployee()
{
return new Employee(newLastName, newMiddleName, newFirstName, newId, newBirthYear, newBirthMonth, newBirthDate, newHireYear, newHireMonth, newHireDate);
}

}

The code used to call the adapted builder shown in the last code listing is exemplified in the following code listing. This code listing demonstrates how readable ("fluent" in the more trendy vernacular) the client code is with the builder and demonstrates that the object is never in a partial or inconsistent state.


package dustin.examples;

import java.util.Calendar;

/**
* Example calling adapted employee builder to get an instance of employee.
*
* @author Dustin
*/
public class Main
{
public static void main(final String[] arguments)
{
final Employee employee =
new EmployeeBuilder("Coyote", "Wile", "E.")
.setNewBirthMonth(Calendar.SEPTEMBER)
.setNewBirthDate(17)
.setNewBirthYear(1949)
.createEmployee();
}
}

The most significant drawbacks to the builder implementation are potential performance impacts of extra object instantiation (probably not an issue for most Java applications) and the extra code verbosity.

Although I don't show it here, the other thing I like to do with my builder implementations is to include them as nested classes in the class they build. This is how the code example in the second item of the Second Edition of Effective Java implements it, but I don't see anyway in NetBeans 7.2 to generate the builder as a nested class rather than as a standalone class.

Although the NetBeans 7.2-generated builder class is not quite what I have written by hand, it is pretty close and really easy to use. It makes it easy to use an existing parameterized constructor to quickly generate a largely equivalent builder class. Although I have to edit the generated class slightly to get my preferred implementation, it still saves me significant time. Furthermore, this is another example of where an IDE's code generation capabilities help a developer to see how a particular paradigm or pattern is implemented.

Thứ Sáu, 27 tháng 7, 2012

Undocumented Oracle JVM HttpServer Properties

I have blogged before on the utility of the HttpServer provided with the Oracle HotSpot JVM. One of the general challenges associated with its use is the lack of documentation. Fortunately, its open source implementation allows certain features to be discovered. In this post, I look at some apparently undocumented properties that are used by the HttpServer's source code.

A colleague (thanks Jim!) pointed out the existence of these properties as discovered in the source code. There are multiple places from which the relevant source code can be acquired and reviewed. One easily accessible location is Docjar. For example, the code listings for sun.net.httpserver.ServerConfig and sun.net.httpserver.ServerImpl are hosted there. Other similar sites include Open Source Java Code (ServerConfig) and grepcode (ServerConfig).

The static initialization block of the sun.net.httpserver.ServerConfig class includes the setting of several static variables based on specific Java properties or based on a default if no property is provided. The next code listing comes from that class and indicates the default values for these static variables.


static final int DEFAULT_CLOCK_TICK = 10000 ; // 10 sec.

/* These values must be a reasonable multiple of clockTick */
static final long DEFAULT_IDLE_INTERVAL = 30 ; // 5 min
static final int DEFAULT_MAX_IDLE_CONNECTIONS = 200 ;

static final long DEFAULT_MAX_REQ_TIME = -1; // default: forever
static final long DEFAULT_MAX_RSP_TIME = -1; // default: forever
static final long DEFAULT_TIMER_MILLIS = 1000;

static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;

As the code and comments above indicate, the default idle interval is 300 seconds (5 minutes). The default request and response times are "forever" indicated by -1.

Although defaults are available as indicated in the above code listing, these can be overridden via the specification of Java properties. These properties are not well documented, but can be gleaned from the code. The following is a list of them as extracted from the ServerConfig class with notes about each property based on other portions of the code.

Properties for Configuring HotSpot HttpServer
  • sun.net.httpserver.idleInterval
  • sun.net.httpserver.clockTick
  • sun.net.httpserver.maxIdleConnections
  • sun.net.httpserver.drainAmount
  • sun.net.httpserver.maxReqTime
    • Replaces sun.net.httpserver.readTimeout
  • sun.net.httpserver.maxRspTime
    • Replaces sun.net.httpserver.writeTimeout
  • sun.net.httpserver.timerMillis
  • sun.net.httpserver.debug

Note that the property sun.net.httpserver.selCacheTimeout is no longer used, but does not have its replacement spelled out in the code comments or logged messages.

The Oracle JVM HttpServer allows for configuration based on Java properties. These properties are not well advertised, but the open source nature of the HttpServer implementation makes it possible to browse the code to determine which properties are available.