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 "ant". 338 entries found.

You can also try this same search on Google.

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

Carpal Tunnel

When I finished hacking away on Roller this past Saturday, my fingers hurt from typing so much. Who knows why, I didn't add that much code. Must've been all the keystrokes to run Ant, start Tomcat, and test stuff. Yeah, we need more tests - but those won't help tweak CSS. Yesterday, all I did was review Hibernate in Action, so no coding, but a fair amount of typing. By the time I went on a bike ride yesterday afternoon - my left hand's left-most fingers were curled up naturally and my forearm was aching. Carpal Tunnel has set in quite nicely in my left forearm. I can still type, as evidenced by this post - but it definitely hurts and it seems like I could do some serious damage if I keep it up.

Herein lies the problem. I took this week off from my regular gig to concentrate on the Spring book. So I need to be typing like a madman all week - but my body is not cooperating. Rather, it's trying to tell me something - "you're not cut out for this this much coding/typing." So what should I do? I've had these same symptoms before - and when I did, I got a massage and took a couple of days off. That's a bit difficult this week with my livelihood depending on a pain-free left arm/wrist/fingers. I've booked a 10:00 massage - let's hope that gets me through the week. I definitely need a longer-term solution though. It'd be nice to write this book w/o typing, just talking.

Related: Carpal Tunnel in March 2006.

Posted in General at Mar 22 2004, 08:22:23 AM MST 13 Comments

JAG - similar to AppFuse, but offers more choices

This afternoon, I stumbled upon the open source Java Application Generator on SourceForge:

JAG is an application that creates complete, working J2EE applications. It is intended to alleviate much of the repetitive work involved in creating such applications, while providing a means of quality assurance that the applications created will be of consistent quality.

Major differences include: JAG has a Swing GUI to create your app and it uses EJB 2.0 for its persistence layer. AppFuse has an Ant task (ant new) and uses Hibernate (or iBATIS) for the persistence layer. Both use Struts 1.1 with Tiles and Validator support. The question is - will they eventually offer Spring, WebWork and Tapestry options for the MVC layer? I doubt it...

BTW, my experience with java.net has been quite nice so far. I like the fact that I can use a pserver for developer CVS access (vs. SSH only at SF). I also like that I can approve e-mails just by replying to an e-mail (vs. using a web interface on SF). The best part, however, has to be that CVS commits and e-mail messages are immediately browse-able in the archives. This is rather convenient when you're a blogger that likes to link to source code and messages in (sudo) real-time.

Posted in Java at Mar 04 2004, 01:05:51 PM MST 1 Comment

[ANN] Anthill 1.7.0 Released!

I've been using Anthill for about a year now, and I think it's a kick-ass product. I don't really have any issues with the current version, but it's nice that there's a new release. If you're interested, you can view the release notes.

Posted in Java at Mar 02 2004, 09:52:51 AM MST 2 Comments

Speaking at MySQL User Conference

MySQL User Conference Speaker I've been accepted to present a 30 minute session on AppFuse at the MySQL User Conference in Orlando! I would have never thought to even apply, but Mark Matthews sent me an e-mail and convinced me to give it a shot. Now I'm pumped that I did. Here is the abstract for Easy Java Development with MySQL:

Using my open source AppFuse application, I will show how easy it is to setup a MySQL database using Ant, create the Tables using Hibernate/Ant and populate it using DBUnit.

Other events I'm speaking at in the next couple of months include a one-day conference in NYC on Developing Webapps using Open Source Tools and a Basic Concepts presentation on AppFuse at Denver's JUG in June.

Now the only question is - should I use PowerPoint/Keynote or enhance my simply preso app to write these presentations?

Posted in Java at Feb 24 2004, 11:45:40 AM MST 11 Comments

Good Ant Tip

Nick has an Ant tip that I can put to good use.

This A little-known Ant feature is the hyphenated target name. If you have a target name that starts with a "-", such as "-test-setup", you will not be able to call that target from the command line. Developers creating utility targets in their build.xml files can use this to avoid confusing other developers with irrelevant support targets.

There are a fair amount of internal targets in AppFuse that don't need to be visible and can't be really be called from the command line. Last time I checked, IDEA and Eclipse both allowed hiding of internal targets - so I rarely see these, but it might be a good idea to make them more explicit. I'll put it on my what-I-can-do-when-I-get-bored list.

Posted in Java at Feb 17 2004, 09:23:10 AM MST 1 Comment

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

[DJUG] Hibernate and Jabber Tonight

Tonight's Denver JUG should be good. The basic concepts meeting is on Hibernate and the main show is on Jabber: XMPP and Jabber Streaming Objects library. Nice! It's snowing like the dickens right now so getting there might be tough. Good thing I live close to downtown! The meeting is actually located in the same building where Julie works.

Update: Tonight's meeting was pretty good, but kinda boring. I didn't learn anything new in the Hibernate session - but I did see Chris do a lot of stuff via command line (vs. Ant). I do everything in Ant, so I was again able to see the beauty of Ant and Hibernate's <schemaexport> task.

The Jabber talk was interesting but dry - probably because Peter and Matt didn't have a presentation or agenda for the meeting. Rather, they just stood up and talked about Jabber and its XMPP Protocol. From what they said, Jabber's streaming XML protocol is being used for a lot of things besides Instant Messaging. It's biggest feature seems to be presence - the ability to know when someone (or something) is online. For using Jabber in your Java applications, you might want to look at Matt's JSO Project. While I'm at it, I might as well mention my article describing how to setup a Jabber Server.

Posted in Java at Feb 11 2004, 03:58:16 PM MST Add a Comment

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

apache.org won't let e-mail through from comcast.net

I don't use my comcast.net account, but I do use their SMTP server to send e-mail. I've sent a few messages to the tomcat and ant mailing lists in the past couple of days, and they've never shown up. Today, I realized why. Howard says:

...it appears that there's a disruption which is preventing mail originating at comcast.net's domain from reaching apache.org's. This may have been going on for a week (its probably related to the massive amount of e-mail from the MyDoom virus).

I guess I'll have to resend those suckers from my Yahoo account. Even with this disruption, I still think Comcast's broadband is the best in the business. Who can complain about 2 MB/sec (downloads average 250K/sec)? OK, maybe it's not that today, but usually it's pretty close.

Posted in The Web at Feb 04 2004, 01:41:14 PM MST Add a Comment