Tuesday, May 31, 2011

Groovy 1.8's @Canonical Transformation: Great Functionality, Less Code

The final example in my blog post Groovy 1.8 Transformations: @ToString, @EqualsAndHashCode, and @TupleConstructor demonstrated using the @ToString, @EqualsAndHashCode, and @TupleConstructor annotation-signified transformations on a single Groovy class. Although using the three of these together does work as shown in that post, Groovy 1.8 provides an ever easier approach for specifying all three. In this post, I look at using the @Canonical annotation-based AST transformation to have these methods all generated implicitly.

To demonstrate @Canonical, I begin by reproducing the aforementioned example that specified the three annotations separately. The Groovy class used then was called TheWholePerson and is shown in the next code listing.

TheWholePerson.groovy
@groovy.transform.TupleConstructor
@groovy.transform.EqualsAndHashCode
@groovy.transform.ToString(includeNames = true, includeFields=true)
class TheWholePerson
{
   String lastName
   String firstName
}

The above can be simplified by replacing the three specific annotations with the @Canonical annotation. This is shown in the next code listing.

CanonicalPerson.groovy
@groovy.transform.Canonical
class CanonicalPerson
{
   String lastName
   String firstName
}

There's not much code in the CanonicalPerson.groovy code listing, but there is more there than meet's the eye. For convenience, I next reproduce the test driving code listing I used in my previous post with added functionality to demonstrate CanonicalPerson in action.

demonstrateCommonMethodsAnnotationsWithCanonical.groovy
#!/usr/bin/env groovy
// demonstrateCommonMethodsAnnotationsWithCanonical.groovy

def person = new Person(lastName: 'Rubble', firstName: 'Barney')
def person2 = new Person(lastName: 'Rubble', firstName: 'Barney')
def personToString = new PersonToString(lastName: 'Rockford', firstName: 'Jim')
def personEqualsHashCode = new PersonEqualsHashCode(lastName: 'White', firstName: 'Barry')
def personEqualsHashCode2 = new PersonEqualsHashCode(lastName: 'White', firstName: 'Barry')

// Demonstrate value of @ToString
printHeader("@ToString Demonstrated")
println "Person with no special transformations: ${person}"
println "Person with @ToString transformation: ${personToString}"

// Demonstrate value of @EqualsAndHashCode
printHeader("@EqualsAndHashCode Demonstrated")
println "${person} ${person == person2 ? 'IS' : 'is NOT'} same as ${person2}."
println "${personEqualsHashCode} ${personEqualsHashCode == personEqualsHashCode2 ? 'IS' : 'is NOT'} same as ${personEqualsHashCode2}."

// Demonstrate value of @TupleConstructor
printHeader("@TupleConstructor Demonstrated")
def personTupleConstructor = new PersonTupleConstructor('Whyte', 'Willard')
println "Tuple Constructor #1: ${personTupleConstructor.firstName} ${personTupleConstructor.lastName}"
def personTupleConstructor2 = new PersonTupleConstructor('Prince')  // first name will be null
println "Tuple Constructor #2: ${personTupleConstructor2.firstName} ${personTupleConstructor2.lastName}"

// Combine all of it!
printHeader("Bringing It All Together")
def wholePerson1 = new TheWholePerson('Blofeld', 'Ernst')
def wholePerson2 = new TheWholePerson('Blofeld', 'Ernst')
println "${wholePerson1} ${wholePerson1 == wholePerson2 ? 'IS' : 'is NOT'} same as ${wholePerson2}."

// Simplify the combination!
printHeader("Simplified via Canonical")
def canonicalPerson1 = new CanonicalPerson('Goldfinger', 'Auric');
def canonicalPerson2 = new CanonicalPerson('Goldfinger', 'Auric');
println "${canonicalPerson1} ${canonicalPerson1 == canonicalPerson2 ? 'IS' : 'is NOT'} same as ${canonicalPerson2}."

/**
 * Print a header using provided String as header title.
 *
 * @param headerText Text to be included in header.
 */
def printHeader(String headerText)
{
   println "\n${'='.multiply(75)}"
   println "= ${headerText}"
   println "=".multiply(75)
}

The output from running the above script is shown next. One important observation to make from this output is that the @Canonical does indeed provide implicit toString() support as well as implicit equals support. A second observation is that the output does not return name/value pairs like the example specifying the three annotation separately did for the toString() representation.


The output from using @Canonical uses default settings for toString() output. To override these settings, the @ToString annotation should be applied in conjunction with the @Canonical annotation as shown in the next version of the Groovy model class shown previously, this time called CanonicalToStringPerson.groovy.

CanonicalToStringPerson.groovy
@groovy.transform.Canonical
@groovy.transform.ToString(includeNames = true, includeFields=true)
class CanonicalToStringPerson
{
   String lastName
   String firstName
}

In the above code listing, the same line with @groovy.transform.ToString(includeNames = true, includeFields=true) that led to the Groovy class TheWholePerson's toString() returning field name/value pairs is added to the class using the @Canonical annotation. This allows for customization of the @ToString representation. When I add some lines of code to the test driving Groovy script shown above with new output indicates that name/value pairs are listed for the fields in the toString() representation.


There is an obvious benefit to using @Canonical if the "vanilla" versions of the three transformations it represents (ToString, EqualsAndHashCode, and TupleConstructor) are sufficient. However, once it must be overridden with one or more individual annotations for customization, it might be preferable to simply specify the individual annotations.

There are several other references for additional reading and/or different perspectives on @Canonical. The Groovy 1.8 release notes reference John Prystash's blog post Groovy 1.8: Playing with the new @Canonical Transformation. Another useful reference is mrhaki's Groovy Goodness: Canonical Annotation to Create Mutable Class.

The @Immutable AST transformation has been available since Groovy 1.6 and is preferable to @Canonical when the state of the Groovy object should not change after instantiation. The advantage of @Canonical exists when the class state does need to be modified after its original instantiation, but the developer wishes to have much of the boilerplate code automatically generated.

Javap Proves What @Canonical Adds

Although my test code listed above shows the value of @Canonical, perhaps the best way to see what it adds to a normal Groovy class is to look at the javap output of a Groovy class without any annotations and to compare that to the javap output of a Groovy class employing the @Canonical annotation. For the "control" Groovy class that doesn't use any of these annotations, I again borrow from my previous post and that class (Person.groovy) is reproduced here.

Person.java
class Person
{
   String lastName
   String firstName
}

The javap output for the simple Person class looks like this:

javap Output for Person Class Class
Compiled from "Person.groovy"
public class Person extends java.lang.Object implements groovy.lang.GroovyObject {
  public static transient boolean __$stMC;
  public static long __timeStamp;
  public static long __timeStamp__239_neverHappen1306808397612;
  public Person();
  public java.lang.Object this$dist$invoke$1(java.lang.String, java.lang.Object);
  public void this$dist$set$1(java.lang.String, java.lang.Object);
  public java.lang.Object this$dist$get$1(java.lang.String);
  protected groovy.lang.MetaClass $getStaticMetaClass();
  public groovy.lang.MetaClass getMetaClass();
  public void setMetaClass(groovy.lang.MetaClass);
  public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
  public java.lang.Object getProperty(java.lang.String);
  public void setProperty(java.lang.String, java.lang.Object);
  public static void __$swapInit();
  static {};
  public java.lang.String getLastName();
  public void setLastName(java.lang.String);
  public java.lang.String getFirstName();
  public void setFirstName(java.lang.String);
  public void super$1$wait();
  public java.lang.String super$1$toString();
  public void super$1$wait(long);
  public void super$1$wait(long, int);
  public void super$1$notify();
  public void super$1$notifyAll();
  public java.lang.Class super$1$getClass();
  public java.lang.Object super$1$clone();
  public boolean super$1$equals(java.lang.Object);
  public int super$1$hashCode();
  public void super$1$finalize();
  static java.lang.Class class$(java.lang.String);
}

The Person class has "get" and "set" methods for its fields because Groovy provides these out-of-the-box for its property support. Although we see that it has hashCode() and equals(Object) implementations from its parent class, it does not have any of its own. Now, we can contrast this output against the javap output for the class with the @Canonical annotation.

javap Output for CanonicalToStringPerson
Compiled from "CanonicalToStringPerson.groovy"
public class CanonicalToStringPerson extends java.lang.Object implements groovy.lang.GroovyObject {
  public static transient boolean __$stMC;
  public static long __timeStamp;
  public static long __timeStamp__239_neverHappen1306808397590;
  public CanonicalToStringPerson(java.lang.String, java.lang.String);
  public CanonicalToStringPerson(java.lang.String);
  public CanonicalToStringPerson();
  public int hashCode();
  public boolean equals(java.lang.Object);
  public java.lang.String toString();
  public java.lang.Object this$dist$invoke$1(java.lang.String, java.lang.Object);
  public void this$dist$set$1(java.lang.String, java.lang.Object);
  public java.lang.Object this$dist$get$1(java.lang.String);
  protected groovy.lang.MetaClass $getStaticMetaClass();
  public groovy.lang.MetaClass getMetaClass();
  public void setMetaClass(groovy.lang.MetaClass);
  public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
  public java.lang.Object getProperty(java.lang.String);
  public void setProperty(java.lang.String, java.lang.Object);
  public static void __$swapInit();
  static {};
  public java.lang.String getLastName();
  public void setLastName(java.lang.String);
  public java.lang.String getFirstName();
  public void setFirstName(java.lang.String);
  public void super$1$wait();
  public java.lang.String super$1$toString();
  public void super$1$wait(long);
  public void super$1$wait(long, int);
  public void super$1$notify();
  public void super$1$notifyAll();
  public java.lang.Class super$1$getClass();
  public java.lang.Object super$1$clone();
  public boolean super$1$equals(java.lang.Object);
  public int super$1$hashCode();
  public void super$1$finalize();
  static java.lang.Class class$(java.lang.String);
}

In the above javap output, we can see that the expected parameterized constructor provided by @TupleConstructor is available as are the equals(Object), hashCode(), and toString() methods. The @Canonical annotation and its associated AST transformation did its job.


Conclusion

The introduction of @Canonical in Groovy 1.8 continues Groovy's theme of simplifying coding and providing for concise syntax with little unnecessary verbosity. Wikipedia's primary definition of "canonical" seems to fit the use of the newly available @Canonical: "reduced to the simplest and most significant form possible without loss of generality." The @Canonical annotation and underlying AST do indeed make the Groovy data class nearly as simple as possible while maintaining the canonical functionality associated with such data classes.

Monday, May 30, 2011

Visible Script Variables: Using Groovy 1.8's @Field AST

My most common use of Groovy is for writing scripts. As such, I enjoy its characteristics that enable an improved script development experience, but I also notice features of Groovy that are less than desirable for writing scripts. One of the minor annoyances of Groovy script writing has been the inability to have defined script variables visible to methods defined in the script. The current version of the Groovy User Guide define these rules in the Scoping and the Semantics of "def" section. This section explains the problem:
When you define a variable in a script it is always local. But methods are not part of that scope. So defining a method using different variables as if they were attributes and then defining these variables normally in the script leads to problems.

The problem is that locally declared (in the script) variables are not visible to methods defined in that same script. The Groovy 1.8 Release notes describes the problem in a slightly different way: "When defining variables in a script, those variables are actually local to the script's run method, so they are not accessible from other methods of the script."

Before Groovy 1.8, the standard tactic we Groovy script developers used to deal with this situation was to not define the local variables with the def keyword or with a static type declaration. In other words, the approach has always been to declare script variables with no def or static typing. This effectively places the undefined script local variable into "the binding," which the script's methods do have access to. The Scoping and the Semantics of "def" section of the Groovy User Guide puts it this way (emphasis present in source):
When is something in the Binding and when not? That's easy. When it is not defined, it is in the binding. The trick is - and that is admittedly not easy for Java programers - to not to define the variable before using it, and it will go into the binding. Any defined variable is local. Please note: the binding exists only for scripts.

The following Groovy code listing demonstrates this issue. The script defines three variables at the script level, one without 'def' or explicit type (will be in binding), one with 'def', and one with explicit type. All three local variables are used in respective methods without passing the argument to the method using it. Only the variable in the binding will work properly and the other two lead to MissingPropertyExceptions.

demoScriptVarDefinitionsWithoutFieldAst.groovy
#!/usr/bin/env groovy
// demoScriptVarDefinitionsWithoutFieldAst.groovy

/**
 * This variable is a binding variable because it lacks 'def' or type. It is
 * therefore visible to methods of this script.
 */
SPEED_OF_LIGHT_M_PER_S = 299792458     // visible to script methods

/**
 * This variable is a local variable because it is defined with 'def'. It would
 * have similarly been considered a local variable had it been explicitly
 * and statically typed to Double or BigDecimal. As a local variable, it is NOT
 * visible to methods defined on this script. 
 */
def SPEED_OF_SOUND_M_PER_S = 340.29    // NOT visible to script methods

/**
 * This variable is a local variable because it is explicitly typed. As a local
 * variable, it is NOT visible to methods defined on this script.
 */
Integer AVG_RADIUS_OF_EARTH_KM = 6371  // NOT visible to script methods 

useSpeedOfLight()
useSpeedOfSound()
useRadiusOfEarth()


/** Print the speed of light. */
def useSpeedOfLight()
{
   println "The speed of light is ${SPEED_OF_LIGHT_M_PER_S} m/s."
}

/** Print the speed of sound. */
def useSpeedOfSound()
{
   println "The speed of sound is ${SPEED_OF_SOUND_M_PER_S} m/s."
}

/** Print the average radius of the Earth. */
def useRadiusOfEarth()
{
   println "The average radius of the earth is ${AVG_RADIUS_OF_EARTH_KM} km."
}

When the code above is run via Groovy as-is, the local variable for speed of sound (which is local because it was defined with 'def') will be the first to break the script's execution. This is shown in the next screen snapshot.


When I comment out the single line that calls the useSpeedOfSound() method, the exception just shown is not encountered, but a similar one for another local script variable (which is local because it was defined with a static type) will be thrown. That is shown in the next screen snapshot.


If I comment out the call to the useRadiusOfEarth() method, the script runs fine, but I don't see either of the two constants printed out. This is shown in the next screen snapshot.


With the above in mind, the obvious solution and commonly used approach up to now has been to simply remove the def keyword and to remove the explicit static type definition so that all local script variables are in the binding. Fortunately, Groovy 1.8 provides a better alternative. The Groovy 1.8 release notes state:
Fortunately, the @Field transformation provides a better alternative: by annotating your variables in your script with this annotation, the annotated variable will become a private field of the script class.

The next code listing shows the previous script adapted to use this new Groovy 1.8 @Field annotation and the AST behind it.

demoScriptVarDefinitionsWithFieldAst.groovy
#!/usr/bin/env groovy
// demoScriptVarDefinitionsWithFieldAst.groovy

import groovy.transform.Field

/**
 * @Field makes this visible to script's methods.
 */
@Field SPEED_OF_LIGHT_M_PER_S = 299792458     // visible to script's methods

/**
 * @Field makes this visible to script's methods.
 */
@Field def SPEED_OF_SOUND_M_PER_S = 340.29    // visible to script's methods

/**
 * @Field makes this visible to script's methods.
 */
@Field Integer AVG_RADIUS_OF_EARTH_KM = 6371  // visible to script's methods

useSpeedOfLight()
useSpeedOfSound()
useRadiusOfEarth()


/** Print the speed of light. */
def useSpeedOfLight()
{
   println "The speed of light is ${SPEED_OF_LIGHT_M_PER_S} m/s."
}

/** Print the speed of sound. */
def useSpeedOfSound()
{
   println "The speed of sound is ${SPEED_OF_SOUND_M_PER_S} m/s."
}

/** Print the average radius of the Earth. */
def useRadiusOfEarth()
{
   println "The average radius of the earth is ${AVG_RADIUS_OF_EARTH_KM} km."
}

This works beautifully as shown in the next screen snapshot.



Conclusion

The @Field annotation and associated AST don't offer anything for non-script Groovy software, but it is a much appreciated addition for the writing of scripts in Groovy 1.8.

Java Exploits Biggest Threat to PCs?

Gregg Keizer's ComputerWorld article New malware scanner finds 5% of Windows PCs infected includes the subtitle: "Java exploits remain biggest threat to PCs, says Microsoft." The part of the article that talked about freely available (for PCs with "Genuine Windows" installed) Microsoft products Microsoft Safety Scanner and Microsoft Security Essentials prompted me to run Microsoft Safety Scanner against my primary laptop. I am pleased to report I am part of the 95% without the issues discussed in this article. However, the other part of the article that interested me and is the subject of this blog post is the high number of Microsoft-identified exploits associated with Java.

The Keizer article references the blog post Microsoft Safety Scanner detects exploits du jour, which is the source of most of the information I discuss in this post. The Microsoft Malware Protection Center (MMPC) blog post by Scott Wu and Joe Faulhaber discusses the statistics gathered from the initial week following the release of Microsoft Safety Scanner earlier this month. They report that there were nearly 420,000 downloads of Microsoft Safety Scanner in that first week and nearly 20,100 computers needed to be cleaned. Here is the big news from a Java perspective: seven of the top ten exploits that Microsoft Safety Scanner identified in that first were were Java-related (including the all of the top four).

The Microsoft Safety Scanner detects exploits du jour post provides a table listing the top ten encountered threats with a "threat name," threat count, machine count, and a "note." Seven of the ten threats have "Java Exploit" as their note. The New malware scanner finds 5% of Windows PCs infected article does a nice job of associating these threats with previous Microsoft Malware Protection Center statements regarding Java and Windows security. Many of these previous statements were made in Holly Stewart's October 2010 MMPC blog post Have you checked the Java?

The Holly Stewart post postulates some possible reasons for Java being associated with so many Windows security issues, particularly in the United States. She states:
Java is ubiquitous, and, as was once true with browsers and document readers like Adobe Acrobat, people don't think to update it. On top of that, Java is a technology that runs in the background to make more visible components work. How do you know if you have Java installed or if it's running?

I now look at some of the exploits seen in the first week of Microsoft Safety Scanner's deployment that are Java-related.

CVE-2008-5353

The most frequently seen threat (in terms of threat count and fourth in terms of machines involved) in this first week of Microsoft Safety Scanner deployment was CVE-2008-5353, which Microsoft rates as Severe. Java/CVE-2008-5353 is resolved with Java SE 6 Update 11 (Sun Alert ID 244991). This issue has to deal with improper deserialization (a more general issue most commonly blamed on the much maligned Calendar class).

CVE-2010-0840

Threat CVE-2010-0840 was the second most seen threat (and was also on the second most machines). Sami Koivu provides a detailed overview of this vulnerability in Java Trusted Method Chaining (CVE-2010-0840/ZDI-10-056). The vulnerability is addressed in Java SE 6 Update 19 or through the March 2010 Patch Update.

CVE-2010-0094

The third most commonly seen threat in the first week of Microsoft Safety Scanner's deployment was CVE-2010-0094 (fifth in terms of number of machines involved). This was addressed in the March 2010 Patch Update and was resolved in the standard SDK distribution as of Java SE 6 Update 19. This little baddie is another one related to deserialization (specifically "deserialization of RMIConnectionImpl objects").

OpenConnection

Second highest by machine count and fourth highest by threat count, the OpenConnection family of threats. The OpenConnection.MW threat appears to be a particular "malicious Java applet trojan that exploits a vulnerability described in CVE-2010-0840" (quote source) and, as such, is addressed by Java SE 6 Update 19.

CVE-2009-3867

CVE-2009-3867 was the sixth most frequently seen threat both in terms of threat count and in terms of machine count. This threat is described as "A stack-based buffer overflow occurs when processing long 'file://' URL arguments in the 'HsbParser.getSoundBank()' function" and is addressed in Java SE 6 Update 17.

Mesdeh

Mesdeh is a data file intended to exploit the previously discussed CVE-2010-0094 vulnerability and, as such, is foiled by updating to at least Java SE 6 Update 19. This was ninth of the ten discovered exploits in terms of threat count as well as in terms of machine count.

OpenStream

The final Java-related exploit of the top ten exploits discovered in the first week of deployment of Microsoft Safety Scanner is named OpenStream and is a Java applet Trojan downloader (Trojan horse). It can be invoked on any web browser that runs Java, but is harmless to non-Windows operating systems because the file it downloads is a Windows-specific EXE file. Because it involves a signed JAR, the user must accept it to allow it to have its way with their machine. Just as it is said that the people of Troy allowed a horse full of Greeks in and just as it is said that people must let Vampires in, so too the user must let this baddie in.

Patching of Exploits Not Limited to Java SE 6

All of the above exploits are resolved in current versions of Java SE 6. Current versions of J2SE 5 tend to address these as well, but I focused on Java SE 6 in this post.


Java Vulnerabilities

I discussed Java-related vulnerabilities briefly in my earlier post Recent Posts of Significant Interest (Java Security, XML, Cloud Computing). In that post, I referenced the article RSA: Java is the Most Vulnerable Browser Plug-in. That article reported that RSA found the Java plug-in to be the most vulnerable to exploitation followed by Adobe Reader, Apple QuickTime, and Adobe Flash. The article also cited another article that reports that "Cisco said that Java vulnerabilities are now more exploited than those in Adobe Acrobat and Reader."


Conclusion

It appears that Java indeed is or has been related to many Windows exploits. The good news for end users is that it's generally fairly easy and doesn't take a lot of time to upload the latest JRE. Best of all, my PCs are set up so that I'm automatically reminded to perform these updates and thus don't risk "forgetting" to do so. One could probably download hundreds of JRE updates in the time it takes to download and install one iTunes update.

Saturday, May 28, 2011

File System Management with PHP

I blogged previously on using PHP on the command line, but I did not cover using PHP to access the file system in that post in the interest of blog post size. I use this post to cover some of the basics of PHP file system management.

Many of us who write and use scripts do so for functions related to the file system. We script actions we commonly perform in the file system. Specifically, we often find ourselves needing to copy files, rename files, remove files, and open and close files. We often need to perform certain logic based on certain characteristics of files and directories. It'd be difficult to seriously consider a language as a scripting language without decent file system support. Fortunately, PHP has built-in support for file system management. This support can be used in conjunction with command line PHP.

W3Schools.com is a proven valuable resource for learning about web technologies and their coverage of PHP Filesystem Functions is another example of that. The page reminds us that the PHP filesystem functions "are part of the PHP core" and "allow you to access and manipulate the filesystem." More importantly, this page also summarizes PHP file system configuration details, PHP file system functions, and PHP file system constants. Clicking on a function name leads to a page with more details on that function as well as a PHP code example using that function. Because I'll only cover a subset of these in this post, I wanted to make sure to reference this W3Schools page early.

The following script, demoPhpFileSystemManagement.php, demonstrates several of PHP's functions for determining file information. I list the whole script here and then reproduce portions of the script again as I discuss them.

demoPhpFileSystemManagement.php
#!/usr/bin/php
<?php
//
// demoPhpFileSystemManagement.php
//

do
{
   echo "\nWhich PHP File System Operation Do You Want To Run?\n\n";
   echo "1. Parse File Path Information\n";
   echo "2. Acquire an Absolute Path\n";
   echo "3. Get File Size\n";
   echo "4. Get Disk Size and Free Space\n";
   echo "5. Get File Times\n";
   echo "\nEnter 0 to Exit\n";
   echo "\n\nYour Choice: ";
   $selection = trim(fgets(STDIN));
}
while (!(   ($selection == "0") || ($selection == "1") || ($selection == "2")
         || ($selection == "3") || ($selection == "4") || ($selection == "5")));


switch ($selection)
{
   case "1":
      echo "Enter a file path: ";
      $filePath = trim(fgets(STDIN));
      $filePathInfo = parseFilePath($filePath);
      echo $filePathInfo;
      break;
   case "2":
      echo "Enter path: ";
      $filePath = trim(fgets(STDIN));
      $realPath = convertPathToAbsolute($filePath);
      echo $realPath;
      break;
   case "3":
      echo "Enter path and name of file: ";
      $filePath = trim(fgets(STDIN));
      $sizeOfFile = getSizeOfFile($filePath);
      echo "File ".$filePath." has a size of ".$sizeOfFile." bytes.";
      break;
   case "4":
      echo "Enter disk label: ";
      $diskLabel = trim(fgets(STDIN));
      $diskSpace = getDiskSizeAndFreeSpace($diskLabel);
      $percentageFree = $diskSpace[1] / $diskSpace[0];
      echo "Disk ".$diskLabel." has ".$diskSpace[1]." of ".$diskSpace[0]
          ." bytes free (".round($percentageFree*100)."%).";
      break;
   case "5":
      echo "Enter a file who access/changed/modified times are desired: ";
      $filePath = trim(fgets(STDIN));
      $fileTimes = getFileTimes($filePath);
      echo "File ".$filePath." was last accessed on ".$fileTimes[0]
          .", was last changed on ".$fileTimes[1]
          .", and was last modified on ".$fileTimes[2];
      break;
   case "0":
   default:
   echo "\n\n";
   exit();
}


/**
 * Parse the provided file path. Demonstrates the following PHP functions:
 *
 *  - basename() : Provides base portion of file path (file name).
 *  - dirname()  : Directory name portion of file path.
 *  - pathinfo() : All components of path (basename, directory name, extension).
 *
 * @param $filePath File path to be parsed.
 * @return File path information in a single String.
 */
function parseFilePath($filePath)
{
   echo "Parsing file path ...", $filePath, "\n";
   $fileBaseName = basename($filePath);
   $fileDirectoryName = dirname($filePath);
   $pathInfo = pathinfo($filePath);
   return "File Name: ".$fileBaseName."\nDirectory Name: ".$fileDirectoryName
         ."\nFileName: ".$pathInfo['basename']."\nDirectory Name: "
         .$pathInfo['dirname']."\nFile Extension: ".$pathInfo['extension']
         ."\nFile name without extension: ".$pathInfo['filename'];
}


/**
 * Convert the provided path to an absolute path.
 *
 * @param $filePath File path to be made absolute.
 * @return Absolute version of provided file path.
 */
function convertPathToAbsolute($filePath)
{
   echo "Converting file path ", $filePath, " to absolute path...\n";
   return realpath($filePath);
}


/**
 * Determine size of provided file.
 *
 * @param? $filePath Path and name of file whose size is needed.
 * @return Size of file indicated by provided file path and name (in bytes).
 */
function getSizeOfFile($filePath)
{
   echo "Getting size of file ", $filePath, "...\n";
   return filesize($filePath);
}


/**
 * Provide disk size and free space on disk for provided disk.
 *
 * @param $diskLabel Label of disk whose total size and free space are to be
 *    provided.
 * @return Array of two elements, first of which is total disk space (in bytes)
 *    and second of which is free disk space (in bytes).
 */
function getDiskSizeAndFreeSpace($diskLabel)
{
   return array(disk_total_space($diskLabel), disk_free_space($diskLabel));
}


/**
 * Provide access, changed, and modified times for given file path.
 *
 * @param filePath Path and name of file whose times are desired.
 * @return Array of three elements with first being the file's access time,
 *    second being the file's changed time, and third being the file's modified
 *    time.
 */
function getFileTimes($filePath)
{
   $dateTimeFormat = "d-m-y g:i:sa";
   $fileAccessTime = fileatime($filePath);
   $fileChangedTime = filectime($filePath);
   $fileModifiedTime = filemtime($filePath);
   return array(date($dateTimeFormat, $fileAccessTime),
                date($dateTimeFormat, $fileChangedTime),
                date($dateTimeFormat, $fileModifiedTime));
}
?>

Before going into more detailed coverage of the PHP file system functions used in the above example, I have observed my Java background in that PHP code. For example, I used Javadoc-style comments for the functions in the code. Fortunately, PHPDocumentor respects Javadoc-style comments when generating code documentation. The above code also demonstrates the difference of naming conventions I'm accustomed to in Java (camel case) and the naming conventions of PHP (all lowercase names with words separated by underscores) as shown by the PHP functions invoked.

The first part of the PHP script provides a simple text command-line menu that prompts the user to enter choices and file names and paths. This snippet of code does not do anything itself with the PHP file system functions, but it does demonstrate PHP standard input and output and the PHP switch statement. That first portion is reproduced here.

Command Line Menu and Input Processing
do
{
   echo "\nWhich PHP File System Operation Do You Want To Run?\n\n";
   echo "1. Parse File Path Information\n";
   echo "2. Acquire an Absolute Path\n";
   echo "3. Get File Size\n";
   echo "4. Get Disk Size and Free Space\n";
   echo "5. Get File Times\n";
   echo "\nEnter 0 to Exit\n";
   echo "\n\nYour Choice: ";
   $selection = trim(fgets(STDIN));
}
while (!(   ($selection == "0") || ($selection == "1") || ($selection == "2")
         || ($selection == "3") || ($selection == "4") || ($selection == "5")));


switch ($selection)
{
   case "1":
      echo "Enter a file path: ";
      $filePath = trim(fgets(STDIN));
      $filePathInfo = parseFilePath($filePath);
      echo $filePathInfo;
      break;
   case "2":
      echo "Enter path: ";
      $filePath = trim(fgets(STDIN));
      $realPath = convertPathToAbsolute($filePath);
      echo $realPath;
      break;
   case "3":
      echo "Enter path and name of file: ";
      $filePath = trim(fgets(STDIN));
      $sizeOfFile = getSizeOfFile($filePath);
      echo "File ".$filePath." has a size of ".$sizeOfFile." bytes.";
      break;
   case "4":
      echo "Enter disk label: ";
      $diskLabel = trim(fgets(STDIN));
      $diskSpace = getDiskSizeAndFreeSpace($diskLabel);
      $percentageFree = $diskSpace[1] / $diskSpace[0];
      echo "Disk ".$diskLabel." has ".$diskSpace[1]." of ".$diskSpace[0]
          ." bytes free (".round($percentageFree*100)."%).";
      break;
   case "5":
      echo "Enter a file who access/changed/modified times are desired: ";
      $filePath = trim(fgets(STDIN));
      $fileTimes = getFileTimes($filePath);
      echo "File ".$filePath." was last accessed on ".$fileTimes[0]
          .", was last changed on ".$fileTimes[1]
          .", and was last modified on ".$fileTimes[2];
      break;
   case "0":
   default:
   echo "\n\n";
   exit();
}

The remainder of the PHP script contains functions that use and demonstrate the PHP file system management functions.

PHP provides functions for easy access to file path details such as the directory of the file, the full name of the file itself, the file's extension, and the name of the file without extension. Some of these are demonstrated in the above example in the parseFilePath function, which is reproduced next. The function shows off PHP's basename, dirname, and pathinfo functions.

PHP Provides File Path Information
/**
 * Parse the provided file path. Demonstrates the following PHP functions:
 *
 *  - basename() : Provides base portion of file path (file name).
 *  - dirname()  : Directory name portion of file path.
 *  - pathinfo() : All components of path (basename, directory name, extension).
 *
 * @param $filePath File path to be parsed.
 * @return File path information in a single String.
 */
function parseFilePath($filePath)
{
   echo "Parsing file path ...", $filePath, "\n";
   $fileBaseName = basename($filePath);
   $fileDirectoryName = dirname($filePath);
   $pathInfo = pathinfo($filePath);
   return "File Name: ".$fileBaseName."\nDirectory Name: ".$fileDirectoryName
         ."\nFileName: ".$pathInfo['basename']."\nDirectory Name: "
         .$pathInfo['dirname']."\nFile Extension: ".$pathInfo['extension']
         ."\nFile name without extension: ".$pathInfo['filename'];
}

The output from running the above against an example file is now shown.



PHP provide a useful realpath function that provides an absolute version of a provided path. For example, it will resolve soft links and relative directories to return the absolute path. This is demonstrated in the convertPathToAbsolute function in my example (and reproduced in the next code listing).

Demonstrating Absolute Paths via realpath
/**
 * Convert the provided path to an absolute path.
 *
 * @param $filePath File path to be made absolute.
 * @return Absolute version of provided file path.
 */
function convertPathToAbsolute($filePath)
{
   echo "Converting file path ", $filePath, " to absolute path...\n";
   return realpath($filePath);
}

The above portion of the script produces the following output.



PHP makes it easy to determine the size of a file with the aptly named filesize function. My getSizeOfFile function demonstrates this and is listed on its own in the next code listing.

Getting File Size in PHP
/**
 * Determine size of provided file.
 *
 * @param? $filePath Path and name of file whose size is needed.
 * @return Size of file indicated by provided file path and name (in bytes).
 */
function getSizeOfFile($filePath)
{
   echo "Getting size of file ", $filePath, "...\n";
   return filesize($filePath);
}

The code leads to the output shown in the next image.


PHP also makes it easy to get disk space information. PHP's disk_total_space and disk_free_space functions are demonstrated in the code listing below for my getDiskSizeAndFreeSpace function.

PHP Disk Size and Free Space
/**
 * Provide disk size and free space on disk for provided disk.
 *
 * @param $diskLabel Label of disk whose total size and free space are to be
 *    provided.
 * @return Array of two elements, first of which is total disk space (in bytes)
 *    and second of which is free disk space (in bytes).
 */
function getDiskSizeAndFreeSpace($diskLabel)
{
   return array(disk_total_space($diskLabel), disk_free_space($diskLabel));
}

The above example is not only demonstrates PHP's disk_total_space and disk_free_space functions, but it also demonstrates using PHP's array function to create an array and place elements within the array in a single statement.

The output of this portion of the script is shown next.


The final function in my script is getFileTimes and its purpose is to demonstrate three PHP methods for accessing dates/times associated with files. Specifically, the fileatime, filectime, and filemtime functions are demonstrated.

PHP File Times
/**
 * Provide access, changed, and modified times for given file path.
 *
 * @param filePath Path and name of file whose times are desired.
 * @return Array of three elements with first being the file's access time,
 *    second being the file's changed time, and third being the file's modified
 *    time.
 */
function getFileTimes($filePath)
{
   $dateTimeFormat = "d-m-y g:i:sa";
   $fileAccessTime = fileatime($filePath);
   $fileChangedTime = filectime($filePath);
   $fileModifiedTime = filemtime($filePath);
   return array(date($dateTimeFormat, $fileAccessTime),
                date($dateTimeFormat, $fileChangedTime),
                date($dateTimeFormat, $fileModifiedTime));
}

The above code demonstrates the three methods fileatime, filectime, and filemtime. One of my first questions when running across these methods was, "What is the difference between 'changed time' and 'modified time'?" The answer is available in the PHP Manual which differentiate filemtime returning the last time the contents of the file were changed versus filectime which returns the "inode change time" of the file.

The output from running the above piece of the script is shown next.



Conclusion

PHP provides an impressive set of built-in functions for determining information about files, directories, and the file system in general. These functions can be very important in different types of scripts.

JavaFX 2 Beta: Time to Reevaluate JavaFX?

JavaFX 2 beta was released earlier this week. The main JavaFX download page states the following regarding this release:
JavaFX 2.0 Beta is the latest major update release for JavaFX. Many of the new features introduced in JavaFX 2.0 Beta are incompatible with JavaFX 1.3. If you are developing a new application in JavaFX, it is recommended that you start with JavaFX 2.0 Beta.

I posted O JavaFx, What Are Thou? a year ago. Much has changed in JavaFX since then. Most notable of these changes were the JavaOne 2010 announcements related to JavaFX's direction. As I blogged about at JavaOne 2010, I thought Oracle's plans to move to a standard Java API for JavaFX to replace a separate and highly unrelated F3-based JavaFX Script language was the correct decision for any possibility of long-term and wide-spread adoption of the technology. Although a small minority of developers really like JavaFX Script, that direction did not seem to appeal to the vast majority. The good news for those who want to continue using JavaFX Script is the spawning of Visage. I was excited about Oracle's new announced direction for JavaFX, but we all knew that we needed to wait to see if Oracle would deliver.

With the announcement regarding JavaFX 2 beta, a natural question is, "Is it time to reconsider JavaFX?" My previously mentioned post O JavaFX, What Art Thou? brought up several of the issues that concerned developers considering adoption of JavaFX. Most of this post asks those questions again in light of JavaFX 2 beta.


Is JavaFX Java?

One of the questions in that post, "Is JavaFX Java?" seems to be answered somewhat (and more than before) in the affirmative. Because JavaFX 2 will support standard Java APIs, it will at least be "Java" in the sense that any third-party library like Hibernate or the Spring Framework is "Java." It still may not be Java in the sense that it's neither part of the Java SE specification or the Java EE specification.


Is JavaFX Standard?

I've seen nothing to indicate that JavaFX 2 will be any more "standard" than previous versions. As far as I can tell, JavaFX remains a product with no standard specification and only a single implementation (Oracle's). There are no specifications that others might implement.


Is JavaFX Open Source?

This is another question that probably won't be fully answered until JavaFX 2 is formally released in production version. My best guess is that it will consist of a similar mixture of licenses (some open source) as earlier versions did.


What is JavaFX's license?

This is one more question to add to the list of questions to ask again with the formal release of JavaFX 2 non-beta release. My best guess, similar to my guess regarding its open source status, is that JavaFX's licenses will remain somewhat similar to those for previous versions of JavaFX. I also expect JavaFX licensing to follow the Flex/Flash licensing model with the compiler and language tools tending to be open source and the runtime tending to be proprietary.

The Oracle Early Technology Adopter License Terms seem to apply for the beta release. The Charles Humble interview of Richard Bair in JavaFX 2.0 Will Bring Hardware Accelerated Graphics and Better Licensing Terms to the Platform includes brief mention of licensing plans. Regarding licensing of the JavaFX runtime, Bair states, "The JavaFX license is expected to be consistent with the JRE license, which allows such distribution under specific conditions."


How is JavaFX's Deployment?

Although I believe that one of the largest drawbacks of JavaFX adoption in the past was the need to learn another non-Java language in JavaFX Script, there is no question that issues with the deployment model competed for most important disadvantage of JavaFX. Max Katz has stated, "I think JavaFX failed to gain any significant momentum mainly because of deployment problems." He discussed these deployment problems in a separate post.

The crux of the problem with JavaFX deployment seemed to revolve around its applet foundation. In the previously mentioned Max Katz post, he stated:
As the mantra in real estate is: location, location, location. The mantra in JavaFX is: deployment, deployment, deployment. Unfortunately, this is where JavaFX has failed miserably. The original Java applets failed miserably in deployment and JavaFX (which was supposed to be the next applet technology or applets 2.0) has inherited the failed deployment with it. In other words, nothing has really changed since 1995.

Although the "Next Generation in Applet Java Plug-in Technology" did bring improvements to the applet deployment environment, it simply wasn't enough. Developers were widely unhappy about its performance and usability when compared to environments such as Flash, HTML/JavaScript, and Silverlight. Unfortunately, it may be too late to salvage the applet at this point.

Oracle appears to be addressing the deployment issue in JavaFX 2. In Deploying JavaFX Applications, Nancy Hildebrandt writes about "three basic types of [JavaFX] application deployment": the maligned applet, Web Start, and standalone desktop. I'm particularly excited about the non-browser deployment environments.

In her article, Hildebrandt talks about JavaFX 2 Beta Deployment Features that are specific to each deployment environment (improvements for applet/browser and Web Start environments) as well as general deployment features. I particularly like two of these general deployment features that are highly related:
  • "The same JavaFX source code works for applets, Web Start applications, and standalone desktop applications."
  • "The same JavaFX JAR file can be deployed as an applet, a Web Start application, or a standalone application."


Is It Time to Revisit JavaFX?

Since my initial significant disappointment with JavaFX since the now infamous 2007 JavaOne announcement, I have been a skeptic of JavaFX's future. Beginning with the JavaOne 2010 opening keynote announcement regarding Oracle's change of direction for JavaFX, I have begun to think that JavaFX has an outside chance at a real future in application development. Oracle does seem to be delivering on their announced plans. If they continue to do so, JavaFX is likely to be a more compelling choice than it's ever been.

My previous concerns regarding JavaFX all involved a common theme: it had nothing to really distinguish itself from a host of more mature products with wider communities and support. Because JavaFX had its own language in JavaFX Script, it really was no "easier" for a Java developer to learn than Flex/MXML/ActionScript. Flash and Silverlight are proprietary, but so is the JavaFX runtime. JavaFX was (and is) no more standards-based than any of the competitors. Flash and Silverlight have also boasted better runtime experiences than JavaFX. HTML5 is a recent entry to provide formidable competition for JavaFX.

Oracle appears to be changing JavaFX to distinguish itself better from other technologies. By allowing for standard Java APIs and for non-browser JavaFX applications, JavaFX becomes more attractive to the massive Java developer base. JavaFX will have the most difficulty competing in the browser space with Flex/Flash, Silverlight, and HTML5 already entrenching themselves there. However, I think JavaFX can find some success in the Web Start and standalone desktop environments against tools like Adobe AIR. AIR has been aimed at Flex developers who wish to developer desktop applications. JavaFX may just reintroduce the Java advantage of the same code/same JAR being able to run in the browser or on the desktop.

Because I have a lot on my plate already (starting to really use PHP for instance), I'll probably monitor others' reports of their use of JavaFX 2 beta in blog posts and other online forums. Assuming more good reports than bad, I hope to start trying JavaFX out for myself between now and JavaOne 2011 (where I expect to see heavy emphasis on JavaFX coupled with releases and other news).

Although lack of time is my biggest reason for not starting to use JavaFX 2 beta today, there are other reasons that may keep some from starting to use JavaFX 2 beta immediately. First, it is not available for all of the major operating systems platforms. The JavaFX 2.0 Beta System Requirements page states which operating systems and web browsers are currently supported. In general, the supported operating systems are 32-bit and 64-bit versions of Windows (Windows XP, Windows Vista, and Windows 7). Although Safari and Opera are not explicitly listed as supported, recent versions of the three most popular web browsers are explicitly supported: Chrome, Firefox 3.6 and Firefox 4, and Internet Explorer 8. Many of us hope, of course, that JavaFX will ultimately be available not only for other desktop machines (Linux or Mac), but will be available for mobile devices. This can be seen in the comments on Richard Bair's post Is JavaFX 2.0 Cross Platform?

The JavaFX 2.0 Beta System Requirements page also states that JDK 6 Update 24 (perhaps better known for patching a significant security hole) or later is required. In addition, it points out that 32-bit JavaFX runtime and 32-bit JDK are supported on the Windows environments, even for 64-bit Windows versions.

The JavaOne 2010 opening keynote focused largely on continued inclusion of Prism in JavaFX 2 and other desktop Java technologies. The JavaFX 2.0 Beta System Requirements page states which graphics cards are known to be support Prism. JavaFX will work without these graphics cards, but the Java 2D pipeline is used instead of Prism in such cases.


Conclusion

Oracle's JavaOne 2010 plans for JavaFX and their recent release of JavaFX 2.0 beta have piqued my curiosity. Once I have a little more time and once a few of the wrinkles commonly associated with beta software have been ironed out, I do plan to reevaluate JavaFX. This could change based on others' documented experiences, but my current plan is to start using JavaFX in the near future and to definitely be somewhat more familiar with it in time for JavaOne 2011. I also expect there to be significant news and information on JavaFX 2 at JavaOne 2011.

Friday, May 27, 2011

Finding Humor in Software Development, Part I

I have run across a few posts recently that I have found funny. However, in finding amusement in these, I must admit some very small degree of personal nerdiness. I don't think, for example, that my wife would find these to be as amusing as I did. With the weekend rapidly approaching, this lighter blog post related to software development seemed apropos.


WHATWG Specification on Microblogging

Reddit user cycles recently posted I just noticed the HTML specification has a nice, subtle jab at microblogging, which already has well over 300 comments. The link is to WHATWG's HTML specification section on the input element's maximum length attribute. The referenced comment is funny because it provides a hypothetical example in this specification that states (I added the emphasis): "The following extract shows how a messaging client's text entry could be arbitrarily restricted to a fixed number of characters, thus forcing any conversation through this medium to be terse and discouraging intelligent discourse." The hypothetical example provided "happens" to feature a maxlength of 140, the Twitter character limit.


Legal Protections for Hello, World

Another Reddit user, leadline, posted Legal Overkill, which is a link to source code for HelloWorldApp. This one is funny because there are thirty lines of comments with disclaimers and licensing information for ten lines of "code" (five of which are Javadoc for the main method).

This, of course, is understandable as a likely result of some type of script being run across all code samples available from Oracle. It wouldn't be funny if there was some code of significant interest or risk involved, but it so happens that this code is simply the tired old Java Hello, World that has been around since the beginning of Java.


HTTP Status Code 418: I'm a teapot

I've known about this one for longer than the two mentioned previously, but have found it amusing. HTTP Status Codes, while useful in web and REST applications, are a relatively boring business. I think it's funny that some folks took enough time to create the Hyper Text Coffee Pot Control Protocol in a realistic fashion and assign it HTTP status code 418. Although this was an April Fools' Joke in 1998, it continues to play a joke on people even today. Google has been known to annually generate some good technically related Aprils Fools' Jokes.


Conclusion

The three examples mentioned in this post are primarily humorous to software developers. If humor can be found in HTTP status codes, Hello World applications, and a standard specification, we can likely find humor anywhere in our business.

Thursday, May 26, 2011

Jolokia, Java, JMX, and Groovy

The Bhut Jolokia is not just a chili pepper; it was deemed for several years as the hottest chili pepper in the world. In this blog post, I talk about something presumably named after this chili pepper (the logo and subtitle "JMX on Capsaicin" are strong hints): the "remote JMX with JSON over HTTP" project called Jolokia.


The main Jolokia page describes this project:
Jolokia is remote JMX with JSON over HTTP. It is fast, simple, polyglot and has unique features. It's JMX on Capsaicin. Jolokia is a JMX-HTTP bridge giving an alternative to JSR-160 connectors. It is an agent based approach with support for many platforms. In addition to basic JMX operations it enhances JMX remoting with unique features like bulk requests or fine grained security policies.

Java Management Extensions can be extremely useful for managing and monitoring Java-based applications. For the most part, JMX remote clients are typically written in Java or a JVM-based language like Groovy or JRuby because JMX is most friendly to JVM-based clients.

Although there are non-JVM approaches to JMX web clients such as the experimental JMX Web Services Connector, these are the exception rather than the rule. Perhaps the most significant advantage of Jolokia is that it is based on HTTP (rather than traditional RMI used for JMX remote access) and its format is language-independent JSON (which I recently discussed in Groovy 1.8 Introduces Groovy to JSON). Having HTTP as the transport mechanism and JSON as the data format allows Jolokia-based clients to be written in nearly any conceivable language. At the time of this writing, out-of-the-box Jolkia agents are WAR (Java EE web application) Agent, OSGi Agent, JVM JDK6 Agent, and the Mule Agent. I focus on the JVM JDK6 Agent in this post.

The next code listing contains a simple nonsensical class that is intended solely to provide a long-running Java application whose automatically-provided MXBeans can be accessed via Jolokia.

Main.java
package dustin.examples;

import static java.lang.System.out;

/**
 * Main class for demonstrating Jolokia JVM Agent. This class doesn't really do
 * anything special except "live" in the JVM so that its built-in JMX MXBeans
 * can be accessed by JMX clients.
 */
public class Main
{
   /**
    * Main executable function.
    *
    * @param arguments Command-line arguments: one numeric argument expected.
    */
   public static void main(final String[] arguments)
   {
      final long numberLoops = arguments.length > 0 ? Long.parseLong(arguments[0]) : 1000000L;
      for (long count = 0; count < numberLoops; ++count)
      {
         if (count % 100 == 0)
         {
            try
            {
               Thread.sleep(10000);
            }
            catch (InterruptedException interruptedEx)
            {
               out.append("Thread's beauty sleep was interrupted.");
            }
         }
      }
   }
}

The above class, once compiled, can be run with the Java launcher. However, to employ Jolokia's JVM JDK6 Agent, the JVM Tool Interface (JVMTI) must be used. The JVMTI documentation warns that "JVM TI may not be available in all implementations of the JavaTM virtual machine." The Jolokia documentation is more specific in saying that Oracle's HotSpot JVM is the one for which their particular Agent is supported (because it leverages the HttpServer embedded in HotSpot).

Assuming that the Main.java class shown above is compiled and then packaged into a JAR file called JolokiaDemo.jar, the Java launcher can be run against this JAR file and associate the Jolokia JVM JDK6 Agent with the following command:

java -javaagent:C:\jolokia-0.90\jolokia-jvm-jdk6-0.90-agent.jar=port=8778,host=localhost -cp dist\JolokiaDemo.jar dustin.examples.Main 1000000000

The command just shown specifies the Jolokia agent JAR (jolokia-jvm-jdk6-0.90-agent.jar) and specifies two properties with values (host and port). Note that the specified host and port happen to be the defaults, but I included them here explicitly to indicate how they are supplied to the agent. The portion "-javaagent:C:\jolokia-0.90\jolokia-jvm-jdk6-0.90-agent.jar=port=8778,host=localhost" is the JVMTI portion and everything else is "traditional" Java launcher syntax.

Running the java launcher as indicated above leads to output like that shown in the next screen snapshot.


I like that Jolokia reports the URL by which its HTTP-exposed JMX information is available. This makes it easier to ensure that the client connects properly. In "normal" mode, this is about all that is seen as the client interacts with the application. However, I find it useful to enable Jolokia's debugging when getting the client to connect to this exposed application and this is easily done by adding debug=true onto the end of the JVMTI agent specification. An example of this is shown next.

java -javaagent:C:\jolokia-0.90\jolokia-jvm-jdk6-0.90-agent.jar=port=8778,host=localhost,debug=true -cp dist\JolokiaDemo.jar dustin.examples.Main 1000000000 

Running with debug=true leads to output like the following:


I haven't shown the client yet, but this debug output gives pretty good hints as to what the client is asking for. I found this invaluable as I experimented with the Jolokia requests. Speaking of the client, the next code listing contains a Groovy script for accessing some built-in MXBeans information about this simple thread sleeping class.

runJolokiaJmxClient.groovy
#!/usr/bin/env groovy
// runJolokiaJmxClient.groovy

import org.jolokia.client.J4pClient
import org.jolokia.client.exception.J4pConnectException
import org.jolokia.client.exception.J4pRemoteException
import org.jolokia.client.request.J4pReadRequest
import org.jolokia.client.request.J4pReadResponse

def localHost = InetAddress.getLoopbackAddress()
def urlStr = "http://${localHost.hostAddress}:8778/jolokia/"
def j4pClient = new J4pClient(urlStr)
println "Attempting to connect to ${urlStr}..."
def heapMemoryRequest = new J4pReadRequest("java.lang:type=Memory",
                                           "HeapMemoryUsage")
def threadingRequest = new J4pReadRequest("java.lang:type=Threading",
                                          "ThreadCount")
def operatingSystemRequest = new J4pReadRequest("java.lang:type=OperatingSystem",
                                                "Arch")

J4pReadResponse heapMemoryResponse = null
J4pReadResponse threadingResponse = null
J4pReadResponse osResponse = null
try
{
   heapMemoryResponse = j4pClient.execute(heapMemoryRequest)
   threadingResponse = j4pClient.execute(threadingRequest)
   osResponse = j4pClient.execute(operatingSystemRequest)
}
catch (J4pConnectException connEx)
{
   println "ERROR: Cannot connect to ${urlStr}\n${connEx.message}"
}
catch (J4pRemoteException remoteEx)
{
   println "ERROR encountered while trying to access Jolokia-exposed JVM\n${remoteEx.message}"
   println "Status: ${remoteEx.status}"
   println "Error Code: ${remoteEx.errorType}"
   println "Remote Stack Trace: ${remoteEx.remoteStackTrace}"
}
println "Heap Memory: ${heapMemoryResponse?.value}"
println "Thread Count: ${threadingResponse?.value}"
println "Operating System Architecture: ${osResponse?.value}"

The simple script above uses basic Jolokia classes and exceptions to communicate with the Jolokia instrumented Java application. The output from running the above script is shown in the next screen snapshot.


The output proves that the client was able to talk to the simple Java application and acquire information about its memory usage, its thread count, and its operating system architecture. For this exercise, I threw all the required dependencies on the classpath explicitly provided to the Groovy launcher, but there are other ways to handle classpath dependencies in Groovy.

Accessing JMX information via Groovy clients is pretty straightforward thanks to Groovy being a JVM-based language and thanks to its JMX syntactic goodness. In the case of Groovy clients, I probably would not be likely to employ Jolokia. However, the fact that the remote access is via HTTP and that the data is passed back in JSON format means there are numerous possibilities for non-JVM-based clients to access JVM information. Tomasz Nurkiewicz's post Jolokia + Highcharts = JMX for human beings provides a thorough example of doing just this. Nurkiewicz not only covers using JavaScript on the client side, but also provides examples via curl of the JSON format returned by Jolokia.

Jolokia's current version is 0.90 and the main page suggests that 1.0 will be released in late summer of 2011. Jolokia can be downloaded as binary or source code (it has an Apache 2 license). Individual JARs such as the JVM-Agent JAR and the Java Client JAR used in my example can be downloaded as well. The main Jolokia site provides simple examples of using the Jolokia Java Client Library, the JavaScript Client Library, and the Perl Client Library. There are also simple examples of code using the various agents such as the JVM Agent. The Jolokia Reference Documentation is still a work in progress and is also available in PDF format (though the HTML format seems more complete to me).


Conclusion

Jolokia holds significant promise as a mechanism for exposing valuable information held within Java applications and their hosting JVMs to non-Java/non-JVM clients. In this post, I've looked at one very simple example of accessing a Java application's JVM information from a Groovy client using Jolokia.

Wednesday, May 25, 2011

Web-less PHP: Command Line PHP

When I decided to give PHP a closer look, I wondered if PHP was a browser-only technology or if it could be used for command line scripting. It turns out that one can write operating system level scripts with PHP as discussed in online resources such as Command Line Scripting in PHP, Command Line PHP on Microsoft Windows, and Executing PHP files. In this blog post, I look at PHP command line scripting at an introductory level.

At first glance, command line PHP script code looks like PHP code intended for the web browser. The difference becomes more obvious, though, when one notices there is typically no web-specific code (HTML/CSS/JavaScript) in the PHP command line script (and there often is for browser-oriented PHP).

I like to start PHP command line scripts with a shebang statement to make it even more obvious that it's a script intended for the command line rather than for the web browser. Although the shebang is intended for Unix and Linux operating systems, it doesn't hurt anything in DOS/Windows and communicates the target of the script (command line instead of web browser). The following code snippet indicates use of the PHP shebang in a simple PHP Hello, World example.

demoBasicHelloWorld.php
#!/usr/bin/php
<?php
   print "Hello World!";
?>

The short PHP script above does its job and, when run from the command line, prints out the string "Hello World!". This is shown in the next screen snapshot.


Many scripting languages seem to share the sometimes helpful/sometimes maddening trait of having multiple ways to do any one task. In the case of writing output, PHP has multiple approaches. I used the PHP print language construct in the above example, but the echo language construct works as well as shown in the next code listing.

demoBasicHelloWorldWithEcho.php
#!/usr/bin/php
<?php
   echo "Hello World!";
?>

The output of using echo instead of print appears exactly the same and so I don't show it here. Why would one ever choose to use print instead of echo or echo instead of print? There are seemingly numberless online resources explaining the differences between the two and contrasting them in various performance benchmarks. These include PHP Echo Vs Print: Which Should Developers Use?, PHP: Echo Versus Print(f) [which reminds us there is also the printf for printing formatted output in a similar fashion as C's sprintf and Java's String.format/Console.printf], and Echo (PHP) Versus Print (PHP). PHP Tidbit: echo vs print succinctly explains the difference: print returns a boolean value indicate status of the output whereas echo does not return anything. The slight performance benefit typically seen with echo typically does not favor it significantly compared to print for most use.


PHP Command-line Arguments

Any scripting language needs to be able to accept and use arguments passed to it on the command line. Even Java class's main functions expect arguments and Groovy makes this easier to use by implicitly providing the args handle to all Groovy scripts. PHP handles command-line arguments in a fashion similar to the C language. The use of command-line arguments is demonstrated in the next PHP code listing.

#!/usr/bin/php
<?php
if ($argc < 2)
{
   print "Hello World!";
}
else
{
   print "Hello $argv[1]!";
}
?>

The output from running the above script with and without an extra argument on the command line is shown in the next screen snapshot.



Getting PHP and Environment Information

PHP makes it really easy to get more information than you could probably ever use. This is demonstrated in the next very simple PHP code example.

showPhpInfo.php
#!/usr/bin/php
<?php
phpinfo();
?>

This simple code using phpinfo() returns too much information to show here. It includes PHP configuration information as well as the names and settings of the applicable environment variables. The end of the output contains PHP licensing information.

Speaking of environmental variables, most scripting languages running in an operating system environment need access to one or more environmental variables. PHP makes it easy to access these as shown in the next code listing.

getGroovyHomeEnvVar.php
#!/usr/bin/php
<?php
print getenv('GROOVY_HOME');
?>

The output from executing the above script leads to the output shown in the next screen snapshot.



Running Operating System Commands from PHP

Most scripting languages must support an ability to invoke operating system commands. PHP support is covered in the article Use command-line tools in PHP. Sub-titled "Run shell commands in your Web applications," this article "considers the tools built into PHP that allow you to tap into the underlying shell environment and file system PHP is running on." Specific commands for invoking shell commands from PHP include shell_exec() (equivalent to using backticks), exec(), passthru(), and C-like system().

When possible, I prefer scripts that are independent of operating system. However, when I do need operating system specific functionality, I like to either make the script either clearly advertise that it is operating system specific or, even better, put code in the script to handle different operating systems. PHP makes it possible to determine the operating system via its php_uname function.

The next PHP code listing demonstrates using php_uname in conjunction with the backticks to execute a command appropriate for the identified operating system.

#!/usr/bin/php
<?php
$os_name = php_uname("s"); // "s" mode requests operating system 'name'
if (strtoupper(substr($os_name, 0, 3)) === 'WIN')
{
   echo `dir`;
}
else
{
   echo `ls`;
}
?>

The output from running the above script is shown in the next image.



Distinguishing Web Browser PHP from Command Line PHP

There are numerous ways to determine whether a piece of PHP code is intended for a web browser or for a command line. A brute force mechanism is to look for HTML and other telltale signs of web pages to identify a piece of PHP intended for the web browser. Looking for line breaks can be useful because web-intended PHP will tend to use <br> tags while command-line intended PHP tends to use "\n". A convenient runtime mechanism for determing the environment in which the PHP code is executing is php_sapi_name, which returns the interface between the PHP code and its executing server. If the returned String is "cli," it is a command-line interface. If it is anything other than "cli," it is not command line (and is likely running on a web server and intended for a web browser).

The code below demonstrates use of php_sapi_name to distinguish running in command line versus in web server.

demoDisplayPhpEnv.php
#!/usr/bin/php
<?php
   /*
    * Script that indicates how to programmatically determine the environment
    * within which a PHP script is running.
    */
   $php_type = php_sapi_name();
   if ($php_type == "cli")
   {
      echo "PHP script executed from command line.\n";
   }
   else
   {
      echo "PHP script NOT executed from command line.\n";
   }
?>

The output from running the above PHP script from the command line is shown next.


The CLI SAPI differs from other PHP SAPIs and these differences are documented in PHP Command Line Usage: Differences to other SAPIs.


Conclusion

PHP is not just for web pages and web sites anymore. It can be used for command line scripting as well. My primary interest in PHP remains for web development and I believe I will continue to prefer languages such as Groovy, Ruby, and bash for my scripting. However, it is useful to know that PHP can be used for command line scripts. PHP developers can probably find the same benefits using the language they know well to write scripts that I find when using Groovy to write scripts. For me, I find working with PHP on command line scripts to be an easy way to become more familiar with PHP syntax, standard functions, and coding conventions.


Additional Resources