[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