Matt RaibleMatt Raible is a Web Architecture Consultant specializing in open source frameworks.

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.

AppFuse Light » AppFuse, Maven Archetypes and Shared Web Assets

Last night, I stayed up into the wee hours of the morning working on something I've been wanting to do for a long time. It wasn't until I was trouncing around the woods in Montana that I realized how easy it would be. The something I've wanted to do was to modify AppFuse Light to use AppFuse's core modules (service and dao). It only took me a few hours to make it happen and it inspired additional ideas.

I believe the major mistake we made in AppFuse 2.x was making it easy for user's to upgrade their applications. We currently use the maven-war-plugin and our own maven-warpath-plugin to make it possible to include AppFuse classes and assets in your project. You can easily start a new project w/o having a whole bunch of files in your project. The problem is, you can't easily use "mvn jetty:run" to work on your project. Of course, you can use "mvn appfuse:full-source" to solve this, but I'm starting to think more and more that "full-source" should be the default. This is what we did in 1.x and it seems to be the more natural pattern for folks using AppFuse.

That hard part about moving to "full-source" by default is coming up with a way to share common assets and classes among wars and war projects. Sure, I can copy all the shared images, css and js into each project - but that could become a maintenance nightmare. Subversion 1.5 with relative svn:externals might solve this, but it still seems kinda hacky. I don't want to use the maven-war-plugin because the overlay is kinda hokey and I think it's easier for users to understand when everything is in their project. AppFuse's current directory structure in SVN looks as follows. I've added indicators of what is in each directory.

AppFuse Web SVN

Rather than using AppFuse's current (manual) archetype-creation process, I'd like to move to a more automated creation process using the maven-archetype-plugin's create-from-project feature. I'd like to figure out a way where I can have the source code and assets from web/common included in each of the other web/* projects (both when using "jetty:run" and "archetype:create-from-project"). One idea I thought of is to make Jetty/Maven aware of multiple src/war directories for "jetty:run" and "package" and then somehow hook into the archetype plugin at creation time to pull in the shared resources. I don't know if something like this is possible. If you know of a good solution to this shared web assets issue, I'd love to hear about it.

Back to AppFuse Light. If I can figure out how to solve shared resources in web modules, I can use this in AppFuse Light to move to a modular SVN structure vs. its current "use Ant to create different combinations" setup. If a modular structure (like appfuse/web/*) is possible for AppFuse Light, I believe it makes sense to move its source into AppFuse's SVN repository. Below is how the directory structure might look after this move.

AppFuse Light » AppFuse

With this addition and "archetype:create-from-project", we should be able to create all the basic and light archetypes automatically. We'll probably still need a manual archetype-creation process for modular archetypes, but I'm OK with that.

The last thing I'm struggling with is figuring out the best way to create archetypes for something like AppFuse. In the past, we've used dependencies to allow users to inherit dependencies and their versions. This works, but it results in a lot of duplicate XML (in projects and archetypes) for developers. Last night, I tried using a parent project instead of dependencies and it seems to work much better. Not only do you inherit dependencies, but you also inherit plugins, profiles and properties. If you inherit, you can override, which is slick.

If you're an AppFuse user, how would you feel about having an AppFuse module as your project's parent? Would you prefer that, dependencies on AppFuse or full-source with no dependencies on AppFuse? Regardless of parent vs. dependencies, I think running "appfuse:full-source" should allow you to de-couple your project from AppFuse.

Posted in Java at Oct 29 2008, 02:18:59 AM MDT 7 Comments
Comments:

You can already define several webapp source directories in jetty. See Configuring Multiple WebApp Source Directory

Posted by Kai Grabfelder on October 29, 2008 at 01:47 PM MDT #

Thanks for the tip Kai. I tried this by 1) upgrading to Jetty 6.1.12.rc3 and 2) removing the warpath dependency (which resolves dependencies in war projects) in web/struts/pom.xml. According to the link you provided, Jetty run should recognize war dependencies and add their source path. When I tried it, I got an error about a class not being found that was in my war. If I added the warpath dependency back in (to resolve class files in the war project), I get an error about a missing JSP that's in the dependent war. In other words, it doesn't work. :(

Posted by Matt Raible on October 29, 2008 at 02:30 PM MDT #

Hi Matt,
Take a look at this technique for sharing resources: http://blogs.sonatype.com/people/brian/2008/04/17/how-to-share-resources-across-projects-in-maven

--Brian

Posted by Brian Fox on October 30, 2008 at 06:20 AM MDT #

Thanks Brian - that's a pretty long how-to. ;-) I'd love something more concise:

  1. Publish WAR as a src WAR instead of binary.
  2. Dependent projects add WAR as a dependency (or use the dependency plugin).
  3. Dependent projects extract src WAR into their src upon startup.

I don't know if that's a viable solution, but it seems a lot simpler to understand. Ideally, jetty:run (and mvn package) could use source/assets from multiple projects (side by side on disk) and archetype:create-from-project could include both projects when creating archetypes.

Posted by Matt Raible on October 30, 2008 at 11:33 AM MDT #

You could choose to use the war plugin to package your resources, the dependency plugin can unpack them all since they are just zips. In fact, layering of wars was how the dependency plugin came to exist. The draw back to making your build pick up stuff side by side on disk is portability. To me, each module should be buildable standalone, meaning everything it requires should either be in it's scm tree, or retrievable via the repository.

Posted by Brian Fox on October 30, 2008 at 11:53 AM MDT #

Brian - will the Maven plugin allow me to package the raw source (including .java files)? Can those then be extracted into my source tree (vs. .class files in the target directory)? I want to be able to run "mvn jetty:run" so I can save+refresh w/o restarting the server.

Posted by Matt Raible on October 31, 2008 at 11:50 AM MDT #

Matt, I just installed Appfuse for the first time for a personal project a few minutes ago (although I use it at work for a real project) and here's some timely feedback:

Using it at work is painless. I don't know I'm using Appfuse. It's nicely hidden. Perhaps because the setup was done prior to my joining the project.

Setting it up at home was hell. (sorry.) I chose the Struts 2 modular version. Maven get downloading...and downloading...and downloading. And then it died a few times. So I tried again. Then I was missing artifacts. So I tried running Maven from the parent pom. And it started downloading...and downloading. No lie: this was a 3 hour task.

Right there, I'd suggest less is more. All I asked for (and thought I was getting) was a Struts 2 bootstrap with maybe Spring and Hibernate. I think I downloaded every possible web technology in use today.

I then open up the source in a IDE. Very little source code is there. I later learn most of the source is in a war in m2.

Now I'm confused. Is Appfuse a bootstrapping framework intended to get a fella up and running quickly...or is it an app? It seems to be a little of both, which is ok.

I would expect the bootstrapping part fine to keep in a war. But the source/sample app part should be in your project.

So right now, I have Appfuse up and running, but I might not to use it. Why? Because less is more. I wanted to use Struts 2. But as I poked around, I noticed that I "get without asking" Tapestry and Velocity as well. And Canoe. And DWR. And JPA, though I expected Hibernate. And probably a whole lot of other stuff that I either have to learn, or rip out (and have to learn how to rip out).

I'll give this a few days and keep poking around to see what I need to learn, and see if I feel like learning it, before deciding whether to use it wholeheartedly on a personal project.

Posted by Tony on November 16, 2008 at 11:26 PM MST #

Post a Comment:
  • HTML Syntax: Allowed