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.

Resin slower than Tomcat, fails the AppFuse Test

As part of AppFuse 1.6, I was hoping to supply the option to use Resin instead of Tomcat. In reality, hardly anyone has asked for this on the mailing list - but since so many folks say that "Resin is better" - I figured I'd give it a whirl. I hate to be the guy that spoils all the Resin users mantra, but it seems like Tomcat is the better server. Why? Speed, compliance and shit works. Here are some things I found:

  • Server startup time when AppFuse is only app installed (deleted work directories before starting):
    • Resin: 25 seconds
    • Tomcat: 14 seconds
    I also found that Resin loads my StartupListener twice b/c it's defined in web.xml and XDoclet puts it in the generated TLD. I think the best solution is to add a flag to XDoclet to allow you to exclude listeners from the TLD when it's generated. I commented out the entry in web.xml for this test.
  • Running "ant test-canoo" which runs through all the JSPs using Canoo's WebTest (server already started):
    • Resin: 1st run (no compiled JSPs) - 53 seconds, 2nd run (compiled JSPs) - 24 seconds.
    • Tomcat: 1st run (no compiled JSPs) - 49 seconds, 2nd run (compiled JSPs) - 14 seconds.

I did have to hack a number of things to even run the tests (which verifies titles, success messages, etc.) on Resin. First of all, SiteMesh seems to puke with if you try to use <dispatcher>FORWARD</dispatcher> on the filter-mapping. I had to comment this out, resulting in a lots of HTML Tidy errors during the tests ( Error: <content> is not recognized!). I also had to turn off Resin's fast-jstl to bypass this bug. Finally, I had to revert the displaytag to using the non-EL version (which required changing titleKey -> title and name="${listName}" -> name="listName"). It seems that Resin enables EL even if you're using a 2.3 DTD. With Tomcat, and I believe the spec says this, EL is only enabled if you use a 2.4 XSD.

So there you have it folks, not only is Resin 3.0.9 slower than Tomcat 5.0.28 (JDK 1.4.2, Windows XP), but it's not standards compliant. Of course, the speed could be due to my using the open source version (with performance enhancements turned off) - but I'd think the other (albeit minor) stuff should be easy to fix. Everytime I try to use Resin, I end up finding bugs and going back to Tomcat. I guess this is another one of those days. I don't think I'll include a Resin installer as part of 1.6, but I might distribute one later if I can get these issues solved. I wonder if I should give Orion a run for its money?

P.S. Since I know people are going to ask: Tomcat 5.5.3 with JDK 5.0 took 9 seconds to startup. Running "test-canoo"? First run: 37 seconds, second: 14 seconds. Looks like the new compiler is quite a bit faster.

Posted in Java at Oct 07 2004, 07:13:09 PM MDT 24 Comments

Integrating WebWork into AppFuse

Last week was a busy one as I was trying to finish up AppFuse 1.6 before starting my new gig (more on that later). Most of this involved 1) integrating WebWork and 2) writing the Ant-based installer for replacing Struts with WebWork. I've worked with WebWork before, so this post is mostly an extension of that - as well as documentation on what I did so others can understand AppFuse+WebWork better. Below is a list of things I found.

  • WebWork's concept of "results" are very similar to Struts "action-forwards". However, they also allow you to chain to other actions and use expressions.
  • Implementing the ModelDriven interface in your Actions is a good idea, but it's not that great. I found that by simply using get/setUser(), I got the same functionality - except that I had to add "user." to all my form elements in my JSP. The advantage to doing things this way (over ModelDriven) is you can have an Action that services many objects. The main reason I'm not using ModelDriven is because the following tag doesn't render the label (it's just blank). Strangely enough, it renders just fine after validation fails.
    <ww:textfield label="getText('user.firstName')" name="'user.firstName'"
        value="user.firstName" required="true"/>
  • WebWork is similar to Tapestry in that they encourage you to specify i18n messages (properties files) on a per-action basis (Tapestry is per page). Some might think this is a good idea, but after using Struts and Spring, I'm used to using one ResourceBundle for everything. To migrate AppFuse from using 1 bundle to many bundles just for WebWork would've been a pain. Luckily, in WebWork 2.1, they added the ability to specify a custom bundle using "webwork.custom.i18n.resources=ApplicationResources" in webwork.properties. I believe my issue with ModelDriven and labels is caused by this new feature.
  • The Spring-integration provided by SpringObjectFactory is quite nice. Unfortunately, client-side visitor validation doesn't work with it.
  • Unit-testing WebWork actions is easy, though it's kinda wierd to not send request parameters and such to set values (instead, you just set values directly on the Action).
  • I experimented with putting stuff on the stack and pulling it off in JSPs, but never got it to work quite right. After failing the 10 minute test, I decided to just put stuff in the request and get it working. Looking through the code now, there's only 3 places where I'm stuffing attributes into the request: 2 in FileUploadAction and 1 in ExceptionHandlerInterceptor.
  • With most frameworks I've used in the past, I rarely jumped into the source to try and see how things worked. Because of this, I rarely extended framework classes for my own use. However, with WebWork/XWork, I found it quite easy to dig in and extend the framework. Especially with Interceptors - which I dig.
  • Following up on Interceptors, I was able to easily create my own ValidationInterceptor that cancels validation on GET requests, and when cancel or delete is clicked.
  • Other interceptors that came in handy are a UserRoleAuthorizationInterceptor (which I borrowed from Spring) and an ExceptionHandlerInterceptor (which is modeled after Spring's SimpleMappingExceptionResolver). The 1st interceptor made it easy to mimic Struts' ability to declare a "roles" attribute on an action-mapping. The 2nd one allows you to map exceptions to results. This is something I was looking for when I first started using WebWork.
  • The "required" attribute in WebWork's JSP tags have nothing to do with validation, except that they add an asterisk to the field label. I'd rather this be integrated with validation - where an asterisk shows up when a field is "required" in its Action/POJO-validation.xml file.
  • I had a few other issues with validation: client-side validation shows one error at a time, client-side validation doesn't allow cancelling and field errors are displayed in a random order. If I were to start a project tomorrow that wanted WebWork with client-side validation, I'd probably try to integrate Commons Validator.
  • Testing Actions is easy, as it should be. Using Spring's Servlet API mocks made it easy to test Actions that used ServletActionContext to set cookies and other such request-related stuff.
  • I dig the rich set of form tags and it's great that these can be easily customized. I customized a few for AppFuse to make the syntax a bit more XHTML-compliant.
  • I'm a stickler for formatting and good-looking XHTML in JSPs. I try to keep lines less than 80 characters. Here's a comparison of the LOC required by the different frameworks for userForm.jsp:
    • Struts: 298
    • Spring: 319
    • WebWork: 186

All in all, I enjoyed working with WebWork and if given a choice of an AppFuse combination to use on my next project - it would probably be WebWork+Hibernate. If the client wanted client-side validation, I'd either integrate Commons Validator (which shouldn't be too hard) or use Spring+Hibernate. After using Spring and WebWork, which allow you to use your model objects directly in the view, it would be tough to go back to Struts. However, I still do know Struts better than the other two - so if I had a really tight deadline, that might be the smart way to go.

Posted in Java at Oct 04 2004, 08:17:37 AM MDT 2 Comments

Playing with JDK 5.0 and Tomcat 5.5.2

I did some experimenting this evening with JDK 5.0 and Tomcat 5.5.2. The good news is that AppFuse compiles fine with JDK 5.0 and runs on Tomcat 5.5.2 nicely too. Here's a couple of things I found:

JDK 5.0
I received a number of interesting errors from the new JDK. Here's one of them:

   [javac] Note: Some input files use unchecked or unsafe operations.
   [javac] Note: Recompile with -Xlint:unchecked for details.

I received a few other messages that were deprecation warnings. The wierd thing is that it was telling me what's deprecated in HttpServletResponse, rather than what's deprecated in my code. Huh - what's the point?

Unfortunately, I found that Cactus won't run on JDK 5.0. Too bad, everything else seems to work fine.

Tomcat 5.5.2
I like the speediness of the new Tomcat, but I was disappointed to find out that they changed the DTD for the context.xml file. The old one works fine on Tomcat 4.1.x and 5.0.x, but you have to make some modifications for it to work on 5.5.x. To be fair, the new syntax is shorter and more concise. I've updated AppFuse's build.xml to detect Tomcat 5.5 and swap context files as appropriate.

Because of the Cactus bug, I think I'll be sticking with JDK 1.4.2 and Tomcat 5.0.28 for now - but it's cool to know that everything else will work once Cactus is fixed.

Posted in Java at Sep 30 2004, 11:32:03 PM MDT 6 Comments

There's a new sorting and paging taglib in town

From the Apache News Blog, I found there's a new sorting and paging taglib in town. We already have the Display Tag and the Value List Handler, but now we have the Data Grid. It looks pretty good too - although it doesn't seem to support/enforce XHTML. For your viewing pleasure, I've setup a demo. To be fair, you can also checkout the Value List Handler Demo and the Display Tag Demo.

Posted in Java at Sep 16 2004, 09:15:54 PM MDT 19 Comments

[DJUG] JMX and JDO 2.0

Last night I attended the local Denver JUG meeting. Chris Huston gave a presentation on JMX and Dion gave a presentation on JDO 2.0. Below are my notes from the event.
-----------------------------

Java Management Extensions one of the first JSRs and now included in to JDK 5. Monitors health of the system. Alter sys-admin of error conditions. Provides capability of to view and modify runtime parameters.

MBeans are deployed in an MBeanServer and their capabilities are exposed through Connectors. Then tools talk to these connectors to get their information.

JMX is covered by two separate specifications: JSR-3 (MBeans) and JSR-160 (Connectors). BTW, Chris has some good slide-making capabilities - I'll have to get some tips from him for my next preso. For example, he shows an entire class and its methods, then he fades it and zooms in on certain methods and highlights them to explain what they do.

Four types of MBeans: Standard MBeans, Dynamic MBeans, Model MBeans and Open MBeans. More info on these Mbeans can be found at http://docs.sun.com.

Standard MBean: All you need to do create an interface for your class your class name with "MBean" appended to it.

In order to deploy, you need to create and configure an MBeanServer. You can create an MBeanServer using javax.management.MBeanServerFactory.createMBeanServer(). MBeanServers keep track of MBeans using a javax.management.ObjectName. After creating and configuring an MBeanServer, you simply need to register your MBean using an Agent. All pretty simple so far, right? Now you have to use a Connector to expose your MBean to the outside world.

"Connectors are the fly in the ointment." MX4J is an open source project that has good Connectors: i.e. RMIAdaptor and HTTPAdaptor. There's also SNMP Adapters from a number of commercial vendors. In order to solve the current lack of good Connectors we have JSR-160: Distributed Services Specification. This JSR defines one connector: JMXConnector (part of JDK 5).

Chris is now showing us a counter widget deployed as a Swing app and managed using MX4J's web interfaces. Very cool stuff - the ability manipulate runtime parameters. As Chris stated - the real power of JMX will come from the tools. I wonder if there's MBeans available for monitoring webapps - seems like there'd be quite a market for management beans you could just drop in and deploy.

Notifications are another feature of MBeans and can be sent by an MBean. Two important interfaces: NotificationEmitter and NotificationListener.

Chris gave a good introduction to JMX, but I don't see myself using it anytime soon. It seems to be something that framework and container developers might use, but not many application developers. Maybe I'm wrong - are you deploying MBeans as part of your web applications? Chris mentioned that Hibernate and Spring have MBeans as part of their distribution - anyone using these? If nothing else, it's great to know that JMX is available if I ever do need to monitor and control applications.

-----------------------------
Now Dion's up after a 1/2 hour break with announcements. Dion is talking about JDO 2.0. I think JDO would be a lot more popular if it wasn't for Hibernate. Hibernate seems to have done JDO better and faster.

What is JDO?

  • Allows for object persistence
  • "I have objects, some need to be persisted"
  • "Keep state and behavior together. That is the OO way."

JDO Main Objectives:

  • To enable pluggable implemenentations of data stores into application servers
  • To provide applicaiton programmers a Java-centric view of persistent information, including enterprise data and locally stored data.

Other Objectives:

  • Transparent Persistence
  • Persistence-by-Reachability
  • OO framework on top of potentially non-OO stores.
    • RDBMS (98% of the time)
    • Files
    • TP Monitors
    • Legacy
    • Properietary
  • Integrate with existing technologies
  • Java compatible - no need to learn new language
  • Usable in managed and non-managed environments
  • Define easy semantics for caching objects
  • Ability to run in all Java platforms (J2SE, J2EE, J2ME)

When JDO first started, a bad thing happened - the object database guys were heavily involved. JDO 1.0 had 80% of its Expert Group from object database vendors. JDO 2.0 got object guys off the committee and real-world (relational) folks onto it.

JDO 1.0: Most of it is not very new - just a standard way of implementing persistence. Other proprietary tools already accomplish most of what JDO is.

JDO 2.0 Strategic Goals:

  • Easy to Use
    • natural programming model
    • configuration and deployment
  • In a Wide Variety of Environments
    • J2SE (rich clients)
    • application, web servers

JDO 2 Status: First Early Draft Review is out there. Soon there's going to be a Community Review - then things will start rolling after that.

JDO 2.0 Goals:

  • Maintain JDO 1.0 Compatibility (big thing with Sun)
  • Standardize Mapping to Relational DB (was vendor extension in 1.0)
  • Multi-tier Development Improvements
  • Usability Improvement
  • Better Object Modelling
  • Richer Queries - JDOQL, SQL and Named Queries
  • More Vendor Support - try to get Hibernate and Oracle on the bandwagon for political reasons

Dion's take on politics between EJB 3 and JDO 2

  • Let's get a standard around transpanent persistence first
  • Let's have a standard that can be shared between various groups: J2EE, J2SE, J2ME
  • Why have more than one O/R mapping specification?
  • Specifications such as EJB could be an umbrella spec for the cross cutting concerns

Why are people even arguing about it? Money. Because companies have invested a lot of time and money into X technology and therefore they bash the other. This problem might be solved by an O/R Mapping JSR that both EJB and JDO have to adhere to.

JDBC vs. JDO

JDBC JDO
SQL-oriented Object-oriented
Explicit intrusive code Fully transparent
Manual mapping Automatic mapping (automatic == create XML file)
RDBMS-centric Universal

JDO will use all J2EE services inside a container.

Deployment time scalability - database becomes bottleneck as number of users increases. JDO middle tier can relieve this load on the databse. JDO's configuration can be altered at deploy time to handle better scalability through caching.

JDO 2.0 Multi-tier Development - big thing is disconnected objects through attach/detach. Very simple API for detaching and re-attaching objects. Internally there's a version that's used to determine if the object is the same one.

JDO and EJB
As opposed to Entity bean, JDO instances...

  • May have subclasses
  • May exist outside a container
  • Has 1 optional interface to implement
  • Accessible as transient objects

And as of JDO 2 (new and improved object modeling!)

  • Persistent Abstract Class Support
    • map abstract classes to tables
    • map properties, fields to columns
    • create new implementation instances
  • Persistence Interface Support
    • map interfaces to tables
    • map properties to columns
    • more, but I missed them

Some argue that JDO is what Entity Beans should have been!

  • JDO is "purer" way to use OO
  • Since Entities should be used via local interfaces, why not just do Session Facade -> JDO objects
  • CMP in Sun AppServer uses JDO

Some argue that JDO complements Entity Beans because Entity beans can use JDO.

EJB3 is totally moving directorys with regards to Entity Beans, and they are much more like JDO.

EJB3 EntityManager == JDO PersistenceManager == Hibernate Session

JDO and Connector Architecture - JDO is NOT a framework, but plays well with others!

The JDO architecture uses the J2EE Connector architecture for application servers. The JDO PersistenceManager is a caching manager as defined by the J2EE Connector architecture.

A PersistenceManager may define the following Connector components:

  • ResourceAdapter
  • ConnectionManager
  • ManagedConnectionFactory
  • ManagedConnection
  • LocalTransaction

Persistence Contract (behind the scenes)
- To achieve transparence, JDO:

  • Defines a PersistenceCapable interface
  • Used too mandate binary compatibility among all vendors (optional in JDO 2)
  • Uses tools to make a class persistence capable

- Declares any fields available for persistence storeage

- Defines methods that allow JDO instance management

  • jdoIsDirty()
  • jdoIsDeleted()
  • jdoMakeDirty()

JDO has a number of callbacks that you can implement: jdoPostLoad(), jdoPreStore(), jdoPreClear(), jdoPreDelete().

In JDO 1: one interface: InstanceCallbacks
In JDO 2: InstanceCallbacks purely extend interfaces: LoadCallback, StoreCallback, etc.

Ways to make classes persistence capable: byte code enhancement, annotations (maybe for JDO 2.1).

JDO Interfaces: PersistenceManagerFactory, PersistenceManager, Transaction (new set/getRollbackOnly() in JDO 2) and JDOHelper (class with static methods, for use by persistence-aware classes), Query, Extent. You'll probably never use an Extent; like "select * from table". Represents all instances of a class or subclasses.

A persistence cabable class is just a POJO - you could use the same class for JDO and/or Hibernate. A default contructor is required in JDO 1, but not in 2.

JDO 2.0 has "use cases" for lazy-loading. This enables you to configure fetching based on certain situations. Sounds pretty cool.

Extent is usually optimized for better performance. If you're selecting all records from a table, you're probably better of using Extent vs. Query in order to avoid OutOfMemory errors.

New in JDO 2: ability to specify query filters in other languages - i.e. SQL or HQL or user-defined. These languages are up to the JDO vendor to implement.
JDO can use stored procedures if you map it in your metadata.

JDO 2.0's Query API looks very rich. It allows you to limit your results to certain properties/columns, as well as set what type of to return.

JDO 2.0 supports obtaining a java.sql.Connection from PersistenceManager. However, this may reduce portability since not all SQL is portable b/w databases.

Overall, I thought this was a great talk by Dion. If you're looking to start working with JDO 2.0, I'd recommend JPOX (also see JPOX with Spring or Tapestry). Unfortunately, their implementation still requires you to "enhance" your classes at build-time, but hopefully they'll have a transparent mechanism for manipulation (i.e. cglib) soon.

Posted in Java at Sep 09 2004, 10:06:42 AM MDT 6 Comments

FindBugs

I ran FindBugs on AppFuse last night and found/fixed a number of issues as a result. I'm now down to only a handful left - most of them being "Class is Serializable, but doesn't define serialVersionUID". I tried to generate one using serialver, but I couldn't it to work after numerous attempts. My issues seemed to be classpath related: it wanted the servlet api in my classpath, and once I'd add that, it could find my class. I'll have to try the SerialVer Ant Tasks. Fixing this issue would be nice, but I doubt it's really affecting appfuse-based applications. The other bug is "Inconsistent synchronization" in UserCounterListener.contextInitialized() method. Any tips on solving this one are appreciated.

Posted in Java at Aug 19 2004, 09:46:50 AM MDT 15 Comments

Should I ditch Tiles in AppFuse?

I've haven't been developing applications with AppFuse since May. Instead, I've been using Equinox. One of the main things in Equinox I've grown to love is SiteMesh. It's worked in all the webapps I've written, which utilize frameworks like Struts, Spring MVC, WebWork, Tapestry and JSF. Tiles will only work in 3 of those.

I think it's time to make an executive decision on AppFuse and ditch Tiles in place of SiteMesh. It's faster and easier to develop with, and it doesn't get in your way. In fact, I didn't have to change a single line of SiteMesh-related code to support any of the aforementioned frameworks. Furthermore, using SiteMesh would also greatly reduce the duplicate between frameworks. I've thought about keeping Tiles around, but it's a pain in the ass to maintain parallel sets of documentation.

Whaddya think - any reason you can think of to keep Tiles? I can't. In fact, I think I'd cringe if I had to start my next AppFuse-based project w/o SiteMesh.

Posted in Java at Aug 18 2004, 10:11:56 AM MDT 33 Comments

My JSF Experience

Of all the MVC Frameworks I've developed with in the last few weeks (Struts, Spring MVC, WebWork and Tapestry) - JSF was by far the worst. And it's not the implementations that are the problem, it's the spec itself (as far as I can tell). Plain and simple, it does not simplify web development.

I spent 3 days developing a simple JSF app - most of it which I had done in the first day. The last 2 days have been spent migrating to MyFaces and trying to find clean ways to do things. My perspective on JSF after this experience? Run away. Run far, far away. All of the above mentioned frameworks are MUCH superior to this technology. Let's get on with the things I learned.

  • MyFaces handles duplicate posts nicely. If you hit "reload" on your browser after saving a record, you get presented with an empty form rather than a duplicate record. I believe I got a duplicate record with Sun's RI.
  • The ability to specify an "action" attribute on a button (or a link) and them map that action to a page (in faces-config.xml) is pretty cool.
  • Every button or link clicked results in a form post. That's just wrong - why can't I have true links like the web is supposed to? So much for bookmarks.
  • Saving state on the client results in enormously long URLs and/or hidden fields.
  • JSF support is fairly non-existent. Unlike the other MVC frameworks, the MyFaces mailing list has hardly any traffic and the Sun forums aren't much better.
  • The MyFaces website seems to be down whenever I want to look something up on it, like right now.
  • I did find some CRUD examples, like this this one, but was disappointed to find that i18n is not considered for setting success messages. I ended up using the solution described in this post. 6 lines of code to set a success message - you've got to be kidding me! Most frameworks have a simple 1-2 liner.
  • Waiting for JSPs to compile the first time has surprisingly become painful after using Tapestry, Velocity and FreeMarker for the last 2 weeks.
  • Integration with Spring is fairly easy (code is in CVS), but MyFaces spits out an error when it shouldn't be.
  • Validation messages are ugly. For instance, when a required field isn't filled in, I get: "lastName": Value is required. I was able to override the default messages, but I was never able to use the label of the field (vs. the field's id).
  • The <h:messages> tag is practically worthless. Sure it's great for displaying messages (error and success), but that's about it. It has a "layout" attribute that doesn't even work in Sun's RI, and in MyFaces it just wraps a <span> with a <ul><li> or a <table>. Both of these layouts are useless b/c you can't set a css class on them. I ended up using "table" and having to set a generic CSS rule (width: 100%) in order to get the message/error bar to show across the top of my page. This tag also doesn't allow you to escape HTML.
  • The <h:dataTable> component is nothing like the displaytag. MyFaces claims to have a pageable/sortable component, but it requires custom logic/methods in your managed-bean. Yuck. I ended up using <h:dataTable>, which has neither sorting or paging. This is only because I couldn't get an <h:commandLink> working inside a displaytag column.
  • JSF-created apps are pretty much untestable. Managed-beans are testable, but the UI seems really difficult with jWebUnit and Canoo's WebTest. IMO, it should be possible to specify a URL to edit a record (i.e. editUser.html?id=2). With JSF and my master/detail app, the link to edit actually sets about 5 hidden form fields with JavaScript and then submits the form. I could probably figure the URL out, but it'd be ugly. Also, the MyFaces <h:dataTable> will not render an "id" attribute if you specify one. This is needed to verify tables and their data with jWebUnit.
  • When using "ant reload" to reload my application (using Tomcat's Ant Tasks), I kept encountering a ThreadDeath error. This seems to be specific to MyFaces as I never saw it with other frameworks or Sun's RI.

Like Tapestry, I felt like I was banging my head against the wall a fair amount. However, with Tapestry (and all the other frameworks), I was able to get exactly the behavior I wanted w/o too much work. I could produce clean and user-friendly error messages - (Tapestry already had clean required messages built in). I was able to write a jUnitWebTest to test all CRUD activities. With JSF, I was able to test one thing - adding a new record. I couldn't edit it b/c the JavaScript support (which I tend to not use) puked every time it encountered a JSF-generated JavaScript function.

My opinion after all of this? If you know Struts, Spring MVC and WebWork are fairly easy to learn. WebWork is simpler and elegant, but Spring MVC supports more view options out-of-the-box. Tapestry is cool, but you'll have to invest a lot of time into learning it and you'll probably get caught up in its cult and forever be claiming "Tapestry Rocks!" which can get annoying to your fellow developers. ;-) Finally, I can confirm that SiteMesh rocks - it worked for all the frameworks I used and I never had to change a single line of code.

Whatever you do, don't use JSF. Not yet anyway.

Posted in Java at Aug 06 2004, 04:53:22 PM MDT 76 Comments

AppFuse Changes: Unit Testing with Easy Mock and Spring's Struts Plugin

I have a couple of proposal for the next AppFuse release. Let me know what you think:

  • Change service and action/controller tests to use Easy Mock to mock dependencies. This will likely require a bit more code in the test, but it'll allow true unit testing of components. Current tests are more like integrations tests, which tend to be slower. The Canoo WebTests will continue to act as the integration tests that verify functionality top-to-bottom.
  • Change Struts to use Spring's Struts Plugin. XDoclet's Spring stuff should make this pretty easy so you don't have to modify any XML - just like the current situation. The advantage of this is you can use dependency injection on your actions, rather than getBean(...).

I hope to get these in, along with a WebWork option, in the 1.6 release. I'd love to get 1.6 done and released in August, but I'm probably dreaming since I'd like to finish Spring Live in the same time frame. Of course, I'm also planning on fixing any bugs that are currently entered.

Posted in Java at Aug 02 2004, 11:34:21 AM MDT 12 Comments

10 minutes into Tapestry

As I'm trying to figure out the JARs required by Tapestry, I find that commons-upload.jar is required by default.

2004-07-21 17:12:47 StandardWrapperValve[tapestry]: Servlet.service() for servlet tapestry threw exception
java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileUploadException
	at org.apache.tapestry.request.RequestContext.(RequestContext.java:153)

Huh?! That's wierd - I'm not doing any file uploading... (I know, this type of message belongs on the mailing list - I just thought it was funny ;-))

Posted in Java at Jul 21 2004, 05:15:47 PM MDT 2 Comments