GeoAPI interfaces are sometimes generated from other files provided by OGC, like XSD files.
But there is always a manual revision, and often modifications compared to automatically generated Java files.
It would have been possible to automatically generate Java interfaces from OGC standards using existing tools.
For example one of the most commonly-used approaches is to transform XSD schemas
into Java interfaces using command line utility xjc
.
As this utility is included in most Java distributions (it is one of the JAXB tools),
this approach is favoured by many projects found on the Internet.
Other approaches use tools integrated into the Eclipse Development Environment,
which is based on UML schemas rather than XSD ones.
A similar approach was attempted in the early days of the GeoAPI project, but was quickly abandoned.
We favor a manual approach for the following reasons:
Some XSD schemas are much more verbose than the original UML schemas.
Converting from XSD schemas introduces — at least in the case of metadata —
almost double the number of interfaces actually defined by the standard, without adding any new features.
XSD schemas also define attributes specific to XML documents (id
,
uuid
, xlink:href
, etc.), that do not exist in the original UML diagrams,
and which we do not necessarily wish to expose in a Java API.
Converting from UML schemas avoids this problem, but tools capable of performing this operation are less common.
Example:
XSD metadata schemas insert a <cit:CI_Citation>
element
inside a <cit:citation>
,
a <cit:CI_OnlineResource>
element inside a <cit:onlineResource>
,
and so on for the hundreds of classes defined by ISO 19115 standard.
This redundancy is certainly not necessary in a Java program.
OGC standards use different naming conventions than Java.
In particular, the names of almost all OGC classes begin with a two-letter prefix,
such as MD_Identifier
.
This prefixes fulfill the same role as package names in Java.
GeoAPI adapts this practice by using interface names without prefixes and placing these interfaces in packages corresponding to the prefixes,
but with more descriptive names.
Occasionally we also change the names; for example, to avoid acronyms, or to conform to an established convention such as JavaBeans.
Example:
The OGC class MD_Identifier
becomes the
Identifier
interface in the org.opengis.metadata
package.
The OGC class SC_CRS
becomes the CoordinateReferenceSystem
interface,
and the usesDatum
association becomes a getDatum()
method,
rather than the “getUsesDatum()
” that would result from an automatic conversion tool.
We do not allow programs to blindly apply rules that ignore the conventions of the community whose schemas we translate.
The standards may contain structures that do not have a direct equivalent in Java, such as unions similar to what we would find in C/C++. The strategy used to obtain an equivalent feature in Java depends on the context: multiple inheritance of interfaces, modification of the hierarchy, or simply omitting the union. These decisions are made case-by-case based on a needs analysis.
Example:
ISO 19111 standard defines different types of coordinate systems, such as spherical, cylindrical, polar or Cartesian.
It then defines several subsets of these types of coordinate systems systems.
These subsets, represented by unions, serve to specify that a class may only be associated with a particular type of coordinate system.
For example, a union of types may be associated with an image, named CS_ImageCS
,
which can only contain CS_CartesianCS
and CS_AffineCS
.
In this case, we get the desired effect in Java through a modification of the hierarchy of classes:
we define the CartesianCS
interface as a specialization of AffineCS
,
which is semantically correct.
But it is not possible to apply a similar strategy to other unions without violating the semantics.
Several specifications overlap. GeoAPI performs the work of integration by replacing some duplicate structures with references to equivalent structures from the standards that best represent them.
Example:
ISO 19115:2003 standard, which defines metadata structures,
also attempts to describe a few structures representing coordinate reference systems (CRS).
Yet these are also the focus of another standard: ISO 19111.
At the same time, ISO 19111:2007 states in section 3 that it reuses all of the elements of
ISO 19115:2003 except MD_CRS
and its components.
GeoAPI interfaces reduce the redundancy by applying the exclusion recommended by ISO 19111 to the entire project.
The complexity of some standards have increased for historical reasons rather than technical ones, related to the standardization process. GeoAPI reduces the technical debt by designing interfaces with each element in its proper place, regardless of the chronological order in which the standards were published.
Example:
ISO 19115-2 standard is an extension of ISO 19115-1 standard, adding image metadata structures.
These metadata were defined in a separate standard because they were not yet ready when the first part of the standard was published.
As it was not possible for administrative reasons to add attributes to already-published classes,
the new attributes were added in a sub-class bearing almost the same name.
Thus, ISO 19115-2 defines the class MI_Band
,
which extends the class MD_Band
from ISO 19115-1 by adding attributes that would have appeared
directly in the parent class if there were ready on time.
In GeoAPI, we have chosen to “repair” these anomalies by fusing these two classes into a single interface.
Deviations from the standards are documented in each affected class and method.
Each mention of a deviation is also collected on a single page in order to provide an overview.
Since these deviations blur the relationships between the standards and certain Java interfaces,
the correspondence between these languages is explained by @UML
annotations and property files described in the following section.
@UML
annotations
For each class, method and constant defined by an OGC or ISO standard,
GeoAPI indicates its provenance using annotations defined in the org.opengis.annotation
package.
In particular, the @UML
annotations indicates the standard,
the name of the element in that standard, and also its obligation.
For example, in the following code snippet, the first @UML
code indicates that the Java interface that follows
(ProjectedCRS
) is defined using the SC_ProjectedCRS
type of ISO 19111 standard.
The second @UML
annotation, this time applied to the getCoordinateSystem()
method,
indicates that this method is defined using the coordinateSystem
association of ISO 19111 standard,
and that this association is mandatory — meaning, in Java, that the method is not allowed to return a null
value.
package org.opengis.referencing.crs
;
/**
* A 2D coordinate reference system used to approximate the shape of the earth on a planar surface.
*/
@UML(specification=ISO_19111, identifier="SC_ProjectedCRS
")
public interface ProjectedCRS extends GeneralDerivedCRS {
/**
* Returns the coordinate system, which must be Cartesian.
*/
@UML(obligation=MANDATORY, specification=ISO_19111, identifier="coordinateSystem
")
CartesianCS getCoordinateSystem()
;
}
Java reflection methods allow access to this information during the execution of an application.
This is useful for displaying UML identifiers for users familiar with OGC standards,
or for writing elements in an XML document.
Class org.apache.sis.util.iso.Types
provides static convenience methods
like getStandardName(Class)
for such operations.
For example the following code will display
“Standard name of type org.opengis.referencing.crs.ProjectedCRS
is SC_ProjectedCRS
”:
Class<?> type = ProjectedCRS.class;
System.out.println("Standard name of type " + type.getName() + " is " + Types.getStandardName(type));
The Types.forStandardName(String)
convenience method performs the reverse operation.
Applications who want to perform those operations without SIS convenience methods can follow indications
provided in a separated chapter.
Some classes and methods have neither an @UML
annotation, nor an entry in the class-index.properties
file.
They are either extensions of GeoAPI, or else types defined in other libraries, such as standard JDK.
In this last case, the mapping to ISO standards is implicit.
The following table describes this mapping for ISO 19103 types.
Java’s primitive types are preferred when applicable,
but where necessary their wrappers are used in order to authorize null values.
ISO type | JDK type | Remarks |
---|---|---|
Numbers | ||
Integer |
int |
Sometimes java.lang.Integer for optional attributes. |
Integer (in some cases) |
long |
Sometimes java.lang.Long for optional attributes. |
Real |
double |
Sometimes java.lang.Double for optional attributes. |
Decimal |
java.math.BigDecimal |
|
Number |
java.lang.Number |
|
Texts | ||
FreeText |
(no equivalent) | See org.opengis.util.InternationalString below. |
CharacterString |
java.lang.String |
Often org.opengis.util.InternationalString (see below). |
LocalisedCharacterString |
java.lang.String |
|
Sequence<Character> |
java.lang.CharSequence |
|
Character |
char |
|
Dates and hours | ||
Date |
java.util.Date |
|
Time |
java.util.Date |
|
DateTime |
java.util.Date |
|
Collections | ||
Collection |
java.util.Collection |
|
Bag |
java.util.Collection |
A Bag is similar to a
Set without being restricted by uniqueness. |
Set |
java.util.Set |
|
Sequence |
java.util.List |
|
Dictionary |
java.util.Map |
|
KeyValuePair |
java.util.Map.Entry |
|
Enumerations | ||
Enumeration |
java.lang.Enum |
|
CodeList |
(no equivalent) | See org.opengis.util.CodeList below. |
Various | ||
Boolean |
boolean |
Sometimes java.lang.Boolean for optional attributes. |
Any |
java.lang.Object |
The nearest equivalent for CharacterString
is the String
class,
but GeoAPI often uses the InternationalString
interface, allowing the client to choose the language.
For example, it is useful on a server that simultaneously provides pages in multiple languages.
By returning translations when objects are used rather than at the time of their creation,
we allow the SIS library to provide the same instances of Metadata
or Coverage
(for example) for the same data, regardless of the client’s language.
Translations may be made on the fly with the help of the application’s ResourceBundle
,
or may be provided directly with the data (as in the case of Metadata
).
An Enumeration
corresponds to an Enum
in Java.
Both define all authorized values, without allowing the user to add any.
A CodeList
is similar to an enumeration, except that users may add their own items.
Standard JDK does not offer this possibility.
GeoAPI defines an abstract CodeList
class that reproduces some of the functionality of Enum
while being extensible.
Extensions are made available by the valueOf(String)
static method, which, in contrast to Enum
,
creates new instances if the name provided does not correspond to the name of an existing instance.
MediumName cdRom = MediumName.CD_ROM;
MediumName usbKey = MediumName.valueOf
("USB_KEY
"); // There is no constraint on this value.
assert MediumName.valueOf
("CD_ROM
") == cdRom : "valueOf must return existing constants.";
assert MediumName.valueOf
("USB_KEY
") == usbKey : "valueOf must cache the previously requested values.";