[Yanel-dev] Usecase Framework
Josias Thöny
josias.thoeny at wyona.com
Mon Apr 2 23:25:19 CEST 2007
Hi all,
I have experimented with a resource-based usecase framework prototype,
and I would like to show how it works with two examples: list all users
and create a new user.
The framework follows the MVC pattern, whereas the model is (in this
example) the user framework, the view is a jelly view template (see
[1]), and the controller is a simple java class which implements the
Usecase interface.
There is a config file (the resource configuration) which connects those
elements.
1. List users
There is a resource of type "usecase" at the url /usecases/listusers
It's rc file contains a class attribute (for the controller class) and a
view configuration:
<yanel:rti name="usecase"
namespace="http://www.wyona.org/yanel/resource/1.0"/>
<yanel:property name="class"
value="org.wyona.yanel.impl.usecases.ListUsers"/>
<yanel:custom-config>
<views>
<view id="default" type="jelly">
<template>/usecases/test/listusers.jelly</template>
</view>
</views>
</yanel:custom-config>
The controller class ListUsers implements the Usecase interface and
looks as follows:
public class ListUsers extends AbstractUsecase {
public User[] getUsers() throws UsecaseException {
UserManager userManager =
getRealm().getIdentityManager().getUserManager();
try {
return userManager.getUsers();
} catch (AccessManagementException e) {
throw new UsecaseException(e.toString(), e);
}
}
}
And the jelly view template:
<j:jelly xmlns:j="jelly:core">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h1>Users</h1>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
</tr>
<j:forEach var="user" items="${usecase.getUsers()}">
<tr>
<td>${user.getID()}</td>
<td>${user.getName()}</td>
<td>${user.getEmail()}</td>
</tr>
</j:forEach>
</table>
</body>
</html>
</j:jelly>
That's all we need for the listusers usecase, the framework will take
care of all the rest.
This is a very simple usecase because it does not really do anything.
Usecases which execute some kind of action may implement the
ExecutableUsecase interface.
A executable usecase must provide three different views: "default",
"done", and "cancel". See the second example:
2. Create new user:
View config:
<views>
<view id="default" type="jelly">
<template>/usecases/test/createuser.jelly</template>
</view>
<view id="done" type="jelly">
<template>/usecases/test/createuser-done.jelly</template>
</view>
<view id="cancel" type="jelly">
<template>/usecases/test/createuser-cancel.jelly</template>
</view>
</views>
Java class (simplified):
public class CreateUser {
public void execute() {
String id = getParameterAsString("userID");
String name = getParameterAsString("name");
String email = getParameterAsString("email");
String password = getParameterAsString("password1");
userManager.createUser(id, name, email, password);
}
public boolean checkPreconditions() {
String id = getParameterAsString("userID");
if (id == null || id.length()==0) {
this.addError("Please enter a user ID.");
return false;
}
// TODO: check other params
return true;
}
}
and the main jelly template:
<j:jelly xmlns:j="jelly:core">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h1>Create User</h1>
<p>${usecase.getErrorMessages()}</p>
<form action="">
User ID: <input type="text" name="userID"
value="${usecase.getParameterAsString('userID')}"/>
<br/>
Name: <input type="text" name="name"
value="${usecase.getParameterAsString('name')}"/>
<br/>
Email: <input type="text" name="email"
value="${usecase.getParameterAsString('email')}"/>
<br/>
Password: <input type="password" name="password1"/>
<br/>
Password: <input type="password" name="password2"/>
<br/>
<input type="submit" name="submit" value="Ok"/>
<input type="submit" name="cancel" value="Cancel"/>
</form>
</body>
</html>
</j:jelly>
The usecase framework will first show the default view (the form) and if
the user clicks submit, it will show the "done" view as a confirmation
screen. If the user cancels, the "cancel" view will be shown.
The views in the example are all of type "jelly". Other possible types
are "redirect" and "custom".
One also could implement a more complicated "workflow", e.g. with
multiple usecase steps.
Basically this stuff is working, but there are a few problems/open
questions:
- There has to be a .rc file in the repository for each usecase, and the
jelly templates are stored in the repository, too. This means that this
stuff has to copied into each realm where someone wants to use it.
Well, the jelly templates could be stored in the directory of a
resource, but then they cannot be overridden in a realm.
- Build process: it's not clear where to put the java usecase classes
and how to resolve their dependencies. For my tests I put them all into
the usecase resource.
- The Usecase interface is not that different from the Resource class.
Basically both provide a view. Maybe this could be unified somehow, but
I currently don't see how it could be done.
I've been thinking about ditching the Usecase interface and just use
resources. But somehow it doesn't quite seem to fit together.
What I would like to avoid is having to create a new resource type for
every single usecase like "list users", "create user", "delete user",
"edit user profile", etc.
Any suggestions how to solve these problems are highly appreciated.
In the attachment there is the current prototype of the usecase
resource, if anybody wants to have a closer look.
Josias
[1] http://jakarta.apache.org/commons/jelly/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: usecase-resource.zip
Type: application/zip
Size: 16210 bytes
Desc: not available
Url : http://wyona.com/pipermail/yanel-development/attachments/20070402/05d74e9d/usecase-resource-0001.zip
More information about the Yanel-development
mailing list