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!

Saturday, November 28, 2009

New Source of Programming Tasks

Are you learning any new tools? I've recently been working with Erlang and Go. But I've got a problem-- without some sort of task to work on, I sometimes end up exploring too much of a new language, resulting in a sort of 'analysis paralysis'.

Lucky for me, Facebook has provided a nice resource to help me keep my efforts in scope. If you visit http://www.facebook.com/careers/puzzles.php, you'll find several small programming assignments suitable for use in language exploration. Who knew file i/o could be so strange to an Erlang newbie, for instance?

Happy coding!

Rick

Sunday, October 4, 2009

Statistics 'R' easy!

A while back I read an early review of 'R in Action' from Manning. This gave me some ideas about what the R language can be used for-- to be specific, it makes statistics easy! With just a few lines, you can generate mean, standard deviation, quartiles, histograms, graphs, and much more.

I've recently had the opportunity to use this new-found knowledge. At work we're building a new sharded-MySQL back end, and we've just started performance testing. We ran our first performance test and started looking at latency data. I poured the data into R, ran a few stats and printed a few graphs-- instantly a pattern showed up in the graph that shows us a repeating pattern of incremental slowdowns. (It's a saw-tooth pattern, much like what you see in JVM garbage collection graphs-- starts out low, builds to an unacceptable level, then drops back down to the initial decent value.) Cool!

R pointed out the problem, now to go dig up the root cause....

Rick

Wednesday, September 16, 2009

Review of "AspectJ in Action"

Ramnivas Laddad knows Aspect Oriented Programming. In fact, I'd say he knows AOP front to back, top to bottom, a to z. That's good.

But it's not necessarily good for you. Luckily, Mr. Laddad has taken the time to persist all his knowledge in an easy to read book, which you can read. Now that's really good!

I've recently reviewed that book, "AspectJ in Action, Second Edition" from Manning and am very impressed by the quality of this book. It covers everything you'd want to know about Aspect Oriented programming in general and AspectJ in particular, and it does it in amazingly readable ways.

For starters, here are some of the goodies this book covers:
- AOP and AspectJ basics, of course
- The mysteries of weaving plainly explained
- Common use cases for AOP, as would be expected
- How to use AOP to monitor application behavior and performance
- Using AOP for transaction control
- AOP design patterns
- Ways to maintain your AOP-infused applications and keep them clean

Each sub-topic of AOP is given it's own generous chapter, with useful source code examples and easy to understand (and realistic!) use cases.

The depth of coverage is great. But that's not what makes the book great-- the ease of reading is what makes this book great.

If you're a Java coder, you owe it to yourself to check this book out.

Thursday, August 20, 2009

Dependency Injection book, a must-read!

I've just received a hard copy of "Dependency Injection" by Dhanji R. Prasanna. This book is great!

If you are not yet a DI user, this book will guide you from beginning to expert use. If you are already a DI user, this book will reveal best practices, patterns, and a surprising number of useful suggestions to enhance your use of Dependency Injection.

Mr. Prasanna is clearly an expert in his field, and he presents ideas in an easy-to-read manner.

DI usage, like Unit Testing, facilitates writing good code. The author covers a lot of ground, making recommendations for coders dealing with AOP, thread-safety, framework design, and others.

I highly recommend this book to any developer!

Sunday, May 17, 2009

Thorough architecture-- remember testability!

When architecting software, be sure to document which test utilities you anticipate will be needed to validate your application.

Think about each operational step that is required-- then think if you had just performed that step, how would you be assured everything went well?

As an example, let's pretend you've just architected an application that should help you load some data to a backend data store (maybe a database, maybe an indexed file system, maybe something else)
  • How would you be sure the data you've loaded is really there?
  • How would you be sure it's *all* there?
  • How do you know it's available?
  • How do you know it wasn't mangled in the process of loading it?
  • Can you access it from all the places you need to access it?
If I were the operator charged with running these processes (loading the data), I'd want some sort of script I could run to make sure the data got where it was supposed to go. The time to think about this is in planning your architecture-- thinking of such things will lead you to consider the needs of your stakeholders and will give you insights into parts of your application you may have overlooked.

Thursday, April 9, 2009

Continuous Integration for C++

I've used Continuous Integration with Java for quite a while-- usually using CruiseControl, JUnit, and PMD. I've had good luck with these running them against PVCS, CVS and Subversion. Lately, though, I've had an interest in using CI for C++ development, which was a whole new story.

This time around, I thought I'd try Hudson instead of CruiseControl. I was pleasantly surprised by the ease of use-- basically, just untar Hudson someplace and run the web application, which is a .jar. Once Hudson's running, you configure it through web forms. It's really easy!

I wanted to use Subversion this time around, it was trivial to enter the URL, user and password.

Next, we had to find a way to cause our build to happen. I already had a Make-style C project to work with, so I started out using Hudson's 'run a script' configuration to invoke Make. This worked great-- right out of the box Hudson will check your project out and invoke Make.

I wanted to use a JUnit-style unit test framework, and decided to go with CPPUnit based on internet reviews. I'd had an earlier failure trying to get CPPUnit to compile under Cygwin, but that was quite a while ago, so I got the most recent build and started building with 'configure, make, make install'. (By the way, I used the relocation option to give 'configure' a hint to build CPPUnit in a local directory. I didn't want to muddy up this shared Linux server until I was confident things were going to work out well.) CPPUnit built well and I had a sample program (based on a 'Net tutorial) running in a short while.

To run CPPUnit from Hudson, I altered my script to invoke the Unit test driver right after 'make clean' and 'make'. I also redirected the output from CPPUnit to a file and echoed the contents of the file at the end of the script. (In this way, you can see everything in the 'console output' view of your Hudson build. No need to reformat the XML output!)

Next up was civilized logging. This really wasn't a necessary part of CI for C++, but I've been so spoiled by Log4J that I had to have it. So I got Log4Cxx (which also required Apache's runtime 'apr' and 'apr-utils') then built all 3 in the order apr, apr-util, then Log4Cxx. All this was done with configure (with relocation), make, make install. Log4Cxx also worked right out of the box-- woohoo!

I wanted to see how well my unit tests were covering the code, so I added new CXXFLAGS to my Make file. I had the Hudson build script use sed to toggle the flags on (which enabled me to run gnu's gcov with the Unit test driver), then I got stats which naturally got redirected into the same file CPPUnit redirects to, and thus is echoed at the end of the Hudson build script. Now our console output for the build shows Unit tests and coverage.

As a final step, I wanted to gather some stats on how my code was performing, so I invoked Valgrind in the Hudson build script and redirected the output again to the tell-all echoed file. I ended up taking this one out in the end, because it got very wordy and made for a pretty large file to view in the scrollable browser Hudson gives you. Maybe I'll try to cut that down sometime and re-add it, but for now I'm just doing without.

So there we have it! I found the whole experience totally satisfying and well worth the minimal effort it took to get the whole toolset going. I hope you have as much luck in your efforts!

Rick

Saturday, February 21, 2009

Stax Rox!

I just got done taking my first test drive of Stax, the Java Cloud provider. I haven't gone very far into it yet, but so far I've been *very* impressed with the development model. Here are the highlights:

  • Just went beta, no cost for a dev account
  • Easy to follow 5 minute videos to get you started writing your Cloud Java Web app
  • Very nice local dev environment, with easy to use tools to slog code from your desktop to the cloud
  • Trivial button-push creation of a sample Web App you can modify
  • The sdk downloads your app to your desktop for modification, it provides a built-in Eclipse project that fires up with no modifications
  • Trivial button-push to make a database (MySQL) for your application. (I haven't yet built my schema, I'm looking forward to watching the video for that.)

All things considered, this is the easiest Cloud I've had a look at. For Java devs, I can't imagine it getting much easier than this. (Although there are persistent rumors Google App Engine is bringing Java soon. Google also strongly understands the power of low-barrier-to-entry, so that'll be interesting.)

One downside: the User Agreement forbids several flavors of Open Source, notably the GNU stuff. For now, I'm sticking with the prepackaged stuff Stax gives you, so I shoudn't get in trouble that way.

If you've got 30 minutes to burn, you can have your own Cloud app up and running. The URL is here: http://www.stax.net/appconsole