blob: e0bef39386aa879979425878b59e87bb1cd19bf6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sis.internal.simple;
import java.util.Date;
import java.util.Collection;
import java.io.ObjectStreamException;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.citation.CitationDate;
import org.opengis.metadata.citation.OnlineResource;
import org.opengis.metadata.citation.PresentationForm;
import org.opengis.metadata.citation.ResponsibleParty;
import org.opengis.metadata.citation.Series;
import org.opengis.metadata.identification.BrowseGraphic;
import org.opengis.util.InternationalString;
import org.apache.sis.xml.IdentifierSpace;
import org.apache.sis.metadata.sql.MetadataSource;
import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.internal.system.Loggers;
import org.apache.sis.internal.util.Strings;
import org.apache.sis.util.logging.Logging;
/**
* Base class for the {@code public static final Citation} constants defined in some SIS classes.
* This base class contains only an abbreviation (e.g. {@code "OGC"} or {@code "EPSG"}) which can
* be used as the primary key where to search for more information in a database. If no database
* is available, then that simple primary key will be used as the citation title.
*
* @author Martin Desruisseaux (Geomatys)
* @version 1.0
*
* @see IdentifierSpace
* @see Citations
*
* @since 0.6
* @module
*/
public class CitationConstant extends SimpleCitation {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -8429121584437634107L;
/**
* Class of {@code public static final Citation} constants which are also used as namespace for identifiers.
* The most typical example is the "EPSG" authority which manage the codes identifying Coordinate Reference
* System (CRS) objects in the EPSG namespace.
*
* @param <T> the type of object used as identifier values.
*/
public static class Authority<T> extends CitationConstant implements IdentifierSpace<T> {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 2067932813561130294L;
/**
* Creates a new citation for an authority managing codes in the given namespace.
* This constructor assumes that the namespace is the same as the abbreviation given as citation title.
*
* @param namespace the namespace of codes managed by this authority (e.g. "EPSG").
*/
public Authority(final String namespace) {
super(namespace);
}
/**
* Creates a new citation for an authority managing codes in the given namespace.
*
* @param name a human-understandable primary key for fetching more information.
* @param namespace the namespace of codes managed by this authority (e.g. "EPSG").
*/
public Authority(final String name, final String namespace) {
super(name, namespace);
}
/**
* Returns the name space given at construction time. Can be one of the following:
* <ul>
* <li>Abbreviation of the authority managing the codes (e.g. {@code "EPSG"} or {@code "ISBN"}).</li>
* <li>XML attribute name with its prefix (e.g. {@code "gml:id"}, {@code "gco:uuid"} or {@code "xlink:href"}).</li>
* </ul>
*/
@Override
public final String getName() {
return namespace;
}
/**
* Returns a string representation of this identifier space.
*/
@Override
public final String toString() {
return Strings.bracket(IdentifierSpace.class, title);
}
}
/**
* The name by which this citation is known to {@link Citations#fromName(String)}.
* Often the same than the abbreviation that {@link CitationConstant} uses as the title.
* If this {@code CitationConstant} is a {@link Authority} subtype, then this is also
* the authority namespace.
*/
public final String namespace;
/**
* The citation which contain the "real" data, or {@code null} if not yet created.
* This is usually an instance created by {@link MetadataSource}. Those instances
* manage their own caching, so accesses to the database should not occur often.
*/
private transient volatile Citation delegate;
/**
* Creates a new proxy for the given primary key.
* The key should be readable enough for being usable as a fallback if the database is not available.
*
* @param name a human-understandable primary key for fetching more information.
*/
public CitationConstant(final String name) {
super(name);
this.namespace = name;
}
/**
* Creates a new proxy for the given primary key but a different programmatic name.
* The key should be readable enough for being usable as a fallback if the database is not available.
*
* @param name a human-understandable primary key for fetching more information.
* @param namespace the name by which this citation is known to {@link Citations#fromName(String)}.
*/
public CitationConstant(final String name, final String namespace) {
super(name);
this.namespace = namespace;
}
/**
* Notify this instance that the database content may have changed, or that the classpath has changed.
*/
public final void refresh() {
delegate = null;
}
/**
* Returns the citation instance which contain the actual data. That instance is provided by the
* {@code sis-metadata} module, which is optional. If that module is not on the classpath, then
* this {@code delegate()} method will use the few information provided by the current instance.
*
* <p>Note that it should be very rare to not have {@code sis-metadata} on the classpath,
* since that module is required by {@code sis-referencing} which is itself required by
* almost all other SIS modules.</p>
*/
@SuppressWarnings("DoubleCheckedLocking")
private Citation delegate() {
Citation c = delegate;
if (c == null) {
synchronized (this) {
c = delegate;
if (c == null) {
try {
c = MetadataSource.getProvided().lookup(Citation.class, title);
} catch (MetadataStoreException e) {
/*
* If no database was available, MetadataSource.getProvided() was supposed to fallback on
* the MetadataFallback class. So if we get this exception, a more serious error occurred.
* It is still not fatal however, since most of Citation content is informative.
*/
Logging.unexpectedException(Logging.getLogger(Loggers.SQL), CitationConstant.class, "delegate", e);
c = new SimpleCitation(title);
}
delegate = c;
}
}
}
return c;
}
/**
* Redirects the call to the delegate citation (the instance which actually contain the data).
*
* @return the value returned by the delegate.
*/
@Override public InternationalString getTitle() {return delegate().getTitle();}
@Override public Collection<? extends InternationalString> getAlternateTitles() {return delegate().getAlternateTitles();}
@Override public Collection<? extends CitationDate> getDates() {return delegate().getDates();}
@Override public InternationalString getEdition() {return delegate().getEdition();}
@Override public Date getEditionDate() {return delegate().getEditionDate();}
@Override public Collection<? extends Identifier> getIdentifiers() {return delegate().getIdentifiers();}
@Override public Collection<? extends ResponsibleParty> getCitedResponsibleParties() {return delegate().getCitedResponsibleParties();}
@Override public Collection<PresentationForm> getPresentationForms() {return delegate().getPresentationForms();}
@Override public Series getSeries() {return delegate().getSeries();}
@Override public InternationalString getOtherCitationDetails() {return delegate().getOtherCitationDetails();}
@Override public Collection<? extends OnlineResource> getOnlineResources() {return delegate().getOnlineResources();}
@Override public Collection<? extends BrowseGraphic> getGraphics() {return delegate().getGraphics();}
@Override public String getISBN() {return delegate().getISBN();}
@Override public String getISSN() {return delegate().getISSN();}
/**
* Invoked at deserialization time in order to replace the deserialized instance by the existing
* instance defined in the {@link org.apache.sis.metadata.iso.citation.Citations} class.
*
* @return the instance to use, as an unique instance if possible.
* @throws ObjectStreamException never thrown.
*/
protected Object readResolve() throws ObjectStreamException {
final Citation c = Citations.fromName(title);
return (c instanceof CitationConstant) ? c : this;
/*
* Returns 'this' should happen only if the Citation has been serialized
* on a more recent version of Apache SIS than the current version.
*/
}
}