jueves, marzo 11, 2010

... Volver, con la frente marchita, las nieves del tiempo platearon mi sien...



Today I am going to talk about building and adding a simple addon to Spring-Roo. I will not talk about what is Roo or about their benefits.

Roo is built on an add-on architecture that enables different types of Java applications to be built. For this reason is so important to know how to build new addons for Spring-Roo.

Our addon:

First of all install Spring-Roo. After correctly installed (see Spring Roo documentation).

After installed, create a new directory called listfiles-addon.

Enter into directory and start roo.

Then type into roo console project --topLevelPackage com.test.roo.addon --template ROO_ADDON_SIMPLE

This sequence will create a project for creating a simple addon, with all required classes.

Let's examine what have created and how a modification will be applied for creating our addon.

In directory src/main/resources/META-INF/spring two files are present, log4j.properties and applicationContext.xml. applicationContext file is a Spring configuration file that configure Spring for work with annotations (@Configurable, @Component, ....).

First class to take a look:


src/main/java/com/test/roo/addon/PropertyName.java

This class represents attributes of options of our command. For example, logger addon, the command is logging setup and then --level is the option, and that option has many attributes (FATAL, ERROR ...), these attributes are what are defined in this class. Must implements Comparable.

Let's take a look of important points:

private String propertyName; [1]

public static final PropertyName USERNAME = new PropertyName("Username"); [2]
public static final PropertyName HOME_DIRECTORY = new PropertyName("Home Directory");

private PropertyName(String propertyName) { [3]
Assert.hasText(propertyName, "Property name required");
this.propertyName = propertyName;
}

public String getPropertyName() {
return propertyName;
}

public final boolean equals(Object obj) {
return obj != null && obj instanceof PropertyName && this.compareTo((PropertyName) obj) == 0;
}

public final int compareTo(PropertyName o) { [4]
if (o == null)
return -1;
int result = this.propertyName.compareTo(o.propertyName);

return result;
}

public final String getKey() { [5]
return this.propertyName;
}


[1]: Property name. This value will be used in our Command class, for now, imagine as a key that is unique.
[2]: A list of public static final attributes must be defined. Their type must be the same of class we are implementing, and their name will be used for autocompletation. In case of logger addon (FATAL, ERROR, INFO, ...).
[3]: Good practice to generate constructor as private in this kind of classes.
[4]: Class must implements compareTo. Because our key (propertyName) is unique, this attribute is used, and as usually equals is also implemented using compareTo.
[5]: Method that must returns the key (propertyName). Must be called getKey()

Next important class:

src/main/java/com/test/roo/addon/Commands.java

This class represents the command, and what options accept. This class must implement CommandMarker.

Let's take a look of important points:

@ScopeDevelopmentShell [1]
public class Commands implements CommandMarker {

private static Logger logger = Logger.getLogger(Commands.class.getName());

private Operations operations; [2]

public Commands(StaticFieldConverter staticFieldConverter, Operations operations) { [3]
Assert.notNull(staticFieldConverter, "Static field converter required");
Assert.notNull(operations, "Operations object required");
staticFieldConverter.add(PropertyName.class);
this.operations = operations;
logger.warning("Loaded " + Commands.class.getName() + "; try the 'welcome' commands");
}

@CliAvailabilityIndicator("welcome property") [4]
public boolean isPropertyAvailable() {
return true; // it's safe to always see the properties we expose
}

@CliCommand(value="welcome property", help="Obtains a pre-defined system property") [5]
public String property(@CliOption(key="name", mandatory=false, specifiedDefaultValue="USERNAME", unspecifiedDefaultValue="USERNAME", help="The property name you'd like to display") PropertyName propertyName) [6] {
return operations.getProperty(propertyName); [7]
}

....


[1]: Annotation for registering Command with automatic classpath scan.
[2]: Can be called the Business Object of our Command object. Contains logic of command, options and attributes.
[3]: Constructor, with two arguments, first of all StaticFieldConverter, which will be used for registering our previous, attributes class. (PropertyName.class). The second one is the business object class.
[4]: Annotates a method that can indicate whether a particular command is presently available or not. The string represents the name of the command or commands that this availability indicator represents.
[5]: Annotates a method indicating which method must be called when the command have to execute. value attribute is the name of the command (what user must enter), in case of logging is logging setup, and help attribute that shows the message when help is required.
[6]: Each option is annotated with CliOption. This method can contain as many CliOption annotations as required. Of all annotation attributes, one is so important, key. The attribute value must be the same as returned in getKey() function of PropertyName.class. Another important thing, look the METHOD attribute, it is our attribute class defined before. Spring Roo will inject the static final instance chosen by user.
[7]: Calling business object.

Last important class is:

src/main/java/com/test/roo/addon/Operations.java

This plain annotated class, is responsible of implementing command logic. Because of annotation, spring-roo can use constructor inject for providing some specific type instances. Those classes can be FileManager, PathResolver, MetadataService, ProjectOperations, ... Zero or more of these classes can be used in constructor. Let's take generated class as example:

@ScopeDevelopment [1]
public class Operations {

private static Logger logger = Logger.getLogger(Operations.class.getName());

private FileManager fileManager;
private MetadataService metadataService;

public Operations(FileManager fileManager, MetadataService metadataService) { [2]
Assert.notNull(fileManager, "File manager required");
Assert.notNull(metadataService, "Metadata service required");
this.fileManager = fileManager;
this.metadataService = metadataService;
}

public String getProperty(PropertyName propertyName) { [3]
Assert.notNull(propertyName, "Property name required");
String internalName = "user.name";
if (PropertyName.HOME_DIRECTORY.equals(propertyName)) {
internalName = "user.home";
}
return propertyName.getPropertyName() + " : " + System.getProperty(internalName);
}


[1]: Annotation used by Spring-Roo.
[2]: Constructor only using two spring-roo classes. FileManager and MetadataService, both of them will be injected by spring-roo.
[3]: Business Method called by Command class.

Another example could be LoggingOperations. That's the class used by logging addon.

LoggingOperations(FileManager fileManager, PathResolver pathResolver, MetadataService metadataService) where other class rather than used in our exmaple, is passed, PathResolver.

Now I am going to explain what is the purpose of most used injected classes in Operations class.

- FileManager, used for modifying the underlying disk storage. Can be used for scanning directories, create files, directories, delete, ...
- PathResolver, is primary mechanism to resolve paths.
- MetadataService is used for returnig metadata information. Usually used as
ProjectMetadata projectMetadata = (ProjectMetadata) metadataService.get(ProjectMetadata.getProjectIdentifier());
and ProjectMetadata offers convenience methods for acquiring the project name, top level project package name, registered dependencies and path name resolution services.
- ProjectOperations provides common project operations, such as adding dependencies, update project type, ...

And as an overview, that's all. Finally perform assembly command is executed and we have our addon ready.

Final step move generated jar to $ROO_HOME/dist and restart roo.

In next entries I will write how to modify applicationContext, generate specific files, ITD, …

martes, marzo 09, 2010

QR

Today I have found one really useful link for generating QR codes from any text. The link is http://invx.com/. If you look closely you will find a "REST" url for generating QR files from your application. Link is http://invx.com/code/?code=YOUR+TEXT in UTF-8.

jueves, marzo 04, 2010

.. she spends her last dollar for a bottle of vodka for tonight ...



Drink a Mojito and leave EasyMock. In some conferences I have been recently, I have discovered that most people in unitary tests, use EasyMock for stubbing and mocking. And I am wondering, why? Mockito offers, from my point of view, the same features that EasyMock, but better readability and simplified.

Take a look of next example:

In EasyMock:


import static org.easymock.classextension.EasyMock.*;

List mock = createNiceMock(List.class);

expect(mock.get(0)).andStubReturn("one");
expect(mock.get(1)).andStubReturn("two");
mock.clear();

replay(mock);
someCodeThatInteractsWithMock();

verify(mock);


And with Mockito the same code:


import static org.mockito.Mockito.*;

List mock = mock(List.class);

when(mock.get(0)).thenReturn("one");
when(mock.get(1)).thenReturn("two");

someCodeThatInteractsWithMock();

verify(mock).clear();


In http://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/Mockito.html anyone can see Mockito documentation and tutorial, but what I am going to explain is how Mockito help me writing better tests.

First of all, I use Mockito for stubbing classes (Business Objects). In always use Design By Interfaces approach. This approach in conjunction with Spring Framework (IoC), makes my software so modular and reusable, and as you will see soon, testable too.

Imagine we are creating a piece of software that uploads an image in FTP server. We would have an interface called FTPService with a method called int upload(String serverDirectoryPath, String filenamePath) throws NotEnoughSpaceException.

This method would upload a file to given server directory, returning the number of written bytes, and if server is full, NotEnoughSpaceException is thrown; and its implementation called FTPServiceImpl.

Moreover we would have a business object, which will act as a controller of all procedures related with uploading a file (check if uploading file exists, establishing connection, closing connection ...). This class would have a FTPService setter for injecting the implementation (in our case FTPServiceImpl).

Ok, we have got the scenario, now we start playing with Mockito.

As you can see, first problem for testing our business object is that we require a ftp server and/or network connection, but, wait, we are writing unit tests, not integration tests, so a strategy for testing controller without a server is required. And here comes stubbing and Mockito. A stub may simulate the behavior of existing code (such as a procedure on a remote machine) or be a temporary substitute for yet-to-be-developed code. And creating a stub with mockito is as simple as:

(test class)

import static org.mockito.Mockito.*;

....

ControllerBOImpl controller = new ControllerBOImpl();

//Create Mock
FTPService mockedFtp = mock(FTPService.class);

//stubbing. When upload method with "serverPath" as first argument and "filePath" as
//second argument, 1234 integer will be returned.

when(mockedFtp.upload("serverPath", "filePath")).thenReturn(1234);

//inject mock to ControllerBO
controller.setFTPService(mockedFtp);

//Now we can start testing ControllerBOImpl as a FTP Server was present.
int writtenBytes = controller.uploadFile("serverPath", "filePath");
....


Of course more steps would be required in previous example like stubbing more methods of FTPService or writing asserts for ControllerBOImpl. But I think that would be information that distracts reader from what is really important. Stubbing with Mockito is so easy.

As you have noted, when you stub something that has attributes, you must provide hardcoded values, and that values must be used in method calling. It is not the same calls controller.uploadFile("serverPath", "filePath") than controller.uploadFile("directory",”filePath") because attribute values are different.

To avoid that, hamcrest http://code.google.com/p/hamcrest/ appear on screen.


Second reason why I use Mockito. I can also use Hamcrest. Following previous example would not use the expression:

when(mockedFtp.upload("serverPath", "filePath")).thenReturn(1234);

but:

when(mockedFtp.upload(anyString(), anyString())).thenReturn(1234);


More flexible solution, any string will act in the same way. See http://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/Mockito.html#3 for more examples about argument matchers.

Third reason. I can mock for returning exceptions.

Previous example throws an exception when hard disk becomes full. But how can I test that!!! If I can't upload a file that its size must be 500Gb or more!!!.

No problem with Mockito, I write down another test, but changing one line:

from

when(mockedFtp.upload(anyString(), anyString())).thenReturn(1234);

to

when(mockedFtp.upload(anyString(), anyString())).thenThrow(new NotEnoughSpaceException());


Easy to test that complicated and rare situation.

Fourth Reason. Mockito allow stubbing void methods.

Stubbing voids requires different approach from when(Object) because the compiler does not like void methods inside brackets.

There are four possible solutions, but I only use two of them. doThrow(Throwable) when I want to test a void method throwing an exception, and doNothing() [default behavior], when no interaction is required.

FTPService would also have a method for connecting to server, maybe called connect()throws IOException() and would throw an exception when could not establish a connection.

Two tests are required for testing that these functionalities:

First Test:

doNothing().when(mockedFtp).connect();

And Second one:

doThrow(new IOException()).when(mockedFtp).connect();


And finally, and this reason applies only people who write tests using BDD approach. In summary, means write test with follow structure, //given //when //then comments as fundamental parts of test methods.

Remember that Mockito uses when method for “record” behavior? Well, in BDD approach, when paragraph is used for calling the business method. Note that when does not fit nicely into BDD, because given paragraph is what is called when in Mockito. For that reason Mockito provides a BDDmockito class. This class changes when method name for given method name. Thanks of that, our test is more readable and follows BDD standard.

So my test in BDD would look like:

import static org.mockito.BDDMockito.*;

…..
ControllerBOImpl controller = new ControllerBOImpl();

//Create Mock
FTPService mockedFtp = mock(FTPService.class);
//Given
given(mockedFtp.upload(anyString(), anyString())).willReturn(1234);

//When
int size = controller.uploadFile("serverPath", "filePath");

//Then
assertEquals(1234, size);



And these are the four reasons why I am using Mockito, in summary because it is simpler than EasyMock, more readable and easy to use.

Donate If You Can and Find Post Useful