Thursday, September 11, 2008

The Next Step

I know it's been 2 months since my last post, but things have been really busy for me, mostly because I've just made the next step in my career; joining a development team in Chesterfield, MO (just outside St Louis). It's a move from the DoD Contracting world to Corporate Product Development, one that I'm excited to make.

I haven't had experience yet shipping a product to a large number of end users. That's probably the thing I'm looking forward to the most. On top of that, I get to continue to work with Groovy and may have the opportunity to get some experience in the .Net world.

I'm especially excited to be back in STL. 4 years away from friends and family has had it's pains and perils. My wife & I got an apartment for the time being just a few minutes from work. This area of STL is absolutely great; swarming with restaurants and parks, and clean and nice to look at.

I think that's it for this post. Now that I'm settled in though, you should see my blogs pick back up.

Saturday, July 12, 2008

Scour the Web

Thanks to Mashable, I found out about the up and coming search engine Scour.

Scour actually forwards your criteria to the giants you already know (Google, Yahoo, and MSN). What you get is a combination of those results with some additional information and power.

Most importantly, the results are interactive. You can vote and comment on each one. Users' feedback provides Scour with an additional metric on each result in addition to the page rank it has with the 3 giants.

More over, as you participate, you earn points. And yep, you guessed it, you can redeem your points once you've earned enough. Right now, you'll be rewarded with Visa Gift Cards in values of $25, $50, or $100.

Feel free to sign up and give it a try.

Monday, June 16, 2008

DZone Refcardz

I haven't been spending as much time on DZone as I used to (or want to), so I just read about this. It's not breaking news, but I thought it was something worth sharing in case you haven't heard of these yet either.

DZone has begun publishing Refcardz. These are cheat sheets for developers and other technical professionals on various technologies. Refcardz cover things like IDEs or even patterns from the GoF book. It appears they're being released at a rate of once a week, so I'm sure if there isn't one you're interested in yet, it won't be too long. Just subscribe to the feed and keep an eye out.

Friday, June 13, 2008

CXF vs OC4J ... Round 2

Security is a big deal in our deployment environment and one thing being used is all HTTPS connections require Mutual Authentication. This past sprint, one story I worked on involved reproducing the mutual authentication requirement on a mock service implementation in our local test environments (so we're as close as possible to the real deal). This is the same service I talked about last time; one that we're using CXF to create a mock implementation of and client for, from the provided WSDL.

I began by enabling server authentication only, which went well and took no time at all. However, enabling the client authentication threw a huge wrench into the mix. Seriously, the stars had to align to hit us with this one.

The error: Attempting to invoke the service returns a 405 Method Not Allowed and your Apache error log shows SSL Re-negotiation in conjunction with POST method not supported


  • Condition 1: The service you're hitting requires client authentication via an SSL Certificate

  • Condition 2: When using the CXF Client, you point it at the live WSDL
    • When generating client code from a WSDL, by default, the client's default constructor will use the path on the file system to the WSDL; alternatively, another constructor takes the WSDL location as a parameter
    • Details here


  • Condition 3: The service is invoked through Apache; a version lower than 2.2.0.
    • A common setup is Oracle Application Server with Oracle HTTP Server (Apache)

  • Condition 4: You're not in control of the box where the service is deployed



Basically, CXF is initializing the connection with a GET request to retrieve the WSDL. Following this GET, CXF makes a POST request to invoke the service. Switching from a GET to a POST is causing the error. We thought for a minute that if necessary, we could copy the WSDL to the file system (WEB-INF/wsdl/ maybe?) and therefore, CXF wouldn't perform the GET. Then we realized, when CXF parses the WSDL, it retrieves any imports it finds. If one of those is a resource (custom XSD for example), it must perform a GET to retrieve that from the server.... leaving you right back at square one.

We temporarily abandoned our effort here. We need to be 100% sure that the Oracle HTTP Server in our deployment environment hasn't been patched. We'll approach the group that owns the service we're integrating with and see what their thoughts are and whether or not they've had the same issue (this service is still in development). Hopefully we can resolve this w/o moving WSDLs and XSDs to the file system and creating a maintenance nightmare.


Notes:

CXF vs OC4J ... Round 1

My deployment environment was recently switched to Oracle Application Server with Oracle Http Server (OC4J + OHS). Currently, our primary focus is integration with some external SOAP Web Services and we've been using the Apache CXF Project to generate a mock implementation of the service as well as a client from the WSDL.

I'm well aware of common pains of switching between JEE Application Servers, having worked with WebLogic, GlassFish v2, JBoss, and now OC4J. There's the initial learning curve for things like auto/hot-deployment directory, automated deployment w/in your build, getting to know the admin console, and log locations. Unfortunately it's never just that easy. You always end up running into issues around configuration differences and sometimes terrible class path and version nightmares.

The worst part of porting our applications to OC4J was most definitely deploying our Mock Service Implementation and CXF Clients. It's funny, after hitting the first CXF deployment issue I found myself at the CXF App Server Guide. A quick glance down the page indicates I'm in for quite the ride.

I found that in the end, a little more than half of the information on this page was correct... but not everything. Here are the differences I ran into. (Note: I hope I'm capturing everything, I meant to write this a month ago, during the time I was running into these issues, but never got around to it)

1. Shared Libraries and Deployment
I completely skipped the sections Replace the Oracle XML parser with Xerces and Deploying Applications Section.
I ended up having to make a number of modifications to the -Xbootclasspath/p: Java Option inside opmn.xml and by the time it was over and done with, managing shared libraries was unnecessary.

2. Setting System Properties
No matter what I did, OC4J gave me an implementation of javax.xml.parsers.DocumentBuilderFactory that would break CXF. So, I did end up setting a System Property (I know, I know ...). When using CXF to stand up a service, your web.xml will need to identify a listener as such:


<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

So, I wrote my own ContextLoadListener that extends this one (and modified the web.xml to point to mine). It's just a pass-through, simply making a call to the same method on the listener I'm extending. However, in the contextInitialized method, I set the system property just before calling the super class.

public void contextInitialized(ServletContextEvent event) {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
super.contextInitialized(event);
}


In the end...
  1. I Followed these Sections from the CXF App Server Guide:

    • Preparing stax-api

    • Get rid of OC4J JAX-WS libraries

    • swapping Oracle wsdl.jar with wsdl4j.jar and jaxb.jar API with jaxb-api-2.0.jar



  2. I Didn't Follow these Sections from the CXF App Server Guide:

    • Replace the Oracle XML parser with Xerces

    • Deploying Applications Section



  3. Ended up with the following -XbootClasspath/p: values:

    -Xbootclasspath^/p:C:\stax-api-1.0.1.jar;C:\xercesImpl-2.8.1.jar;C:\xalan-2.7.0.jar;C:\xml-apis-1.3.02.jar;C:\webservices\wsdl4j-1_6_2\lib\wsdl4j.jar;C:\jaxb-api-2.0.jar


  4. Set one system property in a custom ContextLoaderListener (as shown above)



Other Notes:

  • These steps worked for me with CXF Versions 2.0.2-incubator & 2.0.6

  • If you're on CXF version 2.1, you'll need jaxb-api-2.1 instead of 2.0

  • Download CXF here

  • Download Xerces 2.8.1 here

  • Download WSDL4J here

  • Make a directory to keep custom artifacts as you move through the process

Firefox 3 - Help Set a New World Record

The release date for Firefox 3 has been set, June 17th, 2008.

On Download Day, we're going to shoot for the most software downloads in a 24-hour period and set an official Guinness World Record.

Visit Spread Firefox and pledge your download!

Download Day

Wednesday, May 28, 2008

Morning Daily Stand-ups

I've been on Scrum teams for the past 3 years. Every team I've been on has decided to do its daily stand-up in the morning. I've tried the lunch time thing before and it just didn't work. People use their lunch hour to get things done; appointments, errands, etc. I've never tried it as an end of the day meeting. I've just always thought that by the next morning, I wouldn't recall important details.

So, my problem is that my team really isn't doing it in the morning. Our stand-up time is 9:30am. After some thought, I'm pretty sure this is having a significant negative impact on my productivity. I'm going to suggest we move to 8:15 or 8:30. If that doesn't happen, I'm going to have to figure something out for myself.

Here's a breakdown of why this isn't working for me. I come in most days between 8 and 8:30. I catch up on email that went out the night before; usually takes about 15 to 30 minutes. Then I'm left with about 30-60 minutes before the meeting. I spend about 15 minutes reviewing ScrumWorks, our project tracking tool. I make sure I've updated my hours on tasks I'm working, ensure I'm working on the highest priority tasks, etc. At that point I'm down to 15-45 minutes before our daily stand-up.

How much can you really get done in that amount of time? Maybe if you've got something small to finish up, but that isn't the case for me very often... ever.

So, we go until 9:45 in our stand-up (ideally). We talk about off-line things that came up until 10:00 or later. Sometimes we schedule meetings for directly after our stand-up since we're already in a meeting room. Most days, by the time I'm back to my desk and really starting to get something done, it's 11:00. Yep, just 1 or 2 hours before I break to eat.

The problem is, there's not much time to get up any real momentum. Even if that's my only meeting in the day, it's just not in a good spot. I don't hit any long stretches until after lunch.

Consider what I'm really saying here. A single, 15-minute meeting is noticeably hindering my productivity due to the normal routine I follow and the meeting's placement in the day. Maybe this is why I'm working so many nights on this project and always find myself saying, "Is it seriously noon already?!?!".

I think that even if my team moves to an earlier daily stand-up, I need to re-evaluate my morning routine and see if I can make any improvements on it.

From 0 to VisualSVN in 90s

I've started working on a few little things from home and wanted to start managing the source with Subversion. I've got a desktop at home running Windows XP and decided to put SVN there. On the SVN site, on the downloads page, I found this excerpt:


VisualSVN Server is a standard Windows Installer package that contains everything necessary to install, configure and manage Subversion server on Windows platform. It includes latest stable releases of Subversion, Apache plus a management console to perform most common Subversion administration tasks such as repository creation and access rights management.

I had this thing downloaded, installed, and configured in no time at all. So, if you're installing SVN on Windows, I highly suggest VisualSVN Server.

  • 30 seconds to download

  • 30 seconds to install

  • 30 seconds to configure

Tuesday, May 27, 2008

Boo Office Noise

Last week I spent a full day working from home. It's been a very long time since I've had that opportunity, and wow was it much needed. I just didn't realize how distracted I am in my current setting.

I work in a room packed with 12 people; as many as it can fit. As much as I understand and have experienced the benefit of working in an open area with your team, tight quarters with half of the conversations distracting you isn't the same thing. On top of that, we have hardwood floors, bare walls, and no ceiling. Everything from the area next door carries right in. All of these things just make my office space a productivity inhibitor. Unfortunately, we have no where else to go.

If I am ever in the position to build spaces for software engineering teams, I think I'd do the following:


  1. Open spaces for groups of up to 8 people

  2. Cubicles in a designated 'quiet' area

  3. No assigned seating. Everyone has a rolling cart to take with them. Mobile tables throughout with core supplies, an extra monitor, etc.

  4. A couple of relaxation rooms

  5. PLENTY of meeting rooms. I forgot to mention earlier that sometimes we have to hold meetings or conferences at our desks

Thursday, May 15, 2008

Automated Deployment to OC4J in Maven2

Below are example Maven2 Profiles that will deploy/undeploy a WAR to an OC4J Instance. For information on exactly what each parameter does and everything else about working with the admin_client.jar, consult your Oracle Application Server documentation.

Enjoy!

Thanks to Phillip Anderson for this work.


<!-- The base installation directory of OC4J -->
<oc4j.home>C:\JEE\AppServers\oc4j</oc4j.home>

<!-- The string needed to deploy to an OC4J Instance; This would be different for a standalone oc4j instance -->
<oc4j.deployer>deployer:oc4j:opmn://localhost/home</oc4j.deployer>

<!-- The admin userid for OC4J -->
<oc4j.user>oc4jadmin</oc4j.user>

<!-- The password for the OC4J admin user -->
<oc4j.password>admin</oc4j.password>

<profile>
<id>OC4JDeploy</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>deploy</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<arguments>
<argument>-jar</argument>
<argument>${oc4j.home}\j2ee\home\admin_client.jar</argument>
<argument>${oc4j.deployer}</argument>
<argument>${oc4j.user}</argument>
<argument>${oc4j.password}</argument>
<argument>-deploy</argument>
<argument>-file</argument>
<argument>${basedir}\target\${project.build.finalName}.${project.packaging}</argument>
<argument>-deploymentName</argument>
<argument>myWar</argument>
<argument>-bindAllWebApps</argument>
<argument>secure-web-site</argument>
<argument>-contextRoot</argument>
<argument>myWar</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>OC4JUndeploy</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>deploy</id>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<arguments>
<argument>-jar</argument>
<argument>${oc4j.home}\j2ee\home\admin_client.jar</argument>
<argument>${oc4j.deployer}</argument>
<argument>${oc4j.user}</argument>
<argument>${oc4j.password}</argument>
<argument>-undeploy</argument>
<argument>myWar</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

Wednesday, May 14, 2008

Outgoing SSL Connections in OC4J

The project I'm working on is currently deployed to Oracle Application Server. I spent most of the day yesterday trying to figure out 2 things.

1. Why can't I set the java options javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword in the opmn.xml file w/o the system spewing error messages on startup?

2. How can I get my application to successfully make outgoing HTTPS connections if I can't set those system properties?

I posted a message on the Oracle forms here with no response. I spent hours searching online, only finding documentation on how to secure your deployed applications with SSL.

I ended up finding an off-topic document that revealed the answer. OC4J looks to a default trust store located at ${ORACLE_HOME}/jdk/jre/lib/security/cacerts. So, after adding the certificate I needed to trust into this trust store, all was good.

I knew that java had a default trust store, but my goal was to point OC4J to a trust store of my choice, not edit the system default. I did look for a way to configure OC4J through other means, but no luck. And in this case, my whole goal was to point the system to a trust store of my choice, so I was ok with using the system properties.

It still irks me that I can't set those system properties. Oh well.

Wednesday, May 7, 2008

WAMP Hurdles

If you've read the last 2 of my book reviews, you're probably noticing a trend. I'm attempting to expand my skill set horizontally, starting down the path of what I view as the skill set of a 'classical' web application developer. I've brushed up on the essentials; HTML and CSS. And followed that up with a poor introduction to JavaScript. Now, I'm on my way to the exciting and powerful capabilities of PHP and MySQL.

After some time of reading and coming up to speed on the basics of PHP development, I decided to take a head first dive (no, there's no Head First PHP book) into this and focus on finding tutorials that build (small) applications from start to finish. Unfortunately, just getting my environment set up has been.... predictable.

Yes, I'm on Windows. I know, I know. I could buy a cheap development box, use a VM can, etc. Honestly, I'd rather just tough it out for now and worry about porting to LAMP (that made me laugh) when that bridge comes.

So, my first hurdle...

I downloaded PHP 5.2.5 and MySQL 5.0.51b, arriving at my first roadblock. The instructions I was following simply asked me to uncomment the line "extension=php_mysqli.dll" from my php.ini file; easy enough. Unfortunately, I found error logs reporting that the dynamic library could not be loaded and the specified module could not be found.

Quickly I found some indications online that I needed to grab a new PHP/MySQL connector. Following the provided link to a page on the MySQL site took me to pretty much, the last thing I wanted to see. Yeah, it was asking me to check out source code, overwrite some files, and build it myself. No thanks.

15 minutes of dedicated investigation later, I found a connector (already built) that I could download and replace the dll that came with PHP to work with just a slightly older version of MySQL (5.0.19).

Voila!

Tuesday, May 6, 2008

Review: Head First JavaScript

Head First JavaScript



Summary:

This book teaches the reader the basics of JavaScript and explorers a few use cases and example applications. In some ways, it does resemble the other Head First texts I've read. For example, throughout this book the reader can progressively enhance a couple of example applications with what they're learning in the given chapter. Unfortunately however, the best things about Head First books fail to present themselves here. First off, this book does not keep you involved with the example code that corresponds to what you're learning. The vast majority of the time it is up to you to follow along in the example source code as you work through the book. Secondly, this book is too basic. It does not reach a wide enough audience. Essentially, if you have any type of development background, you'll get bored.


Audience:

Those interested in exploring JavaScript to enhance their web applications (with the exception of those with a development background).


Pros:


  • The reader doesn't have to be a developer to understand the book.

  • The reader gets to see a web site progress using the new skills he/she learns throughout the book.

Cons:

  • It barely scratches the surface of JavaScript.

  • It does not hold up to the reputation of other Head First texts.



Recommendation:

If you're a regular Joe that experiments with some web development here and there, and really really prefers a text book to online tutorials and guides, this book might be for you.

Friday, April 18, 2008

I love you OC4J

Recently our team found out that our deployment environment would use Oracle's OC4J App Server. So, after getting it up and going, I finally started working with it locally; deploying and testing our application.

One of the rest services in our application was returning a 500 response code. To investigate, I navigated to this WAR's application log for a look. I couldn't believe what I found....

The 500 was a result of an everyday NoClassDefFoundError. What blew me away was what OC4J had put in the log. Check it out...


08/04/18 13:41:16.484 10.1.3.1.0 Started
08/04/18 13:41:16.828 safxc-test: 10.1.3.1.0 Started
08/04/18 13:50:43.546 safxc-test: Servlet error
oracle.classloader.util.AnnotatedNoClassDefFoundError:

Missing class: javax.xml.bind.annotation.XmlRootElement

Dependent class: com.sun.ws.rest.impl.streaming.JAXBElementProvider
Loader: safxc-test.web.safxc-test:0.0.0
Code-Source: /C:/JEE/AppServers/oc4j/j2ee/home/applications/safxc-test/safxc-test/WEB-INF/lib/restbeans-impl-R2.jar
Configuration: WEB-INF/lib/ directory in C:\JEE\AppServers\oc4j\j2ee\home\applications\safxc-test\safxc-test\WEB-INF\lib

The missing class is available from the following locations:

1. Code-Source: /C:/JEE/AppServers/oc4j/j2ee/home/applications/safxc/safxc/WEB-INF/lib/jaxb-api-2.0.jar (from WEB-INF/lib/ directory in C:\JEE\AppServers\oc4j\j2ee\home\applications\safxc\safxc\WEB-INF\lib)
This code-source is available in loader safxc.web.safxc:0.0.0.

2. Code-Source: /C:/JEE/AppServers/oc4j/j2ee/home/applications/dashboard/dashboard/WEB-INF/lib/jaxb-api-2.0.jar (from WEB-INF/lib/ directory in C:\JEE\AppServers\oc4j\j2ee\home\applications\dashboard\dashboard\WEB-INF\lib)
This code-source is available in loader dashboard.web.dashboard:0.0.0.

3. Code-Source: /C:/JEE/AppServers/oc4j/j2ee/home/applications/cop/cop/WEB-INF/lib/jaxb-api-2.0.jar (from WEB-INF/lib/ directory in C:\JEE\AppServers\oc4j\j2ee\home\applications\cop\cop\WEB-INF\lib)
This code-source is available in loader cop.web.cop:0.0.0.

4. Code-Source: /C:/JEE/AppServers/oc4j/j2ee/home/applications/resource-discovery-widget-service/resource-discovery-widget-service/WEB-INF/lib/jaxb-api-2.0.jar (from WEB-INF/lib/ directory in C:\JEE\AppServers\oc4j\j2ee\home\applications\resource-discovery-widget-service\resource-discovery-widget-service\WEB-INF\lib)
This code-source is available in loader resource-discovery-widget-service.web.resource-discovery-widget-service:0.0.0.

at .... STACK TRACE WAS HERE ....


That's right! Unreal! In some beautiful, very readable output, it ...

  1. Tells you the exact class that is missing (outside of the stack trace)

  2. Tells you the dependent class

  3. Tells you what artifact contains the dependent class

  4. Tells you where you can go find the missing class !!!!



If I haven't said it already ... this is awesome. I can't wait to see what else is in store for me.

Tuesday, April 15, 2008

Review: Head First HTML with CSS & XHTML

Head First HTML with CSS & XHTML

Topics (pretty obvious):

  • HTML
  • XHTML
  • CSS

Summary:

This book teaches the reader everything he/she needs to know to get up and going with HTML and CSS. Throughout the book you build up a website for a coffee shop. Each chapter improves the site just a little through new things being taught to the reader. You'll learn everything from HTML history to HTML standards; from the most common HTML elements to the box model; from simple CSS rules to complex selectors and visual effects. A reader of this book can go from Zero web development knowledge to the ability to quickly create simple, yet functional web sites.


Audience:

Anyone interested in learning web site development essentials.


Pros:

  • The reader doesn't have to be a developer to understand the book.

  • The reader gets to see a web site progress using the new skills he/she learns throughout the book.

  • As with any Head First book, there is plenty of humor to keep the reader interested.
  • Suggestions on where to go after reading this book. (This is an invaluable part of every Head First book in my opinion)

Cons:     ???

Recommendation:


No matter what your background is, if you're looking to learn the essentials of web development this is the book. And as it goes for every Head First book I've read, you'll be entertained and enjoy the book from cover to cover. If you're looking to get into web development, this book is a must.

What you get for Over-Working your Product Owner


  1. No Roadmap (at least nothing outside of the PO's brain, or not until the week before it gets delivered to your client)

  2. A backlog being prioritized/updated as you walk into/during your backlog selection meeting

  3. Stories that smell of implementation and architecture (why developers aren't good product owners)

  4. Realization after 2-3 sprints that your Scrum Master owns the backlog

  5. An over-worked Scrum Master

Thursday, March 13, 2008

Dynamic Method Calls with Groovy

Thanks to some help from James Lorenzen, Chad Gallemore and Travis Chase, ...

A couple of days ago I found myself iterating through a set of key=value pairs, and for each one calling a setter method on another object. In order to know which setter method to call, I had to examine the key. That's when it hit me... What if I could use the key to generate the setter method to call. Check this out.

I've got a simple bean with 2 member variables: username and password. There are corresponding setter methods: setUsername() and setPassword().


class UserBean {
private String username;
private String password;

void setUsername(String username) {
this.username = username
}

void setPassword(String password) {
this.password = password
}
}

Here I have a HashMap that I want to iterate through. It just so happens the keys in the map entries correspond exactly to the member variables of my simple bean. So, instead of examining each key to decide what setter method to call, I can do this:

import junit.framework.TestCase
public class DynamicMethodBuildingTest extends TestCase {

void testBuildMethodsBasedOnMapKeys() {

def testMap = new HashMap();
testMap.put("username","chad")
testMap.put("password","asdfasdf")

def userbean = new UserBean();

testMap.entrySet().each { entry ->
userbean."$entry.key" = entry.value
}
}
}

At this point I'm not really building the method that is being called. I'm building the property name. So, let's look at actually building a method call.

I've added 2 methods to my UserBean: login() and logoff().

void login() {
println username + " has Logged In"
}

void logoff() {
println username + " has Logged Off"
}

Let's test calling these 2 methods dynamically.

void testExecuteUserAction() {
def userActions = ["login", "logoff"];

def userbean = new UserBean()
userbean.username = "chad"

userActions.each { action ->
userbean."$action"()
}
}

Here's the output:

chad has Logged In
chad has Logged Off

Well, that's all it takes. And if you're asking, "What about a method that takes parameters?"... simply put your parameters inside the parenthesis. It may look something like this:

userbean."$action"(username)


Now I wonder, what would it take to accomplish this in Java?

Wednesday, March 5, 2008

Free Travel to Java Symposium 08

Since travel budgets seem to hinder conference attendance quite often, The Server Side is offering a raffle to win free airfare and hotel for the conference. And before you ask... No, you don't have to register for the conference to enter. Just sign up for the raffle. If you win, then worry about convincing your project manager to pay for the conference itself.

And... it's in Vegas!

Good Luck!

Thursday, February 28, 2008

A small Gotcha using Groovy's StubFor or MockFor

I (literally) just posted about my first experience with Groovy. I forgot to mention one thing that I got hung up on when using the StubFor class (this applies to MockFor as well).

I have a simple utility method that just reads from a file and returns the text. I wrote the following unit test and it looked like this at first.


1. def void testReadFromFile() {
2. def expectedText = "<test>myXml</test>"
3. def fileStub = new StubFor(File)
4. fileStub.demand.text {
5. return expectedText
6. }
7.
8. fileStub.use {
9. def val = FileIO.readFromFile("x.xml")
10. println("val: " + val)
11. assertEquals("Expected Text not Found", expectedText, val)
12. }
13. }


Do you see anything wrong here? Check out line 4. Still think it looks ok? The problem is that there is no method "text". There is however, a method "getText()". That's right. Even though the code I'm testing looks like this

   new File(fileName).text

and works perfectly fine, under the covers the actually method being called is getText(). Running the unit test from above results in the following error:

   junit.framework.AssertionFailedError: No more calls to 'getText' expected at this point. End of demands.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at org.codehaus.groovy.runtime.MetaClassHelper.doConstructorInvoke(MetaClassHelper.java:526)
at groovy.lang.MetaClassImpl.doConstructorInvoke(MetaClassImpl.java:2331)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1227)
at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1157)
...

Line 4 in the unit test above should read like this:


4. fileStub.demand.getText {


So, remember that when using StubFor or MockFor your demands must specify the actual method that will be called.

My First Groovy Experience

For a while now, several people in my office have been diving head first into the Groovy experience (James Lorenzen, Chad Gallemore, Joe Kueser, and Travis Chase). Thanks to these guys, my first Groovy experience went pretty well overall.

I do all of my development in IntelliJ IDEA and with Maven2. So, my first steps were to get the JetGroovy plugin, install Groovy, and get my Maven2 project setup to handle Groovy source. Other than a small hiccup getting the plugin, this all went relatively smoothly.

During this experience, I jumped right in using the StubFor class for some unit testing and XmlSlurper to parse through some XML. Both of these proved extremely easy to use and much better than their alternatives in Java.

So, now to what didn't go well. First, when I'm working on an individual unit or integration test, I just run it in IDEA. When I was writing my first Groovy class (and associated tests), I was having trouble with strange behavior with my unit test. After a short time of extreme confusion, it hit me what was happening. If I didn't make a change to the Groovy class between every test, IDEA would not actually use the class (if that makes any sense). I wasn't seeing any exceptions regarding missing classes, but the code would actually not be run. So, I had to make a change in the unit test class as well as the class under test if I wanted to run the test from IDEA. Fortunately, I confirmed with my coworkers that this problem did not exist in IDEA version 7.0.2 (I was running 7.0). A quick upgrade fixed my problem.

The only other thing I have to complain about is the customization of colors in IDEA for Groovy source. Unlike most, I use a very colorful scheme for development. I happen to be terribly color blind and find it much easier when different things in the code stand out. If you ever get the chance to see my screen, you'll see brown, blue, purple, yellow, red, white, grey, and shades of several of those. So, unfortunately for me, there's not quite as much customization available for Groovy source. Oh well. I'm sure I'll live.

At the end of the day, it was a good experience and gladly I'll continue use Groovy where it makes sense.

Wednesday, February 27, 2008

A couple more Maven2 Plugins

Last week I wrote about using the Maven Build Helper Plugin and just started wandering how many other plugins were out there that could be very useful for me, but that I had not yet discovered. So, after a little searching, I found two other plugins that I really wish I would have known about before this. Note however that I have not tried using them to verify their capabilities.


Maven 2 License Plugin

I really, really could have used in the past. I work on about 5 Open Source projects on Java.Net. Most of those started out being built internally. So right before that initial commit you've got to insert a header in every single file. Additionally, I work on DoD contracts and when we deliver code at the end of each quarter, it must include a Government Purpose Rights header. Yes, that includes replacing the open source headers with the GPR headers.

Anyway, I'll list the features of the plugin so you can decide if you want to go check out the project site here.

  • Check: check if header is missing in some source file
  • Reformat: add headers if missing
  • Custom mappings: enables easy support of new file extensions
  • Variable replacement: You can add some variable in your header, such as ${year}, ${owner} and they will be replaced by the corresponding values taken from the pom or system properties.


JMeter Maven Plugin

I'm not using JMeter on my current project, but I have used it on several previous projects. And, there's nothing better than being able to automate a testing process into your build. That's right, this plugin will run your JMeter tests during your build. Unfortunately, it seems like there may be a lack of documentation. However, I've located one additional resource that even includes report generation in it's example of how to use this plugin.

Check out the plugin's site here.

Enjoy!

Thursday, February 21, 2008

Maven2, Multiple Source Directories, and the Build Helper Plugin

I'm currently working on a project dealing a lot with Web Services. I'm using the CXF Codegen Plugin to generate Java classes from an existing WSDL. However, I need to write a few classes of my own to create a common client interface and a mock implementation in addition to the code generated by CXF.

My dilemma is that Maven2 supports only using a single <sourceDirectory> in the pom. I don't want to use a single source directory because of cluttering my code with the generated source or vice versa. I'd rather not use two separate modules because ... well, I don't want 2 different artifacts exposing virtually the same capabilities.

So, after a few Google searches, I found the Build Helper Maven Plugin.

This plugin allows you to add additional source directories to your module. See my example below. I'm adding the directory of my generated source files, ${basedir}/target/generated/src/main/java (in addition to the default source directory ${basedir}/src/main/java).


<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated/src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.0.2-incubator</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<!-- This is where the generated source files will be placed -->
<sourceRoot>${basedir}/target/generated/src/main/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/wsdl/my.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

Monday, February 18, 2008

To Dig or Not To Dig

Around the beginning of the year, I thought about writing a post about what I wanted to accomplish this year when it comes to this industry and my career. Basically, a professional New Year's resolution list. I never got around to coming up with an official list; however, there's been one item on my mind quite a bit that is my #1 'resolution'.

It's quite often with my personal- and work-related projects that I have the chance to do something I haven't done before. For example, work with a new open source framework, use a technology for the first time, or play with language I haven't yet touched. There have been some occasions where several weeks/months later I've said to my self, "I should have taken just a little more time to explore that in more detail; dig a little deeper".

My #1 resolution is that whenever I get the opportunity to work on something new, I will take a step back and ask myself, "Is this something I should dig deeper on, or is just touching the surface enough?"

Let me give you an example. I am currently working on an IntelliJ IDEA plug-in during some of my spare time. Part of that process has introduced me to Swing development. I haven't once touched Swing or the java.awt package before this. So, needless to say, I'm learning quite a bit. I get to have fun with things like trying to get components to be certain sizes and figuring out how to enable drag and drop. This is the point I need to stop and ask myself the question, "how far do I want to go?" My point is that I need to figure out, do I simply find answers to my questions so that I can get by creating this plug-in? Or, do I spend some time learning more about many aspects of Swing development; something that will last me much longer than this single engagement.

In this case, I chose (for now) to simply find out the answers to my questions so that I can build the plug-in. I'm doing no other Swing development. Not on other personal projects. Not on any work assignments. Nor do I see myself doing any other Swing development in the near future.

With this resolution, I'm trying to keep those moments of "I should have dug deeper" to an absolute minimum. Maybe for you this is just a common sense example of thinking before you act, but for myself (unfortunately), there have been times I should have done more research to gain a solid understanding vs. just enough to produce what I want. Hopefully at the end of this year I can look back and know that put the right amount of effort into learning new things.

Wednesday, February 6, 2008

Review: Head First Design Patterns

Head First Design Patterns


Topics:
  • Design Principles
  • Design Patterns
  • OOP

Summary:

This books teaches the reader about basic concepts behind several common design principles and patterns. Most chapters begin by creating a scenario that involves a development team being given a task to add functionality to an application. It then walks the reader through implementation options by showing example code in Java, while pointing out pros and cons. This ends up identifying a design principle and showing how a specific design pattern can be applied to the problem at hand. The last couple of chapters transition the reader from working with simple, ideal situations to real world expectations of working with design patterns.


Audience:

Any level developer who has a grasp of OOP and is looking to improve their development skills through design principles and patterns.


Pros:
  • Perfect for an introduction to design patterns and principles (and more advanced literature, e.g. GoF text).
  • Examples do an excellent job of showing the benefits of applied principles and patterns.
  • Plenty of humor to keep the reader interested.
  • Suggestions on where to go after reading this book.

Cons:
  • Goes off-topic to explain details of how RMI works during its discussion of the Proxy pattern, a waste of 10-20 pages.
  • While additional patterns are briefly covered in an appendix, I'd like to see a few of those included in chapters of their own.

Recommendation:


If you've got a grasp on OO concepts, but don't really know much about design patterns, this is the perfect place to start. This book is easy to read and does an excellent job of not just explaining the concepts, but proving them with examples as well.

Wednesday, January 30, 2008

BT in Software Engineering

Many people have the opinion that Computer Science graduates are not being well prepared for the road ahead, and I completely agree. I don't want to repeat any of the arguments or my personal take on the exact problems with today's curriculum, but I do want to broadcast an idea of where the solution needs to come from.

I think we need to separate Technology from Science and the Arts. I want my (future) son to go to a 4-year University and get a Bachelor of Technology. Science relates to facts, theories, and formulas. Arts relates to creativity, culture, and individualism. Neither of these describes technology related fields, and coming to that realization is what we need.

We've seen the beginning of it. New buildings on campus to house computer science and other engineering programs. The equipment that students interact with has changed. But did the way we teach change?

Our world isn't built on formulas, theories, and laws like the traditional science programs. Our world is built on best practices, innovation, collaboration, adaptability, and abstract concepts. You can't learn best practices from a book. You don't experience innovation through canned programming assignments. Collaboration isn't taught by sitting in a classroom with 50 other students, staring at a projector screen. The world has evolved and so should our teaching methods.

AgileTeams: What does it take to be Great?

It can take some time, but with the right guidance, an agile team can become good and solid relatively quickly. It depends on many things like how much experience each individual has working on an agile team to the meshing of the best practices each has picked up along the way. However, taking the team to the next level can be difficult. In my experience, the items I've listed below can take a good agile team and turn it into a great agile team. At a glance, they don't seem like anything difficult, yet for some reason I've seen teams struggle with these items over and over. However, when a team does reach that point where all these items are coming naturally, you see a big difference in productivity, efficiency, communication, and sense of ownership. Let me know what you think.

1. Use of the Project Tracking Tool


Whether you're using ScrumWorks, XPLanner, note cards, or another project tracking tool, here are a few things I've picked up that seem to really make a difference.


1) Lump Sum Tasks

Sometimes when you come out of backlog selection, you've got a thorough understanding of what it takes to complete a story, and sometimes you don't. If you're not quite ready to break the tasks down completely, just enter a lump sum task. As you identify individual tasks, remove hours from the lump sum and place them in your new task. The goal here is to eliminate surprises. You don't want your team thinking that you're almost done with a story, and then for the next 2 weeks you just continue to add new tasks out of the blue.

2) Overhead
Don't make the mistake of thinking your project tracking tool was only built to track user stories. By leaving out overhead tasks that are going to take up your time, you're depriving the team of having a true understanding of what needs done. For example, say your team has the responsibility of managing a small open source project. When a support request comes in from the community, identify it in your project tracking tool. You don't want to hide the fact it's something that needs done.

3) Enforce Updating
This is a big one. As easy as it is to update your project tracking tool each day, it seems just as easy to forget. This one is easy to address though. Just show your project tracking tool during the daily stand-up. When people give their reports, they should point out the exact tasks they're reporting against. It becomes very apparent when the tool isn't being updated as it should be. You get someone saying they've completed a task, but for some reason it isn't shown as completed in the tool.

The point here is to maintain high visibility into the current progress of the sprint and its individual stories and tasks.



2. Accountability


An Example:
I report Monday that I'm going to commit to finishing tasks ABC and DEF, each taking approximately 4 hours. Tuesday I give a report that I completed task ABC and that I'm going to commit to finishing task DEF today.

This should immediately throw up a red flag for you. 8 hours of work just turned into 16 hours of work and everyone should be asking why. What are some scenarios as to why this is now going to take me twice as long as I reported out yesterday?

1) Task ABC did only take 4 hours, but I'm really stuck on task DEF.
In this case, I'm saying that I think task DEF will take me 3x as long as I originally thought. That's quite an increase in hours. If this situation was exposed in the daily stand-up, the team could make the decision as to whether or not I should get some help instead of trying to tackle it on my own.


2) Task ABC ended up taking me 8 hours, and I think the same will happen with DEF.

This is a signal that I'm consistently underestimating the time it will take me to complete a task (or at least tasks of this nature). Someone should point this out to me and encourage me to analyze the situation so that I may be able to improve my accuracy in estimation.

3) I've had something come up and was in meetings half the day Monday. The same will happen again Tuesday.
Apparently I didn't think it was a big deal that this work would take 2 days instead of one. Maybe however, one of my other team members was expecting me to be available this afternoon and needed my help. In this case I failed to report an impediment that showed up and kept me from completing these 2 tasks on schedule. In addition, I didn't relay to the team that I would be unavailable this afternoon.

4) I felt like playing Solitaire for half the day and only got around to working on task ABC.
In this case, you've got to expose me as a slacker. I'm holding back the team by only giving about 50% effort. The team could do much better with another resource in my place (read this).



3. Sprint Retrospective


The sprint retrospective, in my opinion, is one of the most overlooked tools for improving team performance. Having the opportunity to sit down and reflect on the previous sprint(s) is priceless. However, it's not good enough just to identify what went well, what didn't go well, and areas for improvement. You MUST act on your findings.

If you've seen concerns or areas for improvement come up over and over again in your retros, someone should be waving giant red flags all over the place. It's THE signal that you're not making the most of your retro. It is crucial that your team takes the initiative to act on the items you've identified. This doesn't mean just saying, "Lets all try to work on {areaOfImprovement} this sprint." Put in the extra effort and track these items. This could be done in your project tracking tool, or maybe by revisiting your action items at a certain interval throughout the sprint.

Wednesday, January 23, 2008

Trust All Certificates

Need to establish an Https connection and don't care about validating the server's unsigned certificate? Don't want to mess with importing the server's certificate into a local keystore? This won't show you how to ignore those SSLHandshakeExceptions due to unsigned certs, but it will show you how to get rid of them all together!

Step 1:


Implement the X509TrustManager Interface as follows.

public class TrustEverythingTrustManager implements X509TrustManager {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { }

public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { }
}


Step 2:


Implement the HostnameVerifier Interface as follows.

public class VerifyEverythingHostnameVerifier implements HostnameVerifier {

public boolean verify(String string, SSLSession sslSession) {
return true;
}
}


Step 3:


Initialize an SSLContext with your TrustEverythingTrustManager and set the context as the default SSL socket factory on the HttpsURLConnection class.

TrustManager[] trustManager = new TrustManager[] {new TrustEverythingTrustManager()};

// Let us create the factory where we can set some parameters for the connection
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new java.security.SecureRandom());
} catch (NoSuchAlgorithmException e) {
// do nothing
}catch (KeyManagementException e) {
// do nothing
}

HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());


Step 4:


Open the connection and set your VerifyEverythingHostnameVerifier as the HostnameVerifier.

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new VerifyEverythingHostnameVerifier());



Thats it. Done and Done!