Blogbody Rotating Header Image

Project Able: a complete Java web stack

UPDATE: This information is no longer accurate. Please see the new Able project on Google Code for the full details.

Project Able is a full Java-based web development stack designed to make web development painless. In a sense, it is an attempt to bring together quality opensource tools in one cohesive stack, similar to what Rails has done for Ruby, while also encouraging common practices I’ve used in software engineering for a long time.

It is very similar to projects such as Trails, Grails, and AppFuse. However, there are a few key differences:

  • The stack components are different (WebWork, Spring, iBatis, etc).
  • In addition to the basic framework, Able also encourages common development techniques and patterns (more below).

Overview

Able was started for two reasons:

One: with the success of Ruby on Rails, it was clear there was a demand in the web development for a streamlined stack. In the Java world, there has been a long fascination with building up a hodgepodge of components in to a custom stack. But often, all we really want is to get started right away.

Two: having recently built HostedQA and BigBark in a very short time period, I realized that there was a common pattern for building web apps that I had been following for years. Able is an attempt to ingrain those patterns and techniques in to a single starting point for new webapps.

When looking at a framework like Rails, one quickly starts to see that Rails isn’t just a web framework and therefore similar to WebWork or Struts. In fact, it is much more: it provides the database layer, a build infrastructure, a testing infrastructure, and more. In short: it provides the complete package all under one roof.

Not a Library

Able is not a library. It is not like RIFE or like WebWork or Hibernate. Able is, instead, a starting point for building webapps. The code inside of Able becomes the code in your application. It is meant to be adjusted and mutated as your project goes on.

Of course, Able will evolve too, but for the most part your only need for Able will be when you start your work. Some, however, may wish to look at Able as a way to streamline their existing web development process. But most will checkout Able from SVN the day they start their project, and then never look back.

Part of the reason I’m doing this is because the more and more I’ve been using (and developing) opensource, the more I’ve found it is easier to simply grab a copy of the latest release of Library X and either fork it or provide hooks in to little known APIs that allow me to control the inner guts. At the end of the day, I’ve found that if I had simply just had the entire project’s code checked in to my project, I would have been more efficient.

In many ways, this is like code generation. That isn’t to say that there aren’t libraries that Able depends on (there are), but rather the extensions done to those libraries aren’t delivered as another library, but rather source code you are free to modify and improve over time.

I think this will provide the best and easiest way to get started quickly and still allow for a lot of freedom to change things moving forward.

The Parts of Able

Able can be split up in to two parts:

  • Components – these are the libraries Able depends on (iBatis, Spring, WebWork, etc).
  • Development patterns – these are the techniques used in Able that we encourage other projects to adopt (upgrade framework, build profiles, test fixtures, etc).

Components

Able uses the following components/tools:

Each of these libraries is the leader or considering one of the leaders in the space it occupies. They were all picked by me as personal favorites for various reasons. In the future, if people are curious, I’d be happy to go in to detail why each one was picked.

I imagine that the Spring and iBatis picks may be cause for some concern among certain people, but know that most of these choices were primarily based on three criteria:

  1. Does the framework provide control and insight in to what it is doing?
  2. Does the framework fail fast when it can?
  3. Does the framework allow for hooks in to it to let me customize it in unique ways?

If two particular frameworks pass that test equally, it ultimately came down to personal style. The good news is that with Able, you are free to just modify the source as you see fit. That’s one of the advantages I see with distributing Able as a project rather than a library/framework.

Development Patterns

Able also addresses very common development processes and packages them up in a ready-to-use form. They are:

  • Clean URLs in WebWork (ex: /profile/1/view). The IDs in the URLs are automatically extracted and turned in to parameters using the following convention: /profile/1/view becomes /profile/view?profileId=1.
  • Convention/annotation-based WebWork action configuration (no xwork.xml file at all). Simply create a class in the proper package and your action is configured. JSPs are assumed as the default result, but you can override them with a @Result annotation.
  • Additional support for common web techniques, such as the “Flash scope” (Redirect-After-Post pattern), simple checkbox support, and an easy way to mark WebWork actions as “page partials” that should not be decorated by SiteMesh.
  • A configured QuickStart setup (QuickStart is part of WebWork) that allows for quick deployment of your application during development.
  • A nice DAO wrapper around iBatis that utilizes Java 5 generics quite nicely, as well as provides support for multiple database vendor syntaxes.
  • Support for reloading iBatis configuration files during deployment to ease development (thanks to Steve Grimm for this!).
  • An upgrade framework that tracks your current build and helps take you to most up to date version (can be used for database changes and other changes). For more info, see here and here.
  • A test fixture built on TestNG and optimized for Java 5, utilizing code from Spring that ensures your Spring container is set up properly on every run. This helps integration testing immensely.
  • A concept of build profiles, including a development (default) and production profile. Here you can specify things like an in-memory database, a MockMailService, and anything else you’d like to use to streamline development.
  • IDE project generation specifically tailored for IDEA that automatically configures your IDEA project with Run/Debug profiles for launching the webapp and running integration tests. Your team really can simply “checkout and go”. (Note: IDEA 6.0 will provide the ability to save Run/Debug settings in ipr and iml files, making this feature less useful. But until IDEA 6.0 comes out of beta, it is still a big help.

Examples

Let’s take a look at an example of a few of these key items:

Clean URLs

Typically, Java-based web applications require fairly ugly URLs such as foo.action or foo.do. Not only do these URLs expose their implementation, they are just more painful to work with. Able helps by adopting a more REST-like URL strategy where the URL itself actually encodes some of the data typically found in query parameters.

For example, a typical WebWork URL might look like:

/viewPerson.action?personId=1

Using Able, we instead encourage a URL like this:

/person/1/view

Not only is the URL more concise and descriptive, it actually makes writing HTML easier. For example, using the viewPerson.action style, an update form might look like:

bc..

name=”person.firstName”/>

You now can simply do:

bc..

name=”person.firstName”/>

Similarly, I’ve found this style reduces the need for things like the ww:url tag and other mechanisms to make URL generation easier to deal with. By simply making the URLs themselves easier, there is little need to use those wrappers anymore.

The automatic parameter application only works for numeric values currently. Perhaps in the future we’ll support Strings and other types, though that requires a bit more work to distinguish a String from a legitimate sub-directory.

Directories are handled by the convention-based configuration (discussed next). The actual underlying implementation of this ActionMapper can be found in the AbleActionMapper class.

Convention-based configuration

Another pain I’ve experienced with WebWork is growing configuration files. The fact is that most of what was in those files was based on the same pattern over and over. Able takes those common patterns and makes them a standard convention. The rules for the conventions are:

  1. Actions must be stored in com.opensymphony.able.actions.
  2. Sub-packages in that package are treated as directories.
  3. Actions must be named in the style FooAction, meaning classes that don’t end in “Action” won’t be mapped.
  4. Results are assumed to be found at /path/to/action-resultValue.jsp. For example, if com.opensymphony.able.actions.foo.BarAction returns “success”, then Able will look for /foo/bar-success.jsp.
  5. If that JSP can’t be found, Able will try /foo/bar.jsp. This is done because there is a common pattern of sharing the same JSP for several result values.
  6. If you need to do override the conventions for result mappings, such as to provide a redirect, you can do so with the @Results annotation.

An example annotation for a redirect might be:

@Results(values = {
@Result(name = Action.SUCCESS, type = Redirect.class,
location = "http://www.hostedqa.com")
})
public class FooAction extends AbleActionSupport {
...

The interceptor stack is hardcoded and includes support for the flash scope, partial page rendering, and better checkboxes (see the next topic for more). If you need to change the interceptor stack, you’ll need to edit the class AbleConfiguration.

You can even tweak the file to do a combination of reading in an xwork.xml file and also using convention-based configuration – it’s up to you. However, having built two medium-sized applications using this style so far, I’ve found it is often easier to deal with the 10% exception cases by structure the class hierarchy.

I have had one case, for example, where I have an empty action class that simply extends another class. This is an alternative to action aliasing that actually turns out to be fairly nice to work with. But again, you are free to change AbleConfiguration as you see fit.

Common web development techniques

There are a few common web development techniques that either aren’t supported by WebWork or aren’t in WebWork’s scope. Either way, Able provides the following features:

  • A complete implementation of the “flash scope” or Redirect-After-Post pattern.
  • Better support for boolean checkboxes, specifically making submission of unchecked checkboxes easier.
  • A way to tag your actions as @Partial, which forces SiteMesh to not decorate the rendered view. This makes doing AJAX with SiteMesh very simple.

Flash scope support

Using the annotation-based result mapping (see above), you can replace a Redirect annotation with a Flash annotation. It behaves almost exactly the same, except that the subsequent request that you’ve redirected (flashed) to will have the original action pushed on to the stack. This means you can display content from the previous action (such as a confirmation message) easily.

Example:

@Results(values = {
@Result(name = Action.SUCCESS, type = Flash.class,
location = "/person/${person.id}/view")
})
public class FooAction extends AbleActionSupport {
...

Seamless un-checked checkbox support

Embarrassingly, WebWork has never made supporting un-checked checkboxes easy. The problem lies in the fact that HTML doesn’t submit a form value if the checkbox is not checked. Able fixes this by changing the WebWork checkbox template to actually render out two form items per checkbox: the checkbox itself and a hidden field.

Then an interceptor is applied that compares the hidden field and adds the value to the parameters to apply to your action if checkbox was not found (therefor not checked).

Partial page identification

People who use SiteMesh love it, but I’ve found that often SiteMesh users structure their URLs in a way that makes using SiteMesh simpler, rather than ways that make their URLs make more sense. Common URL patterns I’ve seen include “/secure” or “/member” (to have a root path that the logged in decorator should show) as well as “/partial” (to have a root path that shouldn’t be parsed).

This happens because SiteMesh makes it easy to map URL patterns such as /secure* or /partial* to specific decorators, or to be excluded.

With the increased use of AJAX, SiteMesh users find themselves needing to exclude much more content than they have in the past. The @Partial annotation, when applied to an action, allows for you to easily make some actions render back just partial HTML (to be used by Prototype’s Ajax.Updater, for example) without placing all your partial actions under a common URL root such as /partial*.

iBatis DAO wrapper

Using Java Generics, there is a base DaoService class you can extend for additional service classes for new entities. It encourages a practice of one service per entity (Foo -> FooService, Bar -> BarService, etc). The DaoService provides a Dao<T> object specifically for that entity. You can then do things like:

public User findById(long userId) {
return dao.selectSingle("byId", userId);
}

public User findByEmail(String email) {
return dao.selectSingle("byEmail", email);
}

public User findByFirstNameOrLastName(String firstName,
String lastName) {
return dao.selectSingle("byFirstNameOrLastName",
firstName, String lastName);
}

public List findByUpdatedAfterDate(Date updatedAfter) {
return dao.select("byUpdatedAfter", updatedAfter);
}

The key thing here is that the DAO object uses var-args and Generics. The var-args usage is unique in that the name of the query (ex: “selectByFirstNameOrLastName”) gets parsed for “and” and “or” keywords and then the parameters are placed in to a map with those keys. In the case of findByFirstNameOrLastName(), the iBatis query looks like so, found in User.xml:

bc..

The same applies for delete, update, and insert.

In addition to this, the DAO layer also looks for queries named “foo-vendor”, where vendor is something like “hsql” or “postgres”. This lets you write your application to work on multiple databases. Even websites should do this, simply for the fact that using an in-memory database helps with testing/development but you’d want to use a real database in production.

Upgrade framework

The best way to understand the upgrade framework is to look at my previous blog entry on the subject.

Build profiles

One thing that I really like that Rails encourages, and that I think most developers have done for years, is using the concept of build profiles. Out of the box, when you run “mvn install” you get a different build from when you run “mvn -Pprod install”. Looking at pom.xml, you can see that the “prod” profile simply copies over config.prod.xml to config.xml when building the webapp.

Inside of config.xml (the default/dev profile), a MockMailService is used, as well as JDBC url that indicates to Able to use an in-memory database and a sample database script (sample.sql) to populate initial data. This makes developing much easier, and encourages a “checkout and go” philosophy.

Inside of config.prod.xml, a real MailService is used and a real postgres database is specified. Tests are also skipped, since we assume that by the time you are ready for production you don’t need to run your tests.

Using this pattern, you might want to introduce a “staging” or “qa” profile as well.

Getting Started

Are you interested in getting started today? Great, welcome aboard! Right now Able is nothing more than code checked in to OpenSymphony’s sandbox SVN repository. You can find it at:

https://svn.opensymphony.com/svn/sandbox/able

Once you’ve checked out the code, simply do the following:

  1. Make sure you’ve downloaded maven 2.0.4 and have it in your PATH
  2. Make sure you’ve got the TestNG plugin (TestNG-J) downloaded and installed in IDEA.
  3. Run “mvn install”.
  4. Run “mvn idea:idea” to generate your IDEA project files (”maven eclipse:eclipse” should work too, but I haven’t optimized that yet)
  5. Open able.ipr in IDEA
  6. Run the “Run Webapp” target to launch Able at http://localhost:8080
  7. Run the “Services” target to run all the TestNG Spring service tests
  8. Rename the package com.opensymphony.able to whatever package you’d like to start with (this package is also referenced in a few classes, so you’ll need to change those too – soon I plan to refactor that hardcoded package out to a single configuration file).

That’s it! Let me know what you think and look out for Able graduating from a sandbox project in the not-to-distant future.

22 Comments on “Project Able: a complete Java web stack”

  1. #1 Spiff
    on Aug 14th, 2006 at 10:58 pm

    This looks very promising, I hope I have some time to try it out some day. But for now, I guess the obvious question is: why did you choose iBatis as the O/R mapper? Why not Hibernate or the now-standard JPA?

  2. #2 Patrick Lightbody
    on Aug 15th, 2006 at 7:03 am

    Spiff,
    Honestly, I had a couple criteria:

    1) I like how iBatis fails fast with error messages, like when I have a typo in my beans.
    2) I like that I can control my own queries.

    Now, to be fair, I’ve never really used Hibernate 3 or JPA, so things may have changed quite a bit since Hibernate 2. I’d definitely be opening to switching it out – perhaps you can give me a patch for Able that uses Hibernate and I can see which one works best.

    One thing Able is not is a “choice” platform like AppFuse. We’ll pick one and stick with it in until we switch to another.

  3. #3 Erik Weibust
    on Aug 15th, 2006 at 7:57 am

    Sounds like a great stack. I especially like the choice of iBatis. The big problem is that you don’t have anything to help Eclipse users. Isn’t IDEA a distant 3rd to Eclipse and NetBeans? How about some instruction on getting started with Able and Eclipse?

    Erik

  4. #4 Patrick Lightbody
    on Aug 15th, 2006 at 8:37 am

    Erik,
    Try:

    mvn -DdownloadSources=true eclipse:eclipse

    Then open up the project in Eclipse. Make sure you’ve set M2_REPO to ~/.m2/repository by going to Preferences -> Java -> Build Path -> Classpath Variables. Then you can build the project.

    To launch it, simply run the QuickStart class and go to localhost:8080.

  5. #5 csar
    on Aug 15th, 2006 at 8:56 am

    Nice stuff, just got it workin with Eclipse 3.2.

    The quickstart.xml doesn’t work for Eclipse (there is no iml-file)

    I did a little hack to parse .classpath and voila!

    The onky thing missing is accessing the M2_REPO-variable properly (right now it is hard-coded in my .launch)

  6. #6 Patrick Lightbody
    on Aug 15th, 2006 at 9:09 am

    Csar,
    Very cool – if you want to get me a patch for supporting both idea configurations and eclipse .classpath file, I can get it back in the code. Feel free to email me at plightbo@gmail.com.

  7. #7 Kunle Gbadamosi
    on Aug 15th, 2006 at 1:23 pm

    Nice stack. +1 for choice of iBatis.

  8. #8 Alexander Shvets
    on Aug 15th, 2006 at 1:42 pm

    Nice app. Major problem of AppFuce is that this project is not maven2-ready.

    You can improve your maven pom.xml file by including/replacing these dependencies:

    <dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
    </dependency>
    <dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1</version>
    </dependency>
    <dependency>
    <groupId>postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>8.1-407.jdbc3</version>
    </dependency>
    <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>4.7</version>
    <classifier>jdk15</classifier>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.0</version>
    <scope>provided</scope>
    </dependency>

    It is unclear why do you need to install able:

    mvn install

    Usually you can run jetty plugin without installing the artefact:

    mvn compile war:war jetty:install

    Use this fragment to use jetty:

    <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>

    <configuration>
    <scanIntervalSeconds>2</scanIntervalSeconds>

    <connectors>
    <connector implementation=”org.mortbay.jetty.nio.SelectChannelConnector”>
    <port>9090</port>
    <maxIdleTime>60000</maxIdleTime>
    </connector>
    </connectors>
    </configuration>
    </plugin>

    Alexander Shvets.

  9. #9 botah
    on Aug 15th, 2006 at 3:21 pm

    Pat,
    Looks great. I got it all running with the exception of the TestNG piece… I ran install and installed the TestNG plugin… but im still getting this error:org.testng.remote.RemoteTestNG … normally I would chaise down the offending jar and amke sure it was in my classpath… but since my ipr was built for me magic like I thought perhaps something was wrong.

    Also, the quickstart piece… is it supposed to support dynamic class reloading? IE: start Webapp and change a class and boom it gets reflected in my running webapp? I think this was supposed to be something in WW.2.2 right.

    Also… I see that you have that upgrade framework (big word small framework) that you blogged about in there… make sure to add that to the feature list. ;)

    Ive been mulling around the idea of starting my next project w/ ibatis… this could be the straw… ill let you know after one more cup of coffee, i am in Seattle after all and we don’t make important decisions like that w/out consulting our coffee first.

  10. #10 botah
    on Aug 15th, 2006 at 3:52 pm

    Pat,
    Also, any reason you did not use WW’s domain model validation support system? Rather than overridding validate in RegisterAction for example? You could have created something like IsUniqueValidators that take in a bean type and a property and do a unique lookup for them… I wrote something like that and it worked really well… Just more sugar really I guess.

  11. #11 botah
    on Aug 15th, 2006 at 4:10 pm

    One more final question… really more about iBatis than Able… but…

    When your mapping your select queries… do you really have to repeat the columns every time query..IE:selectByUsername and the such in user.xml

    And… I see that you have atomic updates like updatePassword and holistic updates like update…. is it more the standard in iBatis (vs Hibernate) to update just the field(s) that you know changed… or would you still to it the ‘domain object’ approach where you fetched the domain in the prepare method… then had the WW parameter setter set the changed fields… then saved the whole darn domain object… thats how i do it in hibernate… usually the extra Select to prepare the bean is no biggie cause Hibernate is caching it for me.

  12. #12 sameh
    on Aug 19th, 2006 at 7:34 am

    After reading through your blog, and haven’t got Able running yet, it seems to me that you can combine iBatis and Hibernate (instead of favoring one to the other) by using the iBatis DAO framework to control Hibernate sessions. This will force using a DAO layer with Hibernate (always a good thing) while still keeping the option of using SQL Maps through iBatis. This will have the price of complicating the stack a little.

  13. #13 Patrick Lightbody
    on Aug 20th, 2006 at 8:32 pm

    Alexander,
    Your patch has been applied. If you (or anyone else) has anymore thoughts on Able, come join the discussion at sandbox@opensymphony.com by sending an email to sandbox-subscribe@opensymphony.com.

  14. #14 Patrick Lightbody
    on Aug 20th, 2006 at 8:33 pm

    Sameh,
    We are going to take a good look at JPA/Hibernate.

  15. #15 Patrick Lightbody
    on Aug 20th, 2006 at 8:40 pm

    Mike,
    Not sure about the RemoteTestNG problem – could be that you have the wrong TestNG IDEA plugin?

    Re: QuickStart – I turned off the class re-loading because it isn’t reliable. We will be taking it out of Struts 2.0 entirely. Unfortunate, but necessary for now.

    Re: validation – no particular reason. My philosophy is only to create that stuff when I need to reduce code duplication.

    Re: repeated ibatis queries – yes, you do have to repeat the columns. I’m hoping we can extend some APIs of iBatis to eventually make that less painful.

    Re: holistic updates – I tend to be pragmatic. Sometimes I have a general need to update the whole table, and other times I just want to offer a single update query. With iBatis, you can choose the best option for the situation on hand – something you can’t do with Hibernate and other more full featured ORM frameworks.

  16. #16 larry
    on Sep 5th, 2006 at 1:44 pm

    I am not sure I understand the question re: iBATIS and repeating the columns.

    You can do things like including common column lists, etc with iBATIS (if that is the issue).

    If not, post an enhancement request on JIRA and we will try to get it in the next release if we can. ;-)

  17. #17 Ted Husted
    on Oct 6th, 2006 at 5:28 am

    > /person/1/view
    > The automatic parameter application only works for numeric values currently.

    This is a showstopper for me, since my own applications use GUIDs, which are not pure numeric strings.

    According to the spec, “The hash (”#”, ASCII 23 hex) character is reserved as a delimiter to separate the URI of an object from a fragment identifier”.

    So, why not,

    /person/#ABCD/view

    instead, perhaps as an alternative escape character when the attribute is not numeric.

    Also, moving the parameter into the middle of the string seems like it will cause incompatiblity with other systems. For example, the Confluence macros expect that a parameter can be tacked onto the end of a query string. It might be simpler to go with URIs that use a conventional sequence

    • /person/view/1
    • /person/view/#1234-abcd-5678-efgh

    When the “default” attribute is not being used, we might also support expanding the pattern

    • /person/view/personid#1/flavor#vanilla

    where the last token without a # is the last token in the action path.

    While the latter is not a vast improvement over query strings, I understand that some proxies don’t like query strings, and prefer URIs that look like references to a static resource. For composing Action URIs, this at least simplifies whether to ? or not to ?.

    —-

    > 1. Actions must be stored in com.opensymphony.able.actions.

    Why not just use “actions” for the package? If the code doesn’t belong to com.opensymphony (or org.apache), why bother with the extra verbiage?

    > 2. Sub-packages in that package are treated as directories.
    > 3. Actions must be named in the style FooAction, meaning classes that don’t end in “Action” won’t be mapped.

    Given #1, is not #3 redundant? Why not just use Foo for the classname? If it is a class under the “actions” package, then it should be by definition an action class.

    > 4. Results are assumed to be found at /path/to/action-resultValue.jsp. For example, if
    > com.opensymphony.able.actions.foo.BarAction returns “success”, then Able will look for /foo/bar-success.jsp.

    Hmmm, did we change the example from the Foo Action to the Bar Action?

    Given a Bar action in the package actions.foo, I’d prefer we make the default path /foo/Bar-success.jsp, since this corresponds to the Action package and result code exactly. (I like the way this convention lines up with the Classname-mapping-validator.xml.)

    If we are automating mapping, then we should automate mapping, and avoid introducing arbitrary inconsistencies.

    > 5. If that JSP can’t be found, Able will try /foo/bar.jsp. This is done because there is a common pattern of sharing the
    > same JSP for several result values.

    As mentioned, for consistency, /foo/Bar.jsp

    Extension to 1/3/4/5

    If we accept the best practice “Link only to mappings, never to pages”, are we really linking to Action classes or to server pages?

    Which begs the question: Should the framework generate mappings based on Action classes or server pages?

    If we are looking to see if we have this page or that page, perhaps we should do that up front and generate the mappings based on the pages.

    In this case, there would be a virtual mapping for each page, which may (or may not) be augmented by an Action or other meta-helper, such as validation, conversion, or localization.

    We might even consider doing both. Everything in the “actions” package or “pages” folder is mapped.

    —-

    @Results(values = {
    @Result(name = Action.SUCCESS, type = Redirect.class,
    location = “http://www.hostedqa.com”)
    })
    public class FooAction extends AbleActionSupport {

    What is the purpose of the “location” attribute? Is it optional? Is still a way to change the default result type?

    —-

    • Annotation-based result mapping
    • Flash scope support
    • Seamless un-checked checkbox support
    • Partial page identification
    • iBatis DAO wrapper

    Are these not issues that can be addressed in the Struts HEAD, regardless of the Able ActionMapper?

    -Ted.

  18. #18 Jim Shingler
    on Dec 10th, 2006 at 7:33 pm

    I am a newbie to this, . . . I have run into some newbie issues and don’t really want to subscribe to the email list but would be happy to look through a forum or email archive for an answer.

    Any chance of setting them up.

  19. #19 Patrick Lightbody
    on Dec 11th, 2006 at 7:26 am

    Jim,
    Actually, yes… we’re close to a release that should be much more “official” and provide better support channels for folks like you.

  20. #20 Rahul
    on Nov 25th, 2008 at 4:22 am

    Hi Patrick,

    Did project Able graduate from the sandbox?

    Also, Ted had some questions above – i am wondering if you have any thoughts on those.

    Cheers,
    Rahul

  21. #21 JumpStart Your Web Application « Connexxion : Connecting Life with Technology
    on Dec 2nd, 2008 at 4:06 pm

    [...] ABLE: is a starting point for building web apps. It is not a library and is an aggregation of various open source tools to in one cohesive stack. This is similar to Appfuse and something that Rails has done to Ruby. Able uses Spring for Ioc and iBatis for OR mapping. It does not support Hibernate as of now, or at least I could not find details on that. [...]

  22. #22 Tutorial pantas project-able « CASB Development Blog
    on Sep 12th, 2009 at 7:10 pm

Leave a Comment