use of org.opengis.metadata.citation.Citation in project sis by apache.
the class NameMeaning method toURN.
/**
* Formats the given identifier using the {@code "ogc:urn:def:"} syntax with possible heuristic changes to
* the given values. The identifier code space, version and code are appended omitting any characters that
* are not valid for a Unicode identifier. If some information are missing in the given identifier, then
* this method returns {@code null}. This method tries to "fix" the given values using some heuristic
* knowledge about the meaning of URN.
*
* @param type the object type.
* @param authority the authority as one of the values documented in {@link DefinitionURI} javadoc.
* @param version the code version, or {@code null}. This is the only optional information.
* @param code the code.
* @return an identifier using the URN syntax, or {@code null} if a mandatory information is missing.
*
* @since 0.7
*/
public static String toURN(final Class<?> type, final String authority, String version, String code) {
if (type == null || authority == null || code == null) {
return null;
}
final String key = authority.toUpperCase(Locale.US);
String codeSpace = AUTHORITIES.get(key);
if (codeSpace == null) {
/*
* If the given authority is not one of the authorities that we expected for the OGC namespace,
* verify if we can related it to one of the specifications enumerated in the Citations class.
* For example if the user gave us "OGP" as the authority, we will replace that by "IOGP" (the
* new name for that organization).
*/
final Citation c = Citations.fromName(key);
codeSpace = Citations.getCodeSpace(c);
if (AUTHORITIES.get(codeSpace) == null) {
// Not an authority that we recognize for the OGC namespace.
return null;
}
// Unconditionally overwrite the user-specified version.
version = getVersion(c);
/*
* If the above lines resulted in a change of codespace, we may need to concatenate the authority
* with the code for preserving information. The main use case is WMS codes like "CRS:84":
*
* 1) Citations.fromName("CRS") gave us Citations.WMS (version 1.3) as the authority.
* 2) getCodeSpace(Citations.WMS) gave us "OGC", which is indeed the codespace used in URN.
* 3) OGC Naming Authority – Procedures (OGC-09-046r2) said that "CRS:84" should be formatted
* as "urn:ogc:def:crs:OGC:1.3:CRS84". We already got the "OGC" and "1.3" parts with above
* steps, the last part is to replace "84" by "CRS84".
*/
if (!authority.equals(codeSpace) && !code.startsWith(authority)) {
// Intentionally no ':' separator.
code = authority + code;
}
}
final StringBuilder buffer = new StringBuilder(DefinitionURI.PREFIX);
loop: for (int p = 0; ; p++) {
final String part;
switch(p) {
case 0:
part = toObjectType(type);
break;
case 1:
part = codeSpace;
break;
case 2:
part = version;
break;
case 3:
part = code;
break;
default:
break loop;
}
if (!Utilities.appendUnicodeIdentifier(buffer.append(DefinitionURI.SEPARATOR), '\u0000', part, ".-", false)) {
/*
* Only the version (p = 2) is optional. All other fields are mandatory.
* If no character has been added for a mandatory field, we can not build a URN.
*/
if (p != 2) {
return null;
}
}
}
return buffer.toString();
}
use of org.opengis.metadata.citation.Citation in project sis by apache.
the class ServicesForUtility method createCitation.
/**
* Returns the build-in citation for the given primary key, or {@code null}.
*
* @param key the primary key of the desired citation.
* @return the requested citation, or {@code null} if unknown.
*
* @todo The content is hard-coded for now. But the plan for a future version is to fetch richer information
* from a database, including for example the responsible party and the URL. However that method would
* need to make sure that the given key is present in the alternate titles, since we rely on that when
* checking for code spaces.
*/
public static Citation createCitation(final String key) {
CharSequence title;
CharSequence alternateTitle = null;
CharSequence edition = null;
String code = null;
String codeSpace = null;
String version = null;
Identifier[] alternateIdentifiers = null;
CharSequence citedResponsibleParty = null;
PresentationForm presentationForm = null;
// Copy citedResponsibleParty from those citations.
Citation[] copyFrom = null;
switch(key) {
case "ISO 19115-1":
{
title = "Geographic Information — Metadata Part 1: Fundamentals";
edition = "ISO 19115-1:2014(E)";
code = "19115-1";
codeSpace = "ISO";
version = "2014(E)";
citedResponsibleParty = "International Organization for Standardization";
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case "ISO 19115-2":
{
title = "Geographic Information — Metadata Part 2: Extensions for imagery and gridded data";
edition = "ISO 19115-2:2009(E)";
code = "19115-2";
codeSpace = "ISO";
version = "2009(E)";
copyFrom = new Citation[] { Citations.ISO_19115.get(0) };
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case "WMS":
{
// OGC title
title = "Web Map Server";
// ISO title
alternateTitle = "Geographic Information — Web map server interface";
alternateIdentifiers = new Identifier[] { new ImmutableIdentifier(null, "OGC", "06-042", null, null), new ImmutableIdentifier(null, "ISO", "19128", "2005", null) };
edition = "1.3";
code = "WMS";
codeSpace = "OGC";
copyFrom = new Citation[] { Citations.OGC, Citations.ISO_19115.get(0) };
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case Constants.OGC:
{
title = "Identifiers in OGC namespace";
code = Constants.OGC;
citedResponsibleParty = "Open Geospatial Consortium";
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case Constants.IOGP:
{
// Not in public API (see Citations.IOGP javadoc)
// Geomatics Guidance Note number 7, part 1
title = "Using the EPSG Geodetic Parameter Dataset";
code = Constants.IOGP;
copyFrom = new Citation[] { Citations.EPSG };
presentationForm = PresentationForm.DOCUMENT_DIGITAL;
break;
}
case Constants.EPSG:
{
title = "EPSG Geodetic Parameter Dataset";
code = Constants.EPSG;
codeSpace = Constants.IOGP;
citedResponsibleParty = "International Association of Oil & Gas producers";
presentationForm = PresentationForm.TABLE_DIGITAL;
/*
* More complete information is provided as an ISO 19115 structure
* in EPSG Surveying and Positioning Guidance Note Number 7, part 1.
* EPSGDataAccess.getAuthority() also add more information.
* After we moved the content of this citation in a database,
* EPSGDataAccess.getAuthority() should use this citation as a template.
*/
break;
}
case Constants.SIS:
{
title = "Apache Spatial Information System";
code = key;
break;
}
case "ISBN":
{
title = "International Standard Book Number";
alternateTitle = key;
break;
}
case "ISSN":
{
title = "International Standard Serial Number";
alternateTitle = key;
break;
}
case Constants.PROJ4:
{
title = "Proj.4";
break;
}
case "S57":
{
title = "S-57";
break;
}
default:
return null;
}
/*
* Do not use the 'c.getFoo().add(foo)' pattern below. Use the 'c.setFoo(singleton(foo))' pattern instead.
* This is because this method may be invoked during XML serialization, in which case some getter methods
* may return null (for preventing JAXB to marshal some empty elements).
*/
final DefaultCitation c = new DefaultCitation(title);
if (alternateTitle != null)
c.setAlternateTitles(singleton(Types.toInternationalString(alternateTitle)));
if (edition != null)
c.setEdition(Types.toInternationalString(edition));
if (code != null)
c.setIdentifiers(singleton(new ImmutableIdentifier(null, codeSpace, code, version, null)));
if (presentationForm != null)
c.setPresentationForms(singleton(presentationForm));
if (citedResponsibleParty != null) {
final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.PRINCIPAL_INVESTIGATOR);
r.setParties(singleton(new DefaultOrganisation(citedResponsibleParty, null, null, null)));
c.setCitedResponsibleParties(singleton(r));
}
if (copyFrom != null) {
for (final Citation other : copyFrom) {
final Collection<? extends ResponsibleParty> parties = other.getCitedResponsibleParties();
final Collection<ResponsibleParty> current = c.getCitedResponsibleParties();
if (current != null) {
current.addAll(parties);
} else {
c.setCitedResponsibleParties(parties);
}
}
}
if (alternateIdentifiers != null) {
// getIdentifiers() should not return null at this point.
c.getIdentifiers().addAll(Arrays.asList(alternateIdentifiers));
}
c.freeze();
return c;
}
use of org.opengis.metadata.citation.Citation in project sis by apache.
the class DefinitionVerifier method withAuthority.
/**
* Compares the given CRS description with the authoritative description.
* The authoritative description is inferred from the identifier, if any.
*
* @param crs the CRS to compare with the authoritative description.
* @param factory the factory to use for fetching authoritative description, or {@code null} for the default.
* @param lookup whether this method is allowed to use {@link IdentifiedObjectFinder}.
* @return verification result, or {@code null} if the given CRS should be used as-is.
* @throws FactoryException if an error occurred while querying the authority factory.
*/
public static DefinitionVerifier withAuthority(final CoordinateReferenceSystem crs, final CRSAuthorityFactory factory, final boolean lookup) throws FactoryException {
final CoordinateReferenceSystem authoritative;
final Citation authority = (factory != null) ? factory.getAuthority() : null;
final String identifier = IdentifiedObjects.toString(IdentifiedObjects.getIdentifier(crs, authority));
if (identifier != null)
try {
/*
* An authority code was explicitly given in the CRS description. Create a CRS for that code
* (do not try to guess it). If the given code is unknown, we will report a warning and use
* the given CRS as-is.
*/
if (factory != null) {
authoritative = factory.createCoordinateReferenceSystem(identifier);
} else {
authoritative = CRS.forCode(identifier);
}
} catch (NoSuchAuthorityCodeException e) {
final DefinitionVerifier verifier = new DefinitionVerifier(crs);
verifier.arguments = new String[] { e.getLocalizedMessage() };
return verifier;
}
else if (lookup) {
/*
* No authority code was given in the CRS description. Try to guess the code with IdentifiedObjectFinder,
* ignoring axis order. If we can not guess a code or if we guess wrongly, use the given CRS silently
* (without reporting any warning) since there is apparently nothing wrong in the given CRS.
*/
final IdentifiedObjectFinder finder;
if (factory instanceof GeodeticAuthorityFactory) {
finder = ((GeodeticAuthorityFactory) factory).newIdentifiedObjectFinder();
} else {
finder = IdentifiedObjects.newFinder(Citations.getIdentifier(authority, false));
}
finder.setIgnoringAxes(true);
final IdentifiedObject ref = finder.findSingleton(crs);
if (ref instanceof CoordinateReferenceSystem) {
authoritative = (CoordinateReferenceSystem) ref;
} else {
// Found no identifier. Use the CRS as-is.
return null;
}
} else {
return null;
}
/*
* At this point we found an authoritative description (typically from EPSG database) for the given CRS.
* Verify if the given CRS is equal to the authoritative description, or a variant of it. The similarity
* variable tells us if we have equality (0), mismatch (-), or equality when using a variant (+).
*/
int similarity = 0;
final AbstractCRS ca = AbstractCRS.castOrCopy(authoritative);
AbstractCRS variant = ca;
while (!variant.equals(crs, ComparisonMode.APPROXIMATIVE)) {
if (similarity < VARIANTS.length) {
variant = ca.forConvention(VARIANTS[similarity++]);
} else if (identifier == null) {
// Mismatched CRS, but our "authoritative" description was only a guess. Ignore.
return null;
} else {
// Mismatched CRS and our authoritative description was not a guess. Need warning.
similarity = -1;
break;
}
}
final DefinitionVerifier verifier;
if (similarity > 0) {
/*
* Warning message (from Resources.properties):
*
* The coordinate system axes in the given “{0}” description do not conform to the expected axes
* according “{1}” authoritative description.
*/
verifier = new DefinitionVerifier(variant);
if (identifier != null) {
verifier.resourceKey = Resources.Keys.NonConformAxes_2;
verifier.arguments = new String[2];
}
} else {
verifier = new DefinitionVerifier(authoritative);
if (similarity != 0) {
/*
* Warning message (from Resources.properties):
*
* The given “{0}” description does not conform to the “{1}” authoritative description.
* Differences are found in {2,choice,0#method|1#conversion|2#coordinate system|3#datum|4#CRS}.
*/
verifier.resourceKey = Resources.Keys.NonConformCRS_3;
verifier.arguments = new Object[3];
verifier.arguments[2] = diffCode(CRS.getSingleComponents(authoritative).iterator(), CRS.getSingleComponents(crs).iterator());
}
}
if (verifier.arguments != null) {
verifier.arguments[0] = IdentifiedObjects.getName(crs, null);
verifier.arguments[1] = IdentifiedObjects.getIdentifierOrName(authoritative);
}
return verifier;
}
use of org.opengis.metadata.citation.Citation in project sis by apache.
the class Code method forIdentifiedObject.
/**
* Returns a {@code <gml:identifier>} for the given identified object, or {@code null} if none.
* This method searches for the following identifiers, in preference order:
* <ul>
* <li>The first identifier having a code that begin with {@code "urn:"}.</li>
* <li>The first identifier having a code that begin with {@code "http:"}.</li>
* <li>The first identifier in the {@code "EPSG"} codespace, converted to the {@code "urn:} syntax.</li>
* <li>The first identifier in other codespace, converted to the {@code "urn:} syntax if possible.</li>
* </ul>
*
* @param type the type of the identified object.
* @param identifiers the object identifiers, or {@code null} if none.
* @return the {@code <gml:identifier>} as a {@code Code} instance, or {@code null} if none.
*/
public static Code forIdentifiedObject(final Class<?> type, final Iterable<? extends ReferenceIdentifier> identifiers) {
if (identifiers != null) {
boolean isHTTP = false;
boolean isEPSG = false;
ReferenceIdentifier fallback = null;
for (final ReferenceIdentifier identifier : identifiers) {
final String code = identifier.getCode();
// Paranoiac check.
if (code == null)
continue;
if (code.regionMatches(true, 0, "urn:", 0, 4)) {
return new Code(identifier);
}
if (!isHTTP) {
isHTTP = code.regionMatches(true, 0, "http:", 0, 5);
if (isHTTP) {
fallback = identifier;
} else if (!isEPSG) {
isEPSG = Constants.EPSG.equalsIgnoreCase(identifier.getCodeSpace());
if (isEPSG || fallback == null) {
fallback = identifier;
}
}
}
}
/*
* If no "urn:" or "http:" form has been found, try to create a "urn:" form from the first identifier.
* For example "EPSG:4326" may be converted to "urn:ogc:def:crs:EPSG:8.2:4326". If the first identifier
* can not be converted to a "urn:" form, then it will be returned as-is.
*/
if (fallback != null) {
if (!isHTTP) {
final String urn = NameMeaning.toURN(type, fallback.getCodeSpace(), fallback.getVersion(), fallback.getCode());
if (urn != null) {
final Code code = new Code();
/*
* Rational for EPSG special case below:
* -------------------------------------
* Apache SIS already formats the Identifier.getCodeSpace() value in the URN.
* This value is "EPSG" for IdentifiedObject instances from the EPSG database.
* But GML additionally have a "codeSpace" attribute, and common usage seems to
* give the "OGP" or "IOGP" value to that attribute as in the following example:
*
* <gml:identifier codeSpace="IOGP">urn:ogc:def:crs:EPSG::4326</gml:identifier>
*
* A discussion can be found in the comments of https://issues.apache.org/jira/browse/SIS-196
*
* Where to take this "IOGP" value from? It is not the Identifier.getCodeSpace() String value
* since ISO 19115-1 clearly uses the "EPSG" value in their example. We could consider using
* the Identifier.getAuthority() value, which is a Citation. But the "EPSG" part in above URN
* is named "the authority" in URN specification, which suggest that Identifier.getAuthority()
* should return a citation for the "EPSG Geodetic Parameter Dataset" rather than for the IOGP
* organisation.
*
* Apache SIS declares IOGP as the codespace of the EPSG codespace, i.e. the identifier of the
* EPSG authority is "IOGP:EPSG". So the code below searches for the "IOGP" part of the above.
* However there is no indication at this time that objects from other sources than SIS would
* follow such convention, so we also keep a hard-coded "IOGP" default value for now.
*
* A symmetrical special handling for EPSG is done in the 'getIdentifier()' method of this class.
*
* See https://issues.apache.org/jira/browse/SIS-199
*/
final Citation authority = fallback.getAuthority();
if (isEPSG) {
// Default value if we do not find a codespace below.
code.codeSpace = Constants.IOGP;
if (authority != null) {
for (final Identifier id : authority.getIdentifiers()) {
if (Constants.EPSG.equalsIgnoreCase(id.getCode())) {
if (id instanceof ReferenceIdentifier) {
final String cs = ((ReferenceIdentifier) id).getCodeSpace();
if (cs != null) {
code.codeSpace = cs;
break;
}
}
}
}
}
} else {
code.codeSpace = getCodeSpace(authority);
}
code.code = urn;
return code;
}
}
return new Code(fallback);
}
}
return null;
}
use of org.opengis.metadata.citation.Citation in project sis by apache.
the class Code method getIdentifier.
/**
* Returns the identifier for this value. This method is the converse of the constructor.
* If the {@link #codeSpace} contains a semicolon, then the part after the last semicolon
* will be taken as the authority version number. This is for consistency with what the
* constructor does.
*
* @return the identifier, or {@code null} if none.
*/
public ReferenceIdentifier getIdentifier() {
String c = code;
if (c == null) {
return null;
}
Citation authority = null;
String version = null, cs = codeSpace;
final DefinitionURI parsed = DefinitionURI.parse(c);
if (parsed != null && parsed.code != null) {
/*
* Case where the URN has been successfully parsed. The OGC's URN contains an "authority" component,
* which we take as the Identifier.codeSpace value (not Identifier.authority despite what the names
* would suggest).
*
* The GML document may also provide a 'codeSpace' attribute separated from the URN, which we take
* as the authority. This is the opposite of what the names would suggest, but we can not map the
* 'codeSpace' attribute to Identifier.codeSpace because the 'codeSpace' attribute value found in
* practice is often "IOGP" while the 'Identifier.description' example provided in ISO 19115-1 for
* an EPSG code has the "EPSG" codespace. Example:
*
* - XML: <gml:identifier codeSpace="IOGP">urn:ogc:def:crs:EPSG::4326</gml:identifier>
* - ISO: For "EPSG:4326", Identifier.codeSpace = "EPSG" and Identifier.code = "4326".
*
* Apache SIS attempts to organize this apparent contradiction by considering IOGP as the codespace of
* the EPSG codespace, but this interpretation is not likely to be widely used by libraries other than
* SIS. For now, a special handling is hard-coded below: if codeSpace = "IOGP" and authority = "EPSG",
* then we take the authority as the Citations.EPSG constant, which has a "IOGP:EPSG" identifier.
*
* A symmetrical special handling for EPSG is done in the 'forIdentifiedObject(…)' method of this class.
*/
if (org.apache.sis.internal.util.Citations.isEPSG(cs, parsed.authority)) {
authority = Citations.EPSG;
} else {
// May be null.
authority = Citations.fromName(cs);
}
cs = parsed.authority;
version = parsed.version;
c = parsed.code;
} else if (cs != null) {
/*
* Case where the URN can not be parsed but a 'codeSpace' attribute exists. We take this 'codeSpace'
* as both the code space and the authority. As a special case, if there is a semi-colon, we take all
* text after that semi-color as the version number.
*/
final int s = cs.lastIndexOf(DefinitionURI.SEPARATOR);
if (s >= 0) {
version = cs.substring(s + 1);
cs = cs.substring(0, s);
}
authority = Citations.fromName(cs);
}
return new NamedIdentifier(authority, cs, c, version, null);
}
Aggregations