July 28, 1998 - Jack Harich - Document Map
There are two types of parameters: those for container nodes and those for worker (Bean) nodes. Below is an example of a typical system root node. This one is for the server system of a 3 tier application.
Container parameters are used to define and "lightly" configure their members. Heaver configuration is done by parameters per member.
Note the Primordial Invocations at the bottom. These are invoked when the node is started. Since this is a system root node, datastore.start() starts the entire system after the BA has initialized the root container members.
All systems have the equivalent of a root container that initializes and starts the system. Most systems have the equivalent of sub-containers that initialize and start subsystems. The advantage of the BA is this is standardized and resuable. This gives a team tremendous infrastructure and built-in discipline.
// _Container.parex - DataServer root
this_Item has:
IsContainer is: true
End: this_Item
//========== ItemDefs ==============================
datastore_Item has:
BeanClassName is: org.jcon.df.Datastore
// The alias should use the preferred database, which is
// ATSDR_SybaseProduction or ATSDR_LocalAccessProduction
Config hasLines:
setDatabaseFactory(org.jcon.df.DatabaseFactory databaseFactory)
addDatabaseNameAlias("atsdr", "ATSDR_LocalAccessProduction")
End: Config
End: datastore_Item
databaseFactory_Item has:
BeanClassName is: org.jcon.df.DatabaseFactory
ParamMarkerItemName is: this
ParamFileName is: DatabaseFactory.parex
Config hasLines:
setSchemaMgr(org.jcon.df.SchemaMgr $schemaMgr)
setConnectorMgr(org.jcon.df.ConnectorMgr connectorMgr)
End: Config
End: databaseFactory_Item
connectorMgr_Item has:
BeanClassName is: org.jcon.df.ConnectorMgr
End: connectorMgr_Item
translatorTypes_Item has:
IsContainer is: true
End: translatorTypes_Item
schemaMgr_Item has:
BeanClassName is: org.jcon.df.SchemaMgr
IsContainer is: true
End: schemaMgr_Item
// Root getting too large, need to put this in child node
problemHandler_Item has:
BeanClassName is: org.jcon.util.log.ProblemHandler
Config hasLines:
setMarkerClass("gov.cdc.atsdr.server.DataServer")
setResource("ProblemLog.txt")
setDisplayProblem(true)
hookupToGenLib()
End: Config
End: problemHandler_Item
//========== Primordial ============================
PrimordialInvocations hasLines:
datastore.start()
End: PrimordialInvocations
|
Below is a smaller container "param". Param is the internal class name for the data structure that parameter text is converted to. Note the preponderance of event links. This is typical. As system size grows the number of event links gets quite large, but diminishes when ContainerServices are used.
This is the param for the node in the Bean Assembler that handles the visual System Tree.
// _Container.parex - The tree module
this_Item has:
IsContainer is: true
Config hasLines:
this.addMessageListener("TreeOpened", ML treeMgr)
this.addMessageListener("CloseAllTrees", ML treeMgr)
this.addMessageListener("ParamApplied", ML treeMgr)
End: Config
End: this_Item
//========== ItemDefs ==============================
eventRouter_Item has:
BeanClassName is: org.jcon.ba.system.router.EventRouterBIP
Config hasLines:
provideListener("org.jcon.ba.tree.ItemTreeListenerProxy", Object treeMgr)
End: Config
End: eventRouter_Item
treeMgr_Item has:
BeanClassName is: org.jcon.ba.tree.TreeMgr
Config hasLines:
addMessageListener("EditParam", ML this)
addMessageListener("GroupClosed", ML this)
addMessageListener("EditModule", ML this)
addMessageListener("InspectItem", ML this)
addMessageListener("ItemSelected", ML this)
End: Config
End: treeMgr_Item
//========== Primordial ============================
PrimordialInvocations hasLines:
End: PrimordialInvocations
|
Below is the a worker param used to define how the Data Framework maps logical datatypes to Sybase's native datatypes. Other params define other database types, such as Access, Oracle, Informax, etc. This example shows how well designed parameters can play powerful roles in system design. The objective of this param's design was to allow database independence.
// TranslatorTypeSybase.parex - for TranslatorType // Name is: Sybase AutomaticTimeStamp is: true // // Nulls not allowed by default so return indicator NullAllowed is: null // // "Format" or exact value such as "NULL" NullDateValue is: Format // // Values are ColumnDefType, DatabaseDatatype, FormatPrefix, // and FormatSuffix ColumnDefTypes hasLines: MID, money, $, None TimeStamp, timestamp, None, None String, varchar(254), ', ' Mask, varchar(254), ', ' Code, varchar(254), ', ' Integer, int, None, None Boolean, bit, None, None Memo, text, ', ' Date, smalldatetime, ', ' Year, int, None, None Money, money, $, None End: ColumnDefTypes
Below is the UserSys entity param. Note the ease with which we can express what to do. The param is very readable, even by those who have never seen it before. One goal of the Param Engine was to allow non-programmers to easily edit raw parameter text.
Note the "Type" key/value. These are the logical datatypes, such as String, that are used in the above param to map logical to native datatypes. The Data Framework exposes only logical datatypes to business objects.
// The UserSys entity. Represents a person who is allowed // to use the system. "UserSys" chosen for name since // "User" is a Sybase reserved word. // @author Jack Harich Name is: UserSys UniqueIndexes hasLines: UserID End: UniqueIndexes DescriptionColumnNames is: LastName, FirstName EntityListener is: gov.cdc.atsdr.server.EntityValidator Columns has: UserID has: Type is: String MaxLength is: 10 Required is: true UpperCase is: true End: UserID Password has: Type is: String MaxLength is: 10 Required is: true End: Password AdminCode has: Type is: String DisplayName is: Admin Code MaxLength is: 7 Required is: true UpperCase is: true End: AdminCode IsAdmin has: Type is: Boolean DisplayName is: Is Admin Required is: true Default is: false End: IsAdmin SSN has: Type is: Mask Mask is: 999-99-9999 End: SSN FirstName has: Type is: String DisplayName is: First Name MaxLength is: 20 Required is: true UpperCase is: true End: FirstName MiddleInitial has: Type is: String DisplayName is: Initial MaxLength is: 1 UpperCase is: true End: MiddleInitial LastName has: Type is: String DisplayName is: Last Name MaxLength is: 20 Required is: true UpperCase is: true End: LastName LastLogon has: Type is: Date DisplayName is: Last Logon Date Required is: true End: LastLogon UserProfileMID has: Type is: MID DisplayName is: User Profile LinkEntityName is: UserProfile End: UserProfileMID End: Columns
That's the basics of text parameters. Once you have lots of them additional infrastructure is needed.
Suppose deep in a Param you have a value that varies. We call this a setting. An example is the current fiscal year, which is used by a number of components to filter data. We handle this by replacing the setting when the Param is used. For example:
FilterLine is: FiscalYear = [[Awards.CurrentFiscalYear]]Would after replacement become:
FilterLine is: FiscalYear = 1997Settings can be modified at runtime by the user. The next time a parameter using that setting is used, the new setting value is used.
Suppose you want to reuse an entire system and change a bunch of parameter values. The BA comes with a reusable approach to this that is, guess what, parameter driven. An example would be too long to put here. What you do is define via parameters what you wish to change, and then run ConfigParameters.
As you can see, parameters can express a wide variety of behavioral reguirements. While the above examples are oriented toward editing a relational database, parameters can handle other domains just as well. We have merely chosen the Data Framework, which is built on top of the Bean Assembler, as the first serious use of the BA since so many apps are database apps.
A really cool aspect of parameters is they are language independent, with the small exception of embedded class names. They are also implementation independent, which decouples the "what" from the "how". Thus a single system can use different reusables and a single param to, for example, have a system behave differently depending on user skill level. This is much harder with other approaches.
And now we move into the controversial. Parameters are a much better approach to specialization than inheritance over 50% of the time. Enough said.