Blogs : Latest entries
|
|
| < Previous page |
|
RIFE has a unique approach towards validation which is centralized around bean instances and not bean classes. Instead of having an external validation service, each bean instance publishes meta data about its constraints. Every part of the system (validation, form generation, database structure creation, ...) will inspect the meta data and peruse it. Validation is an exception in that after inspecting the meta data, the results of the validation are contributed back for each specific bean instance as Instead of implementing a container that keeps track of all the mappings between bean instances, their meta data and the validation errors, I decided that each bean instance will actually hold this data into fields. However, since people generally dont want to pollute their bean classes with framework-specific constructs, I created the meta-data merging facility. This automatically looks for a class with the All this is very intuitive when you use it in practice and develop a database-backed website. RIFE's database layer doesn't use an entity container either but rather creates and populates new bean instances each time an entity is fetched from the database. This has the benefit of each thread having a dedicated version of the entity which can be manipulated without risking data races. Only when all the operations are finished, the entity is stored back into the database through an explicit save call. The code could be like this when editing an existing
User user = database.restore(userId);
fillSubmissionBean(user);
if (((Validated)user).validate()) {
database.save(user);
template.setBlock("content", "success");
} else {
generateForm(template, user);
}
print(template);However, when using Terracotta (or something else, like a cache), you typically don't want every entity to go back to the database. Instead, you want to keep them in memory and only store certain parts into the database. So instead of having a database manager, you have some kind of in-memory service that is able to find and store entities. Intuitively and naively you would replace the code above with the following broken code: // this code is broken, read below to know why
User user = service.findById(userId);
fillSubmissionBean(user);
if (((Validated)user).validate()) {
service.store(user);
template.setBlock("content", "success");
} else {
generateForm(template, user);
}
print(template);The problem relies in the fact that each and every thread will be working with the same instance of the So, instead of retrieving the user from the service to modify it with possibly invalid data, you want to create a new instance of the entity that will be in local scope until the validation has succeeded. Only then you want to store it back into the service. This guarantees that your data is always correct and also allows perfectly concurrent access on users with the same identifier. The correct code would thus be:
User user = getSubmissionBean(User.class);
user.setId(userId);
if (((Validated)user).validate()) {
service.store(user);
template.setBlock("content", "success");
} else {
generateForm(template, user);
}
print(template);This had me scratching my head when I was bitten by the broken code above. However, if you think about it, it's perfectly logical. Working with in-memory containers is fundamentally different from working with relational database, where your data is stored independently from the actual objects that you're using. You have to remember that an in-memory container is a store too, and you don't want invalid or intermediate results to end up in there. However, this is what you risk to happen when you directly manipulate the fields of the instances that are already in the in-memory container ... but it's oh so tempting to do! |
|
Joshua Hansen wrote a nice example of how to create custom meta data constraints and display dedicated validation error messages with RIFE. He also shows how easy it is to make RIFE/Crud display your validation errors for beans that use your custom constraints. |
|
In case you want to learn more about RIFE, ask questions, chat a bit about what you've done, share experiences, etc., feel free to come the the BOF tonight that I'm organizing during the QCon conference in San Francisco. You can find all the details here:
http://qcon.infoq.com/sanfrancisco/conference/ The address is: Westin San Francisco Market Street 50 Third Street San Francisco California 94103 The BOF will be from 8:30pm - 9:30pm in the 'City' room. We are also organizing a Terracotta BOF right before it, so if you're interested in that, you can come from 7:30pm - 8:30pm to the 'Stanford' room. See you there! |
|
I'm speaking at NFJS in London at the end of this month about RIFE and Terracotta. You can find the abstract of my session quoted below. The schedule looks very interesting and I'm excited that NFJS is finally taking place in Europe too. If you're interested in going, you might want to click on the banner to the right or to use the promotion code NFJS-RIF660. This will give you a free Nintendo Wii with your registration (woohooo, I love my Wii!). See you at NFJS Europe. I also have another session about Terracotta in the real-world.
|
|
In this article, Jonas Bonér and me discuss how the RIFE Web framework helps you become productive and efficient in building conversational Web applications. Productivity with RIFE is in large part due to RIFE's unique approach to Web development—its use of continuations for conversational logic, and complete integration of meta-programming to minimize boilerplate code. We also introduce you to Terracotta and it's JVM-level clustering technology, and show you how Terracotta and RIFE can work together to create an application stack that allows you to scale out and ensure high-availability for your applications, but without sacrificing simplicity and productivity. This means working with POJOs, and minimal boilerplate and infrastructure code. You can read it at Artima. |
| < Previous page |


