Thursday, January 22, 2009

Spring Server + Maven + Eclipse notes

I feel I am a bit more experienced than when I've started.
Last time I've mentioned about problems I've faced. Maybe it's high time to elaborate a bit about solutions.


  1. Tools:


  2. Dependencies management:
    There are two aspect to discus. Firstly that we are usually manage our dependencies using Maven (of course if we are using maven ;D ). Secondly, bundle dependencies management. Using default configuration we need to feed maven repository using maven and spring server repository using Eclipse Server Editor, which in current version seems to be not working, or provisioning mechanisms.
    This bi-declaration effect have also consequences in how it is seen by Eclipse.
    We have two declaration of the same library in build path.


    As I am using multi-module project. And have inter-module dependencies it resulted in build path error and compilation failure.


    Default configuration has also other consequence. We have to double dependencies definition or we have maven script not usable outside Eclipse tooling. What if we want to share the project? We need to toss the usr bundle catalog round the users, etc.

  3. Solutions:
      Server configuration

      Fortunately we can make our server to use maven repository structure to look for bundles. What I am using is slightly modified configuration from documentation. As OSGi enabled bundles from spring are usually
      in com.springsourceXXX packages we can reuse this information:

      "searchPaths": [
      "repository/bundles/subsystems/{name}/{bundle}.jar",
      "repository/bundles/ext/{bundle}",
      "${user.home}/.m2/repository/**/com.springsource*/**/{bundle}.jar",
      "repository/libraries/ext/{library}",
      "repository/libraries/usr/{library}"
      ]


    • Repository configuration


      Second observation is:use OSGi enabled libraries. In other case you will need to deal with inner JAR's. Which add to the management complexity IMHO.
      Most common libraries prepared to work in OSGi can be found in SpringSource maven repository:

      <repositories>
      <repository>
      <id>com.springsource.repository.bundles.release</id>
      <name>SpringSource Enterprise Bundle Repository -
      SpringSource Bundle Releases</name>
      <url>http://repository.springsource.com/maven/bundles/release</url>
      <releases>
      <updatePolicy>daily</updatePolicy>
      <checksumPolicy>ignore</checksumPolicy>
      </releases>
      </repository>
      <repository>
      <id>com.springsource.repository.bundles.external</id>
      <name>SpringSource Enterprise Bundle Repository -
      External Bundle Releases</name>
      <url>http://repository.springsource.com/maven/bundles/external</url>
      </repository>
      </repositories>

      How to find correct dependency? Easly :) SpringServer editor can lead you to repository browser (Look at the picture).

    • Independ maven build

      The last step to is to keep all dependencies in maven. Why ? Independent build.
      My solution is maybe naive but it works - Maven profiles.


      <profiles>
      <profile>
      <id>standalone</id>
      <dependencies>
      <dependency>
      <groupId>com.oracle.jdbc</groupId>
      <artifactId>com.springsource.oracle.jdbc</artifactId>
      </dependency>
      <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>com.springsource.org.apache.commons.collections</artifactId>
      <version>3.2.0</version>
      <scope>provided</scope>
      </dependency>
      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>org.springframework.web.servlet</artifactId>
      <version>${spring.components.version}</version>
      <scope>provided</scope>
      </dependency>
      </dependencies>
      </profile>
      </profiles>


      To build project outside the only think you need to do is to eneble standalone profile.



Monday, January 19, 2009

Tools integration

Hopefully I've found support for all ideas used in our project.
Eclipse, and it is not surprising for those knowing me, as my IDE.
Maven as a project build tools (at the moment working well only as Eclipse embedded).
Maven tooling for Eclipse. Spring Server. Spring tooling and spring tooling for eclipse. Have I missed sth ? Off course there there are SVN Track and everything eclipse has to support it.
Now let me elaborate on "hopefully". I have no doubts that without Eclipse plug-ins life could be painful.
But:

  • why I have cycles in my builds (ok I am using a bit customized scripts)
  • what is the best way to share such a project (how to share server configs, how to use relative paths)
  • how to fight with the dual sources of buildpath dependencies (one from maven, second from budle dependencies) - at the moment I am testing use of standalone profile to store dependencies from OSGi configuration.


Maybe its time (if this is possible) to build set of good practices for spring + maven + eclipse integration.

Sunday, January 18, 2009

Spring Integration Testing for Web

I am building OSGi web based (partially) application. As usual when you touch new area of technology (especially new technology) it tends to be problematic.

Today problem I have faced three weeks ago. How to test web controller.
Maybe its not a problem at all (you can configure everything manually), but I really wanted to use spring support for testing.

If you're preparing a test for IoC managed components you can use this fact (if you need more information refere to spring documentation).

To build your context you can use Spring TestFramework annotations.

package com.example;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/com/example/MyTest-context.xml"
@ContextConfiguration
public class MyTest {
// class body...
}

You can also specify where to look for context(s) definition(s). And at the moment you're redy to use @Autowired annotation

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/META-INF/spring/module-context.xml", "/test-context.xml"})
public class ControllerTest {
@Autowired
private Controller controller;
}

As you can see I'am using application context and test context (which is used for components normally reached via OSGi). But if we leave it this way It won't work.
The reason is that Controller needs web context and Spring test mechanism provides normal one. But there is a solution. We can provide our context loader which is able to provide required context.
@ContextConfiguration(locations = {"/META-INF/spring/module-context.xml", "/test-context.xml"}, loader = XmlWebApplicationContextLoader.class)

And here is XmlWebApplicationContextLoader:

public class XmlWebApplicationContextLoader extends
AbstractContextLoader {
...
public final ConfigurableApplicationContext loadContext(String... locations)
throws Exception {
if (logger.isDebugEnabled()) {
logger
.debug("Loading ApplicationContext for locations ["
+ StringUtils .arrayToCommaDelimitedString(locations)
+ "].");
}
GenericApplicationContext context = new GenericWebApplicationContext();
prepareContext(context);
customizeBeanFactory(context.getDefaultListableBeanFactory());
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
customizeContext(context);
context.refresh();
context.registerShutdownHook();
return context;
}

Now you are ready to test web controller classes. In spring framewor Http request and response mock are off the shelf.