Ganymede Release 1.0pre1 beta 5 December 18, 2000 CHANGES --------------------------------------------- -------------------- Changes from 0.99.9 to 1.0pre1 ------------------- RELEASE DATE: January ??, 2001 1. [SERVER] Reworked server synchronization logic The GanymedeServer.login() method was vulnerable to a nested monitor deadlock due to a section being synchronized on both the server's GanymedeServer object and its DBStore object. Basically, I was getting way too fancy in synchronizing on various server objects instead of defining a proper semaphore class and using that. I added the loginSemaphore class, which takes care of everything without my having to worry about n^2 different possible code paths. I modified the admin console to report the login semaphore count for each log entry.. this makes it easy to see at a glance how many users are logged on for each log entry, and to insure that the semaphore count is incremented and decremented properly under all circumstances. In the process of all this, I realized that I was unnecessarily doing a notifyAll() every time I did a synchronized operation on the server's DBStore object.. I had misunderstood when it was necessary to do a notify when I originally wrote a lot of this code. The sweepInvids() and checkInvids() methods have been fixed so that they are no longer synchronized on GanymedeServer but they do now establish a dump lock on the server's database, to insure that the object walk is done safely. 2. [SERVER] Added getBackLinks() method to the DBObject class Martin Schneider reported that he needed to be able to get the Vector of Invid's pointing to a given object through asymmetric links, in the same way that was possible by using the old backlinks field. To support this, I added a getBackLinks() method to the DBObject class that directly consults the DBStore's backPointers hash tree. 3. [ADMIN CONSOLE] Fixed admin console confusion with multiple logins The admin console had a bug that would cause the console user table to become confused if more than one user with the same persona name was logged in at the same time on the Ganymede server. This problem only happened when an admin logged into the server with admin privileges more than one at a time. Logging in without admin privileges did not cause this problem, because the server assigns unique usernames to logins, but the server does not guarantee unique persona names. The server now reports to the admin console each login's unique user name, which the admin console uses for login tracking, but the admin console will continue to display the user's (possibly non-unique) persona name. This one has bugged me for awhile, it's good to have this fixed. This change (and change 5 below) change some of the semantics of the admin console's operations, so you should not use an older version of the Ganymede admin console with a 1.0pre1 server. 4. [CLIENT] Right clicking on a selected JTable row no longer de-selects the row This one has bothered me for a long time, too. I changed the baseTable, rowTable, and tableCanvas classes in src/JTable so that right-clicks on a table row won't ever deselect that row if already selected. Left-clicking on a selected row in the rowTable will still deselect the row. 5. [ADMIN CONSOLE] Threaded out server-to-console communications The Ganymede server has always communicated synchronously with any attached admin consoles, which made the server effectively block if the admin console became non-responsive without explicitly throwing a RemoteException. I noticed today that the admin console was blocking the server from processing logins/logouts while my window manager on X was waiting for me to place a new window, which of course is not acceptable. The Ganymede server now queues up notification events for the admin console, and uses a separate thread for each admin console for actually handling the server-to-console communications, using the new serverAdminProxy class. The Ganymede server will no longer sit around waiting for the admin console when something happens, with the obvious benefits resulting in speed and reliability on the server. As a side benefit of the event queueing model, I've implemented event coalescing and event replacement, so that if the Ganymede server is generating admin console events faster than the console update thread is getting them to the admin console, the server will combine and/or drop old events, so that the server won't waste time sending events to the console that are already out of date. The admin console was changed a very little bit to support event coalescing; the changeStatus() method in arlut.csd.ganymede.iAdmin now depends on the server prefixing each status line with a time stamp, rather than trying to time stamp each event from the server itself. Good stuff, and very clean on the server. 6. [ADMIN CONSOLE] Fixed admin console shutdown process I fixed some code in the server's GanymedeAdmin class so that an admin console will stay open if a shutdown attempt by it was refused for some reason. Also fixed a bug in the admin console that made it fail to really attempt to shutdown the server if it tried once and failed. 7. [SERVER] Cleaned up some locking and transaction logic I went through and did a code review of all of the server's transaction and locking classes, and removed a few bits of extraneous stuff, fixed a couple of mistakes that could conceivably cause problems on edge cases, and extensively commented code that I hadn't really touched for a couple of years so that if I dive into it in 2002 I won't have to figure it all out from scratch again. These changes probably won't be noticeable in operation unless I broke something. The DBLock code itself has been reworked a fair bit. The DBLock code no longer synchronizes directly on the Ganymede server's DBStore object, but instead uses a DBLockSync object held in the DBStore object. This as well will help prevent deadlock problems, by limiting the scope of synchronization on the DBStore object even further. 8. [SERVER] Made the database dumper task less timid Due in part to the increased confidence I have in the server's thread safety with the new login semaphore and my code review, I made the database dumper task go ahead and do a database consolidation even if users are logged into the server. Previously, the database consolidation task could be postponed indefinitely if users were logged in each time the dump task fired, leading to a bigger journal file and longer startup times if the server machine was rebooted. Now the database dumper task will go ahead and do the dump, even if it has to wait for transaction commits to finish so it can assert a DBDumpLock on the database. 9. [SERVER/CLIENT] Added bulk add/remove methods to DBField The Ganymede client has long supported moving large blocks of choices from the unselected panel to the selected panel in vector invid and string fields, using shift-click to do multiple selection. Unfortunately, actually doing this with large blocks has been *excruciatingly* slow to perform, as each item moved was a separate round trip network call. For Invid fields, things were even worse, as each single item moved involved a separate transaction checkpoint to make sure that all bind and unbind operations for the element add/delete were done with transactional consistency. The db_field interface now has explicit addElements() and deleteElements() methods that support bulk adds or deletes. The DBField and InvidDBField classes have had these methods added as well. For InvidDBField particularly, the speed up from using the bulk add/delete methods is dramatic. In the process of adding addElements() and deleteElements() on the server, I wound up significantly increasing the efficiency of even non-bulk vector adds where there is an enumerated list of choices that any adds have to be chosen from. In the process of supporting such bulk transfers, I modified a good bit of the client and the client's StringSelector GUI component. Everywhere the client uses the StringSelector can now handle bulk moves in one operation. Making this change has the potential to complicate custom DBEditObject subclasses, which now have to be able to respond in wizardHook() to both singleton and bulk adds and deletes, and which have to provide separate finalizeAddElements() and finalizeDeleteElements() in addition to the old finalizeAddElement() and finalizeDeleteElement() methods if the customizer wishes to take special action when items are added to or removed from a vector field. 10. [CLIENT] Cleaned up the Objects Owned panel in the Owner Group window Despite the fact that the 'Objects Owned' panel in the Owner Group window uses the same GUI component that the normal 'General' panel uses, it was not possible to right-click on entries in order to view or edit objects listed. This has been fixed, and it should now be possible to right-click on any object listing in the client and get at least a view/edit menu. The object type listing pulldown menu in the Objects Owned panel will now be sorted in the client. Turned debugging off in the Objects Owned panel. 11. [CLIENT] Added threading to adminHistory panel When I added a thread-out to the generic history panel in the client (change 0.99.9#10), I neglected to do the same for the admin history panel that is present when viewing and/or editing an admin persona object. The admin history panel is now threaded so that it won't block the GUI refresh during long waits for a history summary from the server. 12. [SERVER] Fixed journal handling on start up The DBStore load() method failed to consolidate the journal into a clean ganymede.db dump if the journal was not in a fully consistent state. It would print an error message and then skip the normal start-up dump. Now, the error message is still printed, but since the journal loading code will properly cope with incomplete or malformed transaction records in the journal, the normal startup process is followed thereafter. 13. [SERVER/CLIENT] The client now displays whether the server is doing a build The server will now notify the client when it starts and stops performing a build. The client displays this information in the panel in the very bottom left corner, where the 'Status: ' text used to be. This is an asynchronous message sent by the server using a new serverClientProxy class that has its own background thread for queueing and sending asynchronous RMI calls to the client. The mechanism used to send this message is generic; it will be easy to extend this mechanism if I want to add more generic server notification features to the client. This involved a change to several server classes, including the GanymedeBuilderTask base class. Any task not subclassed from GanymedeBuilderTask will not trigger this status update. 14. [SERVER] Took out deprecated thread stop() operations The Ganymede Server's background scheduler used the deprecated java.lang.Thread.stop() method call to shut down running tasks when the server is shut down. The stop() method is deprecated in 1.2 as unsafe, however, so the scheduler now uses the interrupted() method instead. The scheduler and all tasks included with Ganymede 1.0pre1 are responsive to the interrupted() call, but custom background tasks written for use with the Ganymede scheduler may need to be reworked to respond to the interrupt call. The GanymedeBuilderTask base class will check for an interrupt between phase1 and phase2 of a build, but it will be up to a builder task writer to check java.lang.Thread.currentThread.isInterrupted() during the two phases if they want to be able to quickly interrupt their builder task. With this change and a couple of unrelated deprecation fixes in the JDataComponent and JTree packages, the Ganymede server and client should now build with no deprecation warnings under Java 1.2 and later. 15. [SERVER/CLIENT] Added regexp support for IP fields in Query mechanism The Ganymede server and client did not previously support regexp matching for IP fields. The client now provides a 'matching' option in the query box for performing regexp searches on IP address fields. Gil Kloepfer (gil@arlut.utexas.edu) pointed this out. 16. [SERVER] Did a basic reworking of ganymede.db and DBStore structures I've been laying the groundwork for support for XML database export/import, and towards this end, I have evolved the ganymede.db database format and the server's DBStore data structures in a direction that may make it easier in the future to load data from an XML file, and to make the server code simpler. The ganymede.db file no longer includes definitions for the mandatory fields in the schema section. The server now implicitly creates these field definitions whenever an object type definition is read from the ganymede.db file or created with the schema editor. This not only makes the schema editor simpler, but it also will lessen bulk and possibility for error when schema importation from an XML file is supported, as the XML file would only need to specify custom object and field types. And while I was mucking around with the file format, I modified server code and the ganymede.db file format to make keeping track of the order of fields within an object and object types within a category simpler, and more robust. There were also a good number of RMI interface changes to simplify schema editing logic. Signficant changes were made to Base, BaseField, Category, FieldTemplate, and SchemaEdit, and the classes that implement these interfaces. A number of effects of these changes are discussed in change 1.0pre1#17, below. These changes in the server are wrapped in file version checks, so Ganymede 1.0pre1 should work fine with ganymede.db files from older versions of the Ganymede server. When 1.0pre1 dumps out the ganymede.db file, however, it will be dumped in its new form. 17. [SERVER/ADMIN CONSOLE] Made schema editing more robust The server now supports schema editing better. Schema changes that would break the database are prevented (at least, much more than before). The server now provides feedback to the admin console (with error dialogs, and the like) if an attempted change would cause problems. A lot of the interface between the graphical schema editor and the server has been simplified and regularized, to depend less on serialization of server-specific data structures. The schema editing system now uses String labels to identify objects to be manipulated in many cases. A number of operations during schema editing that were performed as an interaction between the graphical schema editor and the server are now done locally on the server, to reduce performance problems. 18. [SERVER] The server now resolves client ip addresses to host names When a user or admin console logs into the Ganymede server, the server will now do a reverse DNS lookup to get the fully qualified name of the system that the user is logging in from. The admin console will show the fully qualified domain name for attached clients. 19. [SERVER] Transaction email can be turned off with the starttransaction event Formerly, the server would always send a transaction log to the admin who commited a transaction, as well as sending email to all owner groups that own any objects affected by the transaction. Now, this email can be turned on or off by editing the 'starttransaction' system event object. If the 'Event Mail' checkbox in the starttransaction object is not checked, no transaction logs will ever be mailed. If it is checked, then the 'Cc: Admin' and 'Cc: Owner Groups' checkboxes are consulted to determine whether the admin and the owner groups of any affected objects should be notified. In addition, any email addresses added to the 'Mail List' vector field will receive a complete copy of any transaction logs generated during the server's operation. By default, all three checkboxes are turned on and mail will be sent out in the same fashion that it was in 0.99.9 and earlier. Users with pre-existing Ganymede databases will have to edit this system event object in order to restore the previous mail behavior. 20. [SERVER] Fixed QueryResult.append() The arlut.csd.ganymede.QueryResult class's append() method did not properly update its invidHash and labelHash tables when multiple QueryResult objects were coalesced. This caused the appended QueryResult object on the server to act as if it did not contain Invid's that it did, which could result in a permissions violation report when an InvidDBField tried to verify an Invid in an addElement operation. This only had an affect when the DBEditObject.obtainChoiceList() method used the QueryResult.append() method to concatenate query results, which the gasharl schema kit's emailListCustom class did for its Internal Members field. Thanks to Andrew Helyer (helyer@arlut.utexas.edu) for reporting this. 21. [CLIENT,SERVER] Fixed object description mail from the client Fixed the client's object mail feature. Added getSummaryDescription() to the DBObject class and the db_object interface, which is now used for sending an email description of an object from the client. This feature is activated by using the 'Mail To...' menu item under the 'File' menu in the client's object view/edit windows. 22. [SERVER] Fixed role cloning The PermissionMatrixDBField class had a slight error in its copyFieldTo() method which broke role cloning. This was supposed to work, but it didn't. Thanks to Pug Bainter (pug@pug.net) for reporting this. 23. [SERVER] Changed client naming for concurrent use Previously, if a user logged into the Ganymede server with more than one client at a time but the same username, the Ganymede server would report the second account as user2 in the logs and the admin console. This can be confusing for situations where both user and user2 actually exist as valid user accounts, so the Ganymede server logic has been changed so that if 'user' is logged in twice at the same time, the second login will be reported as 'user[2]' rather than 'user2'. Thanks to Pug for complaining about this. 24. [SCHEMA] Fixed gash/gasharl schema system interface deletion bug Pug caught a bug in the gash/gasharl schema kit, by doing something I would never have been able to make myself do. He created a system, set the room to a room with a single network, edited the system's single interface, set the network, then deleted the interface. In doing so, he discovered that the gasharl schema kit didn't keep track of things properly on interface deletion, and that the network that was chosen became unavailable as a choice for that system when an interface was created again with the 'add interface' button. I've fixed this, so now you can delete and add interfaces all you want without losing the ability to choose a previously chosen network. 25. [CLIENT] Fixed default owner dialog logic Previously, the ganymede client could get confused about the proper settings for the default owner dialog (the dialog that pops up to ask you what owner group you want to put a soon-to-be created object into) if you change personas. It would be too painful right now to explain the precise situation in which the ganymede client wouldn't do the right thing, but it doesn't anymore. It does the right thing. This is another one of those things that's been bugging me for a long time, and I'm glad to see it fixed. 26. [SERVER] Fixed case-sensitive login handling The GanymedeServer login process was mishandling login authentication, by canonicalizing user login to lower case, but using a case-sensitive comparison to find matching admin privileges. GanymedeServer.login() now uses a case-insensitive query to look up a user's login privileges. This is another thing that Pug caught. 27. [SERVER] Fixed mail handling for persona names Another fix for a Pug bug. Pug reported that attempting to log into a server with a fully qualified persona name, like 'pug:admin', and messing up on the password would cause the server to attempt to send mail to 'pug:admin@mailserver.com', which his mail system ultimately resolved to be equivalent to 'admin@mailserver.com'. The DBLog code that handles system event mail will now truncate at the colon, so a bad login for 'pug:admin' will be sent to 'pug@mailserver.com', as it should. 28. [PASSWORD CLIENT] Fixed PasswordClient compatibility for 1.2 The PasswordClient class used by the changePassword program attempted to set an RMISecurityManager, which is not allowed under Java 1.2. As a result, running changePassword on a 1.2 JVM would cause a security exception to be thrown. Sun really makes it hard to be both 1.1 and 1.2 compatible, some times. Fortunately, the Ganymede clients work acceptably well with the default security manager, since we package all of the RMI stub classes with the client and password jar files. This was yet another fine bug report by Pug. 29. [NIS PASSWORD CLIENT] Fixed rpcpass non-termination errors There were certain conditions in which the rpcpass client proxy would not properly exit the JVM, but would instead linger until manually killed. Now, the client will always terminate if something goes wrong, rather than sticking around. This time, for real. 30. [SERVER] The dump task now reports how many transactions it is dumping The dump task, which typically runs every couple of hours to consolidate the transaction journal into the ganymede.db file, will now announce the number of transactions in the journal to the log and admin console when it runs. 31. [SERVER] Fixed supergash admin persona renaming in DBStore.initializeObjects(). The Ganymede server wasn't properly renaming the supergash admin persona on startup if the ganymede.properties file specified an alternate name for the supergash persona. I've fixed this.. the server will now always reset the supergash persona name to that specified in the server's ganymede.properties file. Thanks to Alex Robinson (Alex_robinson@bigfoot.com) for reporting this. 32. [SERVER] Improved object cloning with partial failure on vector copy I happened to notice that when I attempted to clone a user who belonged to one or more groups that I did not have permission to put into a new user, Ganymede did not react well. That is, I got a dialog saying that certain items could not be cloned, and when I looked at my newly cloned object, several of the fields were just totally blank. I've now modified DBField.addElements() and InvidDBField.addElements() so that they are able to handle partial copies, and so that the DBField.copyFieldTo() method takes advantage of this to make object cloning more robust. 33. [CLIENT] Added a fabulous new XML client When installing the client, a new text-mode client program called xmlclient is installed. xmlclient is able to bulk load data into the Ganymede server from an XML file. Loading data through the xmlclient is less efficient than the old custom runDirectLoader hacks that data loaded depended on before, but it is far more versatile and lets you load in any kind of data that you can specify in your Ganymede schema definition with nothing more than a Perl script and this client. Ultimately, I want to make the xmlclient able to not only load arbitrary Ganymede data from an XML file, but for it also to be able to connect to an empty Ganymede server and establish a custom schema from an XML file. Supporting this and converting all of the existing schema kits to this method of server initialization is the big goal left for Ganymede 1.0. 34. [SERVER] Made the server less picky about setting owner groups ahead of time The Ganymede server now allows non-interactive clients (clients that have turned wizards off) to create objects without having previously selected one or more owner groups to be the default owners for newly created groups. This was only an issue if the user that was creating objects belonged to more than one owner group, such as supergash. Now, if supergash creates objects through a non-interactive client, the objects will be created with null (supergash) ownership. If a non-supergash user that belongs to multiple owner groups creates objects through a non-interactive client, the objects will be owned by the first owner group found by the server. All of this was done to simplify things for XML bulk loading. 35. [SERVER] Made the server not complain about redundant invid loading I'm finding that I need to make a number of tweaks to the server so that it behaves in a reasonable way in the XML client context. In many ways, the server was designed around interactive usage, and a number of issues are coming up with the batch mode XML client. In this case, the server previously complained if an object reference (invid) was added to an vector object reference field that already contained that object reference. Now, the server silently discards redundant invid additions. This allows the XML client to have a symmetric invid relationship in which both sides of the relationship show the link without having the server reject the second object's invid links as redundant. 36. [SERVER] Improved error reporting on object editing contention The Ganymede server previously returned a misleading error message if during editing the user attempted to cause an object to be linked to an object that was already checked out for editing by another user on the Ganymede server. Now, if a link to an object cannot be established because the object is already checked out for editing by another user, the server will report the error properly, and will identify the user that has the object checked out for editing. 37. [SERVER, CLIENT] Fixed the deferred shutdown option The 'shutdown the server when all users log off' mechanism was broken, and didn't actually shutdown the server even when all active users logged off. This has been fixed. Additionally, the Ganymede ClientBase class has been reworked slightly so that if the server is in deferred shutdown mode, the login failure message will explain this, rather than the generic 'bad username/password?' message. 38. [SERVER] Added deleteAllElements() to the db_field interface I added the deleteAllElements() method to the server's DBField class and db_field interface, to allow the new XML client to remove all values in a Vector DBField without having to do an additional roundtrip to the server to get the list of elements currently in the field. 39. [SERVER] InvidDBField.createNewEmbedded() now includes a db_object ref Another change to support the XML client efficiently. The InvidDBField createNewEmbedded() method now includes a db_object reference as well as a serialized Invid. This removes the need for the XML client to make an additional round trip request to the server in order to get an editing handle on a newly created object. 40. [SERVER] Added support for high speed log scanning The Ganymede server has always had support for scanning its own log file to produce an object summary report for the Ganymede client. Unfortunately, Java is rather inefficient at text file parsing, and the log scanning code converts each line of the log file scanned into a DBLogEvent object. This conversion made coding convenient, but made scanning a very large log file much much slower than a simple grep would be. The Ganymede server now supports an external Perl script which prefilters the log file on request, so the Ganymede server only needs to process those lines that match the object being reported on. This makes the object history feature much much faster, as the server doesn't have to process unrelated log entries. If an object (such as an owner group) actually does have a very large number of lines in the log file, parsing and reporting on what might be megabytes of log data will still be very slow, however. At some point, the log scanning code should probably be written to avoid the object conversion step in favor of simply identifying matching lines through textual means and appending the text of such lines to the object history report. The external helper program is an optional acceleration.. if the 'ganymede.loghelper' property isn't defined in the server's ganymede.properties file, then log scanning will be performed in the old-fashioned style. 41. [CLIENT] Fixed persona creation in user object panel The Ganymede client allows new admin personae to be created in two different ways. In 0.99.9, however, creating a new admin persona from within the user editing window threw an exception. It is now possible to create new admin personae either directly through the client's tree by creating a new 'Admin Persona' object, or by editing a user object and using the Personae tab to create a new persona. 42. [SERVER] Optimized critical database lookup code. This one's embarassing. A long time ago I heavily tuned and optimized the Ganymede server's database hash structures. A job well done, I said to myself. Unfortunately, the DBSession.viewDBObject() method which everything in the server actually uses to pull objects out of the server was doing some extremely dumb things. In particular, before ever looking in the highly optimized database structures, viewDBObject() looked to see if the object being sought was already checked out for editing by the session's transaction. Unfortunately, the DBEditSet transaction class tracked objects checked out for editing in a linear Vector rather than a hashing structure, so as more and more objects got checked out by a session, *all* database access operations on behalf of that session got slower and slower and slower. This turns out to be the reason why the Ganymede server's bulk loading was so very slow. Now this transactional data structure has been converted to a Hashtable, and viewDBObject() has been extensively optimized so that it will only attempt to find an object in the transaction's hashtable if an object has not yet been committed into the main database structures. All transactional object view, edit, delete, inactivate, and clone operations will involve *much* less work as transactions get bigger. I knew there was a reason I hadn't called it 1.0 yet.. 43. [SERVER] Schema Editor dumps database after making schema changes A number of people, including Christoph Litauer (litauer@uni-koblenz.de), reported problems resulting from the server not consolidating its on-disk database after schema changes were committed. The problems arose whenever changes were made to the server's schema in the schema editor after which transactions were committed to the journal file before the server was abnormally terminated, leaving a mix of object data in the journal file from after the schema change, which is not itself recorded in the journal file. The server will now dump its database to disk and consolidate the journal file when schema changes are committed, so there is no opportunity for a mismatch between the schema in the ganymede.db file and the object change records recorded in the server's journal file. 44. [SERVER] Object Event Mail Is Now Coalesced Another change in response to bulk loading with the XML client. It used to be that people who requested mail notification when certain operations happened to certain kinds of events (such as when a user was created or deleted, say) will now get a single message with a summary of all events of that type during a transaction rather than a single message for each event. We had a user who was subscribed to system creation objects and was getting hundreds of messages all at once every time I ran my bulk loader test. Now he'll just get an easily deleted summary. In addition, when these events do happen one at a time, the message subject in the mail sent out by Ganymede will now include the name of the object operated on. 45. [SERVER] Expiration/Removal dates may not be set to times past Jeff Sims (jsims@arlut.utexas.edu) reported that Ganymede erroneously allowed a user's Expiration date to be set to an already passed date. The admin intended to set the Expiration some months in the future, across a year boundary, but neglected to change the year, causing Ganymede to expire the object at the next run of the Expiration Task. Ganymede will now forbid any changes to an object's Expiration or Removal date that would set either date to a time earlier than the Ganymede server's notion of current time, as a safeguard against this sort of mishap. 46. [SERVER/CLIENT] Server now has soft timeout option The Ganymede server has always had the ability to time out users that were idle in the Ganymede client. Tom Embleton (embleton@arlut.utexas.edu) expressed dissatisfaction with this, for the reason that having to login again from scratch forced him to readjust his windows and was a pain in general. In response, I implemented a soft timeout option that can be turned on by activating the 'ganymede.softtimeout' property in the server's ganymede.properties file. If this option is chosen, the server will send a time out message to the client, which will respond by downshifting from any admin persona to the base user login and presenting a mandatory persona selection dialog which will insist on being given a proper password in order to let the user continue work. A soft timeout will still close any transactions open at the time of the server timeout, but it will be faster to enter the user's password into the persona dialog and get back to work than to login from scratch again. In addition, the server's two time limits (for idle sessions with no objects checked out and for idle sessions with objects checked out for editing) are now configurable in the server's ganymede.properties file. 47. [SERVER] Added shutdown semaphore to keep shutdown from breaking builds I have added an additional semaphore to the server so that when an admin initiates a shutdown of the server from the admin console, the server will wait for any builder tasks waiting on phase 2 (execution of external scripts for NIS/DNS/etc. builds) to complete before shutting down. This is to insure that a builder task in phase 2 won't interrupt an external build script or program, leaving a network service in an inconsistent state. 48. [SERVER] Fixed namespace-optimized lookups on IP fields The server has special logic in GanymedeSession for optimizing query lookups on namespace-indexed data fields. That logic was not properly handling IP address fields when given an IP address in string form rather than in byte array form. Now, the query logic will properly convert IP strings to byte array form for optimized namespace lookups. 49. [SERVER] Fixed queries on embedded objects The GanymedeSession queryDispatch() method will now properly perform a search on an embedded object if a Query is submitted whose requested returnType is equal to the searched-for type. My initial decision to include embedded objects in the Ganymede design has made *so* many things painfully complex in the whole system. Sigh. This is another bug that showed up in development and testing of the XML client. 50. [SERVER] Optimized transaction commit The server code had a potentially quite expensive checkpoint() operation in the DBEditSet.commit() method. This checkpoint operation was there to allow the server to set the historical fields (creation and/or modification date and user identity) before the commitPhase1() methods were called while still being able to do a rollback() if a commitPhase1() method rejected the transaction commit. This checkpoint and rollback pair could be enormously expensive if the transaction gets real big, as it can with the xmlclient. The commit() method now forces the new date and user identity information into the transaction's edited objects in a manner that bypasses the object value freeze put in place during an early point in transaction commit. This change will make committing large transactions a good deal faster, and will make failed commit attempts even faster than that. 51. [SERVER] Improved startup sequence The server now intelligently checks to make sure that no server is already running at the same host and port, rather than simply ignoring the warning from the RMI rebind process. The server will now decline to start up if another server is answering the phone at the same address. 52. [SERVER] Fixed PermissionMatrixDBField loading The server had a bug that would prevent the database from loading if a role had a permission matrix defined with no entries defined in it. 53. [INSTALL] Install scripts now check to make sure jars were built All of the install scripts now double check to make sure the jar files were made during the system build. 54. [SERVER] Reworked checkpoint handling for non-interactive transactions I have simplified how non-interactive transactions handle checkpoints.. basically, the DBEditSet class now automatically ignores checkpoint activity for non-interactive transactions. Any rollback request made during a non-interactive transaction will result in the transaction committing hari-kari at commit time. By putting all the logic for this in DBEditSet, I've simplified a fair bit of code in InvidDBField, DBEditObject, and DBSession. I should have done this before. 55. [CLIENT] Added count indicator to StringSelector The vector field GUI component now includes a count number, to make it easy to see how many items are in the field. 56. [CLIENT] Windows now kept within bounds It turns out that the default Swing window resize/move logic made it possible to resize/pull windows above the top of the inner desktop, such that the title bar was no longer accessible. Richard Mach here at ARL:UT graciously pointed out this problem, and it turned out to be pretty easy to fix. The Ganymede client will now block attempts to resize or pull a window out of the visibility area to the top and left. 57. [CLIENT] Fixed owner panel on view windows The right-menu popup menus weren't enabled on view object windows in the owner panel. Now, you can view any object and be able to right-click on the items in the owner list to directly view or edit the owner groups that own that object. 58. [SERVER] Fixed object cloning in previously broken case The object cloning logic was not previously excluding object linkage (invid) fields that were involved in a one-to-one or many-to-one relationship. The upshot of this was that when a user here cloned an I.P. network, the cloned network had duplicated not only a list of rooms for the network to be present in, but also the systems, thereby unlinking those systems from the original in the process. This caused much confusion until the cause was detected. Thanks again to Gil Kloepfer for pointing this out. 59. [SERVER] Fixed rollback for object deletes This was a really critical bug. The result of this bug was that if an object deletion was attempted, but was refused due to consistency problems, the system would rollback everything *except* the object's to-be-deleted status. This meant that if the user went on to commit a transaction after unsuccessfully deleting an object, that object would be deleted anyway. Worse, all the objects that should have had their links to the object undone as part of the deletion operation will retain their links to the deleted object, ruining the symmetrical pointer integrity constraint of the Ganymede database. This bug and #58 above manifested as part of the same incident, so thanks must go again to Gil Kloepfer for demonstrating a really ugly problem. This bug has been in Ganymede since 0.99.8, lurking quietly for over 10 months. The fix was to move one line of code in DBSession up about three lines. Amazing how these little touches matter. 60. [SERVER] Serialized checkpoint logic, removed client access to checkpoint() In examining the checkpoint and rollback code, I realized that there was nothing in the system that would prevent multiple threads from attempting to assert and rollback checkpoints on the same transaction. This meant that it was in principle possible for the server to interleave checkpoint operations, leading to unpredictable and incorrect results if multiple threads simultaneously attempted to do things like object creation, deletion, and linking within a single session's transaction. I don't believe this does ever happen, in practice, but if it ever did it would be confusing and a pain to debug. To avoid this, I put in a system whereby only one thread at a time is allowed to have a checkpoint on any given transaction. If another thread attempts to checkpoint a transaction while it is already checkpointed by a thread, the thread that is attempting to checkpoint will block until the earlier checkpoint is popped or rolled back. This scheme will guarantee safety of checkpoint operations at the cost of an mildly increased risk of deadlock. To mitigate the deadlock risk, I removed the ability for remote clients to access the checkpoint() and rollback() methods in the GanymedeSession class, and I put a deadlock timeout on the checkpoint block, so if a checkpoint() attempt blocks for more than 60 seconds, an exception will be thrown and the checkpointing thread will let go. The loss of client access to checkpoint and rollback doesn't seem to be an unreasonable thing to do, as no client code that I have yet seen has done anything with the intra-transactional checkpoints. If someone convinces me that it is critical that remote clients be able to access intra-transactional checkpoints, I'll need to rework the anti-interleaving code to deal with the fact that subsequent RMI calls from a single client are not guaranteed to be handled by the same thread on the server. 61. [SERVER] Fixed deadlock vulnerabilities Previously, the GanymedeServer object used Ganymede.internalSession to process database queries for user and admin console logins. The problem was that this was prone to deadlock with some other uses of Ganymede.internalSession in the Ganymede server. In particular, if anyone ever attempted to login at the same precise moment that a transaction was being committed, the whole server locked up. Now, the Ganymede server uses a distinct GanymedeSession object to handle logins. Since GanymedeServer has its own synchronization at a higher level, it is no longer possible to get nested monitor deadlocks from logins. In addition, since the Ganymede.internalSession object is often used by random Ganymede server code to look up things in the database, I partially de-synchronized DBSession.viewDBObject() so that a DBSession that does not have an open transaction asssociated with it will not incur a synchronization penalty/deadlock opportunity merely to retrieve a reference to an object from the database. 62. [SERVER, CLIENT] Added -dump{schema|data} to the xmlclient, removed decodeDB The xmlclient is now able to emit a copy of the server's schema definition in xml format, using xmlclient -dumpschema, and to dump the server's database in its entirety in xml format, using xmlclient -dumpdata.. Due to this, I have removed the old hackish decodeDB and permdecodeDB front ends to the Ganymede server. 63. [SERVER, ADMIN CONSOLE] Added runEmbeddedTest, runEmbeddedSweep Bug 59 above, the deletion rollback bug, allowed some inconsistencies into our database, wherein embedded objects were left in the database when their owners had been deleted. I added test features to the server and the admin console to detect and repair this condition. 64. [CLIENT] Made Client check for MOTD message in background The client now runs its check for a new MOTD in a background thread, so as not to lock up the GUI thread initially. This will get rid of the ugly lack of refresh that was visible when the user dismissed the select persona dialog. 65. [CLIENT, ADMIN CONSOLE] Cleaned up login boxes, console shutdown dialog I finally went back and got the admin console and gui client to put the focus on the username box, so people can just start typing their name when the clients come up. I reworked the admin console shutdown dialog so it just uses one dialog box for the various shutdown modes. 66. [INSTALL] Removed installClient2, made installServer autodetect java version A bunch of changes to the installation process. installClient2 is now gone, installClient is now smart enough to autodetect what version of Java is being used and to configure the client install appropriately. Ditto the installServer script. I cleaned up the gasharl schema kit's ganymede.schema file to take care of some inconsistencies that have been in that file for a long while. 67. [CLIENT] Tweaked right-menu clicks in StringSelector to select and popup Mike Mulvaney (ex-Ganymede GUI guy) filed a bug report indicating that clicking the right mouse button should select the item that the pop-up menu is being applied to. He was right, and I so fixed it. 68. [SERVER SECURITY] Fixed a loophole in the object permission system The Ganymede system allows admins and users to be given editing privileges to objects that are not considered to be owned by the admin or user. This is an unusual circumstance, usually only done when the customizer wants objects to appear in the client's object tree but doesn't want to allow certain (or even any) fields to be modified. The problem was that the built-in fields, including the owner list field, do not typically have their own access permissions tracked, independently from the object's access permissions. This allowed any user who could edit an object to grant themselves ownership of the object, which is bad. The server now refuses to grant edit privilege to an object's owner list field unless the user already owns the object, or is running with supergash-level privileges. 69. [SERVER, XMLCLIENT] Added XML-based schema editing through the xmlclient The xmlclient can now be used to perform schema edits on a running Ganymede server (so long as no users are logged in, and as long as the schema edits do not result in an incompatibility that will break loaded data). This makes is possible to get rid of the old directLoader crud in the schema kits. 70. [SERVER, ADMIN CONSOLE] Fixed exceptions on drag/drop in schema editor Fixed bug #13 in bugzilla. 71. [SERVER] Added TaskOptionStrings to Task definition The built-in object type, 'Task' now supports an optional vector string field, which will be used in 1.0 to represesnt builder task options for schema kits that support more than one transaction-time builder task. 72. [CLIENT, SCHEMA EDITOR] Fixed tree's pop-up menus on Linux The GUI tree component was still using old-style AWT pop-up menus, which wasn't working properly on Linux using Java 1.3. Since almost everything in the Ganymede client and admin console are based on Swing, switching the pop-ups to Swing should keep things consistent and working on various platforms. 73. [ADMIN CONSOLE] Fixed console deadlocks on Linux I was being sloppy with my GUI thread handling in the admin console.. updates from the server were not being painted on the GUI thread, which was leading to swift lockups when running the admin console on the Linux 1.3 JDK. I fixed this, the admin console should run fine in any Java environment now. 74. [SERVER] Reworked query engine to increase concurrency The Ganymede server no longer has to block threads from doing most queries on the server while a transaction has portions of the database locked for updates. The Ganymede server will now only lock the database on a standard GanymedeSession query if the query spans more than one object type. In practice, this means that unless you or your code attempts to do a query that involves embedded object values (as in searching for a system using a give i.p. address held in an embedded interface object), the query will never block. For this reason, it is now safe to take advantage of the Ganymede query mechanisms during all stages of transaction commit in DBEditObject subclasses. -------------------- Changes from 0.99.8 to 0.99.9 ------------------- RELEASE DATE: January 13, 2000 1. [SCHEMA] Fixed gasharl schema errors a. The gasharl schema kit had a bug which made it impossible to edit a system if that system was connected to a room that had no networks listed. b. The gasharl GASHBuilderTask code is designed to handle netgroups that overflow the 1024 byte NIS line length limit, but the code that handled netgroup folding did so very inefficiently, putting only one netgroup entry per line after the first. 2. [SERVER] Fixed race condition in Qstmp stopThreaded() method The Qstmp shutdown process could throw a NullPointerException in stopThreaded() if thread timing worked out just wrong. This has been caught, and this race condition will no longer be able to prevent clean server shut-down. 3. [SERVER] Fixed various deadlock possibilities in server a. The 3 DBLock subclasses (DBReadLock, DBWriteLock, DBDumpLock) did not properly call notifyAll() on the DBStore object if they threw an exception in their establish() method. Now, all synchronized blocks in the DBLock subclasses use try..finally to guarantee that other threads waiting on DBStore will be woken up, even if something unexpected happens. The DBReadLock.establish() code had code to throw an exception if a session that possessed a write or dump lock tried to obtain a readlock at the same time. Unfortunately, the internal sessions used for the Ganymede builder tasks, expiration task, and warning task were given the same identifier as the standard 'internal' session used to process queries in the login process, so if a login was attempted during a builder task's phase1 execution, or during portions of the expire or warning task, an exception could be thrown, possibly causing threadlock if other threads had wait()'ed at that point. All this should be fixed now. b. There are several ways a user can be forced off of the Ganymede server.. the idle timer, the admin console, and the RMI unreferenced object mechanism. Previously, various essential objects in the server could get locked if the client refused to respond to the server's disconnect command. Now the client force-disconnect code is better coordinated so only one thread in the server will ever attempt to force the user to disconnect, and that thread will itself spawn a background thread to force the user to disconnect. As a result, although the server may wind up with a single dangling thread per client if the RMI system blocks trying to call the client, nothing in the server will deadlock because of it. As a result of this change, knocking a user off the system by the admin console is no longer a synchronous operation, so it may take a few seconds before the admin console updates to show the results of a user kill operation. c. The admin console code in the server had a number of problems that could lead to a deadlock that blocked any admin console operations (including the stopServer script). The server code that handles communications to/from the admin consoles have been significantly reworked so as to not be vulnerable to a threadlock condition, and some redundant operations have been pruned to reduce overhead. A number of possible race conditions have been closed. This will make the server faster and safer when admin consoles are attached, but the admin console updating is still generally synchronous. Every admin console connected to the Ganymede server will slow the server down a bit. 4. [SERVER/CLIENT] Added support for 'browse' mode in client John Knutson pointed out that the Ganymede client wasn't an adequate directory browser because it always hid things that couldn't be edited, when in fact the user had a perfect right to see everything for which he is granted view access. This was intended to be a feature of the client, that it could present a simplified tree to the user to avoid confusion, but it needlessly restricts advanced users. The server and client have now been modified so that the client can display all objects and object types viewable by the user, even if the user does not have editing permission. This is toggled by a 'Hide non-editable objects' checkbox menu item under the client's 'File' menu. I expect I may move this someplace else in the client's GUI eventually. This involved changes to GanymedeSession.java, Session.java, and CategoryTransport.java on the server, and gclient.java on the client, so a 0.99.9 server will now require a 0.99.9 client. As before, the server is really responsible for deciding what object types are reported to the client.. the client can't choose to show object types in the tree if the server doesn't report them, but the client can now ask to have all visible object types reported, which it couldn't do before. 5. [CLIENT] Reworked object folder pop-up menus in client tree display The client's object folder pop-up menus in the tree display has been reworked to be less ambiguous. The old 'List editable' and 'List all' have been changed to 'Report editable' and 'Report all', and the old 'Show All Objects' has been changed to 'Show Non-Editables', and moved to the top of the pop-up menu. Hopefully this should be less confusing for folks. 6. [SERVER] Fixed custom schema migration bug from 0.99.8 Change 0.99.8, #17, listed below, which modified how the server handles non-symmetrically linked InvidDBFields, didn't properly handle InvidDBField definitions that explicitly listed the backlinks field as the field to be linked to. Apparently, in 0.99.7 and before, the schema editor presented the backlinks field as a valid symmetric field target. Martin Schneider reported that Ganymede 0.99.8 was complaining when it came across such a field in his ganymede.db file from 0.99.7. I had the server handling invid fields with target fields set to 'none', but I hadn't handled the equivalence case of the 'backlinks' target. The Ganymede server will now treat an invid field with a target field set to field 8 (the obsolete backlinks field) in precisely the same way that it treats invid fields with no target field specified. This should make Martin's ganymede.db file from 0.99.7 work properly in 0.99.9. 7. [SERVER] Made bad login user notification optional Previously, the Ganymede server would always attempt to send notification of a bad password/login attempt to the name of the user entered at the login attempt, regardless of the configuration of the 'badpass' system event object. Now the Ganymede server will not do this unless the 'badpass' system event object in the ganymede.db database has the 'Cc: Admin' flag set. 8. [SERVER] Took out unnecessary fields in DBField.java The DBField base class had a number of redundant or unnecessary fields, including both a scalar and vector field, even though no field is both a scalar and a vector. I've removed the Vector values holding field and replaced it with accessors which will treat the single value field as a Vector as appropriate. I also took out the 'fieldID' short, which was redundant, since the DBField.getFieldDef() method already calculated that information from the field definition reference. I also took out the 'newValue' field, which was only used in one very specialized case in the userCustom plug-in, and which was better handled by putting an extra field in that custom DBEditObject subclass. This will save 10 bytes per field in the database while in memory, with probably around 40 bytes of per-field overhead remaining for scalar fields, rather more for Vector fields. Not a very big deal, but it does amount to 80-300 bytes of RAM per object in the database. For our current database, this probably saves us a megabyte of in-memory space, or around 3% of the total resident memory usage. That percentage could probably get quite a bit higher when the initial size of the server itself is amortized over larger and larger databases. This change doesn't affect the on-disk database file at all. 9. [STOPSERVER] Modified the stopServer code to prompt for supergash password Previously, if the Ganymede server's supergash ("root") password was not kept in the server's ganymede.properties file, the stopServer client would simply fail. Now, if it can't load the supergash password from the ganymede.properties file, stopServer will prompt the user for the supergash password. 10. [CLIENT] Threaded out the client's history panel to avoid locking GUI Here at ARL, our server log is getting quite large, and the round trip time for reporting on the history of changes to an object is getting large. Because of this, the client's GUI has been locked for a longer and longer time as the client's GUI thread blocks waiting for the server to report the object history. Because of this, the Ganymede client has been modified to thread out history reporting. The client's GUI will no longer lock up while the client is waiting to get a report on an object's history back. -------------------- Changes from 0.99.7 to 0.99.8 ------------------- RELEASE DATE: November 23 , 1999 1. [SERVER] Included regexp info in schema html dump The html/text schema dump facilities in DBObjectBaseField.java now include regexp information for string fields, if defined. 2. [SERVER, CLIENT] Made it possible to do a more limited log search Previously, the history panel in the client's "show history" function showed the complete transaction in which the object was modified. There is now support for showing only changes directly affecting the object in question. Added a new version of viewObjectHistory to the Session RMI interface. Added explanatory tool tips to the show history buttons in the client's history panel. Cleaned up the historyPanel generally. 3. [CLIENT] Cleaned up object report mail/save dialog The Ganymede client allows the user to mail and/or save a status summary for single objects in the Ganymede database (from the File menu in the object view/edit window), but the dialog that came up was really lousy, and hadn't been touched for over a year. I restructured the dialog and made it more usable. 4. [SERVER] Made server start-up less fragile A user here got a ganymede.db file into a state where a field had a namespace listed, but that namespace wasn't declared in the .db file. The server was not able to recover from this because the DBObjectBaseField class was throwing an illegal argument exception. I modified DBObjectBaseField so that a warning message is displayed instead. Hopefully I'll be able to find how the system got into that state and prevent it, but the server can deal with that inconsistency now. 5. [SERVER] Improved Qsmtp mail-out code Previously, the Qsmtp mailer code would abort sending a message if any of the recipients were rejected by the mailhost. Now the Qsmtp code will go ahead and complete the message if any of the recipient addresses were accepted. This was causing the 'bad login' mail for an invalid user login attempt not to be sent. 6. [CLIENT] Made rpcpass exit cleanly The rpcpass client (used in conjunction with the Linux NISkit's rpc.yppasswdd to pass NIS password changes into Ganymede) wasn't properly terminating after execution a transaction in Ganymede, resulting in lots of lingering rpcpass processes hanging around. This is a result of the JVM's policy of not closing down an application until all of its non-daemon threads terminate. Since the rpcpass code is an RMI server, this never happened. I added a System.exit(0) to take care of this. 7. [SCHEMA] Minor fix to the nisonly schema Fixed the nisonly schema's userCustom.java's fieldRequired() method to not attempt to call isInactivated() on the non-value-containing objectHook instance of userCustom.java. John Knutson here at ARL was developing a schema based on the nisonly schema kit, and it turns out that I haven't done much in the way of upkeep on that schema kit for awhile now. 8. [SERVER] Made GanymedeBuilderTask.backupFiles handle an empty dir ok The backupFiles() method in the GanymedeBuilderTask class is intended to produce a zip archive of all files in the out directory when a builder task is run. Unfortunately, it caused an exception to be thrown if there are no files in the out directory, as is the case the very first time the builder task is run after installing Ganymede. This has been fixed. Thanks to John Knutson for reporting this. 9. [SCHEMA] Fixes to the gasharl schema a) The server used to throw an exception if an admin created a user and hit 'commit' without filling in the home group field, because some of the custom logic wasn't checking to make sure that the field was there before trying to do calculations based on it. b) Moving a system from a room to another which was not connected to the network that the system had been allocated on was broken.. a 'can't free network' error was being reported. This case is now properly handled. 10. [CLIENT] Miscellaneous Client Improvements and Fixes a) You can now right-click on a row in the query result table and inactivate or delete objects shown, rather than having to do a query to find the object you want to delete and then use the tree to find and delete it. b) Related to this change, the 'are you sure you want to delete this' dialog will now appear whenever an object is deleted, whether from the delete object dialog, the table, or the tree (which used to not prompt for verification). The object deletion verification dialog is now more friendly and descriptive. c) The client now resets its 'default owner chosen' flag when the user changes personae. *** STILL NEED MORE HERE *** d) The GUI component for scalar invid fields has been very significantly revised to make it possible to enter a choice by using the keyboard instead of having to mouse through a possibly huge list. This was done using a custom JComboBox editing component that monitors keystrokes to do 'choice completion' during the course of text editing. I'm sort of pushing the Swing JComboBox to the limit here.. hopefully with Kestrel/1.3 Swing will be more useful for real world stuff. e) Reworked StringSelector to put the add box on the left, and to enable typed choice completion if the only valid choices are listed f) Changed the layout algorithm for window placement within the client. No more client windows being placed partially outside the client's display area. 11. [SERVER] Implemented support for object cloning Since the beginning, I've planned on having a clone_db_object() method on the server that would create a new object by copying values from an existing one, but somehow I never had gotten around to implementing it. The work John Knutson is doing with Ganymede would benefit from this feature particularly, so I went ahead and got it done today. This involved lots of changes to the server, including DBField and all its subclasses, DBEditObject, DBObject, GanymedeSession, and possibly other classes. These changes included making the server's code differentiate between inhibiting wizards for the sake of an automated field copy and inhibiting oversight for the purpose of loading the database on server start, etc. I still need to document all of this in the DBEditObject subclassing guide. 12. [SERVER] Added support for floating point fields All of the code for this came from John Knutson (johnk@arlut.utexas.edu) here at the laboratory. This change bumps the DBStore revision numbers to major: 1 minor: 15 13. [CLIENT] Improved speed for object editing The client was inefficiently and redundantly sorting large choice lists, slowing object editing down a great deal. Now all QueryResult objects from the server are automatically sorted one time only, on receipt, using an efficient binary insertion sort. 14. [SERVER] Reworked Password fields to support FreeBSD-style MD5 hashing The Ganymede has supported 'MD5 passwords' since August, but this was actually just a simple MD5 hash of the plaintext. FreeBSD, OpenBSD, Linux PAM, and possibly other operating systems use a much more involved process of generating 'MD5' passwords, including a salt field and a thousand round trip through MD5 to make dictionary cracks much more time-consuming. Ganymede's PasswordDBField class now supports these fancy MD5 passwords, and the old support for a simple MD5 password hash has been removed. This change bumps the DBStore revision numbers to major: 1 minor: 16 15. [CLIENT] Fixed tree filtering The Ganymede client had a bug in gclient.recurseDownCategories which could cause categories to be erroneously omitted from the client's tree display in a specific situation. This was detected by John Knutson in regard to a custom schema that he did. 16. [SERVER] Took unnecessary fields out of the DBObject class I took the 'int id' and 'DBEditSet editset' variables out of the DBObject class. This will save 8 bytes per object in the database in memory. Not a major deal, but every little bit helps, I suppose. Added methods to compensate for the lack of the redundant, but directly accessible variables. 17. [SERVER] Major reworking of object linking I spent a week and did major surgery on the Ganymede server's handling of non-symmetric object linking. Previously, if an invid field did not point to an explicit field in a remote object, the server would automatically maintain the symmetric back pointer in the target object's back links field, field 8. This meant that whenever an object's field was set to point to an object, that object had to be exclusively checked out by the server to handle the association. Only one transaction at a time could establish such a linking, which could make for a really big and unnecessary bottleneck in the server. Now the server maintains at all time a separate, in-memory hash structure for back pointers. This hash structure is designed to allow any number of objects to 'anonymously' link to a given object concurrently. The server maintains a separate system to track deletion locking for objects, allowing anyone to forge or remove an asymmetric link to a common object, and to allow the common object itself to be edited, as long as no one tries to delete that common object. This change can drastically increase performance in cloning objects which point to a lot of non-symmetrically linked objects, since those targetted objects no longer need to be pulled out of the database for editing in order to establish the link. This change bumps the DBStore revision numbers to major: 1 minor: 17 18. [SERVER] Server object accounting fix There was an opportunity for the server's objects checked-out accounting to get out of sync if an object creation operation was not able to proceed to completion as a result of a failure to perform the custom object initialization. Now the server's object accounting should be reliable under all circumstances. 19. [SCHEMA] Updated BSD and Linux schema kits to support MD5 hashed passwords I have put preliminary (but functional) support into the Linux and BSD kits for MD5-hashed passwords. Someone will have to let me know how well this works. -------------------- Changes from 0.99.6 to 0.99.7 ------------------- RELEASE DATE: October 13, 1999 1. [SERVER] Fixed the Ganymede server's registry binding for localhost Michael McEniry (mmceniry@itsc.uah.edu) provided a patch to Ganymede.java which corrects the problem on Linux systems with the server failing on startup with a localhost RMI registry binding permissions failure. 2. [SERVER] Fixed object deletion for multi-level nested objects Martin Schneider (martin@ira.uka.de) wrote to report that deleting objects which contained embedded objects which contain embedded objects fails on transaction commit.. the problem was that the GanymedeSession.getContainingObj() method couldn't walk the embedding stack to find the top-level parent to determine object ownership for logging purposes. GanymedeSession.getContainingObj() will now check to see if it is trying to find the parent of an embedded object which has been processed for deletion, in which case it will check the original version of the object in order to find the original parent. 3. [SERVER] Added support for regexp matching in StringDBField Added support for specifying a regular expression pattern in string fields. Modified the server and schema editor to support regular expression binding to string fields. The older 'OkChars' and 'BadChars' string field parameters are still maintained.. any change to a string field must satisfy any regular expression specified in addition to the OkChars and BadChars parameters. This change bumps the DBStore revision numbers to major: 1 minor: 14 Martin Schneider (martin@ira.uka.de) asked for this change, it seemed like a good idea to me. 4. [SERVER] Fixed server-loading bug from 0.99.6.6 Change 6 to Ganymede.java in release 0.99.6 broke loading data from a freshly dumped schema. Fixed the server initialization so that it can properly reset passwords if the password field is undefined in the supergash persona object. 5. [SERVER] Fixed schema dump bugs in DBObject.partialEmit() Since July there has been a bug in DBObject.partialEmit() which makes it impossible to successfully dump a modified schema to disk and then turn around and use it to load a new database. The problem was that when the server was dumping a ganymede.schema file, the supergash persona was being written to disk without the link to the supergash owner group (owner group 0) that gave it supergash privileges. Actually, there were a cluster of bugs in the schema dump logic. All of them have been fixed, so schema dumping should produce a clean and usable ganymede.schema file now. I knew the code for schema dumping was poorly architected, but I somehow missed the fact that it was so thoroughly broken. 6. [SERVER] Added code to protect the essential server data structures It used to be possible to manually delete the supergash owner group, which would put the ganymede.db file in an unusable state. GanymedeSession.remove_db_object() now refuses attempts to do this. In addition, the Ganymede server now checks the database schema on start-up to make sure that all of the essential database objects are defined, including the supergash persona object, the supergash owner group, the default role, and the system event objects. If any of these objects are undefined in the database on server startup, the server will now recreate them. The server still doesn't do a schema sanity check on startup, though. Still lots more work to do to clean up schema editing as a whole. 7. [SERVER] Fixed logging for IP address changes The IPDBField.getDiffString() method had an error that caused it to report the old value for a changed IP address when it was meant to be showing the new. 8. [SERVER] Added a background task to disconnect idle users The Ganymede server now has a built-in task which runs every minute to disconnect users that have been idle for a certain period of time. Currently, users with no objects checked out of the database will be disconnected after 15 minutes of idle time, and users who are in the middle of a transaction but have not done anything for a long time will be disconnected after 20 minutes of idle time. 9. [CLIENT, SERVER] Made client able to re-acquire server without restarting The Ganymede client is now able to attempt to re-acquire the Ganymede server if the server goes down while the client is running. That is, if the server goes down cleanly while the client is running, the client will close the main window, leaving the login box. The login box will now be able to attempt to bind to a new instantiation of the Ganymede server if the server has been brought back up. In order to do this properly, I had to add a new method to the RMI Server interface (Server.up()), so you'll need to install the client from Ganymede 0.99.7 for use with the 0.99.7 server, and vice-versa. Also modified the client to be more responsive to a server shut-down message, even if the user was sitting on the persona selection dialog. 10. [SERVER] Server now associates embedded objects with container in log Previously, if changes were made to an embedded object that did not result in a modification to the state of the container, the log for that change did not record that the container was involved in the transaction, making such changes invisible to the history panel of the containing object. Now, whenever an embedded object is changed, the log record for the change will be associated its container and the change will show up properly in the container's history view. 11. [SERVER,SCHEMA,DISTRIBUTION] Changes to handle descriptor starvation We put Ganymede in production at the laboratory on October 10th and quickly discovered that the Ganymede server was running into file descriptor exhaustion when builds are done at a high rate of speed. It turns out that one of the problems was that the GASHBuilderTask class in the gasharl schema kit wasn't explicitly closing the file descriptors for the Process object used to do the external build. Looking on the Java BugParade, I found bug item #4025386, which describes the problem and how to fix it. I went through all the BuilderTask classes in all the schema kits included with Ganymede and added a finally {} clause to close the Process file descriptors once the external build was done. Even after this change, I still saw the server run out of descriptors, so I put a 'ulimit -n 128' in the runServer script (64 is the default on Solaris.. the ulimit command is commented out so that people on Linux, etc., don't get an artificially low descriptor limit), and I fixed a few other places in the code where the system was unnecessarily waiting for garbage collection to close resources. File descriptor depletion is still a big issue with Ganymede, as a user with the client login window open is taking up a descriptor on the server for the RMI connection, even though the user isn't doing anything. I'm not sure how much I can do about this, since I believe the only way to force an RMI break is by allowing the remote object to be garbage collected on the client. In any case, the problem isn't so much that the Ganymede server itself is keeping an excessive number of descriptors open, but that the extensive Ganymede/GASH build process we initiate on transaction commit opens dozens of files, taking up lots of the server's descriptors along the way. Java doesn't provide any good way to manage this, but it may be a good idea to put another ulimit invocation in the script run by Ganymede? 12. [SERVER] Fixed really stupid DBEditSet rollback mistake Ugh. Ugh. Ugh. I had broken the DBEditSet rollback code with change #0.99.6.9 below. There was no way it could have ever worked. It didn't come close to working. Not even remotely plausible code. I am dum. I fixed it.. it is now both efficient and correct. 13. [SERVER] Optimized DBEditSet.commit() I reworked DBEditSet.commit() so that it doesn't need to use rollback() to handle an incompletely filled-out object at transaction commit time. Basically streamlined commit() so that it does the minimum amount of work required to check things out, without doing an unnecessary checkpoint()/rollback() pair when one or more objects in a transaction aren't completely filled out. And I checked my work, and I tested the code, this time. 14. [SERVER, ADMIN CONSOLE] Added a deferred shutdown option The server can now be told to disable logins and to shutdown the server when all users log out of the system. This is very useful for shutting the server down cleanly in a production environment. If you use the 'stopServer' script, you can now say 'stopServer -delay' to have the server do a user-friendly shutdown. If you do do 'stopServer -delay', the stopServer script will not wait for the server to shut down before exiting. If you shut the server down through the admin console, a dialog will pop up asking if you want to make the shut down deferred or not. This change involves an incompatible change to the arlut.csd.ganymede.adminSession RMI remote interface used by the server, admin console, and stopServer script. 15. [SCHEMA] Several tweaks to gasharl schema Lots of minor fix-ups to the gasharl schema code, which we are actually using in production at ARL now. -------------------- Changes from 0.99.5 to 0.99.6 ------------------- RELEASE DATE: August 27, 1999 1. [SERVER DISTRIB] Fixed decodeDB decodeDB was failing because the properties weren't being loaded and the db load routine was attempting to find the Ganymede.journal property. 2. [SCHEMA] More improvements to gasharl schema. Fixed ARL maildirect file generation to only emit entries for normal category user records, made it possible to clear the primary user field for systems. Fixed a minor infidelity in hosts_info generation. 3. [CLIENT] Fixed problems with string area gui object I fixed a couple of problems with the JstringArea class used in the Ganymede client to display and edit multi-line string fields. I had to make some changes to the code so that it really didn't try to do editing when the field was not editable, and so that when errors are returned when the JstringArea is edited, the focus-loss update trigger won't get into an infinite loop, popping an error dialog up over and over and over and over again. The JstringArea is one of the least used GUI components in the client, which is why this wasn't detected and fixed a long time ago. 4. [CLIENT] Fixed error in handling fixable transaction failure The change I made in 0.99.5 to the client's handling of catastrophic transaction commit failure broke proper handling of non-catastrophic, correctable commit failure.. if such a transaction failed to commit, gclient would reset its state, even though the transaction was still open and repairable. gclient.commitTransaction() now handles both circumstances properly. 5. [SERVER] Added support for MD5-hashed passwords. Added MD5 support to PasswordDBField.java. Bumped DBStore.minor_version to 13 for MD5 support. The server can now store and authenticate using MD5-hashed passwords. Schema kits can be written to input MD5-hashed passwords into the system as well as UNIX crypt()'ed passwords. Neither the Linux nor the BSD schemas have yet been modified to support MD5 passwords, but the PasswordDBField code now supports MD5. 6. [SERVER] Improved the server's password reset logic Previously, if the -resetadmin parameter was given on the command line, the server would always open a new transaction and reset the supergash password. Now the server checks to see if the password has changed before doing the edit. This cuts down on the redundant 'hey, i set the supergash password!' mail that Ganymede was sending out. 7. [SERVER] Fixed adminPersonaCustom.convertAdminInvidToString() The new DBLog transaction logic for finding an email address to mail to was broken when the change was made by an end-user and not by an admin persona. I fixed adminPersonaCustom.convertAdminInvidToString() so that it can gracefully deal with the possibility that the 'admin invid' in an DBLogEvent produced by the DBEditSet commit() routine is actually an end-user Invid. 8. [SERVER] Reworked DBSession.createDBObject() The old createDBObject() call in DBSession had problems if a user in an owner group tried to create a new object at the same time that another user had the owner group checked out for editing.. the object create would fail in an ungraceful manner, resulting in the server thinking that the user had a negative number of objects checked out, and getting very confused. The DBSession createDBObject() code now does a transaction checkpoint before attempting to place the newly created object in the proper owner groups. If one of the owner groups turns out to be unavailable, the object create will fail and the transaction will be rolled back. I also modified createDBObject() to return a ReturnVal so that detailed failure information can be returned to the user if object creation fails. This is continuing a trend.. I've been finding the need to go through the code and make some of the server's internal paths better about returning detailed error information. 9. [SERVER] Improved DBEditSet.rollback() code Minor changes to the transaction rollback code, to take advantage of the optimized vector compare operations in arlut.csd.Util.VectorUtils. Should make rollbacks in very large transactions noticeably faster. 10. [DISTRIBUTION] Added template schema directory, fixed installServer In 0.99.5 and for awhile before, the installServer script would break if you tried to install the Ganymede server without choosing a schema kit, which caused installServer to break with a complaint about 'Couldn't write schema build config'. installServer now goes ahead and installs an empty schema directory with all of the build scaffolding required to develop your own schema kit. I am planning on significantly revising the way that schema kits are packaged and distributed to make it easier to distribute schema kits independently, but that is something for a future revision, I think. Thanks to Glen Joseph for reporting this. 11. [SERVER] Reworked embedded object initialization In 0.99.5 and before, embedded objects had their custom initializeNewObject() methods called before the embedded object was linked into its container, making it hard for custom code to make initialization decisions based on the container's state. This has been fixed; initializeNewObject() for embedded object types is now called after the object has been linked into its parent. In addition, initializeNewObject() now returns a ReturnVal rather than a boolean, to allow detailed error messages to be returned to the user. All custom DBEditObject subclasses included in the Ganymede distribution have been brought up to date with the new initializeNewObject() method signature. Thanks to Martin Schneider for bringing this to my attention. 12. [SERVER] DBEditObject.createNewEmbeddedObject() now returns ReturnVal Another change made to provide better feedback paths for server errors. This method wasn't one that was ever overridden in the schema kits provided with Ganymede, but adopters who did override this method will need to modify their custom code to return a ReturnVal rather than a boolean. 13. [CLIENT] Fixed string field GUI component.. now limits size properly Way back in dev6a, I modified the arlut.csd.JDataComponent.JentryField class so that it would employ a custom DocumentModel to make sure bad characters couldn't be entered into a string/number/ip field in the Ganyemde client. Looks like I had somehow missed testing the code which was supposed to prevent entry of characters after the size limitation on the field had been met. There was code there for that function, but it wasn't correctly functional. Modified the arlut.csd.JDataComponent.JentryDocument class to check for the number of characters currently in the JentryField versus the stated limit (if any) on the number of characters allowed in the field. 14. [SERVER] Moved GanymedeServer creation, binding to end of server start Previously there was a remote chance that a user or admin console could attach to the server before all startup housekeeping was taken care of. The GanymedeServer RMI binding is now the very last thing done by Ganymede.main(). 15. [CLIENT] Fixed client behavior for Java 1.3 beta (Kestrel) In the new Java 1.3 beta, code-named Kestrel, a lot of JInternalFrame code has been changed. Several things in the Ganymede client had to be tweaked to insure internal windows in the Ganymede client work acceptably well with all existing versions of Swing. -------------------- Changes from 0.99.4 to 0.99.5 ------------------- RELEASE DATE: July 28, 1999 1. [SCHEMA] Several gasharl schema mods The commitPhase2() method in userCustom for the gasharl schema now calls out to 'directory_namer' and 'directory_maker' to handle external actions when users are renamed or created. Added support for generation of the ARL maildirect file, which will be of absolutely no interest to anyone outside of ARL. 2. [CLIENT] Fixed client behavior on catastrophic transaction commit failure The client wasn't properly getting rid of any edit windows if a transaction commit failed catastophically. This was occuring during development and test of changes in 1.) above.. a NullPointerException was causing the transaction to be aborted rather than committed, and the client wasn't properly resetting its state to reflect this. 3. [DOCUMENTATION] Put a warning about deadlock possibilities into DBEditObject guide The DBEditObject commitPhase1(), commitPhase2(), and release() methods are called by the server while portions of the database are locked. Using the GanymedeSession query mechanism will very likely bring the server into deadlock, as I discovered. Documented this in the DBEditObject subclassing guide, as well as the javadocs for those methods. 4. [SERVER] Revised GanymediatorWizard spec, logic In 0.99.4 and before, the GanymediatorWizard logic depended on the custom wizard author writing a getStartDialog() method that had to be smart enough to unregister() itself if no further interaction with the user was needed. It was very, very easy to not do this, and so leave the client's GanymedeSession with a registered wizard blocking further activities. To prevent this problem, I have deprecated getStartDialog() in favor of a processDialog0() method to start the wizard sequence. This has the advantage that the GanymediatorWizard's respond() method will automatically unregister a wizard that no longer needs to talk to the user. This is an incompatible change in the GanymediatorWizard class that will break existing wizard-using custom code, but fixing this now will make wizard use far more reliable, and it would only be harder to fix this later. I don't expect many (any?) folks outside of ARL have written wizards for use with custom schemas yet. For those who are interested, the GanymediatorWizard javadoc header now has some hopefully usable documentation on how to do this. (I've also written a guide on the whole subject.. see change #18.) Modified all wizard code in all of the included schema kits (not counting the not-maintained ganymede.only schema) to use the modern wizard support code. 5. [SERVER] Made transaction commit, abort clear active wizard Another fix to help keep wizards from getting stuck.. aborting or committing a transaction will now clear any wizard from registration with the GanymedeSession object. 6. [SERVER] Improved lock system to prevent intra-thread deadlock Modified the DBSession and DBEditSet lock handling code to help insure that the server can't be deadlocked by a thread attempting to establish a lock when it already holds one that would cause the new lock establish() to deadlock the server. This should only be an issue in terms of deadlock brought about during transaction commit through errors in custom-plugin development.. the existing system already prevented deadlocks between threads. Now the server will report an intra-thread lock error rather than simply dead-locking. Note that this deadlock prevention is in the form of an InterruptedException being thrown, rather than permissive lock-sharing.. the reason for this is that the operations that require a read or dump lock (such as a query) will not be able to provide transaction-consistent results when called from within a transaction commit. This change is entirely for the purpose of making the server more friendly to customizers, and should not have any significant effect on normal server operations. 7. [CLIENT] Fixed password handling in dialogs passed to the client Wizards that asked the client for a new password value (as in the user reactivation wizard in the gasharl schema) were not able to get a password back because the password field logic in StringDialog and JpassField was not working properly. Wizards can now request a new password from the client properly. 8. [SERVER] Changed dump process to be safer Previously, the server would dump the database by first renaming the old on-disk database to ganymede.db.bak, and then write the current in-memory database to ganymede.db. This meant that if the server was killed while writing out the database, there would be an incomplete ganymede.db file in place, which would require the admin to manually recover from the ganymede.db.bak file. Things would always be recoverable, but it wasn't an automatic process. Now, the ganymede.db file is not renamed until the server has completed dumping out its new dump, which is called ganymede.db.new during the dump. There are still one very narrow opportunity for stopping the server at a point in which the server can't recover on its own at restart, but the odds of this occuring are infinitesimally low now.. only if the server is killed after it has renamed ganymede.db to ganymede.db.bak and before it has renamed ganymede.db.new to ganymede.db will the server be unable to properly recover on start-up. This change does slightly increase the amount of disk space needed during operations, as the system needs to have enough disk space for three versions of ganymede.db at a time during a database dump. Thanks to Darrell Tippe, , for reporting the problem. 9. [SERVER] Made DBObjectBase explicitly record max object id The Ganymede server in some cases could erroneously re-use an Invid. This could occur if an object was deleted, and the server was restarted before another object of that type could be created. The server now explicitly records the maximum object id seen for each object type in the ganymede.db file. This change bumps the DBStore revision numbers to major: 1 minor: 12 10. [SERVER] Seriously Improved Logging, Mailouts Systems Reworked lots and lots code in DBLog.java, DBEditObject.java, and DBEditSet.java to make all of the transaction logging stuff work right. -- Mail-related exceptions will no longer cause transactions to fail to commit.. the server will report the mailer error, but continue with normal processing. -- Modified the Qstmp class so that it can queue messages for sending on a background thread.. the extensive mail-outs in the revised logging system was noticeably slowing down transaction commits. All e-mail messages sent out by the DBLog class will be done without blocking the logging thread. -- The DBEditSet class now does transactional event logging after a transaction's objects have had all of their commitPhase2() methods called. This change makes it possible for a commitPhase2() method to send mail out. -- Added variants of DBSession.viewDBObject() that will automatically retrieve the original version of a DBObject that is being deleted by the current transaction. Useful for getting the original version of an object during transaction commit from the object's Invid. -- Added a getLabel() override to DBEditObject.java that will automatically return the object's pre-deletion label if the object is being deleted and the DBObject getLabel() routine returns null. -- Added standard methods to allow custom objects to identify email addresses that should be notified when changes are made to them. Useful for making sure that users get cc:'ed on any changes made to their account, etc. These methods are documented in the DBEditObject subclassing guide, and are used by the logging system. 11. [CLIENT] Added tooltip support to checkboxes, other GUI field types A number of the GUI field types supported by the clients were not being added to containerPanel with any registered field comments set as tooltips. Fixed. 12. [SERVER] GanymedeScheduler could lose on-demand tasks If the Ganymede server tried to initiate an on-demand task that was currently running, the scheduler would 'lose' the task instead of properly doing back-to-back execution of the task. Big oops. 13. [SERVER] GanymedeBuilderTask didn't do overlap properly The GanymedeBuilderTask base class has code that remembers the last time the builder task was run, so that it can check for changes in the various object bases that occurred since the last builder task run. Unfortunately, the time stamp was being recorded after the builder task completed, even though changes could be made in the database after builderPhase1() finishes and before builderPhase2() completes, which left the possiblity for build tasks to not be re-issued properly if two transactions affecting the same object base were committed back-to-back . The GanymedeBuilderTask base class now properly records the time before entering builderPhase1(), so that rapid sequences of changes to the database will always properly trigger subsequent builds. 14. [SERVER, CLIENT, CONSOLE] Cleaned up login sequence Both the admin console and client will now give a nice dialog if login fails. Previously, the admin console showed an exception trace, which did not make it clear that the problem was a bad username or password. Made the clients include error.gif in several of their dialogs. 15. [CLIENT] Removed extraneous menu items from object windows The object view/edit windows had a menu on them that included a number of options that didn't always apply, as well as a 'print' option which never worked well enough to be available to the end user. Now, the object window's "File" menu only includes actions that can't be done anywhere else. The File menu will now only present the 'Set Inactivate Date' option when the object being edited can in fact be inactivated. 16. [SERVER] Cleaned up schema dumping of persona objects Modified DBObject and DBObjectBase's partialEmit() methods so that supergash's locally-defined email address is not saved into the ganymede.schema file. 17. [WEB FILES] Reworked the web access system for the Ganymede clients Brian O'Mara did a very nice job of making a new set of web pages for the Ganymede clients. The new primary web page uses JavaScript to launch the clients in their own frames, making it possible to run a client and console simultaneously, and to be able to close the original launch frame without killing the clients. 18. [DOCUMENTATION] Added a detailed guide to Wizard authoring Added another long document on customizing the server with plug-in code, this time on the topic of wizard authoring. -------------------- Changes from 0.99.3 to 0.99.4 ------------------- RELEASE DATE: July 8, 1999 1. [SERVER] Optimizations to permissions system The simplifications to GanymedeSession.getPerm(object,field) that I did for 0.99.3 was in fact doing too much work, and the logic didn't flow clearly. GanymedeSession.getPerm(object, field) is now correct, efficient, and easy to read. 2. [SERVER] Added new versions of anonymousLinkOK/UnlinkOK() to DBEditObject It was previously impossible to grant anonymous linking privileges to a field only when the other side of the link was being created in a particular object type/field. This posed a problem in the circumstance where you want to allow a specific field in a given object type to be linked to another object type's backlinks field without having general editing permissions for the other object. I added a couple of new versions of these methods that take additional parameters identifying the originating object and field, so that customizers can take the other side of the proposed link into consideration before granting anonymous linking permissions. See the DBEditObject.anonymousLinkOK()/anonymousUnlinkOK() javadocs for details. Hopefully I'll get around to writing a full-scale technical manual for Ganymede that will go into when/where you would use these methods. Modified InvidDBField.bind() and InvidDBField.unbind() to call the new versions. 3. [CLIENT] Improved StringSelector used in String and Invid fields The StringSelector GUI component used in the client to allow editing of String and/or Invid vector fields has been fixed so that it does not include the text box for entering custom entries unless the StringSelector is editable. Fixed some minor GUI problems with the StringSelector resizing itself to a minimum size after adding a new entry to an empty no-choices-provided string selector, made the 'remove' button disable itself after removing something. 4. [SCHEMA] Improved email list behavior in gasharl schema An email list owner can now add any user, list, or redirect to his list without having general editing privileges for that user, list, or redirect. This takes advantage of change #2, above. 5. [INSTALL] Various improvements to the install process Modified installServer so that the custom loading instructions it writes out at the end is sent to a README.custom file in the installed server's directory rather than to screen. No sense spewing a couple of screen's worth of customized install instructions if the user has to do cut and paste to save it to a file for reading. Added an installWeb script to install the web files into a designated directory, separate from the normal UNIX client install. This has the advantage that you can install the web resourcs for Ganymede without having to have Swing installed locally (which installClient checked for.) Added a handy index.html file for the Ganymede web resources, got rid of the old activator and hotjava directories, added a nice set of web frames to allow the installer to bring up their browser and directly visit the directory where they installed the web resources. 6. [WEB FILES] Updated plugin client files for 1.2 The plugin client files were re-generated from the 1.2 htmlconvertor utility, and now include proper links to the latest version of Sun's java plug-in for Solaris and Windows. 7. [SCHEMA] Fixed BSD schema master.passwd parser, Linux passwd parser The old Linux and BSD passwd file parsers would break if they encountered a user record with a blank password field. Modified GanymedeServer.login() and GanymedeServer.admin() to make sure the server won't throw a null pointer exception if the database contains a user or admin persona with no password during the login process. If a Ganymede user record has no password set, that user will not be able to login to the Ganymede server. Unlike UNIX, Ganymede never lets anyone log in without a password. 8. [ADMIN CONSOLE, SERVER] Reworked admin console, server's admin API Fixed the admin console so that it will properly log itself out when it is closed through the window system. In prior versions, the admin console wanted to know the name of the supergash account on the server, so that it could preemptively refuse to perform certain operations.. this really makes no sense at all, and was never needed for security. The admin console now goes ahead and attempts such operations, and depends on the server properly refusing the operations. The install scripts no longer prompt for the supergash account name when installing the UNIX and web clients. Also in previous versions, the server wasn't actually honoring the console permissions checkboxes in the admin persona objects.. any admin persona could log into the server via the admin console, but no one other than supergash could do any control operations. The admin persona console permissions checkboxes now properly control the server's response to admin console operations. Admins other than supergash and monitor will need to log into the server via the admin console using their full persona name.. i.e., 'broccol:GASH Admin'. 9. [DOCUMENTATION] Revised, improved the install guide, added FAQ Significantly revised and enhanced the install guide, corrected some mistakes, included information on the use of installWeb. The text INSTALL file is now a lynx-generated version of the HTML file.. it was too much work and too error-prone trying to maintain both independently. Added a text FAQ file. Will convert this into a nice web version at some point. -------------------- Changes from 0.99.2 to 0.99.3 ------------------- RELEASE DATE: June 23, 1999 1. [SERVER] Fixed value() in StringDBField.java The value() method in StringDBField.java was improperly forcing a permissions check, despite the fact that value() was used for server-side code only. This was causing a problem at transaction commit-time under certain conditions, caused by the PermMatrix.union() bug below. 2. [SERVER] Fixed bugs in permissions system Ugh, I had screwed up PermMatrix.union() in 0.99.2, the object->field inheritance logic wasn't working properly. I fixed PermMatrix.union(), simplified GanymedeSession.getPerm(), and modified both PermEntry.union() and PermEntry.intersection() to optimize out a lot of new PermEntry creation. -------------------- Changes from 0.99.1 to 0.99.2 ------------------- RELEASE DATE: June 18, 1999 1. [DOCUMENTATION] Seriously Improved Javadocs Lots more improvements to the source code javadocs. Improving the javadocs is an ongoing project.. I really want to make it possible to get a very good feel for how the entire system works on a technical level by simply browsing through the javadocs. It's an interesting exercise, and a continuing one. If you find yourself puzzling about something in the code, please let me know so I can document it better. 2. [SERVER] Improved DBLock, DBObjectBase classes slightly Added some more explicit lock status check methods to DBObjectBase. Modified GanymedeAdmin's schema edit status check to use the new DBObjectBase.isLocked() method. Pulled some methods and variables from the DBLock subclasses up to DBLock. Added DBLock.isLocked(Vector) to safely test a lock against a vector of DBObjectBases. Modified GanymedeSession.queryDispatch() to use the new method, and to verify that the database remains read locked at the completion of the query loop. (the user could have been knocked off via the admin console, etc.). Documented all the pieces of the lock system in the Javadocs. 3. [SERVER DISTRIB] Added permdecodeDB command permdecodeDB will take an existing ganymede.db file and report on the permissions bits encoded by roles in the database. Useful for debugging permissions code problems. See #4 below. 4. [SERVER] Corrected, simplified server's permissions system The Ganymede server's permissions system had a complex and (as it turned out) broken system for inheriting 'default permissions' for fields in an object. Previously, an object type could have a default permissions bitset registered, and any fields in that object for which permissions had not been explicitly set would take on the default value. This was intended to support reasonable behavior for newly created fields, but the code to implement this had problems in some odd cases. The notion of an explicitly recorded default permission set for fields that differed from the permissions on an object type itself has been removed. In keeping with this, the setDefaultFieldPerms() methods on both PermissionMatrixDBField and perm_field have been taken away, in favor of setFieldPerms(), which sets permissions for all existing fields in an object type, but doesn't involve the complex default logic. The permissions logic has been simplified, and better documented in the javadocs. Now, when new fields are added to object types through the schema editor, all Role objects will grant the permission for the object as a whole to the new fields. If you run the permissions editor in the client on a Role object's permissions fields, you can change this default. Since the Ganymede client's permissions editor dialog had no code for calling the setDefaultFieldPerms() methods on perm_field, this change shouldn't affect any custom work people have done. The gash and gasharl ganymede.schema files did ship in 0.99.1 with a default permission set on a few object types. People using a ganymede.db file derived from a gash or gasharl ganymede.schema may find that they need to use the permissions editor to correct problems in the GASH Admin Role object's permissions bits. 5. [SERVER] Changes to permissions fields now descriptively logged If an administrator makes changes to the permission bits in a Role object, the server's log will now record the precise changes, which will be visible in the Role object's history panel. The history recorded may be a bit deceptive in the case where a field which previously had no explicit field-level permissions set has them set.. if the object type has a permission of view/create/edit, and you edit the field's permission to set it to view/edit only, the log file will show that the field gained view and edit, when it effectively lost create, which was previously inherited. 6. [SERVER] Miscellaneous methods added Added debugging toString() to DBField, PermMatrix classes. Added getFieldName(short) to DBObject, db_object. 7. [ADMIN CONSOLE] Fixed admin console The admin console now works properly in a browser, and properly initializes under all conditions. The magic incantation to get the Ganymede Admin console to find the arlut/csd/ganymede/GanymedeServer_Stub.class file was to include the arlut/csd/ganymede/Client.class in the ganymedeAdmin.jar file. Apparently, Sun's RMI classloading logic freaks out if it comes across a reference to an unavailable RMI remote interface parameter in a RMI remote method _Stub.class file, even if the freaked-out client in question never refers to that method call. I tried *everything* to figure this out, before finally noticing the blurb in the Java plug-in's console about the Client.class load attempt.. d'oh. I wound up having to include arlut.csd.ganymede.Client and arlut.csd.ganymede.GanymedeScheduler because both were referenced by RMI methods or serialized objects the admin console needed. In addition to fixing the ganymedeAdmin.jar file, the applet code was revised to be closer to that of the standard client, to improve its behavior and appearance in a web browser context. I still need to make a nice 'admin console' logo for the admin console applet. Thanks to Charles Adams (charles.adams@central.sun.com) and Andy Johnson (andyjohnson@engineer.com) for reporting the problem with the admin console not working properly with the Java plug-in. 8. [SERVER] Fixed login logic In 0.99.1 and before, the server had an ambiguity that would allow users to login to the wrong priviliged admin account on occasion, if there was more than one account with the same persona name. I.e., if there was persona account 'broccol:supergash' and 'supergash', each with different passwords, the broccol:supergash password could allow access to the non-user-associated supergash admin account. This was true for both normal client login and for admin console attachment. 9. [SERVER] Fixed DBQueryHandler's field DEFINED logic The Ganymede server's DBQueryHandler would throw an exception if attempting to process a "field is defined" QueryDataNode if the field in fact did not exist. -------------------- Changes from 0.99 to 0.99.1 ------------------- RELEASE DATE: May 27, 1999 1. [SERVER] Made decodeDB omit built-in field types by default Did a bit of work to clean up the schema report code generated by decodeDB. 2. [SERVER] Cleaned up, documented DBEditSet, DBEditObject Added lots and lots of documentation to the DBEditSet transaction class, made the commit() operation a bit more robust in terms of relinquishing a write lock on exceptions and errors. The DBEditObject class was modified to include a boolean finalAbort parameter in the release() method. Javadocs for this method were improved to clarify and document the different ways this method can be called. 3. [SERVER DISTRIBUTION] Added a stopServer commandline app In order to facilitate automatic shutdown of the Ganymede server on operating system shutdown, I've created a command-line stopServer application that can shut the server down if you keep the server's supergash password in its ganymede.properties file. Yet another thing for production use.. we use this to support automatic server shutdown when we reboot our Solaris Ganymede server. 4. [SERVER, CLIENT DISTRIBUTION] Made registry port number configurable The Ganymede server and clients can now be configured to use an RMI Registry on a non-standard tcp port. This is necessary if you are going to run the Ganymede server on the same system as other RMI servers (such as Sun's SIMS administration console). The server, client, admin console and password client all now accept a property/parameter called ganymede.registryPort. If the ganymede.registryPort is not set, all Ganymede code will default to the standard RMI registry port, 1099. 5. [SERVER] Added Session.findLabeledObject() Added a convenient shortcut method in Session called findLabeledObject() which allows the client to quickly get an invid from an object type and name without having to use the full Query() method. This method is used by client/rpcpass.java. 6. [CLIENT] Added client/rpcpass.java to support Linux NIS rpc.yppasswdd Added a program 'rpcpass' to the client distribution. rpcpass is designed to be used with the -x/--execute option present in versions 1.3.6.92 and later of the Linux NISkit's rpc.yppasswdd daemon (included in the ypserv distribution), to allow users to use yppasswd to change their password in Ganymede. When run, rpcpass reads a single line from stdin, which should be of the form o: p: s: g:\n Where the p:, s:, and g: fields are each optional. After reading this line from stdin, rpcpass will connect to the Ganymede server and change the password and/or shell. If this operation succeeds, rpcpass will emit a single line to stdout, OK\n which is to be read by rpc.yppasswdd to signal success. If there are any problems, these will be described in a report to stdout, which rpc.yppasswdd will take as a failure signal. Note that while the rpc.yppasswdd daemon may pass gcos information to rpcpass, the gecos field is formatted differently on different operating systems, and so rpcpass does not attempt to handle it at all. Of course, any program can use the rpcpass program to propagate password/shell change requests to Ganymede, not just the Linux NIS kit's rpc.yppasswdd daemon. 7. [SOURCE] Fixed a couple more PATH problems with building sources A couple of fixes relating to doing source builds with '.' not in one's PATH. EXECUTING: src/server/build ERROR : buildrmi: command not found FILE FIXED: src/server/build PREV LINE : buildrmi NEW LINE : ./buildrmi EXCECUTING: src/classes/buildJar ERROR : sync_tree: command not found FILE FIXED: src/classes/buildJar PREV LINE : sync_tree NEW LINE : ./sync_tree Reported by Andy Johnson (andyjohnson@engineer.com). 8. [DOCUMENTATION] Significantly Improved Documentation Fixed all link errors in the javadocs. Added more javadocs to several classes. Reworked doc/index.html. Added an HTML version of the INSTALL file, cross-linked to a file glossary. Added the log file format documentation to the doc distrib. -------------------- Changes from 0.98 to 0.99 ------------------- RELEASE DATE: April 16, 1999 1. [SCHEMA] gasharl schema mods Various kinds of objects listed in an emailList object are now shown with extra detail so that admins can see what sort of thing they are dealing with. Modified interfaceCustom so that the server will now check ethernet addresses for valid form. 2. [CLIENT] Newly created object windows can now be undone. Put the close box back on object creation windows.. now if you close the window, the client will prompt you as to whether you want to delete the object. If you do, the server will drop the newly created object from the server when the transaction commits. Unfortunately, the code to handle intercepting the internal frame close request in framePanel.java and windowPanel.java had to be hacked with the VetoablePropertyChangeListener since Swing 1.1 and 1.1.1-beta1 have JInternalFrame.setDefaultCloseOperation() totally broken. If you click the close box on an edited object, you'll also get a dialog explaining what that does and does not do. 3. [SERVER] Server always allows deleting a newly created object This provides an exception to change 0.98.5 to allow the client to always undo an object creation, even if normally they could only inactivate the object, not delete it. The server had always had support for DROPPED objects as well as DELETED objects, the change above just really takes advantage of this more. 4. [SERVER/CLIENT] Added case-insensitive regexp matching The server and client now support performing a case-insensitive regular expression comparison when querying on string and object reference (invid) fields. 5. [CLIENT] Scalar invid fields are now always sorted Scalar invid fields would become unsorted when the server instructed the client to refresh them. The client will now properly sort invid lists from the server on field refresh as well as on field construction. 6. [CLIENT] Client code simplified, documented, improved Embedded object vector panels were seriously broken, and would break when you tried to delete entries. The vectorPanel refresh logic was totally reworked and should behave properly in all situations now. Loading embedded object vectors will be more efficient now. The client's tracking of container panels active loading information from the server has been simplified and better documented.. the client does less work now to track container panels, and hitting cancel or commit while loading a panel should still do the right thing. Lots and lots of javadocs added and corrected in the client code. Some of the debug output when running the client in debug mode has been cleaned up. 7. [CLIENT] Fixed error on loading 'inactivate.gif' on HPUX JVM The client included code to try to create an inactivate icon from a file called inactivate.gif. That file did not exist in the jar file distributed with Ganymede 0.98, and the JVM on HPUX 10.20 threw an exception on this, even though Sun's JVM's do not. Reported by Lewis Muhlenkamp (lewism@tt.comm.mot.com) 8. [DISTRIBUTION] Build scripts, make files no longer require '.' in PATH The Ganymede install and build scripts required '.' in the user's PATH during install. This should no longer be the case. Reported by Lewis Muhlenkamp (lewism@tt.comm.mot.com) 9. [DISTRIBUTION] configure prompts for Swing jar location Previously, src/make client would fail because the client's build script didn't know how to find the Swing swingall.jar file if it wasn't in the user's CLASSPATH. Now the initial configure bootstrap script will ask for the location of the Swing jar files so that the build scripts in the source tree can be properly configured. Reported by Lewis Muhlenkamp (lewism@tt.comm.mot.com) 10. [CLIENT] Fixed focus handling for IP address component The JIPField GUI component class had problems with reentrancy that could cause problems when dialogs were thrown up in response to focus loss. 11. [CLIENT] Added toolbar to the Query Results window The File menu on the Query Results window was really unobtrusive, and didn't really emphasize to users that they could mail out the query table. Brian put in a spiffy mini-toolbar to show people what's up. 12. [CLIENT] JComboBoxes in client are more keyboard friendly Previously, JComboBoxes in the client used the default KeySelectionManager, which only allowed you to search for items by their first letter. You can now type in a full name of an object and as long as you don't pause for more than a half-second between keystrokes, the JComboBox will find the object by its full name. Actually, this doesn't work as well as it sounds, because Swing's KeySelectionManager stuff doesn't let you use the keystrokes to choose an entry in a JComboBox before actually selecting it, and selecting items in the Ganymede client will tend to be a slow operation due to the round-trip to the server. 13. [SERVER DISTRIBUTION] Added decodeDB command Added a new executable in the server's bin directory, decodeDB, which takes the name of a ganymede.db or ganymede.schema file and generates a print-out of the file's object and field type information. This was added mainly to make it easier for me to do quick checks on the ganymede.db and ganymede.schema files packaged with Ganymede releases. 14. [DISTRIBUTION] Fixed linux, bsd, nisonly schema kits In Ganymede 0.98, the linux, bsd, and nisonly schema kits had an incompatibility that rendered them inoperable. This had to do with a field in the admin persona object type that was not defined in these kits, but which the server had been modified to depend on. I've modified the kits so that the field is defined, and modified the server so that the lack of the field won't prevent an existing ganymede.db file from being usable. Reported by Nikola Nedeljkovic, nikola@carbonix.iam.tu-clausthal.de 15. [SERVER] Upgraded to gnu.regexp 1.0.8 Updated the gnu.regexp classes used in the server to version 1.0.8. -------------------- Changes from 0.97 to 0.98 ------------------- RELEASE DATE: March 17, 1999 1. [BUILD] Ganymede build scripts moved out of db/out to db The Ganymede server now uses a property called 'ganymede.builder.scriptlocation' to locate the builder scripts to be run by the builder tasks registered in the server. Previously, the builder tasks ran the build scripts in the out directory, which wasn't really compatible with the decision in 0.97 to have the build tasks archive the output files written by the build tasks. Now the build scripts are expected to be located by default in the directory about out, which allows the zip archives to be cleanly made. There is still some confusion here.. in theory, you can have multiple build tasks registered in the server, each of which will try to zip up the out directory. This is not optimal, but what to do about it? 2. [SCHEMA] Added emailListCustom class to gasharl schema kit. The email list members field is an invid field that can point to objects of different types. It is used to allow the email list object to have members that are users, external email listings, or other email groups. Previously, the email list members field couldn't really be edited after the bulk loading process was complete. 3. [CLIENT] Made windows for newly created objects non-closeable The client allows the user to close object windows manually as a convenience, to avoid cluttering up the client when editing lots of objects. Unfortunately, if we allow the user to close a newly created object, there isn't necessarily a good way of getting that window back if it turns out that the user left some mandatory field unfilled when they go to click on 'commit'. Now object creation windows will not be closeable, so that it's not possible to 'lose' object windows that you need to do further editing on. 4. [CLIENT] Modified the list editor GUI component The 'list editor' GUI component used in the client may have a text field at the bottom to allow the user to simply type in something to add to the list. Previously, the 'Add' button connected to the text field was enabled all the time, confusing users manipulating the component. Now the 'Add' button will only be enabled when the user has entered something into the text button. 5. [SERVER/CLIENT] Modified removal/inactivation handling The server now by default refuses to allow objects to be removed that have an inactivation protocol defined. supergash can go ahead and remove objects directly, and custom DBEditObject subclasses can still redefine this behavior by overriding canRemove(). In conjunction with this change, the client has been modified so that it will always show 'delete' as an option when right-clicking on an object, even though the object may have an inactivation protocol defined. This makes things simpler, since it would be difficult to handle the delete toolbar icon properly if I just wanted the client to prevent the user from ever trying to delete an object that can be inactivated. And besides, the user might be operating with supergash privileges. 6. [SCHEMA] Lots of refinements to gasharl schema Modified the loader code to use BufferedReader, and to take care of a few deprecation warnings. Loading files from GASH should be a good bit faster now. The GASHARL schema now includes fields in the admin persona and owner group objects to track information used for more complete GASH compatibility. New users and groups will be created with their uid and gid starting in a numeric range compatible with GASH's permission model if the owner group has a minimum uid/gid set. The GASHARL schema now includes support for handling ARL contract information, which will be of no interest to anyone outside the lab. 7. [CLIENT] Reworked the persona select handling The client now prompts users with multiple admin personae with a persona selection dialog on log-in. 8. [SERVER] Fixed the html schema dump code in DBStore.java Oops. DBStore had my home directory path hard-coded when it should have been using the ganymede.htmldump property. Fixed. 9. [SERVER] Fixed a bug preventing creating new object types in develop mode The server's schema editing code had a bug that caused it to reject the creation of new object types when the server was run with -develop on the command line, which allowed for the creation of new universal fields. Not a bug that anyone else should have run into, but some aspects of this bug had the server doing some unnecessary extra work. 10. [CLIENT] Changed date representation in the query table The query table will now use 4 digit years when showing dates. 11. [CLIENT] Fixed Calendar GUI Previously, viewing an object that had date fields in it was not handled properly.. the date field in most respects did not act properly (clear button, calendar popped up in edit mode, etc.). Fixed bug in JPanelCalendar which caused the calendar's year field not to be refreshed properly upon rejecting a date as out of range. 12. [CLIENT] Fixed stupid lingering 'working guy' window bug Fixed the problem with the 'working' internal frame not being properly disposed of, and with it being hidden behind existing windows when created. 13. [CLIENT] Redesigned query dialog The querybox has been redesigned for clarity and user-friendliness. The querybox now allows the ownerlist field to be searched on. 14. [SERVER] Optimized memory handling for strings All strings loaded into the database are now interned(), trading database load time for memory/runtime efficiency. Not sure that this makes a noticeable difference, but it will be of some help. 15. [CLIENT] Fixed dialog placement and sizing errors The JCenterDialog placement code was broken if the dialog was larger than the frame parenting it. All Ganymede dialogs should now always be entirely visible on screen. The JCenterDialog's pack() method improperly adjusted the size of centered dialogs, causing the edges of centered dialogs to be too small. All dialogs should now be properly sized on NT as well as UNIX. 16. [SERVER] Empty strings are considered undefined in StringDBField The server's required fields logic wasn't detecting an empty string (a string equal to "" rather than null) as an undefined field, which it should do and now does. 17. [SERVER] Improved error reporting paths in server Changed the verifyNewValue() methods in DBField and DBEditObject to return a ReturnVal so that those methods can pass back detailed error dialogs to the user. 18. [SERVER/ADMIN CONSOLE] Added more information to admin console Added a column to the active user table to show how many objects each user is actively editing, to help track actual use. Added a column to the task table to show when each task was last run. -------------------- Changes from 0.96 to 0.97 ------------------- RELEASE DATE: February 11, 1999 1. [DISTRIBUTION] Fixes to the distribution set There was an error in scripts/sync_tree.admin.in.. it didn't include the NameSpaceEditor class required by the admin console's schema editor, so editing namespaces in the schema editor was broken in 0.96. Thanks to frederick.j.dickey@boeing.com for reporting this. 2. [DOCUMENTATION] Fixes to the customization guide The DBEditObject customization guide has lots of references to javadoc pages, but the method links weren't properly constructed for use with the 1.2 javadoc output format. You should now be able to click on method names in the customization guide and be taken directly to the method docs. Brought the guide's content up to date with recent changes to DBEditObject. 3. [SERVER] Amended journal loading code for production mode The journal loading code in the Ganymede server now simply complains politely to stderr if the journal is truncated inappropriately, rather than throwing an IOException. This allows the server to recover gracefully if the server was killed while in the middle of writing a transaction to its journal. The Ganymede server no longer keeps the old journal files around, but rather just keeps a single back-up. While it was entertaining doing a hexdump on old journal files to see what had been done, it cluttered the db directory more than being of any use. 4. [SERVER] Changed how file backups are handled Previously, all of the schema kits' builder tasks copied individual files to file. when the builder task was re-run. Now any time a builder task is executed, the existing output files are zipped into a file named .zip in an 'old' directory in the output directory. Actually, didn't modify all of the kits.. I didn't bother to modify the ganymede.old kit, which is really in need of a major overhaul. The ganymede.db file itself is now archived when the newly created archive task is run (on command by an admin console currently), or when the server starts up with a dirty journal. 5. [SERVER] Enhanced Task Management The server's task scheduling system was basically replaced. The old 'Builder Task' object type is now a generic 'Task' type, with support for editing scheduling parameters directly from the Ganymede client. You can now add, remove, or tweak any task's scheduling parameters from the Ganymede client. Previously, of course, all but the builder tasks were configured by hand in Ganymede.java. Now it will be possible for Ganymede adopters to have total control over task registration and scheduling without having to edit code. The downside to this is that the server will not have the 'standard' tasks scheduled unless the ganymede.db file you are using has the tasks registered. Most importantly, the change from Builder Task to Task object types is an incompatible change from 0.96 and previous releases. You will need to start from scratch with the schema files included in the Ganymede 0.97 release in order to get the new Task object definition that the server now requires. Or, if you are particularly enthusiastic and don't want to lose data already in Ganymede, you could use the schema editor to bring your pre-0.97 datafile into compliance with the 0.97 Task object schema. Generally, I am not committing to a freeze on the basic schema definition until 1.0. I don't expect any more incompatible changes to the basic schema, but no promises until 1.0. See doc/server.html for a guide on the new task scheduling system. 6. [CLIENT] Better taskbar icons Brian reworked the taskbar significantly, with bigger and nicer taskbar icons. The dialogs brought up when the toolbar buttons are clicked have been reworked a bit to be more distinctive. More work coming to the client's GUI in 0.98. 7. [CLIENT] Fixes to date GUI code The date selector dialog now properly shows the time of day set in a date field. You could set the time of day before, but upon reloading, it would not be displayed properly. -------------------- Changes from 0.95 to 0.96 ------------------- RELEASE DATE: January 29, 1999 1. [DISTRIBUTION] Fixes to the distribution set Added the missing calendar.gif used by JdateField. Added missing up.gif and down.gif used by JpanelCalendar. Added doc/buildjavadoc to automate building of javadocs. Added a -develop option to the configure script, to allow doing builds in a CVS checkout directory, with the results of compiles put in a location outside the checked out tree. For use when developing and maintaining Ganymede. 2. [SERVER] Fixed bug in query engine Queries that combined embedded and non-embedded fields would cause the server to throw an IllegalArgument exception, complaining about a DBObjectBase being locked with an extantLock. Made the query engine a bit more regular with respect to dump() vs. query(). Made things a bit safer. Improved the server's handling of a forced disconnect of a user who is executing a query. 3. [CLIENT] Fixed bug with open object dialog and inactivated objects The client displays inactivated objects in the tree with "(inactive)" added to the end. The dialog brought up when clicking on the Edit, Delete, or View buttons on the toolbar were including the "(inactive)" bit when brought up with a tree node selected. 4. [SERVER] Made GanymedeExpirationTask more robust Previously, the Ganymede Expiration Task would be unable to commit its transaction if, by removing objects from the database, other objects were left with empty fields that are normally mandatory. Now, the expiration task will commit successfully, possibly leaving some objects with empty invid fields that would ordinarily not be permitted. This is the most straight-forward way of handling things like systems with required user fields, which would otherwise have to be automatically removed, a much dicier prospect. Probably need to add a feature to scan the database for objects which do not satisfy the required-fields check. Any time an admin edits an object that doesn't satisfy the check, the user will be required to fix the object before that transaction can be committed. 5. [SCHEMA] Fixed the gasharl schema's user inactivation logic The userCustom object in the gasharl schema was not properly differentiating between the case of wizard-led inactivation and automated inactivation in handli