Tuesday, December 29, 2009

Book Review - "GlassFish Administration"


Book Review of "GlassFish Administration", Packt Publishing

Available here.

This book is meant to be a resource for users of the GlassFish application server. It covers many aspects of GlassFish usage, including installation, configuration, application deployment, clustering, performance monitoring, and more. I would believe this book is appropriate for Enterprise Java administrators of all experience levels.

The book is generously illustrated, often times making use of screen shots to help users navigate the excellent GlassFish administrative UI. Better yet, the book also provides the Command Line equivalents wherever the UI is shown. These handy tips will allow experienced administrators to script installations, significantly cutting down both time and errors.

The CLI tips are just one example of the author's mastery of advanced server control issues. The author, Xuekun Koum, clearly understands the needs of enterprise server administrators and clearly spells out many best practices. For this reason, I would recommend this book for anyone planning to use GlassFish in a production environment. The chapters on performance tuning, monitoring, and security alone will make this book worthwhile for that audience.

In addition to that audience, I would also recommend this book to Enterprise Java developers who wish to keep abreast of best coding practices for the Java EE platform. Have you ever seen a coding demo given by Sun engineers? Using Netbeans and GlassFish, they are usually able to quickly generate flawless Java EE applications using mostly plain intuitive Java. (No hand-configuration of deployment descriptors!) This book, paired with a recent release of Netbeans and "Java EE 5 Development using GlassFish Application Server" (another Packt title) will allow you to knowledgeably generate Enterprise Java applications as easily as the Sun folks do. I'll be honest-- I'm usually not a NetBeans/GlassFish user, but this combination makes it drop-dead simple to generate entire applications in no time. Best of all, the generated source and configuration files are so clean that it's a snap to understand what each component does so you can brush up on how the whole things works. GlassFish does it's part by nicely bundling all the required resources (databases, application server instances, JMS providers, etc.), making them all very easy to administer. I've long thought Microsoft developers had a leg up on productivity given their excellent IDE and matching runtime environment, but after working with this toolset for a while I now believe the gap is closing.

I own some other titles on application server administration as well as this one. Frankly, I find this the most readable of these books. The instructions it provides are straightforward and very easy to follow. The author provides expert insights that probably came from many hours of working with GlassFish in different production settings. (Some of these ideas extend beyond current use of GlassFish, as well. In this regard, the book provides some best practices that should give the reader some wisdom without having to pay for it the hard way.) This book also touches on topics that really aren't specific to GlassFish, but rather are of interest to anyone working with an application server. Of particular interest in this area are sections on application monitoring and load balancing.

As for complaints, I have few. The primary thrust of the book is GlassFish 2, which is the current production mainstay. There is a chapter on GlassFish 3, but I wish the book were weighted a little more heavily towards version 3 so the book would maintain relevance longer. (In fairness to the author, I guess it's not possible to offer real-world experienced opinions on products that haven't been in use for much time. So I guess the version 2 / version 3 ratio is about right, realistically.) I wish this title contained a little of the content from some of Packt's other developer-centric titles (i.e. Netbeans tips). Other than those, I can't think of any other wants.

All things considered, this is a solid addition to any Java architect/developer's library. I'd urge you to check it out!

Thursday, December 24, 2009

Adventures in ORM

I've been spending a little time over the Christmas break working with toolsets I don't usually use. (I think this helps me better appreciate the tools I use, no matter what they are.) For the past couple of days I've been having a look at Java ORM solutions.

I had a quick look at Spring 3 / Hibernate 3, but hit some resistance in the form of strange errors I couldn't easily resolve. Sometimes in this case I'll just dig in and spend as much time as I have to, but in this case I decided to put down this toolkit and pick up another.

I've been doing a little work with the GlassFish application server, so I thought this would be a good chance to pick up NetBeans and make use of some of it's neat features. Every time I see the Sun folks talk, they really make NB look attractive, so I was hoping to find something good there.

Well.... I initially liked what I saw. I already had a PostGres database (also not my usual choice), so I made use of a cool code-gen feature to instantly make some Entity objects. Really easy!

The Entity beans weren't much use without a wrapper class to use them, so I also auto-generated (all this through right-click!) some Controller classes off the Entity beans. Also very easy!

Now just to hand-code a 'Main' and invoke the Controller classes. Much to my chagrin, all my nicely generated code didn't work. What was up?

A quick look at the log showed the query that was generated. Something like this:
select Name, Id from BC_Schema.BowlingCenters

That was a good clue. I knew from running hand-built queries that PostGres preferred something like this:
select "Name", "Id" from "BC_First_Schema"."BowlingCenters"

The difference was only the quotation marks. (Maybe this seems natural to PostGres users. I don't often use it, so it seemed odd to me.)

After quickly searching the web (thanks Google!) I found the quick cure was to doctor up the generated Entity class. Wherever an annotation referenced a keyword in the query, I added a backslash-double-quote to make it print the quotes when it gen'ed the query. Example:

@Column(name = "Id")

Was fixed to be:

@Column(name = "\"Id\"")

After that, I was able to quickly generate Entities and Controllers, building out a db-based application in no time. Very productive!

Probably the most valuable idea I got from the whole adventure was this:

When working with a new ORM setup, start out by coding a plain JDBC snippet to view a few rows. This will convince you you've got your credentials right, allowing you to work with fewer factors as you run down your initial bugs.

Happy Coding, and Merry Christmas!

Friday, December 18, 2009

Hadoop Solution for the Hoppity problem

The latest in the Code Snippet series.

A highly contrived solution to the Hoppity problem, using Hadoop.

Why in the world did I do this? After all, Hadoop is a batch framework for working with large amounts of data in parallel, hardly the right tool to solve a trivial small-data problem on a single laptop.

I did it primarily to exercise my Hadoop skills, though even here it's a light workout. But I think Hadoop is well worth learning and practicing, so here goes!

The Setup
- You have to have Hadoop installed. For that task, I used Michael Noll's excellent Hadoop-on-Ubuntu blog entry.
- If you have a problem running after Michael's instructions, if it's a host naming problem, be sure your hosts file has 127.0.0.1 as 'localhost'.

Run scripts
You'll probably want to use utility scripts for the following tasks:

# Compile
javac -cp /usr/local/hadoop/hadoop-0.20.1/hadoop-0.20.1-core.jar:/usr/local/hadoop/hadoop-0.20.1/lib/commons-cli-1.2.jar Hoppity.java
jar -cfv hoppity.jar *.class

# Make a directory
bin/hadoop dfs -mkdir /user/hadoop/HoppityInput


# Copy the file containing Hoppity input into the directory

bin/hadoop dfs -copyFromLocal numHops.txt /user/hadoop/HoppityInput

# Run
bin/hadoop jar hoppity.jar Hoppity /user/hadoop/HoppityInput /user/hadoop/HoppityOutput


# View your output

bin/hadoop dfs -ls /user/hadoop/HoppityOutput
bin/hadoop dfs -cat /user/hadoop/HoppityOutput/part-r-00000

# Destroy the output directory for the inevitable re-runs as you learn
bin/hadoop dfs -rmr /user/hadoop/HoppityOutput

Finally, the code

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class Hoppity {

public static class HoppityMapper
extends Mapper<Object, Text, Text, Text>{


public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
int theValue = Integer.parseInt(value.toString().trim());
StringBuilder result = new StringBuilder();
for (int idx = 1; idx < (theValue + 1); idx++){
if (isModN(idx, 3) && isModN(idx, 5)){
result.append("Hop~");
continue;
}
if (isModN(idx, 3)){
result.append("Hoppity~");
continue;
}
if (isModN(idx, 5)){
result.append("Hophop~");
continue;
}
}
Text resultKey = new Text("ResultKey");
Text resultValue = new Text(result.toString());
context.write(resultKey, resultValue);
}

private boolean isModN(int num, int mod){
if ((num % mod) == 0){
return true;
}
return false;
}
}

public static class HoppityReducer
extends Reducer<Text,Text,Text,Text> {

public void reduce(Text key, Iterable<Text> values,
Context context
) throws IOException, InterruptedException {
for (Text val : values) {
String[] hops = val.toString().split("~");
for (String hop : hops){
Text blankText = new Text();
context.write(blankText, new Text(hop));
}
}
}
}

public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
if (otherArgs.length != 2) {
System.err.println("Usage: Hoppity <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "hoppity");
job.setJarByClass(Hoppity.class);
job.setMapperClass(HoppityMapper.class);
job.setCombinerClass(HoppityReducer.class);
job.setReducerClass(HoppityReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}


Happy Coding!

Monday, December 14, 2009

A fish of a different color....

It seems there are many books available tell you how to develop software for various JEE application servers. These books are invaluable when you are writing your software components, especially when the technology is new or you are venturing into territory you haven't visited before.

But there comes a time when your development work is done, and you need to go to the next level. You need to integrate your work with external entities like JMS providers. You need to harden the environment and secure it. You need to monitor the application server, watching for resource usage trends and guarding against future failures. You need a book that emphasizes Application Server administration, not component development.

I've just been informed of a new book from Packt Publishing that emphasizes administration of the excellent GlassFish AS. The book, titled "GlassFish Administration", is scheduled for publishing later this month. I read the sample chapter and found it well written, illustrated generously with easy to read diagrams and friendly screenshots.

I hope the rest of the book is as good as the sample chapter. Watch this blog for a full review as soon as the book is available!

Happy Coding!

Saturday, December 12, 2009

Erlang solution for the Hoppity problem

The latest in the Code Snippets series.

An Erlang solution to the Hoppity problem.

For those who have never tried functional programming, here's a taste of what you might encounter. For those who know how to program in this way, I salute you! I did much learning on the way, there is much more road to travel.

To run the code:
Put the code in a file called hoppity.erl.
In the Erlang shell ('erl'), compile the file by typing:
c("hoppity").

Run the code in the Erlang shell:
hoppity:start().


-module(hoppity).
-export([start/0]).

start() ->
{ok, Device} = file:open("/home/rick/Programming/Hoppity_Hop/data.txt",[read]),
ALine = string:strip(getALine(Device)),
{AsInt, Junk} = string:to_integer(ALine),
printHoppity(AsInt),
io:fwrite("~n~s", [" "]).


getALine(Device) ->
case io:get_line(Device, "") of
eof -> file:close(Device), "None";
Line -> file:close(Device), Line
end.

printHoppity(Num) ->
printHoppityNTimes(1, Num).

printHoppityNTimes(Current, Max) ->
if Current > Max ->
pass;
true -> % 'else'
ByThree = Current rem 3,
ByFive = Current rem 5,
%io:fwrite("~n~s", [integer_to_list(ByThree)]),
%io:fwrite("~n~s", [integer_to_list(ByFive)]),
printHoppityValue(ByThree, ByFive),
printHoppityNTimes(Current + 1, Max)
end.

printHoppityValue(0, 0) ->
io:fwrite("~n~s", ["Hop"]);
printHoppityValue(0, _) ->
io:fwrite("~n~s", ["Hoppity"]);
printHoppityValue(_, 0) ->
io:fwrite("~n~s", ["Hophop"]);
printHoppityValue(_,_) ->
pass.



C++ Solution for Hoppity problem

Here's a C++ language solution for the Hoppity problem. This is part of the Code Snippet series.

To run this:
Make a simple Make file and a script to run the resulting executable, or else run it in your favorite C IDE. I used Netbeans to build this one. The only argument to the exe is the path to the file that contains the number as described by Hoppity.

The code:

#include <stdlib.h>
#include <iostream>
#include <fstream>

using namespace std;

bool isModN(int num, int mod){
if ((num % mod) == 0){
return true;
}
return false;
}

int main(int argc, char** argv) {

if (argc < 2){
cout << "Must have 1 argument, the file name" << endl;
exit(1);
}

ifstream inFile;

inFile.open(argv[1]);
if (!inFile) {
cout << "Unable to open file" << endl;
exit(1); // terminate with error
}

int theNum;
while (inFile >> theNum) {
// assume it's good -- don't do this when coding for 'real'!
}

inFile.close();

for (int kount = 1; kount < (theNum + 1); kount++){
if (isModN(kount, 3) && isModN(kount, 5)){
cout << "hop" << endl;
continue;
}
if (isModN(kount, 3)){
cout << "Hoppity" << endl;
continue;
}
if (isModN(kount, 5)){
cout << "Hophop" << endl;
continue;
}
}

return (EXIT_SUCCESS);
}

Friday, December 11, 2009

Python solution for the Hoppity problem

An entry in the Code Snippet series.

Here's a Python solution to the Hoppity problem.

How to set it up:
Copy the script below into a shell script.
Copy the code below into a file, Hoppity.py
Make a data file that contains the number, as required in the Hoppity problem.

How to run it:
Run the script, give it the path and name to your data file.

The script:
echo "Tell it the path to your data file, i.e. /home/rick/FaceBook_Puzzles/data.txt"
python3 Hoppity.py

The code:
import sys

#input_file = open("/home/rick/FaceBook_Puzzles/data.txt",'r')
line = sys.stdin.readline()
input_file = open(line.strip(),'r')

as_string = input_file.read()
the_val = eval(as_string)
for idx in range(1, (the_val + 1)):
if ( ((idx % 3) == 0) and ((idx % 5) == 0)):
print ("Hop")
elif ((idx % 3) == 0):
print ("Hoppity")
elif ((idx % 5) == 0):
print ("Hophop")

The Hoppity Problem

Here's the first problem I'd like to post in the new Code Snippet series. Thanks goes to Facebook for providing this one!

----------------------------------------------------------------------------------------------

Hoppity Hop!
Write a program that takes as input a single argument on the command line. This argument must be a file name, which contains a single positive integer. The program should read this file and obtain the integer within, and then output a sequence of strings based upon the number (details below).


Input specifications
The input file will contain a single positive integer (in base 10) expressed as a string using standard ASCII text (e.g. for example, the number "15" but without the double quotes). This number may or may not be padded on either side with white space. There will be no commas, periods, or any other non-numeric characters present within the number. The file may or may not terminate in a single new line character ("\n"). An example input file is below:

15




Output specifications
The program should iterate over all integers (inclusive) from 1 to the number expressed by the input file. For example, if the file contained the number 10, the submission should iterate over 1 through 10. At each integer value in this range, the program may possibly (based upon the following rules) output a single string terminating with a newline.

* For integers that are evenly divisible by three, output the exact string Hoppity, followed by a newline.
* For integers that are evenly divisible by five, output the exact string Hophop, followed by a newline.
* For integers that are evenly divisble by both three and five, do not do any of the above, but instead output the exact string Hop, followed by a newline.


Example output (newline at end of every line):

Hoppity
Hophop
Hoppity
Hoppity
Hophop
Hoppity
Hop

The Code Snippets series

I've decided to launch a series of blogs detailing my journey through programming tasks. I'll post a problem to be solved, then some solutions coded in different languages. My hope is that the code snippets will be small and clear enough that the blogs can be used as a reference, sort of a cut-n-paste repository to help coders quickly get program shells running.

The code snippets will not be industrial-strength implementations. They'll probably lack error handling, flexibility, optimized performance, and other attributes you'd like your real-world code to have.

The code snippets will offer quick'n'dirty implementations of common programming problems, formatted for maximum re-use.

Critiques and alternative implementations are welcome. Iron sharpens iron, they say, so feel free to suggest a better way. Watch for the first post soon.

Happy Coding!