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 "form". 326 entries found.

You can also try this same search on Google.

Write your Java apps in Visual Studio.NET?

Apparently Visual MainWin allows you to write your webapps in C# and .NET and then deploy them to a J2EE server.

Visual MainWin for J2EE enables these organizations to deploy .NET and J2EE applications on a single J2EE infrastructure, eliminating the need to maintain two separate application servers or implement complex interoperability solutions between the .NET and J2EE platforms.

This product certainly won't do anything for me. I've heard that Visual Studio is a great IDE, but if I can't write Java in it - what's the point?

how it works

Then again, I'm biased. I have a friend who is a long-time Java developer. Lately, he's been developing in C# because that was the only gig he could get (in Nevada). He says that C# is a piece of sh*t compared to Java.

Update: My friend contacted me to set the record straight. To quote him, "C# is OK, its the .NET framework that sucks ass. The C# syntax is a total ripoff of Java anyways."

Posted in Java at Feb 17 2004, 12:20:00 PM MST 21 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

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

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

A few thoughts on AppFuse

I've been thinking about how to structure AppFuse for the upcoming Spring and iBatis enhancements. These enhancements shouldn't require any directory structure changes. However, I've received some suggestions to change the common, ejb and web directory structure to be a little more inline with the tiers. So it would become something more like database, business and web (or dao, service and web). After thinking about this for the last couple of days, it seems to make sense. I picked up the notion of common from Erik Hatcher's JavaDevWithAnt, which I borrowed heavily from when creating AppFuse. Erik used common because this represented classes that would be included in both the web tier and the EJB tier. But since I (currently) don't plan on every adding EJBs to AppFuse, does it make sense? Even if I did, I'd probably only use SessionBeans, and those could easily fit into the service layer. The nice thing about moving the business layer (currently in web/**/services) to it's own directory is that it will get it's own JAR (with hardly any modifications to build.xml) and can be used outside of the webapp.

The nice thing about isolating the web directory to web-only classes is I can use Ant to replace any Struts-specific classes with WebWork or Tapestry. To prevent AppFuse from being cluttered with too many options, it'll ship with Struts out-of-the-box. If users want WebWork for their framework, they can download a WebWork version of the web-tier and run an Ant target that will replace all the Struts stuff with WebWorks stuff. It seems like the cleanest way to do web framework switching.

Another thing that might happen to AppFuse, caused by my enthusiasm to try out everything, is that it will contain too much stuff for a basic web application. It currently has security and user management built in, which is what most webapps need. I recently added in OSCache and Clickstream. OSCache is not enabled, but most webapps can probably use it somewhere. Clickstream is a different story. For most of the webapps I've built, this is not needed at all. Most of the apps are no more than 20 screens, and it's unlikely the client will care where people go the most. Another option that deserves ripping out is the idea of Struts' submodules. I tend to rip this out as the first thing when starting a new project. File Upload is something I've used rarely, so I should probably lose that feature too.

There are also other technologies that I've thought of adding to AppFuse, namely Quartz and Lucene. However, I've only used Quartz on 1 of my last 5 projects and Lucene on 2 - so obviously these might be considered bloat for a basic webapp. I think the best thing would be to implement these in AppFuse, on my own, and then document how I did it on the wiki (for an example, see diagramming build.xml with Vizant). If folks need to use it they can add it on their own. Documentation is always good, and if I can just document how to add stuff, I can certainly reduce the bloat.

Whaddya think - is it better to include options out-of-the-box or simply document them? Should I restructure the directories to match the tiers more?

Posted in Java at Jan 23 2004, 06:58:11 AM MST 9 Comments

Struts' MappingDispatchAction

I stumbed upon Struts' MappingDispatchAction this morning. It's basically the same thing as the LookupDispatchAction (which I use as my BaseAction in AppFuse), but you specify the method name in the action-mapping - rather than with request parameters (i.e. ?action=methodName). At first, this would seems tedious, but I usually end up creating a lot of action-mappings for a single action anyway, so this might be the way to go. There's really no need to change this in AppFuse now, but it is available in AppFuse's struts.jar (nightly from Dec 2, 2003).

In other news, the Open Source book is humming right along. I've finished the Hibernate, WebWork and Sitemesh chapters. I like what I see. IMO, this book is excellent for Hibernate, WebWork and Sitemesh newbies like me.

Posted in Java at Jan 20 2004, 05:38:43 AM MST 2 Comments

MD-5 password encryption and the "secret key"

According to a post on the Struts User mailing list, it's possible to encrypt a password using MD-5 (which is one-way), stuff it into a cookie, and then use a server's "secret key" to verify that it's a good one. Since I'm guilty of storing base64 encrypted passwords in cookies for a "Remember Me" feature, I'd love to figure out a more secure way of doing this.

So the question is - is it possible to implement "Remember Me" in J2EE in a secure way?

Setting the cookies on a certain path (i.e. /roller/security/) works, but not on Tomcat 5. I want to securely set my userid/password/rememberMe cookies at the root level of my app, map a filter to login.jsp (dispatcher = forward for TC 5) and be done with it.

Posted in Java at Jan 14 2004, 10:27:04 AM MST 6 Comments

Sunken/Highlighted Input Fields with CSS

One thing I really like about TheServerSide's new look is the sunken input boxes (that light up on focus) in the top right corner. I noticed that Macromedia does this on a lot of their form's too. It's good stuff. Here's how easy it is to add this "feature".

In your stylesheet, add the following class definitions:

/* for cool looking "sunken" input boxes, from www.theserverside.com */
form#searchForm input {
    padding-left: 4px;
    margin: 1px 1px 1px 1px;
    border: 1px solid black;
    color: #777;
    background-image: url(../images/input_white.gif);
}

form#searchForm input.focus {
    margin: 0px 0px 0px 0px;
    border-bottom: #ffdead solid 2px;
    border-right: #ffdead solid 2px;
    border-left: #c07300 solid 2px;
    border-top:  #c07300 solid 2px;
    color: #000000;
}

Of course, restricting these classes to one form (as I've done with form id="searchForm") is optional. Then in your form's input fields, add: add a couple of onfocus and onblur event handlers:

onfocus="this.className='focus'" onblur="this.className=''"

You'll also need to grab the background image and put it on your site. If you're adding this to a form in your webapp, it might be easier to add all the event handlers with JavaScript:

var inputs = document.getElementsByTagName("input");
for (i=0; i < inputs.length; i++) {
    inputs[i].onfocus=function() {this.className='focus'};
    inputs[i].onblur=function() {this.className=''};
}

Thanks to the guys at TheServerSide for showing me how to do this - I dig it.

Posted in The Web at Jan 14 2004, 08:35:50 AM MST 11 Comments

AppFuse on DB2 and WebSphere

I did some trial-and-error this morning, and with the help of a lot of handy-dandy unit tests, I got [Appuse working on DB2|AppFuseOnDB2]. I learned that I need to figure out how to create a database with page size = 8 by default - anyone got a SQL script to create DB2 databases (with reasonably sized table spaces) lying around?

Next up: Getting AppFuse running on WebSphere 5.1, this should be fun. Especially considering that they only seem to support .ear files, not .war files. I've only glanced at the thing for 5 minutes - any advice/links would be awesome.

Posted in Java at Jan 12 2004, 10:23:11 AM MST 9 Comments

Should I buy a PowerBook or a PC?

I received the following e-mail from Jason Boutwell a couple of days ago (published here with his permission).

I'm in the market for a new development laptop, either a P4 or a G4. I see from some of your older blog posts that you went through the same thing last year. First you went with a P4, then ended up with a PowerBook, so you've done both.

Since we seem to have similar professional interests (jobs where you BYOL, developing J2EE apps with tools like Hibernate, Struts, XDoclet, IDEA, etc.), you seem an ideal person to ask.

It's as simple as this: you can't beat the form-factor of the PowerBook. The fact that it's so small and light really make it a killer laptop. iPhoto, iMovie and iTunes are all killer apps and make digital photography and video so much easer. However, as a development environment - it sucks. It's sooooo much slower that my Windows XP desktop (that only cost $800).

My perspective of the speed difference might not be fair though - desktops (most likely) will always be faster than laptops. However, to run "ant deploy" for AppFuse takes 23 seconds on my 2.6 GHz CPU / 1.5 GB RAM desktop and 36 seconds on the PowerBook (1.33 GHz CPU / 1 GB RAM). It is difficult for me to develop on the Mac after developing on my PC for awhile, it's just so much slower. That being said, I don't think I'd be happy with a PC laptop - they're too ugly and bulky (for the 17" models) and don't offer the slick digital hub integration that the Mac does.

Don't expect the PowerBook to be a desktop replacement. And if you've never used a Mac, prepare to be frustrated. I've been a Windows user for 10+ years and getting used to the way a Mac works is not easy. It's been most frustrating for me because I can navigate around and do stuff on Windows really fast - it's almost like second nature. On the Mac, I have to think about how to do stuff. I think that Mac or Linux users migrating to Windows would feel the same frustration.

Above all else, you need to experience a Mac first hand. Go to your local Apple Store and play around with one. Download your favorite IDE and checkout an open source project from SourceForge. Download and install Ant and try compiling the project. You're gonna love the feel of the Mac, but you might find it's a bit slower than you're used to.

The one problem with not buying a PowerBook is that you'll always long for one. ;-) Would I buy a PowerBook again? Definitely. Would I give up my Windows desktop for a Mac desktop? No. Why should I give up all my years of becoming an efficient Windows user to be a slow-ass frustrated Mac user - it just doesn't make sense.

Posted in Mac OS X at Jan 10 2004, 05:58:17 PM MST 23 Comments