Most importantly it achieves the seperation of business logic from the front end development by providing
default front ends which are dynamically rendered depending on the user permissions. This means that unless
a bespoke front end is required, ALL the development is on coding the business requirements.
Mai Arch is short for Mai
TechnologyArchitecture. It is the application framework developed and used by
Mai Technology.
The framework provices for a set of object
independent components which negate the need for initial front end development.
Provided business objects are coded according
to these guidelines then the MaiArch gui components and struts components with
handle them correctly.
Beans representing business objects implement the MaiArch.j2ee.EntityBean
interface. See appendix A for the interface listing.
This interface corresponds closely with the j2ee standard
Entity Bean interface.
Optional methods are methods which are searched for in a
bean by various components of TrackII but which are optional. They are not
enforced through an interface, but instead the calling objects will search for
them with introspection.
Instantiates the specified bean. Throws and exception if the
bean cannot be found in the database.
Returns a string array of vectors which should be expanded
on the BeanDisplayPanel. If a vector
is not in this list but has a get / set method pair then the vector is simply
displayed in the bean display panel with its name and item count. The user can
drill down into this vector using the F1 key, at which point the vector is
opened in a BeanVectorPanel. If the
vector is in this list then the BeanVectorPanel
is created and added to the BeanDisplayPanel
so that it is all viewed on 1 screen.
e.g. in StockItem
public static final String[]
getVectorsToExpand (){
return new String[] {"vectSubItems"};
}
Beans are searched for using a standard search panel BeanLookupPanel which looks at the
primary table for the bean and allows searching whilst limiting the number of
records returned from the table. The returned string array should consist of 3
fields,
the primary table, the primary field which is used by ejbFindByPrimaryKey and any additional
fields which should be shown during the search.
e.g. in StockItem
//returns table information for quick lookups
public static final String[] getQuickLookup()
{return new String[] { "tblSKU", "txtID",
"txtDescription,txtCategory" };
}
Returns a vector of strings listing the primary tables for
this bean. The user can then view the tables directly. This table access is
through the bean display panel using CTRL T. This table list will expand with
subclasses.
e.g. in StockItem
public Vector getTables()
{
if(vectTables == null)
{
vectTables = new Vector(1,1);
//add any constraints here in the future
vectTables.addElement("tblCategory");
}
return vectTables;
}
e.g the Memory
bean which is subclassed from StockItem
public Vector getTables()
{
if(vectTables != null)
return vectTables;
super.getTables();
//add any constraints here in the future
vectTables.addElement("tblMemory");
vectTables.addElement("tblMemoryType");
return vectTables;
}
The field constraints are listing of foreign keys for use in
constrained fields. These constraints are used by the BeanDisplayPanel and BeanTable
objects which display the constrained fields as drop down boxes and do not
allow the user to type in their own values.
A field constraint is defined by the field of the object
which it applies to, and a SQL string which returns a data pair of the value to
be placed in a field and also the visible value for the drop down box.
e.g the StockItem
bean
public Vector getFieldConstraints()
{
if(vectFieldConstraints == null)
{
vectFieldConstraints = new Vector(1,1);
try{vectFieldConstraints.addElement(new
FieldConstraint("txtCategory",
"SELECT txtCategory, txtDescription FROM tblCategory
ORDER BY txtDescription"));
}
catch(Exception e)
{MW.utils.HandleException (e,MW.App.errFileName , "
Memory.getFieldConstraints");
}
}
return vectFieldConstraints;
}
SubClassed beans simply continue adding their constrained
fields to the vectFieldConstraints.
e.g. the MemoryBean
public Vector getFieldConstraints()
{
if(vectFieldConstraints != null) //this has already been initialised so just return
return vectFieldConstraints;
super.getFieldConstraints();
try{vectFieldConstraints.addElement(new
FieldConstraint("txtType",
"SELECT txtType, txtDescription FROM
tblMemoryType"));
}
catch(Exception e)
{MW.utils.HandleException (e,MW.App.errFileName , "
Memory.getFieldConstraints");
}
return vectFieldConstraints;
}
public static final String getDefaultWorkflow()
Returns the default workflow name for this object. The
StatePanel will originally populate with the state history from this workflow.
If there is only one start state for this object then the
Object will go through this state transition automatically.
{return InternalRequestRaisingWorkflow.IR_RAISING;
}
Database access is performed through a global
database connection held in MediaTools.System.
This is configured at the startup of the program. Concurrency issues are not
addressed through the beans. This means that many people can have access to the
same business objects. Locking is performed through means of a lock table tblLock which is controlled through the
BeanDisplayPanel and the BeanTable objects.
N.B. the global database access can be a
connection pool.
A Bean Action is an piece of functionality
which operates on a bean. It is separated from the actual bean class itself as
it may involve GUI action which would make it incompatible with the j2ee model.
A Bean Action class must have a class name
like it’s target bean followed by ‘Action***’ where *** is the unique action
name, and exist in the same package as the target bean. A Bean action class
only has one target bean associated with it although once the action is started
it can do anything with any number of beans.
For example the MediaTools.Contact.User class has and ActionClass called UserActionClonePermissions associated
with it which acts upon it.
This naming is necessary because the
MediaTools GUI looks for permissions with this name relationship when it is
deciding what actions a user may perform on a bean.
Bean Actions implement the following
interface which is in the MediaTools.Infrastructure package:
package MaiArch.Infrastructure;
public interface BeanAction {
public String
getDescription();
public String
getButtonDescription();
public Object doAction(Object
c,Object bean) throws Exception;
public void
repeatAction(Object c,Object bean) throws Exception;
public void cleanup(Object c)
throws Exception;
}
getDescription()
and getButtonDescription() are used
in the popup menus for selecting an action. doAction() is performed on an object if 1 object has been selected
to have this action performed on it. repeatAction()
is performed for all subsequent actions if more than 1 object has been selected
to have this action performed on it.
It is possible to select more than 1 object
both in the BeanTable and SQLTable classes. For example in the UserActionClonePermissions class doAction() requires the user to specify
a source User bean. If this action is
perfomed on many Users then repeatAction() uses same User for any subsequent permission cloning. – crap example – due to
the fact it is on User – but the only one I can give at the mo!!
N.B. In essence this corresponds to the
SessionBean of the j2ee model with the addition of GUI awareness.
Struts considerations
Actions which additionally inplement the
struts bean action interface will appear in the permissions driven drop down
many on the struts site. The interface is as follows
public interface
StrutsBeanAction {
public ActionForward
initialise(ActionMapping mapping,
ActionForm form,
HttpServletRequest
request,
HttpServletResponse
response) throws Exception;
public ActionForward
process(ActionMapping mapping,
ActionForm form,
HttpServletRequest
request,
HttpServletResponse response) throws Exception;
}
The initialise action is expected to
initialise the actionparamters vector in the formEntityBean e.g.
FormEntityBean fm = (FormEntityBean) form;
Vector vActionParameters = new Vector(2,2);
for(int i = 0; i < strutsParams.length; i++)
{vActionParameters.addElement(new
KeyValue(“emailText”,
“defaultValue”));
These parameters are rendered with input
controls on the action process page. The public ActionForward process method then retrieves the
ActionParameters to continue with the action.
Workflows
All permissions are defined through the ObjectPermission class whose primary data is held in
tblObjectPermission.
The object permissions are defined on a per user basis. Each
User has a parent User object. The object permissions are
first inherited from the parent user, and then overridden by the users own
permission. In this way a user’s permissions may be more than their parent’s
permission or less than their parents. In addition there is a UserLevel defined
for each user. These User Levels are uses to set certain options for the user.
For example an IT level user automatically creates new ObjectPermission objects if they are not defined with full access
to the system, whereas if any other user is looking for an ObjectPermission which is not defined it is created with no access
which then has to be edited by a user with permissions to edit them.
The ObjectPermissions affect the following areas of the
front end screens:
The field visibility sets the visibility of the field
exposed by the specified method for both BeanDisplayPanel
and BeanTable.
|
tblObjectPermission
Field
|
|
Example
|
|
txtClass
|
The Bean Class
|
MediaTools.Stock.CPU
|
|
txtField
|
The Access Method
|
setTxtWebCopy
|
All elements of the Utility menu are set with
entries in the tblObjectPermission.
These fields are accessed in the buildUtilityMenu method of MediaTools.Applications.Admin. Default
menu options do not have permissions set in this way but are visible to all
users.
|
tblObjectPermission
Field
|
Value
|
Example
|
|
txtClass
|
MaiArch.Infrastructure.Utility
|
MediaTools.Infrastructure.Utility
|
|
txtField
|
Classname
|
DBSwingPanels.UrlRequestPanel
|
Defines which users are permitted to perform which actions
on an object.
|
TblObjectPermission
Field
|
|
Example
|
|
txtClass
|
The Bean Class
|
MediaTools.State.User
|
|
txtField
|
The Action Class
|
MediaTools.State.UserActionCascadePermissions
|
Defines which users are permitted to perform which reports.
|
TblObjectPermission
Field
|
|
Example
|
|
txtClass
|
MediaTools.Report
|
MediaTools.Report
|
|
txtField
|
The Report file (*.mtr) or the report class
|
User.mtr
or
MIS.MISSalesByCustomer
|
Defines which users are permitted to use which state
transition.
|
TblObjectPermission
Field
|
Value
|
Example
|
|
txtClass
|
MediaTools.State.StateTransition
|
MediaTools.State.StateTransition
|
|
txtField
|
The start and end state ID with -> in between
|
7->4
|
package MaiArch.j2eestubs;
import java.util.Vector;
import MaiArch.State.User;
/**
* interface which corresponds to j2ee EntityBean interface
*/
public abstract interface EntityBean extends
java.io.Serializable
{
/**
* The following
methods correspond to the j2ee Entity Bean Interface
*/
void
setEntityContext(String p0) throws Exception;
void unsetEntityContext()
throws Exception;
void ejbRemove()
throws Exception;
void ejbActivate()
throws Exception;
void ejbPassivate()
throws Exception;
void ejbLoad()
throws Exception;
void ejbStore()
throws Exception;
/**
* The following
method ensures that a string unique ID is available. This is used for
* variouse GUI
components in displaying the bean.
*/
public String
getTxtID();
public void
setTxtID(String txtID) throws Exception;
public Vector
getFieldConstraints(Integer GUIType,String sourceField);
public void
ejbRecreate(MaiArch.DataAccess dest) throws Exception;
}