Archive for the ‘springframework’ category

After the Spring Storm

2008/09/25

Few days ago, I have received an email asking to attend the SpringSource conference and offering $300 discount if I decide to buy before end of month. The timining was pretty ironical, considering the recent contraversy about SpringSource Entreprise Maintenance policy change. The was a heated discussion on TheServerside.com and even FAQ was compiled by Rod Johnson to explain the whole thing.

So what is the issue: SpringSource, commercial entity behind community driven Spring Framework decided to capitalize on the investment and push the community toward paid service suport contract. Whether or not it was related to funding round and VC’s entering the game, is not important. Unfortunately, the terms were not really well explained and SpringSource did initially very poor job explaining and communicating the actual change. The community overreacted and lot of people started to call for code fork, project Summer or similar – or switching to different framework.

What the change really means is that maintenance releases will not be available (as binary, official downloads) after 3 months, unless you pay for the support. It means that using new policy after let’s say release 2.0, only for three months everybody could download binary distributions of 2.0.1, 2.0.3 etc. If at the end of month 3 you would need fixes in the 2.0 branch, you would be on your own. The source code repository with 2.0 branch would still be available, with fixes committed (see later) but without tags (or labels) and certainly without pre-packaged download of 2.0.4, 2.0.5. You could compile the actual head of the 2.0 branch yourself, but it would not be clear what version you actually run.

This is actually not such terrible limitation as it may seem. Maintaining old code base and backporting the changes from trunk into fixes in branches is lot of work, requires testing and so on. SpringSource did invest a lot into the codebase and as commercial entity provides service to the users. The release management and software maintenance is slightly different type of work that developing new great release, and I can imagine that there are even less contributors and volunteers for this (seldom appreciated) kind of work. Multiply that with many branches and you’ll see the magnitude of the problem.

What did SpringSource do wrong, in my opinion is that they are taking away something that was available for the community for free and that created lot of negative sentiment. There are two ways how to push people to pay for free service – and cutting unless you pay is wrong one. Right way is to offer more on top of what is available for free, something that has value specifically for enterprise clients. There are several areas where there is a need: more and much better samples, template applications, guides, tutorials. Their availability has huge value for customers in saving development time and better quality of the products using the Spring platform.

There are several technical subtleties that are in open: the FAQ says that the changes and fixes from trunk will be available in the maintenance branches, but does not say when. Delaying changes can be powerful argument … Lack of tags in public repository also implies existence of private repository with these tags – how else could the SpringSource build the “supported releases”. The existence of two repositories in project (unless you use distributed VCS, of course) is often starting point of splitting project to payware and limited “community edition”. I hope this will not happen to Spring.

The most unfortunate impact of the maintenance policy decision may be for the Spring based opensource projects, that helped a lot to establish acceptance of the platforms over last few years. Dilema of facing either cascading changes of permanent upgrades just to keep in sync with latest trunk version, or permanently monitoring the branch to see which of the changes are important – in absence of “official” maintenance release with defined bug fixes etc can be an issue for many projects. I hope SpringSource will find workarounds and solutions for these.

Despite of that, forking Spring would be very bad idea. The very last thing enterprise Java needs is another framework that is esentially same or very similar than existing one. SpringSource employs brilliant engineers, Spring community also has great contributors – what is the point of splitting the forces when there is no architectural disagreement, the issue is “just money” ?

Forking also does not solve the core problem: who will be providing the community service of maintaining and building the old releases. The maintainers of Summer codebase (or whatever the name of Spring forked successor would be) will face the same dilema – choose between working for free forever or finding way how to employ enough manpower to keep the balls rolling.

I would recommend that instead of forking Spring codebase, whoever feels like it, try instead to fill in the gap and provide the “inofficial official” builds, a “community maintenance releases” as counterpart and alternative to official SpringSource maintenance releases for enterprise (== paying) customers. This would actually help the project and all projects that depend on it much more than asking them to switch.

It would also not hurt SpringSource – I am convinced that they would loose very little revenue (if any) because of that. It has been done (Centos vs RHEL). If my project would be based on Spring platform and not on commercial Java server (which it is not) and the support cost would be reasonable (which it IMHO is), I would happily pay for priviledge to have access to the people of Juergen Holler’s caliber (and many others).

Let’s face it, folks: when it comes to support and software maintenance and similar less attractive areas of our profession, there is definitely no such thing as free lunch …

Versioning with Spring and Ant

2008/03/10

This is post is NOT about version control in the sense of source code control. It addresses the issue how to easily tell which version of the Web application is running as well make sure that the same version is reflected in the snapshots performed by Ant. We have used this approach on several applications and found it quite useful.

The version I talk about is not the automatically generated version from VCS system (such as SVN revision). The version number is set manually.

In every project, we include property file named application.properties, placed at the root of the classpath (next to ‘com’ directory in the source tree). The content can look like this


app.name = MyApp
app.version = 0.5.4
app.info = User authentication implemented

This property file will be available to Java code because of its location in classpath. Our build.xml file ususally starts with few includes like this



    
    ...
    

We try to load first the property files named after the computer. This way we can easily address differences in e.g. Tomcat locations, pathnames to libraries etc. This is very useful if not all team members have identical development environment – which is almost always the case, as I am on Mac and the others mostly on Windows :-). The environment variable COMPUTERNAME is automatically set for you if you are on Windows, for Mac/Linux users all you need is an export in your .bashrc file.

The second include loads the application properties and makes the ‘app.version’, ‘app.name’ available for Ant tasks. Externalizing the app.name allows reusing same Ant script for multiple project. Here is an example of the task that creates and archive of current source code snapshot using this information:



      
            
            
            
            
            
            
            
            
            
      
    

The DSTAMP and TSTAMP are set in prepare task:



        
            
        
        
    

To access the information from application.properties, we simply add it to the list of message sources:

    
        
            
                messages
                application
            
        
    

This allows to easily display the version number and information as part of e.g. JSP page:


 -
            

For production, I usually still leave the version in the JSP, only include it in HTML comments, so that it does not interfere with the UI but is still accessible by viewing page source.

I usually set version number and info string manually, but it possible to automatically write information about e.g. build date and time of the application and make it a part of the version info. To do that, use the Ant task:



    
        
    
    File test.properties updated at ${DSTAMP} ${TSTAMP}
  

In this case, the value of property app.stamp will be overwritten every time the ‘set_version’ task executes.

iBatis, Date null values and Oracle

2008/03/07

I better blog this before I forget what was the issue :-).

During daily run of unit tests, I started to receive this (very well explained) exception:

org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [17004];
--- The error occurred while applying a parameter map.
--- Check the APPROVAL_TASK.insert-InlineParameterMap.
--- Check the parameter mapping for the 'scheduledDate' property.
--- Cause: java.sql.SQLException: Invalid column type; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred while applying a parameter map.
--- Check the APPROVAL_TASK.insert-InlineParameterMap.
--- Check the parameter mapping for the 'scheduledDate' property.
--- Cause: java.sql.SQLException: Invalid column type
	at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.translate(SQLStateSQLExceptionTranslator.java:121)
	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.translate(SQLErrorCodeSQLExceptionTranslator.java:322)
	at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
	at org.springframework.orm.ibatis.SqlMapClientTemplate.insert(SqlMapClientTemplate.java:397)
... 

Now the problem was that scheduledDate was null. Here is partial SQL map used:


    insert into APPROVAL_TASK (APPR_ID, STEP, TASK, EMAIL_TO, CREATE_DATE)
    values (#apprId:DECIMAL#, #step:DECIMAL#, #task:DECIMAL#, #emailTo:VARCHAR#, #createDate:DATETIME#)


The createDate time jdbcType DATETIME was actually one of my changes. What Abator generated originally was this:


    insert into APPROVAL_TASK (APPR_ID, STEP, TASK, EMAIL_TO, CREATE_DATE)
    values (#apprId:DECIMAL#, #step:DECIMAL#, #task:DECIMAL#, #emailTo:VARCHAR#, #createDate:DATE#)
</pre>
<pre>

This map does not suffer by the Null value problem, but unfortunately does not store the time portion of the date – which was the main reason why I used DATETIME, unaware of the Null sensitivity.

There are three ways how to fix this. First is obvious – do use DATETIME and make sure that the field has value. This may be good enough as long as you do not need to save null values.

Second solution is to keep DATETIME and use iBatis magic with conditionals in map definition:

</pre>
<pre>
    insert into APPROVAL_TASK (APPR_ID, STEP, TASK, EMAIL_TO, CREATE_DATE)
    values (#apprId:DECIMAL#, #step:DECIMAL#, #task:DECIMAL#, #emailTo:VARCHAR#,
                
			null
		
		
			#createDate:DATETIME#
		   )
</pre>
<pre>

This deals with the null value differently and avoids “guessing” the column type, which caused the problem.Third solution may not work on other databases, but on Oracle works prefectly. The data type TIMESTAMP does both store the time portion as well as handles Null values without any problems. This is what I used at the end.

Final map:

</pre>
<pre>
    insert into APPROVAL_TASK (APPR_ID, STEP, TASK, EMAIL_TO, CREATE_DATE)
    values (#apprId:DECIMAL#, #step:DECIMAL#, #task:DECIMAL#, #emailTo:VARCHAR#, #createDate:TIMESTAMP#)
</pre>
<pre>

How to generate and send emails using Spring and Velocity

2008/03/05

Testing applications that communicate using email is more challenging than e.g. testing database access. Thanks to GMail and Spring, it can be done pretty easily.

Here is the scoop: I need to generate email notifying users about business events and after sending the email, store the content in the database. In real environment you will use corporate SMTP server and real email addresses of real people.
For development we can avoid bothering and spamming our customers by few simple tricks.

First step is to get new GMail account. Name it e.g. Company.Notifier or something easily distinguishable. In Spring, configure the sender bean:


           
                  smtp.gmail.com
           
           
                  
                          true
                          
                          true
                          25000
                
            
            
                   company.notifier
            
            
                   secret
            
            
            <!--   you don’t need to set the port number, 25 is default -->
     

The port can have value 25 (default) – but if you are using ISP provider such as Rogers, chances are the default port is blocked for outgoing connections – you can use port 587 instead.Second piece is component that actually uses the mailSender: notificationService.

    
           
           
           
       
           
               miro.adamy+alwaysCC@thinknostic.com
           
       

    .... deleted ...

   

Note the velocityEngine bean that is used to generate the body of the email from the template. The ‘alwaysCCList’ property is using nice little trick available with GMail: if you send email to YOURNAME+anything@gmail.com, the ‘+anything’ will be ignored but kept with email and it will arrive as if the address were just YOURNAME@gmail.com. You can use the postfix to find or autotag the emails.The code that sends email is actually pretty simple (the method of the notificationService)

public EmailContent sendNotificationEmail(EmailParameters params, EmailContent _content, boolean isDryRun) {

    final EmailContent c = mergeTemplate(params, _content);

    MimeMessagePreparator preparator = new MimeMessagePreparator() {
         public void prepare(MimeMessage mimeMessage) throws Exception {
            MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
            message.setTo(c.getEmailTo());
            message.setFrom("DO-NOT-REPLY@company.com"); // could be parameterized...

            message.setText(c.getEmailBody(), true);
            message.setSubject(c.getEmailSubject());

            if (alwaysCCList != null &amp;&amp; alwaysCCList.size() &gt; 0) {
                message.setCc(alwaysCCList.toArray(new String[0]));
                c.setEmailCcFromList(alwaysCCList);
            }
            ...
         }
      };

      if (isDryRun || emailsToFile)
      {
              // save to file
            ...
      }

      if (!isDryRun)
          this.mailSender.send(preparator);
      return c;
}

The class EmailContent is container for email address, subject, body, CC list.
It gets created as empty class with only recipient name and email address passed from business method as well as name of the Velocity template that is used to render email body. The method mergeTemplate loads the Velocity template and renders the actual email body, using the parameters (which is more or less) a hash map, cotaining e.g. URL’s or information that needs to be inserted to email. The generated content is stored back to EmailContent, which will be after successful delivery written to database for audit and archiving purposes.If you are JavaScript or Ruby programmer, you will immediately recognize the ‘functor’ pattern: preparator is set to instance of anonymous inner class and is used with configured preparator.The actual rendering of the content using Velocity can be done like this:


private EmailContent mergeTemplate( EmailParameters params, EmailContent content) {
    Map model = new HashMap();
    model.put("param", params);
    model.put("content", content);

    String text = "MISSING TEXT";
    String subject = "Notification email";
    String template = content.getTemplateId();
    try {

        // get subject line

        if (template_names.containsKey(template)) {
            subject = template_names.get(template);
            VelocityContext velocityContext = new VelocityContext(model);
             StringWriter writer = new StringWriter (  ) ;
             PrintWriter out = new PrintWriter ( writer ) ;

             Velocity.evaluate(velocityContext, out, "subject", new StringReader(subject));
             subject = writer.toString();

             model.put("subjectLine", subject);
            // now the body
             text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine,
                    "com/thinknostic/APP/service/email/"+template, model);

        }
        else {
            // TODO: log configuration error - template not found
        }

        content.setEmailBody(text);
        content.setEmailSubject(subject);
        return content;

    } catch (VelocityException e) {
        // back to untranslated
        // TODO: error report
        // subject = params.subject;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return null;
}

In the above, template id is actual file name with body of the HTML email and the hashmap template_names (configured in Spring XML) maps the id to another string, which is then used as subject line. Both body and subject can contain macros.
Note: if you get conflict on ${} syntax, see this entry.

Now, finally – how do we test this ? It is quite easy, thanks to JUnit support in Spring.


@ContextConfiguration(locations={"/com/thinknostic/APP/test/test-context.xml",
"/com/thinknostic/APP/test/service/NotificationTests-context.xml"})
public class NotificationTests extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    NotificationServiceImpl notificationService;
    public NotificationServiceImpl getNotificationService() {
        return notificationService;
    }
    public void setNotificationService(NotificationServiceImpl notificationService) {
        this.notificationService = notificationService;
    }

    @Autowired
    ApprovalDAO        approvalDao;
    public ApprovalDAO getApprovalDao() {
        return approvalDao;
    }
    public void setApprovalDao(ApprovalDAO approvalDao) {
        this.approvalDao = approvalDao;
    }

      Document doc;
      EmailContent cont;
      Approval app;
      ApprovalStep step1;
      ApprovalStep step2;

      @Before
      public void createMockApproval() {
          this.logger.info("Before");
          // controlls whether to use emails
          notificationService.setReallySend(true);

          doc = (Document)DocumentInfo.createMockDI("103", 1);

          // create the approval and insert it into
          app = Approval.createMockApproval(1L, doc);
          approvalDao.insert(app);

          step1 = ApprovalStep.createMockStep(app.getApprId(), 1);
          approvalDao.insert(step1);
          step2 = ApprovalStep.createMockStep(app.getApprId(), 2);
          approvalDao.insert(step2);

          cont = EmailContent.createMock(app.getApprId(), step1.getStep(), "miro adamy", "miro_adamy@rogers.com");

      }

      @After
      public void cleanup() {
          this.logger.info("After");
          // reset
          notificationService.setReallySend(false);
          doc = null;
          cont = null;
          app = null;
          step1 = null;
          step2 = null;
      }

      private void assertEverything()
      {
          assertTrue("The email service is empty", notificationService != null);
        assertTrue("The email parameteres not available", emailParameters != null);
        assertTrue("The document does not exist", doc != null);
      }

    @Test
    public void approval_all_cancelled_test() {
        doc.setFilename("approval_all_cancelled");

        notificationService.notifyApprovalCancelledAll(doc, cont);
    }

    @Test
    public void approval_cancelled_test() {
        assertEverything();

        doc.setFilename("approval_cancelled");
        EmailContent ui = EmailContent.createMock(app.getApprId(), step1.getStep(), "miro adamy", "Miro.Adamy@gmail.com");

        notificationService.notifyApprovalCancelled(doc, ui);
    }

    // and so on - many more tests
    ....
}

Assumed that your Spring context configuration files defined in annotations are OK, all you have to do is run the suite. The XML defines beans with names corresponding to the test properties and autowiring will take care of the rest.Also notice that @Before method (which runs before each test) actually DOES modify the database and inserts records with same primary key over and over. This works thanks to transaction magic of Spring, which rolls back the inserts at the end of the test.Last thing to mention is using of “mockXXX” static methods to generate the instance of object. IT not really a mock object we are creating here, but a well defined instance of business object with some properties parametrized. You can even define it as a bean in Spring context XML, but that is IMHO an overkill – keeping everything in test Java class makes things easier to understand.

This method does belong to tests, but it is very convenient just to keep it with domain object. I usually create the ‘createMock’ method right after I add a new domain object

Spring PropertyPlaceholderConfigurer with Velocity

2008/02/25

Part of the configuration magic is (one of several) Spring post-processors, that allows load the property file or files and refer to the values in these files inside XML configuration files. The rationale behind these is that property files are much easier to edit that possibly huge XML config file and using property values prevents repeating same value over and over again. With this approach, the following configuration:

 	
		
		
	

can be written as

 	
		
			
				WEB-INF/mail.properties
				WEB-INF/jdbc.properties
			
		
	


 	
		
		
	

 

and (in jdbc.properties)

jdbc.username=some_user
jdbc.password=secret

If you are using in the same project Velocity and want to utilize the VTL macros inside the configured values, the approach above will not work, because PropertyPlaceholderConfigurer will try to replace ALL macros in form ${something} with a value from property file – and throw exception if not found.The solution is easy: you need to switch the prefix of the PropertyPlaceholderConfigurer to something else than the default ${ and avoid conflict wih Velocity. The modified configuration could look like:

 

	
		
		
			
				WEB-INF/mail.properties
				WEB-INF/jdbc.properties
			
		
	
 
	
		
		
	

 

Spring Framework – the biggest missing piece

2008/02/04

I am having the pleasure working with Spring 2.x since about October last year. It is my return back to Spring, after first encounter in 2005 (counting only larger projects). Same as in previous project, it has been so much fun :-). So much fun in fact, that I was spending my evening playing with code and reading up what is new in 2.5, rather that blogging 😉

I am still amazed about how nice is the whole thing designed and how many ways it can be used. It’s flexibility is simply breathtaking. The price for the flexibility is complexity – sometimes it is not obvious what of many options should be chosen and what are all these options anyway :-).

Spring has very good documentation, compared to most of the open source projects I have looked at (and it was pretty large number over last 10 years). There are also many books on Spring, several of them pretty good. All this makes the fairly steep learning curve more accessible. But what is still missing are good examples.

But wait a moment, you may say – Spring source distribution DOES have several examples – for example JPetstore (offering two alternative implementations of UI – once using Spring MVC, once using Struts), Petclinic, and several others. The source code is nicely readable and well commented. So what is the big deal ?

The big deal is the ratio of options and possibilities offered by the framework to the options actually presented and demonstrated by the examples. Let’s take only the Spring MVC, which is certainly less than 30 % of the area covered by framework. Considering the possible combination of components would easily justify 20 examples just on that topic, not 2 or 3. The examples select one or two of possible URL mappers, provide some examples of controllers, view resolution and then the actual view. What is missing are alternatives and explanation of the differences. How would using SimpleUrlHandlerMapping instead of BeanNameUrlHandlerMapping impact the application, is explained pretty well in Chapter 13 of the documentation. For an experienced developer this (and a source code itself) is usually enough. If you try to explain Spring based application to somebody without prior IoC / DI experience, you may find out that it is not as obvious and that having an example of working code that would show the actual different implementation and letting him/her to compare and experiment, turning one into another would probably be the easiest way how to get started.

I realize that creating enough examples could be possibly a code maintenance nightmare – at least if the pace of Spring development will remain the same. In many cases, more documentation on the samples, explaining how it works at the high level and discussing the alternatives would be almost as helpful as the full source. The otherwise very good documentation is quite brief on the Samples side – the Chapters 26 has about two screens, and that for all the samples.

And because this is definitely NOT a rant, but an attempt to make a constructive suggestions, I plan to do something about the situation myself and will post the notes from “dissecting the Spring App” that I used for explaining how things works in Spring MVC and around. As soon as I get them to presentable form ;-). Stay tuned.

Spring 2 MVC and ResourceBundleViewResolver problem

2008/01/24

This one took some time to figure out – it is one of those problems that are obvious after you know the solution but hard to see beforehand.

I had the ResourceBundleViewResolver configured with Tiles 2, like this:







and the view.properties was:

parent-view.(class)=org.springframework.web.servlet.view.JstlView
parent-view.(abstract)=true

about.url=/WEB-INF/jsp/about.jsp
form.url=/WEB-INF/jsp/form.jsp
list.url=/WEB-INF/jsp/list.jsp

It kept givin exception saying that /WEB-INF/jsp/list.jsp does not exist. Which it did. I tried couple of things, no result.

The problem was in trailing space AFTER list.jsp, therefore the path to JSP file searched for was “/WEB-INF/jsp/list.jsp “, not “/WEB-INF/jsp/list.jsp”.

Not sure if this is bug or feature – but removing trailing spaces should really be a sensible thing to do. As I found afterwards, the problem exists since 2005 – see this and this.