Friday, November 16, 2007

At No Fluff Just Stuff Chicago

Arrived at NFJS Chicago today and promptly jumped into the afternoon sessions. I'll be trying to post information I'm finding interesting as I come across it and I've already put up two posts. Where? Well - on the new Coding blog I started in my iWeb site. The first post is on Enterprise Performance & Scalability. The second is on Domain Driven Design and how to build the ubiquitous language in your team.

Still need to blog about monitoring your applications, but that will come tomorrow, I'm afraid.

Enjoy!

Wednesday, October 31, 2007

IP Aliasing on Leopard

I just added a new blog in my iWeb site on tips/tricks I use to be productive. The first post is about IP Aliasing on Leopard, something I am using to run multiple instances of JBoss AS. This makes a nice environment to test the Web Services Transactions (XTS) module from JBoss Transactions (JBossTS).

Saturday, October 27, 2007

Eclipse on Leopard: fine. 64-bit? Not so fine.

I know I'm a late adopter and all, but I thought I'd provide some information on Eclipse on OS X Leopard. First off: it runs fine. Many of the concerns were that 64-bit Java would break Eclipse because of the SWT/Carbon underpinnings, which are 32-bit, as I understand it.

Well, rest easy - as it does with many new technologies, Apple has left full backwards compatibility in place. It appears that Java runs in 32-bit mode by default, so basically everything that worked previously (including SWT) will continue to work.

So what about Eclipse on 64-bit Java? Yeah, it doesn't work. So - to all those that predicted this, kudos. You got it right. Adding "-d64" is the flag that tells the JVM to run in 64-bit mode - and adding this to eclipse.ini "-vmargs" causes an exception when SWT is loaded.

Want to test if you can run 64-bit Java? Here's what to do. In Terminal, run the following command:



/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java -d64 -Xmx2560M -version

Running this should output something like so:



java version "1.5.0_13"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05-237)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_13-119, mixed mode)

If you don't get this, or get some type of message like "Cannot run Java in 64 bit mode. Continuing in 32 bit mode." then you may not have a 64-bit chipset. Notably, the PPC chips (while G5s are 64-bit) cannot run 64-bit Java). Further, the first generation of Intel chips released by Apple, Duo Core, are not 64-bit. Only the Core 2 Duo (and later) chips are 64-bit. Finally - if you ran the "-d64" test by just specifying "java" on the command line, instead of the full path - you may be running into a bug that was discovered too late to be fixed in GM.

I'll give a shot at running 64-bit Java from within Eclipse (say, to run JBoss AS - that should work). I'll report back with results!

Sunday, October 21, 2007

Locavore in training.

To document and track my ongoing efforts to become more of a Locavore with my family, I have started a new blog on my new iWeb site. I have a few things up there already (and am liking how easy it is to layout photos in iWeb, sweet!). I hope to keep things up-to-date, though this Locavore family might run into harder straights with winter coming on and the harvest nearing completion.

Though that in itself should provide ample material to blog about! Enjoy.

New blog!

I have started a new blog, mostly to evaluate the iWeb '08 software that's part of the iLife '08 suite from Apple. As part of my "Site" in iWeb, this blog will focus on thoughts and insights I have in the field of requirements engineering (RE). While most of my day-to-day activities don't focus 100% on this field, in my current position, I do deal with this on an ongoing basis, helping the business better communicate their needs, formulate what features the software should provide, and if needed, expand on those features in use case specifications.

Anyway, topics related to RE will be the focus of this new iWeb blog. Enjoy!


Monday, September 24, 2007

EasyMock testing: isolating methods with partial mocks

Today I was faced with testing a method that presented two difficulties. First, the method under test was overriding a superclass method and invoking the superclass' same-named method. Second, the method needed to invoke an unavoidable static method on a utility class. I managed to work around both difficulties with essentially the same approach, instead of invoking the difficult to mock methods directly (super.whatever() and Utility.staticMethod()), delegate to a helper method, which can then be mocked with a partial mock.

Here are the details.

The method under test overrides getAction(ActionContext context, String type, ActionConfig actionConfig).

    @Override
protected synchronized Action getAction(ActionContext context, String type, ActionConfig actionConfig) throws Exception { // NOPMD
Action action = super.getAction(context, type, actionConfig);
Class actionClass = action.getClass();
Method[] methods = actionClass.getMethods();

/*
* Determine if methods exist that need to be injected with
* beans from the ApplicationContext.
*/
for (Method method : methods) {
if (method.isAnnotationPresent(InjectBean.class)) {
InjectingCreateAction.LOG.info("Found annotation on: " + actionClass.getName());
Class< ? > clazz = method.getParameterTypes()[0];
Object bean = ApplicationContextUtils.getBean(clazz);
method.invoke(action, new Object[] { bean }); // NOPMD
}
}
return action;
}

The two methods presenting some difficulties are highlighted in yellow. A straightforward EasyMock test of this method would fail on these two methods, unless they were run in an environment where these methods could successfully execute. Since the class extends Struts' CreateAction to inject dependencies on Action classes, calling super.getAction() would require all the necessary Struts pieces to be in place when this unit test runs. That's more than we need to test this functionality.

Using EasyMock's class extension 2.2.2+, we can create a partial mock of the class under test, and use this with some simple refactoring to isolate this method to make it testable.

    @Override
protected synchronized Action getAction(ActionContext context, String type, ActionConfig actionConfig) throws Exception { // NOPMD
Action action = getActionObject(context, type, actionConfig);
Class actionClass = action.getClass();
Method[] methods = actionClass.getMethods();

/*
* Determine if methods exist that need to be injected with
* beans from the ApplicationContext.
*/
for (Method method : methods) {
if (method.isAnnotationPresent(InjectBean.class)) {
InjectingCreateAction.LOG.info("Found annotation on: " + actionClass.getName());
Class< ? > clazz = method.getParameterTypes()[0];
Object bean = getBean(clazz);
method.invoke(action, new Object[] { bean }); // NOPMD
}
}

return action;
}

/**
* Delegate method to allow for mock testing of getAction method, which would
* otherwise call a static method on {@link ApplicationContextUtils}.
* @param <T> the class of the return object (inferred)
* @param clazz the class of the requested object (explicit)
* @return an object from the ApplicationContext matching clazz
*/
public <T> T getBean(Class<T> clazz) {
return ApplicationContextUtils.getBean(clazz);
}

/**
* Delegate method to allow for mock testing of getAction method which overrides
* {@link CreateAction#getAction(ActionContext, String, ActionConfig)}.
* @param context ActionContext
* @param type String
* @param actionConfig ActionConfig
* @return The configured Action object
* @throws Exception pass-through
*/
public Action getActionObject(ActionContext context, String type, ActionConfig actionConfig) throws Exception { // NOPMD
return super.getAction(context, type, actionConfig);
}

We have created two delegate methods to do the dirty work of invoking the static method and calling the super class method. Here's how we put that to use with a partial mock.

    public void testGetAction() throws Exception {
InjectingCreateAction partialMock =
EasyMock.createMock(InjectingCreateAction.class,
new Method[] {
InjectingCreateAction.class.getMethod("getActionObject",
ActionContext.class,
String.class,
ActionConfig.class),
InjectingCreateAction.class.getMethod("getBean",
Class.class),

});

IWorkflowController bean = EasyMock.createMock(IWorkflowController.class);
SmokeTestAction test = new SmokeTestAction();
EasyMock.expect(partialMock.getActionObject(
(ActionContext) EasyMock.anyObject(),
(String) EasyMock.anyObject(),
(ActionConfig) EasyMock.anyObject())).andReturn(test);
EasyMock.expect(partialMock.getBean(IWorkflowController.class))
.andReturn(bean);

test.setWfService(bean);

EasyMock.replay(partialMock);
EasyMock.replay(bean);

Action action = partialMock.getAction(null, null, null);
assertNotNull(action);
EasyMock.verify(partialMock);
}

Creating the EasyMock with an array of Methods tells EasyMock to only mock these methods, not the entire class. The remaining calls are passed through to the underlying class. The remainder of the test is standard EasyMock stuff.

Thursday, September 06, 2007

ZopeEditManager, Safari, automation

Since Safari 3 debuted, I have been using Safari in lieu of Firefox, more and more. One feature I've missed is Firefox' ability to associate the ExternalEdit files from Plone with the ZopeEditManager. Click on the pencil, and voila, you're editing locally.



Well, I've finally figured out what to do to get this linked up in Safari. Enter Automator.



And if you're a Mac user like myself, it won't come as a surprise that it was actually quite easy.
  1. Launch Automator. You'll see a couple panes on the left (drag-src) and a pane on the right (drag-target).
  2. Your first workflow step will be Find Finder Items (the search box, top left, is a convenient way to find the workflow steps). 
  3. Select the folder where Safari will drop the .zem files (Desktop, in my case)
  4. Select "Name", "Ends with", and ".zem" for the criteria.
  5. Add the final criteria (yep, already on the last one!) - Open Finder Items.

     
  6. Nothing to configure on this workflow step, the default "Open with: Default Application" suits us just fine (note: if ZopeEditManager isn't associated with .zem files on your system, select ZopeEditManager in this drop-down).
  7. Almost done. Save your workflow as a "Folder Action" plugin. File ~ Save As Plug-in...

    Attached to Folder: should be the folder you selected in your first workflow step.
  8. Ctrl-click (i.e. right-click) on the folder you're targeting, select "Enable Folder Actions" if this is the first time you're using , Folder Actions on your system.
  9. Ctrl-click on the folder you're targeting, select Configure Folder Actions ...
  10. Click the "+" for the left pane, select your folder (e.g. Desktop)
  11. Click the "+" for the right pane, select your Automator workflow
  12. Close Folder Actions Setup, you're done!
Test it out by clicking an ExternalEdit link from Safari, should work like a charm.

Enjoy!