Welcome

Please contact me (Phil Haack) at here with any errors, problems, and/or questions.

To learn more about the application, check out the Subtext Project Website.

Powered By:

Syndication

Blog Stats

Bloggers (posts, last update)

Latest Posts

Moving again

Due to a change in jobs I'm moving my weblog again.

I had some problems exporting my old blogposts so my old blogposts will be staying here. You can find my new weblog over here: http://blog.mendeltsiebenga.com

posted @ 8/16/2008 10:23 PM by Mendelt Siebenga

Bugs!

http://buglabs.net/, one to watch on the ubiquitous computing front.

posted @ 3/27/2008 6:17 PM by Michalis Sarigiannidis

Visual Studio Gallery

I and my colleagues are always very, very critical of our IDE's. There's always something missing! - or crashing, but that's another story. For those of you out there who like their Add-ins as much as I do, Microsoft has set up the Visual Studio Gallery.

What I like about it: You can actually find some useful stuff there, like the PowerCommands for Visual Studio 2008. One of the commands actually allows you to copy a project, and paste it as a reference to another project in the same solution... Not exactly magic - but useful, nevertheless.

What I don't like about it: Not everything is free. For whatever reason, commercial and open-source stuff mixed together on the same website has never worked for me.

posted @ 3/16/2008 12:58 PM by Michalis Sarigiannidis

How To: Silverlight in ASP.NET Controls

Here's how to put Silverlight in ASP.NET Controls
Extreme ASP.NET: Encapsulate Silverlight with ASP.NET Controls

posted @ 3/16/2008 10:04 AM by Michalis Sarigiannidis

CodeProject: WPF Diagram Designer

Here's an interesting WPF tutorial in three parts:

posted @ 3/16/2008 9:56 AM by Michalis Sarigiannidis

Sudoku solver web service

I created a sudoku solver using candidate elimination together with back tracking. That in itself is quite nice, but I also exposed the solver to the world in the form of a web service. What does that mean?

If you go to this url:
http://82.93.220.122:8080/SudokuWS/ws?wsdl
You will be able to download the wsdl file describing the webservice. It describes the sudoku soap message you have to send and the soap message you will get back. Using many tools you can create a client to use this web service or use a general purpose web service viewer.

If you send this soap message:

   1: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ws.sudoku.enigmatry.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   2:   <soapenv:Body>
   3:     <q0:sudoku>
   4:       <row>
   5:         <cell>0</cell>
   6:         <cell>0</cell>
   7:         <cell>4</cell>
   8:         <cell>7</cell>
   9:  
  10:         <cell>9</cell>
  11:         <cell>0</cell>
  12:         <cell>6</cell>
  13:         <cell>0</cell>
  14:         <cell>0</cell>
  15:       </row>
  16:  
  17:       <row>
  18:         <cell>0</cell>
  19:         <cell>0</cell>
  20:         <cell>0</cell>
  21:         <cell>0</cell>
  22:         <cell>0</cell>
  23:  
  24:         <cell>0</cell>
  25:         <cell>0</cell>
  26:         <cell>0</cell>
  27:         <cell>4</cell>
  28:       </row>
  29:       <row>
  30:         <cell>0</cell>
  31:  
  32:         <cell>2</cell>
  33:         <cell>9</cell>
  34:         <cell>0</cell>
  35:         <cell>0</cell>
  36:         <cell>0</cell>
  37:         <cell>0</cell>
  38:  
  39:         <cell>8</cell>
  40:         <cell>0</cell>
  41:       </row>
  42:       <row>
  43:         <cell>0</cell>
  44:         <cell>1</cell>
  45:         <cell>0</cell>
  46:  
  47:         <cell>0</cell>
  48:         <cell>4</cell>
  49:         <cell>0</cell>
  50:         <cell>0</cell>
  51:         <cell>0</cell>
  52:         <cell>8</cell>
  53:  
  54:       </row>
  55:       <row>
  56:         <cell>0</cell>
  57:         <cell>3</cell>
  58:         <cell>0</cell>
  59:         <cell>0</cell>
  60:         <cell>0</cell>
  61:  
  62:         <cell>0</cell>
  63:         <cell>0</cell>
  64:         <cell>5</cell>
  65:         <cell>0</cell>
  66:       </row>
  67:       <row>
  68:         <cell>4</cell>
  69:  
  70:         <cell>0</cell>
  71:         <cell>0</cell>
  72:         <cell>0</cell>
  73:         <cell>2</cell>
  74:         <cell>0</cell>
  75:         <cell>0</cell>
  76:  
  77:         <cell>3</cell>
  78:         <cell>0</cell>
  79:       </row>
  80:       <row>
  81:         <cell>0</cell>
  82:         <cell>8</cell>
  83:         <cell>0</cell>
  84:  
  85:         <cell>0</cell>
  86:         <cell>0</cell>
  87:         <cell>0</cell>
  88:         <cell>5</cell>
  89:         <cell>7</cell>
  90:         <cell>0</cell>
  91:  
  92:       </row>
  93:       <row>
  94:         <cell>2</cell>
  95:         <cell>0</cell>
  96:         <cell>0</cell>
  97:         <cell>0</cell>
  98:         <cell>0</cell>
  99:  
 100:         <cell>0</cell>
 101:         <cell>0</cell>
 102:         <cell>0</cell>
 103:         <cell>0</cell>
 104:       </row>
 105:       <row>
 106:         <cell>0</cell>
 107:  
 108:         <cell>0</cell>
 109:         <cell>1</cell>
 110:         <cell>0</cell>
 111:         <cell>6</cell>
 112:         <cell>8</cell>
 113:         <cell>2</cell>
 114:  
 115:         <cell>0</cell>
 116:         <cell>0</cell>
 117:       </row>
 118:     </q0:sudoku>
 119:   </soapenv:Body>
 120: </soapenv:Envelope>
 121:  

 

You will receive this message in return, with the solved sudoku:

   1: <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
   2:   <env:Body>
   3:     <sudokuResult xmlns:ns1="http://ws.sudoku.enigmatry.com/">
   4:       <solved>true</solved>
   5:       <sudoku>
   6:         <row>
   7:           <cell>8</cell>
   8:           <cell>1</cell>
   9:  
  10:           <cell>3</cell>
  11:           <cell>6</cell>
  12:           <cell>7</cell>
  13:           <cell>4</cell>
  14:           <cell>9</cell>
  15:           <cell>2</cell>
  16:  
  17:           <cell>5</cell>
  18:         </row>
  19:         <row>
  20:           <cell>5</cell>
  21:           <cell>6</cell>
  22:           <cell>2</cell>
  23:           <cell>1</cell>
  24:  
  25:           <cell>3</cell>
  26:           <cell>9</cell>
  27:           <cell>8</cell>
  28:           <cell>4</cell>
  29:           <cell>7</cell>
  30:         </row>
  31:  
  32:         <row>
  33:           <cell>4</cell>
  34:           <cell>7</cell>
  35:           <cell>9</cell>
  36:           <cell>5</cell>
  37:           <cell>2</cell>
  38:  
  39:           <cell>8</cell>
  40:           <cell>6</cell>
  41:           <cell>3</cell>
  42:           <cell>1</cell>
  43:         </row>
  44:         <row>
  45:           <cell>7</cell>
  46:  
  47:           <cell>8</cell>
  48:           <cell>4</cell>
  49:           <cell>3</cell>
  50:           <cell>1</cell>
  51:           <cell>6</cell>
  52:           <cell>2</cell>
  53:  
  54:           <cell>5</cell>
  55:           <cell>9</cell>
  56:         </row>
  57:         <row>
  58:           <cell>9</cell>
  59:           <cell>5</cell>
  60:           <cell>1</cell>
  61:  
  62:           <cell>4</cell>
  63:           <cell>8</cell>
  64:           <cell>2</cell>
  65:           <cell>3</cell>
  66:           <cell>7</cell>
  67:           <cell>6</cell>
  68:  
  69:         </row>
  70:         <row>
  71:           <cell>3</cell>
  72:           <cell>2</cell>
  73:           <cell>6</cell>
  74:           <cell>7</cell>
  75:           <cell>9</cell>
  76:  
  77:           <cell>5</cell>
  78:           <cell>4</cell>
  79:           <cell>1</cell>
  80:           <cell>8</cell>
  81:         </row>
  82:         <row>
  83:           <cell>6</cell>
  84:  
  85:           <cell>3</cell>
  86:           <cell>7</cell>
  87:           <cell>9</cell>
  88:           <cell>4</cell>
  89:           <cell>1</cell>
  90:           <cell>5</cell>
  91:  
  92:           <cell>8</cell>
  93:           <cell>2</cell>
  94:         </row>
  95:         <row>
  96:           <cell>1</cell>
  97:           <cell>9</cell>
  98:           <cell>8</cell>
  99:  
 100:           <cell>2</cell>
 101:           <cell>5</cell>
 102:           <cell>3</cell>
 103:           <cell>7</cell>
 104:           <cell>6</cell>
 105:           <cell>4</cell>
 106:  
 107:         </row>
 108:         <row>
 109:           <cell>2</cell>
 110:           <cell>4</cell>
 111:           <cell>5</cell>
 112:           <cell>8</cell>
 113:           <cell>6</cell>
 114:  
 115:           <cell>7</cell>
 116:           <cell>1</cell>
 117:           <cell>9</cell>
 118:           <cell>3</cell>
 119:         </row>
 120:       </sudoku>
 121:     </sudokuResult>
 122:  
 123:   </env:Body>
 124: </env:Envelope>

 

Pretty cool, isn't it? If you can write a nice looking frontend for this webservice, in the form of another website, or a desktop client app, please drop me an email. I would really love to see it!

posted @ 3/14/2008 5:04 PM by Arjan Seesing

Subversion opzet en versienummering

This article is in dutch, sorry...

Subversion heeft een standaard structuur voor elke repository die er zo uit ziet:

repo1

De root is een url, en die kan niet hoger worden opgevraagd, bijvoorbeeld: https://192.168.1.17:8443/svn/javaTraining

Onder de trunk worden de nieuwste sources ingecheckt. Als dat 1 project is kunnen de directories en files onder de root van het project hier meteen ingezet worden. Zijn het meerdere projecten, dan moeten de roots van de projecten hier ingezet worden. Dit is alleen zo gewenst als de projecten ook echt afhankelijk van elkaar zijn en niet worden gedeeld tussen verschillende projecten, dan moeten die in hun eigen repository worden opgeslagen.

Versienummering

Naast de build nummers worden er door mensen bedachte versie nummers gebruikt. De ideale situatie is dit. Er is een major en een minor nummer. Het minor nummer wordt bij elke (test) release met 1 verhoogd. Het major versienummer wordt verhoogd indien er een grote aanpassing van de code plaats vindt of wanneer er aan 2 versies tegelijk moet worden gewerkt. Dat is bijvoorbeeld bij het ingebruik nemen van de software door de klant met de benodigde bugfixes die soms nodig kunnen zijn en de ontwikkeling van een nieuwe versie. Als dat het geval is dan vind de ontwikkeling van de nieuwe versie plaats in de trunk en de bugfixes in de andere versie in de branch. Het maken van de branch kan uitgesteld worden tot dat er daadwerkelijk een bug optreed die opgelost moet worden in een huidige versie terwijl er ook wordt ontwikkeld aan een nieuwe versie.

De naam van de branch bevat alleen het major versie nummer. Als er een release plaats vindt, dan wordt die neergezet in de tags directory, inclusief het minor nummer.

Voorbeeld

Major versie nummer is: 1.1
Minor versie nummer is: 4
Complete huidige versie is 1.1.4
We vergeten even alle andere vorige versies, dit is de huidige situatie in de repository:

repo2

In de trunk wordt doorgewerkt aan de nieuwe versie, het is nog niet bepaald welke versie dat gaat worden. Maar ondertussen is 1.1.4 wel in productie bij een groot bedrijf en op een gegeven moment vinden ze een bug. Het is makkelijk te verhelpen. De ontwikkelaar die checkt versie 1.1.4 uit van svn en repareert de bug. Tags zijn read-only, dus de fix kan hij niet zomaar inchecken. Hij kopieerd 1.1.4 naar de branches folder in svn en noemt de branch 1.1. En commit zijn code in die branch. Nu ziet het er zo uit:

repo3

Versie 1.1.5 kan gereleased worden naar de klant en iedereen is blij. Als er nu een 2de bug wordt gevonden wordt er een 1.1.6 versie gemaakt van de branch enzovoort. Deze bugs moeten ook worden opgelost in de versie in de trunk! Anders heeft een volgende nieuwe versie ineens weer oude bugs. Dit kan vaak makkelijk gedaan worden met behulp van de merge functie of patch functie van svn/Eclipse .

Twee maanden later is de nieuwe versie af waaraan wordt gewerkt in de trunk. En een eerste versie wordt opgeleverd voor de test. Deze versie kan niet major versie 1.1 krijgen omdat er dan gaan oplopende volgorde van features meer aanwezig is. Dus wordt het versie 1.2 of als er hele grote veranderingen zijn 2.0. Laten we het houden op 1.2. De eerste test versie wordt dan 1.2.0, er wordt nog geen branch gemaakt, omdat de trunk nu als branch fungeert:

repo4

Nu bestaan versie 1.2.x en 1.1.x naast elkaar en kunnen afzonderlijk gereleased worden.

posted @ 3/12/2008 5:21 PM by Arjan Seesing

Mission critical HawaiianAir.com website powered by MOSS 2007

Here's another interesting case study,  the migration of HawaiianAir.com to a MOSS-based website.

As these things go, this is another patting-ourselves-on-the-back story - but it's a good one.

posted @ 3/11/2008 9:31 AM by Michalis Sarigiannidis

SharePoint: How Dell Does It

This is one of the more interesting case studies on SharePoint I've seen so far. Dell has put tens of TBs on SharePoint.

posted @ 3/11/2008 9:26 AM by Michalis Sarigiannidis

Hans Rosling

When people hear Web 2.0, they think Twitter, Facebook, Yahoo! Pipes, and Microsoft's PopFly.

When I hear Web 2.0, I think Hans Rosling talking at TED, and GapMinder.

Now, I could spend a lot of words to explain why, but why talk when there's video to see and interactive media to play with.

posted @ 3/11/2008 9:12 AM by Michalis Sarigiannidis

Microsoft SharePoint Products and Technologies Team Blog

Microsoft's official SharePoint Blog. I should point out that Microsoft does not use SharePoint for it's blogs on MSDN.

Microsoft SharePoint Products and Technologies Team Blog

posted @ 3/11/2008 8:54 AM by Michalis Sarigiannidis

L'Oreal doing SharePoint

posted @ 3/11/2008 8:49 AM by Michalis Sarigiannidis

To blog or not to blog

A friend recently told me, a lot of people who consider to start a blog do not, because they assume most other people already know what they have to say.

Far be it from me to show any such modesty - but it's a good point.

So, to get things rolling and get used to blogging,

I'll start with the essentials - links, reference material, comments, etc. - and try and build it up to full-fledged technical articles. Baby steps, as they say.

posted @ 3/11/2008 8:38 AM by Michalis Sarigiannidis

My First Web Service

I was interviewed for a project two weeks ago and got accepted soon after. I will be working in Rotterdam to build a new website. The new site will replace the old site, which is not even live yet. This will be my first (or actually second, but first big) project outside the company so although there are many bad smells, I want to see it happen with my own eyes. Bad smells are triggers which tell you the project is crap and will stay crap. What were the smells I smelled:

  • The site which will be replaced is not in operation at this moment
  • The project will probably use old technologies with some buzzwords sprinkled in:
    • old tech:
      • Struts as web framework instead of JSF or even Stripes, or Struts 2.0
      • iBatis as O/R mapper, instead of Hibernate or JPA
    • new tech (= buzzwords):
      • Web Services, but not only to communicate to the outside world, but for use between the front and the back-end inside the same VM!
      • EJB 3, what is the use of EJB 3 if you are using iBatis instead of JPA or Hibernate?

Anyway, EJB 3 might be the only good thing about the whole project. I know EJB 3 quite well at the moment. We will be developing in Oracle JDeveloper, for the Oracle application server and using the Oracle Portal framework. I never heard of Portal before, but they told me that is the reason they will be using Struts. I still have to get a good answer why JPA or Hibernate would be worse than iBatis. And the Web Service idea is completely back wards.

Web Services are intended to expose a certain API to the outside world in a language independent manner so others can use your service. I underlined several words in that last sentence because they highlight the problem I have with using a Web Service inside your own application stack, where you export and consume your own web service at the same time.

Certain API. You expose a certain high level, coarse (not fine grained) API, which is designed to be as easy to use as possible and have the minimum amount of operations possible. This API is hard to change when others start using the web service you are exporting, because they are dependent on it.

Outside world. Your web service is to be used by the outside world. Not by yourself. See the previous argument.

Language independent. Web services can be used and exported in any programming language, programming system and operating system. This is possible because they use XML to define all communications. This means that every time you call a web service, or your webservice is called, you have to generate and decode XML messages. These messages will be send over http connections. All these things cause overhead, which will not be a problem when external parties want to communicate with you, because there is no other easier way, but why would you want to incur all this overhead and other problems inside your own system?

For my Java Business Components certification I learned about web services, but I never wrote one. Some projects I worked on used web services, but I only altered some small things, I never wrote one from scratch. So for this new project I wanted to test myself, can I write a web service?

The Library Web Service

In the last blog post I wrote about a small project setup based on three layers. The back end, the front end, and the interface for the back end, used by the front end. For this web service, I would keep the back end and the interface the same, but I would change the front end. It would not be a website, but web service, which will expose the back end interface.

At first I failed. I tried the standard JBoss 4.2.2, but I could not get it to work. I generated all the proxy and skeleton classes but the web service explorer could not connect to it. And clients I created would fail to connect as well. I tried using Glassfish, the open source application server from Sun. But I had to rewrite all my build scripts. And I could not get my ear file through the verifier, which verifiers the correctness of my ear file. At last I installed another webservice stack for JBoss, the Sun Metro implementation and got a lot further, but I had to generate the proxy classes myself for this stack. I can do that, but the native stack from JBoss can do that during deploy time, so I installed that stack and now my web service finally works correctly.

How did I do it?

I started a new Dynamic Web Project inside Eclipse. In that project I created a new class, called com.enigmatry.library.ws.Library which has a method for each of my library service methods. I only have to annotate this class with the @WebService annotation to make it a web service. I changed the web.xml file so it maps everything to my webservice. Now it looks like this:

   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"
   4:     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   5:     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   6:     id="WebApp_ID" version="2.5">
   7:     <display-name>EnigLibWS</display-name>
   8:     <servlet>
   9:         <servlet-name>LibraryWebService</servlet-name>
  10:         <servlet-class>com.enigmatry.library.ws.Library</servlet-class>
  11:         <load-on-startup>1</load-on-startup>
  12:     </servlet>
  13:     <servlet-mapping>
  14:         <servlet-name>LibraryWebService</servlet-name>
  15:         <url-pattern>/*</url-pattern>
  16:     </servlet-mapping>
  17:     <session-config>
  18:         <session-timeout>30</session-timeout>
  19:     </session-config>
  20: </web-app>

The biggest problem I have (or had) is to reference EJB3 Session Beans from the web layer. I have not found a way to let me locate the EJB3 bean from the InitailContext without specifying an explicit JNDI name with the @org.jboss.annotation.ejb.LocalBinding annotation, which is JBoss specific, so prohibits me from writing a portable ear. In the end I used a JBoss specific deployment descriptor, so I do not have to use the annotation.

Inside the META-INF dir inside the ejb3 jar I added jboss.xml:

   1: <jboss>
   2:     <enterprise-beans>
   3:         <session>
   4:             <ejb-name>library</ejb-name>
   5:             <jndi-name>library</jndi-name>
   6:         </session>
   7:     </enterprise-beans>
   8: </jboss>

Now I can get a reference to the library bean by writing:

   1: Library library = (Library) new InitialContext().lookup("library");

JBoss 5.0 will support the @EJB annotation in the web layer to inject EJB3 Session beans. Other application servers already support this, but JBoss is so much easier to work with. Deploying is just a copy operation instead of calling complex ant tasks with difficult class path definitions.

When I build this war file and use it in my ear file instead (or next to my website war) I can access the webservice definition (the wsdl) by going to this url: http://localhost/war-name/?wsdl. This wsdl is generated at deploy time by the JBoss native web service stack. With other stacks you have to use tools to generate this file. This file can now be used to build client applications which can talk with the created web service.

The Client

I wrote a simple proof of concept client, just to see it working outside the web service explorer. I created the required proxy files from the wsdl by using the wsimport tool from JBoss inside my build script, this is my ant target:

   1: <target name="create-proxy" description="Create local port proxy">
   2:     <taskdef name="wsimport" classname="com.sun.tools.ws.ant.WsImport2">
   3:         <classpath>
   4:             <path refid="cp"/>
   5:         </classpath>
   6:     </taskdef>
   7:     
   8:     <mkdir dir="${dist.dir}" />
   9:     <mkdir dir="${build.dir}" />
  10:     <wsimport 
  11:         wsdl="${conf.dir}/library.wsdl" 
  12:         destdir="${build.dir}" 
  13:         sourcedestdir="${src.dir}" 
  14:         keep="true" 
  15:         extension="false" 
  16:         verbose="true" 
  17:         wsdlLocation="http://localhost:8080/EnigLibWS/library?wsdl" 
  18:         package="com.enigmatry.library.ws">
  19:     </wsimport>
  20: </target>

This creates several files which can then be used to talk with the web service. The only code I had to write is this:

   1: public static void main(String[] args) {
   2:     try {
   3:         LibraryService service = new LibraryService();
   4:         System.out.println("Retrieving the port from the following service: " + service);
   5:         Library library = service.getLibraryPort();
   6:         System.out.println("Invoking the getVersion operation on the port.");
   7:         String response = library.getVersion();
   8:         System.out.println(response);
   9:         BookArray books = library.searchBook(new SearchBookVO());
  10:         for(Book book : books.getItem()){
  11:             System.out.println(book);
  12:         }
  13:     } catch(Exception e) {
  14:         e.printStackTrace();
  15:     }
  16: }

As you can see, I create a new LibraryService object (line 3)  and get the port from this service to get a proxy object (line 5) which I can use to call the web service. All these objects are generated by the wsimport tool. Then I can just call the web service as it is my normal interface (line 7 and 9).

There are some things different though. I could not use a Set<Book> as a return type in my web service, so I used a Book[], but as you can see in the client, the method will return a BookArray type (line 9). Which returns a List<Book> if you call getItem() on it (line 10).

It is probably possible to change the generated files so it returns a Book[] directly, but that will involve a lot of hand coding.

posted @ 3/6/2008 6:29 PM by Arjan Seesing

One way to start a simple layered project

"Can you please set up a default Java development environment for us?", my boss asked me a while ago.  That's a pretty difficult question, because where I come from, everyone is allowed to set up his or her own environment. Some people use NetBeans, others use a old version of Eclipse while others use the newest beta version of Eclipse with all possible plugins installed. Everyone should be able to customize his or her tools as they see fit. But I do agree, there should be some consistency across developers and projects.

So I started to set up a new fresh Java project with several goals in mind:

  • Create a play environment to learn web development and server development for the java certifications, mostly the web components and business components certifications.
  • Make a setup which can be used as a template for future projects.
  • Test my ability to start a project from scratch, which I have never done before.
  • Test the tooling of Eclipse to help me do it.

The Project

I decided to start a small web application which used a Stripes front end, a JPA/Hibernate domain model and an EJB3 backend. As I said, I never started a project before, so I asked Eclipse to help me. The normal way to organise these things in Eclipse is to have a separate project for each layer in the same workspace. I created these projects:

  • A Dynamic Web project
    Holds the webpages and the view code logic. Simple applications can be implemented in only this project.
  • An EJB project
    Holds the business layer of the application, the Enterprise Beans, is completely independent of the view layer.
  • An EJB Client project (gets created by the EJB project)
    Defines the interface of the business layer used by the view layer. Also contains the JPA Entity classes and the value objects, which are used in the interface of the business layer.
  • An Enterprise Application Project
    Does not contain any code, but wraps the other 3 projects together in an .ear file to be deployed on a J2EE application server.

This setup compiles and packages the files in the correct manner and deploys it to the J2EE server configured in Eclipse. This is all nice and simple, but this removes the ability for a developer to set up his or her own environment because the build process is now dependent on Eclipse, the environment. So I created an Ant build script to build, package and deploy the whole project without Eclipse. I also could have used Maven, but my experience with Maven is that it is slow to build and hard to configure and even harder to track down problems when they exist. Also missing dependencies, old online repositories and different versions causing problems made me choose for Ant.

Building and Deploying

I think the manner Eclipse chooses to setup of these kind configurations is pretty smart. To be able to build another kind of web front on the same backend, one only has to switch out the web project, tweak the ear project to package the new web project and everything should work. It is also possible to build a Swing client or some webservice, all using the same backend. So I tried mimic this approach in the ant script.

Short interlude: an ear file is an enterprise archive, which contains other archives which when combined consist of an application which can run on an application server, like JBoss, Geronimo, Glashfish and others. The other archives are jars and wars, which are Java archives or web archives. A Java archive contains java classes and configuration files, and can contain enterprise java beans of various sorts and normal Java code. Web archives contain web pages in the form of servlets, which can be a jsp pages or other static content and can also include normal Java classes.

Each project has its own ant script which builds the project and places an .jar or a .war file in the 'dist' folder of the project. The ear project has a special ant script which invokes the other scripts and packages the created .war and .jar files in an .ear file. The ear script decides on which projects to call (so the developer can rename the projects or check them out to a different directory) on a '.ant-global.properties' file, which should be present in the workspace directory. This file also holds a reference to the JBoss instance, so the ear file can be deployed by the script as well.

Importing Libraries in Eclipse and Ant

Applications build on a J2EE platform depend on many libraries. This are jar files which hold common code used by the system, for example logging, Hibernate and Stripes. In the past, projects had different ways to acquire the correct libraries used by the application. When Maven was used, they would let Maven handle these dependencies, which would work correctly, until the repository was not available anymore. Also checking these dependencies would take ages every time the project would be build. Other projects used Ant to checkout the used libraries from a special library project which would hold all the libraries for each project.
Eclipse uses the reference to the application server to reference all its libraries. So I realized I don't need to download 20+ jar files in my build script somehow, I can use the ones in the JBoss server. And I also have a reference to the JBoss environment for the deploy feature of my script. Now I only have to manage the libraries which are not bundled in application servers, which are not many. So far I have the JSTL core library and the Stripes library in the application, and for now I just check those in the repository so they are downloaded and managed directly with the project. Only problem is duplicate entries of the same jar file in many future projects, but as disk space becomes cheaper almost every minute, this won't be a problem for now, or maybe ever.

posted @ 2/27/2008 3:54 AM by

Adopting unit-testing

Jacob Proffitt has a two posts here and here on how the emphasis on TDD instead of plain unit testing is harming the adoption of unit testing.

His basic assumption (if I understood him correctly) is that people would adopt unit testing faster if unit testing proponents told them doing it without TDD is an option too.

This sounds logical if it were indeed easy to unit test without TDD. I think it's not

I found this out the hard way. Not because the testing is hard but because the code I (and some of my coworkers) used to write was highly test-resistant. I almost stopped unit testing because it took too much time to do and it took too much time to maintain the tests. The problem was that there were too much dependencies between parts of my code. Tests would be hard to write because I had to write a lot of setup code. And existing tests would fail all the time when seemingly unrelated parts of the system changed.

The solution has been well known for decades. You have to reduce coupling and increase cohesion in your code. I knew this but this is hard to maintain without immediate feedback on the quality of your code. That's where TDD comes in. By writing tests before you write code you get feedback on the testability of your code before you've written a single line of it. You're forced to think about how to call the code before it's written.

I know that I'm making an implicit assumption here too. I'm saying that testable code = high quality code. But my experience tells me this is indeed true.

If someone were to ask me how to start unit testing. I'd tell him to start using test-first on new code. Usually domain logic is easy to decouple so it's easy to test. Testing code that has been written code-first is advanced unit-testing and it's the easiest way to have people who are new to unit-testing stop doing it forever.

posted @ 2/24/2008 1:56 PM by Mendelt Siebenga

Refactoring the Template method

In this previous post I mentioned that I'm not that impressed with the Template Method pattern. If you let them grow too big they beimagecome unreadable, untestable chunks of code that are tucked away in protected methods in subclasses that you don't call directly.

This is a simplified version of the class-diagram I showed in my last post. The main code-smell that caught my attention were the protected methods in the subclasses. The ReadHeader and ReadLine methods are only called by the ReadFile method. That's a good argument to keep them protected. But I'd like to test them separately.

Usually when you want to make code public just for testing it's a big sign the code is in the wrong class and it's refactoring time. The ReadHeader and ReadLine method shouldn't be in the TabularFileReader class but they should be in their own class hierarchy. This way they can be tested separately but it will still be encapsulated neatly because the LineReader property of the TabularFileReader is private so the calling code can't access the LineReader that's used to read the file. Another benefit is that I could get rid of a nasty code duplication between the ReadHeader and ReadLine function. The LineReader classes only know about lines and splitting them up into fields. The TabularFileReader knows about headers and fieldnames.

imageThe code is also potentially more reusable. You can use the LineReaders separate from the TabularFileReader.

So let's recap... what have we done. The variation in the class that contained the Template Method has been refactored into a separate class hierarchy. This makes things more testable. The LineReader has become a strategy pattern. The TabularFileReader can be injected with the right strategy to make it do whatever we want.

When you want to know what's happening the code get's a lot more readable. You're calling the TablularFileReader directly so when you click 'go to definition' from your calling code you can at least see the ReadFile method.

posted @ 2/17/2008 8:36 PM by Mendelt Siebenga

The Heisenbug

A bug that dissapears when one attempts to probe or isolate it.

Found frequently in multithreaded code.

posted @ 1/23/2008 3:26 PM by Mendelt Siebenga

Oh no! it's a Template method.....

One of the patterns I used to use a lot was the Template-pattern. Wikipedia has a nice article on the template pattern here if you want a quick refresher on what I'm talking about. This weekend I've been digging through some code I wrote about a year ago where I used this pattern a lot and I found it hard to read and hard to test.

The template method is a method that lives in an abstract base-class that calls a couple of abstract functions to do what it has to do. Those functions are then implemented differently in the children of the base-class to make a couple of classes that do the same thing differently. I've got a simplified example where I use it to read tabular data from comma delimited (csv), position delimited (pdv) and xml files.

 image

The first problem was testability. The subclasses contained some private functions that I wanted to test. I could make them public to test them but then client code would be able to mess with the implementation of reading the file. The whole reason for using the template method was to abstract this away from the calling code.

The second problem was readability. Actually I found two problems here.

The first problem is that when you look at code using a CsvReader this pattern makes it harder to find out what it's doing. You expect this class to handle Csv-reading but it only handles simple subtasks, the pattern obscures the higher level logic by putting it out of sight in a base-class.

My code got even messier because I had some code I could reuse between the CsvReader and the PdvReader. These two worked with simple textfiles. But not the XmlTableReader. It made no sense to push this code up to the base-class because of the XmlTableReader. I could put it in an external class or I could add a layer in the inheritance tree above the CsvReader and PdvReader.

image

This looks like a neat solution. But in practice this makes the code even less readable. I've seen template method implementations with as much as 4 levels of inheritance that were completely unreadable.

So how do we make this better? I'll give you a hint. It involves dependency injection and the Strategy pattern. More on this in my next post.

posted @ 1/13/2008 1:58 PM by Mendelt Siebenga

Dragging enums into the OO world

   1: public enum Weekday {
   2:     Monday,
   3:     Tuesday,
   4:     Wednesday,
   5:     Thursday,
   6:     Friday,
   7:     Saturday,
   8:     Sunday
   9: };

 

What's wrong with this code?

This looks like C# but actually you could already do this in C in the 1970's. In those days the ability to define your own types was a novel idea but in today's object-oriented languages we expect a bit more, like extensibility or the possibility to inherit from types.

What if we want to extend our Weekday-type with a method to check for weekends? Or a 'Next' and 'Previous' method? Usually these will end up as static methods in some Utility class. Smelly! I want to be able to do this:

   1: if( Weekday.Saturday.IsWeekend() ) {
   2:    ...
   3: }

Let's try again. This time with class :-)

   1: public class Weekday {
   2:     public static Weekday Monday = new Weekday();
   3:     public static Weekday Tuesday = new Weekday();
   4:     public static Weekday Wednesday = new Weekday();
   5:     public static Weekday Thursday = new Weekday();
   6:     public static Weekday Friday = new Weekday();
   7:     public static Weekday Saturday = new Weekday();
   8:     public static Weekday Sunday = new Weekday();
   9: }

Now why exactly is this better? It looks like a lot more work.

Maybe because you can extend it like this?

   1: public class Weekday {
   2:     public static Weekday Monday = new Weekday();
   3:     public static Weekday Tuesday = new Weekday();
   4:     public static Weekday Wednesday = new Weekday();
   5:     public static Weekday Thursday = new Weekday();
   6:     public static Weekday Friday = new Weekday();
   7:     public static Weekday Saturday = new Weekday();
   8:     public static Weekday Sunday = new Weekday();
   9:  
  10:     public bool IsWeekend() {
  11:         // ...
  12:     }
  13:  
  14:     public Weekday Next() {
  15:         // ...
  16:     }
  17:  
  18:     public Weekday Prev() {
  19:         // ...
  20:     }
  21: }

Looks familiar? Take a look at the System.Drawing.Color class.

posted @ 12/15/2007 3:59 PM by Mendelt Siebenga

Introduction

My name is Michalis Sarigiannidis.

I have been working as a software developer and architect since 1998 - but I have been programming as an amateur since 1986. In short, I’ll admit, I’m a geek. I am also one of the founders of Enigmatry (shameless plug: for more information, please visit our Website), and the company strategist.

I’ll be writing about software development, focusing on the work I am doing now, but also about trends and developments in the industry. I’ll also be writing about other stuff I like, such as obscure or little known programming languages, upcoming technologies, and philosophy of the mind – to mix it up a little.

A few things to know about me
  • I am addicted to software and books
  • I love bleeding-edge technology
  • Given the chance, I will argue with you about anything and everything.

posted @ 12/7/2007 3:23 PM by Michalis Sarigiannidis

Hello world!

Hello world!

posted @ 12/5/2007 8:32 AM by Blog Author

Mendelevium has moved

And you're on the right page, the new one

My employer, , has been kind enough to offer me some space on a fast server to host my weblog. So here it is; Mendelevium without 30 second page-loads.

I hope more Enigmatry-bloggers will follow.

posted @ 12/2/2007 2:49 PM by Mendelt Siebenga

Mixins in C#

Now that Visual Studio 2008 and C# 3.0 is out all the talk in the blogosphere is about what is still missing and what we want in the next version. And mixins are high on the list.

Mixins could be implemented elegantly by extending generics so you can use them for inheritance like this;

   1: class Mixin<T> : T {
   2:     public void MixinMethod() {
   3:         // ...
   4:     }
   5: }

By allowing to inherit from T you can use Mixin to extend any none sealed type like this

   1: var mixinString = new Mixin<string>;
   2: mixinString.MixinMethod();

It's a pity Anders Hejlsberg doesn't read my blog.

posted @ 11/27/2007 5:39 AM by Mendelt Siebenga

Why VB.Net XML Literals are not a good idea

The days of programming in just one language are long gone. To use the power of modern programming environments your code gets interlaced with SQL, XML, XPath, XQuery, Regex, HQL and more. Usually this doesn´t help make your code more readable. All the ´alien´ code lives in strings so it won´t benefit from autocompletion and syntax highlighting offered by modern ide´s and more importantly... no checks by the compiler. Any mistakes you make won't show up until you (or a customer) runs the code.

Microsoft has 'solved' this problem for Xml by making Xml part of VB.Net with Xml literals. You can now sprinkle your code with Xml. While this seems nice I think it only solves part of the problem in a bad way. Productivity won't increase by giving developers the tools to write a lot of unreadable code really fast.

For C# I'd like a more extendable solution for this problem. There's no problem with storing code in strings as long as the editor and the compiler know what to expect. The only extension to the language should be a mechanism to let programmers express what should be inside a string. That leaves the door open for your editor and compiler to call plugins to check the code without blurring the lines between languages.

posted @ 11/21/2007 5:56 PM by Mendelt Siebenga