By now, there is a good chance you have at least heard of
Ruby on Rails. For those
who haven't, Rails is a framework using the Ruby language that
allows one to create database-driven web applications in a fraction
of the time it would normally take. I'm not going to cover Rails in
this article, as Curt Hibbs has already done a masterful job in
"Rolling
on Rails." Instead, this article will focus on how we can do
Rails-esque "rapid application development the right way" in
Java.
I first heard of Rails as I was hanging out after a meeting of
my local Java users
group with my good friend Jim Weirich. Jim is a well-known Ruby nut and all
around good, smart guy. So when he started talking very excitedly
about "this new Ruby web thing I can't remember the name of," I
decided to hang out a little longer and take a look at a video he
wanted to show me. I probably wouldn't have bothered to read a long
article about it, but heck, even I can spare a few minutes to watch
a video. The video was a screen capture of a developer creating a
fully functional database-driven web application in ten minutes.
As a Java developer my first reaction to Rails was sheer,
unabashed envy. Developing a web application in Java, even with
best-of-breed technologies such as Spring, Hibernate, and Tapestry,
is still much more difficult than cranking out a Rails application.
My next reaction was to think about how we can bring some of the
brilliant ideas of Rails to Java. I'm here to say with certainty
that we can, and I've spent the last several months working to make
it possible for any Java developer to do it.
The fruit of this effort is a framework named, unoriginally
enough, Trails. Despite the name, Trails is in no way a port of
Rails. Rather, it is a framework designed to bring a similarly
radical productivity increase to J2EE web application
development.
What's the Problem?
The first thing we need to figure out is what makes Java
development with our current technologies and methods more
difficult than we would like. To highlight the problem, let's
imagine we are developing a J2EE web application using Spring and
Hibernate, and that we need to add a new type of domain object
called Person to the application. The precise steps will vary
depending on what web framework we select, but here are the steps we would typically need to perform:
Create Person class.
Create PersonDAO class.
Create Person table in database.
Define PersonDAO in Spring application context XML
file.
Create Person page or action class.
Add Person pages to web framework XML
configuration files.
Create personList page to list Person
instances.
Create personEdit page to edit Person
instances.
Of course, these steps will vary, depending on our specific
application design and the frameworks we select, but in general
they are representative. I'm hoping that seeing these list of steps
has you thinking "Phew, that's a lot of work!" Can we do
better?
What's the Solution?
What is the real problem here? I'm going to suggest that we need
to stop repeating ourselves. In fact, this point is so important
that it's worth saying again: We need to stop repeating
ourselves. All we really want is to add a new type of entity to
our system, yet we have at least eight different things we need to do.
What if we could dramatically reduce the number of steps required?
What if we could reduce the number of steps to:
Create Person class?
How could that be possible? Well, let's think about those eight
steps again. I'm going to propose that all of the information we
really need to produce a simple, working application is contained
in the Person class. From it, we can determine:
What kind of attributes a person can have.
The name of each attribute.
The type of each attribute.
Using just this information, we can make enough assumptions to
produce a working application. What if we assume:
For each entity, we want screens in our application to perform
basic operations such as create, retrieve, update, and delete
(CRUD).
We want each entity to be persisted in a database.
We want a database table to be created for each entity.
We would like screens to manage the relationships between
different entities.
Of course, these assumptions will not always be correct, but in
many applications they will be. If we had a framework that could
use these assumptions to produce a working application based on our
domain model, we could greatly accelerate development in many
cases. Furthermore, if this framework let us easily override these
assumptions where necessary, we could quickly produce a working
prototype application and "flesh it out" into our final
application.
Introducing Trails
Trails is a domain-driven development (DDD) framework for Java. Its goal is to allow
us to develop J2EE web applications with the fewest redundant
steps. The term "domain-driven development" refers to the process
of developing an application with a rich domain model: in the most
basic example of a Trails application, the domain model will be the
only code we write! Trails uses this domain model as the only
source of information it needs to dynamically create a basic
application. As mentioned above, it makes a lot of assumptions to
be able to do this, and we'll explore how to override those
assumptions in a future installment. But that's getting ahead of
ourselves. First, let's start with a very simple Trails
application.
If you have not already done so, download and unzip Trails. You
will also need the following installed on your system to use
Trails:
Ant 1.6. Note: Be sure to
have your ANT_HOME system property set correctly.
Trails will use this property to add a .jar to
ANT_HOME/lib.
Our First Trails Application
For this article, we will gradually recreate the Recipe
application from Curt Hibbs' RoR article. To create our application,
you need to be in the same directory where you unzipped Trails. In
this directory, do ant create-new-project. You will be
prompted for the following:
Base directory
Name of project
For the name of the project, enter "recipe." This will build a
project with the following directory structure:
<basedir>/recipe/
The directory containing your new project. This contains a
build.properties file you will need to customize as
well as a build.xml file. Point your IDE at this
directory.
<basedir>/recipe/src
The directory in which to place your source code. The
compile and build-hibernate-config
targets will start from here.
<basedir>/recipe/context
This contains your web application.
<basedir>/recipe/context/WEB-INF
This directory contains the web.xml file and the Tapestry page
definitions. The hibernate.properties file is also
located in this directory. Editing it will allow you to change your
database configuration.
<basedir>/recipe/lib
This contains all of the .jars Trails depends upon.
Be sure, if you have not already done so, to add a user to
Tomcat with privileges to use the manager application, as the
Trails Ant build will be unable to deploy our application
otherwise. By default, Tomcat does not have such a user, but it's
easy to add one. Edit your conf/tomcat-users.xml file
(relative to where you installed Tomcat). Add a line like this:
To complete the setup process, edit the build.properties
file in the directory where you installed Trails. Below is a list
of the properties in this file.
tomcat.home
The directory where Tomcat is installed.
tomcat.url
The URL to use to connect to your Tomcat server.
manager.username
The username to use when connecting the Tomcat manager
application.
manager.password
The password to use when connecting the Tomcat manager
application.
How 'Bout Some Code?
Alright, now that setup is out of the way, let's write some
code. If you have been paying attention, you can probably guess
what code we'll develop first. If you said "domain object," give
yourself a pat on the back. Domain objects in Trails are just plain
old Java objects (POJOs). Because Trails uses Hibernate to persist
our domain model into a relational database, we will also need to
add some JSR-220 persistence annotations to tell Hibernate some
extra information it needs. For a first domain object, let's create
a Recipe class, as follows:
package org.trails.recipe;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
@Entity
public class Recipe
{
private Integer id;
private String title;
private String description;
private Date date;
@Id(generate=GeneratorType.AUTO)
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
}
This is a fairly simple JavaBean: we've got properties for
Title, Description, and Date,
and an Id property. We also have two JSR-220
annotations. We have an @Entity annotation that tells
Hibernate that this class is persistent. We also have an
@Id(generate=GeneratorType.AUTO) that tells Hibernate
which property is the identifier property (a "primary key," in
database parlance), and that we want this property to be
automatically generated. Notice that we don't need to explicitly
mark our other properties as persistent. This is because Hibernate,
in conformance to the EJB3 spec, will assume all of our properties are
persistent unless we explicitly mark them as
@Transient.
Step One ... and We're Done!
Believe it or not, we've now developed our first Trails
application. Let's deploy it and see it in action. If it is not
already running, start your Tomcat instance. Next, go into the
directory where you created the project and do ant
deploy. This will build our application and deploy it in our
running Tomcat instance. For maximum simplicity, Trails uses HSQL
as a simple in-memory database and lets Hibernate create all the
tables (this is, of course, configurable). To see our application
in action, we simply point your browser at
http://localhost:8080/recipe. For nothing more than
the cost of our simple domain class, Trails gives us a simple
application that will lets us work with recipes.
The default home page of a Trails application will show a list
of all of the domain object types in our application, as seen in
Figure 1.
Figure 1. Application home page
Following the List Recipes link takes us to a page which, if you
can believe it, lists all the recipes. As you can see in Figure 2,
there aren't any yet.
Figure 2. List recipes
Following the New Recipe link takes us to a screen that will
let us create a new recipe, shown in Figure 3. Notice the date
widget provided for us at no extra charge.
Figure 3. Edit recipe
Not bad for just coding one class, eh?
How It Works
Some of you already thinking "How is all that code being
generated?" There's a short and simple answer to that question:
It's not. Trails eschews code generation for the simple
reason that code generated is still code to maintain. Rather than
generate code, Trails dynamically creates your application at
runtime. For each domain class, a set of metadata is built up
through a combination of reflection and Hibernate mapping
information. Intelligent web components then use this metadata to
produce a UI.
Sounds simple enough, but as you probably can guess, there's a
lot going on under the covers. Fortunately, Trails has a lot of
help. One of the key goals of Trails is to eliminate unnecessary
code, so it only makes sense that Trails avoids reinventing wheels
wherever possible. In fact, Trails leverages other frameworks to do
a lot of the heavy lifting. Trails uses:
Hibernate for persisting domain objects to the RDBMS, as well
creating the tables.
Spring for dependency injection and configuration.
Tapestry as the web component application framework.
Relationships
We have an application, but it's not very interesting. What
makes an application interesting is not objects in isolation, but
objects and their relationships. Let's introduce the concept of
categories to our domain model and assert that a
Recipe is in exactly one Category. We'll
start by creating a Category class:
package org.trails.recipe;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import org.apache.commons.lang.builder.EqualsBuilder;
@Entity
public class Category
{
private Integer id;
private String name;
@Id(generate=GeneratorType.AUTO)
public Integer getId()
{
return id;
}
/**
* @param id The id to set.
*/
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
this.name = name;
}
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
}
public String toString()
{
return getName();
}
}
Like Recipe, this is a basic POJO with two
annotations. Notice that we have overridden two methods from
Object: toString() and isEquals(). These
methods are necessary for Trails to build a web interface for
objects that are related to Category. The
toString() method is necessary to tell Trails how to
display a Category. The isEquals() method
is necessary for Category objects to work properly
when used in a List. We will see how these are important
shortly.
Now that we have created a Category class, we can
add a category property to our Recipe class:
private Category category;
@ManyToOne
public Category getCategory()
{
return category;
}
public void setCategory(Category category)
{
this.category = category;
}
Nothing fancy here, just a simple JavaBean property with an
annotation to tell Hibernate what kind of relationship this is.
Now we'll probably need to actually get into the nitty gritty
and start typing some HTML, right? Nope, not yet. Trails will give
us an application that manages the Recipe-Category relationship for free, no grunt coding
required. Don't believe me? Run ant redeploy.
When you visit the initial page, notice the link to List
Categories. Follow this link and click on the New Category link.
Create a couple of categories. Now go back to the Recipe page and
create a new Recipe. You should see now see a Category
field on the Edit Recipe page, as seen in Figure 4.
Figure 4. Assigning a category to a recipe
Trails will give you, free of charge, a
<select> list of all of the Category objects for
you to choose which Category a Recipe belongs in. This is where the
toString() and isEquals() methods come
into play. The toString() method is used to display
the label in the select list, and isEquals() is used
to determine which Category was selected.
Conclusion
Let's take stock of what we've done. We've built a complete
(though simple) J2EE application that lets us manage recipes and
assign them to categories. The only code we've written has been our
domain model, and in return, we have an application that includes a
web UI and database persistence. We have solid architecture that
builds on proven frameworks such as Spring, Hibernate and Tapestry.
And we've built this in just a few minutes.
In the next installment we will explore Trails in greater depth.
We will learn how to customize a Trails application to override the
assumptions Trails makes. We will also see how Trails also handles
relationships more complex than a simple many-to-one. And finally,
we'll explore how Trails supports validation by annotating your
domain classes.
Resources
Code from this article:
For those who want to play along with our contestants at home,
a .zip
of the source
For those who always skip to the answers at the back of the
book, the
completed .war file ready to deploy
Great but... equals()?
2007-06-14 10:29:35 tdman
[Reply | View]
This code still exists in SVN:
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
}
It simply does not work properly, I am able to create two categories with same name and see it in a list of categories.
Isn't it better to develop from scratch...
public boolean equals(Object object) {
if (!(object instanceof Category)) {
return false;
}
Category category = (Category) object;
return category.getName().equals(this.getName());
}
Trails is very attractive. How is it possible that main and simplest functionality isn't carefully tested still? Looks like a toy... but I need it, I like it.
And... with InnoDB of MySQL do not use SELECT COUNT(*)!!! It will take a while with big tables.
Great but... equals()?
2007-06-14 10:39:30 tdman
[Reply | View]
This is buggy:
return category.getName().equals(this.getName())
;)
Great job
2006-07-24 23:01:55 bparanj
[Reply | View]
Chris, Your approach is very promising. You have succeeded where Sun engineers have failed miserably.
By taking the best of breed open source frameworks and following the DRY principle Trails brings joy to web application development and it rocks!
Please do not get distracted and try to support million different web frameworks. KISS principle will allow this framework to gain popularity.
I am still learning Rails but I am still a newbie to Ruby. I wish we could make this as good as Rails. How many developers are currently working on this project?
I am assuming lot of features similar to Rails such as database migrations, web services support, email service are coming soon.
Where is the hivemind?
2006-05-26 05:53:55 kcolassi
[Reply | View]
Hi Chris,
I particularly admired the way you surgically identified hibernate objects and used AspectJ to create an across the board datasqueezeadapter for all of the pojos in one sweep. That was really cute.
But I am still questioning the need for SPRING. It seems you have your hibernate service rigged there.
I believe you can perform the same thing with hivemind and reduce the foot print.
I have looked at ytour stuff and operated my own versions. Keep coming back to trails and liking it alot more.
If there is a way to reduce the footprint that would be nice. Codebase footprint that is.
- cheers
help please! how to resolve this compile error?
2006-04-19 20:10:10 evan_zeng
[Reply | View]
compile:
[iajc] D:\test\mytest\src\org\trails\recipe\Recipe.java:6 [error] The impor
t javax.persistence.GeneratorType cannot be resolved
[iajc] import javax.persistence.GeneratorType;
[iajc] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help please! how to resolve this compile error?
2006-04-19 20:48:10 ccnelson
[Reply | View]
HIbernate annotations have changed in the .9 release of Trails. See HIbernate annotations docs for details on the new form of id generation annotations.
help please! how to resolve this compile error?
2006-04-20 01:33:40 evan_zeng
[Reply | View]
thanks!
Soultion For: help please! how to resolve this compile error?
2007-01-30 12:25:23 ahmedlondon
[Reply | View]
Hello, I Have Faced This Problem Too But I've Solved The Problem As Follow:
1- You have to download the Persistence Package If You Don't have it and include it in your lib.
2- annotation is changed in new trails and hibernate, so you have to modify the recipe.java code as follow:
package org.trails.recipe;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.*;
@Entity
public class Recipe
{
private Integer id;
private String title;
private String description;
private Date date;
@Id @GeneratedValue
public Integer getId()
{
return id;
}
....
the rest will be the same... and that's all...
A.H.S
help please! how to resolve this compile error?
2006-05-19 10:44:52 schaleff
[Reply | View]
I am hoping you can tell use how to fix this in the demo. I looked at the hibernate website, but am unfamiliar with it and not sure where to start. I would like to just get your demo up and working. Thanks Sky
What about upgrade to the persistent code?
2006-03-28 20:31:30 st946tbf_3
[Reply | View]
When you change your code, how do you upgrade the underlying database in the way that you want and also fit into the new code? Some cases, it's not simple as add a new field, or rename a field. Takes for example: refactor a big project, etc.
Other stuffs should be of concern is permission based. For example: user A may see some items in the list, but user B see other items. Or some lists user A can see while user B cannot.
Validation and error handling?
Where is the configuration for database? I imagine in some hibernate configuration files. This is just an example, but are you prepared for growth senario that much more complicated project requires larger than linear effort? What I tried to say here is that if default is not good enough, or a function was not provided, a work around should be also very easy, and there must always be aworkaround for anything not supported.
I got knowledge of your project just from an article about the new logo contest.
Ironically it was the same headlined "Web 2.0 and the Java developer" by Rick Ross' cover story.
Since what the benefits of Trails are supposed to be I had a framework back between 1998 and 1999 (based on Oracle 8 and later 8i with its JVM on the server) which tried to solve similar problems back then.
It was even called "Domain Framework" designed for a customer of mine a (internationally rather unimportant ;-) Sun and Oracle partner company from Austria.
However, instead of using that framework and get aspects of "Web 2.0" done and maybe even sold long before 1.0 burst, some product manager unable to understand it found the process to write generators for those DAOs, DTOs, XMLs,... too complicated and insisted on using EJB EntityBeans EVERYWHERE (even directly in the Swing or Web Client!;-)
Those of you familiar with Patterns might know that as one of the AntiPatterns.
And even based a whole application server, they wrote on that and other AntiPatterns (I do not have to tell you how many copies they sold ?;-)
So I turned that concept into a framework called "LOV" (List Of Values) to distinguish it from that old one which died with its container.
And merged it into a collection of J2EE frameworks and components called "OdysEE" around 2001.
Day to day project work as well as the burst of Web 1.0 (not directly linked to 911, but somewhere around and after it) made this one stale for most of the time. And today I also keep using frameworks which emerged later and many of them also got similar ideas as I did anyway.
Maybe I can also participate here. So the "Long Trail of DAO" might not take forever, and OdyssEE or some of its ideas to ease Enterprise Development might get a sequel even before 2010?
I'm interested in some documentation and also the topic of user access. Is there a recommended solution, existing solution or plan to incorporate that?
This article and the sequel provide the main user documentation for Trails. There is also a good deal of information on the Trails wiki.
Security is well under way, and is being implemented using the Acegi framework. At this point the code in CVS head will let you experiment with Security, though there is no documentation yet I'm afraid.
Well, did anybody try to combine this with Struts? (instead of Tapestry?)
2005-10-23 04:01:24 markygoldstein
[Reply | View]
Well, did anybody try to combine this with Struts? (instead of Tapestry?)
Could this be done?
Well, did anybody try to combine this with Struts? (instead of Tapestry?)
2005-10-24 09:02:09 ccnelson
[Reply | View]
It would be pretty difficult to do Trails without a component oriented framework. That makes JSF an option, and one I may consider after 1.0. Porting to Struts would be, IMO, a lot of work to support a deprecated framework.
Well, did anybody try to combine this with Struts? (instead of Tapestry?)
2005-12-03 13:21:57 emcmillan
[Reply | View]
Hopefully migrating to JSF will be something to consider after 1.0 since I think you will get much more community support for a component oriented framework that has taken ideas from Tapestry and has become an industry standard. You are using Hibernate that is going to be compliant with the EJB 3.0 persistence standard and it is a defacto standard in its own right so that has many people looking at this framework. I think trails could become very popular as it progresses.
Well, did anybody try to combine this with Struts? (instead of Tapestry?)
2006-04-12 08:26:16 jayzou
[Reply | View]
How about the new Spring Web Flow inside of Spring? It sounds cool but may be too early. Is any support of AJAX (the topic of day)? Can I plugin another java blog package into the framework?
First of all, compliments for the Job done, is really effective the way you decided to combine "effective" pieces together. I know that is maybe premature, but the support for all the annotation tag can be improved, in particular the support for @Embedded object that at the moment are not shown in the form for editing. It could be possible to create a Typestry component to be embedded inside the EditPage if there are some @Embedded objects... How does this sounds?
Compliments Again, I am planning to use trails seriously, I could also contribute in my spare time...
Yeah, supporting Hibernate "components" (same as @Embedded) is on my list. I believe it now would be possible to do in CVS HEAD, as you can specify per type editors, but not as easy as I would like to make it. I'd love to have your help if you want to get involved. This might be a great area for someone to jump in and tackle.
OK, I have some spare time now, I am browsing the code to get the right philosofical grip and try to introduce components to render @Embedded Objects as well as a support for @Inheritance, which I think is also missing, at least in my tests ;-)
Ciao
ANdreaT
Context path is required
2005-08-13 04:53:58 baltner
[Reply | View]
This looks very promising and I'd begun reading about Tapestry,Spring and Hibernate so this gives me a chance to start using them all at the same time.
However, I am getting an error when trying to deploy the recipe app. Ant reports an IOException on line 144 of the build.xml file because, for some reason, a context is not specified (see below). The war file does get deployed but tomcat can't start the application. I am quite sure that my build.properties file is correct. Any ideas? Thanks!
-Bruce
BUILD FAILED
C:\JAVA\Trails\working\recipe\build.xml:144: FAIL - Encountered exception java.io.IOException: java.lang.IllegalArgument
Exception: Context path is required
Context path is required
2005-08-13 10:03:14 ccnelson
[Reply | View]
I would try manually deploying the application and watching the tomcat output to see if errors occur on startup. Please report issues on the Issue Tracker for the project.
Context path is required
2005-08-13 08:05:19 baltner
[Reply | View]
Also, I tried adding path="/recipe" to the context.xml file, as someone suggested on the Trails blog deployment forum, but it didn't help.
Thanks.
One more nit to pick
2005-08-02 17:34:51 einer
[Reply | View]
The import statement for the ManyToOne class is missing in Recipe.java. This is only noticeable if you try adding the annotation stuff mentioned later in the tutorial to your model. Maybe a note there about also adding that import statement? I think I'm almost there!
One more nit to pick
2005-08-02 20:09:24 ccnelson
[Reply | View]
I'm pretty sure it's there in the source code zip (else it wouldn't have worked, and, though it may seem hard to believe, I did actually try it :) ). It didn't make it into the article, since I only include the full source of Recipe once, and at that point I hadn't added it yet. I'm so used to Eclipse automatically doing things like that for me I didn't notice.
One more nit to pick
2005-08-03 13:35:48 einer
[Reply | View]
Actually, once I realized there was a source zip, that's how I found it. Also, it now works!
I'm playing with the Tapestry templates now. This is some really neat stuff.
I haven't been this excited about a technology (framework) since eclipse and the MyEclipseIDE plugin set.
My next mission is to learn how to fully customize the tapestry templates and relationship types between the domain entities. The article says that this will be covered in the next article. Is there another alternative for the impatient (besides reading the source)?
Oh. Almost forgot. Thank You! There's a free pint in Nashville with your name on it.
Performance vs Productivity
2005-08-01 12:39:51 rmsaavedra
[Reply | View]
I've been studying some web development frameworks and Ruby-On-Rails' productivity really caught my attention. Haven't seen anything similar to that in Java or any other language (till now...?)
It seems that Trails may add that kind of productivity to a project, with an extra point since my team is used to Java programming.
I was warned about the possibility of performance problems when using R-O-R in a large scale. I would like to know how much the adoption of Trails would affect the response time in a (for instance) 1 Million users portal. I'm sure there is a trade-of on that, but would it be possible to scale a Trails-based solution that much?
Regards
Performance vs Productivity
2005-08-01 13:24:53 ccnelson
[Reply | View]
Well, think about it this way. Trail relies on Spring, Hibernate, and Tapestry to do all the heavy lifting. All these technologies have very proven track records when it comes to scalability. Tapestry, for instance, is used on TheServerSide.com, so we're talking about many millions of hits and users. Spring and Hibernate have similar success stories I'm sure.
Another error
2005-07-30 14:15:22 einer
[Reply | View]
I believe the build.properties file is in the directory where the recipe app was generated, not the directory where Trails itself was unzipped.
Another error
2005-07-31 09:49:05 ccnelson
[Reply | View]
Yes, you're right here too. I should have said "the directory where you created the application".
Quick bug report
2005-07-30 14:09:48 einer
[Reply | View]
The article says to use the command "ant create-new-project" but the "create-new-project" target doesn't exist in the build.xml file. I assume "ant create-project" was meant?
How about using BeanShell for creating model classes?
2005-07-17 19:12:17 acidblue
[Reply | View]
I was just thinking that using something like the BeanShell would be pretty cool for creating the domain objects. The would give us the ability to write less code, and "compete" with other scripting based laguages for < lines of code.
Is something like this possible? Well, I am definately sure that it is, but would people be interested?
How about using BeanShell for creating model classes?
2006-04-11 13:00:55 furashgf
[Reply | View]
I'm a big fan of beanshell. I think it would be a good idea and a good fit for this specific project. Trails is still java, as is beanshell (in spirit, at least).
How about using BeanShell for creating model classes?
2005-07-17 20:01:30 ccnelson
[Reply | View]
The thing that might make using a scripting language more difficult is persisting these domain object via HIbernate. The use of Hibernate annotations means we can map our domain model without have to go monkey with XML files. With a scripting language that doesn't have annotations we need to find another way. We also may have issues if these objects are not "real" java objects. Hibernate would need to know how to persist them.
That´s what I was looking for.
2005-07-12 09:19:08 jhvaranda1
[Reply | View]
Man, great job!!!
I´m already using Tapestry + Spring + Hibernate and now you,ve made things much faster!!!
I really would like to contribute to this project!
Cheers,
JH
date field
2005-07-06 13:41:20 wkinney
[Reply | View]
why is the date field auto entered as 10 Jun 2005?? not MM/DD/YYYY, YYYY-MM-DD, etc??? My only concern is people wanting to enter the date manually...or does it accept multiple formats
Where do you put your business logic?
2005-06-27 11:02:56 kadrianus
[Reply | View]
One think I couldn't understand after being watching the video and following the tutorial:
Where resides the business logic of your model in Trails? I know that this is not a Rails port to Java...but just only to make a comparision: In Rails you have conttrollers...Are there any similar concept in Trails?...
Sorry about the previous accidental post :)
Where do you put your business logic?
2005-06-27 11:23:01 ccnelson
[Reply | View]
Well, ideally, you put your business logic in your domain model. That's one of the fundamental tenets of DDD. But I don't think that really answers your question. If the question is, "what is the analogue to Rails controllers?", then I would say Tapestry pages are the answer. Tapestry page objects allow you to have methods invoked from your buttons and links (and this will get even easier with Tapestry 4.0) like controllers (as I dimly understand them). I would say in most cases you would want pages to delegate to domain objects to do the real work, but that is a design decision.
Where do you put your business logic?
2005-07-07 02:49:14 okamps
[Reply | View]
Well, that very much depends on what exactly you mean by domain model. DDD certainly does not advocate putting all your business logic on (persistent) domain objects (entities), but explicitly acknowledges the notion of a service.
This a-domain-object-is-a-web-page-is-a-database-table approach might work well with relatively small applications. However, I have some difficulties to see this work with complex domain object models (as in lots of classes, lots of associations, non-trivial interactions and constraints), which is exactly the kind of applications where you'd favor a domain model over alternate approaches (eg transaction script, see Fowler's PoEEA).
Kind regards,
Oliver
Where do you put your business logic?
2005-07-15 00:40:20 banq
[Reply | View]
I agree you, domain model must be separate from business logic, buiness logic should in service layer, here there is another framework like trails (DDD):
http://jdon.sf.net/
in jdon framework , there are two kinds codes:domain object or service; no action; no spring's "ref=" configure.
in this project ,there are a few samples include jpetstore with jdon
Where do you put your business logic?
2005-07-07 07:14:29 ccnelson
[Reply | View]
While it is certainly possible to have type specific services in Trails, I'm going to disagree with your argument that domain objects aren't the place for business logic in complex applications. They are exactly the right place, IMO. I am currently working in my day job on a very large system which has taken this approach, and it has enabled us to cope with complexity very well. We do have services in our application, but as it evolves we find ourselves taking more logic out of our service layer and putting it in our domain objects, not the other way around.
DDD as I am using it is just a new fangled term for OOP. I'm trying to lead us back to the idea of having our data and our logic together again in these handy dandy things called objects.
Where do you put your business logic?
2005-06-27 11:01:12 kadrianus
[Reply | View]
One think I couldn't understand after being wataching the video and following the tutorial:
Where resuines the business logic of your model in tails? I know that this is not a Rails port to Java...but just only to make a comparision, In Rails you have conttrollers...Are there ani similar concept in Trails?...
I have been generating basic forms from data tables for years, but eventually you need customized pages anyway.
I guess my point is that generating presentation from Value Objects is worthless as the final presentation. Although, it is nice to have something you can work with quickly.
I am moving towards MDA to simplify things in the long run.
one potential drawback is the need to learn yet another framework (Tapestry) to add basic functionality such as user authentication... I'm still trying to digest chapt 10 of Tapestry in Action and honestly, that's no fun :-(
This sounds quite good, really.
I just wonder about the mentioned topic. Are this features yet included? Or do the labels equal the field names of a POJO?
How much effort is it to modify the JSP / whatever you use to build the HTML?
Or exchange some of the underlying componentes, like some JDO technology instead of Hibernate?
Right now the label is the name of field, uncamelcased, eg, firstName becomes First Name. You can overrride this with annotations (discussed in next installment). i18N is not yet included, but should be possible by leveraging Tapestry which includes this. Tapestry HTML templates are what is used and would be customized. I will discuss how to do this in the next installment, but suffice to say you can customize your pages to your heart's content.
--Chris
It's about time
2005-06-23 13:43:26 dog
[Reply | View]
It's about time someone came along to simplify the mess we have to deal with.
The domain code of an app should be a complete different dimension than the framework.
I must say, this looks incredibly promising. It's been very hard to justify all the extra work to do webapps in java - we went from having to write lots of code, to still having to write a lot of code but then mixing in painful XML files. If Tiles turns out to be as easy as this article makes it look, and if it still allows easy MVC seperation, then it might really be something to combat the naysayers.