Wednesday, November 13, 2013

Designing a “modular” web application

Background

I would like to separate functionality for a web application into separate jar-modules and include these in a war project.
The purpose for this is to separate development and deployment, that is, to develop functionality separately and include it in the war-packaging and it should automatically be usable with templates, menues etc.
Sorry if the code don't display so well. But putting codes with Generics is not so well handled by Bloggers editor, so until I have time to fix it you will have to live with it ;) and I will use [] instead of <>


Structure

To make it modular it is nescessary to have some common code (placed in “common-web”). The structure for this is basically:

  • common-web: will contain code common to modules and web-applications.
    • templates: for reuse in different modules, basic templates is put in a common module.
    • login: (out of scope, will not implement login in this example) for reuse of login-form etc. i.e. the same files and functionality applies to all web-applications that uses login.
    • resources: common css and images is placed to be reused.
    • menu: functionality to assemble n menu(es) from m modules so they will present in web-applications no matter in what module a page is used.
    • common code: code for hoding and generating menu(es), common utility code for JSF, ManagedBeans etc.
  • war: web-project with war-packaging that will use modules.
  • webmoduleA..X: functional parts that implement a function or group af functions that logically belong together.
    • as an example I will implement at “todo-webmodule” in a PoC to show the functionality.


Menu

Basic functionality for menu is placed in common-web.

What am I trying to solve here?

A module can have different kind of needs, to access parts of its functionality we need a menu with 1 or more items (even if a module can be without menu, for example common-web may not need one, even if it is also a kind of a module).


Requirements:
  • A menu sholud be able to present itself as a top-menu in a menubar
  • A menu should be able to present itself as a part of another menu (i.e. not on toplevel) but in another menu.
  • Should be able to order children of a node.
  • Support to up to 4 levels of menues (more level will not be displayed)


Assumptions:
  • If a menu has no children it should have an action attached (=no expression needed)
  • If a menu has children, it has no action attatched to it.(=no expression needed)
  • Only SubMenus can be placed, not single menues (MenuItem). And they can only be placed in other SubMenus.



Placement:
“/” is root, putting menues under “/” would put them in top menubar.
Take as an example; you have 3 top menus (Admin, Project, Help). These should all be placed under “/”


Further, say we want to capture this endresult for menues.
  • /
    • admin
      • add user
      • list users
    • project
      • add project
      • list projects
      • issues
        • add issue
        • list issues
    • help
      • about


/admin
/admin/add user
/admin/list users
/project
/project/add project
/project/list projects
/project/issues
/help
/help/about

We have Issues under its own grouping and this should be inserted under project. (The reason behind this is that it may be developed in another module and we want to insert it under project in this application)

Ordering

When it comes to ordering, I want to speify an order on all levels. The purpose of this is that when adding top menues dynamically I do not know which order they will appear, hence it is usefull to be able to define it on top-level.
Another purpose is, that since it is possible to insert a menu into another, this may disturb the order or we want the inserted menu group to in another position than it gets inserted to.

This solution for this is to sort all items alphabetically and then resort according to supplied ordering (which is allowed to just use the ones it wants to sort in from start)

Solution

Model



Description


I will describe the solution by taking my example project on bitbucket as an example.
The example project (on bitbucket) have the following structure:


In this example the only “working” code for a MenuGroup that I will implement is the TODO-functionality, and of course the supporting code to have it modular. As goes for the concept of menus I will add a couple of MenuGroups undermodule-web itself. (Do not be surprised if the code here differs from the one on bitbucket, because there may be improvements done in the real code.). There is also mockup code to add the menues as described above to get more than one menu.


To have a menu for “Todo”, the following code will give me that as a “MenuGroup”





To have it modular and generate modules, this is done by having the menu.xhtml and supporting classes in common-web. The most important are MenuBean (that assemble the menu for the view), MenuAssembler (that assembles a menu for MenuBean from the groups it is provided)


To get menu groups aswell as config of orderings and placement from other modules, a bit of CDI is used.




Since we do not know which MenuGroups will exist when developing common code, we inject any type in an Instance. The view will call getMenus() tha if empty will try to assemble the menu. The placement and ordering should be provided from outside aswell, not hardcoded as in this case.


The order we do this is:

  1. add MenuGroups
  2. add rules
    1. placement and/or ordering (defined in a WebMenuConfig implementation)
  3. call assemble()


The last call will assemble the menu and return a list of the top menus. These menus will after returning be rendered in the view.


The implementation of the WebMenuConfig in this case is defined like this:




This will give a menu that looks like:









No comments:

Post a Comment