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.

DBUnit and CLEAN_INSERT

A few days ago I was trying to hook DBUnit into my test process so that my database would contain the same data before my JUnit tests are run. I had some issues getting it to work and later found that there was a bug in DBUnit's ant task. Basically, it was not allowing me to disable batch statements. Anyway, it's been fixed in CVS and now my JUnit tests (all run through a common test-module task) depend on a "db-load" task. Pretty cool and awful easy to configure. I'll be updating struts-resume/appfuse in the next few days to contain this slick trick. In the meantime, here's my db-load target. The file sample-data.xml is also built using Ant via DBUnit's "export" task.

<target name="db-load" description="Loads database from exported DBUnit file">
    <property name="operation" value="CLEAN_INSERT"/>
    <property name="file" value="metadata/sql/sample-data.xml"/>
    <dbunit driver="${hibernate.connection.driver_class}"
        supportBatchStatement="false"
        url="${hibernate.connection.url}"
        userid="${hibernate.connection.username}"
        password="${hibernate.connection.password}"
        schema="${hibernate.connection.schema}">
        <operation type="${operation}" src="${file}" format="xml"/>
    </dbunit>
</target>

Posted in Java at Mar 25 2003, 11:13:58 AM MST Add a Comment

Life as a Contractor

This weeks sucks to be a contractor. It's a 2-day week and that's all I'm getting paid for - 2 days. Damnit, wish I was full-time. Then again, if I were making the big bucks, 2 days would be plenty to pay the mortgage. Alas, I am not - and I'm tempted to work this weekend. What the hell is wrong with me - work on the weekend?! I make fun of my friends when they work on the weekend - now I'm a hypocrite. I have a to do list that makes my weekend boring as all getout:

  • work 10-12 hours at day job
  • add user administration to struts-resume
  • release appfuse
  • finish new design prototype for client
  • release displaytag (no one else seems to want to do it)
  • clean the house before Julie gets home

No wonder I miss Julie and Abbie so much when they're gone - I sit in front of the fricken computer all the time! When I get out of the house (or simply off the computer), I find I miss them much less (it's been almost 2 weeks!). I might have to scrap my to do list (save the paid part - item 3) and get off the damn computer. Booking happy hour and ski dates shortly... ;-)

Posted in General at Mar 21 2003, 04:07:13 PM MST 2 Comments

DBUnit has released version 1.5

I'm using DBUnit on all many of my personal projects (appfuse, struts-resume, security-example, day job) right now and I really dig it. It makes things so much easier. Mainly I've been using it to populate a database with default data, and haven't made my JUnit tests depend on cleaning/inserting. Today I've decided to tackle this issue (clean, insert, run test) - so I trotted on over to dbunit.org and discovered a new version (1.5) was released at the beginning of this month. I'm hoping (haven't tried yet) that I can do an export and CLEAN_INSERT and my task will be finished.

BTW, I dislike the case of the name "Dbunit" and I prefer "DBUnit," so that's what I'll be typing it as - hope you don't mind.

Posted in Java at Mar 21 2003, 11:31:51 AM MST Add a Comment

Struts Training: Week 2

I'm planning on attending today's Struts training and will be reporting here again. I got up at 6, hoping to do the labs and discovered the first step was downloading the latest Basic Portal setup. Since it's 200 MB, I've been dicking around for the last hour and a half, waiting for it to download. Yikes - I thought struts-resume was bad at 10.5 MB! I guess the difference is that it includes JRockit, Mozilla, OpenOffice, Vim, Ant, Eclipse, JMeter, Jikes, PostgreSQL and Resin.

Today's session seems to be covering databases, SQL and database performance. Vic mentions that 90% of performance is in the data model design. If you can fit your database on a laptop, then performance will probably not be an issue. I agree with this. I did the first lab during the first half-hour of the preso. Pretty simple stuff: creating HTML files and accessing them through a browser. This is probably a good lab to get everyone going and stuff installed. Also proves that Resin is running. Of course, it took me two hours to complete this lab, including the download, so I guess it's not that short!

Commons SQL is a new version of Torque (a manual persistence layer). Vic uses RowSets a lot, has one site with 40,000 concurrent Struts users with sub-second response times. He attributes this to rowsets. He says, "To create high-scalable applications, you need to know SQL and use things like RowSet, Ibatis.com, Commons SQL and Scaffolding." I tend to disagree - I think that EJBs (and possibly Hibernate) are your best bet for highly scalable application (i.e. 10,000+ hits per second). If your EJBs are slow, it's probably your code or your appserver. Try EJBs on JBoss and I'm betting you will be pleased. Then again, I've never created a highly-scalable application, and Vic has, so I'm not much of an authority. He, he - he mentions that Castor has lost a lot of mindshare; "Great for development, but not very scalable in production." So true - or at least Roller seems to prove this. From the folks he's talked to, Vic says that TopLink has a horrible reputation.

Hmmmm, interesting. Vic puts all the database connections and CRUD in his ValidatorForms. This is not saying that his bean matches his database tables. I don't know that I'd recommend this, but it certainly might simplify things. However, personally, I'm more comfortable with keeping my POJOs and ActionForms pretty dumb (just getters and setters). He has a DAO that handles CRUD and population of the bean. I wonder where you'd put the business rules in this implementation? In the DAO? If it's in the DAO, what if you have to write a new DAO implementation. For instance, if we used this approach on Roller, we'd have to re-write our business rules for Hibernate and Castor. Ugh.

For testing, he puts a test() method on his beans and uses a Servlet or a plain class with a main() method. Personally, I'd recommend using JUnit and JUnitDoclet (and Ant) to generate and run your unit tests. It's much easier than writing a servlet to test - and can easily separate your tests from your real code. See struts-resume for examples. I'll be releasing AppFuse in the next couple of weeks. This (hopefully) will provide a nice starting point for creating web applications. In reality, if no one uses it, I'll probably be better off (less support). It's been working great for me on my current project and has easily saved us a month of startup time. Right now, appfuse == struts-resume.

Vic mentions using a BaseAction that dispatches to the appropriate method in your subclasses. He says that the only difference between this technique and DispatchAction (or LookupDispatchAction) is you can specify a default method. Here's a tip: use the unspecified method. Here's how to make your edit() method the default:

public ActionForward unspecified(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
throws Exception 
{
    return edit(mapping, form, request, response);
}

Vic hints that the next iteration of Basic Portal will be written to use the iBATIS Database Layer and MySQL. Interesting, I thought iBATIS was a company, but nope: it's from the author (Clinton Begin) of JPetstore. On most days, I'd recommend Hibernate here, but I've spent the last 3 days wrestling like mad with it, so I won't. Of course, after leaving work last night, I think I might've figured out the problem. My brain is likely to blame more so than Hibernate.

Ted Husted chimed in at the end and mentioned that he is going to touch on Hibernate next week. Cool!

Posted in Java at Mar 08 2003, 08:13:11 AM MST 4 Comments

Ant Rocks (but you already knew that)

I have a few different side projects I'm working on right now. The first two, struts-resume and security-example are for the Wrox chapters and the third, AppFuse is the kindling I'm using to build these projects. Basically, I'm using AppFuse as a starting point for developing webapps. I think I've got most of what I want done for a baseline, so I'll be removing some struts-resume specific code from appfuse and calling it 1.0. For security-example, I'll be removing even more code.

The slick thing, and the reason for this post, is that I've been doing all my development on one project - appfuse. When I want to update struts-resume or security-example, I simply execute an ant command, and it updates whatever files have changed since I last updated. Ant figures out automagically which files have changed. I love it. I did a few updates and I'll be uploading the struts-resume 0.6 release tonight. Here's what I did to update the app from appfuse.

$ant new -Dapp.name=struts-resume -Ddb.name=resume
Buildfile: build.xml

clean:
     [echo] Cleaning build and distribution directories
   [delete] Deleting directory D:\source\appfuse\build
   [delete] Deleting directory D:\source\appfuse\dist

new:
     [echo] Creating new application named 'struts-resume'...
     [copy] Copying 17 files to D:\source\struts-resume
     [copy] Copied 1 empty directory to D:\source\struts-resume
     [copy] Copying 1 file to D:\source\struts-resume

BUILD SUCCESSFUL
Total time: 27 seconds

Now all I have to do is commit it to CVS (BTW, you can get struts-resume from SourceForge CVS) and execute and dist. I could FTP to SF using Ant too I suppose (I have Erik's book sitting right here), but I'll just hope someone sends this task (or page number) to me. ;-)

Posted in Java at Feb 28 2003, 12:25:30 AM MST 1 Comment

Struts Validator: Validating Two Fields Match

In the Struts Validator Guide, there is a section on how to create a pluggable validator that matches two fields. I've been using this server-side validator (as shown in the example) to do password/confirm password validation. This has worked great for me, but I've always wanted the Validator to have the client-side JavaScript method for it too. I wrote my own that just compared the two fields, but it's not the same as having one rendered for you (from validator-rules.xml). So yesterday, I did some tinkering and figured out how to add the JavaScript method to validator-rules.xml. So here's how to configure the whole thing (most of this is contained in the Validator Guide, save the JavaScript).

How To Add a TwoFields Validator

Step 1: Create a class with a validateTwoFields method. In my code, my class is ValidationUtil and has the following method:

public static boolean validateTwoFields(Object bean, ValidatorAction va,
                                        Field field, ActionErrors errors,
                                        HttpServletRequest request) {
    String value =
        ValidatorUtil.getValueAsString(bean, field.getProperty());
    String sProperty2 = field.getVarValue("secondProperty");
    String value2 = ValidatorUtil.getValueAsString(bean, sProperty2);

    if (!GenericValidator.isBlankOrNull(value)) {
        try {
            if (!value.equals(value2)) {
                errors.add(field.getKey(),
                           Resources.getActionError(request, va, field));

                return false;
            }
        } catch (Exception e) {
            errors.add(field.getKey(),
                       Resources.getActionError(request, va, field));

            return false;
        }
    }

    return true;
}

Step 2: Edit validator-rules.xml to contain the "twofields" rule.

<validator name="twofields" 
    classname="org.appfuse.webapp.util.ValidationUtil" method="validateTwoFields" 
    methodParams="java.lang.Object,
                  org.apache.commons.validator.ValidatorAction,
                  org.apache.commons.validator.Field,
                  org.apache.struts.action.ActionErrors,
                  javax.servlet.http.HttpServletRequest" 
   depends="required" msg="errors.twofields">
    <javascript><![CDATA[
        function validateTwoFields(form) {
            var bValid = true;
            var focusField = null;
            var i = 0;
            var fields = new Array();
            oTwoFields = new twofields();
            for (x in oTwoFields) {
                var field = form[oTwoFields[x][0]];
                var secondField = form[oTwoFields[x][2]("secondProperty")];
            
                if (field.type == 'text' ||
                    field.type == 'textarea' ||
                    field.type == 'select-one' ||
                    field.type == 'radio' ||
                    field.type == 'password') {
            
                    var value;
                    var secondValue;
                    // get field's value
                    if (field.type == "select-one") {
                        var si = field.selectedIndex;
                        value = field.options[si].value;
                        secondValue = secondField.options[si].value;
                    } else {
                        value = field.value;
                        secondValue = secondField.value;
                    }
                
                    if (value != secondValue) {
                    
                        if (i == 0) {
                            focusField = field;
                        }
                        fields[i++] = oTwoFields[x][1];
                        bValid = false;
                    }
                }
            }
            
            if (fields.length > 0) {
                focusField.focus();
                alert(fields.join('\n'));
            }
            
            return bValid;
        }]]></javascript>
</validator>

Step 3: Configure validation for your form in validation.xml:

<field property="password"
     depends="required,twofields">
  <msg
    name="required"
    key="errors.required"/>
  <msg
    name="twofields"
    key="errors.twofields"/>

  <arg0 key="userForm.password"/>
  <arg1
    key="userForm.confirmPassword"
  />
  <var>
    <var-name>secondProperty</var-name>
    <var-value>confirmPassword</var-value>
  </var>
</field>

Where errors.twofields=The '{0}' field has to have the same value as the '{1}' field. An alternative to Step 3 is to use XDoclet to generate your validation.xml. This requires (1) configuring XDoclet (of course) and (2) adding some @struts tags to your form on the setPassword method.

/**
 * Returns the password.
 * @return String
 *
 * @struts.validator type="required" msgkey="errors.required"
 * @struts.validator type="twofields" msgkey="errors.twofields"
 * @struts.validator-args arg1resource="userForm.password"
 * @struts.validator-args arg1resource="userForm.confirmPassword"
 * @struts.validator-var name="secondProperty" value="confirmPassword"
 */
public String setPassword() {
	return password;
}

I've sent this as a proposal to the struts-dev mailing list yesterday, but haven't heard anything yet. Enjoy!

Update: You'll need to update ValidationUtil.java and validator-rules-custom.xml for Struts 1.2. Full files: ValidationUtil.java and validation-rules-custom.xml.

Posted in Java at Feb 26 2003, 12:29:56 PM MST 10 Comments

Hibernate Upgade: 1.2.3 to 2.0 (My Story)

I'm upgrading struts-resume to Hibernate 2.0 tonight. I thought I'd blog my adventure and what I needed to change.

Step 1: Patch XDoclet to allow specifying the DTD in the generated .hbm.xml files.

Step 2: Download Hibernate 2.0 beta 2. It's at the bottom of the preceding link.

Step 3: Extract to struts-resume/lib and change lib.properties to version 2.0.

Step 4: Edit build.xml file to pick up the new DTD. I changed <hibernate/> to be <hibernate validatexml="true" version="2.0"/>.

Step 5: Using HomeSite, I did s/cirrus.hibernate/net.sf.hibernate/g. 14 matches. The project currently has 3 DAO's and a ServiceLocator to get Hibernate Sessions.

Step 6: ant clean deploy Not too bad, only one compile error.
D:\source\appfuse\src\ejb\org\appfuse\persistence\ServiceLocator.java:12: cannot resolve symbol
symbol : class Datastore
location: package hibernate
import net.sf.hibernate.Datastore;


Step 7: Open up Eclipse, refresh the project and right click on the project name, click Properties >> Java Build Path. Change path for hibernate.jar to struts-resume/lib/hibernate-2.0/hibernate.jar. Remove the previous path.

Step 8: Go searching for what the heck happened to Datastore. Hibernate CVS is first choice. Pause to post (per chance someone reads and sends solution).

Step 9: Step 4 from the Hibernate 2 Porting Guidelines. Replacing attribute names, DTDs and changed throws SQLException to JDBCException in ServiceLocator class.

Step 10: Repeat Step 5 for all Unit tests (they live in "test," rather than "src"). End up repeating for entire project, makes about 1800 replacements - hibernate-1.2.3/src was in search path. Remove lib/hibernate-1.2.3.

Step 11: Revisit Step 8 and try to use new Configuration API. Tried this...
Datastore datastore = Hibernate.createDatastore() - changed to Configuration config = new Configuration();

Not working yet... But Gavin has responded to the mailing list and Chiara is listening. Good to have the support ;-)

Step 12: Found a problem with XDoclet, modifying source. Changing "role" attribute to "name" for the following types (in order replaced by HomeSite): subcollection, collection, set, bag, list, map, array, primitive-array. Rebuilt hibernate module. Changed attribute "readonly" to "inverse" and tried again. Changes to set and bag only.

Step 13: I'm using the Configure.configure() method to initialize from hibernate.cfg.xml (I had to rename the package for my dialect from cirrus.hibernate.sql.MySQLDialect to net.sf.hibernate.dialect.MySQLDialect). I doubt it'll work though since this expects a JNDI DataSource.

Step 14: Nope, that didn't work. I found out I needed to remove the "length" attribute from any <key> elements in <bag>'s. Back to trying to use config.addClass().

Step 15: Internet connection goes down, reboot router. Change dialect package name in database.properties. This file is renamed to hibernate.properties and used for running JUnit tests. Now time to have fun with JUnit and get UserDAOTest to run.

I'm getting a connection to the database now thanks to Gavin's advice:
sf = new Configuration()
     .addClass(Foo.class)
     .addClass(Bar.class)
     .buildSessionFactory();


Step 16: Changed xdoclet tags "inverse" attribute to be "false" where previously readonly="true", now inverse="false". Now I'm getting the following error:

[junit] java.sql.BatchUpdateException: Invalid argument value: Duplicate entry '0' for key 1
[junit] at com.mysql.jdbc.jdbc2.PreparedStatement.executeBatch(Unknown Source)


Whenever I try to run the addResume test for a user. The mapping looks fine, I'll try dropping and re-creating the database. Found I needed to change the package names in build.xml. Note to upgraders: don't filter by file extension when replacing the package name.

Discovered that the SchemaExport class had moved from net.sf.hibernate.tools to net.sf.hibernate.tool.hbm2ddl.

Step 17: The UserDAOTest runs successfully. Now for the web...

Couldn't get "ant test-canoo" (Canoo WebTest) to run until I copied xerces.jar back into lib/hibernate-2.0/lib. Changed my log4j.properties to use new package name for logging.

After looking at some 2.0 documentation, I discovered a new DTD for hibernate-configuration. Unfortunately, it's not there. So I put it on this site as a workaround. Got rid of startup errors. One change in the DTDs is that all <property> declarations must be within a <session-factory> element.

Now I can't get Hibernate to connect to JNDI. Back to the doco...

(5 minutes later) Yep, right in the doco. I changed StartupServlet.java to have the following:
SessionFactory sf =
  new Configuration().configure().buildSessionFactory();


Now, when I login I'm getting:

java.lang.UnsupportedOperationException
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:125)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:329)


Since my Unit tests on the business level run, I'm guessing it's something wrong with this line in hibernate.cfg.xml:
  <property name="connection.datasource">java:comp/env/jdbc/resume</property>

Get a good nights sleep; zonked out at 3, up at 8:30 to continue...

Step 18: Find out (from Gavin) that there's probably a hibernate.properties file in my classpath that is causing the problem. I find this fine inside hibernate.jar. Doh! There's an error in packaging. ;-) I remembering seeing this sometime last week on the mailing list. I decide to upgrade to Hibernate 2.0 beta 3, which was released while I was sleeping. The file hibernate.properties is removed from hibernate2.jar in this release. I did have to update lib/lib.properties to handle the change of jar-name. Compiling, testing...

Dropped and re-created the database b/c I was getting duplicate key errors. Ran UserDAOTest - BUILD SUCCESSFUL - run it again - BUILD FAILED.

Further updates to hibernate-properties.xdt to replace paramName="role" to paramName="name", also replaced paramName="readonly" with paramName="inverse". Sent an e-mail to xdoclet-devel inquiring about best way to make hibernate-properties.xdt both 2.0 and 1.1-compatible.

This change in XDoclet makes UserDAOTest pass - so it looks like the upgrade is a success. Now I just have to figure out a way to convince the XDoclet team to add support for Hibernate 2.0. This might take awhile, it has for POJO -> StrutsForms support (still pending).

Posted in Java at Feb 23 2003, 11:03:02 PM MST 6 Comments

Tomcat 4.1.x Tip - Contexts

Did you know that with Tomcat 4.1.x you can actually take an application's context out of the server.xml file and put it in a contextName.xml file in the $CATALINA_HOME/webapps directory? This makes it much easier to install and configure your webapps. Using this feature, you can easily setup Tomcat for your webapp using an Ant task. Here's the one I'm using for AppFuse:

<target name="setup-tomcat" if="tomcat.home"
    description="copies mysql jdbc driver and application's context to tomcat">
    <echo level="info">
        Copying MySQL JDBC Driver to ${tomcat.home}/common/lib
    </echo>
    <copy todir="${tomcat.home}/common/lib">
        <fileset dir="${hibernate.dir}/lib" includes="mm*.jar"/>
    </copy>
    
    <echo level="info">
        Copying ${webapp.name}.xml to ${tomcat.home}/webapps
    </echo>
    <copy todir="${tomcat.home}/webapps">
        <fileset dir="metadata/web" includes="${webapp.name}.xml"/>
    </copy>
</target>

Posted in Java at Jan 11 2003, 08:01:51 AM MST 1 Comment

Struts Resume 0.5 Released!

I was up until 7:00 a.m. this morning finishing the struts-resume example application for my Struts chapter. I finally did it - I'm done. At least for now. I'd love to set a demo up on this server, but it requires a MySQL database, and I don't want to pay Keith the $20 to setup another database instance for me. I know, I know - Why don't I use HSQL? Because I just finished the damn application, and I need to convince myself to not touch it for at least a few days, or I'll never get anything else done (like cleaning my desk and hitting the gym).

Short-term (next 2-3 week) goals for this project are:

  • Abstract the good stuff out of struts-resume for AppFuse. They're really the same thing right now, and I'll need to trim it down a bit so there's only CRUD on a user or something like that.
  • Get it into the Struts Project's CVS at SourceForge.net. Ted Husted made me a committer, now I just have to do it. I'd rather check in appfuse than struts-resume, so the previous step is a must.
  • Change Struts to use path-mapping (/do/*) rather than extension-mapping (*.do). The tricky part is making this work with modules.
  • Code cleanup and Javadocs. Use checkstyle to make everything peachy-keen.

I don't believe it's important to fully flush out the features in the application at this point - that might overwhelm users in the end - maybe in a couple months I'll get around to doing that. You can bet I'll get super motivated right around the time I'm looking for a new gig! I'm expecting this in June, so might be awhile.

Posted in Java at Jan 05 2003, 01:05:05 PM MST Add a Comment

Using Both Ant and Maven

Erik Hatcher makes a request to get his JavaDevWithAnt project converted from using Ant to Maven:

Ok, a challenge to the Maven or Centipede experts tuning into my blog: make my JavaDevWithAnt project build with either. But the trick is that it has to be simpler than the current Ant build.xml. Believe it or not, I've not (seriously) used either of these tools. I hear the buzz about these and want to become a "believer".

I'm all for this as I've created my AppFuse project using his directory structure/build file as a template. I did go down this path to Mavenism already, but gave up before I finished. My problem is I have 15 different 3rd party JARs I use in my project - many testing frameworks and jakarta stuff. And a lot of these are nightly (or personal) builds because there's been some bug fixed, or enhancement added. What I really want is to continue using Ant b/c I think it rocks and it gives me more control over little tasks, but also to use Maven to generate a project site.

The problem with Erik's request is that I'm guessing no one will jump at the opportunity. Maybe, but in reality, no one looks at each others code unless there's a bug, or they need a sample to get started. Too bad - we could really do wonders for the Java Community if we started reviewing each others code. Erik, maybe you could post little snippets of your build file, and we could convert small parts of it. By posting a measly 10 lines, some other coders might be so inclined to help mavenize it. I know this is not how Maven works, but it sure would be nice if using Maven didn't require abandoning Ant.

Tonight I'll be staying up late trying to finish up AppFuse and Struts-Resume. Since the security-example download seems to be getting a lot of traffic (and it's a 15MB download), I should probably try to get these projects into SourceForge and save myself some bandwidth. Who knows if I'll get it done, I'm pretty tired, and it's already 10:00. But what choice do I have - Saturdays are family days, I promised my client that I pump a bunch of new features out on Sunday, and I get to work an 80 hour-week next week to get our first version out at my new job. Ugh, I need a vacation.

Posted in Java at Jan 03 2003, 09:47:25 PM MST Add a Comment