Document last updated 26 December 2001.
Return to the generated Javadoc for this
In the Oreo Data API, every record type has an associated
metadata object that implements the interface
This object, in turn, contains one or more FieldDescriptor
objects that represent the restrictions on a record's fields. Concrete implementations
of these API's are in the org.oreodata.metadata
package. It will be extremely rare for an application programmer to actually instantiate
any of these objects in java code. They will be specified in an external
configuration file in XML and the necessary instantiations will occur within the
underlying application framework (such as Niggle) on startup.
There are 2 basic kinds of metadata that will be specified: record metadata (this includes the fields) and data source metadata.
I shall assume that your record metadata file is called recorddefs.xml. The $NIGGLEROOT/src/org/oreodata/metadata/recorddefs.dtd contains the document type definition (DTD) for the record metadata. It is not terribly complicated. The root element is called RECORDDEFS, which contains one or more RECORD elements.
The RECORD element has various attributes you can use to configure certain things. Two are required: TYPE and PRIMARY_KEY. The TYPE attribute indicates the lookup name for the record type that the singleton DataRegistry object will use. The PRIMARY_KEY attribute indicates the field which is to be the primary key field of this record. Note that the Oreo semantics are that the combination of the record type and primary key value should serve to uniquely identify a record.
<RECORD TYPE="order_entry" PRIMARY_KEY="unique_id" >
Three other attributes that you may want to use are:
The first of the attributes above is used by the JDBC bridge code to find out the name of the table in the database that this data lives in. If this is not specified, this is simply assumed to be the same as the TYPE attribute. The CLASS attribute specifies the java class that is used to represent this record on the java layer. It must be something that implements Oreo's Record interface. If you do not specify this, it will simply use the default implementation, which is: DefaultRecord class. The PRESENTATION_CLASS attribute can specify a java class to use as a "presentation wrapper" to display this record.
You can optionally specify some PROPERTY elements within a RECORD element. This is actually not being used currently, but provides an implementor a hook to put some application-specific info here. This is in the form of:
<PROPERTY KEY="key" VALUE="value" />
Your app can get at them via the getProperty() hook.
You can also put in one or more BASEREC elements that allow you to say that this record has all the fields in a given RECORD and then some.
<BASEREC NAME="order_entry" />
For example, a BASEREC element as above might be included in a record of type "special_order_entry" if, for example, a special_order_entry record has all the fields of an order_entry record and then some. Basically, this is a disposition that mirrors the kind of crude inheritance that the relational model provides.
Then you define your fields. At least one FIELD element is obligatory, since every record must have at least a primary key field. You can define various attributes in a FIELD element, but only 2 of them are required.
<FIELD CLASS="&STRING;" NAME="city">
The &STRING; is actually an XML entity, i.e. an alias for readability. If you look in the recorddefs.dtd file, you will see that this is actually defined as being: org.oreodata.metadata.StringField. We could perfectly well have written:
<FIELD CLASS="org.oreodata.metadata.StringField" NAME="city">
but the first way is more readable. If you are using an RDBMS, you may want to specify a SQL_TYPE attribute to indicate the exact SQL type that this is. This is useful in particular if the table is to be automatically generated.
Different classes will use different properties that are specified within PROPERTY elements. For example, the StringField allows you to specify MIN_LENGTH and MAX_LENGTH.
Within a FIELD element, you can also specify some NORMALIZE elements which indicate some canonical cleanups that should happen when reading this value from a user interface. This is convenient, for example, if you want to treat the strings "Smith ", "Smith" and "SMITH" as being the same.
There is also the possibility of specifying a Perl 5 regular expression to validate against. This only works for StringField or subclasses of StringField. Here is an example:
The FORMAT element is only used by the DateField currently. It allows you to set a default storage format for date/time strings. This follows the conventions in the java.text.SimpleDateFormat class.
You can specify a foreign key relationship like so:
<FIELD CLASS="&FOREIGN_KEY;" NAME="customer_id"> <PROPERTY KEY="DATA_SOURCE" VALUE="customers" /> <PROPERTY KEY="RECORD_TYPE" VALUE="customer" /> <PROPERTY KEY="JAVA_TYPE" VALUE="Integer" /> </FIELD>
In the above, we specify a foreign key field called "customer_id". This refers to a record of type "customer", which lives in a data source named "customers". By convention, in OREO, a foreign key ends with "_id". Thus, when you call order.get("customer") the system tries to pull out the record that the customer_id field refers to.
As of the version 1.1pre5, you can specify that field values be "interned".
You do this by adding the attribute
INTERN="Y" to the specification
of a FIELD element. This can lead to very great memory savings if, for example,
the field is usually one of only a handful of values.
You will specify your data source metadata in a separate file, typically called datasources.xml. This follows the DTD in NIGGLE_HOME/src/org/oreodata/metadata/datasources.dtd. This is actually simpler than the record metadata configuration. The root element is DATASOURCES which contains one or more DATASOURCE elements.
The required attributes of a DATASOURCE element are CLASS and NAME. The CLASS is the name of the concrete java class that you are using. The NAME is the lookup name of the data source object that the singleton DataRegistry object will use. You may optionally specify whether this data source should "preload". The default is yes, though there are some conditions under which lazy loading might be desirable. The last attribute LISTENS_TO is interesting. Assuming that the DataSource implements the DataListener interface, we ask whether this DataSource should listen to the events of one or more other ones. You can put in comma-separated names of other data sources here. Note that you cannot forward reference. If you mention another data source in there, it must be specified earlier in the XML file.
Really, all DataSource implementations are different, so this scheme relies on your specifying other things in PROPERTY elements. A typical sort of thing might be:
<PROPERTY KEY="JDBC_DRIVER_CLASS" VALUE="org.gjt.mm.mysql.Driver"/> <PROPERTY KEY="JDBC_URL" VALUE="jdbc:mysql://myhost.com/mydb?user=xxx&password=xxxx"/>
for a JDBC connection to a MySQL database. Other data source implementations will need entirely different properties to be specified. In other words, this is entirely implementation-defined, depending on the data source class you are using.
Your web application can also use remote references to a data source obtained by RMI lookup. Thus, the "real" underlying DataSource object can be in a different process or on an entirely different machine. This can be one approach to scalability issues. The configuration in your datasources.xml would look something like this.
<DATASOURCE CLASS="USE_RMI" NAME="users"> <PROPERTY KEY="RMI_URL" VALUE="rmi://other.mynet.com/myapp/entries"/> </DATASOURCE>
Of course, this also assumes that you have a process on the other machine that instantiated the data source and registered it in the RMI registry.
Note also that, by default, for various obscure technical reasons, the prebuilt jar files do not have the RMI support built in. You will have to rebuild with RMI support. The instructions are in the build.html.
This is a first draft of a document to specify the XML configuration files. Still, the best way to learn how to use this, is... by using them! If you note any inaccuracies in this document, or have any suggestions for improvement, please write me!