mmatloka
mmatloka

Reputation: 2014

Spring + Vaadin integration design patterns

What design patterns are used when integrating spring with vaadin/gwt? We're using spring with hibernate in our application, every dao is a spring bean. Question is what is the best way to use them on Vaadin side?

Options which we've find so far are:

Upvotes: 3

Views: 7433

Answers (5)

mstahv
mstahv

Reputation: 1934

The de-facto method these days is to use the official Vaadin Spring integration library. This makes UI classes Spring managed beans and provides handy Vaadin related scopes. Then you can decide based on your requirements how many of your helper classes in UI code you wish to make Spring beans. At least consider making e.g. all Views Spring managed.

start.spring.io service contains an option to add relevant Vaadin Spring dependencies, then just create UI class and annotate it with @SpringUI annotation. No need to create VaadinServlet separately.

Upvotes: 0

mendlik
mendlik

Reputation: 61

I would recommend using Vaadin UIProvider mechanism. This way autowiring in UI is totally transparent.

You can have a look at a really simple example that uses this solution on github: spring-vaadin-example

Upvotes: 2

Nico de Wet
Nico de Wet

Reputation: 334

What design patterns are used when integrating spring with vaadin/gwt?

A slight variation of that which has been provided above. It works for me and is very simple so I'm posting it here.

I added the following to web.xml and used an exact classpath reference to a dependency's spring-context (change the path to suit your needs):

<!-- Spring context loader -->
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>      
</listener>
<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:com/company/appserv/spring/spring-context.xml</param-value>
 </context-param>

The above assumes you have added spring-web to your pom.xml, so be sure to do that. You will also need servlet-api. So you will add the following to your pom, adjust the versions to suit your needs:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${org.springframework.version}</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
</dependency>

Now, create the following class:

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SpringContextHelper {

private ApplicationContext context;

private static Logger logger = LoggerFactory.getLogger(SpringContextHelper.class);

public SpringContextHelper(Application application) {
    ServletContext servletContext = ((WebApplicationContext) application.getContext()).getHttpSession().getServletContext();
    context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
    logger.debug("Number of beans: {}",context.getBeanDefinitionCount());
}

public Object getBean(final String beanRef) {
    return context.getBean(beanRef);
}    
}

And now create your DAO class (as suggeted in an earlier post):

import com.company.appserv.dbo.DatabaseHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.Application;

public class DAO {

private static DatabaseHelper databaseHelper;

private static Logger logger = LoggerFactory.getLogger(DAO.class);

public static final void initialize(Application application) {
    logger.debug("DAO initializing...");
    if (databaseHelper == null) {
        logger.debug("Creating databaseHelper...");
        SpringContextHelper helper = new SpringContextHelper(application);
        databaseHelper = (DatabaseHelper)helper.getBean("databaseHelper");
    }
}

public static DatabaseHelper getDatabaseHelper() {
    return databaseHelper;
}
}

Finally, be sure to initialize your DAO that you will now use in various view classes. This initialization will happen in whatever class you have extended Application, as shown below:

import com.vaadin.Application;
import com.vaadin.ui.Window;

/**
 * The Application's "main" class
 * 
 * Vaadin framework associates requests with sessions so that 
 * an application class instance is really a session object.
 */
@SuppressWarnings("serial")
public class VoucherTool extends Application
{
  private Window mainWindow;

  @Override
  public void init() {
    mainWindow = new Window("Application");
    setMainWindow(mainWindow);

    // Needed because composites are full size
    mainWindow.getContent().setSizeFull();

    LoginView myComposite = new LoginView();
    mainWindow.addComponent(myComposite);
    setTheme("applicationtheme");

DAO.initialize(this);
 }
}

Upvotes: 1

Archie
Archie

Reputation: 5421

Try my Spring Stuff Vaadin Add-On, which has some helpful classes for integrating Vaadin and Spring.

There is a demo on GitHub that shows how it works.

Upvotes: 2

noone
noone

Reputation: 11

After playing a bit with Vaadin and Spring, we decided to use Spring beans only for DAO classes, where PersistenceContext injection comes in really, really handy. All the other classes, including but not limited to Vaadin controls, are "ordinary" classes with no Spring control over them.

After that decision, the actual question becomes "how do we get Spring-enabled DAO in a non-Spring related code?" We choose a quick&dirty solution that "just works" with minimum hassle.

0) Added two Spring listeners and a filter to web.xml:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<filter>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <servlet-name>BlahBlah Application</servlet-name>
</filter-mapping>

1) Create an application-wide placeholder for all Spring-managed service beans:

public class DAO {
    private static Logger log = Logger.getLogger(DAO.class);

    private static BlahBlahService blahBlahService;
    private static AnotherService anotherService;

    public static final void initialize(ApplicationContext context) {
        log.info("DAO initializing...");
        blahBlahService = context.getBean( BlahBlahService.class );
        anotherService = context.getBean( AnotherService.class );
    }

    public static BlahBlahService getBlahBlahService() {
        return blahBlahService;
    }
    public static AnotherService getAnotherService() {
        return anotherService;
    }
}

2) Declare Spring-service classes normally via @Service stereotype annotation.

3) The Vaadin application servlet has load-on-startup enabled. The actual init() method does the following:

@Override
public void init( ServletConfig config ) throws ServletException {
    Logger.getLogger( InitServlet.class ).info( "init()..." );

    super.init( config );

    WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext( config.getServletContext() );

    DAO.initialize( wac );
}

4) The application code has to call DAO.getThisOrThatService() and work with it normally.

Upvotes: 1

Related Questions