Since we have an object database in the Order Processing project we need to learn how to maintain it as the project changes.
In a standard (relational) database you have the same kind of problems as here, but to a lesser extent. The database itself needs to be reversioned whenever we change the kind of data we store in it, of course. this is true in any database. However, in an object database, the database needs to be reversioned whenever any class with stored objects changes. This is because the class stores the classes as well as the objects.
Actually, in Java, the database needs to be reversioned only when the public interface of a class changes.
There are two different ways to version a database, depending on whether you have live data or are just versioning in initial development. Actually you can use the simpler version even with live data if you don't have a lot of data. In this document I will explain only the simpler version leaving to other for later. The Versionable interface is intended to help with the second, and more complex, method.
The simple way to version a database during development is to keep a separate copy of the data in the database in a non-object form. There are a variety of ways to do this, but the easiest to use is one in which we keep the data in a human readable file that we can actually edit with a text editor when necessary.
Here is an example of such a file.
Now we have the problem of creating and maintaining this file. We do this with another project file: Maintenance.java. You should download this file and add it to your project. (To download, right click the link and select Save Link As...)
Maintenance.java dumps out all of the project database data to a listing file and reads it back in depending on what command line parameters you give it. It does this by "marshalling" the data as it writes it out, and "unmarshalling" it as it reads it back in. This is in essense the process that most programmers need to go through with the live data in order to store it in a relational database and retrieve it as needed. It is the step we normally avoid by using an object database.
Before you change one of the classes with data in the database (all but OrderEntry, OrderProcessor, InventoryManager, the test classes and this file) you should determine if your maintenance copy is up to date and if not, execute the project with Maintenance as the main file and giving it command line parameters like: save list.txt. You can set these from the Project->Interpreter Options menu as follows:
In fact, if you do this now, with the current database, you will create a file like list.txt that was linked to above. This can be your base for later changes.
Then you can change the class you are working on and recompile it. The next time you run, however, you will get the dreaded "Failed restoring database" and an InvalidClass exception. To recover from this, again run Maintenance as your main class, but this time with the restore list.txt option.
You will need to do this whenever you change a class that has data in the database, but it isn't very hard, especially if you aren't adding a lot of data as you go along. You may only need to do the first step infrequently if you haven't actually added any data to the database.
To summarize, the main in Maintenance requires two command line parameters. The first can be either save or restore. The second is a filename.
However, there is one common situation in which you need to do more.
Suppose that you change the project so that you now need to store additional data in the database or change the way in which you store some information. For example, one flaw with the current design that will be repaired in a future cycle, is that we don't now have a class for Product. This means that orders and invoices can't be checked against the products that we sell (or more importantly, against current inventory).
Suppose, to keep it simple, that we want to add an additional field to our Customer class and store this new field in the database. Let's assume we have saved the current database to our maintainance list as shown in the link.
We now begin to modify the Customer class. All is well. But we must also modify the Maintenance class to both write and read this new field as well.
Therefore we need to modify the dumpCustomers and restoreCustomers methods of Maintenance.java. Decide where you want them in the listing file and write input and output statements accordingly.
Next you need to rebuild everything. More than just Maintenance and Customer will need to be compiled. The safest way is to rebuild all.
You must then go and manually edit the listing file (list.txt) so that it contains appropriate data in the format you used in the step just above and in the locations in the file at which the read statements expect to find it.
Once you have done this, you can run Maintenance as the main again with the restore command line argument and you should have a new database compatible with your new files.
For a more extensive change (adding Product to the project) we might need to write new dump and restore methods and call them from main, of course.
To summarize the steps:
The nature of the classes in the Order Processing project leave us with a special problem. Since the Customer (and Order...) numbers are assigned internally, we don't have a constructor for Customer that specifies a Customer number (key). In the object database itself, this is not a problem. However, when we stream the data out to a file and then stream it back in, a constructor must be called to create the new object from the saved data. We must guarantee that the new objects created have exactly the same key fields in the new database as they did in the old. In the current Maintenance class this is handled in the following way.
When we stream the data out we write the records in key order. The application also has the property that no Customer object is ever deleted. Same for Orders and Invoices, which also have keys. Then, when they are read in again, the usual constructors give them the same keys they had before, since the keys are also assigned in order.
Note that not deleting objects is key to this happening correctly. It is also one of the business rules, so it is not a problem here. When a customer becomes "inactive" we can store them in a different HashMap to indicate the fact, but not delete the object itself.
If we don't have the property that the objects never disappear from the system, and we still require system assigned consistent keys, then we need a different solution. This may occur in the future. The solution is to provide a private constructor (private is important) that does create a new object with an assigned key rather than a system derived key. This constructor would only be used as part of the maintenance process and would be used to construct the object with the same key as that stored in the maintenance file.
Note that I use the phrase "object database" in a very loose sense here. Our database while the system is running is just a few HashMaps that store our information. When the project is not running, the database is the data stored on an ObjectStream. There certainly are Object Databases with all of the sophistication of Relational Databases.
Last Updated: October 9, 2000