Ganymede Release 2.0 October 1, 2008 CHANGES Last Commit: $Format:%cd$ --------------------------------------------- -------------------- Changes from 1.0.12 to 2.0.0 ------------------- RELEASE DATE: October 1, 2008 1. [EVERYTHING] Ganymede Rebooted.. Subversion, Ant Went through everything in the old Ganymede tree and did lots of surgery, completely restructuring the source tree, moving files into new packages. Created sub packages arlut.csd.ganymede.server, arlut.csd.ganymede.common, arlut.csd.ganymede.rmi, arlut.csd.ganymede.admin, to make clear the different roles various classes in the old arlut.csd.ganymede package play. Deepak created a very nice Ant-based build system for Ganymede, and restructured the source code into a package structure to make builds with Ant convenient. We imported the old Ganymede CVS repository into Subversion. I went through all of the source files and replaced the old CVS keywords with Subversion keywords. Subversion is wonderful. Ganymede 2.0 would never have happened if we were still stuck with CVS. 2. [SERVER] Localization The Ganymede clients and server now incorporates a method for localizing message strings. A new class, arlut.csd.Util.TranslationService, has been added which handles string lookup and templatization from string resource files held in the src/resources tree. A considerable portion of the Ganymede server has been modified to use this localization mechanism, as has the admin console, and the entirety of the Ganymede graphical client. The default, American English version of these localization files held in the src/resources tree are simply called .properties. When the Ganymede server is run under a JVM that is configured to use a different locale, the TranslationService class will automatically read any translated resources from the appropriate file, if it is present in the appropriate directory. For instance, if an adopter wanted to translate the messages used by the arlut.csd.ganymede.server.GanymedeSession class into French, he would create the file src/resources/arlut/csd/ganymede/server/GanymedeSession_fr.properties Ganymede uses the standard Java Internationalization method for handling message strings, with interpolated parameters injected into the message strings with tokens like {0}, {1}, and etc. The new Ant build system provides a task to cross check the default localization resources against the Ganymede source code, to ensure that the localization message strings match the usage in the Ganymede source code. If you run 'ant validate' in the src directory, a Perl script is run to do this analysis and verification. 3. [SERVER] Added support for SSHA password hashing in DBPasswordField Here at ARL, we're working to move from NIS to LDAP for our Unix and Mac OS X systems. Since the OpenLDAP server doesn't support md5Crypt and since traditional Unix crypt is just too inadequate in the face of John the Ripper and other brute force dictionary attacks, I've implemented support for encoding passwords entered into Ganymede using the Netscape Salted SHA-1 hash algorithm. See http://www.openldap.org/faq/data/cache/347.html for more details on the SSHA hash format. Nota bene: From what I've read, SSHA is actually a relatively cheap hash algorithm.. it doesn't contain the arbitrary delay features that something like md5Crypt uses to slow down the hashing algorithm. As a consequence of this, attempts to use brute force dictionary attacks against SSHA hashes can be pretty successful. The primary benefit of SSHA over Crypt in the LDAP context is that longer passwords can be supported (vs. the 8 character limit of traditional Unix Crypt). 4. [SERVER] Integrated Jython interpreter support in the server XXX - to be written. Discuss DBEditObject subclasses, tasks. 5. [SERVER, CLIENT] Java 5.0 fixes Sun, long may their name be praised, decided in Java 5.0 to arbitrarily make 'enum' a language keyword, despite never having put it on the reserved keyword list. We had to go through the entire source code and replace 'enum' with 'en'. In a number of other places, we had to explicitly cast some parameters when making reflection calls to avoid confusion between an older method call that has null as the final parameter and the newer Java 5.0 varargs versions of those methods. We've made the ant build files for everything specify a source code and class file target level of Java 1.4, so nothing in Ganymede 2.0 should require a Java 5.0 system. 6. [CLIENT] Cleaned up some threading We're now using FoxTrot (http://foxtrot.sourceforge.net/) to allow some activity in the client to be synchronous in ordering but asynchronous in that we allow the GUI thread to continue redraw and processing further GUI events until certain server calls complete. This fire-and-wait support makes the GUI client feel much snappier in a few places. 7. [SERVER] The return of passive password capture Thanks to Deepak, we have now re-enabled the passive password capture logic in the PasswordDBField class that was removed in 1.0.10. Previously, the big showstopper with passive password capture was that it was possibly to capture erroneous plaintext that nonetheless matched a stored hash format, particularly the 8-character-significant traditional UNIX 'crypt' hash function.. Now, passive password capture is back, but it is smart enough not to capture plaintext on login if the password is not known from a hash with adequate specifity. The whole point of having passive password capture is that it enables Ganymede to learn about plaintext from interacting with a user, while still allowing us to forego saving plaintext passwords persistently to our ganymede.db file. 8. [SERVER] Made transaction commit more resilient to exceptions in commitPhase1 The DBEditSet's transaction commit logic was vulnerable to getting into a confused and broken state if an object's commitPhase1() method threw an uncaught exception. It's fixed now so that the client gets an exception report and the transaction unwinds itself back to a consistent state, ready to try committing again (though it will probably fail if the error condition in the plugin classes is not fixed). 9. [SERVER, CLIENT] Added SSL support, 1.4 requirement, Firewall friendliness Added the arlut.csd.ganymede.server.GanymedeRMIManager class to handle all RMI exports, with support for SSL encryption of client/server communications through the arlut.csd.ganymede.common.RMISSLClientSocketFactory and arlut.csd.ganymede.common.RMISSLServerSocketFactory classes. The Ant build process now incorporates automatic generation and distribution of key and certificate material into the appropriate jar files when the jar files are built. The SSL support now present in Ganymede requires a minimum of Java 1.4 to work. We are therefore intending to make JDK 1.4 a minimum requirement of Ganymede 2.0. It is now possible to specify the port number that the Ganymede server should use for publishing its RMI object targets. This means that the Ganymede server will now use only two ports, one for the rmiregistry and one for client access, and that these can be specified for compatibility with a fixed firewall configuration. 10. [SERVER, CLIENT] Changes to Query system (Deepak) Deepak implemented support for a text based (ANTLR-based) querying language that can be used by Jython code to do queries on the Ganymede server. Deepak also added the new arlut.csd.ganymede.common.QueryResultContainer class, which acts like the old arlut.csd.ganymede.common.QueryResult class, but which implements the java.util.List interface for convenient use from Jython. At this writing, this new QueryResultContainer isn't actually being used, yet. In specifying the ANTLR grammar, Deepak defined a new dereference operator, which allows for a query to express a constraint based on the value pointed to be an invid field. By using this dereference operation, I was able to drastically simplify and speed up the GanymedeSession query logic by pulling some of it inside-out. 11. [SERVER, CLIENT] Removed the OwnerObjectsOwned field from OwnerBase With this change, Owner Group objects no longer include an InvidDBField tracking objects owned by that Owner Group. Instead, it is the responsibility of the owned object to point to its owner. By making this relationship non-symmetrical, we gain the ability to add or remove objects from an owner group during a transaction without having to check out the owner group for exclusive editing. As such, this change will significantly improve concurrency in the Ganymede system when many objects are owned by a single owner group. This change was made possible by the (now quite old) change described in 0.99.8, #17. The 'Objects Owned' pane is still present in the client when viewing or editing an Owner Group object, but this is now done using discrete query logic rather than the old InvidDBField lookup, again for the benefit of avoiding Owner Group locking. 12. [SERVER] Added a per-DBObjectBaseField lastChange variable For the entire history of Ganymede, the GanymedeBuilderTask has consulted a lastChange variable in each DBObjectBase to decide whether any objects of a given type (user, group, system, etc.) has been changed since that builder task last ran. Our custom builder tasks use this to avoid doing builds when the builder task is not interested in what has changed since it last ran. One problem with this has always been that the object-level timestamp didn't really have as much granularity as we would desire. Now, each DBObjectBaseField has its own timestamp, so we can write builder tasks that will, say, check to see if any user has had their username or password changed since the builder task last ran. Previously, all the builder task could do was check to see if any user had been edited in any way since it last ran. This meant that editing the Notes field on a user would trigger unnecessary activity in all builder tasks that cared at all about user changes. 13. [CLIENT] Numerous fixes in the client's query table logic Fixed a number of bugs in the client, including the bug that allowed an object to be deleted in the client then viewed in an empty state through the use of the query result table pop-up menu. Now, all checks against an object being already marked as deleted are done at the proper place, rather than being done in the tree response code. Also, I fixed bugzilla bug #14, which caused the title of query windows not to be properly updated when a transaction is committed and the query windows are refreshed, possibly with a different number of entries (see 1.0.12, item 14, below). While I was working on that, I shuffled some code around in the client for better thread safety when accessing some windowPanel data structures, as well as the use of a common windowPanel.setWindowTitle() method for picking and maintaining unique window names. 14. [ADMIN CONSOLE] Significant fixes to bugs in console login process Improved the admin console login procedure. The server now returns an explicit dialog refusing admin console login if the user provides an unprivileged or incorrect username and password. The admin console now responds properly to a failure to login or to the Ganymede server being down. The admin console will now also repeatedly test the server to see whether it has come up, and can be told to attempt a new connection if the server is believed to come back up. Much of the connection establishment threading has been improved in design. The use of the arlut.csd.Util.booleanSemaphore also helps some, by allowing for proper exclusion of overlapping connection threads. The connection thread now properly uses the SwingUtilities to handle proper issuance of gui updates in response to the connection thread. Good stuff, and long overdue. 15. [NIS PASSWORD CLIENT] Removed the rpcpass program I've taken out the old rpcpass program which was used in conjunction with the -x option to Thorsten Kukuk's NIS yppasswdd daemon for Linux. The vaguely named rpcpass was used to propagate password, shell, and finger info changes from the Linux yppasswdd daemon into Ganymede. Unfortunately, the passwords that the yppasswdd is capable of transmitting to Ganymede are in the old Unix crypt() format, which means that passwords submitted in this way are useless if Ganymede needs to sync to anything but NIS. Therefore, and given that we at ARL have not used this code in nearly five years, I removed it. If you are reading this out there in Internet land and decide that you've got to have it, let me know and I'll see about resurrecting it from Subversion. 16. [XMLCLIENT] Massive speed-ups in the XML client, reversal of method calls Previously, when the xmlclient was used to extract data from the Ganymede server, the xmlclient would publish an RMI target and allow a thread on the server to repeatedly call the client, pushing XML data from the server. This had the disadvantage that the xmlclient could not be run on a system with a local firewall blocking incoming TCP connections. With SSL support now added to the Ganymede server, this reverse flow of RMI method calls also meant that the xmlclient needed its own SSL certificates and key material, or else XML sent from the server to the client would be unprotected on the wire. Now that the xmlclient pulls data down from the server with iterative method calls, the XML is naturally protected with the existing SSL connection. In addition to this change of direction for the method calls, the arlut.csd.Util.BigPipedInputStream class has been fixed so that it actually will properly increase the size of the buffer used for internal pipes within the Ganymede server. In the case of the pipes used to feed the xmlclient, this means that the server can now provide 64kbyte chunks from the XMLWriter, rather than the default 1k chunks normally provided by PipedInputStream. This has the effect of reducing the number of RMI calls required to transmit XML to the client by a factor of 64, resulting in a massive speed-up. In testing here, this change made the new code 5 times faster at wall-clock time in doing a system-local xmlclient dump to /dev/null, even with the overhead of SSL encryption included, relative to previous releases. 17. [SERVER] Use of external rmiregistry eliminated The Ganymede server now implements an rmiregistry in-process, rather than depending on an external rmiregistry support process. This simplifies the startup and shutdown of the Ganymede server, as well as operational usage generally. 18. [XML] Improvements to namespace handling in In some testing we were doing, we got surprised at the case sensitivity of namespaces that we were creating with the xmlclient. The surprise was that by default, namespaces created are case-insensitive. To be fair, our documentation said this, but it was just too easy to forget this when crafting xml test data. To address this, we have made the system warn if the case-sensitive attribute is not present in . Also, the Ganymede server now properly handles switching a namespace from case-sensitive to insensitive, or vice-vera, as needed, and checks to make sure that this redefinition operation can be done safely on the namespace-constrained data loaded in the server. The admin console's schema editor still does not allow changing the case sensitivity of a namespace, but the xmlclient may be used to do this. 19. [SERVER] Fixed a bug that made newly defined object types inaccessible Oops! We weren't properly updating the baseTransport cache after schema editing. This resulted in a failure whenever we tried to use the Ganymede client to access an object of a type that did not exist before the schema edit immediately after the schema edit took place. The only reason this didn't bite us before was that we haven't added a lot of object types through the schema editor without subsequently shutting down and restarting the server. Gotta love really exercising old code paths in relatively new ways. 20. [CLIENT,SERVER,userKit] Scalability work Lots of work on increasing the scalability of the Ganymede server and client. At the time of this writing, we've tested the userKit to a loading of 250,000 users and 250,000 groups, a total of some 7.5 million data fields, with a nominal (fully garbage-collected rest state) memory usage of around 600 megabytes on the server. In order to get there, we had to fix some poor algorithmic choices in certain points in the Ganymede server. This included a complete cut over from using the old cheapo QuickSort implementation I slapped together in a day from someone's online course notes to using the java.util.Arrays sort algorithm that came in Java 1.2. I also fixed a bug in the userKit userCustom.java class that made it do about a bazillion times more work than it should have when doing processing, thanks to a failure to set and retain the schemaConfStamp time stamp variable properly. The Ganymede transaction logging system is now very much more efficient as well. Previously, all events that needed to be logged in conjunction with a transaction would be assembled into a Vector of DBLogEvent objects before any events were logged to disk. Now, the transaction commit logic streams these log events to the logging system as they are generated, so that garbage collection can occur during the logging process. This should help reduce memory loading on very large transactions. Made some improvements in the XML import logic to intern commonly occuring strings, again to reduce memory usage. 21. [CLIENT,SERVER] Invid redefined, private constructors, InvidPool The Ganymede object id pointer class, arlut.csd.ganymede.common.Invid, has been modified slightly to make its constructors private, in order to force code wanting to create Invids to go through the Invid class' static factory method, createInvid(). The purpose of this is to allow for intelligent re-use of Invid objects on the server, so that the server will only need to keep one copy of any given Invid. This has an effect similar to the interning that the Ganymede server has always done when loading strings from its database, and should help lower the server's memory usage a bit on large datasets. In addition, an InvidPool has been implemented on the server, which uses a hashing SoftReference data structure to efficiently implement Invid interning. This seems to cut memory loading on the server with large datasets by 15% or more. 22. [CLIENT] Reworked the client layout/rendering algorithm The layout/rendering algorithm for the client object windows and the admin console schema editor has been rewritten to behave better in a greater variety of circumstances. In particular, bugs that were seen when using the multi-line label field have been addressed. 23. [SERVER,ADMIN CONSOLE,CLIENT] New data field type added for Sync Channel Introducing the first new DBField type since the introduction of Float back in 1999.. the FieldOptionDBField! The purpose of the FieldOptionDBField is to allow the client and/or xmlclient to configure the list of objects and fields that the new Sync Channel synchronization channels (to be introduced hereafter) will use when writing out an XML description of transactions to disk as they happen. The intention is that the Sync Channel will write out an XML description in a known format for each transaction that is committed, and a dedicated queue runner will be launched on an asynchronous basis to sweep up the XML records for the queue, up to a fixed transaction number, for integration into directory services oriented around change requests rather than complete dump and reloads. 24. [SERVER] Made DBEditObject.deleting variable private I've made the deleting boolean in DBEditObject private rather than protected, so that use of it can be controlled better. If your custom plugins consult deleting directly, they will need to be tweaked to use "isDeleting()" rather than "deleting". 25. [SERVER, XML] Corrected xmlclient behavior for namespace swaps The xmlclient is intended to allow just about any legal change to the Ganymede server's data to be made by submitting a declarative xml file. Unfortunately, it turned out that one thing the Ganymede server could not do when handed an xml file was to swap two namespace values around. That is, suppose you wanted to rename two user accounts simultaneously, giving account A the name previously associated with account B, and account B the name previously associated with account A. If you try to do this in the GUI client, you'll find that you need to make up some transient name to act as a placeholder for account A, then give A's name to B, then go back and give B's name to A, erasing the placeholder in the A account. This kind of fine grained control over the order of operations isn't possible when using the xmlclient, so I have tweaked the server's namespace management logic so that it will allow non-interactive sessions to have an arbitrary number of namespace linkages 'in flight' at a time. Giving name 'A' to account B will be allowed, even though it means that for a brief window, both account A and the old account B will be associated with the 'A' name. If the name 'A' is not unlinked from the old account A by the time the xmlclient's transaction commits, however, an exception will be reported and the transaction will be canceled. This logic is even capable of resolving object renaming cycles, such as would occur in an XML file that required System A to be renamed as System B System B to be renamed as System C System C to be renamed as System A 26. [SERVER, XML, EVERYTHING] Object labels no longer virtualizable, must be namespace constrained The Ganymede server has never previously actually enforced a requirement that all objects must have unique labels. I thought this very clever in my initial design, allowing DBEditObject plugin classes to completely fabricate labels for objects on demand. In fact, this was a very stupid idea, as it makes all sorts of things much more complicated, including the XML dump and load logic. Not being able to know for sure that an object's name is unique in an xml dump means that the xml file format is basically kind-of-close to useful, but not actually trustworthy. In Ganymede 2.0, all object types registed in the Ganymede server must have honest to goodness label fields, guarded with a namespace constraint to ensure unique labels within the object type. It is still permissible to allow multiple kinds of objects to have their label fields share a namespace if you so desire. Object types in the base Ganymede system that did not meet this criterion, such as the Object Event type, have been modified to include a hidden label field that is automatically maintained by the new preCommitHook() method added to the DBEditObject class. This change may cause some difficulty for people trying to transition a Ganymede 1.0 environment to 2.0, but I've put in some logic to try and help you out. When you load an old 1.0 database that has any object types without namespace constrained label fields, the Ganymede server will print a warning on startup. When you go to edit the schema, either with the GUI schema editor or the xmlclient, your schema change will refuse to commit unless you make sure that all objects meet this constraint. As well, any built-in Ganymede types that are affected by this change will automatically be tweaked for you by the system the first time you start the server on top of an old ganymede.db file. This change bumped the DBStore version number to 2.11. 27. [SERVER] Clarified that Vector fields may not hold duplicates Previously, certain parts of Ganymede implicitly assumed that duplicate values were not allowed in vector fields, but no code made sure that duplicates were not introduced into vector fields. I have now introduced code to test and enforce that constraint. This change may slow down bulk loading, but it will assure that we have a consistent semantic for vector fields, and other code in the Ganymede server can safely rely on the uniqueness of vector field elements. 28. [SERVER] Added GanyPermissionException to server Several classes in the Ganymede server now throw arlut.csd.ganymede.common.GanyPermissionException when permission problems are encountered. This change was to help insure that Ganymede server internal code was properly tracking permissions failures. As a result of this change, custom schema kit code written to the Ganymede 1.0 series may need to be altered to catch the GanyPermissionException, as it is a declared exception that derives from RemoteException for compatibility with the client. In some cases, methods that previously returned ReturnVal to indicate permissions failures may now throw GanyPermissionException. 29. [SERVER] Added entirely new Sync Channel build systems With Ganymede 2.0, the Ganymede server now has an entirely new family of synchronization services. Previously, all builds were done through the use of the GanymedeBuilderTask and its subclasses, using a two phase process. In phase one, portions of Ganymede's internal datastore were locked against changes while the builder task scanned the database and wrote data (usually text files) out to a specified directory. In phase two, the database was unlocked, and the builder task ran an external synchronization process that used the data files written out by phase 1. When the external build system finished, the task's execution was complete, and a new build could be scheduled and issued for that same task. All of that is still there, and it all works the same way that it ever did. Now, though, there is a second system, based on the SyncRunner and syncChannelCustom classes and the use of an XML file format. I call it the 'Sync Channel' system. The Sync Channel system comes in three flavors.. "Automatic Full State", "Automatic Incremental", and "Manual". The Automatic Incremental Sync Channel system is the most different from GanymedeBuilderTask. It is based on tracking the changes made to the Ganymede data store. When a change is made, the Ganymede transaction commit logic examines all Incremental Sync Channels registered in the server, looking to see if any of them are interested in the objects and fields that have changed. If any Incremental Sync Channel is so interested, that Sync Channel will write out an XML description of the transaction with respect to the objects and fields that the Sync Channel cares about. Each standardized transaction description is written out to a directory devoted to the Incremental Sync Channel, in a file whose name is the transaction's id number. The Ganymede server then triggers the external service program specified for each Incremental Sync Channel, passing it the number of the highest transaction known to have been successfully written out at the time that the service program is run. The service program is intended to read all of the transactions up to and including the number given it, and to integrate those changes into whatever directory service the Sync Channel is intended to support. There's much more to read about this major new feature, including details about the "Automatic Full State" and "Manual" Sync Channels, in doc/synchronization/index.html, or you can go on the web to http://tools.arlut.utexas.edu/svn/ganymede/trunk/ganymede/doc/synchronization/index.html for the details. 30. [SERVER] Forced java.rmi.server.randomIDs on by default In conjunction with the adoption of SSL in Ganymede 2.0, the definition of the property statement 'java.rmi.server.randomIDs=true' is necessary to avoid direct JRMP wire-level access to RMI objects intended to be published by Ganymede for the benefit of a single client. With this property defined in the runServer script, Ganymede RMI objects will be given cryptographically secure 64 bit random object id numbers. Anyone wishing to hijack an RMI-published object would have to have some way of guessing a 64 bit random number in order to send a JRMP message to the Ganymede server forcing an unauthenticated operation. In theory turning off java.rmi.server.randomIDs should make the Ganymede server startup marginally faster, but any modern system that provides high entropy random numbers through a /dev/random device shouldn't see any delay to speak of anyway, and the Ganymede server is much, much, much more secure with both SSL and randomIDs turned on than it is with just one or the other of them turned on. 31. [XMLCLIENT] Added sync argument to allow for constrained dumps Now that Ganymede 2.0 allows you to define object and field constraints on sync channels, the xmlclient has been elaborated to be able to apply a sync channel constraint to a dump. This makes it possible to dump out a tailored XML report that only contains the object and field types that a given synchronization target might be interested in. The ultimate purpose of this is to allow an administrator to pull the full state of Ganymede with respect to certain objects and fields, for the purpose of doing initial setup of an external directory service target, before setting up a sync channel to transmits deltas as they are committed to Ganymede. Use is simple, just type xmlclient -dumpdata sync=Systems > systems.xml and Ganymede will dump out all data that fits the Systems Sync Channel constraint. 32. [SERVER] Ripped out the old schema printing logic The Ganymede server, from way back when, included logic for printing its schema definitions in a readable form to HTML or plain text. All of that code really became redundant when the xmlclient was introduced, so I have gone through and removed it. The Ganymede server will no longer support the ganymede.htmldump property, and will no longer support dumping the schema to an HTML page on server startup. If anyone is interested in generating a schema web page from the xmlclient -dumpschema output, that should just be an XLST script away. Getting rid of that old code helps reduce the maintenance burden on Ganymede, as I don't have to change schema printing logic in three places anymore. 33. [SERVER, XML] Miscellaneous fixes to XML input processing The Ganymede server's XML input processing is now far more robust in terms of dealing with invid label resolution, regardless of the order in which objects are presented in the XML input, and especially in the case where objects are renamed as the XML file is processed. The status report at the end of an xmlclient data batch submission has been fixed. Fixed the bug that led to sshatext being ignored on XML input. Fixed the bug that caused leading or trailing white space to be ignored in scalar string elements. 34. [SERVER, CLIENT] The client now catches and displays exceptions reliably The Ganymede client now catches and displays exception conditions to the user when they happen, rather than just dumping them out the back door to STDERR. When an unhandled exception occurs, the Ganymede client will display a dialog showing the exception. The dialog includes a button to allow the user to report the exception to the Ganymede server for logging. 35. [SERVER] Improved various error messages from Invid fields Lots of clean ups to make the error messages that occur while linking and unlinking objects more readable. 36. [SERVER, CLIENT] The server reports bad regular expression queries to the client The server will now send a dialog to the client explaining about a malformed regular expression query, rather than silently failing to return any data. 37. [SERVER] Honor DBEditObject.canClone() The canClone() method in DBEditObject wasn't being checked by GanymedeSession, which meant that users could clone objects that the schema kit author intended not to be cloneable. This bug was reported by Fredrik.A.Bergman@ericsson.com. 38. [SERVER] Fixed non-namespace constrained IPDBField fields. IP fields that are not namespace constrained no longer throw a rod when you try to change them. This bug was reported by Fredrik.A.Bergman@ericsson.com. 39. [SERVER] Properly handle regexp description in XML input Made sure to read/set the regular expression description attribute when processing xml input. This bug was reported by Fredrik.A.Bergman@ericsson.com. 40. [SERVER] Properly clear qr cache in InvidDBField Made sure to clear the qr cache in a few more places so as to not allow lingering choice lists to be retained. This bug was reported by Fredrik.A.Bergman@ericsson.com. 41. [SERVER] String field schema consistency checks now in GanymedeValidationTask I've added support in the DBField class to allow a consistency check to be made on values held in a field against the static constraints specified in the Ganymede schema. This check is integrated into the old verifyNewValue() call for StringDBField, and the GanymedeValidationTask will run the field contents integrity test when you do the database consistency test from the admin console. Most constraints on fields are still implemented by dynamic method hooks in the DBEditObject class, and those constraints can't really be tested out except at commit time, when the editing context is available. This change came about because we found that a system record in the laboratory's Ganymede server had a colon character in its Manufacturer field, despite our having modified the schema to prevent that some time ago. Note that if you apply a new constraint to a string field, there is no guarantee that previously existing data will match the new constraint until you run the Database Consistency Test / GanymedeValidationTask to be sure. 42. [ADMIN CONSOLE] Split sync tasks into separate task table The admin console now includes a second task monitor table, devoted to sync tasks (i.e., schedulable tasks derived from arlut.csd.ganymede.server.GanymedeBuilderTask or arlut.csd.ganymede.server.SyncRunner). Adding a third tab for this in the admin console makes it easier to track builds and what-not. 43. [SERVER, XMLCLIENT] Added logic for handling space characters on the command line Previously, the Ganymede xmlclient and server, both of which require the ability to process command line arguments, did not properly handle command line arguments containing whitespace. This was due to a major design flaw in how the Java runtime environment handles command line arguments.. in Java, rather than letting the shell break the command line into an argument list, the runtime is responsible for doing this, and it always breaks on whitespace, regardless of attempts at quoting or escaping arguments. This made it impossible to use xmlclient to do sync channel dumps with sync channels whose names contained whitespace. Now, the Ganymede command line argument parser recognizes HTTP-style space character encoding.. any "%20" sequence encountered on the command line will be treated as a space character instead. The xmlclient wrapper script is now written in Perl, and converts space characters in arguments to %20 for passing into the xmlclient Java executable. 44. [SERVER, XMLCLIENT] Added support for full-fidelity dumping and loading The xmlclient now has support for an -includeHistory command line argument, which causes the Ganymede server to include the historical fields (creation time, creator info, modification time, modification info) when dumping out Ganymede objects. The xmlclient now has support for an -includeOid command line argument, which causes the Ganymede server to include the precise invid for dumped objects in the element's oid attribute. The Ganymede server now has support for a -magic_import command line argument, which causes the Ganymede server to support loading the historical fields from an xml file, as well as using the oid attribute to create objects with a predetermined invid number. Between -includeHistory, -includeOid, and -magic_import, it's now possible to dump a server's complete state to an XML file, modify the XML dump by hand to alter the schema (for instance) and then load it into a new server, with all invids and historical fields matching the original server's state. 45. [EVERYTHING] Added support for server-defined custom tabs in the client This change introduces tabs to the Ganymede schema model. Adopters can now place user-defined fields into user-defined tabs, and the client will display the appropriate fields in separate fields, accordingly. The goal here is to make it possible to add more data fields to an object type without overwhelming the user. 46. [CLIENT, ADMIN CONSOLE] No More Redundant Login Box When Running As Application The Ganymede client and admin console are both designed to be able to function either as an application or as an applet, depending on the manner in which they are launched. When they are run as applets within a web browser's window, the applet must remain open in order to avoid terminating the applet. Things are different when the client and console are started as applications, however. In this case, the login box that is displayed when the program is started is fully under control of the application. With this change, the Ganymede client and admin console, when run as applications, will now close their initial login windows after the user has logged into the client or console. This eliminates the redundant/vestigial login window that used to hang around uselessly after logging in to the client and console. When running as an applet (using the 'native' or 'plugin' mode from the Ganymede web launcher), the applet window stays up still, of course. 47. [CLIENT, ADMIN CONSOLE] Application Mode with Java Web Launch In order to take advantage of the previous change, I've changed the JNLP launch files for the Ganymede client and admin console so that they are run as applications rather than as applets. I had already moved in this direction by signing the client and console jar files with the SSL key material. Going ahead and making the client and console run as applications gives me control over disposing the login window, allows me to manage threads a bit better, and lets the client/console connect to whatever machine hosts the Ganymede server, even if different from the web server from which the client or console is downloaded. This will help when it comes time to support fast failover of the Ganymede server. 48. [XMLCLIENT, SERVER] Added support for running queries with xmlclient The xmlclient now supports queries using the GanyQL query language that Deepak developed. See doc/xml/xmlclient.html and doc/querylanguage/index.html for full details. 49. [SERVER] Fixed invid vector cloning Previously, if you cloned an object that contained an Invid vector, any failure in the vector cloning would cause no items at all to be cloned, and the cloned object would have that field empty. Now, the InvidDBField.addElements() method is cognizant of the partialSuccess intention for object cloning, and will clone partial objects. 50. [SERVER, CLIENT] Miscellaneous fixes to client operations I fixed up the logic for the 'default owner' dialog in the client, so that you can close it without making a selection to no ill effect. It will also remember your previous owner group settings, so that you can revisit the dialog and see what defaults you have in effect. I tweaked the server and client so that the client is informed when an object being edited has its label field changed. All objects that point to the edited object through an invid link will be refreshed in the client to reflect the object's new name. This is even true for view-only object windows. The logic here is that changing the label for a linked object doesn't truly change the object being viewed, so having the link label reflect the new name is actually no change at all. It is a bit at odds with the fact that an object view window is a flash-frozen view of an object, though. Newly created objects are now given default object labels on the server until such time as their label field is set. The confusion about these temporary labels is what led to making the client react visibly to object renaming. 51. [CLIENT, JDATACOMPONENT] Fixed listHandle One of the primary data structures used in the client, the arlut.csd.JDataComponent.listHandle, turned out to be not fully defined. It was lacking a hashCode() method, and certain revisions I made in #50, above, needed it to be reliably hashable based on content rather than object identity. By fixing this, it ensures that the optimized VectorUtils class methods can properly manipulate listHandle vectors. 52. [SERVER, CLIENT, JDATACOMPONENT] Added support for server-side reformatting of input The Ganymede system now has the ability to respond to string input from the client by approving a canonicalized version of the input. Previously, the server could accept a given string, reject it outright, or engage the user in a wizard sequence. Now, the verifyNewValue() method in the DBEditObject subclass can use the new setTranformedValueObject() method in the ReturnVal to signify to the Ganymede server and client that the submitted value was accepted but that it was transformed in some fashion and that the client should refresh the GUI widget. We use this with the GASHARL schema kit to auto-format MAC address entry in the Embedded System Interface object's "Ethernet Info" field.. if the user enters "AB-CD-EF-11-22-3", the server will automatically reformat this string to "ab:cd:ef:11:22:03", in keeping with our policy, and the user will get immediate visual feedback that the data was massaged by the server. Good stuff, although it doesn't make the code on the client and server any simpler. ;-/ 53. [CLIENT, ADMIN] Use of Java 1.4 Preferences API to remember window position, etc. The Ganymede client and admin console now use the Java 1.4 Preferences API to remember window positions and various default selections from invocation to invocation on a given client system. 54. [CLIENT, ADMIN] Added support for the scroll wheel The Ganymede client and admin console now properly support the scroll wheel in the custom tree and table components. 55. [SERVER] Fixed a bug relating to limited privilege users in the incremental sync channel logic Came across an interesting bug when dealing with a user who was set up with extremely limited privileges in Ganymede. The emitXMLDelta() method was assuming that all fields defined on an object would be present (not null), and would fail if an administrator with limited privileges edited an object (explicitly or implicitly) in which he did not have permission to edit or see all fields. The bug caused a NullPointerException to be thrown, and a transaction involving this scenario could not successfully proceed to commit. 56. [SERVER] Liberalized anonymous linking behavior for non-privileged admins The DBEditObject class is meant to allow normal permissions to be overridden to allow linking to a symmetric field, even if the admin or user in question did not have permission to edit the target object and/or field. Unfortunately, this logic had a loop hole that caused anonymous object linking to break if the admin or user did not have permission to create the target field and the object, as persisted in the object base, did not contain an defined instance of the target field. This has been fixed by a change to the InvidDBField.bind() method. 57. [SERVER] Various cleanups to avoid proliferation of switch statements on field type I created a handful of static factory methods on the DBField class, and modified a lot of classes to use these factory methods, rather than to repetitively have their own switch statements on the set of field types defined. Now, adding a new DBField subtype is (almost!) as easy as editing a few static factory methods at the top of DBField, rather than having to edit a scattered collection of internal Ganymede code modules. In fact, in doing this work, I fixed a bug that made the DBJournal improperly fail to process FieldOptionDBField data in the journal if the server was abnormally terminated without consolidating its database. This is precisely the sort of bug that this change is intended to help prevent in the future. 58. [CLIENT] Misc fixes.. case insensitive sort, window size, motd window The client now uses a case insensitive sort throughout. The default window size for object view windows is now big enough not to require a horizontal scrollbar. The 'Message of the day' window now appears with the top of the message visible in the dialog, rather than the bottom. 59. [SERVER, CLIENT] Added support for user photos By redefining the getImageURLForObject() method in a custom user DBEditObject subclass, it is now possible to display user photographs in the client. The getImageURLForObject() method is designed to return a URL to a photograph for the user located on a web server accessible by the Ganymede client. There is no support for user photographs in the Ganymede server, itself. 60. [SERVER] Fixed nested monitor deadlock in GanymedeScheduler, scheduleHandle The GanymedeScheduler and scheduleHandle classes had a big opportunity for a nested monitor deadlock. We haven't previously hit the deadlock in the many years we've been running Ganymede as far as I know, but there it is regardless. scheduleHandle now drops all synchronization before calling notifyCompletion() on the GanymedeScheduler. This fixes a bug that caused things to seize up a bit if a user sent a disableTask command to a task while the task was running in the scheduler. 61. [SERVER] Added Event Reporting When External Build Processes Fail I've added an 'externalerror' event to the System Events predefined in the Ganymede Server. An 'externalerror' event is generated (and, optionally, email is sent, according to the definition of the externalerror System Event object in the Ganymede datastore) when the Ganymede server receives an non-zero result code upon executing an external process to service a Sync Channel. I've added similar code to the GASHBuilderTask and the IRISBuilderTask classes defined in the gasharl schema kit, but the launching of external builder scripts in response to builder task build phase 2 execution is not handled in the GanymedeBuilderTask base class, so I've not added 'externalerror' support for all conceivable Builder Tasks. See the runFullStateService() and runIncremental() methods in the src/ganymede/arlut/csd/ganymede/server/SyncRunner to see how to add event logging for errors encountered when running external build scripts. 62. [XMLCLIENT] The xmlclient will no longer leave itself logged in on query exceptions The xmlclient had an error, in which any exception thrown on the server during query processing would cause the xmlclient to terminate without properly logging out. Now, if a GanyQL query submitted to xmlclient causes an exception on the server (a parse exception, say), the xmlclient will report the exception (once!) before doing a clean logout from the server. 63. [XMLCLIENT] The xmlclient no longer fails on object deletion Brian Worden and his team at fg-networking.de provided a patch to fix a NullPointerException bug that occurred when deleting objects using the xmlclient. 64. [XMLCLIENT] The xmlclient can now import files dumped by Ganymede Another bug reported and fixed by Brian Worden and the guys at fg-networking.de. Ganymede was using different minor version numbers for its dump format between the code that generated XML dumps and the code that handled reading those dumps. 65. [EVERYTHING] German translation added Stefan Bier (bier@fg-networking.de) translated all of the Ganymede message strings into German. Users running the Ganymede client on a system with the default locale set to German will see translated messages in the GUI. Messages generated by the Ganymede server will only be translated if the system running the server is also using a German language locale. If you like, you can force any of the Ganymede programs to use German by including -Duser.language=de in the Java invocation line in the startup script, as follows: $JAVA $DEBUG -Xms$MINHEAP -Xmx$MAXHEAP -Duser.language=de arlut.csd.ganymede.client.glogin properties=$PROPERTIES Thanks Stefan! 66. [SERVER] Added Support for Custom Inactivation and Removal Notifications I've modified the DBEditObject class to define a pair of new hooks, reactToExpirationWarning() and reactToRemovalWarning(), and modified the GanymedeWarningTask to take advantage of them. These new DBEditObject hooks are designed to allow custom DBEditObject subclasses to do custom notification when a given object needs to have inactivation or removal warnings sent out, as determined by the basic logic in the GanymedeWarningTask. 67. [SERVER] Fixed dumpAndArchiveTask so it won't throw an exception if it is scheduled while the schema is being edited The dumpAndArchiveTask consolidates the Ganymede journal into the ganymede.db file on a periodic basis. It had a bug that would result in a semaphore exception if it was scheduled during schema editing. 68. [SCHEMA EDITOR] Fixed the right-click menu on embedded object types. The schema editor was popping up the wrong right-click menu on embedded object types in the tree control. This bug made it impossible to create new fields in embedded objects other than during the same schema editing session in which the embedded object type was created. 69. [SERVER] Improved error handling reporting for XML Sync Channels Improved the transactional Sync Channel processing so that the non-existence (or non-writability) of the registered queue directory results in a specific error message explaining that, rather than speculation that the disk might be full. 70. [XMLCLIENT] Improved error handling reporting for xml data uploads. The xmlclient (actually the code in the server which interacts with the xmlclient) has had its error handling improved. Certain classes of document errors are now handled more gracefully, with more explicit error messages. Also fixed the issue that led to the xmlclient stalling if the XML document was not properly terminated. 71. [SERVER] Added lookupInvid and lookupInvidLabel methods to DBObject These new methods are designed to provide a fast, convenient way for creators of DBEditObject subclasses to dereference Invids to the objects and labels which those Invids resolve to in the proper transactional context. Also added getParentInvid() to DBObject, which is applicable to embedded objects. It returns the Invid of the object which contains the embedded object. Also added isDefined() methods to DBObject. which can be used to test to see if a named or numbered field is present and non-empty. These new methods should make a lot of typical DBEditObject subclass logic a bit easier to implement. 72. [CLIENT] Added XML support capability to the GUI client The Ganymede GUI client now has the ability to transmit and receive Ganymede XML data files to and from the server, in addition to the command line xmlclient program. There is now a 'Submit XML Data' menu item under the File menu that supports transmitting XML to the server, and it is now possible to save or email query results from the query table in 'Ganymede XML Format'. With these two features, it is now possible to compose a query with the GUI query builder, get the results, save them in XML format, do some quick editing with the text editor of your choice, and then transmit the changes to the server, all without leaving the Ganymede GUI client. Note that you can't change the schema with the Ganymede GUI client, because the schema can't be changed when a user is logged in. If you want to change the schema, you'll have to be sure all users are logged out and use the standalone xmlclient. 73. [CLIENT] Fixed some threading issues that appeared in Iced Tea OpenJDK 7 The Ganymede client had some threading issues that appeared in the OpenJDK 7 packages that Red Hat ships with Fedora 8. I've slightly reworked a bit of the threading to try and avoid the issues. 74. [CLIENT] No longer prompt for persona if the user selected one in the login box The Ganymede client will no longer pop up the persona select dialog if the user specified a persona at login time, by logging in as 'username:persona name'. This is a nice little optimization that streamlines the login process a bit. 75. [SERVER] Added support for Sha Unix Crypt password hashing in DBPasswordField We have added support for the new SHA256 and SHA512-based 'Unix Crypt' hash algorithms introduced by Red Hat, Sun, IBM, and HP. A discussion and link to the specification for this algorithm can be found at http://people.redhat.com/drepper/SHA-crypt.html These new hash algorithms are intended for widespread adoption in a way that OpenBSD's bcrypt hash algorithm never achieved, while supporting scalable computational requirements to 'future-proof' the hash algorithm. 76. [SERVER] Removed user login and logout events from user history panel Previously, when you viewed the history of changes to a user object, you'd see a ton of login/logout events if that user happened to be a Ganymede administrator, or even an end-user change his password through Ganymede. We're not filtering out this event spam from the retrieveHistory method on the DBLog, so that it will be easier to see actual changes committed against a user object. 77. [SERVER] Rewrote logscan.pl external log scan accelerator The external logscan.pl log scanning accelerator has been re-written to perform efficient date-bounded searches through the log file. Our own log file is now up over 80 megabytes, which is starting to get a bit long to grep through, which is all that logscan.pl really did before. The logscan.pl script is now much smarter, and takes lower and upper time bounds on the command line. If a lower time bound is provided, the logscan.pl script will actually perform a binary search through the Ganymede log file, seeking to find the first record that occurs after that point in time. The Ganymede DBLogFileController class has been amended slightly to interact properly with the new, smarter logscan.pl. If you're upgrading to a version of the Ganymede server more recent than Subversion revision number 7820, you'll want to be sure to update the logscan.pl script. The Ganymede server and the logscan.pl script are designed such that a newer Ganymede server will continue to work properly with an older logscan.pl, but moving to the newer logscan.pl will improve log scanning efficiencies significantly. 78. [CLIENT] Cloning viewable objects now allowed in the graphical client The Ganymede graphical client previously did not allow the user to clone objects unless they had the right to edit those objects. This was an unnecessary restriction that the client was imposing, and has been removed. Now, Ganymede will allow cloning any object so long as the user has the right to view the object to be cloned, and the right to create new objects of that type. 79. [EVERYTHING] ReturnVal amended for ease of use The ReturnVal class has been altered to provide greater programmatic ease of use, and to simplify internal logic in the Ganymede server. Most adopters of Ganymede will not need to concern themselves about the changes made to ReturnVal, save for the following: Most setter methods on ReturnVal now return 'this' rather than void, allowing Smalltalk-style method chaining.. e.g., you can now do things like ReturnVal retVal = new ReturnVal(false); return retVal.setErrorText("Oops, we failed").addRescanField(objId, field.getID()); when you want to modify and return a ReturnVal object, rather than ReturnVal retVal = new ReturnVal(false); retVal.setErrorText("Oops, we failed"); retVal.addRescanField(objId, field.getID()); return retVal; Because the setter methods on ReturnVal now return a ReturnVal object, rather than void, plug-in code that was previously compiled against the Ganymede libraries will need to be recompiled in order to be compatible with this change. Otherwise, a 'NoSuchMethodException' may be thrown at run time when plug-in code is called which was compiled with versions of Ganymede prioer to Subversion repository version 7845. For convenience's sake, the ReturnVal class has four new static methods which perform the proper null check as part of their operation, reducing the necessity for the constant if (retVal == null || retVal.didSucceed()) idiom. Now, one can say if (ReturnVal.didSucceed(retVal)) to achieve the same effect. The four new static methods on ReturnVal are static public boolean didSucceed(ReturnVal retVal); static public boolean hasTransformedValue(ReturnVal retVal); static public boolean isDoNormalProcessing(ReturnVal retVal); static public boolean wizardHandled(ReturnVal retVal); The biggest change to ReturnVal which assists in the internal logic of the Ganymede server is the addition of the static ReturnVal.merge() method, which can be used to intelligently combine the results from multiple ReturnVal-returning operations, preserving and/or combining the important bits of each as processing continues. The Ganymede server has been converted to use this throughout, and benefits from simplified and more regular processing logic in the DBField subclasses. Note that in conjunction with this new merge logic, the single parameter ReturnVal constructor behaves a bit differently than it did previously. Before, a ReturnVal object created by calling result = new ReturnVal(true); would create a ReturnVal for which result.success is true, and for which the doNormalProcessing propery is _false_. Now, either of the following result = new ReturnVal(true); - result = ReturnVal.success(); result in a ReturnVal that has both success and doNormalProcessing set to true, and result = new ReturnVal(false); results in a ReturnVal that has success and doNormalProcessing set to false. This change will generally only affect you if you have written custom wizard code, but as the semantics of the single parameter ReturnVal constructor are different now, I recommend taking a look at your code to see whether something was previously depending on the doNormalProcessing flag being set to false on a 'new ReturnVal(true)'. 80. [CLIENT] GUI improvements in the StringSelector object Gil Kloepfer asked if the StringSelector object (the GUI component used in the client for dealing with lists of Strings or Invids) could be made to take up less space when the field connected to it had no data in it. That is, rather than taking up the equivalent of 12 lines of text in height, Gil wanted an empty String or Invid vector field to only take up a few lines of text worth of height unless and until such time as more data was put into such fields. I have modified the StringSelector class to do this properly. Now, the Ganymede client will only allocate a few lines of vertical space for empty StringSelector objects (enough to maintain the visual familiarity of the component), and will automatically grow as needed until it reaches the size we were previously using. 81. [SERVER] Reduced automatic field rescanning Previously, the Ganymede server was ordering the Ganymede GUI client to rescan fields every time they were edited by the client. This involved an unnecessary extra round-trip call to the server after every field modification performed by the user. Now, the Ganymede server is a bit more picky, and only orders a rescan if the server code performed a value transformation on the submitted value (see change 2.0 #52, above). This improves performance, and will allow the StringSelector to properly highlight newly entered strings when a choice list is not forced on the user. 82. [SCHEMA] Gasharl schema DHCP support tweaked The Gasharl schema code shipped with Ganymede has been elaborated a good bit to support per-host and per-group custom DHCP boot options. The arlut.csd.ganymede.gasharl.systemCustom and arlut.csd.ganymede.gasharl.dhcpGroupCustom classes include useful code that you might want to look at if you find yourself wanting to support cloning of objects that themselves contain embedded objects. 83. [SERVER] Improvements to mail thread reliability We had an incident in which the mailer thread in the Ganymede server got stuck trying to read from a socket from an SMTP server that was having some issues. I've set SO_TIMEOUT on the mailer socket to help out the mailer thread, which will now interrupt socket reads if an individual socket read takes longer than 15 seconds to complete. In addition, various small tweaks to the SMTP handling logic in the Qsmtp class have been made to make Ganymede more compliant with SMTP. 84. [CLIENT] Ganymede client displays basic information about concurrent use The Ganymede client will now display a little message showing how many users are logged into the Ganymede server. Whenever any user commits a transaction (causing the build icon to start animating), a message will appear for a short time identifying the user who made the commit. This change is intended to provide a bit more context for Ganymede users, so they can get a better idea if other administrators are making changes at the same time they are. (This actually went into the Ganymede repository a little while ago, but I had neglected to mention it in CHANGES previously.) 85. [SERVER] Added a ctrl-C handler to allow for clean shutdown upon kill It turns out that Java 1.3 added support for the java.lang.Runtime.addShutdownHook() method, which allows a Java process to register a thread to be invoked in response to ctrl-C/kill. I've taken advantage of this mechanism to allow Ganymede to do a clean shutdown on ctrl-C/kill. This will help us make sure our logs are flushed and any email is drained. kill -9 on the Ganymede server process will still terminate unconditionally of course, if that is required. I hadn't known that Java had this feature, until we started working with JBoss and saw that it was doing this somehow. 86. [CLIENT, ADMIN CONSOLE] Persisted the look and feel selection The admin console and graphical client now remember what look and feel a user last chose on any given system, and automatically re-instates the desired look and feel at startup. 87. [CLIENT] Added a reset button to the calendar widget The popup calendar widget now features a reset date button, which can be used to revert the calendar to the date that was originally set in the calendar. Useful for editing dates in object data as well as for setting the start date for object and admin persona history in the history panels. 88. [EVERYTHING] Reworked the build process for Ganymede to make it require Java 5 As of 7 July 2008, we're going to go ahead and make Ganymede dependent on Java 5, so we can take advantage of some new features in Java 5, most especially the defaultUncaughtExceptionHandler mechanism. Going forward, we'll bring Java 5 features into Ganymede as seems best appropriate. 89. [SERVER] Refactored DBNameSpace classes Gil reported a bug with concurrent xmlclient activity that was capable of confusing the Ganymede object store's namespace system. We have now rewritten the DBNameSpace classes top to bottom. We fixed some unsynchronized operations so as to prevent race conditions, and improved collision detection logic in several respects. Users may notice that the memory loading for DBNameSpaceHandle class has been reduced somewhat, as well. -------------------- Changes from 1.0.11 to 1.0.12 ------------------- RELEASE DATE: March 1, 2004 1. [CLIENT] Properly update StringSelector count display on manual item entry The StringSelector widget used to manipulate vectors of strings and object references in the client was not properly updating the item count when an item was manually entered through the text box. 2. [SERVER] Fixed regression in object event label display I had neglected to edit the objectEventCustom.java class to cohere with the change described in CHANGES 1.0.11#8. 3. [SERVER] Fixed exception vulnerability in admin console, scheduler code We had an occasion in which the Ganymede scheduler terminated during the server's normal operations, as a result of cascading failure in the admin console notification system. The changeStatus() method in serverAdminProxy was not properly checking the done flag, so a NullPointerException was thrown where the GanymedeAdmin code was only expecting the possibility of a RemoteException. The NullPointerException was being thrown up through the Ganymede.debug() call frame, which led to the scheduler being killed. I have fixed the serverAdminProxy.changeStatus() method so that the NullPointerException will not re-occur, and I have fixed the Ganymede scheduler so that nothing but an actual interrupt on the scheduler thread will cause the scheduler to terminate. 4. [SERVER] Turned off extraneous debug output from XML processing logic I had accidentally left the debug flag enabled in the xmlobject and xmlfield classes, which caused a lot of extra output to be displayed when processing XML files through the xmlclient. 5. [SERVER] Removed 1.4-only StringBuffer method usage from DBEditObject.java It turns out that java.lang.StringBuffer gains a method overload that executes special code in the event that the parameter passed to append is itself a StringBuffer. When I compiled the Ganymede code with a 1.4.1 JDK, code that previously was interpreted to have an implicit toString() method call now uses the optimized StringBuffer call, which doesn't exist in JDK 1.3 and earlier. Putting the toString() in explicitly forces javac to use the String parameter method, which is present in all versions of the JDK. This fix should make it possible to run the Ganymede server on JDK 1.3.1 or earlier again. Thanks to Maura Mathieu (maura.mathieu@sdis66.fr) and Kent Wick (kent.wick@mhmr.state.tx.us) for reporting this. 6. [SERVER SCRIPTS] Fixed RMIGC definition in runServer for ksh Per Kent Wick, the RMIGC definition in the runServer templates has been surrounded by single quotes. 7. [SERVER] Preparations for logging to PostGreSQL The Ganymede log classes have been reworked in preparation for supporting SQL databases for log event storage and retrieval. 1.0.12 is not SQL-ready, quite, but I've done some refactoring to allow for a variety of DBLogController implementations. I've implemented a DBLogPostGreSQLController class for logging to PostGreSQL with an appropriate schema, but I'm not including the appropriate support files necessary for initializing the database and what-not. Next release if all works out well. 8. [SERVER, CLIENT] Reworked client and server to support direct login In all previous versions of Ganymede, the login process is a two-step dance.. first the client (GUI or xmlclient) calls up the appropriate login method on the server, passing a reference to a callback object hosted by the client, then the server uses that callback object to query the client or xmlclient for username and password. I initially did this (6-7 years ago) to throw a (vanishingly small) roadblock into the path of people trying to packet sniff the login process, and so that people wanting to do a replay attack would have to emulate the full RMI protocol. This was really always complete silliness, of course. Despite that, I had no real motivation to rework the login process until David Cummins reported that he was unable to use the Ganymede client from his firewalled desktop systems. Given the increasing prevalence of defensive firewalling on the local system level, it seemed like it was time to rejigger the Ganymede login process. Users of a locally firewalled system will now be able to log in and use Ganymede, but the experience will still be second rate.. the server won't be able to send any build status messages to the client, and if the server needs to timeout or force disconnect the client, the client won't get the message. NOTE: One side effect of this change is that certain methods in the Ganymede server are now marked as throwing a 'NotLoggedInException' condition. If you have custom code that calls any of these methods, you may see build problems when you go to rebuild your code for use with Ganymede 1.0.12. Surrounding the offending calls with an appropriate throw..catch clause should be all you need to do to make your code compatible with 1.0.12. 9. [CLIENT] Improvements to text messages in dialogs The common composite dialog class used in the Ganymede client and admin console has been improved to support adaptive word wrapping and scrollbars. This change was motivated by the client's new ability to report remote exception traces in a dialog. 10. [CLIENT/CONSOLE/SERVER] Reworked RMI API to be system firewall transparent This is an extension of the 1.0.12#8 work. It used to be that the server used RMI calls to the client and admin console to send notification for build status and force off (on the client) and all of the data displays on the admin console. The problem with this is that it required the client/console to open a socket and wait for an RMI call from the server to send update information. I have now reworked the server, client, and admin console so that all transmission of data from the server to the client is done by having the client/console run a polling thread which repeatedly calls an asynchronous message port on the server. Since the data is flowing through the result of a forward RMI call, no socket needs to be opened up for listening on the client/console system, and full functionality is achieved even in the presence of a client-side system/personal firewall. This change also speeds up login and noticeably reduces the memory loading on the server. A win/win/win deal. 11. [CLIENT] Fixed gclient.getObjectHandle() The getObjectHandle() method in the client's gclient class didn't properly deal with an empty list back from the GanymedeSession's queryInvids() method. This could result in an exception being thrown rather than a dialog being shown in certain circumstances in the client in which a user tries to edit an object reference that he doesn't have permission to edit or view. 12. [SERVER] Improved namespace conflict message The DBField class in several places had code to report namespace conflicts. Created a common method to generate a more detailed error dialog which informs the user what object/field is conflicting. 13. [SERVER] Cleaned up DBObject.getTypeName()/getTypeDesc() The DBObject class had two methods, getTypeName() and getTypeDesc() which did exactly the same thing. Embarassing. I went through and changed all instances of DBObject.getTypeDesc() to DBObject.getTypeName() calls, in keeping with the db_object interface. 14. [CLIENT] Added row count indicator to query window In response to a so-simple-it's-brilliant suggestion by David Cummins, I have tweaked the Ganymede client to display a count of the rows returned in the title bar of the client's query results window. 15. [CLIENT] Various tweaks for better behavior under JDK 1.5 beta I've made some slight tweaks to the client and console's GUI layout to improve behavior when running under the JDK 1.5 beta. This includes modifications to the JNLP launch files in webforms so that the user will be given the option of using versions 1.2 through 1.5 of the Java runtime. -------------------- Changes from 1.0.10 to 1.0.11 ------------------- RELEASE DATE: December 9, 2002 1. [SERVER] Put safety interlock in DBEditSet.addNewObject() The DBEditSet class had a vulnerability that could conceivably cause transaction corruption if an adopter wrote custom code that attempted to pull new objects in to the transaction in a custom DBEditObject classes commitPhase2() method. Now addNewObject() will throw a RuntimeException() if someone attempts to pull new objects into a transaction during the transaction's commit() process, causing the transaction to cleanly abort. 2. [CLIENT] Made the Ganymede login applet show the server name Added information on the login box about the location of the Ganymede server that the client has bound to. 3. [SERVER] Added new ganymede.subjectprefix property to the server.properties file The server now supports a new server property, entitled 'ganymede.subjectprefix'. If this property is set to a string that begins and ends with single quotation marks, the text included between the single quote marks will be used as the identifying subject prefix for email sent by the Ganymede server. If no such server property is defined, the server will use 'Ganymede: ' as the subject prefix. 4. [SERVER] Fixed GanymedeSession addResultRow(), internalQuery() to honor editableOnly query filtering The query logic in GanymedeSession has always been grotesquely over complicated, and it turns out that there has been a significant error in the addResultRow() method, which was neglecting to filter out non-editable objects from queries that specifically request that non-editable objects be filtered, in the case that GanymedeSession.internalQuery() was used to execute the query. In addition, the addResultRow() logic in the old non-supergash, non-internal case was confused and confusing, so I cleaned that up a bit as well. I have swept through my code looking for instances of internalQuery() usage, and I have made sure that all queries supplied to internalQuery() in non-supergash sessions explicitly turn off the editableOnly restriction. This involved some changes in the schemas/gasharl/custom_src code. 5. [SERVER] Modified DBObject.checkRequiredFields() to check all fields The checkRequiredFields() method in DBObject was only checking the custom-specified fields, rather than all fields. This made it impossible for a DBEditObject plugin's fieldRequired() method to enforce field requirements for the expiration and removal fields. 6. [SERVER] Optimized XMLReader and serverAdminProxy slightly Reworked both XMLReader and serverAdminProxy classes to use an efficient circular buffer rather than continually doing System.arraycopy operations within a Vector. Won't make any noticeable difference, but after seeing Doug Lea's optimized concurrency structures (at http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html), I felt like tinkering. 7. [SERVER/XML] Fixed feedback on transaction failure in the xml subsystem The Ganymede server's XML transaction logic was faulty, and would attempt to report a successful commit even in the circumstance where the commit-time transaction verification logic caused the transaction to be rejected. Now, an xmlclient transaction that could not complete due to consistency problems during transaction commit will no longer report a confusing mix of success and failure messages. 8. [SERVER] Changed plug-in API for object labels The Ganymede object model has always had a rather poorly thought out implementation of object labeling, with two separate means of expressing object labels. The first was by designated label field, the second was by calculated label field using the DBEditObject plugin's getLabelHook() method. There were a number of problems with this. First, the Ganymede query engine completely ignored getLabelHook()-derived labels, and if an object type had both a designated label field and a getLabelHook() method in a DBEditObject plugin, the getLabelHook() was used for many but not all things.. querying on an object's label simply ignored the getLabelHook() method's output and searched on a label field if defined, or simply failed if no label field was assigned. Now, the Ganymede query engine will check the new useLabelHook() method for a plugin, and if that method returns true, the label field will be ignored in queries, in favor of the results from getLabelHook(). To prevent things from being too confusing, the DBObject getLabel() method will now also consult the new useLabelHook() method, and if useLabelHook() does not return true, the getLabelHook() method will simply not be used under any circumstances. 9. [SERVER] runServer now specifies less frequent full-heap GC Since 1.2, Sun's HotSpot JVM (server-mode) has incorporated generational garbage collection, which allows the JVM to perform limited-scope garbage collection passes over recently created objects relatively frequently, while avoiding full heap garbage collection passes unless and until the full heap as a whole is filled. This allows the CPU loading due to garbage collection to be dramatically reduced, relative to a more naive full-heap garbage collector. Unfortunately, the Ganymede server has in the past not been benefitting greatly from generational garbage collection, due to a peculiarity of the RMI system. By default, RMI programs that access remote objects (as the Ganymede server does to asynchronously send messages to the admin console and to the gui clients) do full-heap garbage collection on a periodic basis (once a minute) in order to quickly release any remote RMI objects. This extra garbage collection activity is useless for the Ganymede server, as by design it will never relinquish references to the few remote objects it talks to until such time as the client or admin console disconnects/quits, whereupon the issue of client-side local garbage collection becomes moot. I've recently become aware of an RMI system tuning parameter for recent JVM's which allows this RMI full-heap gc interval to be tuned. I have edited the runServer script in the Ganymede distribution to set this tuning parameter to do full-heap gc once an hour. Previously, our Ganymede server was taking around .5 seconds every minute doing the full-heap GC cycle, now this overhead is only done once an hour, at the cost of a rather greater proportion of the server's allocated heap size 'in-use' on average. All of this is documented in the new runServer script, and this parameter can be tweaked as you like. See http://java.sun.com/docs/hotspot/gc/ for complete details. 10. [CLIENT] Several small improvements to the Ganymede user interface You can now hit enter after typing a search value in the query box and the query will be submitted for you. This should save people from having to mouse down to the 'submit' button for each query. You will still need to manually mouse down to the 'add choices' box if you want to add an additional search constraint. In addition, if a query returns no results, you'll now have the option to pop the query box right back up, revise your query, and resubmit. The GUI widget used for changing passwords in Ganymede will now provide a quick dialog box telling you that you didn't type the password the same way twice, rather than silently clearing the fields and having you try again without any guidance as to why. Thanks to Marcus Walker and Tom Embleton for these suggestions.. I hope the changes I made help out. 11. [SERVER] Improved logging for newly created objects I slightly reworked the commit_createLogEvent() method in DBEditSet so that newly created objects will use DBObject.getPrintString() to create a full summary of the newly created object, as is done when such objects are deleted, rather than using the DBEditObject.diff() method. This has the advantage that newly created objects which contain embedded objects will include full information on the embedded objects. 12. [SERVER] Reworked ownership inheritance The support in GanymedeSession's recursePersonaMatch() method for recursing up the ownership tree to find matching personas was broken in the case when an owner group contained no members. In such cases, the upwards recursion stopped inappropriately. This was a pretty major logical error, and one which has left support for the Ganymede owner group hierarchy broken for quite a long time. Upon looking at the code, I found a lot of gross stuff in the whole owner group permission handling logic. I went in and committed major surgery on the owner group code. The code is now simpler and less prone to security problems due to inappropriate caching. In addition, there may be a noticeable decrease in the time taken when a new object is created, as the owner group list calculation code is far more efficient now. 13. [SERVER] Tweaked object creation ownership behavior Previously, the Ganymede server would complain any time someone tried to create an object with more than one default owner selected. Ganymede will now allow this, but will complain if no owner list has been manually selected in the interactive case. Ganymede will now provide a warning if it had to pick an owner group at random to put a newly created object in when run with a non-interactive client. 14. [CLIENT] Added menu options to view object window, cleaned dialogs The view object window now has several menu options to allow editing, deleting, cloning, and inactivating of objects from the view object window. Cleaned up several dialogs in the code. -------------------- Changes from 1.0.9 to 1.0.10 ------------------- RELEASE DATE: April 2, 2002 1. [SERVER] Consistency checks should not be forced if 'enableOversight' not set We were having some problems with the nightly expiration task failing due to a consistency check failure unrelated to the actual expirations at hand. This was due to the default DBEditObject commitPhase1() method calling consistencyCheck() on each object involved in the expiration transaction, despite the expiration task's having elected to turn off enableOversight. Now, if the GanymedeSession's enableOversight flag is turned off, the default commitPhase1() method won't bother to run consistencyCheck(), and will simply return a positive success value. This comes in handy, as the nightly GanymedeExpirationTask runs with enableOversight turned off, so that we can allow object expiration/removal that would break a required field or other consistency guarantee if need be, rather than having the nightly task be blocked from committing its changes if anything would lead to a slight inconsistency. Note as always that the default DBEditObject commitPhase1() method can be overridden with custom logic if it is not desireable to have any consistency checks skipped in response to the enableOversight flag being reset. See the next item for more. 2. [SERVER] Made default transaction commit-time consistency check smarter Previously, the default DBEditObject.commitPhase1() method rejected a commit if the object's consistencyCheck() method failed. Now, commitPhase1() goes a step further, and only returns a failure code if the object's consistencyCheck() fails, and the consistencyCheck() succeeds for the original version of the object going into the transaction. That is, if a user is processing a transaction and happens to involve in his working set an object which was previously inconsistent, we won't hold it against him and force him to correct the previously existing inconsistency. Instead, we will depend on the GanymedeValidationTask to detect such conditions for a knowledgeable admin to fix, see the next item. 3. [SERVER] Improved GanymedeValidationTask to run consistencyCheck() The GanymedeValidationTask scans through the database checking objects for consistency. Previously, however, the only check this task was performing was to see if any required fields were missing. Now, the GanymedeValidationTask will also call consistencyCheck() on each object, allowing inconsistencies that have creeped in from transactions run with enableOversight turned off to be easily detected on demand. 4. [SERVER] Turned off passive password capture Turned off passive password capture. Ganymede stores passwords in a variety of hashed forms, which are strings that can be used for validating a password but not which can't reveal the actual text of the password without the use of a brute-force encryption search. Plaintext is never saved on disk unless the password field is specifically configured to do so in the Ganymede schema. Things like sync'ing passwords to Windows NT which require plaintext passwords have to obtain them from temporary storage in the Ganymede server. Formerly, whenever a user logged into Ganymede, Ganymede would temporarily acquire and retain the plaintext used to login to Ganymede in RAM only. This plaintext could then be passed to Windows NT for synchronization. In this way, users would not necessarily have to change their passwords in order for their account to be sync'ed. Unfortunately, it turns out that the password identity validation is not perfect. A UNIX password hashed using the traditional Unix crypt() routine is only significant to 8 characters. If a user logged into Ganymede for the first time since the Ganymede server was restarted with a mistyped version of their password that was correct to 8 characters but then diverged in the ninth, Ganymede would remember the incorrect plaintext, and insist on seeing it again before allowing the user to login until such time as the server was restarted, and the plaintext password information was lost. Worse, such carelessly entered passwords could get propagated to our Windows NT domain controller in their erroneous form, and Windows NT's password hashing is significant to 14 characters. This is not a reasonable or tenable situation, so the passive plaintext password capture logic has been disabled. 5. [SERVER] Better error message on link permission failure The Ganymede server will now explicitly report a permissions problem when an attempt is made to link to an uneditable object. 6. [SERVER] Re-enabled optional mailout event logging I had disabled logging of mailout events, to keep the Ganymede log from being flooded by non-critical email sent out by the Ganymede server. Unfortunately, the inevitable question arose here about whether Ganymede did or did not send out an email message warning about an upcoming account inactivation. Having a log of all advisory email sent out by Ganymede would have helped clarify the situation, so this function is being added back to the Ganymede server as an optional logging facility. Now, if the Ganymede server's ganymede.properties file defines a ganymede.maillog property, the file named in that property will have all mailout events logged to it. If the ganymede.maillog property is not set, no mail events will be logged on disk. By default, the server's ganymede.properties file is installed with no ganymede.maillog property defined. If you are using a schema kit that sends out a lot of mailout events, you may only want to enable mail event logging for short periods as a diagnostic. As with all properties defined in the ganymede.properties file, the server must be stopped and restarted for any changes in the properties file to take effect. 7. [SERVER] Improved logging/email for embedded object modifications All informational logging of changes made to embedded objects now includes the name of the top-level object which holds the embedded object. For our usage, this makes it possible to tell what system was involved when an interface definition was changed. 8. [SERVER] Clean ups and optimizations to the admin console handling I found that there was some really ugly code in the GanymedeAdmin class that handles communications to and from attached admin consoles. I substantially reworked this class for better encapsulation, and while doing so wound up removing an extra RMI call that the server was attempting to make to each admin console for every line of log information sent to the console. The serverAdminProxy was eliminating a lot of these calls if lines of logging information were being sent rapidly to the admin consoles, but there was no need to have the server attempt to send so much unnecessary data to the attached admin consoles. 9. [SERVER] Shutdown sequence refinements In the process of doing work for #8, above, I introduced a class cast exception into some of the admin console code that resulted in the server getting stuck during shutdown. In fixing this, I revised the shutdown sequence to be more verbose and to ensure that arbitrary exceptions thrown late in the server shutdown process won't prevent the server from exiting. 10. [CLIENT] Cleanups to the GUI calendar widget I did a cleanup job on the JpanelCalendar class, to make the thing easier to read and maintain, and to improve its layout in the face of window sizing. When viewing, rather than editing, objects' expiration and removal date fields, the client will now show a full-size, display-only calendar rather than the cheap text label that it used to show in that circumstance. When editing these fields, the old label showing what the expiration/removal field was set to in the calendar panel can now be used to jump the calendar back to the calendar page containing the selected time. 11. [SERVER/XML] Liberalized the server's behavior with xmlclient deletions The server was previously rejecting any XML transaction that attempted to delete a non-existent object. Now, the server will merely transmit a warning to the xmlclient that an attempt to delete a non-existent object was attempted, without completely rejecting the valid deletion commands. This change was made in response to a comment by Gaurav Bhargava at Villanova University. 12. [SERVER] Fixed slight inconsistency in object link logging The Ganymede server's logging and email notification logic had a small inconsistency in it. When logging changes to invid (object reference) fields, the Ganymede server logged old values removed using the label for those objects that pertained at the end of the transaction in question. If an object's name changed during the transaction due to other editing, something like the following would be logged: objectchanged ------------- I.P. Network ATL - Outgoing Inet Access Only, <267:96> was modified. Fields changed: Records Deleted: [10.5.16.132 - 08:00:20:9a:16:f2] objectchanged ------------- I.P. Network ADG/OMG - Outgoing Inet Access Only, <267:79> was modified. Fields changed: Records Added: [10.5.16.132 - 08:00:20:9a:16:f2] objectchanged ------------- System corona's Embedded System Interface, '[10.5.16.132 - 08:00:20:9a:16:f2]', <265:970> was modified. Fields changed: I.P. Address Old: 10.8.16.186 New: 10.5.16.132 Ethernet Info Old: 8-0-20-9a-16-f2 New: 08:00:20:9a:16:f2 I.P. Network Old: ATL - Outgoing Inet Access Only New: ADG/OMG - Outgoing Inet Access Only In this case, the 'Records Deleted' part of the 'ATL - Outgoing Inet Access Only' objectchanged log entry is showing the new name for the interface that was deleted, even though when that interface was in the ATL network, it had a different name. This has been changed so that whenever an object is removed from an invid field, the removal will be logged using the object's name as of the start of the transaction. This would make the above logging sequence look like this: objectchanged ------------- I.P. Network ATL - Outgoing Inet Access Only, <267:96> was modified. Fields changed: Records Deleted: [10.8.16.186 - 8-0-20-9a-16-f2] objectchanged ------------- I.P. Network ADG/OMG - Outgoing Inet Access Only, <267:79> was modified. Fields changed: Records Added: [10.5.16.132 - 08:00:20:9a:16:f2] objectchanged ------------- System corona's Embedded System Interface, '[10.5.16.132 - 08:00:20:9a:16:f2]', <265:970> was modified. Fields changed: I.P. Address Old: 10.8.16.186 New: 10.5.16.132 Ethernet Info Old: 8-0-20-9a-16-f2 New: 08:00:20:9a:16:f2 I.P. Network Old: ATL - Outgoing Inet Access Only New: ADG/OMG - Outgoing Inet Access Only This misfeature was reported by Gil Kloepfer, here at ARL. 13. [CLIENT] Put warning dialog up when editing inactivated objects A good number of admins here at ARL have ran into problems when they tried to manually edit inactivated users, rather than using the reactivation function that is available on the object tree right-click menu for inactivated objects. The problem is that most admins here just set the password and commit the transaction, without realizing that they need to clear the Removal Date field. Our server is configured to provide a 'reactivate' wizard when users use the right-click reactivation function, but users too often don't realize or remember that that function exists. In response to this, I have implemented a dialog box which will pop up if an admin attempts to edit an inactivated object, prompting the user to attempt to use the server's reactivation wizard rather than directly editing the object. This is pretty clean, but this will put more pressure on schema kit developers to insure that if they want an object type to be able to be inactivated rather than simply removed, they really will need to provide a reactivation function. 14. [CLIENT] Synchronized the transaction cancel button to avoid exceptions The gui client now synchronizes its cancel button, to ensure that all object windows (which load data from the server on their own threads) have stopped loading before the client tells the server it wants its transaction cancelled. Previously, some of the client's loading threads could briefly race, continuing to try and call data loading methods on the server after the client's main GUI thread had already cancelled the transaction, which could cause the server to throw an exception down to the client. This change just serializes transaction cancellation on the client side a bit better. 15. [CLIENT, ADMIN CONSOLE] Miscellaneous GUI cleanups, improvements Quite a varied collection of small improvements in the GUI client and the admin console. In the client, the history panel now uses the OneTouchExpandable option in its splitter panel, and sets its initial size so all the historical fields are visible. The expiration and removal tabs now show the appropriate icon from the tree when they are present. This will hopefully make it less likely that users will miss noticing that these tabs are present when editing certain user accounts. The client's vertical splitter supports the OneTouchExpandable option as well, making it possible to entirely hide the tree if more space is needed for showing object windows. The admin console's layout has changed very slightly, with a splitter bar added between the log panel and the bottom status tables panel, and the 'clear log' button removed and put in the Control menu, where it won't take up screen real estate. 16. [SERVER] Better exception handling in checkpointed code The object linking code was not properly catching exceptions that might be thrown by plug-in code, and so certain object linking and unlinking operations could leave checkpoints on the server's checkpoint stack. Due to the thread identity checking logic in the DBEditSet checkpointing routines, this could cause a session on the server to refuse any further checkpointing, causing the user to have to cancel the transaction. Now, if any user-level code throws exceptions during object linking or unlinking, the checkpoint stack will properly be cleared. This is in response to a bug report by Gil Kloepfer. 17. [CLIENT] Fixed the clients' failure to terminate on window closure The gui client and admin console were not properly terminating the JVM when the clients were run as applications rather than applets, and the user closed the window using the operating system controls rather than the 'quit' button. The login box will now properly terminate the JVM if the close window button is used. This is in response to a bug report by Gil Kloepfer. 18. [SERVER] Cleanups and refinements to DBEditSet class The transaction commit() method code in DBEditSet has been radically reworked. The biggest part of this reworking is a simple refactoring to make the code far simpler to read, but a number of reliability improvements were made in the process, and a few extremely unlikely yet nonetheless possible security race conditions were fixed. In addition, a lot of DBEditSet member fields have been made private, and special accessors have been added and method calls altered where needed to allow for interaction with other classes. 19. [SERVER] Slight API change for DBEditObject subclasses Previously, the DBEditObject class held a 'committing' boolean flag that needed to be set and cleared in specific methods in order to coordinate field locking during the transaction commit process. The problem is that access to this boolean flag was unsynchronized, making it possible in theory for a system running the Ganymede server with multiple threads on multiple CPU's to allow changes to be made to fields after the commit process has started for a given object. This race condition is extremely unlikely, as it would depend on a system having a non-coherent memory access model in the absence of specific object synchronization, but the Java Language Specification does allow for such implementations. In any case, the committing boolean has been replaced by an arlut.csd.Util.booleanSemaphore object, and made private. Subclasses of DBEditObject which override commitPhase1() and/or release() should now use the DBEditObject setCommitting() method to set or clear that flag. None of the custom object plugins or schema kits that we have provided overrided those two methods, so I think it'll be unlikely that this API change will affect people, but if you are not able to recompile your schema kit and/or plugins with this version of the server, you may need to look at this issue. 20. [SERVER] Shutdown Expedited The GanymedeBuilderTask base class will now inhibit any builder tasks from running at all once a server shutdown command has been issued. Previously, the server shutdown process only blocked phase 2 builds. This change makes it so that the server won't bother trying to write out data files that it won't do anything with before shutdown. 21. [SERVER, ADMIN CONSOLE] Added support for Apache md5 hash format The Ganymede PasswordDBFile class now has support for working with passwords hashed using the variant Md5Crypt() algorithm that the Apache web server supports for its htpasswd files. Implementing this support involved changes to the Ganymede database file format (now up to file format 2.4), along with changes to the RMI interface definition for the schema editor and for the password field interface. Because of these changes, Ganymede 1.0.10 will not work properly with an admin console or client from Ganymede 1.0.9 or earlier. -------------------- Changes from 1.0.8 to 1.0.9 ------------------- RELEASE DATE: December 4, 2001 1. [SERVER] Fixed xml parser error introduced in 1.0.8 The server side XML parsing code in Ganymede 1.0.8 had a major bug. The 'addIfNotPresent' vector field mode was made the default, but support for handling the addIfNotPresent mode was not implemented for invid vector fields. Loading data into invid vector fields silently failed. This has been fixed, and the xml file processing now works properly for all kinds of vector fields. In addition, the server's xml code now reports whenever it sees an element that it is not able to resolve during the data consolidation phase. Apologies to all and thanks to Gaurav Bhargava at Villanova University for reporting this brown paper bag bug. -------------------- Changes from 1.0.7 to 1.0.8 ------------------- RELEASE DATE: November 16, 2001 1. [SERVER] Fixed Invid, String, IP array fields disk i/o to handle large arrays The InvidDBField, StringDBField, and IPDBField classes support array values for object pointeers, strings, and IP addresses, respectively. Prior to this release, the length of these arrays were limited to 32k entries, as a 16 bit signed short was used to store the array length on disk. This has now been changed to a 32 bit signed int, so that Ganymede's disk format can now handle 2 billion items per array. That doesn't mean that the server will be able to behave well with 2 billion items in a String field, but there at least won't be an artificial cap of 32k items anymore. This will be especially valuable in that owner groups will no longer be limited to 32k items per group. This is an incompatible change with versions 1.0.7 and earlier of the Ganymede server. ganymede.db and journal files written by Ganymede 1.0.8 and later won't be readable by Ganymede 1.0.7 and earlier. 2. [SERVER] Fixed scheduler to allow enabling/disabling of on demand tasks The Ganymede scheduler code to handle task enabling/disabling from the admin console had a bug that prevented it from being able to handle on demand tasks. This has now been fixed, and any kind of task should be able to be disabled. This can be useful if you want to commit changes to the Ganymede database without having the server trigger the builder tasks. 3. [CLIENT] Fixed exception in timed out querybox The querybox code was improperly retaining a reference to a client-side cache structure, making the re-use of the querybox impossible after the client was forcibly timed out. The querybox now takes care to get an updated reference to the caching structures it needs, so that re-use of the client querybox after a forced time out will not cause an exception to be thrown. 4. [SERVER/XML] Improved password importing support in the XML system The server's xmlfield code was missing support for processing the "lanman" and "ntmd4" XML attributes for the element in the Ganymede XML file format when loading data. This support has now been added, and it should now be possible to write scripts to load user accounts, passwords included, from a Samba password file. In addition, the XML client can now simultaneously load passwords in several hash formats, so if you already have a Samba file with LANMAN and NTMD4 password hashes along with your UNIX passwd file's crypt and md5 crypt passwords, you can load all four hashes into accounts in Ganymede at once. Ganymede obviously can't verify that the hashes match in this case, but if you already have been synchronizing passwords to different hash formats, this will let Ganymede support your accounts without requiring that your current passwords be available in plaintext. This entails a slightly incompatible change in the RMI API between the client and the server, so the Ganymede 1.0.8 and later xmlclients should not be used with a 1.0.7 or earlier server. 5. [CLIENT/SERVER] Fixed query filtering in Ganymede client and server The Ganymede client has for a long time had a (nonworking) 'Filter Query' menu option that was intended to allow users in many owner groups (including supergash) to set a filter so that only objects owned by a given list of owner groups would appear in the tree. It works now, but it's a touch inelegant. Ultimately, the answer to overloading in the tree is to force a hierarchical data representation, but until such time as we can rework the Ganymede data model that deeply, you can apply and clear owner filters using the "Set Owner Filter" menu item from the client's File menu, and the tree and object choice lists in objects being edited will be dynamically updated. Voila, 'supergash' level power while still being able to 'drill down' on a reasonable subset of the server's data. This entails a slightly incompatible change in the RMI API between the client and the server, so the Ganymede 1.0.8 and later clients should not be used with a 1.0.7 or earlier server. 6. [SERVER] Fixed nullPointerException throw on empty regexp string Fixed a couple of places in DBQueryHandler that could result in a null or empty string being passed down to the gnu.regexp.re constructor. 7. [XML/SERVER] Improved semantics of XML vector field handling Previously, the default mode for vector fields in Ganymede's XML support was "add". That is, the following XML snippet will cause "jonabbey" to be added to the Aliases field in the broccol user object. This is true even if "jonabbey" was already listed in the Aliases field. Now, a new vector field mode has been added, "addIfNotPresent". This mode will now be the default when a vector handling mode is not specified. In other words, the above snippet is equivalent to Note that "add" mode for Invid fields was always handled as if it were "addIfNotPresent", as the InvidDBField.addElements() method automatically filters out duplicates. I have updated the XML docs to reflect this change. In addition, the mode can now properly be used to remove redundant copies of strings from a vector string field.. this did not work properly before. In other words, if we have an object with the following values then will properly remove one of the "jonabbey" strings. Before, the XML field handling logic simply saw that the "jonabbey" string was already in the vector (at least) once, and so didn't bother to remove the redundant copy. 8. [ADMIN CONSOLE/SERVER] More fixes to prevent memory pinning with schema editor The admin console's schema editing code has continued to cause memory on the server to be pinned after the schema editor window has been closed. I've added a great deal of manual object dissolution and reference clearing to prevent memory pinning in the server. More importantly, the admin console's schema editor code now properly handles clearing the server-side schema editor context if the window is closed through the window system's controls rather than through the 'commit' or 'cancel' buttons. -------------------- Changes from 1.0.6 to 1.0.7 ------------------- RELEASE DATE: October 11, 2001 1. [SERVER] Deleted objects now have all of their fields logged The Ganymede server has not been logging the status of objects when they are deleted, which has made it in some cases impossible to determine what was in an object when it was deleted. In theory, today, all objects created in the server will be logged with their initial state as well as all changes made, but at ARL we had a great deal of objects that were imported using the old 'directLoader' hack, without any logging done. The real advantage to this for other users will not so much be for scanning the log file as it will be to make the object deletion email more informative. 2. [SERVER] Better error message on field creation failure The server now gives a better error message if a user tries to link an object to a (previously undefined) field that the user does not have permission to create. 3. [SERVER] Made sessions smarter about refusing to edit objects during commit The DBSession class has been modified to disallow editing of new objects during a transaction's commit or abort process. This is to help make sure that any code during the commitPhase1() and commitPhase2() DBEditObject customization methods that seeks to bring new objects into the transaction after the commit has already started will trigger a runtimeException, rather than silently confusing the commit logic. This change shouldn't have any effect on any code provided with the Ganymede distribution or the userKit, but might force an error in custom code if the customizers were doing some sort of dangerous activities during the commit process. 4. [SERVER] Amended wizard shutdown process The GanymediatorWizard class had a loophole that would cause wizards to not be unregistered from a GanymedeSession if the wizard's state had been forced to DONE outside of the GanymediatorWizard.unregister() method. This has been fixed so that any time a wizard goes through returns a success() or fail() result it will be unregistered. This fix took care of a bug in the laboratory's GASHARL schema kit operations, but is very unlikely to be affecting anyone out there unless you've done just the right (wrong) kind of custom schema coding. 5. [SERVER] Put loopback binding check into server startup The server now checks to make sure that it is not being bound to a loopback address on startup, which would prevent clients from being able to communicate with the server from remote systems. The server will now generate a message of the form ** Error ** Both the system hostname (hostname) and the ganymede.serverhost definition (hostname) resolve to the 127.0.0.1 loopback address The Ganymede server must have an externally accessible IP address or else clients will not be able to communicate with the Ganymede server from other than localhost. If you really want to be only usable for localhost, edit the runServer script to use the -forcelocalhost option. if the server is not able to figure out a hostname that will resolve to a network-accessible IP address. RedHat Linux 7 systems are particularly prone to this, as the default configuration for such systems includes the system's hostname in /etc/hosts as mapping to 127.0.0.1, and the system 'hostname' function returns by default a non-fully-qualified hostname. The combination of these two conditions resulted in the Ganymede server registering itself with the rmiregistry process as being on IP address 127.0.0.1. This change was in response to a problem report from Steve Lemons (steve.lemons@arrisi.com). 6. [SERVER] Objects in the process of being deleted may not be linked to The server's object binding logic had a bug which would allow an object which was being deleted to be improperly linked into an Invid field in another object. This occurred in a bit of custom code in the GASHARL schema kit where unlinking a remote object in a given context resulted in the object being deleted by the custom server-side code. The client, however, showed the unlinked object as a valid choice to be added back into the link field. If the user tried to put the (now deleted) object back into the field, the link was made, even though the object was marked for deletion when the transaction committed. This resulted in an Invid field containing an Invid pointer to an object which no longer existed, which is a bug. The server's InvidDBField logic is now smart enough to forbid linking to an object which has been marked for deletion by the transaction. This was a very obscure integrity violation vulnerability. The server and client have always cooperated in other ways to prevent this condition from arising. It was only due to some odd custom coding in the GASHARL schema kit that this vulnerability was revealed. 7. [CLIENT] Optimized out redundant network calls in the GUI client The Ganymede GUI client has been optimized to remove a great many redundant RMI calls when viewing objects on the server. The client can now display objects with only about half the RMI calls that the client used previously. This will speed up the client noticeably on slow network links, and will reduce loading on the server slightly. -------------------- Changes from 1.0.5 to 1.0.6 ------------------- RELEASE DATE: August 15, 2001 1. [SERVER, ADMIN CONSOLE] Fixed delayed memory release for schema editing The Ganymede server wasn't properly clearing references to a bunch of temporary data structures when a schema edit was cancelled by the admin console. This had the effect of increasing our server's memory footprint by a couple hundred kilobytes or so until such time as the admin console was stopped and restarted. 2. [WEBACCESS] Fixed ganypass.pl to allow < and > chars in passwords The ganypass.pl script, which provides a CGI interface to the xmlclient for changing users' passwords, was improperly failing to convert < and > to the XML entity escapes < and >, which could cause the server's XML parser to reject password changes that involved those characters. 3. [SERVER] Fixed several journal processing bugs Yowtch. Several nasty bugs that were lurking here. None of these bugs caused any problems if the server was shut down cleanly and restarted, but if the server was abnormally terminated, the following bugs caused problems during transaction recovery on startup. Firstly, the server had a bug that prevented successful startup if the server was killed without getting a chance to consolidate the database into a new ganymede.db file, and if one of the transactions in the journal file involved an deleted object that had one or more namespace-constrained database fields. This was due to an attempt to use Ganymede.internalSession before that variable was defined. This has been fixed by making the DBNameSpaceHandle.getField() method look up objects directly out of the DBStore tables without using a GanymedeSession, if needed. Thanks to Gaurav Bhargava at Villanova University for reporting this first bug. Secondly, there was a bad bug that caused transaction processing in the journal handling code to repeatedly process object records in the journal. The journal processing code was not clearing the entry vector at the end of each transaction's processing, which caused the server to do a lot of repetitive work and to generate misleading warnings about 'objects already deleted' in the object deletion case. Ugh. Thirdly, there was a bug, subtle in causation but HUMONGOUSLY AWFUL in effect, which caused the server to *eat* changed scalar fields when processing journal entries. This bug has been in Ganymede since 1.0pre1, when I moved field storage in DBObject to a packed hash as a memory optimization. The replaceField() code that edited the packed hash to replace fields with the versions noted in the journal transaction entries silently failed if it could not find the field it was looking for, causing the changed fields to be simply dropped on the floor. That's what I get for recklessly optimizing my data structures. Data loss bugs in Ganymede have been rare, thankfully, but this was an ugly one, and it bit me when I was testing the fixes to the first two journal bugs. My apologies if it bit anyone else out there. The good news is that I've cleaned up the journal loading code a fair bit, and that I have significantly improved the debug instrumentation in this section of the code. -------------------- Changes from 1.04 to 1.0.5 ------------------- RELEASE DATE: July 27, 2001 1. [DISTRIB] Fixed a number of bugs for JDK 1.4 compatibility Fixed a few places that assumed SimpleTimeZone.getDefault() would return an object of class SimpleTimeZone. Fixed the jar packaging to satisfy Java 1.4's slightly pickier serialization logic. Because of these changes, the Ganymede 1.0.5 server will not be compatible with clients from 1.04 or earlier. 2. [DISTRIB] Added support for using Java Web Start to launch clients Sun's excellent Java Web Start provides the best way yet to launch the Ganymede clients on Windows. I have made changes to installWeb to support the Java Web Start option in the Ganymede launcher. 3. [CLIENT] Fixed java.security.AccessControlException in client On some versions of the JDK, the client, when running as an applet, was refusing to allow changes to the animated build status icon in response to RMI callbacks from the server. This robbed the user of valuable feedback and resulted in java.security.AccessControlException messages being thrown on the server in response to the client notification call. I have added a new 'SecurityLaunderThread' to the client, which waits for build status messages from the server and updates the build status icon. Since the SecurityLaunderThread was started by the client and not by the RMI system, it has proper permissions to play with the Swing Event Queue, and everything works properly. 4. [SERVER, CLIENT] Reworked permissions handling for built-in fields The Ganymede server previously did not separately track permission to edit the "built-in" fields. That is, the permissions editor in the client did not allow per-field permissions to be set for the standard fields that are automatically present in every object, including the Owner List, Expiration Date, Removal Date, and Notes fields. Instead of allowing access controls for these fields to be set in the standard permission matrices in the Role objects, all of these fields were accessible with the same permission as the containing object itself. If a user had permission to edit an object, that user automatically had permission to edit these four system fields. This turned out to be a security hole, because there are many cases in which it is desirable to allow an object to be minimally editable by non-privileged users (so that end users can change their own passwords, for instance), where such users may not be trusted to edit the owner list, notes, expiration date, and removal date fields. The client's permissions editor and the server now allow explicit setting of permissions for the Owner List, Notes, Removal, and Expiration Fields. The four 'historical' fields used to track object creation and modification timestamps and admins are never allowed to be edited by the user, and so are still left out of the permissions editor. In the process of doing this work, a few potential vulnerabilities that might have been exploitable by a rewritten Ganymede client were closed. The Ganymede philosophy is that the server should not trust the client for anything, and a few security assumptions have now been made explicit. The server now makes several checks and forbids the granting of privileges that would be liable to break the Ganymede security model. For instance, non-privileged end users will never be allowed to edit the owner list field for objects, regardless of whatever permission for the Owner List field might be granted in the server's Default role. 5. [CLIENT] Improved GUI cleanup Miklos Muller reported that the client was leaving the permissions editor up if the server forced a client disconnect due to a timeout. I looked into things, and the code for handling resource cleanup on window close in the client was still very messy, despite Bug fix #11 for release 1.0, below. Things are a good bit cleaner in the client, now, and all popup permission editor windows should now be put away properly when the window that the permission editor was launched from is closed. 6. [DISTRIB] Changed numbering scheme I realized that if I have more than 6 more 1.0x releases, I'll suddenly be at 1.1, which I don't want to do by accident. So, we're going from 1.04 to 1.0.5. 7. [DOCUMENTATION] Added an upgrade guide, improved XML docs I've written a short upgrade guide that explains how to go about upgrading the server, schema kit, and clients when a new version of Ganymede comes out. I've also done a fair amount of rework of the xmlclient documentation. 8. [SERVER] Made the server use a default address for email if necessary The Ganymede server typically sends mail out for actions taken by admins on behalf of the admin's email address. That is, Admin Persona objects have an 'email address' field, and when the Ganymede server sends out mail in response to that admin's actions, mail from Ganymede is sent with the admin's address used as the 'From:' header. Previously, if Ganymede could not determine an email address to use for an admin, it would try to send mail out with a null return address, which caused the mail attempt to fail. Martin Vogt reported this bug, and the proper fix for it, back in March of 2000, but I didn't realize how likely this problem was to affect new users until I did some testing of a fresh install on a new system. 9. [SERVER] Fixed field/object permission interaction Previously, the GanymedeSession.getPerm() method filtered per-field permission bits against the permission bits for the object as a whole. This makes sense for the view and edit bits, as you can't view or edit a field if you can't view or edit the object it is contained in, but it does not make sense for the create bit, as it might well be appropriate to be able to create a new field in a pre-existing object that you can edit, even if you don't have the right to create a new object of the type. The server is now smart enough to avoid filtering the create bit for a field against the create bit for its object. -------------------- Changes from 1.03 to 1.04 ------------------- RELEASE DATE: July 9, 2001 1. [SERVER] Fixed NullPointerException thrown in XML Login path The Ganymede server's xmlLogin() method was throwing a NullPointerException if a user submitted an XML file through the XML client with an invalid username and/or password. The server now avoids having that exception thrown by explicitly checking the success of the username/password login before trying to construct a GanymedeXMLSession. 2. [CLIENT] Fixed date reversion in the pop-up calendar GUI component I fixed the pop-up calendar's reversion handling for when the user attempts to change the date/time in a date field and chooses a date that is out of range. 3. [CLIENT] Enhanced list GUI boxes in the client The client's JstringListBox and StringSelector components have had their behavior enhanced, with a 'select all' button added at the top of the StringSelector, and with the JstringListBox keeping all items added selected, to allow easy undo of item moves. The JstringListBox is now capable of supporting item dragging in the list. 4. [CLIENT] Enhanced query box The query box now uses a pair of StringSelectors to represent the list of field choices rather than a bunch of checkboxes. 5. [SERVER] Fixed namespace constraint handling during schema editing Previously, it was possible during schema editing to set a namespace constraint on a field that contained data in violation of that constraint. Now the schema editor will not allow any schema edits to be made that would allow a namespace constraint to be placed on a field that contains data in violation of such a uniqueness constraint. With this change, it should now be impossible to put the server into a state where fields hold data in contradiction to an expressed uniqueness constraint. Thanks to Gaurav Bhargava at Villanova University for reporting this bug. -------------------- Changes from 1.02 to 1.03 ------------------- RELEASE DATE: June 22, 2001 1. [SERVER] Fixed non-event related mail sending in DBLog The DBLog class had an error, effectively, that prevented 'mailout' class mail from being sent, although it was logged. Added a 'sendMail' method to DBLog to simplify the sending of mail by plug-in code and custom tasks. 2. [SERVER] Fixed startup default permissions for non-supergash users Miklos Muller, mmuller@lbcons.net, reported a bug that caused Ganymede to not allow non-supergash users to login to a freshly initialized Ganymede server. Editing the Default Role object's Default Access Bits field, works around the problem, but unless this is done, an exception will be thrown in GanymedeSession.resetDefaultPerms(). I have corrected the GanymedeSession resaultDefaultPerms() method so that it will not freak out when it doesn't find any definition for the Default Access Bits field in the Default Role object. This bug was avoided by users who used the userKit's loader.pl script to initialize the Ganymede database. 3. [SERVER] Fixed infinite loop bug in XML parser The XML parsing code had a bug that would leave it looping infinitely if the XML stream was closed before completion of parsing, either due to an incomplete XML file being fed to the xmlclient, or through the xmlclient dying suddenly. This didn't break the server, but it did take up a lot of processor time, and kept all of the memory associated with an XML session pinned in the server's heap. 4. [SERVER] Fixed default label field for persona objects The persona object schema definition was improperly defaulted to use the older 'name' field as the label, rather than the composite 'label' field. This could cause errors when trying to login with a newly created persona. This bug was reported by Miklos Muller as well. -------------------- Changes from 1.01 to 1.02 ------------------- RELEASE DATE: June 7, 2001 1. [SERVER] Fixed an incompatibility with JDK 1.1 on the server The server code included a use of a generic 'add()' method on the java.util.Vector class that didn't get added until Java 1.2. Replaced it with addElement(). I'm going to have to put up some sort of nightly build directory until I can get network CVS access going, putting out new releases like this is silly. ;-) -------------------- Changes from 1.0 to 1.01 ------------------- RELEASE DATE: June 7, 2001 1. [SERVER] Fixed an IllegalArgumentException with empty namespaces Michael Jung (mikej@confluenttech.com) reported an exception thrown during startup. It turned out to be due to some of the checkpoint code trying to deal with an empty namespace. Easily fixed, so I did. -------------------- Changes from 1.0pre1 to 1.0 ------------------- RELEASE DATE: May 31, 2001 1.[SERVER] Made server do better server-side cleanup for stuck clients The RMI system has the ability to get into a state where a TCP/IP handling thread waits indefinitely for communication from a client. Prior to this fix, the server would wait forever for a dedicated thread to try and notify the client that it is being forced off before handling the server-side client logout housekeeping. Now, the forceOff() method in GanymedeSession will expunge the client from the server on the server-side before notifying the client that it has been disconnected. Note that this fix may still leave those dedicated background threads stuck in the JVM trying to finish reading from a socket from the (presumably dead) client. I can't do much about this other than wait for Sun to fix their RMI implementation so that RMI reads on a socket will eventually time out. In my experience, threads hanging due to a partial socket read is reasonably rare, so I'm not overly worried about hanging disconnect threads clogging up the server. 2. [SERVER, ADMIN CONSOLE] Added support for memory status tracking The server and admin console now collaborate to display the amount of free memory and the total amount of memory taken up by the server, to be updated once a minute by a new Memory Status Updater task. 3. [SERVER] Added the garbage collection task back in I added back in the on-demand garbage collection task, which is an interesting thing to play with now that the admin console shows memory usage on the server. It looks like System.gc() doesn't do much of anything under the HotSpot server VM. Not too surprising, as the HotSpot server VM is already optimized for continual, incremental garbage collection, but having the ability to launch a garbage collection task from the admin console's task monitor may be helpful on some VM's. 4. [SERVER] Cleaned up setLastEvent() usage in GanymedeSession I cleaned up usage of the diagnostic setLastEvent() stuff in GanymedeSession. Viewing or editing objects that contain embedded objects will no longer cause notification for the embedded stuff to be sent to the client. In addition, all setLastEvent()-style notification for non-interactive sessions has been turned off, to reduce the overhead during XML bulk-loading. 5. [CLIENT] Informative dialogs are no longer modal The Ganymede GUI client was occasionally freezing up on start-up if the user attempted to bring up a toolbar dialog at the same time the client was working in the background to bring up the MOTD dialog. This was a result of the HTML messageDialog class used for the MOTD, Credits, and 'About Ganymede' dialogs being configured to lock out any other GUI interactions until those dialogs were released. I don't think there was ever any compelling reason to make these dialogs modal, so I have made them not be so. There's now a small risk that a user might ignore the MOTD dialog without dismissing it, but that's a far less serious outcome than having the client lock up. Thanks to Tom Embleton for bringing this back to my attention. 6. [SERVER] Memory leaks fixed Once I had the admin console tracking memory usage, I quickly saw that the Ganymede server was leaking memory over time. At ARL, our server's heap was starting out at about 10 megs, and after 8-9 days, the heap had nearly doubled in size. I ran the Ganymede server through a profiler for a couple of weeks and identified several places where bits of code were holding on to references to things that were no longer needed. Some of these were really obscure.. things I would *never* have found were it not for the assistance of the profiler. After a month or so of analysis and code work, the Ganymede server's memory usage has been brought under far better control. I've not yet had a chance to run the newly updated server for long enough to judge whether the heap usage is truly stable over the space of weeks and months, but I can say that the server's memory growth rate appears to have dropped to less than a tenth of what it was before, at worst. 7. [SERVER] File descriptor leak fixed The arlut.csd.ganymede.util.zipIt class was neglecting to close files that were being read in for adding to a zip file. This caused the Ganymede server to run out of file descriptors during nightly archives. Apparently this problem was masked on earlier versions of the JVM by the FileInputStream's finalize() method doing clean-up. Since finalize() is n