Interface Transformations
Summary
Most OSID interfaces map one-to-one with Java interfaces and reflect the same interface hierarchy. There are a few places where the OSID Java Binder injects methods not defined in the OSID Specifications. The binder does so by adding a parent interface to the bound OSID interface.
Injection
Interface or method injection is performed by having the OSID interface extend another interface defined in the binding. These additional interfaces are in the org.osid.binder.java package.
AutoCloseable
As Java memory management is based on garbage collection and there are no explicit destructors, Java does not ensure that an object which fell out of scope will be cleaned up. The GC cleans up based on memory constraints, not based on the consumption of other resources such as connections or spawned threads. The Java practice is that if an implementation might have the explicit need release resources right away, its interface must have a close operation (so much for separation of interface and implementation).
The following interfaces have been designated as might have resources to be released.
- osid.OsidManager
- osid.OsidProxyManager
- osid.OsidSession
- osid.OsidList
- osid.transport.DataInputStream
These OSID interfaces, by way of interfaces in the org.osid.binder.java package, implement java.lang.AutoCloseable.
close()
The close() method is defined to throw java.lang.Exception. It does this because java.lang.AutoCloseable was slipped above java.io.Closeable and the latter already threw an IOException. Now we have a checked exception no one is in a position to deal with. It isn't recommended OSID implementations use this exception.
/** * Close this list. * * @throws Exception not recommended * @throws org.osid.IllegalStateException this list already closed */ @OSIDBinding @Override public void close() throws Exception;
The OSID Java Binding allows for an unchecked IllegalStateException to be thrown if close() is invoked more than once.
Automatic Resource Management (ARM)
It may seem that the use of the AutoCloseable interface is a bit forced but the advantage is the try-with-resources construct.
try { org.osid.repository.AssetList assets = session.getAssets(); while (assets.hasNext()) { ... } } finally { assets.close(); }
becomes:
try (org.osid.repository.AssetList assets = session.getAssets()) { while (assets.hasNext()) { ... } }
OsidPrimitives
Each of the OsidPrimitive interfaces extend a binding interface. These binding interfaces define some basic object methods.
equals()
OsidPrimitives, unlike other OSID interfaces, may be tested for equality. Each OsidPrimitive defines the components that must be equal for the test to succeed.
Note that for any object implementing osid.Identifiable, an equals() comparison must compare the Ids and only the Ids regardless of what other data in the object differs. For objects that do not implement osid.Identifiable, the result is undefined.
hashCode()
The hashCode() accompanies the equals() methods in ensuring that if two OsidPrimitives are equal, they compute the same hash. This must be enforced by any implementation of an OsidPrimitive and is performed by the classes in the Primordium package.
Any OsidPrimitive can be used as a key in a java.util.Map. Other OSID objects should not be used as keys.
toString()
This is recommended for any implementation of an OsidPrimitive to display a contextually relevant serialization that should be supported in a valueOf() deserialization method.
compareTo()
Where there is a natural ordering of an OsidPrimitive, a java.lang.Comparable interface is required.
Other Comparisons
OsidPrimitives that represent values will also have additional methods defined for determining greater than and less than.
Uncertainty
Some OsidPrimitives define the concept of uncertainty where there is an implied range of values. These OsidPrimitives may offer additional methods for determining inclusion, exclusion, and the bounds of the value.
Table
OsidPrimitive | equals() hashCode() toString() | compareTo() | less than greater than | inclusion exclusion | certainty bounds | type sensitive |
---|---|---|---|---|---|---|
osid.mapping.Coordinate | ||||||
osid.financials.Currency | ||||||
osid.calendaring.DateTime | ||||||
osid.locale.DisplayText | ||||||
osid.mapping.Distance | ||||||
osid.calendaring.Duration | ||||||
osid.mapping.Heading | ||||||
osid.id.Id | ||||||
osid.mapping.SpatialUnit | ||||||
osid.mapping.Speed | ||||||
osid.calendaring.Time | ||||||
osid.type.Type | ||||||
osid.installation.Version |
OsidPrimitives are some of the most difficult interfaces to implement because these operations must be supported across an infinite range of values. In fact, it is the flexibility of this set of interfaces that in large part make the OSIDs so adaptable. The OSID Primordium package implements most of them for common use cases.
Type Sensitivity
Some OsidPrimitives have Types. osid.calendaring.DateTime, for example, supports a number of calendar Types. Some of the compare methods, other than the basic equals() comparison, would not be supported if given a DateTime of a different calendar. Nor can it be expected that there would be a single external utility that supported any calendar type.
OSID Providers are expected to normalize their OsidPrimitives such that a single OsidPrimitive Type is passed to an OSID Consumer. Typically, an OSID Consumer is part of a Locale and expects certain Types.