Matt RaibleMatt Raible is a writer with a passion for software. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.
You searched this site for "appfuse". 771 entries found.

You can also try this same search on Google.

Hibernate and iBatis co-existing

AppFuse is in an interesting state right now. In order for me to easily switch to using iBatis for the DAO layer, I left all the Hibernate stuff intact and just added iBatis classes and JARs. The next step is to extract the iBatis stuff into a separate CVS module and write a build.xml file to replace the Hibernate implementation with iBatis.

The one thing that will suck, in the iBatis version, is that the database can't be dynamically created from POJOs. However, if you're going to use the iBatis implementation, its likely that the database (or SQL) already exists. The reason I'm writing this post is because right now, in CVS, you can change the dao.type property to "ibatis" or "hibernate" when building and Voila! - that's the implementation you'll get. I see no reason why any project would ever want to have both implementations (maintenance would be a nightmare), so that's why I'm extracting the iBatis stuff in the next few days.

Posted in Java at Feb 10 2004, 04:20:47 PM MST 4 Comments

AppFuse Refactorings Part III: Remember Me

This is a continuing series on what I'm doing to make AppFuse a better application in Winter/Spring 2004. Previous titles include: Changing the Directory Structure and Spring Integration.

- - - -
AppFuse includes a Remember Me feature that works with Container-Managed Authentication. In version 1.3 it works by setting a few cookies: username, password and rememberMe. The last one being a simple flag that the user wants to be remembered. Then a LoginFilter checks for the rememberMe cookie, and if present, logs in the user using the other cookie values. The obvious issue with this is that the password being sent and stored on the user's browser.

This was easily solved in Tomcat 4 by placing the form-login-page and form-error-page under a "security" directory and then setting cookies on the /appfuse/security path. This way, since no other part of the app can access /appfuse/security, these cookies can never be retrieved in any part of the application. The problem is that this didn't work in Tomcat 5 since it forwards to the login page (rather than redirecting). Since forwarding is obviously a better solution (user's can't bookmark the login page), I needed a new way to implement the Remember Me feature.

To my knowledge, cookies can only be stolen if someone is able to login to your AppFuse app and insert JavaScript to send the "document.cookie" value to an external URL. So for AppFuse, it's likely that stealing cookies is not much of an issue. However, for applications like Roller, it is an issue - since other bloggers on the same server (i.e. JRoller) could put JavaScript on their blog to grab cookies from other users.

Just as I was about to give up searching for solutions, along came Charle's persistent cookie strategy. Here's how I implemented it in AppFuse. Hopefully it follows all the rules and is a good solution. Here's what I did make it happen.

- - - -
Step 1: Setting the cookie.
Scenario: A user logs in and selects the "Remember Me" checkbox.
What Happens: When a user clicks the Login button, they submit to a LoginServlet that redirects them to "j_security_check" to take advantage of Container-Managed Authentication. This servlet is responsible for ensuring an SSL Login (if enabled), encrypting the user's password (if enabled) and also sets a session variable to indicate the user wants to be remembered. After authenticating, the user will hit the ActionFilter, where the following code sits:

    // 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());
    

In the above code snippet, the UserManager.createLoginCookie(username) method is responsible for creating a new cookie string and storing this information in the database.

    public String createLoginCookie(String usernamethrows Exception {
        UserCookie cookie = new UserCookie();
        cookie.setUsername(username);

        return saveLoginCookie(cookie);
    }
  
    /**
     * Convenience method to set a unique cookie id and save to database
     @param cookie
     @return
     @throws Exception
     */
    private String saveLoginCookie(UserCookie cookiethrows Exception {
        cookie.setCookieId(new RandomGUID().toString());
        dao.saveUserCookie(cookie);

        return cookie.getUsername() "|" + cookie.getCookieId();
    }

The RandomGUID is a class I found on Java Exchange. Once the rememberMe cookie was set, I had to configure LoginFilter.java (mapped to form-login-page and form-error-page) to look for this cookie. This brings us to Step 2.

- - - -
Step 2: Using the cookie to login the user.
Scenario: A User has already logged in successfully with "Remember Me" enabled.
What Happens: When the login page is served up to the user, the LoginFilter is invoked and it checks the validity of the "Remember Me" cookie.

    Cookie c = RequestUtil.getCookie(request, Constants.LOGIN_COOKIE);

    WebApplicationContext context = 
        (WebApplicationContextconfig.getServletContext().getAttribute
        (WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    UserManager mgr = (UserManagercontext.getBean("userManager");
  
    if (c != null) {
        try {
            String loginCookie = mgr.checkLoginCookie(c.getValue());

The UserManager.checkLoginCookie(value) method looks up a record based on the random GUID, and if it finds a match, it creates a new GUID and saves it in the database. If null is returned, it means the cookieId doesn't exist, and the login proceeds as it normally would. Below is the guts of the checkLoginCookie() method.

    public String checkLoginCookie(String valuethrows Exception {

        String[] values = StringUtils.split(value, "|");

        if (log.isDebugEnabled()) {
            log.debug("looking up cookieId: " + values[1]);
        }

        UserCookie cookie = dao.getUserCookie(values[1]);

        if (cookie != null) {
            if (log.isDebugEnabled()) {
                log.debug("cookieId lookup succeeded, generating new cookieId");
            }

            return saveLoginCookie(cookie);
        else {
            if (log.isDebugEnabled()) {
                log.debug("cookieId lookup failed, returning null");
            }

            return null;
        }
    }

You can see from this, that if the lookup succeeds - a new cookieId is saved and returned. If a not-null cookieId is returned, the remember me cookie is updated, the user is looked up and the Filter forwards an authentication request (with username/password) to the LoginServlet. The Filter also sets an attribute to let the application know that this user authenticated via cookies. This is important so that cookie-authenticated users cannot change passwords. When using cookie-authentication, the password field is hidden and a message warns the user that they must logout/login to change passwords.

Lastly, I had to come up with a solution to remove these login cookies.

- - - -
Step 3: Allow the user to clear their login cookies.
Scenario: A User has already logged in successfully with "Remember Me" enabled.
What Happens: For this, I implemented a simple solution. When a user logs out, all persistent login cookies are removed.

I don't know if it's best to divulge the details of AppFuse's cookie login strategy. However - it *is* open source - so folks can find figure it out if they really want to. By exposing it to the world, I hope to get the most robust solution possible.

Next up, how I replaced Hibernate with iBatis. Using Spring, it only took me a few hours! Pretty slick, eh? ;-)

Posted in Java at Feb 10 2004, 10:35:37 AM MST 4 Comments

AppFuse Refactorings Part II: Spring Integration

I took some time last weekend and refactored AppFuse to use Spring to replace my Factories and Hibernate configuration. It only took me a couple of hours, which says a lot for Spring. I was amazed at how many things just worked. It actually lifted me out of my flu symptoms and made me feel euphoric. Or it could have been the Sudafed. In reality, I only replaced one Factory class (DAOFactory) - a fairly large class that instantiated DAOs using reflection and constructor variable inspection. I was also able to get rid of the ServiceLocator class, the getConnnection() stuff in ActionFilter and the hibernate.cfg.xml file.

The one thing I found when looking at the Petclinic and JPetstore apps was that they used an applicationContext.xml file for unit tests, and a (very similar) one for running the app in a container. To me, this was a warning sign. DRY (Don't Repeat Yourself) is a big reason for using XDoclet and I'm beginning to think that Spring could benefit from a little XDoclet lovin'. Anyway, back to the story.

I wanted to find a way to use the same XML files for testing and in-container execution. As you might know from Part I, AppFuse has 3 different tiers: dao, service and web. To run unit tests for the dao and service layers, I simply load a applicationContext.xml file in my JUnit test's setUp() method and go from there. I saw this in the petclinic app and found that it works pretty well. In the end, I decided to setup different XML files for each layer - applicationContext-hibernate.xml, applicationContext-service.xml and applicationContext.xml for the web layer. The main applicationContext.xml uses entity includes to reference the other two files.

The main pain I found was that the entity includes required different paths for tests vs. running in container. Basically, for tests, I had to use:

<!ENTITY database SYSTEM "applicationContext-database.xml">

While tests, using the ClassPathXmlApplicationContext required:

<!ENTITY database SYSTEM "WEB-INF/applicationContext-database.xml">

Using Ant to do a little replace logic allowed me to jump over this hurdle.

Using this setup, any new DAO definitions are added in src/dao/org/appfuse/persistence/hibernate/applicationContext-hibernate.xml, new Manager definitions (and declarative transaction settings) are be added in /src/service/org/appfuse/service/applicationContext-service.xml. The test-specific applicationContext-database.xml sits in the "test" directory and contains the following:

<bean id="propertyConfigurer" 
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
	<property name="location"><value>database.properties</value></property> 
</bean> 

<bean id="dataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
	<property name="driverClassName"> 
		<value>${hibernate.connection.driver_class}</value> 
	</property> 
	<property name="url"> 
		<value>${hibernate.connection.url}</value> 
	</property> 
	<property name="username"> 
		<value>${hibernate.connection.username}</value> 
	</property> 
	<property name="password"> 
		<value>${hibernate.connection.password}</value> 
	</property> 
</bean>

While the applicationContext-database.xml for the web is simply:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName"><value>jdbc/appfuse</value></property>
</bean>

To integrate Spring with my web layer (Struts), I just used the ContextLoaderListener in my web.xml file. I didn't see any point in bringing yet another JAR file into the mix.

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

Finally, to expose Spring's context to my Struts Actions, I added the following to my BaseAction.java class:

    private WebApplicationContext ctx = null;

    public Object getBean(String name) {
        if (ctx == null) {
            ctx = WebApplicationContextUtils
                  .getRequiredWebApplicationContext(servlet.getServletContext());
        }
        return ctx.getBean(name);
    }

This way, the UserManager implementation can be easier retrieved using:

    UserManager userMgr = (UserManagergetBean("userManager");

The best part about the Spring integration in AppFuse is: (IMO) its Hibernate support and how it drastically simplifies my Hibernate DAOs (as if Hibernate wasn't simple enough already). I dig the ability to specify declarative transactions, and this refactoring seems to have reduced the "src" distribution of AppFuse by 2 MB (to 10MB total)! I don't know where this came from since the Spring JAR is almost 1 MB. The appfuse.war is about 500 KB larger, but I can live with that.

Of course, all of this has been checked into CVS if you'd like to take a look.

Posted in Java at Feb 05 2004, 12:52:18 PM MST 17 Comments

ActionForms: Struts' bastard child

Folks that rag on Struts seem to point to ActionForms as one of its major design flaws. I've been slightly frustrated with ActionForms this week, but overall, I think they're a good thing. It's possible my ActionForm affection is misguided. The major reasons I like them is because I believe they allow me to do stuff that is not possible in other web frameworks. I definitely could be wrong though, so I'm hoping the other framework authors/users will speak up and say "My framework does that!" Specifically, I'm talking to the WebWork, Tapestry, JSF and Spring folks.

I do wish that I could throw my POJOs up to my UI, so I hope the following things are possible with the WTJS frameworks. It would simplify things if I didn't need to transform POJOs -> ActionForms (particularly with Hibernate).

  • Validation and re-displaying the user's entered values. I love Struts' Validator. It's great how I can generate the validation.xml file with XDoclet and have a "required" struts.validator tag right next to a hibernate not-null="true" tag. Two questions:

    1. Can any of the WTJS frameworks re-display the user's entered values? Specifically, back into the input fields where the user entered them? I think this is important for useability.

    2. Do any of them have the ability to generate client and server-side validation, or at least declaratively write it in XML?

    I'd love to find a way to hack the Validator to allow you to define validation rules for a POJO and then use an Interceptor to validate it. I don't like how Spring requires you to write YAJC (Yet Another Java Class) to do validation.
  • Handling checkboxes. The basic reason for the reset() method in ActionForms is to handle checkboxes. Since unchecked checkboxes don't send a value - there needs to be a way to set a boolean back to null. I'm sure all of the WTJS frameworks support checkbox handling, I just want to make sure - and frankly - I'd like to learn a little more about how each framework handles it.

I guess there's only two reasons I like ActionForms - the major one being the ability to specify (and generate) my client and server-side validation in XML. If I don't find this same slick feature in the other frameworks, I might have to do a bit of hacking to do the Interceptor with Validator thing - but hopefully I won't need to go there.

Posted in Java at Feb 04 2004, 08:31:13 PM MST 25 Comments

[ANNOUNCE] Hibernate 2.1.2 Released

Hibernate 2.1.2 has been released. Looks like they fixed a whole sh*tload of bugs. Read the Release Notes or Download. All tests pass in AppFuse!

Posted in Java at Feb 04 2004, 04:18:51 PM MST 1 Comment

Running AppFuse on Orion (a.k.a. OracleAs)

Mike Lawrence has been beating his head against the wall trying to get AppFuse running on Oracle App Server for the last few days. The good news is he finally got it working and he's written up some documentation. I wiki-fied his contribution and now I present you [How To run AppFuse on Orion|AppFuseOnOrion]. Enjoy!

Posted in Java at Feb 04 2004, 10:18:41 AM MST 2 Comments

AppFuse Refactorings Part I: Changing directory structure

I changed the directory structure of AppFuse's "src" and "test" directories this weekend. Rather than:

src 
  - common
  - ejb
  - web

I changed it to:

src
  - dao
  - service
  - web

The change wasn't too difficult, but the results of doing it make me a bit sick to my stomach. I always new that the Managers in AppFuse were dependent on Struts, that's why I originally put them in the src/web/**/webapp/service folder. Now that I've moved them into the service folder, they don't inherit all the luxuries like struts.jar being in the classpath. Even worse, to compile the Managers, I have to compile any ActionForms, both from the build/web/gen directory, as well as from src/web/**/Form. This is because the Managers use BeanUtils.copyProperties() to transfer values from POJOs -> ActionForms and visa-versa.

Ech - this exercise has really shown me how tied together the different directories and layers are. I think I liked it better the other way - or maybe I just liked not knowing how tightly integrated everything was. ;-) The most frustrating thing turned out to be that Ant's <javac> task wanted to re-compile the generated ActionForm's each time I I ran "ant compile-service". Adding an <uptodate> property fixed this problem, but it seems like it should be easier than that.

I ended up putting the org.appfuse.model package in the "dao" directory. It just made things easier - since the model.* classes are used in my DAOs and the "test-dao" needs the XDoclet-generating Hibernate mapping files. I didn't want to have to depend on classes in the src/service directory to compile src/dao. It's bad enough I have to do that with the service-web stuff.

All in all, I'm happy with the refactorings, but implementing workarounds for the service-web relationship was no fun. I probably did this when I originally created AppFuse, but since I haven't heavily manipulated build.xml in so long - I've forgotten the trouble I went through.

Oh yeah, I also integrated Spring for binding the layers and configuring Hibernate. And Charles' persistent cookie strategy? That's done too. I'll write up details on both of these refactorings in the next couple of days.

Posted in Java at Feb 03 2004, 03:56:27 PM MST 10 Comments

One big Service class or several small classes?

I asked this question on the Spring Forums a couple of days ago, but I didn't get a response, so I'll try it here.

Looking through the Spring's petclinic and jpestore applications - both seem to advocate one single class to interface with the database (hibernate or dao/ibatis). I also noticed this pattern in Java Open Source Programming. Is this a recommended pattern or do you still think there's value in several service-level classes (i.e. one for each DAO)? I imagine the single interface and impl could grow quite large on a big project. In fact, in the Spring examples, the Manager isn't even a Business Delegate, it's really a Persistence Manager.

BTW, the Petclinic app is a helluva plug for Hibernate. The Hibernate implementation class is 53 lines, and the JDBC implementation class is 770 lines! If you're still using JDBC over Hibernate, please explain why you put yourself through the pain?

I do like the simplicity of the Single Manager approach, but I tend to do 1 Manager for each DAO (or something resembling this pattern). What do you advocate? AppFuse follows the 1-Manager to 1-DAO pattern. Should I switch to the Single Manager pattern?

Posted in Java at Feb 02 2004, 09:44:39 AM MST 19 Comments

[AppFuse] Use Velocity instead of JSPs for your view?

If you want to use Velocity Templates instead of JSPs in your AppFuse-based web application, Cameron Gray has figured it out. Not only did he figure it out, but he was nice enough to write up a tutorial on it. Thanks Cameron - the time you took to write the tutorial is greatly appreciated.

In other AppFuse news, Rick Hightower seems to have convinced it to work with MyEclipse, JBoss and the Firebird database. Also, I received a few messages this week and I think another user has convinced it to run on Orion/Oracle successfully! If I ever get motivated, I'll try to put How-Tos on the wiki for all of these.

Posted in Java at Jan 31 2004, 10:01:59 AM MST

Ant 1.6.0 with Canoo's WebTest and AppFuse

If you want to use Ant 1.6 with Canoo's WebTest, you'll need to patch the source. Many thanks to Paul Kavanagh for providing the patch - I hate it when I can't upgrade to the latest release. Since AppFuse relies on WebTest for running its JSP tests, you must patch webtest to use Ant 1.6. Or you can can just download webtest.jar and put it in your lib/webtest*/lib directory. This is the from the latest version of WebTest's CVS (build 379 is the latest release used in AppFuse).

Posted in Java at Jan 29 2004, 01:43:00 PM MST 1 Comment