Q:I seem to be able to create db objects within other db objects with calls to new, rather than to createObject() but their behaviour seems erratic. Is this supposed to work or is it inadvisable?
A:Calling new does not create a database object. However, not all persistent classes have to be database classes. Any serializable class will work fine. A Car class may have a string member: name. This name object is persistent and will be stored in the database but it is not a database object because no other than the Car object can access it.
Q:Do all persistent objects need to be created by calling the no-parameter, no-body constructor? or can you call another constructor?
A:Yes you can call other constructors using something like the following:
db.createObject(ExampleImpl.class, String.class.getName() + "|" + "int", new Object[]{"hello", new Integer(23)});
Maybe someone can help and write some lines of code to generate the signature out of the parameter objects so we do not have to supply the signature in a String like this.
Q:What is the difference between creating objects from outside the db server and creating them from within the db server?
A:The result of both operations is the same. But creating a database object from another database object is much faster than from the client. And, if you are creating more than one objects at the same time, doing this inside a database method encloses all the create operations inside a transaction (without the need to explicitely mark transaction boundaries) which is most likely wanted.
Q:Am I right in thinking that if you create an object with database().createObject(), the constructor of myObject can't create other objects - I get an "object is not yet associated to a database container" exception.
A:Yes, you are right. Therefore, although it doesn't look that nice, an initialization method could be used.
A:Another way is to use the callback method onCreate() to get around this problem as this method is called after container association.
Example: public void onCreate() throws Exception { OzoneInterface ob = this.database(); this.address = (Address)ob.createObject(AddressImpl.class.getName()); this.employees = (People)ob.createObject(PeopleImpl.class.getName()); this.customers = (People)ob.createObject(PeopleImpl.class.getName()); }
A:Yes, onDelete() should be added to remove objects that are considered "Contained" by the object. In other words, no other objects should reference them. This will help the referencial integrity of the system by not leaving unreferenced "garbage" objects. Another alternative is to turn on the persistant garbage collector which will clean up these unreferenced objects automatically
Q:If I have a database object which has an attribute that has a list of ordinary serializable objects, does the list gets loaded when I access one of these Objects?
A:If you use the normal Java collections then, yes, the complete collection gets loaded into the memory since ozone works with Java serialization.
Q:That would be a problem as the list could be quite large and loading it would require lots of RAM. How do you suggest I design this in order to minimize redundancy and memory consumption?
A:The solution is using a collection of persistent objects, e.g. a linked list where each list node is a database object. Then the list nodes are loaded and removed on demand. That slows down the performance but saves memory.
A:adding/removing method and adding of members works. See jdk doc about serialization and serialVersionUID.
Additional fields are handled in ozone as additional fields are handled in Java Serialization. If you add a field to a class and deserialize an object which was stored by the old class version, this field gets default-inizialized, that is zero for numbers, false for booleans and null for objects. As no constructors are called during deserialization, there cannot be other initial values for new fields than the default ones.
If you make your database objects 'Externalizable' and implement read/writeExternal clever you can do a pretty good schema evolution. You can then use a version number (not serialVersionUID !), write it in writeExternal, check it within readExternal and do additional actions if the version number has a particular value. Thus you can avoid the normal serialization schema evolution limitations, e.g. removing a member. The serialVersionUID stays always the same. Because of this Java thinks the streamed objects are always compatible to the current implementation. The second version number is for you to control which version you've got serialized.
An Example:
public class TestImpl extends OzoneObject implements Test, Externalizable { // remains always 1 static long serialVersionUID = 1L; // increase it if you added or removed a member static int subSerialVersionUID = 2L; // is member since version 1 private String aMember; // a new member private HashMap bMember; // ... some methods ... public void writeExternal( ObjectOutput out ) throws IOException { out.writeInt( subSerialVersionUID ); out.writeObject( aMember ); out.writeObject( bMember ); } public void readExternal( ObjectInput in ) throws IOException { int version = in.readInt(); aMember = (String)in.readObject(); if (version == 1) { // a deleted member from version 1 in.readObject(); } if (version > 1) { bMember = (HashMap)in.readObject(); } } }
Q:How would I go about retrieving the object with the oldest creationDate attribute? Also, is it possible to retrieve an object or a set of objects based on the exact attribute value (e.g. all cars made in 1974)? Similarly, is it possible to retrieve an object or a set of objects bases on the range of values (e.g. all cars made between 1974 and 1984)?
A:There is no descriptive query system yet. There are two possibilities:
your queries are not that complex; in this case you can Java-code the queries. i.e. you start at the named root objects and than traverse the path to the objects you need as you would do it in a usual Java program.
the queries are complex; in this case you can start an effort to finally make a descriptive query system for ozone ;)
Q:Say we have the query "Select name from table where name=manav". How can i do the equivalent things in Ozone? I.e. how can I perform QUERY Like things in OZONE such as Select,Delete,Update etc.
A:Object databases are very different from relational db's. You manipulate data through the methods defined by your persistant objects. Simply put: UPDATE will probably be a set method, SELECT will probably be a get method etc. so you need to implement your own queryable data structure in the Java objects stored inside Ozone.
For an example of a fairly general and slightly eccentric form of searchable and indexable data structure, see Reasons com.twilightminds.jdf.data and com.twilightminds.jdf.data.ozone packages here, and a introductory guide to same here.
Q:Can you point me to any documentation that might describe how best to adjust the cluster size, table size, etc. for best performance?
A:cluster size does not affect performance that much. But the size of the object cache (JVM heap size) and the dimension of the B-tree caches are very important. The Admin documentation or Server Configuration should help you to get started with this. You should always try to adjust cache and table sizes so that the _working set_ of your data is kept 'in cache'. That is, all objects of your working set of data should fit in memory and the B-tree tableBufferSize should be <= the number of objects in your working set.
A:Yes, connection pooling and multiplexing is built into and handled by the OzoneInterface (ExternalDatabase and LocalDatabase). You just need one ExternalDatabase object for the entire application/session.
For a web application for instance, just store the db object in the application scope and then just use it from all threads. In short: no need to open/close "connections". The notion of a "connection" is not needed by Ozone. Ozone uses (client side) threads and bounds transactions to them; in fact, the programmer does this by calling an ozone method or accessing an ozone object or explicitly begin/end a transaction. The view to the content of the db depends on the thread you are currently in and the transaction (or no transaction) that is currently bound to that thread. This is completely different concept than jdbc connections. Ozone offers a lot more elegant posibilities here.
An Example:
// thread1, no tx ozoneObject.getNumber(); // returns say 1 ExternalTransaction tx = db.newTransaction(); tx.begin(); ozoneObject.setNumber( 2 ); ozoneObject.getNumber(); // now returns 2 tx.abort(); ozoneObject.getNumber(); // returns 1 again
See the users guide for more information on this.
Q:I'm trying to understand how Ozone is licensed. On your license page it says:
Ozone Library License, LGPL Ozone Core License, GPLIf I want to embed Ozone into another product (which utilizes, but is not itself a database) which license am I bound by?
A:If you are using ozone via its APIs, then you are bound to the API's license, which is LGPL. This basically means you can use it freely in both commercial and non-commercial situations and also build on top of the code and include Ozone in your project without having to pay royalties to anyone. If you are changing Ozone itself, then you are bound to the license of the core files, which is GPL. This means you need to make your code open source using a GPL license.