Author: desruisseaux
Date: Fri Mar 1 21:41:44 2013
New Revision: 1451725
URL: http://svn.apache.org/r1451725
Log:
Partial port of the MetadataStandard class.
Added:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
(with props)
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
(with props)
Modified:
sis/branches/JDK7/ide-project/NetBeans/nbproject/project.xml
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
Modified: sis/branches/JDK7/ide-project/NetBeans/nbproject/project.xml
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/ide-project/NetBeans/nbproject/project.xml?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
--- sis/branches/JDK7/ide-project/NetBeans/nbproject/project.xml (original)
+++ sis/branches/JDK7/ide-project/NetBeans/nbproject/project.xml Fri Mar 1
21:41:44 2013
@@ -21,6 +21,7 @@
<spellchecker-wordlist
xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
<word>bitmask</word>
<word>classname</word>
+ <word>classnames</word>
<word>classpath</word>
<word>deserialization</word>
<word>deserialized</word>
Modified:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
---
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/AbstractMetadata.java
[UTF-8] Fri Mar 1 21:41:44 2013
@@ -57,9 +57,11 @@ public abstract class AbstractMetadata i
*
* @see <a href="http://jira.geotoolkit.org/browse/GEOTK-48">GEOTK-48</a>
*/
- private static Class<?> getClass(final Object metadata) {
+ private static Class<?> getPublicClass(final Object metadata) {
Class<?> type = metadata.getClass();
- while (!Modifier.isPublic(type.getModifiers()) &&
type.getName().startsWith("org.apache.sis.metadata.iso.")) { // TODO
+ while (!Modifier.isPublic(type.getModifiers()) &&
+ type.getName().startsWith(MetadataStandard.SIS_PACKAGE))
+ {
type = type.getSuperclass();
}
return type;
@@ -85,7 +87,7 @@ public abstract class AbstractMetadata i
return true;
}
if (mode == ComparisonMode.STRICT) {
- if (object == null || getClass(object) != getClass(this)) {
+ if (object == null || getPublicClass(object) !=
getPublicClass(this)) {
return false;
}
}
Added:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java?rev=1451725&view=auto
==============================================================================
---
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
(added)
+++
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
[UTF-8] Fri Mar 1 21:41:44 2013
@@ -0,0 +1,509 @@
+/*
+ * 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.metadata;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.Collection;
+import java.util.Iterator;
+import net.jcip.annotations.ThreadSafe;
+import org.opengis.metadata.citation.Citation;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.util.resources.Errors;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
+
+/**
+ * Enumeration of some metadata standards. A standard is defined by a set of
Java interfaces
+ * in a specific package or sub-packages. For example the {@linkplain
#ISO_19115 ISO 19115}
+ * standard is defined by <a href="http://www.geoapi.org">GeoAPI</a>
interfaces in the
+ * {@link org.opengis.metadata} package and sub-packages.
+ *
+ * <p>This class provides some methods operating on metadata instances through
+ * {@linkplain java.lang.reflect Java reflection}. The following rules are
assumed:</p>
+ *
+ * <ul>
+ * <li>Properties (or metadata attributes) are defined by the collection of
{@code get*()}
+ * methods with arbitrary return type, or {@code is*()} methods with
boolean return type,
+ * found in the <strong>interface</strong>. Getters declared only in the
implementation
+ * are ignored.</li>
+ * <li>Every properties are <cite>readable</cite>.</li>
+ * <li>A property is <cite>writable</cite> if a {@code set*(...)} method is
defined
+ * in the implementation class for the corresponding {@code get*()}
method. The
+ * setter doesn't need to be defined in the interface.</li>
+ * </ul>
+ *
+ * An instance of {@code MetadataStandard} is associated to every {@link
AbstractMetadata} objects.
+ * The {@code AbstractMetadata} base class usually form the basis of ISO 19115
implementations but
+ * can also be used for other standards. An instance of {@code
MetadataStandard} is also associated
+ * with Image I/O {@link
org.apache.sis.image.io.metadata.SpatialMetadataFormat} in order to define
+ * the tree of XML nodes to be associated with raster data.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-2.4)
+ * @version 0.3
+ * @module
+ */
+@ThreadSafe
+public class MetadataStandard {
+ /**
+ * The package of SIS implementation of ISO 19115.
+ * This package name has a trailing dot.
+ */
+ static final String SIS_PACKAGE = "org.apache.sis.metadata.iso.";
+
+ /**
+ * Metadata instances defined in this class. The current implementation
does not yet
+ * contains the user-defined instances. However this may be something we
will need to
+ * do in the future.
+ */
+ private static final MetadataStandard[] INSTANCES;
+
+ /**
+ * An instance working on ISO 19123 standard as defined by GeoAPI
interfaces
+ * in the {@link org.opengis.referencing} package and sub-packages.
+ */
+ public static final MetadataStandard ISO_19111;
+
+ /**
+ * An instance working on ISO 19115 standard as defined by GeoAPI
interfaces
+ * in the {@link org.opengis.metadata} package and sub-packages.
+ */
+ public static final MetadataStandard ISO_19115;
+
+ /**
+ * An instance working on ISO 19119 standard as defined by GeoAPI
interfaces
+ * in the {@link org.opengis.service} package and sub-packages.
+ */
+ public static final MetadataStandard ISO_19119;
+
+ /**
+ * An instance working on ISO 19123 standard as defined by GeoAPI
interfaces
+ * in the {@link org.opengis.coverage} package and sub-packages.
+ */
+ public static final MetadataStandard ISO_19123;
+ static {
+ final String[] prefix = {"Default", "Abstract"};
+ final String[] acronyms = {"CoordinateSystem", "CS",
"CoordinateReferenceSystem", "CRS"};
+ ISO_19111 = new StandardImplementation("ISO 19111",
"org.opengis.referencing.", "org.apache.sis.referencing.", prefix, acronyms);
+ ISO_19115 = new StandardImplementation("ISO 19115",
"org.opengis.metadata.", SIS_PACKAGE, prefix, null);
+ ISO_19119 = new StandardImplementation("ISO 19119",
"org.opengis.service.", null, null, null);
+ ISO_19123 = new StandardImplementation("ISO 19123",
"org.opengis.coverage.", null, null, null);
+ INSTANCES = new MetadataStandard[] {
+ ISO_19111,
+ ISO_19115,
+ ISO_19119,
+ ISO_19123
+ };
+ }
+
+ /**
+ * Bibliographical reference to the international standard.
+ *
+ * @see #getCitation()
+ */
+ private final Citation citation;
+
+ /**
+ * The root packages for metadata interfaces. Must have a trailing {@code
'.'}.
+ */
+ final String interfacePackage;
+
+ /**
+ * Accessors for the specified implementations.
+ * The only legal value types are:
+ *
+ * <ul>
+ * <li>{@link Class} if we have determined the standard interface for a
given type
+ * but did not yet created the {@link PropertyAccessor} for it.</li>
+ * <li>{@link PropertyAccessor} otherwise.</li>
+ * </ul>
+ */
+ private final Map<Class<?>, Object> accessors;
+
+ /**
+ * Creates a new instance working on implementation of interfaces defined
+ * in the specified package. For the ISO 19115 standard reflected by GeoAPI
+ * interfaces, it should be the {@link org.opengis.metadata} package.
+ *
+ * @param citation Bibliographical reference to the international
standard.
+ * @param interfacePackage The root package for metadata interfaces.
+ */
+ public MetadataStandard(final Citation citation, final Package
interfacePackage) {
+ ensureNonNull("citation", citation);
+ ensureNonNull("interfacePackage", interfacePackage);
+ this.citation = citation;
+ this.interfacePackage = interfacePackage.getName() + '.';
+ this.accessors = new IdentityHashMap<>();
+ }
+
+ /**
+ * Creates a new instance working on implementation of interfaces defined
in the
+ * specified package. This constructor is used only for the pre-defined
constants.
+ *
+ * @param citation Bibliographical reference to the international
standard.
+ * @param interfacePackage The root package for metadata interfaces.
+ */
+ MetadataStandard(final Citation citation, final String interfacePackage) {
+ this.citation = citation;
+ this.interfacePackage = interfacePackage;
+ this.accessors = new IdentityHashMap<>();
+ }
+
+ /**
+ * Returns the metadata standard for the given class. The argument given
to this method can be
+ * either an interface defined by the standard, or a class implementing
such interface. If the
+ * class implements more than one interface, then the first interface
recognized by this method,
+ * in declaration order, will be retained.
+ *
+ * <p>The current implementation recognizes only the standards defined by
the public static
+ * constants defined in this class. A future SIS version may recognize
user-defined constants.</p>
+ *
+ * @param type The metadata standard interface, or an implementation
class.
+ * @return The metadata standard for the given type, or {@code null} if
not found.
+ */
+ public static MetadataStandard forClass(final Class<?> type) {
+ String name = type.getName();
+ for (final MetadataStandard candidate : INSTANCES) {
+ if (name.startsWith(candidate.interfacePackage)) {
+ return candidate;
+ }
+ }
+ for (final Class<?> interf : Classes.getAllInterfaces(type)) {
+ name = interf.getName();
+ for (final MetadataStandard candidate : INSTANCES) {
+ if (name.startsWith(candidate.interfacePackage)) {
+ return candidate;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a bibliographical reference to the international standard.
+ * The default implementation return the citation given at construction
time.
+ *
+ * @return Bibliographical reference to the international standard.
+ */
+ public Citation getCitation() {
+ return citation;
+ }
+
+ /**
+ * Returns the accessor for the specified implementation class, or {@code
null} if none.
+ * The given class shall not be the standard interface, unless the
metadata is read-only.
+ * More specifically, the given {@code type} shall be one of the following:
+ *
+ * <ul>
+ * <li>The value of {@code metadata.getClass()};</li>
+ * <li>The value of {@link #getImplementation(Class)} after check for
non-null value.</li>
+ * </ul>
+ *
+ * @param implementation The implementation class.
+ * @return The accessor for the given implementation, or {@code null} if
the given class does
+ * not implement a metadata interface of the expected package and
{@code mandatory}
+ * is {@code false}.
+ * @throws ClassCastException if the specified class does not implement a
metadata interface
+ * of the expected package and {@code mandatory} is {@code true}.
+ */
+ final PropertyAccessor getAccessor(final Class<?> implementation, final
boolean mandatory) {
+ synchronized (accessors) {
+ // Check for previously created accessors.
+ final Object value = accessors.get(implementation);
+ if (value instanceof PropertyAccessor) {
+ return (PropertyAccessor) value;
+ }
+ // Check if we started some computation that we can finish.
+ final Class<?> type;
+ if (value != null) {
+ type = (Class<?>) value;
+ } else {
+ // Nothing were computed. Try to compute now.
+ type = findInterface(implementation);
+ if (type == null) {
+ if (!mandatory) {
+ return null;
+ }
+ throw new
ClassCastException(Errors.format(Errors.Keys.UnknownType_1, type));
+ }
+ }
+ final PropertyAccessor accessor = new PropertyAccessor(citation,
type, implementation);
+ accessors.put(implementation, accessor);
+ return accessor;
+ }
+ }
+
+ /**
+ * Returns {@code true} if the given type is assignable to a type from
this standard.
+ * If this method returns {@code true}, then invoking {@link
#getInterface(Class)} is
+ * guaranteed to succeed without throwing an exception.
+ *
+ * @param type The implementation class (can be {@code null}).
+ * @return {@code true} if the given class is an interface of this
standard,
+ * or implements an interface of this standard.
+ */
+ public boolean isMetadata(final Class<?> type) {
+ if (type != null) {
+ // Checks if the class is an interface from the standard.
+ if (type.isInterface() &&
type.getName().startsWith(interfacePackage)) {
+ return true;
+ }
+ // Checks if the class is an implementation of the standard.
+ synchronized (accessors) {
+ if (accessors.containsKey(type)) {
+ return true;
+ }
+ final Class<?> standard = findInterface(type);
+ if (standard != null) {
+ accessors.put(type, standard);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the metadata interface implemented by the specified
implementation.
+ * Only one metadata interface can be implemented. If the given type is
already
+ * an interface from the standard, then it is returned directly.
+ *
+ * @param type The standard interface or the implementation class.
+ * @return The single interface, or {@code null} if none where found.
+ */
+ private Class<?> findInterface(Class<?> type) {
+ if (type != null) {
+ if (type.isInterface()) {
+ if (type.getName().startsWith(interfacePackage)) {
+ return type;
+ }
+ } else {
+ /*
+ * Gets every interfaces from the supplied package in
declaration order,
+ * including the ones declared in the super-class.
+ */
+ final Set<Class<?>> interfaces = new LinkedHashSet<>();
+ do {
+ getInterfaces(type, interfaces);
+ type = type.getSuperclass();
+ } while (type != null);
+ /*
+ * If we found more than one interface, removes the
+ * ones that are sub-interfaces of the other.
+ */
+ for (final Iterator<Class<?>> it=interfaces.iterator();
it.hasNext();) {
+ final Class<?> candidate = it.next();
+ for (final Class<?> child : interfaces) {
+ if (candidate != child &&
candidate.isAssignableFrom(child)) {
+ it.remove();
+ break;
+ }
+ }
+ }
+ final Iterator<Class<?>> it = interfaces.iterator();
+ if (it.hasNext()) {
+ final Class<?> candidate = it.next();
+ if (!it.hasNext()) {
+ return candidate;
+ }
+ // Found more than one interface; we don't know which one
to pick.
+ // Returns 'null' for now; the caller will thrown an
exception.
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Puts every interfaces for the given type in the specified collection.
+ * This method invokes itself recursively for scanning parent interfaces.
+ *
+ * @see Classes#getAllInterfaces(Class)
+ */
+ private void getInterfaces(final Class<?> type, final Collection<Class<?>>
interfaces) {
+ for (final Class<?> candidate : type.getInterfaces()) {
+ if (candidate.getName().startsWith(interfacePackage)) {
+ interfaces.add(candidate);
+ }
+ getInterfaces(candidate, interfaces);
+ }
+ }
+
+ /**
+ * Returns the metadata interface implemented by the specified
implementation class.
+ * If the given type is already an interface from this standard, then it
is returned
+ * unchanged.
+ *
+ * {@note The word "interface" may be taken in a looser sense than the
usual Java sense
+ * because if the given type is defined in this standard package,
then it is returned
+ * unchanged. The standard package is usually made of interfaces
and code lists only,
+ * but this is not verified by this method.}
+ *
+ * @param type The implementation class.
+ * @return The interface implemented by the given implementation class.
+ * @throws ClassCastException if the specified implementation class does
+ * not implement an interface of this standard.
+ *
+ * @see AbstractMetadata#getInterface
+ */
+ public Class<?> getInterface(final Class<?> type) throws
ClassCastException {
+ ensureNonNull("type", type);
+ if (type.getName().startsWith(interfacePackage)) {
+ return type;
+ }
+ throw new UnsupportedOperationException(); // TODO: port Geotk code
here.
+ }
+
+ /**
+ * Returns the implementation class for the given interface, or {@code
null} if none.
+ * The default implementation returns {@code null} if every cases.
Subclasses shall
+ * override this method in order to map GeoAPI interfaces to their
implementation.
+ *
+ * @param type The interface, typically from the {@code
org.opengis.metadata} package.
+ * @return The implementation class, or {@code null} if none.
+ */
+ protected Class<?> getImplementation(final Class<?> type) {
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if this metadata is modifiable. This method is not
public because it
+ * uses heuristic rules. In case of doubt, this method conservatively
returns {@code true}.
+ *
+ * @throws ClassCastException if the specified implementation class do
+ * not implements a metadata interface of the expected package.
+ *
+ * @see ModifiableMetadata#isModifiable()
+ */
+ final boolean isModifiable(final Class<?> implementation) throws
ClassCastException {
+ return getAccessor(implementation, true).isModifiable();
+ }
+
+ /**
+ * Replaces every properties in the specified metadata by their
+ * {@linkplain ModifiableMetadata#unmodifiable() unmodifiable variant}.
+ *
+ * @throws ClassCastException if the specified implementation class do
+ * not implements a metadata interface of the expected package.
+ *
+ * @see ModifiableMetadata#freeze()
+ */
+ final void freeze(final Object metadata) throws ClassCastException {
+ getAccessor(metadata.getClass(), true).freeze(metadata);
+ }
+
+ /**
+ * Copies all metadata from source to target.
+ * The source must implements the same metadata interface than the target.
+ *
+ * @param source The metadata to copy.
+ * @param target The target metadata.
+ * @param skipNulls If {@code true}, only non-null values will be copied.
+ * @throws ClassCastException if the source or target object don't
+ * implements a metadata interface of the expected package.
+ * @throws UnmodifiableMetadataException if the target metadata is
unmodifiable,
+ * or if at least one setter method was required but not found.
+ *
+ * @see ModifiableMetadata#clone()
+ */
+ public void shallowCopy(final Object source, final Object target, final
boolean skipNulls)
+ throws ClassCastException, UnmodifiableMetadataException
+ {
+ ensureNonNull("target", target);
+ final PropertyAccessor accessor = getAccessor(target.getClass(), true);
+ if (!accessor.type.isInstance(source)) {
+ ensureNonNull("source", source);
+ throw new
ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_3,
+ "source", accessor.type, source.getClass()));
+ }
+ if (!accessor.shallowCopy(source, target, skipNulls)) {
+ throw new
UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata));
+ }
+ }
+
+ /**
+ * Compares the two specified metadata objects.
+ * The comparison is <cite>shallow</cite>, i.e. all metadata attributes
are compared using the
+ * {@link LenientComparable#equals(Object, ComparisonMode)} method if
possible, or the
+ * {@link Object#equals(Object)} method otherwise, without explicit
recursive call to
+ * this {@code shallowEquals(...)} method for child metadata.
+ *
+ * <p>This method can optionally excludes null values from the comparison.
In metadata,
+ * null value often means "don't know", so in some occasion we want to
consider two
+ * metadata as different only if a property value is know for sure to be
different.</p>
+ *
+ * <p>The first arguments must be an implementation of a metadata
interface, otherwise an
+ * exception will be thrown. The two arguments do not need to be the same
implementation
+ * however.</p>
+ *
+ * @param metadata1 The first metadata object to compare.
+ * @param metadata2 The second metadata object to compare.
+ * @param mode The strictness level of the comparison.
+ * @param skipNulls If {@code true}, only non-null values will be compared.
+ * @return {@code true} if the given metadata objects are equals.
+ * @throws ClassCastException if at least one metadata object don't
+ * implements a metadata interface of the expected package.
+ *
+ * @see AbstractMetadata#equals(Object, ComparisonMode)
+ */
+ public boolean shallowEquals(final Object metadata1, final Object
metadata2,
+ final ComparisonMode mode, final boolean skipNulls) throws
ClassCastException
+ {
+ if (metadata1 == metadata2) {
+ return true;
+ }
+ if (metadata1 == null || metadata2 == null) {
+ return false;
+ }
+ final PropertyAccessor accessor = getAccessor(metadata1.getClass(),
true);
+ if (accessor.type != findInterface(metadata2.getClass())) {
+ return false;
+ }
+ return accessor.shallowEquals(metadata1, metadata2, mode, skipNulls);
+ }
+
+ /**
+ * Computes a hash code for the specified metadata. The hash code is
defined as the
+ * sum of hash code values of all non-null properties. This is the same
contract than
+ * {@link java.util.Set#hashCode} and ensure that the hash code value is
insensitive
+ * to the ordering of properties.
+ *
+ * @param metadata The metadata object to compute hash code.
+ * @return A hash code value for the specified metadata.
+ * @throws ClassCastException if the metadata object doesn't implement a
metadata
+ * interface of the expected package.
+ *
+ * @see AbstractMetadata#hashCode()
+ */
+ public int hashCode(final Object metadata) throws ClassCastException {
+ return getAccessor(metadata.getClass(), true).hashCode(metadata);
+ }
+
+ /**
+ * Returns a string representation of this metadata standard.
+ * This is for debugging purpose only and may change in any future version.
+ */
+ @Override
+ public String toString() {
+ return Classes.getShortClassName(this) + '[' + citation.getTitle() +
']';
+ }
+}
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/MetadataStandard.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
---
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
[UTF-8] Fri Mar 1 21:41:44 2013
@@ -21,9 +21,9 @@ import java.util.Map;
import java.util.Arrays;
import java.util.Locale;
import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Collection;
-import java.util.LinkedHashSet;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
@@ -97,7 +97,7 @@ final class PropertyAccessor {
* Getters shared between many instances of this class. Two different
implementations
* may share the same getters but different setters.
*/
- private static final Map<Class<?>, Method[]> SHARED_GETTERS = new
HashMap<>();
+ private static final Map<Class<?>, Method[]> SHARED_GETTERS = new
IdentityHashMap<>();
/**
* Additional getter to declare in every list of getter methods that do
not already provide
@@ -357,73 +357,6 @@ final class PropertyAccessor {
}
/**
- * Returns the metadata interface implemented by the specified
implementation type.
- * Only one metadata interface can be implemented. If the given type is
already an
- * interface from the standard, it is returned directly.
- *
- * @param type The type of the implementation (could also be the
interface type).
- * @param interfacePackage The root package for metadata interfaces.
- * @return The single interface, or {@code null} if none where found.
- */
- static Class<?> getStandardType(Class<?> type, final String
interfacePackage) {
- if (type != null) {
- if (type.isInterface()) {
- if (type.getName().startsWith(interfacePackage)) {
- return type;
- }
- } else {
- /*
- * Gets every interfaces from the supplied package in
declaration order,
- * including the ones declared in the super-class.
- */
- final Set<Class<?>> interfaces = new LinkedHashSet<>();
- do {
- getInterfaces(type, interfacePackage, interfaces);
- type = type.getSuperclass();
- } while (type != null);
- /*
- * If we found more than one interface, removes the
- * ones that are sub-interfaces of the other.
- */
- for (final Iterator<Class<?>> it=interfaces.iterator();
it.hasNext();) {
- final Class<?> candidate = it.next();
- for (final Class<?> child : interfaces) {
- if (candidate != child &&
candidate.isAssignableFrom(child)) {
- it.remove();
- break;
- }
- }
- }
- final Iterator<Class<?>> it = interfaces.iterator();
- if (it.hasNext()) {
- final Class<?> candidate = it.next();
- if (!it.hasNext()) {
- return candidate;
- }
- // Found more than one interface; we don't know which one
to pick.
- // Returns 'null' for now; the caller will thrown an
exception.
- }
- }
- }
- return null;
- }
-
- /**
- * Puts every interfaces for the given type in the specified collection.
- * This method invokes itself recursively for scanning parent interfaces.
- */
- private static void getInterfaces(final Class<?> type, final String
interfacePackage,
- final Collection<Class<?>> interfaces)
- {
- for (final Class<?> candidate : type.getInterfaces()) {
- if (candidate.getName().startsWith(interfacePackage)) {
- interfaces.add(candidate);
- }
- getInterfaces(candidate, interfacePackage, interfaces);
- }
- }
-
- /**
* Returns the getters. The returned array should never be modified,
* since it may be shared among many instances of {@code PropertyAccessor}.
*
Added:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java?rev=1451725&view=auto
==============================================================================
---
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
(added)
+++
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
[UTF-8] Fri Mar 1 21:41:44 2013
@@ -0,0 +1,147 @@
+/*
+ * 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.metadata;
+
+import java.util.Map;
+import java.util.IdentityHashMap;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.internal.simple.SimpleCitation;
+
+
+/**
+ * Information about an Apache SIS metadata standard implementation.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-2.4)
+ * @version 0.3
+ * @module
+ */
+final class StandardImplementation extends MetadataStandard {
+ /**
+ * The root packages for metadata implementations, or {@code null} if none.
+ * If non-null, then this string must ends with a trailing {@code "."}.
+ */
+ private final String implementationPackage;
+
+ /**
+ * The prefixes that implementation classes may have.
+ * The most common prefixes should be first, since the prefixes will be
tried in that order.
+ */
+ private final String[] prefix;
+
+ /**
+ * The acronyms that implementation classes may have, or {@code null} if
none. If non-null,
+ * then this array shall contain (<var>full text</var>,
<var>acronym</var>) pairs. The full
+ * text shall appear to the end of the class name, otherwise it is not
replaced. This is
+ * necessary in order to avoid the replacement of {@code
"DefaultCoordinateSystemAxis"} by
+ * {@code "DefaultCSAxis"}.
+ */
+ private final String[] acronyms;
+
+ /**
+ * Implementations for a given interface, computed when first needed then
cached.
+ */
+ private final Map<Class<?>,Class<?>> implementations;
+
+ /**
+ * Creates a new instance working on implementation of interfaces defined
in the
+ * specified package. This constructor is used only for the pre-defined
constants.
+ *
+ * @param citation The title of the standard.
+ * @param interfacePackage The root package for metadata interfaces,
with a trailing {@code '.'}.
+ * @param implementationPackage The root package for metadata
implementations. with a trailing {@code '.'}.
+ * @param prefix The prefix of implementation class. This
array is not cloned.
+ * @param acronyms An array of (full text, acronyms) pairs.
This array is not cloned.
+ */
+ StandardImplementation(final String citation, final String
interfacePackage,
+ final String implementationPackage, final String[] prefix, final
String[] acronyms)
+ {
+ super(new SimpleCitation(citation), interfacePackage);
+ this.implementationPackage = implementationPackage;
+ this.prefix = prefix;
+ this.acronyms = acronyms;
+ this.implementations = new IdentityHashMap<>();
+ }
+
+ /**
+ * Returns the implementation class for the given interface, or {@code
null} if none.
+ * This class uses heuristic rules based on naming conventions.
+ *
+ * @param type The interface, typically from the {@code
org.opengis.metadata} package.
+ * @return The implementation class, or {@code null} if none.
+ */
+ @Override
+ protected Class<?> getImplementation(final Class<?> type) {
+ /*
+ * We require the type to be an interface in order to exclude
+ * CodeLists, Enums and Exceptions.
+ */
+ if (type != null && type.isInterface()) {
+ String name = type.getName();
+ if (name.startsWith(interfacePackage)) {
+ synchronized (implementations) {
+ Class<?> candidate = implementations.get(type);
+ if (candidate != null) {
+ return (candidate != Void.TYPE) ? candidate : null;
+ }
+ /*
+ * Prepares a buffer with a copy of the class name in
which the interface
+ * package has been replaced by the implementation
package, and some text
+ * have been replaced by their acronym (if any).
+ */
+ final StringBuilder buffer = new
StringBuilder(implementationPackage)
+ .append(name, interfacePackage.length(),
name.length());
+ if (acronyms != null) {
+ for (int i=0; i<acronyms.length; i+=2) {
+ final String acronym = acronyms[i];
+ if (CharSequences.endsWith(buffer, acronym,
false)) {
+ buffer.setLength(buffer.length() -
acronym.length());
+ buffer.append(acronyms[i+1]);
+ break;
+ }
+ }
+ }
+ /*
+ * Try to insert a prefix in front of the class name,
until a match is found.
+ */
+ final int prefixPosition = buffer.lastIndexOf(".") + 1;
+ int length = 0;
+ for (final String p : prefix) {
+ name = buffer.replace(prefixPosition, prefixPosition +
length, p).toString();
+ try {
+ candidate = Class.forName(name);
+ } catch (ClassNotFoundException e) {
+
Logging.recoverableException(MetadataStandard.class, "getImplementation", e);
+ length = p.length();
+ continue;
+ }
+ if (candidate.isAnnotationPresent(Deprecated.class)) {
+ // Skip deprecated implementations.
+ length = p.length();
+ continue;
+ }
+ implementations.put(type, candidate);
+ return candidate;
+ }
+ implementations.put(type, Void.TYPE); // Marker for "class
not found".
+ }
+ }
+ }
+ return null;
+ }
+}
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/StandardImplementation.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] Fri Mar 1 21:41:44 2013
@@ -380,6 +380,11 @@ public final class Errors extends Indexe
public static final int UnexpectedEndOfString_1 = 30;
/**
+ * Type ‘{0}’ is unknown in this context.
+ */
+ public static final int UnknownType_1 = 76;
+
+ /**
* This affine transform is unmodifiable.
*/
public static final int UnmodifiableAffineTransform = 23;
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] (original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] Fri Mar 1 21:41:44 2013
@@ -88,6 +88,7 @@ StalledThread_1 = Thread
UndefinedOrderingForElements_2 = Ordering between \u201c{0}\u201d and
\u201c{1}\u201d elements is undefined.
UnexpectedChange_1 = Unexpected change in \u2018{0}\u2019.
UnexpectedEndOfString_1 = More characters were expected at the end of
\u201c{0}\u201d.
+UnknownType_1 = Type \u2018{0}\u2019 is unknown in this
context.
UnmodifiableAffineTransform = This affine transform is unmodifiable.
UnmodifiableGeometry = This geometry is unmodifiable.
UnmodifiableMetadata = This metadata is unmodifiable.
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1451725&r1=1451724&r2=1451725&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] (original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] Fri Mar 1 21:41:44 2013
@@ -77,6 +77,7 @@ StalledThread_1 = La t\u
UndefinedOrderingForElements_2 = L\u2019ordre entre les \u00e9l\u00e9ments
\u201c{0}\u201d et \u201c{1}\u201d n\u2019est pas d\u00e9fini.
UnexpectedChange_1 = Changement inattendu dans \u2018{0}\u2019.
UnexpectedEndOfString_1 = D\u2019autres caract\u00e8res \u00e9taient
attendus \u00e0 la fin du texte \u201c{0}\u201d.
+UnknownType_1 = Le type \u2018{0}\u2019 n\u2019est pas
reconnu dans ce contexte.
UnmodifiableAffineTransform = Cette transformation affine n\u2019est pas
modifiable.
UnmodifiableGeometry = Cette g\u00e9om\u00e9trie n\u2019est pas
modifiable.
UnmodifiableMetadata = Cette m\u00e9ta-donn\u00e9e n\u2019est pas
modifiable.