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 "servlet". 226 entries found.

You can also try this same search on Google.

WebLogic Workshop's NetUI and Page Flow

FYI...

April Denver BEA User's Group Meeting

Tuesday April 6th 6:00pm
Tattered Cover Down Town
1628 16th Street
Denver, CO, 80202

This months meeting will focus on WebLogic Workshop's NetUI and Page Flow technology that is built on top of Struts. We have a special treat in that Eddie O'Neal who is the BEA Engineering technical lead on NetUI and Page Flow is comming to talk with us. The primary discussion will focus on Weblogic Workshop and NetUI technology which is built on top of Struts 1.1. We will look a how these two relate and talk about the additional features NetUI provides on top of Struts like the additions to the programming model and the richer data binding. We will also look at a Struts variation of the petstore application that was migrated to a Page Flow.

AGENDA

5:30 - 6:00 Registration, Networking, Refreshments
6:00 - 7:00 WebLogic Workshop NetUI and Page Flow - Edie O'Neal
7:00 - 8:00 Field Secrets the next installation - John Funk
8:00 - 9:00 Further discussion at the Wynkoop Brewery and Raffles

Technology followed by beer is always a good thing!

Posted in Java at Apr 04 2004, 11:39:02 AM MDT 8 Comments

Macromedia Flex 1.0 Released

Macromedia has released Flex 1.0. Flex is basically a server plugin that allows you to write XML to render flash. Here's the marketing lingo from their product page:

Flex is a presentation server installed on top of a J2EE application server or servlet container, a rich library of user interface components, an XML-based markup language used to declaratively lay out these components, and an object-oriented programming language which handles user interactions with the application. The result is a Rich Internet Application rendered using Flash Player and developed using industry standards and a development paradigm familiar to developers.

The major problem with Flex is its price.

Flex presentation server pricing starts at $12,000 for two CPUs and includes annual maintenance.

Macromedia's take on this seems to be "its an evolutionary step in web application design and development" - so $12K is a small drop in the bucket. Sun claims the same for JSF, but you don't see a hefty price tag on that sucker. What Macromedia doesn't seem to realize is that its important to market to developers. If you can inspire the developers to love your product - it's only natural that it will gain more traction. With a price of 12K and no free trial (CD by mail) - good luck on getting developer support.

Of course, as an independent consultant, I probably have a scewed perspective. Maybe the corporate drones like getting their development platform and tools shoved down their throat.

Posted in Java at Mar 29 2004, 07:36:10 AM MST 9 Comments

SiteMesh passed the 10 minute test

I decided to go out on a limb this evening and give SiteMesh a run for its money. The first warning sign was that the documentation refers to version 2.0.2, while the downloads section refers to version 2.0.1. So I proceeded to download 2.0.1. I promptly noticed that the install guide indicated I needed to download SiteMesh's two TLDs and configure them in my web.xml. Blech - this is so year 2000 - most modern containers support loading taglibs from JAR files with a URI.

So I did a good ol' cvs co of sitemesh from java.net. First of all, I'd like to say kudos to java.net and their CVS repositories - they've been rock solid for the few weeks I've used them. After checking out sitemesh, the first thing on my agenda was to give it the tried n' true ant test. This means I navigate to the sitemesh folder and simply type "ant". At this point, I should get one of two things - a BUILD SUCCESSFUL with a JAR or a help message telling me what I should type. I got the former, which I prefer.

After this, I integrated it into my app using the decorators documentation and deployed it. At first, I received the lovely ol' "getOutputStream() has already been called for this response" error, so I hacked PageFilter.java to use PrintWriter writer = response.getWriter(); instead of PrintWriter writer = new PrintWriter(response.getOutputStream());. Build, copy, package, deploy and voila - it all worked!! Wow that was easy. ;-)

Here's the weird part. I decided to reverse my hack on PageFilter.java to prove that I'd actually fixed the bug. Now I'm back to the original code I got from CVS and I can't get the getOuputStream() error to rear its ugly head. Doh!! This experience begs the following question.

Is SiteMesh stable enough on Tomcat 5 that I can should use it in my Spring Live sample app?

SiteMesh definitely passed my 10 minute test, we'll see if it holds up for the long haul. So far, I'm quite impressed with its easy configuration and quick implementation. I especially like that you can literally guess at it's syntax and you'll get it right. Maybe I was just lucky... heh

P.S. You should probably know I'm a big fan of Tiles. I wonder if SiteMesh will let me switch a decorator on the fly like Tiles does?

Posted in Java at Mar 24 2004, 12:07:56 AM MST 16 Comments

Supporting OGNL in Tag Libraries

Adding support for JSTL's Expression Language was fairly easy to do in the Display Tag. It was as simple as adding an ExpressionEvaluator and subclassing the ColumnTag and the TableTag. From there, all that was needed was needed a new TLD to reference these new classes.

So the question is - would it be just as easy to support the OGNL Expression Language? Does it have an ExpressionEvaluator I can write with the same simplicity as the JSTL version? If I could figure that out, I think creating OGNL-aware versions of the displaytag and struts-menu would be a piece of cake. All you'd need to do would be to change you're TLD's URI and you'd be off to the races!

Posted in Java at Feb 25 2004, 10:43:08 AM MST 3 Comments

How do you get around Struts' single inheritence model?

Adrian Lanning sent me an interesting e-mail yesterday. He's looking for a better way to extend Struts. I thought I'd post his message here and see if anyone has ideas.

I am a big struts fan and use it for my projects but I think there is something fundamentally wrong with the design. The real crux of the matter may be that Java is a single-inheritance model and Struts is designed more for multiple-inheritance.

Example 1.
Complexity when trying to use "extensions" to struts that have their own RequestProcessors. Such as my extension for roles (mentioned below) used together with Asqdotcom's ActionPlugin which is a plugin but still uses its own RequestProcessor, plus another hypothetical extension which has it's own RequestProcessor. Basically the only way to use them all is to modify the source of one or two to extend the others which doesn't seem like a good design.

Example 2.
Extending LookupDispatchAction to include per-method validation (set in struts-config.xml). Basically same problem. Need to combine functionality of ValidatorAction and LookupDispatchAction but can't extend from both. Have to modify source. Actually Brandon Goodin wrote this already (I find it very useful). It's called ValidatorLookupDispatchAction.

I know this is a common issue with single-inheritence models/languages. It would be really easy to extend Struts in a multiple-inheritance model.

* THE POINT *
I was just wondering if you knew of a better way to design when dealing with single-inheritance models to avoid problems such as these.

Personally, I don't find the need to extend Struts that much, so this is not much of an issue for me. I think Struts 2.0 will solve many of Struts single-inheritance design by declaring interfaces for all core components. I wonder when 2.0 is roadmapped to ship - sometime in 2006? ;-)

Later: The article, Security in Struts: User Delegation Made Possible, by Werner Ramaeker provides a good example of a Struts extension strategy.

Posted in Java at Feb 25 2004, 04:00:05 AM MST 23 Comments

Upgraded to Tomcat 5.0.19 + thoughts on Resin

I spent 5 minutes tonight and upgraded this site to use Tomcat 5.0.19. Everything seems to be working fine, save for a couple of new messages in catalina.out:

24-Feb-2004 7:48:34 PM org.apache.jk.common.HandlerRequest decodeRequest
WARNING: Error registering request
24-Feb-2004 7:48:44 PM org.apache.jk.common.HandlerRequest invoke
INFO: Unknown message 0

After talking with Rick last weekend, I'm going to try and migrate to Resin as my main dev appserver. The motivating factor was hearing Resin and Orion are so much faster than Tomcat. Sure I've heard this many times before, but mostly from Jakarta-haters. Rick's opinion holds a bit more water for me. Of course, he mentioned that his findings where based on Resin 2.x and Tomcat 4.x. I'd love to see a performance comparison between the latest versions of Orion, Resin and Tomcat.

I hope to modify AppFuse so it can easily run with Tomcat or Resin with a simple property switch. I've already started that process, but I hit a small snag.

I also hope to migrate this site to Resin 3.x soon. If nothing else, it'd be nice to learn more about Resin - and we all know the best way to learn a new technology is to interact with it on a daily basis.

Posted in Java at Feb 24 2004, 08:01:10 PM MST 11 Comments

NYC: DisplayTag and Struts Menu

At the NYC Conference, I'm going to be talking about The Display Tag and Struts Menu. I figure the best presentations are ones that cover new features or introduce something new. So I'm hoping to add the following features to the two libraries in the next month. Please let me know if there are other's you'd really like to see - or ones that'd make the audience go *wow*.

DisplayTag: I'd like to add this pagination enhancement so you can get easy interaction between the records displayed and the records fetched. I'd also like to see sorting by property, not be contents. Lastly, I hope to add an example that does CRUD on a table using JSTL and simple checkbox and input fields.

Struts Menu: A lot of users are interested in seeing a menu that's created from a database table. This shouldn't be too difficult because examples are out there. I was also thinking of adding support for the Joust Outliner, but it doesn't look like it's still developer or actively used. If there's interest, I'll add it.

If you think I'm blogging a lot today (don't you work Raible?), it's because I'm on babysitting duty. Abbie is sick with a fever and Julie had to go to work - so my work day starts when she gets home. I've got the little one tied up with a little Winnie the Pooh action right now...

Later: The DHTML Kitchen has some nice menus, but they're not free. Anyone know of open source menus like these?

Posted in Java at Feb 24 2004, 02:41:26 PM MST 33 Comments

AppFuse Refactorings Part IV: Replacing Hibernate with iBATIS

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, Spring Integration and Remember Me refactorings.

- - - -
On my last project, we ported an existing JSP/Servlet/JDBC app to use JSP/Struts/iBATIS. In the process, I got to learn a lot about iBATIS and grew to love the framework (although I prefer to spell it iBatis). It was super easy to port the existing JDBC-based application because all of the SQL was already written (in PreparedStatements). Don't get me wrong, I think Hibernate is the better O/R Framework of the two, but iBATIS works great for existing databases. The best part is that iBATIS is just as easy to code as Hibernate is. For example, here's how to retrieve an object with Spring/Hibernate:

List users =
    getHibernateTemplate().find("from User u where u.username=?", username);

And with Spring/iBATIS, it requires a similar amount of Java code:

List users = getSqlMapTemplate().executeQueryForList("getUser", user);

The main difference between the two is that iBATIS uses SQL and Hibernate uses a mapping file. Here's the "getUser" mapped statement for iBATIS:

  <mapped-statement name="getUser" result-class="org.appfuse.model.User">
      SELECT * FROM app_user WHERE username=#username#;
  </mapped-statement>

Spring makes it super easy to configure your DAOs to use either Hibernate or iBATIS. For Hibernate DAOs, you can simply extend HibernateDaoSupport and for iBATIS DAOs you can extend SqlMapDaoSupport.

Now to the point of this post: How I replaced Hibernate with iBATIS. The first thing I had to do was write the XML/SQL mapping files for iBATIS. This was actually the hardest part - once I got the SQL statements right, everything worked. One major difference between iBATIS and Hibernate was I had to manually fetch children and manually create primary keys. For primary key generation, I took a very simple approach: doing a max(id) on the table's id and then adding 1. I suppose I could also use the RandomGUID generator - but I prefer Longs for primary keys. Hibernate is pretty slick because it allows easy mapping to children and built-in generation of primary keys. The ability to generate the mapping file with XDoclet is also a huge plus.

As far as integrating iBATIS into AppFuse, I created an installer in contrib/ibatis. If you navigate to this directory (from the command line), you can execute any of the following targets with Ant. It might not be the most robust installer (it'll create duplicates if run twice), but it seems to work good enough.

                install: installs iBatis into AppFuse
              uninstall: uninstalls iBatis from AppFuse
    uninstall-hibernate: uninstalls Hibernate from AppFuse

                   help: Print this help text.

All of these targets simply parse lib.properties, build.xml and properties.xml to add/delete iBATIS stuff or delete Hibernate stuff. They also install/remove JARs and source .java and .sql files. If you're going to run this installer, I recommend running "ant install uninstall-hibernate". Of course, you can also simply "install" it and then change the dao.type in properties.xml. This will allow you to use both Hibernate and iBATIS DAOs side-by-side. To use both Hibernate and iBATIS in an application, you could create an applicationContext-hibatis.xml file in src/dao/org/appfuse/persistence and change the dao.type to be hibatis (like that nickname ;-). In this file, you'd have to then define your transactionManager and sqlMap/sessionFactory. I tested this and it works pretty slick. Click here to see my applicationContext-hibatis.xml file.

Some things I noticed in the process of developing this:

  • Running "ant clean test-dao" with iBATIS (28 seconds) is a bit faster than Hibernate (33 seconds). I'm sure if I optimized Hibernate, I could make these numbers equal.
  • The iBATIS install is about 500K, whereas Hibernate's JARs are around 2 MB. So using iBATIS will get you a slightly faster and smaller AppFuse application, but it's a bit harder to manipulate the database on the fly. There's no way of generating the tables/columns with iBATIS. Instead it uses a table creation script - so if you add new persistent objects, you'll have to manually edit the table creation SQL.

Hibernate is still the right decision for me, but it's cool that iBATIS is an option. Even cooler is the fact that you can mix and match Hibernate and iBATIS DAOs.

Posted in Java at Feb 11 2004, 10:09:23 PM MST 10 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