Download and install

Part of CaptainCasa installation

The CaptainCasa installation includes a file:

<installDir>

    resources

        addons

            eclnt_ccee.zip

            ...

        ...

    ...

 

This file contains the following library files that need to be added to your project:

eclnt_ccee.jar

eclnt_ccee_spring.jar

 

Add both files to your project, e.g. if using the CaptainCasa project structure add both files to the webcontent directory:

<project>

    webcontent

        WEB-INF

            lib

                …

                eclnt_ccee.jar

                eclnt_ccee_spring.jar

                …

 

Add the libraries required for Spring to WEB-INF/lib as well.

Maven

Use the CaptainCasa-Spring project-archetype

There is a project-archetype than contains the configuration of Spring that is explained in the next chapters. We recommend to use this archetype for creating your projects.

The archetype is available within the following remote catalog:

http://www.captaincasademo.com/mavenrepository/archetypecatalog.xml

 

In Eclipse the project is created in the following way:

Similar steps need to be done if using e.g. NetBeans, or IntelliJ IDEA as development environment.

Do it yourself!

(Refer to the documentation “Setting up a Maven Project” if you require information about how to in general create a CaptainCasa Maven project.)

Add the dependencies that as follows.

    <repositories>

        ...

        <repository>

        <id>org.eclnt</id>

        <url>https://www.captaincasademo.com/mavenrepository</url>

     </repository>

        ...

    </repositories>

 

    <properties>

        <cc.version>20191102</cc.version>

    </properties>

 

    ...

 

    <dependencies>

        ...

        <dependency>

            <groupId>org.eclnt</groupId>

            <artifactId>eclntccee</artifactId>

            <version>${cc.version}</version>

        </dependency>

        <dependency>

            <groupId>org.eclnt</groupId>

            <artifactId>eclntccee_spring</artifactId>

            <version>${cc.version}</version>

        </dependency>

        ...

    </dependencies>

 

Source Code

Please note that all source code is available as part of the download. Sometimes textual explanations leave the impression of something very complex going on and indeed things are quite simple if you take a look inside – especially if you are already experiences with Spring.

Take a look into the classes – there are only a few ones, and inside there are only few lines of code!

Overview

Dispatcher

With CaptainCasa a page (.jsp) refers via expressions to its page bean. By default each page is managed by exactly one bean-class.

Example:

demo.jsp

 

...

<t:row id=”g_1”>

    <t:field id=”g_2” width=”100” text=”#{d.DemoUI.firstName}”/>

</t:row>

...

 

The bean class is referenced through a so called dispatcher object which is represented by the leading “d” within all the expressions of the page.

The “d” is resolved within the file “/WEB-INF/faces-config.xml” to a Dispatcher-instance.

faces-config.xml (example)

 

...

<managed-bean>

    <managed-bean-name>d</managed-bean-name>

    <managed-bean-class>managedbeans.Dispatcher</managed-bean-class>

    <managed-bean-scope>session</managed-bean-scope>

</managed-bean>

...

And this Dispatcher-instance is the one to be responsible for transferring the name “DemoUI” into a corresponding Java object. - The Dispatcher itself is just an implementation of the java.util.Map interface, in which the get(...)-method is the one which is overridden correspondingly.

Dispatcher object resolution

The Dispatcher is the one that is affected by the integration to Spring: instead of following own rules how to resolve a name (“DemoUI”) into an object instance – it requests the Spring-context to do the resolution.

Example, in the Spring-context there is a definition:

<beans ...>

    ...

    <bean id="DemoUI" class="test.DemoUI" scope="prototype">

        <property name="..." ref="..."/>

    </bean>

    ...

</beans>

 

Class DispatcherBySpringAccess

CaptainCasa provides within the eclnt_ccee_spring.jar-library a Dispatcher-implementation that does the object resolution via Spring. The following text will tell you details how to use this class.

Implementing Spring Access

There are so many ways to configure and to work with Spring. We will concentrate on the XML-way in this documentation, but of course all other ways (e.g. annotation-based) are supported as well.

Activate Spring in your web application

The spring framework needs to be integrated into the web.xml of your project:

...

<context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>classpath:spring_context_webapplication.xml</param-value>

</context-param>

<listener>

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

</listener>

...

 

The web-application-context

Part of this definition is the name of the XML file that sets up the bean definitions for the web-application-context of Spring. In the example above we define the location to be “classpath:spring_context_webapplication.xml”.

This XML file is the normal Spring-XML for setting up bean instances.

File: <project>/<Java-resources>/spring_context_webapplication.xml

 

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        https://www.springframework.org/schema/beans/spring-beans.xsd">

 

    <bean .../>

    </bean>

    

    <bean .../>

    </bean>

 

</beans>

 

This XML file already could be the end of the Spring integration story by telling you: define your beans here – and they are picked up by the Dispatcher at runtime. - But: we made things bit more structured...

The dialog-session-context

The class “DispatcherBySpringAccess” is an implementation of the “Dispatcher” and opens up one Spring-context for each dialog-session. This dialog-session-context is arranged as child to the web-application-context, so that all bean-definitions of the web-application-context are also available within the dialog-session-context.

At runtime there is one dialog session for each browser instance. If the user opens up the browser three times (either individual browsers or tabs inside one browser), then there are three dialog sessions on server side – and there are three instances of dialog-session-contexts as well.

(Please do not mix “dialog-session” with “http-session”. When using cookie-based session tracking there is one http-session which may span multiple browsers, but still there is one dialog-session per browser.)

There are two implementations of this dialog-session-context that come with eclnt_ccee_spring.jar:

DialogSessionXMLApplicationContext

    (extending Spring's ClassPathXmlApplicationContext)

 

DialogSessionAnnotationApplicationContext

    (extending Spring's AnnotationConfigApplicationContext)

 

Both classes provide configuration methods to set-up there internal processing. In case of the XML based approach the central method is...

DialogSessionXMLApplicationContext.setConfigLocation(...nameOfXmlFile...)

 

...in which the name of the XML-file is passed that is configuring the beans on dialog-session-context level.

Advantages of defining a dialog-sesison-context

In simple scenarios the dispatcher-name-resolution could directly access the web-application-context definitions. But, there are some advantages when using some explicit context below the web-application-context:

Whole setup

The Dispatcher-implementation “DispatcherBySpringAccess” is the one to create a dialog-session-context-instance for each dialog session. Its inner implementation does not directly create the corresponding context-instance, but requests the instance from the web-application-contenxt using the id “DialogSessionApplicationContext”.

This means: in the web-appplication-context you set up the prototype-definition for the dialog-context-instances:

File: <project>/<Java-resources>/spring_context_webapplication.xml

 

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        https://www.springframework.org/schema/beans/spring-beans.xsd">

 

    ...

    ...

    <bean id="DialogSessionApplicationContext"

          class="org.eclnt.ccee.spring.context.DialogSessionXMLApplicationContext"

          scope="prototype">

        <property name="configLocation" value="spring_context_dialogsession.xml"/>

    </bean>    

    ...

    ...

</beans>

 

In the definition of “DialogSessionApplicationContext” you configure the corresponding context-instances, in case of using the XML based dialog-session-context this is the property “configLocation”.

In the example the configLocation “spring_context_dialogsession.xml” is used – so this is the Spring-XML-definition one for the dialog-session-context, which now finally holds the beans that are resolved by the Dispatcher (you remember the “#{d.DemoUI.firstName}”...?).

File: <project>/<Java-resources>/spring_context_dialogsession.xml

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

        https://www.springframework.org/schema/beans/spring-beans.xsd">

        

    ...

    <bean id="DemoUI" class="test.DemoUI" scope="prototype">

        <property name="..." ref="..."/>

    </bean>

    ...    

        

</beans>

 

Your Dispatcher-implementation

Each project comes with an own Dispatcher-class – within a new project it is located in package “managedbeans”. This dispatcher needs to extend the “DispatcherBySpringAccess”:

package managedbeans;

 

import org.eclnt.ccee.spring.context.DispatcherBySpringAccess;

import org.eclnt.ccee.spring.context.SpringDispatcherInfo;

import org.eclnt.workplace.IWorkpageContainer;

 

public class Dispatcher extends DispatcherBySpringAccess

{

    public static DispatcherInfo getStaticDispatcherInfo()

    {

        return new SpringDispatcherInfo(Dispatcher.class,

                                         "spring_context_dialogsession.xml");

    }

 

    public Dispatcher()

    {

    }

 

    public Dispatcher(IWorkpageContainer workpageContainer)

    {

        super(workpageContainer);

    }

}

 

By providing the optional method “getStaticDispatcherInfo” this class delivers information to the CaptainCasa tools, so that the beans that are defined in the dialog-session-context are directly visible within the classes of the bean-browser-tool.

Summary

The total view on the scenario is:

 

Using annotations

In the previous chapter the Spring context was set up by XML definitions – both on web-application and on dialog-session level. Spring allows the configuration also to be done by annotations – this chapter will show some details about how to go on.

Web-application context level

The definition to use the annotation-based context starts with the web.xml. Instead of defining an XML file to be used as configuration you need to name a class which does the configuration.

In the web.xml that is generated by the project archetype you will find the corresponding definitions, but they are commented out (and the XML-configuration is active). So now update the web.xml in the following way:

  <!-- Spring startup - XML based -->

  <!--

  Not used here!

  <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>classpath:spring_context_webapplication.xml</param-value>

  </context-param>

  <listener>

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

  </listener>

  -->

  

  <!-- Spring startup - Annotations based -->

  <context-param>

    <param-name>contextClass</param-name>

    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>

  </context-param>

  <context-param>

      <param-name>contextConfigLocation</param-name>

      <param-value>webapplevel.ContextConfiguration</param-value>

  </context-param>

  <listener>

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

  </listener>

 

You see:

This class “webapplevel.ContextConfiguration” is a class that you have to provide. The easisest way is to extend it from the class “DefaultWebApplicationContextConfiguration” which comes with the CaptainCasa-spring package.

The class “DefaultWebApplicationContextConfiguration” already provides the configuration that is required to create the dialog-session based context:

@Configuration

public abstract class DefaultWebApplicationContextConfiguration

{

    /**

     * Bean "DialogSessionApplicationContext" - the one that represents the

     * Spring context on dialog session level.

     */

    @Bean(name = "DialogSessionApplicationContext")

    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    public DialogSessionAnnotationApplicationContext getDialogSessionApplicationContext()

    {

        DialogSessionAnnotationApplicationContext result = new DialogSessionAnnotationApplicationContext();

        result.setBasePackages(getBasePackages());

        return result;

    }

    

    /**

     * Packages that are scanned for Spring-annotations.

     */

    public abstract String[] getBasePackages();

}

 

You may compare this configuration to the XML-definition of the previous chapter. In the XML definition there was a bean definition of name “DialogSessionApplicationContext”, now the configuration is done by code and annotations.

In your extension you need to list the packages that the dialog-session context should scan for annotations. Example:

package webapplevel;

 

import org.eclnt.ccee.spring.context.DefaultWebApplicationContextConfiguration;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Scope;

 

@org.springframework.context.annotation.Configuration

public class ContextConfiguration extends DefaultWebApplicationContextConfiguration

{

    @Override

    public String[] getBasePackages()

    {

        return new String[] {"managedbeans"};

    }

 

    // own, additional configurations

    // Example:

 

    @Bean

    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

    public ITranslationProvider translationProvider()

    {

        return new TranslationProvider();

    }

}

 

It is important that your class (here: “webapplevel.ContextConfiguration”) is NOT one which is hot deployed! The spring context that is managed on web-application level is accessing the classes in the web-application classloader (WEB-INF/classes and WEB-INF/lib) and does not know anything about hot deployment!

So, do not place this class e.g. in “managedbeans”.

Dialog-session context level

Now you need to place some configuration class in order to configure the Spring context on dialog-session level. The packages to look for annotated classes already were passed by the definition of the previous chapter – so in these packages you now can start to use Spring annotations.

Example:

package managedbeans;

 

import org.springframework.beans.factory.config.ConfigurableBeanFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Scope;

 

@org.springframework.context.annotation.Configuration

public class Configuration

{

    @Bean

    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)

    public Test1UI Test1UI() { return new Test1UI(); }

 

    @Bean

    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

    public ITitleProvider titleProvider() { return new TitleProvider(); }

}

 

In this configuration class you define a name “Test1UI” that points to a Test1UI object. And there is some name “titleProvider” that points to an instance of “ITitleProvider”.

Looking into the implementation of “Test1UI” you see that its inner details are configured by Spring annotations – both pointing to names in the dialog-session and in the web-application context.

package managedbeans;

 

import java.io.Serializable;

 

import org.eclnt.editor.annotations.CCGenClass;

import org.eclnt.jsfserver.pagebean.PageBean;

import org.springframework.beans.factory.annotation.Autowired;

 

import springmgmt.ITranslationProvider;

 

@CCGenClass (expressionBase="#{d.Test1UI}")

public class Test1UI

    extends PageBean

    implements Serializable

{

    @Autowired(required = true)

    ITitleProvider m_titleProvider;

    public ITranslationProvider getTranslationProvider() { return m_translationProvider; }

    public void setTranslationProvider(ITranslationProvider translationProvider) { m_translationProvider = translationProvider; }

    

    @Autowired(required = true)

    ITranslationProvider m_translationProvider;

    public void setTitleProvider(ITitleProvider titleProvider) { m_titleProvider = titleProvider; }

    public ITitleProvider getTitleProvider() { return m_titleProvider; }

 

    public String getTitle()

    {

        String result = "????";

        if (m_titleProvider != null) result = m_titleProvider.findTitle(this);

        if (m_translationProvider != null) result = m_translationProvider.translate(result);

        return result;

    }

    

    public String getPageName() { return "/pages/test1.jsp"; }

    public String getRootExpressionUsedInPage() { return "#{d.Test1UI}"; }

}

 

Other issues

Accessing the dialog-session-context at runtime

You can access the dialog-sesion-context at runtime by using the API:

DialogSessionApplicationContextFactory.instance()

DialogSessionApplicationContextFactory.instance(ISessionAbstraction dialogSession)

 

Both methods return a Spring-AbstractApplicationContext-instance.

Hot Deployment

The implementations within eclnt_ccee_spring.jar are aware of dealing with hot deployment within the CaptainCasa toolset. Hot deployment splits up the application processing into two classloaders: the normal web-application classloader on <webapp>/WEB-INF/lib-level and a child-classloader on <webapp>/eclnthotdeploy/classes level.

The web-application part of the Spring integration is running within the web-application classloader because this is the runtime starting point of Spring.

The dialog-session part of the Spring integration is managed by CaptainCasa, so here the hot deployment is taken into consideration.

This means: when using hot deployment (which we always recommend!), then...