In part 1 of this article, we discussed some alternatives to handling a user login object that is controlled by a legacy application framework outside of Spring. We also discussed some disadvantages with our approach.
To recap, we faced a couple of challenges with implementing our approach:
- As mentioned earlier, the user credential bean was created by an external application and was not managed by the Spring container.
- When attempting to clone the session bean, that did not work using Apache BeanUtils because the user credential bean did not follow the JavaBeans specifications. That meant that reflection would not work because a property called “user” might have a getter or setter called “getUserName”.
Solution
Our solution was to clone the user credential bean and use Spring to manage the cloned bean. We’ll break this up into two steps:
- Create a session scoped Spring managed bean that is a copy of the user login object.
- Use the bean created in step 1 in our application.
Step 1 - Creating a session scoped bean for the user login object
The first thing we’ll do is create a session-scoped Spring-managed bean that is a copy of the UserLogin object created by the legacy framework and stored in the session. We’ll do this by creating a listener class called UserLoginListener that implements the HttpSessionAttributeListener interface. When the UserLogin object is created by the framework and placed in the session, our listener class will make a copy of the UserLogin object that will be managed by Spring. We do this by implementing the ‘attributeAdded’ method.
public class UserLoginListener implements HttpSessionAttributeListener { public void attributeAdded(HttpSessionBindingEvent event) { if (event.getName().equals(Constants.constUSER_LOGIN)) { XmlWebApplicationContext ctx = new XmlWebApplicationContext(); ctx.setServletContext(event.getSession().getServletContext()); ctx.setConfigLocation(Constants.constSPRING_CONFIG_LOCATION); ctx.refresh(); //get the existing UserLogin object created by the legacy framework UserLogin objLogin = (UserLogin) event.getValue(); //get the UserLogin bean created by Spring, which is actually a proxy. //copy the properties from the legacy framework object to the Spring bean. //we have to do this because we can't just copy a reference to the //Spring object, because Spring actually creates a proxy object UserLogin springUserLogin = (UserLogin) ctx.getBean("UserLogin"); try { copyProperties(objLogin, springUserLogin); } catch (ApplicationException e) { e.printStackTrace(); } } } }
The “copyProperties” method copies the properties from the bean created by the legacy application to the bean that will be managed by Spring. This effectively clones the bean:
private void copyProperties(UserLogin src, UserLogin dest) throws ApplicationException { if ((null == src) || (null == dest)) { throw new NullPointerException("Null input parameter"); } dest.setUserId(src.getUserId()); dest.setUserType(src.getType()); dest.setUserRole(src.getRole()); }
The next step is to add a session-scoped bean to the Spring configuration file (we use the default applicationContext.xml file). Note that it is a proxy bean because it is being injected into singleton or prototype beans.
<bean id="UserLogin" class="myapp.login.UserLogin" scope="session"> <aop:scoped-proxy/> </bean>
We need to update the web.xml file to add the listener class that we created, and also add an entry for a RequestContextListener, which is needed by Spring to associate the session scoped bean with the correct thread. Here’s a snippet from the web.xml file:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/applicationContext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> org.springframework.web.context.request.RequestContextListener </listener-class> </listener> <listener> <listener-class>myapp.login.UserLoginListener</listener-class> </listener>
Summary
Let’s recap what we have done. We created a new UserLogin class that is identical to the login bean that is used by the legacy application. Next, we wired that bean into our app (using Spring) and set the bean to be a session scoped proxy bean. We created a new listener class that gets the legacy login bean from the session and copies it to our new Spring-managed bean. We enabled the listener class by modifying the web.xml file.
That’s it for now. Now that we have our user login object managed by Spring and available for use in our application, our next article will bring it all home. We’ll take the user login class that we just created and use it in our application. See you next time.