Monday, 6 May 2013

Using transaction attributes in EJB 3.1 - Container Managed Transactions

When somebody refers to container managed transactions, what we understand is that the EJB container is responsible of managing transactionality for the methods inside EJB's deployed in the EJB container.

The theory behind transaction management in EJB 3.1 is not brief and probably my post would become to long if I tried to explain other important concepts. In this post I want to just focus on an important concept known as the transaction attribute.

To simplify this concept, I will refer to it, as a configuration given to a method/function within an EJB, that will tell the EJB container what to do with the incoming transaction when that method is called.

The thing that will determine what will occur with the transaction when a certain transaction attribute is used will be the transactional context from where the method was called. In other words, if the enterprise method annotated with a certain attribute was called from a non-transactional(e.g a web page) will manage the transaction differently than if it was called from a transactional context(e.g another EJB). And this is the reason why sometimes we have to choose wisely our transaction attributes.

To use transaction attributes in our EJB's its very simple, all you need to do is use an annotation:
 @Stateful  
 public class SomeBean implements SomeInterface {  
   @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)  
   public void someMethod(){  
    //...  
   }  
   //...  
 }  

Now that we know how to annotate the methods, lets see what will occur when each of the transaction attributes is used:

REQUIRES_NEW
When the calling method is not in a transaction: Starts a new transaction.
When the calling method is in a transaction:  Suspends the existing transaction and creates a new one.

REQUIRED

When the calling method is not in a transaction: Starts a new transaction.
When the calling method is in a transaction:  Executes in existing transaction.

NEVER

When the calling method is not in a transaction: It will execute with no transaction.
When the calling method is in a transaction:  It will throw an exception.

NOT_SUPPORTED

When the calling method is not in a transaction: It will execute with no transaction
When the calling method is in a transaction: It will execute with no transaction(No exception will be thrown)  

SUPPORTS

When the calling method is not in a transaction: It will execute with no transaction.
When the calling method is in a transaction:  Executes in existing transaction.

MANDATORY

When the calling method is not in a transaction:  It will throw an exception.
When the calling method is in a transaction: Executes in existing transaction(Execution continues because the caller was already in a transaction).




Saturday, 13 April 2013

How to unzip a .zip file with Zip4j

3 days ago I discovered a  cool easy to use java tool for working with zip files.
It is called Zip4j.

Have a look at this super simple example that will allow you to unzip a file into a given path in your computer:

 String source = "folder/source.zip";  
 String destination = "folder/source/";    
   try {  
     ZipFile zipFile = new ZipFile(source);  
     zipFile.extractAll(destination);  
   } catch (ZipException e) {  
     e.printStackTrace();  
   }  

Use this if the unzip file has a password:

 String source = "folder/source.zip";  
 String destination = "folder/source/";  
 String password = "password";  
 try {  
   ZipFile zipFile = new ZipFile(source);  
   if (zipFile.isEncrypted()) {  
     zipFile.setPassword(password);  
   }  
   zipFile.extractAll(destination);  
 } catch (ZipException e) {  
   e.printStackTrace();  
 }  

That was easy and cool.
Are you now thinking the same as I am thinking?...
Let's go brute force zip passwords!!! :P

Hahaha.... I am just joking don't do that, this is not a hacking blog( yet! :p )  I hope you enjoyed this post. Use Zip4j with care.

Sunday, 7 April 2013

How do I add a project as a dependency of another project and why would I do so? (Maven)

When working in a Java EE distributed system many times we have to manage the dependencies of each of our nodes. Our system will be full of other projects, representing different aspects of the system.


In this post I want to explain how to include a project as a dependency of another project by using an example scenario that is very common in real life: "Sharing the domain model between nodes".

As we know the domain model is the representation of the data that our system works with. To avoid inconsistencies it is a good practice, that each of the projects in our system that are supposed to interact with the domain model do so in a safe way. By interacting safely, we mean look at the domain model as a provided service that the projects use, but without the possibility of corrupting it.

One of the most common ways of achieving our goal would be, to create the domain model, as a separate project, and reference it there where it is needed. Doing this none of the distributed projects of our system will have to be responsible for the domain model, their only responsibility will be to keep the dependency updated, to make sure that they are using the very latest version.


In the following image we can see an example of what could perfectly be a class, in the domain model of a distributed system(Just a trivial example):



This is the project that contains the model and if we want to make sure that it can be use as a dependency in another project, we need to make sure it is packed in a .jar (note the content of the packaging tag in the next image).



When this program is built using the mvn clean install command, it will generate a .jar file that will be stored in the local maven repository(~/.m2). If the build process is successful we should see a message similar to this in our console(Note the message that says that the .jar was installed in the repo):


 A very important thing to understand about this process, is that future versions of this project will need to be increased and also will not have the SNAPSHOT postfix when deployed as stable version. If this process is always done manually by the developer, it possible to make mistakes and that is why in real live, many companies use special tools for building and deploying such as Jenkins and Hudson. The set of tasks and tools that allows distributed software built and deployed automatically in a safe way, is known as Continuous Integration.


Now that we have built and deployed(In this example we just deployed it in the local maven repo) our new domain model, we can reference it in another project.
In this example I will use the model in a project that represents a data access layer for a distributed system, to do so, we will need to add the dependency to the correct version of the model inside the pom.xml file:





Once we build our project we will see that the .jar that contains the model is in the class path and we can use it with no problem in this project:



 When a change is done on those projects on which other projects depend, in order to avoid versions miss matches and inconsistencies, it is a good practice to update all the versions in the dependent projects, re-build and re-deploy.

Now that we know how to add the domain model as a dependency we can add it to other projects that are part of our system(e.g a web app).

Just as a little appendix and even if is not directly related to the post, there is an excellent text about why the Data Transfer Object pattern is no longer needed in JEE in the book: Enterprise JEE Patterns. Rethinking best practices(page 273).  There is a very interesting explanation of why DTO's became superfluous when the JPA entities were introduced. 

Friday, 22 March 2013

How do private methods affect our software testability?

 How many times did we hear the question:
“Should we test private methods?”
In this post I want to share with you my thoughts about this question and how I think we should proceed when having this doubt.
Methods with the access modifier private are code as the rest of the application, so this mean that they can potentially hide bugs.  So after a first impression my answer to that question is: “Yes, we should!”.  
Wait, a second… before you get mad at me. I want to rephrase my statement.
I think that question is completely not in place.  Instead of asking “Should we test private methods?”, we should ask: “How do private methods affect our software testability?”
Let’s consider different approaches to deal with private methods and see their pros and cons from the testability point of view:

Scenario 1 – Ok,ok you leave me no choice but reflection
This is what the official Java tutorials say about reflection: 
“Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.”
Ok, let’s  give it a try, imagine we have some private method, such as this one:



Hhmmm… So how to do this? Oh my god, do I really have to use reflection? Are you sure?
Let’s investigate a bit before making any decision.
Weeks ago I spent one full afternoon searching the internet looking for testability assurance pattern to test this in java. The only interesting discovery I did was that C# developers have a pattern for this called  “Internals Visible To Attribute”.  Unfortunately (Or maybe fortunately hehe…) that technique is not compatible with java.
There has to be an alternative, why can’t we just change the access modifier and test it normally?...
The common answer you get, when you ask that is:  You will compromise security, you will break encapsulation, you are lazy…
Ok,ok,you leave me no choice but reflection:

 Please don’t do this at your workplace J
Let’s see the Pros and Cons now.

Pros:
- The test is green and I tested the piece of code that I wanted to test
- I did not compromise the security of my software(:P Whatever….)
- I am an expert because the official java tutorials say that only cool dudes like me can use reflection.
Cons:
- A simple rename done by anybody to the method, return type or parameter will break the test and I will have to come back to rewrite the test. This type of test is very difficult to maintain.
- I broke the Security of my software. What am I talking about??? How is that possible if the method still private in the production code?? Hacking the internals of a class is a security.
- See how long that test is. Imagine you have to do this for a longer and more complex method.
More drawbacks(Taken from Java official tutorials website):



Scenario 2 – There is always a way out.
As mentioned in the previous scenario a design pattern that can help us testing private fields does not exist. But there are always ways out. Here I am going to suggest 2 and explain them:

- Protect your method: Just change the access modifier to protected. This will allow you to stub the method call and test using a pattern called Subclass & Override. Basically on your test package, you will be creating a fake that extends the class under test and then override using your expectations. You will then use that fake on your test.
This is a very common breaking dependency technique, since that private method will for sure be called somewhere else within the class and present a dependency inside other method/s(Must be broken in order to increase testability).
I don’t agree with this being a security risk because various reasons, one of them is that probably that method should not be private or, is too long to be tested indirectly, or probably that method should not even be there.
The only disadvantage I see is a decrease in the quality of the design, but I will justify that as the price we need to pay when we build software without using TDD or having testability in mind.

- Extract until you drop: Robert C. Martin in his book “Clean Code”, describes a refactoring methodology called “Extract until you drop”, the idea is refactor the code as much as possible until the point there the methods have not more than 4 lines of code. He says that a line with just a curly braces also count as a line.  If you think about it, your methods would be able to use an “if else” statement of just one line in each of the clauses.
If we want to unit test, we need to have units.  After doing this exhaustively on the method or class under test, we will probably see how that method was probably refactored into a new class, or maybe became so small that it can be tested indirectly via another method with no risk at all, since there are no longer inflection points(Places where logic of the software can potentially take a different path).
The main disadvantages of this approach will probably be that doing it probably would take too long, also on our way and specially if we are dealing with legacy code, we will need to use a lot of breaking dependency techniques and this will present a learning curve that will push us to break some of the design rules we were highly tight too in the past when the system was initially built.  But the benefit will be visible at short, mid and long term.

If you are concern about testability and you believe that testability is the path to quality in modern software, then the right question is How do private methods affect our software testability?

Sunday, 17 March 2013

PrimePush in Jboss AS 7

It toke me a while to make PrimePush work in JBoss AS 7.
In this post I will just paste the codes of a simple hello world like program that uses PrimePush libraries to submit an String to a web socket.

The requirement for this exercise, is that you know to create a new JSF project with maven and deploy it into the JBoss 7 AS application server. All the steps to do that can be found in one of my previous post:
http://javing.blogspot.ie/2013/01/how-to-create-new-jsf-21-project-and.html

Once you have your project ready, lets make the following changes in the configuration files:

pom.xml


1:  <?xml version="1.0" encoding="UTF-8"?>  
2:  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
3:       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
4:       <modelVersion>4.0.0</modelVersion>  
5:       <groupId>my.test.project</groupId>  
6:       <artifactId>my.test.project</artifactId>  
7:       <version>0.0.1-SNAPSHOT</version>  
8:       <packaging>war</packaging>  
9:       <name>Java EE 6 webapp project</name>  
10:       <properties>  
11:            <jboss.bom.version>1.0.0.Final</jboss.bom.version>  
12:            <version.faces.mojarra>2.1.7</version.faces.mojarra>  
13:            <version.primefaces>3.4.2</version.primefaces>  
14:            <version.atmosphere>1.0.8</version.atmosphere>  
15:       </properties>  
16:       <dependencyManagement>  
17:            <dependencies>  
18:                 <dependency>  
19:                      <groupId>org.jboss.bom</groupId>  
20:                      <artifactId>jboss-javaee-6.0-with-tools</artifactId>  
21:                      <version>${jboss.bom.version}</version>  
22:                      <type>pom</type>  
23:                      <scope>import</scope>  
24:                 </dependency>  
25:                 <dependency>  
26:                      <groupId>junit</groupId>  
27:                      <artifactId>junit</artifactId>  
28:                      <version>4.10</version>  
29:                      <type>jar</type>  
30:                      <scope>test</scope>  
31:                 </dependency>  
32:            </dependencies>  
33:       </dependencyManagement>  
34:       <dependencies>  
35:            <dependency>  
36:                 <groupId>javax.enterprise</groupId>  
37:                 <artifactId>cdi-api</artifactId>  
38:                 <scope>provided</scope>  
39:            </dependency>  
40:            <dependency>  
41:                 <groupId>org.jboss.spec.javax.servlet</groupId>  
42:                 <artifactId>jboss-servlet-api_3.0_spec</artifactId>  
43:                 <scope>provided</scope>  
44:            </dependency>  
45:            <dependency>  
46:                 <groupId>org.jboss.spec.javax.faces</groupId>  
47:                 <artifactId>jboss-jsf-api_2.1_spec</artifactId>  
48:                 <scope>provided</scope>  
49:            </dependency>  
50:            <dependency>  
51:                 <groupId>org.jboss.spec.javax.el</groupId>  
52:                 <artifactId>jboss-el-api_2.2_spec</artifactId>  
53:                 <scope>provided</scope>  
54:            </dependency>  
55:            <dependency>  
56:                 <groupId>com.sun.faces</groupId>  
57:                 <artifactId>jsf-impl</artifactId>  
58:                 <version>${version.faces.mojarra}</version>  
59:                 <scope>provided</scope>  
60:            </dependency>  
61:            <dependency>  
62:                 <groupId>org.primefaces</groupId>  
63:                 <artifactId>primefaces</artifactId>  
64:                 <version>${version.primefaces}</version>  
65:            </dependency>  
66:            <dependency>  
67:                 <groupId>org.atmosphere</groupId>  
68:                 <artifactId>atmosphere-runtime</artifactId>  
69:                 <version>${version.atmosphere}</version>  
70:                 <exclusions>  
71:                      <exclusion>  
72:                           <artifactId>slf4j-api</artifactId>  
73:                           <groupId>org.slf4j</groupId>  
74:                      </exclusion>  
75:                 </exclusions>  
76:            </dependency>  
77:            <dependency>  
78:                 <groupId>junit</groupId>  
79:                 <artifactId>junit</artifactId>  
80:                 <scope>test</scope>  
81:            </dependency>  
82:       </dependencies>  
83:       <build>  
84:            <finalName>pushcomment</finalName>  
85:            <plugins>  
86:                 <plugin>  
87:                      <artifactId>maven-compiler-plugin</artifactId>  
88:                      <version>2.3.1</version>  
89:                      <configuration>  
90:                           <source>1.6</source>  
91:                           <target>1.6</target>  
92:                      </configuration>  
93:                 </plugin>  
94:                 <plugin>  
95:                      <artifactId>maven-war-plugin</artifactId>  
96:                      <version>2.1.1</version>  
97:                      <configuration>  
98:                           <failOnMissingWebXml>false</failOnMissingWebXml>  
99:                      </configuration>  
100:                 </plugin>  
101:            </plugins>  
102:       </build>  
103:       <repositories>  
104:            <repository>  
105:                 <id>prime-repo</id>  
106:                 <name>PrimeFaces Maven Repository</name>  
107:                 <url>http://repository.primefaces.org</url>  
108:                 <layout>default</layout>  
109:            </repository>  
110:       </repositories>  
111:  </project>  

faces-config.xml


1:  <?xml version="1.0" encoding="UTF-8"?>  
2:  <!-- This file is not required if you don't need any extra configuration. -->  
3:  <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"  
4:    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
5:    xsi:schemaLocation="  
6:      http://java.sun.com/xml/ns/javaee  
7:      http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">  
8:  </faces-config>  

web.xml

1:  <?xml version="1.0" encoding="UTF-8"?>  
2:  <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
3:       xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  
4:       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
5:       version="3.0">  
6:       <display-name>push-comment</display-name>  
7:       <welcome-file-list>  
8:            <welcome-file>index.html</welcome-file>  
9:       </welcome-file-list>  
10:       <context-param>  
11:            <param-name>javax.faces.PROJECT_STAGE</param-name>  
12:            <param-value>Development</param-value>  
13:       </context-param>  
14:       <context-param>  
15:            <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>  
16:            <param-value>2</param-value>  
17:       </context-param>  
18:       <context-param>  
19:            <param-name>javax.faces.DEFAULT_SUFFIX</param-name>  
20:            <param-value>.xhtml</param-value>  
21:       </context-param>  
22:       <context-param>  
23:            <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>  
24:            <param-value>true</param-value>  
25:       </context-param>  
26:       <context-param>  
27:            <param-name>javax.faces.STATE_SAVING_METHOD</param-name>  
28:            <param-value>server</param-value>  
29:       </context-param>  
30:       <context-param>  
31:            <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>  
32:            <param-value>true</param-value>  
33:       </context-param>  
34:       <context-param>  
35:            <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>  
36:            <param-value>true</param-value>  
37:       </context-param>  
38:       <context-param>  
39:            <param-name>com.sun.faces.numberOfLogicalViews</param-name>  
40:            <param-value>5</param-value>  
41:       </context-param>  
42:       <context-param>  
43:            <param-name>com.sun.faces.numberOfViewsInSession</param-name>  
44:            <param-value>3</param-value>  
45:       </context-param>  
46:       <context-param>  
47:            <param-name>com.sun.faces.compressViewState</param-name>  
48:            <param-value>true</param-value>  
49:       </context-param>  
50:       <context-param>  
51:            <param-name>com.sun.faces.serializeServerState</param-name>  
52:            <param-value>false</param-value>  
53:       </context-param>  
54:       <context-param>  
55:            <param-name>com.sun.faces.preferXHTML</param-name>  
56:            <param-value>true</param-value>  
57:       </context-param>  
58:       <context-param>  
59:            <param-name>com.sun.faces.disableVersionTracking</param-name>  
60:            <param-value>true</param-value>  
61:       </context-param>  
62:       <context-param>  
63:            <param-name>primefaces.THEME</param-name>  
64:            <param-value>aristo</param-value>  
65:       </context-param>  
66:       <security-constraint>  
67:            <display-name>Restrict direct access to XHTML documents.</display-name>  
68:            <web-resource-collection>  
69:                 <web-resource-name>XHTML</web-resource-name>  
70:                 <url-pattern>*.xhtml</url-pattern>  
71:            </web-resource-collection>  
72:            <auth-constraint>  
73:                 <description>No roles defined for direct access to XHTML documents.</description>  
74:            </auth-constraint>  
75:       </security-constraint>  
76:       <session-config>  
77:            <session-timeout>20</session-timeout>  
78:       </session-config>  
79:       <error-page>  
80:            <exception-type>javax.faces.application.ViewExpiredException</exception-type>  
81:            <location>/index.jsf</location>  
82:       </error-page>  
83:       <servlet>  
84:            <servlet-name>Faces Servlet</servlet-name>  
85:            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>  
86:            <load-on-startup>1</load-on-startup>  
87:            <async-supported>true</async-supported>  
88:       </servlet>  
89:       <servlet-mapping>  
90:            <servlet-name>Faces Servlet</servlet-name>  
91:            <url-pattern>/faces/*</url-pattern>  
92:       </servlet-mapping>  
93:       <servlet-mapping>  
94:            <servlet-name>Faces Servlet</servlet-name>  
95:            <url-pattern>*.jsf</url-pattern>  
96:       </servlet-mapping>  
97:       <servlet>  
98:            <servlet-name>Push Servlet</servlet-name>  
99:            <servlet-class>org.primefaces.push.PushServlet</servlet-class>  
100:            <init-param>  
101:                 <param-name>org.atmosphere.useWebSocket</param-name>  
102:                 <param-value>false</param-value>  
103:            </init-param>  
104:            <init-param>  
105:                 <param-name>org.atmosphere.cpr.sessionSupport</param-name>  
106:                 <param-value>true</param-value>  
107:            </init-param>  
108:            <init-param>  
109:                 <param-name>org.atmosphere.useNative</param-name>  
110:                 <param-value>true</param-value>  
111:            </init-param>  
112:            <init-param>  
113:                 <param-name>org.atmosphere.cpr.broadcasterCacheClass</param-name>  
114:                 <param-value>org.atmosphere.cache.HeaderBroadcasterCache</param-value>  
115:            </init-param>  
116:            <init-param>  
117:                 <param-name>org.atmosphere.cpr.broadcastFilterClasses</param-name>  
118:                 <param-value>org.atmosphere.client.TrackMessageSizeFilter</param-value>  
119:            </init-param>  
120:            <init-param>  
121:                 <param-name>org.atmosphere.resumeOnBroadcast</param-name>  
122:                 <param-value>true</param-value>  
123:            </init-param>  
124:            <load-on-startup>1</load-on-startup>  
125:            <async-supported>true</async-supported>  
126:       </servlet>  
127:       <servlet-mapping>  
128:            <servlet-name>Push Servlet</servlet-name>  
129:            <url-pattern>/primepush/*</url-pattern>  
130:       </servlet-mapping>  
131:  </web-app>  

Now that everything should be configured, lets write a very simple JSF 2 program to show a primepush.

index.xhtml


1:  <!DOCTYPE html>  
2:  <html xmlns="http://www.w3.org/1999/xhtml"  
3:       xmlns:h="http://java.sun.com/jsf/html"  
4:       xmlns:f="http://java.sun.com/jsf/core"  
5:       xmlns:c="http://java.sun.com/jsp/jstl/core"  
6:       xmlns:ui="http://java.sun.com/jsf/facelets"  
7:       xmlns:p="http://primefaces.org/ui">  
8:  <f:view contentType="text/html" encoding="UTF-8">  
9:       <h:head>  
10:            <meta charset="utf-8" />  
11:       </h:head>  
12:       <h:body>  
13:            <h:form prependId="false">  
14:                 <p:inputTextarea id="cmt" value="#{myCommentBean.comment}"></p:inputTextarea>  
15:                 <p:commandButton actionListener="#{myCommentBean.publish}"  
16:                      process="cmt @this" update="cmt" value="publish"></p:commandButton>  
17:            </h:form>  
18:            <span id="pushComment" />  
19:            <p:socket channel="/comment" onMessage="handleMessage"></p:socket>  
20:            <script type="text/javascript">  
21:       function handleMessage(data)  
22:        {   
23:        jQuery('#pushComment').text(data);  
24:               }  
25:      </script>  
26:       </h:body>  
27:  </f:view>  
28:  </html>  

MyCommentBean.java



1:  /**  
2:   * The JSF Backing bean that will push the messages into the socket.  
3:   */  
4:  package my.first.push.project;  
5:  import javax.faces.bean.ManagedBean;  
6:  import javax.faces.bean.RequestScoped;  
7:  import org.primefaces.push.PushContextFactory;  
8:  @ManagedBean(name = "myCommentBean")  
9:  @RequestScoped  
10:  public class MyCommentBean {  
11:    public static final String BROADCAST_CHANNEL = "/comment";  
12:    private String comment;  
13:    public String getComment() {return comment;}  
14:    public void setComment(String comment) {this.comment = comment;}  
15:    public void publish() {  
16:     PushContextFactory.getDefault().getPushContext().push(BROADCAST_CHANNEL, this.comment);  
17:     this.comment = "";  
18:    }  
19:  }  

So now that we have the application, compile and deploy it in JBoss.
Run it on your browser by just accessing the URL:
http://localhost:8080/pushcomment/

Open a few browsers and see how all the clients listening to the socket will get the updates:



Download this project from:

http://www.2shared.com/file/Vy8ZSkUQ/pushcomment.html

Sunday, 3 March 2013

The legacy code that whispered to the developer

I was practicing my legacy code refactoring skills a bit this weekend (Highly on demand in the industry lately hehe..  ;) ) when I came across this fascinating line of code:

 System.out.println("Process complete!!!");  

My first thought was: "Whatever, just another silly console output nobody cares about!"
As usual, I run my eCobertura code coverage plugin to check how I was getting on with the level of coverage.
That line was red, it didn't bother me much so I continued with the rest of my testing and I said to myself, "I will come back to it latter...".

I was almost done when my torrent software notified me that a movie just finished downloading.
Also I started to feel hungry...  I wanted to go make lunch and enjoy the movie. "Let's continue with the practice another day..." I said to myself.

After making a sandwitch I came back to my laptop with the intention of watching the movie, but my eclipse IDE was still open. And that line that eCobertura painted red, was still there looking at me:


Suddenly it started talking to me and we had a very interesting conversation:

Line 43(In a thretening tone): "Psss!... hey you!..."

Djordje: "Are you talking to me?"

Line 43: "Do you see somebody else in the room? Yes, i am talking to you" 

Djordje: "Who do you think you are taliking to like that?"

Line 43: "I am a piece of untested code in your software. If you are adding code coverage I also have the right to get some."

Djordje: "Why should I unit test you? You are just a piece of old legacy nobody cares about"

Line 43: "You are such a dumb ass, you don't get it!"

Djordje: "Get what? Leave me alone I want to enjoy my sandwitch and watch my pirate movie. Don't make an scene because I will close the IDE and I will not practice with this program never again"

Line 43: "Ok, ok... take it easy! I just want to help you. Please, let's make a deal."

Djordje: "What deal?"

Line 43: "Just spend 5 more minutes trying to unit test me and I will teach you something important."

Djordje: "Fine, just 5 minutes. This better be good, because I am very hungry"

Poor Line 43, probably it just wanted to talk to somebody. What can I learn about TDD from such a simple line of code?  Anyway I decided to make it's wish come true and paint it green with eCobertura. This is what I did:

   private PrintStream originalConsoleOutput = new PrintStream(System.out);  
   @Before  
   public void setUpStreams() {  
     System.setOut(new PrintStream(outContent));  
   }  
   @After  
   public void cleanUpStreams() {  
     System.setOut(originalConsoleOutput);  
   }  
      @Test  
      public void  
      when_the_process_is_complete_show_a_message  
      ()   
      {
           //..   
           statistics.process();  
           assertEquals("Processing completed!!!\n", outContent.toString());  
      }  

Basically  what I did was just asserting that the console output is the same that what the println() command has in its argument. The process() method is where Line 43 was, so its content will go to the console when statistics.process() gets executed. At the end the method @After will restore the console output to the original stream that was previously saved.


Djordje"I painted you green. Are you happy now?"

Line 43"Thank you very much!....Thanks, thanks.... I am so happy now other lines of code will not look me over the shoulder or whisper to each other. They use to say _There is Line 43, did you know that the developer who created it was drunk... I can now walk onto the compiler with my head up..."


Djordje: "Whatever!, You are green, please just be quiet. Are you leaving me alone now?..."

Line 43: "Yes I will leave you alone, bye bye..."

Djordje: "Hey wait a second!... You told me that you would tell me something important if i get you green. What is it?"

Line 43: "Sorry I almost forgot."

Djordje: "Spit it out!"

Line 43:  "Many times when working in legacy software, developers use the so called _poor man technique. They fill the code with print commands to see the contents of the objects, the problem is that they often forget to remove them. But other times there are other print commands that are valid and really are meant to be there. In occasions, it is hard to distinguish what should be tested and what should not be. The rule is: If your application outputs valid information to the console and this is the only way you can test it, then it is correct to do it. But if you can avoid testing the console or other UI's by testing some related methods(sometimes in controllers), then you don't need to test the UI's. Remember that UI's, databases, frameworks and others... should be considered just addons, to our business layer(which at the end of the day is what provides the real business value)." Djordje: "Aaaaghhh... I hate you!"

Line 43"But why?"

Djordje: "My sandwitch is cold!"

Thursday, 21 February 2013

SVN merge operations in eclipse


When in source control slang when we talk about “merge” we refer to the act of applying specific software changes from one version into another.
“Merge” is a very important operation when working in large projects and version control tools such as subversion are of great help to the developers(I feel confident enough to say that today without this tools it would be almost impossible to work in a large scale project).
In this post I would like to describe just one of the many scenarios where “merge” is often used in real life and how we can perform this operation with the eclipse IDE:

Scenario example:
-Team Lead: Djordje, I was informed that the last bug fix will not just go into our next release, to the pre-production environment, we will also need to apply those changes to one of our older branches.

-Djordje: We have this fix currently in preproduction so you want to apply it also to a different branch? Why is that?

 -Team Lead: Yes, one of our principal test engineers think that something might remain untested and he would like to write some more tests, since those test were initially not part of our regression test plan, we don’t want to include them  to our trunk until they are approved by a business analyst, so what we are going to do is apply the changes to a separate branch test and merge back once the testing is complete and approved.

-Djordje: Understood, just give me the details of the branch where we want to perform the testing, I will prepare the environment for the test engineer.

-Team Lead: You will have to this in the support branch 5.6
-Djordje: Thanks, I will let you know when it is ready.




So the instructions were very clear, we will need to take the changes I did commit the other day into the pre-production environment and merge them to the support branch 5.6.
The first step is to make sure that eclipse is configured to use the merge implementation from our source control provider. For that we will just go to the Preferences menu and find Diff/Merge under the SVN option.


Since we use maven as a building tool, we will right click on the root of the project or the root module(where the parent pom.xml is) and find the merge option.



In this menu, make sure that in the “From:” field you select the path to the place where the changes are and in the “To”, place the destination branch.


When you click on the “Select…” option in the top, you will be able to pick the revision that contains your changes.

Note: You will notice that the revision number appearing on the field will be  below the one you selected. This will allow the merge operation can see the changes.

Now the task is completed the only thing needed is to commit the changes made to the branch.
When the engineer in our example finishes with the testing, the new tests can be merged back into the main development branch(trunk), performing the exact same operation but this time from the branch into the trunk.

Just for finishing this post, I would like to mention that in many occasions the terminology might get us confuse in the workplace and many people(often not technical), refer to this operation as a patch.
From my point of view, a patch is something different(Soon in a separate post I will talk about how to perform a patch).