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.

Simplifying XmlHttpRequest with JSON-RPC

In my day job, we decided to use a little XMLHttpRequest lovin' to populate one drop-down from another. This is my review of JSON-RPC, an open source JavaScript library and servlet for simplifying XMLHttpRequest. I considered integrate Direct Web Remoting (DWR) as well, but its java.net site was down the day I needed it. I started out with JSON-RPC 0.7, which caused some conflicts with Commons Validator client-side validation. This was fixed in the 0.8 release. JSON-RPC takes a little more setup than I care for, but it's pretty easy nonetheless:

  1. Download the 0.8 release from http://oss.metaparadigm.com/jsonrpc-dist/json-rpc-java-0.8.tar.gz.
  2. Add the JAR to your project and the webapps/jsonrpc/jsonrpc.js to your projects' "scripts" folder. Include this file in your SiteMesh decorator or Tiles layout. If you're not using SiteMesh or Tiles, it's high time you started.
  3. JSON-RPC currently requires that you register each class you want call methods on. In our project, I registered a Spring bean (LookupHelper) that's a singleton with references to Maps in the ServletContext. Then we used JavaScript functions to call JSON-PRC and look up units for a plant, and vice versa. I'm not going to put the LookupHelper class here - you'll have to trust its methods return a single String or a comma-separated list of Strings. To register this bean with JSON-RPC, I created an HttpSessionListener and configured it in web.xml.

    /**
     * UserListener class used to add/remove session attributes when
     * a user first logs in.  Mainly for JavaScript Remote Scripting stuff.
     *
     @author Matt Raible
     */
    public class UserListener implements HttpSessionListener, HttpSessionAttributeListener 
        private final Log log = LogFactory.getLog(UserListener.class);
        public final static String BRIDGE_KEY = "JSONRPCBridge";

        /**
         * Initializes LookupHelper singleton with values needed for lookup
         *
         @param event the HttpSessionEvent to grab session information from
         */
        public void sessionCreated(HttpSessionEvent event) {
            // Find the JSONRPCBridge for this session or create one
            // if it doesn't exist. Note the bridge must be named BRIDGE_KEY
            // in the HttpSession for the JSONRPCServlet to find it.
            HttpSession session = event.getSession();
            JSONRPCBridge jsonBridge = new JSONRPCBridge();
            jsonBridge.setDebug(true);
            session.setAttribute(BRIDGE_KEY, jsonBridge);
        }

        /**
         * Destroys LookupHelper
         *
         @param event the HttpSessionEvent to grab session information from
         */
        public void sessionDestroyed(HttpSessionEvent event) {
            if (event.getSession() != null) {
                event.getSession().removeAttribute(BRIDGE_KEY);
            }
        }

        public void attributeAdded(HttpSessionBindingEvent event) {
            if (event.getName().equals(BRIDGE_KEY)) {
                HttpSession session = event.getSession();
                // register LookupHelper so we can call methods on it
                ApplicationContext ctx =
                        WebApplicationContextUtils
                        .getWebApplicationContext(session.getServletContext());

                // check for null so we don't have to initialize Spring in tests
                if (ctx != null) {
                    log.debug("Registering lookupHelper for XmlHttpRequest...");
                    JSONRPCBridge jsonBridge =
                        (JSONRPCBridgesession.getAttribute(BRIDGE_KEY);
                    jsonBridge.registerObject("lookupHelper",
                                              ctx.getBean("lookupHelper"));
                }
            }
        }

        public void attributeRemoved(HttpSessionBindingEvent event) {
            // don't care
        }

        public void attributeReplaced(HttpSessionBindingEvent event) {
            // same as attribute added
            attributeAdded(event);
        }
    }

  4. After this setup was complete, I was able to add the following JavaScript to the bottom of my JSP. These are functions that our drop-downs call to populate each other, and keep their options in synch.

    <script type="text/javascript">
    var jsonurl = "${ctx}/jsonrpc";
    var jsonrpc = null;
    var unitDropDown = document.getElementById("equipmentName");

    function filterUnits(plantDropDown) {
        var plantName = plantDropDown.options[plantDropDown.selectedIndex].value;

        if (plantName == "") {
            reloadUnits("");
            return;
        }

        try {
            jsonrpc = new JSONRpcClient(jsonurl);
        catch(e) {
            alert(e);
        }

        // Call a Java method on the server
        var units = jsonrpc.lookupHelper.getUnitsForPlant(plantName);
        setUnits(units);
    }

    function reloadUnits(value) {
        if (value == "") {
            try {
                jsonrpc = new JSONRpcClient(jsonurl);
            catch(e) {
                alert(e);
            }

            // Call a Java method on the server
            var units = jsonrpc.lookupHelper.getAllUnits();
            setUnits(units);
        }
    }

    function setUnits(units) {
        var unitArray = units.split(",");

        unitDropDown.options.length = 1;  // keep "All" option
        for (i=0; i < unitArray.length; i++) {
            unitDropDown.options[unitDropDown.options.length=
                new Option(unitArray[i], unitArray[i]);
        }
    }
    </script>

The hardest part of using JSON-RPC is setting it up. We only experienced minor issues with Commons Validator, but since the JSON-RPC 0.8 release - everything has worked great, on all browsers we need to support. The only thing I don't like about this library is that you have to register objects for each user's session. I briefly looked at DWR and it looks a little cleaner - especially b/c of its Spring integration. The next time we need XMLHttpRequest, we'll probably use DWR just to compare the two.

Posted in Java at Mar 03 2005, 08:44:40 AM MST 8 Comments

Off to Vegas

I'm leaving for Vegas in a couple hours to attend TheServerSide Symposium. It should be a good time, mostly because it's in Vegas - but also because there's going to be a lot of folks to network with and some good sessions to attend. My only goal for this whole 3-day vacation is to attend 5 sessions. I should be able to get most of those in today, so I can sleep in and goof off tomorrow. Of course, since it's Vegas, I might still be up tomorrow when the sessions start. ;-)

Thanks to SourceBeat for the free trip to Vegas!

Posted in Java at Mar 03 2005, 03:47:59 AM MST 3 Comments

Fun with jWebUnit and Canoo WebTest

For the past few days, I've been messing around with jWebUnit and Canoo WebTest at my "day job". I say messing around because I've mainly been trying to overcome perceived bugs with both projects. I'm used to using Ant and both of these libraries "just work".

The problem I had with jWebUnit is that the setOption(selectName, optionLabel) didn't work for me. This turned out to be some sort of conflict with SiteMesh, and when I commented out the SiteMesh <filter-mapping>, everything worked as expected. This is quite strange since I use SiteMesh+jWebUnit with Equinox. I tried to reproduce the problem with Equinox by adding a <select> with <option> elements, but it all worked fine there. I'd blame it on Maven, but I was running my tests from IDEA. As a workaround, I subclassed SiteMesh's PageFilter and stopped processing when the user-agent.startsWith("httpunit"). This is very similar to the JCIFS and jWebUnit workaround we're using.

Before I figured out the jWebUnit/SiteMesh issue, I decided to try my favorite UI testing tool: WebTest. Since we're using Maven, I figured the Maven Canoo Webtest Plugin would be the way to go. This took me about a day to get working (so much for the ol' 10 minute test). Most of the problems where related to the fact that setting the properties didn't seem to have any effect. I ended up writing my web-tests.xml much like I would with Ant - with taskdefs and importing project.properties for the properties to take effect. Last night, after I couldn't get webtest to click a button, I decided to try the same XML file with Ant. I dropped it into AppFuse, changed a few settings and voila! - it all worked! "WTF?" I thought to myself. Turns out the Maven Plugin is from October 2004 and is based on build 543. I ended up rebuilding the plugin to build 733 and then everything worked fine. Here's the patch.

Now that I got them both working, I'm leaning towards using jWebUnit because I can use Java to get the last inserted id (for fullying CRUDing an object). With Canoo, I'd have to use our query interface, add a feature to sort by id (or somehow get the last record added), then click on it to edit the new record. To make matters worse, the API we're talking to right now let's us add records, but we can't fetch them back - no matter what we query by. We've tried both the web services interface and the EJB one with the same results.

Ahhh, the life of an enterprise developer - trying to make 3 systems talk to each other and all of them have broken (or non-existent APIs). For one system, we're actually going through their web interface with httpclient to do CRUD on records!

Posted in Java at Mar 01 2005, 05:09:59 PM MST 5 Comments

Hibernate vs. iBATIS

There's an interesting thread taking place on the iBATIS User Mailing List. The basic jist of the responses are: Hibernate works well when you control the data model, iBATIS works well when you need to integrate with an existing database. I've said this for a couple years now, and I still believe it. Furthermore, I've found that when working with iBATIS, I tend to know what's going on a lot more. After all, it's just SQL. From all the questions on the AppFuse mailing list, it seems like a lot of Hibernate users are constantly trying to get Hibernate to "work its magic" and handle all their relationships for them.

I wonder if newbies would be better of using iBATIS? Using iBATIS, there isn't a whole lot of magic, and you get full control over the SQL - which would likely be easier to understand. Maybe I should create a "newbie" version of AppFuse - where the frameworks uses are the easiest to learn or most documented. It'd probably be Struts+Spring+iBATIS, or maybe just Spring+iBATIS so I could sell more copies of Spring Live. ;-)

Posted in Java at Feb 28 2005, 07:10:25 AM MST 38 Comments

Rails is 8 times slower than Spring+Hibernate

Might as well start off this week by getting people's blood boiling. ;-) According to a comment on Dion's blog:

Having done extensive performance (scalability means different things to different people) testing on both Rails and a comparable Spring/Hibernate/JSP2 webapp (no one seems have have done any sort of benchmarking on Rails, or they simply don't care, I don't really know, but since benchmarking is what I do... :-)) I can say that Apache2/FastCGI/Rails is about... 8x slower than the comparable Tomcat/Spring/Hibernate/JSP2 solution. And that is with caching turned on in Rails (using Rails 0.9.5...)

Quite frankly, 62 req/s on a Dual Opteron with 4GB of RAM rendering a simple view with no DB access is too... damn slow.

Personally, I still think Rails looks like a great (and easy) way to develop webapps. I just wonder if there's some truth to the "can't scale" argument. I guess the best way to find out is for me to develop an application like AppFuse with Rails, and then hammer it (and AppFuse) with JMeter to see what kind of results I get.

On a sidenote, I wonder when Rails will hit the illustrious version 1.0? They released 0.1 last week - which is a bad version number for marketing. If it's as mature as folks claim, why not make the next release 1.0? That version number alone will likely allow developers to use it more in big companies.

Posted in Java at Feb 28 2005, 06:25:27 AM MST 15 Comments

[ANN] Equinox 1.3 Released

This release is mainly a bug fix release, but it also adds support for Maven. All of the frameworks used in Equinox, as well as its build/test system is explained in Spring Live. Detailed release notes are below:

- Added missing "validator" property to "userFormController" bean in Spring MVC version.
- Added "redirect" element to success mapping to user list to prevent duplicate post problem.
- Moved "ctx" variable declaration from decorators/default.jsp to taglibs.jsp so it's available to all JSPs.
- Changed any references to UserDAO in UserWebTest.java instances to use UserManager instead (to prevent problems when transactions aren't used).
- Fixed install scripts in extras so they'd work on Windows from the command prompt. Added "fixcrlf" target for users that encounter issues.
- Added installer for Maven in "extras/maven". This can be used to replace the Ant build system.
- Dependent packages upgraded:

  • Display Tag 1.0
  • Hibernate 2.1.8
  • iBATIS 2.0.9b.550
  • JPOX 1.1.0-beta-1
  • Spring 1.1.4
  • Tapestry 3.0.2

Download. For more information about installing the various options, see the README.txt file.

Demos:

Rather than uploading the different combinations that are possible with Equinox, I figured I'd just wait for requests. So if you'd like things like Tapestry+Spring+JDO, or JSF+Spring+JDBC, let me know and I'll upload a pre-built version of 1.3.

Posted in Java at Feb 27 2005, 05:55:21 PM MST 17 Comments

Table-less forms for your webapp

The Man in Blue has some nice form layouts using fieldsets, labels and CSS. I think I'll integrate one of these styles for the forms in AppFuse. I've always stuck with tables for layout because it seemed easy, but I really like the look and flexibility that CSS provides.

Posted in Java at Feb 26 2005, 03:53:01 PM MST 6 Comments

Updating Pro JSP for JSP 2.1

Apress recently contacted me about updating Pro JSP for JSP 2.1. While the fame of having 3 books published is tempting, I think I'm going to have to pass. The Security chapter I wrote could probably use some updates, but I just wrote a Security Chapter for Spring Live - and I don't really feel like writing another. The other chapter, titled "Using Struts, XDoclet, and Other Tools", would be fun (since it's about AppFuse and Struts Resume), but I'd probably try to squeeze way too much into 50 pages.

Maybe I could just %s/Chapter 11 in Pro JSP/Chapter 12 in Spring Live and %s/Chapter 12 in Pro JSP/Chapter 2 in Spring Live and show folks how to use Struts+Spring+Hibernate. ;-)

Posted in Java at Feb 25 2005, 08:57:42 AM MST 1 Comment

JBoss ClassLoader Logic

Is there any logic to how JBoss puts all WARs, EARs and their accompanying JARs into the same ClassLoader? It seems logical that I should be able to deploy different versions of a JAR in different WARs. This works fine on Tomcat, but doesn't seem to on JBoss. Is there someway to turn this segmentation on?

Posted in Java at Feb 25 2005, 08:00:36 AM MST 11 Comments

There's nothing like...

I got up at the crack of dawn (4:00) this morning. For the first time since the 2nd week in January, I drove to work instead of riding my bike. We have a deadline and the software needs to be ready for production tomorrow. We don't want to stay late tonight, so we figured coming in early would be a good idea. So what happens when I get here? The server that we talk to for all our data is down. Figures - should be a good 3-4 more hours until it's up again. A wasted morning for productivity.

Hmmmm, that's strange. This post's published time shows up as 4:02 a.m. - but it was really 5:02 when I posted it.

Posted in General at Feb 24 2005, 04:02:32 AM MST 4 Comments