001 /*
002 * GeoAPI - Java interfaces for OGC/ISO standards
003 * http://www.geoapi.org
004 *
005 * This file is hereby placed into the Public Domain.
006 * This means anyone is free to do whatever they wish with this file.
007 *
008 * The NetCDF wrappers are provided as code examples, in the hope to facilitate
009 * GeoAPI implementations backed by other libraries. Implementors can take this
010 * source code and use it for any purpose, commercial or non-commercial, copyrighted
011 * or open-source, with no legal obligation to acknowledge the borrowing/copying
012 * in any way.
013 */
014 package org.opengis.wrapper.netcdf;
015
016 import java.util.Set;
017 import java.util.Collection;
018 import java.util.Collections;
019 import java.util.Date;
020 import java.io.Serializable;
021
022 import ucar.nc2.VariableSimpleIF;
023
024 import org.opengis.util.GenericName;
025 import org.opengis.util.InternationalString;
026 import org.opengis.metadata.extent.Extent;
027 import org.opengis.metadata.citation.Citation;
028 import org.opengis.referencing.IdentifiedObject;
029 import org.opengis.referencing.ReferenceIdentifier;
030
031
032 /**
033 * An {@link IdentifiedObject} abstract base class backed by some NetCDF object.
034 * All methods in this class delegate their work to the wrapped NetCDF object.
035 * Consequently any change in the wrapped object is immediately reflected in this
036 * {@code NetcdfIdentifiedObject} instance. However users are encouraged to not
037 * change the wrapped object after construction, since GeoAPI referencing objects
038 * are expected to be immutable.
039 *
040 * <p>This base class assumes that NetCDF objects have a single name and no alias. This assumption
041 * allows us to implement directly the {@link ReferenceIdentifier} interface. The NetCDF object
042 * name is returned by the {@link #getCode()} method.</p>
043 *
044 * @author Martin Desruisseaux (Geomatys)
045 * @version 3.1
046 * @since 3.1
047 */
048 public abstract class NetcdfIdentifiedObject implements IdentifiedObject, ReferenceIdentifier, Serializable {
049 /**
050 * For cross-version compatibility.
051 */
052 private static final long serialVersionUID = 8740287489596438703L;
053
054 /**
055 * Creates a new {@code NetcdfIdentifiedObject} instance.
056 */
057 protected NetcdfIdentifiedObject() {
058 }
059
060 /**
061 * Returns the wrapped NetCDF object on which operations are delegated.
062 *
063 * @return The wrapped NetCDF object on which operations are delegated.
064 */
065 public abstract Object delegate();
066
067 /**
068 * Returns the NetCDF citation.
069 */
070 @Override
071 public Citation getAuthority() {
072 return SimpleCitation.NETCDF;
073 }
074
075 /**
076 * Returns the {@code "NetCDF"} constant, which is used as the code space.
077 */
078 @Override
079 public String getCodeSpace() {
080 return "NetCDF";
081 }
082
083 /**
084 * Returns the version of the NetCDF library. The default implementation
085 * fetches this information from the {@code META-INF/MANIFEST.MF} file in
086 * the NetCDF JAR file.
087 */
088 @Override
089 public String getVersion() {
090 final Package p = VariableSimpleIF.class.getPackage();
091 return (p != null) ? p.getImplementationVersion() : null;
092 }
093
094 /**
095 * Returns a code which identify this instance. This is typically the value
096 * returned by the {@code getName()} method of the wrapped NetCDF object.
097 */
098 @Override
099 public abstract String getCode();
100
101 /**
102 * Returns the name of this identified object. The default implementation returns
103 * {@code this}, so subclasses shall returns the name in their implementation of
104 * the {@link #getCode()} method.
105 */
106 @Override
107 public ReferenceIdentifier getName() {
108 return this;
109 }
110
111 /**
112 * Returns the aliases, or an empty set if none. The default implementation returns an empty
113 * set. Some subclasses will infer the aliases from the projection {@linkplain #getName()}.
114 */
115 @Override
116 public Collection<GenericName> getAlias() {
117 return Collections.emptySet();
118 }
119
120 /**
121 * Returns an empty set, since NetCDF objects don't provide other identifiers than the name.
122 */
123 @Override
124 public Set<ReferenceIdentifier> getIdentifiers() {
125 return Collections.emptySet();
126 }
127
128 /**
129 * Returns the area or region or timeframe in which this object is valid, or {@code null} if
130 * none. The default implementation returns a geographic extent for the world, since most NetCDF
131 * objects except {@link ucar.unidata.geoloc.Projection} are not restricted to a particular area.
132 *
133 * @return The valid domain, or {@code null} if not available.
134 *
135 * @see NetcdfCRS#getDomainOfValidity()
136 * @see NetcdfProjection#getDomainOfValidity()
137 */
138 public Extent getDomainOfValidity() {
139 return SimpleGeographicBoundingBox.WORLD;
140 }
141
142 /**
143 * Returns the description of domain of usage, or limitations of usage, for which this object
144 * is valid. The default implementation returns {@code null} in all cases, since NetCDF objects
145 * don't specify their scope.
146 *
147 * <p>Scope is a
148 * {@link org.opengis.referencing.datum.Datum#getScope() Datum},
149 * {@link org.opengis.referencing.ReferenceSystem#getScope() ReferenceSystem} and
150 * {@link org.opengis.referencing.operation.CoordinateOperation#getScope() CoordinateOperation}
151 * property.</p>
152 *
153 * @return The domain of usage, or {@code null} if none.
154 */
155 public InternationalString getScope() {
156 return null;
157 }
158
159 /**
160 * Returns a description, possibly including coordinates of an identified point or points,
161 * of the relationship used to anchor the coordinate system to the Earth or alternate object.
162 * The default implementation returns {@code null} since this simple implementation does not
163 * define anchor point.
164 *
165 * <p>Anchor point is a
166 * {@link org.opengis.referencing.datum.Datum#getAnchorPoint() Datum} property.</p>
167 *
168 * @return A description of the anchor point, or {@code null} if none.
169 */
170 public InternationalString getAnchorPoint() {
171 return null;
172 }
173
174 /**
175 * Returns The time after which this datum definition is valid. The default implementation
176 * returns {@code null} since this simple implementation does not define realization epoch.
177 *
178 * <p>Anchor point is a
179 * {@link org.opengis.referencing.datum.Datum#getRealizationEpoch() Datum} property.</p>
180 *
181 * @return The datum realization epoch, or {@code null} if not available.
182 */
183 public Date getRealizationEpoch() {
184 return null;
185 }
186
187 /**
188 * Returns the NetCDF object description, or {@code null} if none.
189 * The default implementation returns {@code null}.
190 *
191 * @return The remarks, or {@code null} if none.
192 *
193 * @see NetcdfAxis#getRemarks()
194 */
195 @Override
196 public InternationalString getRemarks() {
197 return null;
198 }
199
200 /**
201 * Compares this object with the given object for equality. The default implementation
202 * returns {@code true} if the given object is non-null, wraps an object of the same
203 * class than this object and the wrapped NetCDF objects are equal.
204 *
205 * @param other The other object to compare with this object.
206 * @return {@code true} if both objects are equal.
207 */
208 @Override
209 public boolean equals(final Object other) {
210 if (other == this) {
211 return true;
212 }
213 if (other != null && other.getClass() == getClass()) {
214 return Objects.equals(delegate(), ((NetcdfIdentifiedObject) other).delegate());
215 }
216 return false;
217 }
218
219 /**
220 * Returns a hash code value for this object. The default implementation
221 * derives a value from the code returned by the wrapped NetCDF object.
222 */
223 @Override
224 public int hashCode() {
225 return ~delegate().hashCode();
226 }
227
228 /**
229 * Returns a string representation of this object {@linkplain #getName() name}.
230 */
231 @Override
232 public String toString() {
233 final StringBuilder buffer = new StringBuilder(getCodeSpace()).append(':');
234 final String name = getCode().trim();
235 final boolean needsQuote = (name.indexOf(' ') >= 0);
236 if (needsQuote) {
237 buffer.append('"');
238 }
239 buffer.append(name);
240 if (needsQuote) {
241 buffer.append('"');
242 }
243 return buffer.toString();
244 }
245
246 /**
247 * Returns a <cite>Well Known Text</cite> representation of this object, if this
248 * operation is supported. The default implementation thrown an exception in all
249 * cases.
250 */
251 @Override
252 public String toWKT() throws UnsupportedOperationException {
253 throw new UnsupportedOperationException();
254 }
255 }