Monday, June 3, 2013

GoF patterns: Strategy

Definition: This pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable at runtime. This pattern is used when you have some logic and you want it to vary independently of the client who uses it while still having an extensible model.



Why encapsulated? Because each algorithm exists in a different class and access all that logic with a method. Why Interchangeable? Because each of those classes implement the same interface.

Say for example, I have a service for buying tickets and I want the service to provide discounts depending on the age of the person. I want to have 2 kind of discounts, but I am sure there will be a lot more in the future. Instead of having an IF statement (and have a whole bunch of nested IF statements in the future), in the whole process of buying a ticket, the strategy will be implemented in the calculus of the discount. Why? Because the result of the calculus is the same (a new price on the ticket) but the way it works is different from each other. As we said, today we just have 2 different calcs of the discount but tomorrow we may have a lot more:



TicketService
public class TicketService {
 
 private DiscountStrategy discountProcess;
 
 public double buyTicket(Client client) {
  double generalTicketPrice = 50;
  double realTicketPrice = discountProcess.calculateDiscount(generalTicketPrice);
  return realTicketPrice;
 }

}

These are the different strategies we have:

HighDiscountStrategy
public class HighDiscountStrategy implements DiscountStrategy {

 @Override
 public double calculateDiscount(double ticketPrice) {
  return ticketPrice - 30;
 }

}

LowDiscountStrategy
public class LowDiscountStrategy implements DiscountStrategy {

 @Override
 public double calculateDiscount(double ticketPrice) {
  return ticketPrice - 10;
 }

}

As you can see, our buyTicket method doesn't care about which type of discount it is applying.

Now, the question is, when do we set the type of discount? Maybe in the service constructor?
But, what if we just want one service class to be instantiated and use that same instance with every client that arrives? Well, that really depends on the problem to be solved, the Strategy pattern doesn't tell you when and how to set the discount type... In this case, I chose to create a new service for each client. So, passing the client in the constructor is enough.

So, our class will be like this with the constructor:

TicketService
public class TicketService {
 
 private DiscountStrategy discountProcess;
 
 public TicketService(Client client) {
  if (client.getAge() >= 18) {
   discountProcess = new LowDiscountStrategy();
  } else {
   discountProcess = new HighDiscountStrategy();
  }
 }
 
 public double buyTicket(Client client) {
  double generalTicketPrice = 50;
  double realTicketPrice = discountProcess.calculateDiscount(generalTicketPrice);
  return realTicketPrice;
 }

}

And an invocation example:

//A new Client is created
  Client kid = new Client();
  kid.setAge(16);
  
  //The service to create discounts is created and its behaviour changes according to the
  //age of the client
  TicketService discountService = new TicketService(kid);
  
  double ticketPriceForKid = discountService.buyTicket(kid);
  Assert.assertTrue(ticketPriceForKid == 20);
  
  //A new Client is created
  Client adult = new Client();
  adult.setAge(25);
  
  //The service to create discounts is created and its behaviour changes according to the
  //age of the client
  TicketService discountService = new TicketService(adult);
  
  double ticketPriceForAdult = discountService.buyTicket(adult);
  Assert.assertTrue(ticketPriceForAdult == 40);

Tuesday, May 28, 2013

Restful Generic DAO with Spring 3 + JPA + unit testing + integration testing

This time, we will create a generic DAO layer, a Service layer and a REST layer which exposes the Service layer to whoever wants to consume it. Unit tests and Integration tests will be created too. Everything is implemented with Spring 3.

Versions used:
  1. Spring 3.2.2.RELEASE
  2. JAXB
  3. Hibernate 4.2.1.Final
  4. Maven 3

pom.xml
<dependencies>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.2.2.RELEASE</version>
  </dependency>
  
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>3.2.2.RELEASE</version>
  </dependency>

  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>4.2.1.Final</version>
  </dependency>

  <dependency>
   <groupId>hsqldb</groupId>
   <artifactId>hsqldb</artifactId>
   <version>1.8.0.10</version>
  </dependency>

  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
  </dependency>

  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.11</version>
   <scope>test</scope>
  </dependency>
  
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test</artifactId>
   <version>3.2.2.RELEASE</version>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>test</scope>
  </dependency>

 </dependencies>

hsqldb will be our in-memory database. Let´s see the rest of the relevant pom info.

<!-- Jetty plugin -->
 <plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <version>6.1.10</version>
  <configuration>
   <scanIntervalSeconds>10</scanIntervalSeconds>
  </configuration>
 </plugin>
With the Maven Jetty Plugin you can manually run mvn jetty:run in your terminal and the server will be started. Now that the server is up, it lets you run the REST services tests (those tests are considered integration tests). Below you can find the automated way to treat integration tests just like normal unit tests are treated.

<!-- This one is to run integration tests -->
 <!-- By default runs all *IT.java tests -->
 <plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-failsafe-plugin</artifactId>
  <version>2.12</version>
  <executions>
   <execution>
    <goals>
     <goal>integration-test</goal>
     <goal>verify</goal>
    </goals>
   </execution>
  </executions>
 </plugin>
Similar to running mvn test to run the unit tests, when you run mvn verify, integration tests are executed. But what if you want to run unit tests and integration tests when you compile your project? Should you run mvn test verify in that case? Well, you must tell maven to start the jetty server right after unit tests finish but before integration tests run (no, you cannot use mvn test jetty:run verify)... see below:

<!-- Responsible for starting jetty before integration tests -->
 <plugin>
  <groupId>org.codehaus.cargo</groupId>
  <artifactId>cargo-maven2-plugin</artifactId>
  <version>1.2.0</version>
  <configuration>
   <container>
    <containerId>jetty6x</containerId>
    <type>embedded</type>
   </container>
  </configuration>
   <executions>
    <execution>
     <id>start-jetty</id>
     <phase>pre-integration-test</phase>
     <goals>
     <goal>start</goal>
     </goals>
    </execution>
    <execution>
     <id>stop-jetty</id>
     <phase>post-integration-test</phase>
     <goals>
     <goal>stop</goal>
     </goals>
   </execution>
  </executions>
 </plugin>
Pretty straightforward, right? Thanks to the Cargo plugin, whenever integration tests are executed, in the pre-integration-test maven phase the jetty server will be automatically started.

web.xml
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath*:spring-beans.xml</param-value>
 </context-param>

 <context-param>
  <param-name>log4jConfigLocation</param-name>
  <param-value>classpath*:log4j.properties</param-value>
 </context-param>
 <servlet>
  <servlet-name>applicationContext</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>applicationContext</servlet-name>
  <url-pattern>/client-crud/*</url-pattern>
 </servlet-mapping>
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
That's a normal Spring setup.

applicationContext-servlet.xml
<!-- Enabling Spring beans auto-discovery -->
<context:component-scan base-package="ar.com.pabloExample" />
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager" />
<!-- Enabling Spring MVC configuration through annotations -->
<mvc:annotation-driven />
In that XML we configure our beans to be scanned because we will use annotations. The transaction manager is enabled to work with annotations too.

GenericDao
public interface GenericDao<T extends Serializable> {
 
 public long count();
 public T create(T t);
 public void delete(Object id);
 public T find(Object id);
 public List<T> getAll();
 public T update(T t); 
}
That's a generic DAO interface.

ClientDao
public interface ClientDao extends GenericDao<Client> {

}
For every entity we want to use the generic DAO, we must create the interface for that entity because the generic DAO is GenericDao<?> and we must tell it which is the entity it will accept, in this case GenericDao<Client>

GenericDaoImpl
public abstract class GenericDaoImpl<T extends Serializable> implements GenericDao<T> {
 
 private Class<T> type;
 
 @SuppressWarnings("unchecked")
 public GenericDaoImpl() {
  Type t = getClass().getGenericSuperclass();
  ParameterizedType pt = (ParameterizedType) t;
  type = (Class<T>) pt.getActualTypeArguments()[0];
 }
 
 @PersistenceContext
 protected EntityManager em;

 @Override
 public long count() {
  String entity = type.getSimpleName();
  final StringBuffer queryString = new StringBuffer("select count(ent) from " + entity + " ent");
  final Query query = this.em.createQuery(queryString.toString());
  return (Long) query.getSingleResult();
 }

 @Override
 public T create(final T t) {
  em.persist(t);
  return t;
 }

 @Override
 public void delete(final Object id) {
  em.remove(em.getReference(type, id));
 }

 @Override
 public T find(final Object id) {
  return em.find(type, id);
 }

 @Override
 public T update(final T t) {
  return em.merge(t);
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<T> getAll() {
  Query query = em.createQuery("from " + type.getName());
  return query.getResultList();
 }
}
This is the implementation of the generic DAO with Hibernate.

ClientDaoImpl
@Repository
public class ClientDaoImpl extends GenericDaoImpl<Client> implements ClientDao {

}
Similar to what we did with the ClientDao interface, we have to do it with the implementation too. We must create the ClientDao implementation and make it extend the generic Dao implementation.
The @Repository annotation only tells Spring this is a bean the "annotations way" of type "DAO" (see the end of the post to understand more of it).

ClientService
public interface ClientService {
 
 public Client create(Client client);
 public void delete(Integer id);
 public Client update(Client client);
 public Client find(Integer id);
 public List<Client> getAll();
 public Long count();
}
This is the  Service layer. It can be generic too, altough in this example only the DAO layer is generic.

ClientServiceImpl
@Service
public class ClientServiceImpl implements ClientService {
 
 @Autowired
 private ClientDao clientDao;

 @Override
 @Transactional(readOnly = false)
 public Client create(Client client) {
  return clientDao.create(client);
 }

 @Override
 @Transactional(readOnly = true)
 public List<Client> getAll() {
  return clientDao.getAll();
 }

 @Override
 @Transactional(readOnly = false)
 public void delete(Integer id) {
  clientDao.delete(id);
 }

 @Override
 @Transactional(readOnly = false)
 public Client update(Client client) {
  return clientDao.update(client);
 }

 @Override
 @Transactional(readOnly = false)
 public Client find(Integer id) {
  return clientDao.find(id);
 }

 @Override
 @Transactional(readOnly = true)
 public Long count() {
  return clientDao.count();
 }

}
In this class, all of our methods are transactional, that's why we annotate them with @Transactional. With @Autorwired we inject the Client DAO implementation. The @Service does the same as @Repository; It tells Spring that this class is a bean too (check the end of the post for more information about it).

spring-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <!-- Datasource configured in spring and not in persitence.xml -->
 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
  <property name="url" value="jdbc:hsqldb:mem:testdb" />
  <property name="username" value="sa" />
  <property name="password" value="" />
 </bean>
 
 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
  <property name="persistenceUnitName" value="spring-webapp-persistenceUnit" />
  <property name="dataSource" ref="dataSource"/>
 </bean>

 <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
  <property name="entityManagerFactory" ref="entityManagerFactory"/>
  <property name="dataSource" ref="dataSource" />
 </bean>

</beans>
This file is a normal one, we define the datasource, the hibernate entity manager and the transaction manager associated with both.

ClientRestService
@Controller
@RequestMapping("/rest-services/clients")
public class ClientRestService {
 
 private static final Logger LOGGER = Logger.getLogger(ClientService.class);
 
 @Autowired
 private ClientService clientService;

 @RequestMapping(method = RequestMethod.GET)
 @ResponseBody
 public Clients loadClients() {
  
  Clients clientsWrapper = new Clients();
  clientsWrapper.setClients(clientService.getAll());
  
  LOGGER.info("--- Client list retrieved ---");
  return clientsWrapper;
 }
 
 @RequestMapping(method = RequestMethod.POST)
 @ResponseBody
 public Client addClient(@RequestBody Client client) {
  
  Client newClient = clientService.create(client);
  
  LOGGER.info("--- New client saved ---");
  return newClient;
 }
 
 @RequestMapping(value = "/{clientId}", method = RequestMethod.PUT)
 @ResponseBody
 public Client updateClient(@PathVariable(value = "clientId") Integer clientId, @RequestBody Client client) {
  
  Client newClient = clientService.update(client);
  
  LOGGER.info("--- Client updated ---");
  return newClient;
 }
 
 @RequestMapping(value = "/{clientId}", method = RequestMethod.GET)
 @ResponseBody
 public Client findClient(@PathVariable(value = "clientId") Integer clientId) {
  
  Client foundClient = clientService.find(clientId);
  
  LOGGER.info("--- Client found ---");
  return foundClient;
 }
 
 @RequestMapping(value = "/{clientId}", method = RequestMethod.DELETE)
 @ResponseBody
 public void deleteClient(@PathVariable(value = "clientId") Integer clientId) {
  
  clientService.delete(clientId);
  LOGGER.info("--- Client deleted ---");
 }
 
}
Here we expose our service layer (in this case, our class annotated with @Service) via REST. To sum up the operations available, you can see this table:

URL Method type Operation
http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients GET get all clients
http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients POST create client
http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients/1 PUT update client id = 1
http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients/1 GET find client id = 1
http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients/1 DELETE delete client id = 1

@Controller does the same job as the previous @Repository and @Service annotations; It tells Spring that this class is a Spring bean.

Clients
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Clients {
 
 private List<Client> clients;

 @XmlElement(name = "client")
 public List<Client> getClients() {
  return clients;
 }

 public void setClients(List<Client> clients) {
  this.clients = clients;
 }

}
This class acts as a wrapper for the list of client class. That wrapper eases the process of consuming a REST service that returns a list of objects. The wrapper class is annotated with JAXB annotations

Client
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@Entity
@Table(name = "T_CLIENT")
public class Client implements Serializable {

 private static final long serialVersionUID = -7682472386786656877L;
 
 @Id
 @GeneratedValue(strategy = GenerationType.SEQUENCE)
 private Integer id;
 private String name;

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

}
The Client JPA entity which is used by Hibernate, is annotated with JAXB elements too so that we can reuse the same entity when exposing it via REST. Of course you may create another Client class in order to expose only the information you want to expose.

Let's test this example!


ClientServiceTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring-beans-test.xml", "/applicationContext-servlet-test.xml" })
public class ClientServiceTest {
 
 @Autowired
 private ClientService clientService;
 
 private Client createNewClient() {
  Client client = new Client();
  client.setName("Rupert");
  
  return client;
 }
 
 @Test
 public void createTest() {
  
  Client client = createNewClient();
  
  Client clientSaved = clientService.create(client);
  
  Assert.assertNotNull(clientSaved);
  Assert.assertNotNull(clientSaved.getId());
 }
 
 @Test
 public void deleteTest() {
  Client client = createNewClient();
  
  Client clientSaved = clientService.create(client);
  clientService.delete(clientSaved.getId());
  Client clientDeleted = clientService.find(clientSaved.getId());

  Assert.assertNull(clientDeleted);
 }
 
 @Test
 public void findTest() {
  Client client = createNewClient();
  
  Client clientSaved = clientService.create(client);
  Client clientDeleted = clientService.find(clientSaved.getId());

  Assert.assertNotNull(clientDeleted);
 }
 
 @Test
 public void countTest() {
  Client client = createNewClient();
  
  long countBefore = clientService.count();
  clientService.create(client);
  long countAfter = clientService.count();
  
  Assert.assertEquals(countBefore, countAfter - 1);
 }
 
 @Test
 public void getAllTest() {
  this.createTest();
  List<Client> all = clientService.getAll();
  
  Assert.assertNotNull(all);
  Assert.assertTrue(all.size() > 0);
 }

}
This unit test is for the Client Service layer. You can run it with mvn test command.

ClientRestServiceIT
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/spring-beans-test.xml", "/applicationContext-servlet-test.xml" })
public class ClientRestServiceIT {
 
 private static final String REST_SERVICE_URL = "http://localhost:8080/spring-webapp-example/client-crud/rest-services/clients";
 private RestTemplate restTemplate = new RestTemplate();
 
 private Client createNewClient() {
  Client client = new Client();
  client.setName("Rupert");
  
  return client;
 }
 
 @Test
 public void createTest() {
  
  Client newClient = createNewClient();
  Client clientCreated = restTemplate.postForObject(REST_SERVICE_URL, newClient, Client.class);
  
  Assert.assertNotNull(clientCreated);
  Assert.assertNotNull(clientCreated.getId());
 }
 
 @Test
 public void updateTest() {
  
  Client newClient = createNewClient();
  Client clientCreated = restTemplate.postForObject(REST_SERVICE_URL, newClient, Client.class);
  
  clientCreated.setName("Stuart");
  
  String restServiceUrl = REST_SERVICE_URL + "/" + clientCreated.getId();
  restTemplate.put(restServiceUrl, clientCreated);
  Client clientModified = restTemplate.getForObject(restServiceUrl, Client.class);
  
  Assert.assertNotNull(clientModified);
  Assert.assertTrue(clientModified.getName().equals("Stuart"));
 }
 
 @Test
 public void findTest() {
  
  Client newClient = createNewClient();
  Client clientCreated = restTemplate.postForObject(REST_SERVICE_URL, newClient, Client.class);
  
  String restServiceUrlFind = REST_SERVICE_URL + "/" + clientCreated.getId();
  Client clientFound = restTemplate.getForObject(restServiceUrlFind, Client.class);
  
  Assert.assertNotNull(clientFound);
  Assert.assertEquals(clientFound.getId(), clientCreated.getId());
 }
 
 @Test
 public void getAllTest() {
  
  Client newClient = createNewClient();
  restTemplate.postForObject(REST_SERVICE_URL, newClient, Client.class);
  
  Clients clients = (Clients) restTemplate.getForObject(REST_SERVICE_URL, Clients.class);
  
  Assert.assertNotNull(clients);
  Assert.assertNotNull(clients.getClients());
  Assert.assertTrue(clients.getClients().size() > 0);
 }
 
 @Test
 public void deleteTest() {
  
  Client newClient = createNewClient();
  Client clientCreated = restTemplate.postForObject(REST_SERVICE_URL, newClient, Client.class);
  
  Assert.assertNotNull(clientCreated);
  Assert.assertNotNull(clientCreated.getId());
  
  //It should be found
  String restServiceUrlFind = REST_SERVICE_URL + "/" + clientCreated.getId();
  Client clientFound = restTemplate.getForObject(restServiceUrlFind, Client.class);
  Assert.assertNotNull(clientFound);
  Assert.assertNotNull(clientFound.getId());
  
  restTemplate.delete(restServiceUrlFind);
  
  //It should not be found
  Client clientDeleted = restTemplate.getForObject(restServiceUrlFind, Client.class);
  Assert.assertNull(clientDeleted);
 }
 
}
This test is the so called integration test we created. You can run it executing mvn verify.

About @Controller @Repository and @Service annotations

All of them do the same! they tell Spring that the class annotated is a Spring bean. So, why don't we use something like "@Bean" for every bean? Because the idea goes like this:
  • Every DAO should be @Repository
  • Every Controller/Action should be @Controller
  • Every Service should be @Service
Say, for instance, you have all of your beans annotated with @Controller (remember those 3 are the same) and you want to apply transactions via aspects with Spring to every Service class. Then, if you had all of your service beans annotated with @Service you could choose to apply transaction via aspects to every class annotated with @Service.

Download the complete example!

Checkout the project: https://subversion.assembla.com/svn/pablo-examples/spring-webapp-example

Run mvn test -> To run the unit tests only
Run mvn verify -> To run the unit tests + integration tests
Run mvn verify -Dmaven.test.skip=true -> To run integration tests only

Additionaly, you may run mvn eclipse:eclipse to convert it to Eclipse project

Wednesday, February 27, 2013

JavaUtils and Apache Common Collections

When it comes to the importance not to repeat yourself while writing code, it is even important to take a look at most common activities. For example, instead of writing a lot of nested for statements, making your code illegible, you can use already Java built-in features. Let's take a look at some really simple utils:

Tested with:
  • commons-collections-3.2.1
  • JUnit 4
  • Maven 3

  • CollectionUtils.select - If you want to retrieve one or more objects from a collection that meet your criteria (like id = 4 or age > 18)
  • CollectionUtils.find - If you want to retrieve only one object from a collection that meet your criteria (like id = 6)
  • Collections.max - If you want to retrieve only one object from a collection, the one which best meets one criteria
  • Collections.sort - If you want to have a collection ordered by some criteria

Data to base our examples on:
@Before
 public void init() {
  Person p1 = new Person(1, "ruben", 17);
  Person p2 = new Person(2, "carlos", 45);
  Person p3 = new Person(3, "ismael", 47);
  Person p4 = new Person(4, "raul", 30);

  personList.add(p1);
  personList.add(p2);
  personList.add(p3);
  personList.add(p4);
 }

CollectionUtils.select
@Test
 public void selectListTest() {
  AdultPredicate adultPredicate = new AdultPredicate();
  Collection adultPersons = CollectionUtils.select(personList, adultPredicate);
  
  Assert.assertNotNull(adultPersons);
  Assert.assertTrue(!adultPersons.isEmpty());
 }

public class AdultPredicate implements Predicate {
 
 @Override
 public boolean evaluate(Object arg0) {
  Person person = (Person) arg0;
  if (person.getAge() != null &&
   person.getAge() >= 18) {
   return true;
  }
  return false;
 }
}

CollectionUtils.find
@Test
 public void findObjectTest() {
  Predicate personNumberTwoPredicate = new PersonNumberTwoPredicate();
  Person personNumberTwo = (Person) CollectionUtils.find(personList, personNumberTwoPredicate);
  
  Assert.assertNotNull(personNumberTwo);
  Assert.assertTrue(personNumberTwo.getId().equals(2));
 }

public class PersonNumberTwoPredicate implements Predicate {

 private static final Integer PERSON_ID_TWO = 2;

 @Override
 public boolean evaluate(Object arg0) {
  Person person = (Person) arg0;
  if (person.getId().equals(PERSON_ID_TWO)) {
   return true;
  }
  return false;
 }
}

Collections.max
@Test
 public void oldestPersonTest() {
  PersonAgeComparator personAgeComparator = new PersonAgeComparator();
  Person oldestPerson = Collections.max(personList, personAgeComparator);
  
  Assert.assertNotNull(oldestPerson);
  Assert.assertTrue(oldestPerson.getAge().equals(47));
 }

public class PersonAgeComparator implements Comparator {

 @Override
 public int compare(Person o1, Person o2) {
  if (o1.getAge() > o2.getAge()) {
   return 1;
  }
  if (o1.getAge().equals(o2.getAge())) {
   return 0;
  }
  return -1;
 }
}

Collections.sort
@Test
 public void sortPersonsTest() {
  PersonAgeComparator personAgeComparator = new PersonAgeComparator();
  //Sort order age ascending
  Collections.sort(personList, personAgeComparator);
  //Sort order age descending
  Collections.sort(personList, ComparatorUtils.reversedComparator(personAgeComparator));
 }

Download the complete example here!

Checkout this: https://subversion.assembla.com/svn/pablo-examples/utils-test

Then from a Terminal get into that folder and run: mvn test
To import it into Eclipse IDE, from a Terminal run: mvn eclipse:eclipse and import it as a Java Project

Tuesday, December 4, 2012

Datasource and database driver in JBoss 7 without module definition

So, you just downloaded JBoss 7 and want to give it a try. You notice that the whole directory structure changed completely but do not want to "waste time with new administration stuff" and want to use another datasource other that the default one which comes with H2 (an in-memory database).

With this configuration, you will be able to easily create a new datasource for JBoss 7 using a new database driver with minimal configuration. This configuration has been tested only in standalone mode and may not be suitable for cluster/production environments. Note that this way will only work with JDBC4 drivers.

Just deploy your jar under <JBOSS_HOME>\standalone\deployments and add the following datasource definition to your <JBOSS_HOME>\standalone\configuration\standalone.xml

<datasource jndi-name="java:jboss/datasources/PostgreSQLDS" pool-name="PostgreSQLDS" enabled="true" use-java-context="true">
       <connection-url>jdbc:postgresql://<your_ip>:<your_db_port>/<your_db></connection-url>
       <driver>postgresql-9.1-901.jdbc4.jar</driver>
      <security>
            <user-name>postgres</user-name>
            <password>123456</password>
      </security>
</datasource>

Now just run <JBOSS_HOME>/bin/standalone.sh (if you are using Linux/Mac, .bat if Windows) to start the server. You can check the datasource health in the new administration console.

Additional information on deploying datasources to JBoss 7 can be found here

Tuesday, October 2, 2012

@ViewScoped and CDI

If you were working with Seam 2 you sure were familiar with @Scope(ScopeType.PAGE) annotation for your action classes. This scope was used in those cases where the user stayed in the same page working until a redirect (or refresh) was done.

Now, taking a look at CDI you see that there is no out-of-the-box scope that does the same job. JSF 2 provides @ViewScoped but it is incompatible with CDI. You may try the following without success:

import javax.faces.bean.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped

public class AdministrarUsuariosAction implements Serializable {

Unlike @SessionScoped where you have the CDI proper annotation and the JSF 2 one:

import javax.enterprise.context.SessionScoped;
import javax.faces.bean.SessionScoped;

...for @ViewScoped you only have the JSF 2 one:

import javax.faces.bean.ViewScoped;

So, is there a way we can have a page scope just like in Seam 2? YES

Thanks to Seam 3 Faces module, we are able to use JSF 2 @ViewScoped annotation inside CDI beans. Just add these jars to the pom file:

<dependency>
  <groupid>org.jboss.seam.faces</groupid>
  <artifactid>seam-faces</artifactid>
  <version>3.1.0.Final</version>
</dependency>
  
<dependency>
  <groupid>org.jboss.seam.security</groupid>
  <artifactid>seam-security</artifactid>
  <version>3.1.0.Final</version>
</dependency>

I've tested this configuration under JBoss 7.1.1.Final using the archetype: jboss-javaee6-webapp. I've used this post from Adrian Paredes blog to adapt the archetype to work with JBoss 7.

Friday, August 24, 2012

JBoss ESB http-gateway service

We can call an ESB service in different ways; It can be invoked via queue messages, HTTP requests, webservices, and so on... In this post we will work with the JBoss ESB and see how we can invoke a service with a HTTP POST request.

Versions used:
- JBoss AS 5.1.0.GA (Community version)
- JBoss ESB 4.11 (not the standalone one, the version which is deployed in the AS)

Let's see the example!


pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>ar.com.pabloExample</groupId>
 <artifactId>helloworld-jboss-esb</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>helloworld-jboss-esb</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <jboss.home>/opt/jboss</jboss.home>
 </properties>

 <dependencies>

  <dependency>
   <groupId>org.jboss.soa.bpel.dependencies.esb</groupId>
   <artifactId>jbossesb-rosetta</artifactId>
   <version>4.11</version>
   <scope>system</scope>
   <systemPath>${jboss.home}/server/esb-default/deployers/esb.deployer/lib/jbossesb-rosetta.jar</systemPath>
  </dependency>
  
  <!-- For testing purposes -->

  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.2</version>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>commons-httpclient</groupId>
   <artifactId>commons-httpclient</artifactId>
   <version>3.1</version>
   <scope>test</scope>
  </dependency>
  
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.17</version>
   <scope>test</scope>
  </dependency>

 </dependencies>

 <build>
  <finalName>helloworld-jboss-esb</finalName>

  <plugins>

   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jboss-packaging-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
     <archiveName>helloworld-jboss-esb</archiveName>
    </configuration>
    <executions>
     <execution>
      <id>build-esb</id>
      <goals>
       <goal>esb</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

   <!-- mvn jboss:hard-deploy -->
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jboss-maven-plugin</artifactId>
    <version>1.5.0</version>
    <configuration>
     <jbossHome>/opt/jboss</jbossHome>
     <serverName>esb-default</serverName>
     <fileName>target/helloworld-jboss-esb.esb</fileName>
    </configuration>
   </plugin>

   <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>

  </plugins>
 </build>

</project>

The jboss-maven-plugin is just a plugin to ease the process of copying the esb file generated to the jboss server. Of course this is not mandatory :)

The jboss-packaging-maven-plugin is the plugin responsible for creating the ESB file that will be deployed in the server.


jboss-esb.xml
<jbossesb
 xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.2.0.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.jboss.org/repos/labs/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.2.0.xsd"
 parameterReloadSecs="5">
 
 <services>

  <service name="helloWorldService" category="helloWorldCategory" description="Hello World" invmScope="GLOBAL">
  
   <listeners>
    <http-gateway name="http-gateway" payloadAs="STRING"/>
   </listeners>
  
   <actions mep="RequestResponse">

    <!-- This action prints the content of the message -->
    <action name="action1" class="org.jboss.soa.esb.actions.SystemPrintln">
     <property name="printfull" value="false" />
    </action>
    
    <action name="action2" class="ar.com.pabloExample.service.MessageCustomAction" process="process" />

    <!-- This action logs a user text and the service name -->
    <action name="action3" class="org.jboss.soa.esb.actions.ServiceLoggerAction">
     <property name="text" value="Message arrived" />
     <property name="log-payload-location" value="true" />
    </action>

   </actions>
  </service>
  
 </services>

</jbossesb>

In jboss-esb.xml we define a service with 3 actions:
"action1" & "action3" : they do some logging
"action2" : takes the "name" query parameter from the URL and creates the "hello <query parameter>" string which is put in the ESB message body

A listener is defined too. The HTTP listener will trigger the service whenever a POST request is make to a special URL (see the test section to see which is that URL).


MessageCustomAction.java
public class MessageCustomAction extends AbstractActionPipelineProcessor {

 public MessageCustomAction(final ConfigTree config) {
  // extract configuration
 }

 @Override
 public Message process(Message message) throws ActionProcessingException {

        HttpRequest req = HttpRequest.getRequest(message);
        Map<String, String[]> params = req.getQueryParams();
        
        String name = params.get("name")[0];
        
        message.getBody().add("Hello " + name);
  
        return message;
 }

}

Here we define the way to process the ESB message, we interpret it as a HTTP request and retrieve the "name" query parameter.


Let's test the ESB service!



HttpRequestServiceTest.java
public class HttpRequestServiceTest {
 
 private static Logger logger = Logger.getLogger(HttpRequestServiceTest.class);
 
 @Test
 public void httpRequestServiceTest() throws HttpException, IOException {
  
 HttpClient client = new HttpClient();
        PostMethod post = new PostMethod("http://localhost:8080/helloworld-jboss-esb/http/helloWorldCategory/helloWorldService");
        post.setQueryString("?name=pablito");
        client.executeMethod(post);
        
        String result = post.getResponseBodyAsString();
        post.releaseConnection();

        logger.info("Service returned: " + result);
 }
}

In this test we simply do a HTTP post to the following URL:
http://localhost:8080/helloworld-jboss-esb/http/helloWorldCategory/helloWorldService

Note that using the default http-gateway the pattern to use would be like this:
http://<server>:<port>/<deployed esb file>/http/<category name>/<service name>


To run this test, create the ESB file and deploy it in the server:
  1. Set the jboss.home property in the pom.xml
  2. mvn clean package -Dmaven.test.skip=true jboss:hard-deploy
Now run the test with mvn test and you're done!


Download the example:


https://subversion.assembla.com/svn/pablo-examples/helloworld-jboss-esb

Tuesday, August 7, 2012

Installing JBoss ESB in JBoss AS 5.1

We will see the steps to install JBoss ESB in a JBoss AS instance. The ESB can be run in a standalone mode which we are not analyzing in this post. The steps to install the JBoss ESB are really simple and the installation already includes JBPM3 within it. In another post we will see different ESB examples.

Versions used:

JBoss AS 5.1.0.GA - Download
JBoss ESB 4.11 Community - Download
Eclipse Indigo SR2 - Download
JBoss Tools 3.3 for SOA - Download
Ant 1.8.4 - Download


Create a new JBoss instance, we will create esb-default based on default
cd /opt/jboss/server
cp default esb-default -r

In your download folder, extract the JBoss ESB zip file:
cp jbossesb-4.11.zip /opt
cd /opt/jbossesb-4.11
unzip jbossesb-4.11.zip

Now, let's get into the install directoy and create a new deployment.properties file
cd /opt/jbossesb-4.11/install/
cp deployment.properties-example deployment.properties

Now edit the new deployment.properties file and modify the following lines:
org.jboss.esb.server.config=default
...
org.jboss.esb.server.home=/jbossesb-server-4.5.GA
to these
org.jboss.esb.server.config=esb-default
...
org.jboss.esb.server.home=/opt/jboss-5.1.0.GA

Now, while in the install directory let's install the ESB in the AS:
ant deploy

To run the server:
./run.sh -c esb-default

In Eclipse IDE with JBoss Tools installed, in order to create a new ESB example:
File -> New -> Other -> ESB Project

In target runtime create a new server based on your esb-default instance. At the end of the wizard, choose Server Supplied ESB Runtime (because we've installed the ESB in the JBoss esb-default instance)

The following guides are essential while working with JBoss ESB:
ESB Tools Reference Guide
ESB Services Guide
ESB Programmers Guide