Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences

Edit this page


Referenced by
AppFuse
AppFuseSecurityMetho...
AppFuseSupport
AppFuseSupport_ko
AppFuse_it
AppFuse_jp
AppFuse_zh
Downloads




JSPWiki v2.2.33

[RSS]


Hide Menu

AppFuseSpringUpgrade


About this Article

This article is designed to explain how to port an AppFuse 1.3 app to use AppFuse 1.4 - where Spring binds everything together and a more robust Remember Me feature exists.

There are many changes between AppFuse 1.3 and AppFuse 1.4. To read more about them, click the links below:

Table of Contents

  • [1] Re-arrange your packages and directory structures
  • [2] Integrate Spring and its configuration files
  • [3] Modify build.xml and properties.xml
  • [4] Delete files and modify tests
  • [5] Change Hibernate DAOs to use Spring
  • [6] Change Managers to be IoC Ready
  • [7] Change Actions to use Managers from Spring
  • [8] Modify web tests to work with Spring
  • [9] Integrate new Remember Me System

Re-arrange your packages and directory structures [#1]

1. src/ejb -> src/dao and test/ejb -> test/dao

2. Move all your POJOs from the "persistence" package to the "model" package. Remember to change any XDoclet tags in your classes that might refer to child mappings.

3. Move the Constants.java file from src/common to src/dao - it belongs in the org.appfuse (or com.yourcompany.appname) directory/package.

4. src/common -> src/service and test/common > test/service

5. Rename the org.appfuse.common.util package to simply org.appfuse.util footnote.

6. Move src/web/**/service and test/web/**/service to src/service and test/service directories, respectively.

7. Rename the org.appfuse.webapp.service to org.appfuse.service.

Integrate Spring and its configuration files [#2]

1. Copy the Spring JARs from appfuse/lib (spring.jar and aopalliance.jar).

2. Add the following to lib/lib.properties:

#
# Spring Framework - http://www.springframework.org
#
spring.version		= 1.0-rc1
spring.dir=${lib.dir}/spring-${spring.version}
spring.jar=${spring.dir}/spring.jar

3. Copy applicationContext-hibernate.xml from AppFuse's src/dao/**/hibernate directory and put it into your src/dao/**/hibernate directory. Modify this file to have the appropriate mapping files and DAO bindings for your application.

4. Copy applicationContext-database.xml from AppFuse's test directory and put it your test directory. Also copy test/dao/applicationContext-service.xml file to your test/dao directory.

5. Copy applicationContext-service.xml from AppFuse's src/service/** directory and put it into your src/service/** directory. Modify this file to have the appropriate Manager bindings and declarative transactions for your application.

6. Copy applicationContext.xml and applicationContext-database.xml from AppFuse's web/WEB-INF directory to your web/WEB-INF directory.

7. Change the JNDI name in applicationContext-database.xml from jdbc/appfuse to your app's DataSource name.

Modify build.xml and properties.xml [#3]

At this point, I decided to cheat and use Beyond Compare to do a diff of the two files. Here is what I found:

properties.xml
1. Add the dao.type parameter:

<property name="dao.type" value="hibernate"/>
2. Change the word ejb to dao.
3. Numerous classpath changes - using a diff tool is really the way to go here.

build.xml
1. Numerous changes - too many to list. Using a diff tool like Beyond Compare or WinMerge makes this pretty easy.

2. Change any references to org/appfuse/webapp/form to match your package/directory structure. Currently, there is only one in the "compile-service" target.

2. Copy tomcatTasks.properties from AppFuse's lib/ant-contrib-0.5 directory.

Delete files and modify tests [#4]

1. Because we are now using Spring to configure Hibernate, we can delete a few classes. Below is a list:

  • src/dao/**/persistence/ServiceLocator.java
  • test/dao/**/persistence/ServiceLocatorTest.java
  • src/dao/**/persistence/DAOFactory.java
  • test/dao/**/persistence/DAOFactoryTest.java
  • src/dao/**/persistence/hibernate/BaseDaoHibernate.java
  • web/WEB-INF/classes/hibernate.cfg.xml

2. Replace your test/dao/**/BaseDaoTestCase.java class with the one from AppFuse. Adjust your *DaoTest.java classes accordingly, I simply deleted the constructor and changed setUp()/tearDown() to resemble the following:


    protected void setUp() throws Exception {
        log = LogFactory.getLog(UserDaoTest.class);
        dao = (UserDAOctx.getBean("userDAO");
    }

    protected void tearDown() throws Exception {
        dao = null;
    }

3. Replace your test/service/**/BaseManagerTestCase.java class with the one from AppFuse. Adjust your *ManagerTest.java classes accordingly. I simply changed my setUp() and tearDown() methods to be something like this:


    protected void setUp() throws Exception {
        mgr = (UserManagerctx.getBean("userManager");
    }

    protected void tearDown() throws Exception {
        mgr = null;
    }

Change Hibernate DAOs to use Spring [#5]

1. Now you'll need to change your Hibernate DAOs extend Spring's HibernateDaoSupport class and use the Hibernate Template. See the UserDAOHibernate.java class in AppFuse for an example.
I replaced many ses.createQuery calls with getHibernateTemplate().find and I was also able to remove many try/catch statements.

2. Remove any constructors from your DAOs - Spring needs a no-arg constructor to initialize the DAOs.

NOTE: For the UserDAO, it's probably best to copy the one from AppFuse since there's new methods for persisting user's login cookies. You'll also need to copy the UserCookie object to your src/dao/**/model directory.

3. A DAOException is not thrown when getHibernateTemplate().load() fails. This is because DAOException extends Exception and Spring throws a RuntimeException. Because of this, I had to modify some of my DAOs to use getHibernateTemplate().get() and then check for null -> if null, then throw DAOException.

4. At this point, you should be ready to run ant setup-db followed by ant test-dao. Before doing this, you might want to trim down Spring's logging. To do this, add the following to your web/WEB-INF/classes/log4j.properties file:

log4j.logger.org.springframework=WARN

Change Managers to be IoC Ready [#6]

1. Now you'll need to change your Managers to remove the constructor and add a setter for the DAO. For example, here is the setter for the LookupDAO:


    public void setLookupDAO(LookupDAO dao) {
        this.dao = dao;
    }

You'll also want to organize/optimize imports and remove any references to deleted classes (i.e. DAOFactory).

2. At this point, you should be able to run ant test-service without errors. I had to fix a few compile errors and such before this actually worked.

Change Actions to use Managers from Spring [#7]

The next step to integrating Spring is to change your web layer to use Spring for communicating with the services layer.

1. First, you'll want to remove the getConnection() method of your ActionFilter since Spring handles this. Also, remove the try/catch statement around the doFilter method (we'll use Springs OpenSessionInViewFilter instead).

2. Change the new UserManagerImpl(conn) call to be:


WebApplicationContext context =
    (WebApplicationContextfilterConfig.getServletContext()
    .getAttribute(WebApplicationContext
                  .ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

     UserManager mgr = (UserManagercontext.getBean("userManager");

3. This same logic is needed in any non-Struts classes that talk to a Manager. Re-use the above code where appropriate - i.e. RegistrationServlet and Listeners.

You gotta love Spring's super-long class names, eh? ;-)

4. Add the following in BaseAction.java:


    private WebApplicationContext ctx = null

    /**
     * Convenience method to bind objects in Actions
     @param name
     @return
     */
    public Object getBean(String name) {
        if (ctx == null) {
            ctx = WebApplicationContextUtils
                  .getRequiredWebApplicationContext(servlet.getServletContext());
        }
        return ctx.getBean(name);
    }

5. Change your Actions to get Managers using the following syntax:


    UserManager mgr = (UserManagergetBean("userManager");

6. (Optional) Add Spring's OpenSessionInViewFilter for Hibernate.

  • First add the following to metadata/web/filters.xml:
<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilter</filter-class>
</filter>
  • Then add filter-mappings for each Servlet/Filter that needs a connection. Here's the default ones from AppFuse:
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/passwordHint/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/register/*</url-pattern>
    </filter-mapping>

Modify web tests to work with Spring [#8]

1. Edit test/web/**/action/BaseStrutsTestCase.java and change the setUp()/tearDown() methods to be the following:


    protected WebApplicationContext ctx = null;

    public void setUp() throws Exception {
        // populate the userForm and place into session
        String username = login.getString("username");
        ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
            this.getSession().getServletContext());
        UserManager userMgr = (UserManagerctx.getBean("userManager");
        userForm = (UserFormuserMgr.getUser(username);
        getSession().setAttribute(Constants.USER_KEY, userForm);
    }

    protected void tearDown() throws Exception {
        ctx = null;
    }

2. Change any *ActionTest.java classes to use ctx.getBean() to obtain Manager instances.

The nice thing about using Spring is I was able to remove all my close session hacks in the ActionTests. Very cool.

Integrate new Remember Me System [#9]

1. Copy src/web/**/filter/LoginFilter and src/web/**/action/LoginServlet from AppFuse. If you're using Eclipse, you can copy the entire file (in package view) and then just organize imports.

2. Remove the LOGIN_PATH String from src/dao/**/Constants.java and add the LOGIN_COOKIE variable from AppFuse's Constants.java.

3. Copy the checkLoginCookie, createLoginCookie and removeLoginCookies from AppFuse's src/service/**/UserManager.java interface (and UserManagerImpl.java) and put them in yours.

4. Copy the RandomGUID.java class from AppFuse's src/web/**/util directory and put it into yours.

5. Add logic in src/web/**/ActionFilter.java to set a "remember me" cookie if the user requested it. This should go right after the user is stuffed in the session.


    // if user wants to be remembered, create a remember me cookie
    if (session.getAttribute(Constants.LOGIN_COOKIE!= null) {
        session.removeAttribute(Constants.LOGIN_COOKIE);
    
        String loginCookie = mgr.createLoginCookie(username);
        RequestUtil.setCookie(response, Constants.LOGIN_COOKIE,
                              loginCookie, request.getContextPath());
    }

6. Move the login.jsp and logout.jsp pages from the web/security to the web folder. Delete the security folder.

7. Change the username cookie's path to be the contextPath. To do this, change web/scripts/login.js - search for "/security/" and change it to "/".

8. Change the web/pages/loginForm.jsp to use <c:url value="/authorize"/> for the loginForm's action, instead of <c:url value="/security/authorize"/>.

9. Change the form-login-config in metadata/web/web-security.xml to remove "/security" and also change the form-error-page to be a real page.

    <form-login-config>
        <form-login-page>/login.jsp</form-login-page>
        <form-error-page>/loginError.jsp</form-error-page>
    </form-login-config>

10. Create a loginError.jsp page in the web directory. You can copy the one from AppFuse, or just use the code below:

<%@ include file="/common/taglibs.jsp"%>

<c:import url="login.jsp">
    <c:param name="error" value="true"/>
</c:import>

11. Remove the session.invalidate() scriptlet from web/logout.jsp as the new LoginFilter will handle invalidating sessions.

12. Remove the cookie setting logic in RegistrationServlet that does Remember Me automatically for new users.

13. Using a diff tool (like Beyond Compare), compare your UserAction.java class with the one from AppFuse and make modifications as needed.

14. Add the following key to web/WEB-INF/classes/ApplicationResources.properties:

userProfile.cookieLogin=You cannot passwords when logging in with the <strong>Remember Me</strong> feature. Please logout and log back in to change passwords.

15. Change the "logout" forward in metadata/web/global-forwards.xml to be:

<forward name="logout" path="/logout.jsp" />

16. In RegistrationServlet.java, remove "security" from the nextURL variable:


String nextURL = "login.jsp";




[#footnote] Replace org.appfuse with com.yourcompany.appname or whatever package naming convention you are using.


Go to top   Edit this page   More info...   Attach file...
This page last changed on 06-Nov-2006 13:52:58 MST by DanQuellhorst.