Joshua Java

Setting up Spring + Wicket on Websphere 5

Posted on: November 14, 2007

Generally you won’t find any problem setting up Wicket on Websphere 5 using WicketFilter. But there are some situation where you just can’t use WicketFilter. One case of that is if you integrate Wicket with Spring, then you’re in trouble. Why?

  1. ContextLoaderListener doesnt’ work on Websphere 5 which is another darkside of Websphere because Servlet 2.3 spec already support listener and it should work on any container.
  2. That means you need to use ContextLoaderServlet.

Is that it?
No. You’re still on another problem.Filter is loaded first before servlet. So you would end up in an exception saying that Wicket can not find your spring context. Thank’s God Wicket also provides a WicketServlet (though this has been deprecated and not recommended to use anymore) for situation like this. And you would not lose all the functionality in WicketFilter because basically WicketServlet will instantiate WicketFilter and call it once it is loaded.

To wrap it up, this is the web.xml configuration you would likely use for such situation:


<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
	"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
	<display-name>wicket</display-name>

	<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
	</context-param>

	<servlet>
		<servlet-name>context</servlet-name>
		<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
		<load-on-startup>0</load-on-startup>
	</servlet>

	<servlet>
		<servlet-name>wicket.wicket</servlet-name>
		<servlet-class>org.apache.wicket.protocol.http.WicketServlet</servlet-class>
		<init-param>
<param-name>configuration</param-name>
<param-value>development</param-value>
		</init-param>

		<init-param>
<param-name>applicationClassName</param-name>
<param-value>com.taxandtech.lab.wicket.web.WicketApplication</param-value>
		</init-param>

		<init-param>
<param-name>applicationFactoryClassName</param-name>
<param-value>org.apache.wicket.spring.SpringWebApplicationFactory</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>wicket.wicket</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>
</web-app> 

Then you call your Spring beans from WicketApplication class as such:

public class WicketApplication extends WebApplication
{
    private DepartmentService departmentService;

    public DepartmentService getDepartmentService() {
        return departmentService;
    }

    public void setDepartmentService(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }

}

And this is an example how your applicationContext configuration would look like:


<beans>
    <bean id="departmentDao" class="com.taxandtech.lab.wicket.dao.DepartmentDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="departmentService" class="com.taxandtech.lab.wicket.service.DepartmentServiceImpl">
<property name="departmentDao" ref="departmentDao" />
    </bean>

     <bean id="wicketApplication" class="com.taxandtech.lab.wicket.web.WicketApplication">
<property name="departmentService" ref="departmentService"/>
    </bean>
</beans>

And that’s about it.You would normally can your spring bean from your wicket page as such:

public class DepartmentInput extends WebPage{
    private Department department;

    public DepartmentInput() {
        add(feedback);
        add( new DepartmentInputForm("departmentInputForm", new CompoundPropertyModel( new Department() )));
        add( new Label("departmentName", new PropertyModel(department, "name" ) ));
    }

    public class DepartmentInputForm extends Form{

        public DepartmentInputForm(String id, final CompoundPropertyModel model) {
            super(id, model);

            department = (Department)model.getObject();

            add(new TextField( "name" ) );

            add(new Button("save"){
                public void onSubmit(){
                    getDepartmentService().save(department);
                }
            });
        }
    }

    protected DepartmentService getDepartmentService(){
        return ((WicketApplication)getApplication()).getDepartmentService();
    }
}

Watch closely on line 19-23 on how the button calls the service and on line 27-29 how the service is called from WicketApplication that we have set up before.

9 Responses to "Setting up Spring + Wicket on Websphere 5"

The wicket servlet is only deprecated for the way most people used it: configuring it on the context root with the /* catch all. If you map it to /app/* you won’t have any problems.

Because of the problems with WebSphere and other servers, the servlet is still a viable alternative and won’t be going away anytime soon.

Thanks for the confirmation. This WicketServlet is important for us that uses Websphere AS.

Hi Joshua,

You saved my bacon! We are going to use Wicket 1.3 for our next big WAS 6.1 project based on my recommendation. However, my proof of concept suddenly stopped working after I integrated Spring/Hibernate following the Wicket in Action book. So I went back to WicketServlet based on your advice, and it works! I have a question for you: I am creating a Hibernate session per each request using the Spring OpenSessionInViewFilter filter — will this filter still work properly with Websphere?

Thanks,
Steve

Hi Steve,

Thanks God you find this post useful🙂 The problem on my experience is not on the wicket filter but the Spring ContextLoaderListener, that’s why I had to use the ContextLoaderServlet, and in turn I can not use the wicket filter because the ContextLoaderServlet should be scanned first and not the wicket filter. Do you get what I mean? I haven’t used the OpenSessionInViewFilter, but that’s interesting based on your story :-d

I have a wicket/spring application that works on Tomcat. I am trying to port it to WebSphere 5.1. After seeing this post, I replaced the listener with the ContextLoaderServlet. That allowed me to get a little further. However, now I am getting the following error when the WAS server starts:


[10/21/08 10:57:32:656 CDT] 35e7f85e WebGroup E SRVE0020E: [Servlet Error]-[ContextLoaderServlet]: Failed to load servlet: java.lang.ClassCastException: org.springframework.web.context.ContextLoaderServlet
at com.ibm.ws.webcontainer.webapp.WebAppServletManager.loadServlet(WebAppServletManager.java:188)
at com.ibm.ws.webcontainer.webapp.WebAppServletManager.loadAutoLoadServlets(WebAppServletManager.java:542)
at com.ibm.ws.webcontainer.webapp.WebApp.loadServletManager(WebApp.java:1279)
at com.ibm.ws.webcontainer.webapp.WebApp.init(WebApp.java:283)
at com.ibm.ws.webcontainer.srt.WebGroup.loadWebApp(WebGroup.java:392)
at com.ibm.ws.webcontainer.srt.WebGroup.init(WebGroup.java:211)
at com.ibm.ws.webcontainer.WebContainer.addWebApplication(WebContainer.java:1005)
at com.ibm.ws.runtime.component.WebContainerImpl.install(WebContainerImpl.java:136)
at com.ibm.ws.runtime.component.WebContainerImpl.start(WebContainerImpl.java:356)
at com.ibm.ws.runtime.component.ApplicationMgrImpl.start(ApplicationMgrImpl.java:505)
at com.ibm.ws.runtime.component.DeployedApplicationImpl.fireDeployedObjectStart(DeployedApplicationImpl.java:808)
at com.ibm.ws.runtime.component.DeployedModuleImpl.start(DeployedModuleImpl.java:354)
at com.ibm.ws.runtime.component.DeployedApplicationImpl.start(DeployedApplicationImpl.java:578)
at com.ibm.ws.runtime.component.ApplicationMgrImpl.startApplication(ApplicationMgrImpl.java:299)
at com.ibm.ws.runtime.component.ApplicationMgrImpl.start(ApplicationMgrImpl.java:256)
at com.ibm.ws.runtime.component.ContainerImpl.startComponents(ContainerImpl.java:536)
at com.ibm.ws.runtime.component.ContainerImpl.start(ContainerImpl.java:413)
at com.ibm.ws.runtime.component.ApplicationServerImpl.start(ApplicationServerImpl.java:152)
at com.ibm.ws.runtime.component.ContainerImpl.startComponents(ContainerImpl.java:536)
at com.ibm.ws.runtime.component.ContainerImpl.start(ContainerImpl.java:413)
at com.ibm.ws.runtime.component.ServerImpl.start(ServerImpl.java:243)
at com.ibm.ws.runtime.WsServer.start(WsServer.java:128)
at com.ibm.ws.runtime.WsServer.main(WsServer.java:225)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60)
at java.lang.reflect.Method.invoke(Method.java:391)
at com.ibm.ws.bootstrap.WSLauncher.main(WSLauncher.java:189)
at com.ibm.etools.websphere.tools.runner.api.ServerRunnerV5$1.run(ServerRunnerV5.java:97)

[10/21/08 10:57:32:656 CDT] 35e7f85e TraceNLS u No message text associated with key Servlet.[ContextLoaderServlet]:.not.a.servlet.class in bundle com.ibm.ejs.resources.seriousMessages
[10/21/08 10:57:32:656 CDT] 35e7f85e WebAppServlet E Servlet [ContextLoaderServlet]: not a servlet class

Any thoughts on what could be causing this error … Thanks!

gbondy,

have you got the spring library in your lib/ folder?

The spring.jar file is in the installedApps application directory under …/WEB-INF/lib. I was able to get around the problem I posted above. The problem was that javax.servlet.Servlet was found in another jar file that was deployed with the application. This didn’t cause a problem for Tomcat but WebSphere didn’t like it.

I have worked through a number of other problems but it’s still not working yet. One problem I had is that we are using version 1.3.4 of wicket which was compiled with JDK 5. I had to use a tool called retroweaver to make it byte-code compatible with JDK 1.4 on WAS.

At this point, I have been able to get the application installed and started on the WebSphere console. When I enter the URL on a browser to start the wicket application I get the error:
“org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘viewController’: Scope ‘session’ is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request? If you are actually operating within a web request and still receive this message,your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.”

This is the web.xml I am using:

PepBoys Mobile Application

contextConfigLocation
/WEB-INF/endpointAppContext.xml

org.springframework.web.context.request.RequestContextListener

context
org.springframework.web.context.ContextLoaderServlet
0

wicket.wicket
org.apache.wicket.protocol.http.WicketServlet

configuration
development

applicationClassName
com.starmountsystems.wicket.app.WicketApplication

applicationFactoryClassName
org.apache.wicket.spring.SpringWebApplicationFactory

1

wicket.wicket
/app/*

This same web.xml works fine on Tomcat.

Thanks for your help.

I got past the last hurdle only to hit another. This is what I discovered. The error above resulted from a setting in our Spring applicationContext.xml. We were setting the scope to “session”, overriding the default of “singleton”. This is what the applicationContext.xml looked like:

After changing the scope to “singleton” the problem was resolved. However, we really need that bean to be associated with the session so we are stuck again.

Looks like, the filter issue with websphere can be fixed with this property

com.ibm.ws.webcontainer.invokefilterscompatibility=true

http://www-01.ibm.com/support/docview.wss?uid=swg24014758

http://www.nabble.com/URL-mounting-on-Websphere-causes-Error-404-td22455795.html

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: