sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1417549 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/internal/jaxb/code/ main/java/org/apache/sis/util/ main/java/org/apache/sis/util/type/ test/java/org/apache/sis/measure/ test/java/org/apache/sis/util/
Date Wed, 05 Dec 2012 17:37:20 GMT
Author: desruisseaux
Date: Wed Dec  5 17:37:18 2012
New Revision: 1417549

URL: http://svn.apache.org/viewvc?rev=1417549&view=rev
Log:
Ported the base classes of JAXB adapters for CodeLists.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
  (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java  
(with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/Types.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java?rev=1417549&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
Wed Dec  5 17:37:18 2012
@@ -0,0 +1,162 @@
+/*
+ * 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.jaxb.code;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import org.opengis.util.CodeList;
+import org.apache.sis.util.type.CodeLists;
+import org.apache.sis.internal.jaxb.MarshalContext;
+
+
+/**
+ * An adapter for {@link CodeList}, in order to implement the ISO-19139 standard. This object
+ * wraps a {@link CodeListProxy}, which contain {@link CodeListProxy#codeList codeList} and
+ * {@link CodeListProxy#codeListValue codeListValue} attributes. The result looks like below:
+ *
+ * {@preformat xml
+ *   <dateType>
+ *     <CI_DateTypeCode codeList="../Codelist/ML_gmxCodelists.xml#CI_DateTypeCode" codeListValue="revision"
codeSpace="fra">
+ *       révision
+ *     </CI_DateTypeCode>
+ *   </dateType>
+ * }
+ *
+ * A subclass must exist for each code list, with a {@link #getElement()} method having a
+ * {@code @XmlElement} annotation.
+ *
+ * @param <ValueType> The subclass implementing this adapter.
+ * @param <BoundType> The code list being adapted.
+ *
+ * @author  Cédric Briançon (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ *
+ * @see CodeListLocaleAdapter
+ */
+public abstract class CodeListAdapter<ValueType extends CodeListAdapter<ValueType,BoundType>,
+        BoundType extends CodeList<BoundType>> extends XmlAdapter<ValueType,BoundType>
+{
+    /**
+     * A proxy form of the {@link CodeList}.
+     */
+    protected CodeListProxy proxy;
+
+    /**
+     * Empty constructor for subclasses only.
+     */
+    protected CodeListAdapter() {
+    }
+
+    /**
+     * Creates a wrapper for a {@link CodeList}, in order to handle the format specified
+     * in ISO-19139.
+     *
+     * @param proxy The proxy version of {@link CodeList} to be marshalled.
+     */
+    protected CodeListAdapter(final CodeListProxy proxy) {
+        this.proxy = proxy;
+    }
+
+    /**
+     * Forces the initialization of the given code list class, since some
+     * calls to {@link CodeList#valueOf(Class, String)} are done whereas
+     * the constructor has not already been called.
+     *
+     * @param <T>  The code list type.
+     * @param type The code list class to initialize.
+     */
+    protected static <T extends CodeList<T>> void ensureClassLoaded(final Class<T>
type) {
+        final String name = type.getName();
+        try {
+            Class.forName(name, true, type.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new TypeNotPresentException(name, e); // Should never happen.
+        }
+    }
+
+    /**
+     * Wraps the proxy value into an adapter.
+     *
+     * @param proxy The proxy version of {@link CodeList}, to be marshalled.
+     * @return The adapter that wraps the proxy value.
+     */
+    protected abstract ValueType wrap(final CodeListProxy proxy);
+
+    /**
+     * Returns the class of code list wrapped by this adapter.
+     *
+     * @return The code list class.
+     */
+    protected abstract Class<BoundType> getCodeListClass();
+
+    /**
+     * Substitutes the adapter value read from an XML stream by the object which will
+     * contains the value. JAXB calls automatically this method at unmarshalling time.
+     *
+     * @param  adapter The adapter for this metadata value.
+     * @return A code list which represents the metadata value.
+     */
+    @Override
+    public final BoundType unmarshal(final ValueType adapter) {
+        if (adapter == null) {
+            return null;
+        }
+        return CodeLists.valueOf(getCodeListClass(), adapter.proxy.identifier());
+    }
+
+    /**
+     * Substitutes the code list by the adapter to be marshalled into an XML file
+     * or stream. JAXB calls automatically this method at marshalling time.
+     *
+     * @param  value The code list value.
+     * @return The adapter for the given code list.
+     */
+    @Override
+    public final ValueType marshal(final BoundType value) {
+        if (value == null) {
+            return null;
+        }
+        return wrap(isEnum() ? new CodeListProxy(CodeLists.getCodeName(value))
+                             : new CodeListProxy(MarshalContext.current(), value));
+    }
+
+    /**
+     * Returns {@code true} if this code list is actually an enum. The default implementation
+     * returns {@code false} in every cases, since there is very few enums in ISO 19115.
+     *
+     * @return {@code true} if this code list is actually an enum.
+     */
+    protected boolean isEnum() {
+        return false;
+    }
+
+    /**
+     * Invoked by JAXB on marshalling. Subclasses must override this
+     * method with the appropriate {@code @XmlElement} annotation.
+     *
+     * @return The {@code CodeList} value to be marshalled.
+     */
+    public abstract CodeListProxy getElement();
+
+    /*
+     * We do not define setter method (even abstract) since it seems to confuse JAXB.
+     * It is subclasses responsibility to define the setter method. The existence of
+     * this setter will be tested by MetadataAnnotationsTest.
+     */
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListAdapter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java?rev=1417549&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
Wed Dec  5 17:37:18 2012
@@ -0,0 +1,206 @@
+/*
+ * 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.jaxb.code;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import org.opengis.util.CodeList;
+import org.apache.sis.util.Locales;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.type.CodeLists;
+import org.apache.sis.internal.jaxb.MarshalContext;
+
+
+/**
+ * Stores information about {@link CodeList}, in order to handle format defined in ISO-19139
+ * about the {@code CodeList} tags. This object is wrapped by {@link CodeListAdapter} or,
in
+ * the spacial case of {@link Locale} type, by {@link CodeListLocaleAdapter}. It provides
the
+ * {@link #codeList} and {@link #codeListValue} attribute to be marshalled.
+ *
+ * @author  Cédric Briançon (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ *
+ * @see CodeListAdapter
+ * @see CodeListLocaleAdapter
+ */
+@XmlType(name = "CodeList", propOrder = { "codeSpace", "codeListValue", "codeList" })
+public final class CodeListProxy {
+    /**
+     * Returns the URL to given code list in the given XML file.
+     *
+     * @param  context    The current (un)marshalling context, or {@code null} if none.
+     * @param  file       The XML file, either {@code "gmxCodelists.xml"} or {@code "ML_gmxCodelists.xml"}.
+     * @param  identifier The UML identifier of the code list.
+     * @return The URL to the given code list in the given schema.
+     */
+    private static String schema(final MarshalContext context, final String file, final String
identifier) {
+        return schema(MarshalContext.schema(context, "gmd", "http://schemas.opengis.net/iso/19139/20070417/"),
+                "resources/Codelist", file, identifier);
+    }
+
+    /**
+     * Returns the URL to a given code list in the given XML file. This method concatenates
+     * the base schema URL with the given directory, file and identifier.
+     *
+     * @param  schema     The schema, typically as a result of a call to
+     *                    {@link MarshalContext#schema(MarshalContext, String, String)}.
+     * @param  directory  The directory to concatenate, for example {@code "resources/uom"}
+     *                    or {@code "resources/Codelist"} (<strong>no trailing {@code
'/'}</strong>).
+     * @param  file       The XML file, for example {@code "gmxUom.xml"}, {@code "gmxCodelists.xml"}
+     *                    or {@code "ML_gmxCodelists.xml"} (<strong>no trailing {@code
'#'}</strong>).
+     * @param  identifier The UML identifier of the code list.
+     * @return The URL to the given code list in the given schema.
+     */
+    private static String schema(final String schema, final String directory, final String
file, final String identifier) {
+        final StringBuilder buffer = new StringBuilder(128);
+        buffer.append(schema);
+        final int length = buffer.length();
+        if (length != 0 && buffer.charAt(length - 1) != '/') {
+            buffer.append('/');
+        }
+        return buffer.append(directory).append('/').append(file).append('#').append(identifier).toString();
+    }
+
+    /**
+     * The {@code codeList} attribute in the XML element.
+     */
+    @XmlAttribute(required = true)
+    public String codeList;
+
+    /**
+     * The {@code codeListValue} attribute in the XML element.
+     */
+    @XmlAttribute(required = true)
+    public String codeListValue;
+
+    /**
+     * The optional {@code codeSpace} attribute in the XML element. The default value is
+     * {@code null}. If a value is provided in this field, then {@link #value} should be
+     * set as well.
+     * <p>
+     * This attribute is set to the 3 letters language code of the {@link #value} attribute,
+     * as returned by {@link Locale#getISO3Language()}.
+     */
+    @XmlAttribute
+    public String codeSpace;
+
+    /**
+     * The optional value to write in the XML element. The default value is {@code null}.
+     * If a value is provided in this field, then {@link #codeSpace} is the language code
+     * of this field or {@code null} for English.
+     */
+    @XmlValue
+    public String value;
+
+    /**
+     * Default empty constructor for JAXB.
+     */
+    public CodeListProxy() {
+    }
+
+    /**
+     * Creates a new code list for the given enum.
+     *
+     * @param value The ISO 19115 identifier of the enum.
+     *
+     * @todo Replace the argument type by {@link Enum} if we fix the type of ISO 19115
+     *       code lists which are supposed to be enum.
+     *
+     * @see <a href="http://jira.codehaus.org/browse/GEO-199">GEO-199</a>
+     */
+    public CodeListProxy(final String value) {
+        this.value = value;
+    }
+
+    /**
+     * Builds a {@link CodeList} as defined in ISO-19139 standard.
+     *
+     * @param context       The current (un)marshalling context, or {@code null} if none.
+     * @param catalog       The file which defines the code list (for example {@code "ML_gmxCodelists.xml"}),
without its path.
+     * @param codeList      The {@code codeList} attribute, to be concatenated after the
catalog name and the {@code "#"} symbol.
+     * @param codeListValue The {@code codeListValue} attribute, to be declared in the attribute.
+     * @param value         The value in English language (because this constructor does
not set the {@link #codeSpace} attribute).
+     */
+    public CodeListProxy(final MarshalContext context, final String catalog,
+            final String codeList, final String codeListValue, final String value)
+    {
+        this.codeList      = schema(context, catalog, codeList);
+        this.codeListValue = codeListValue;
+        this.value         = value;
+    }
+
+    /**
+     * Builds a proxy instance of {@link CodeList}. This constructors stores
+     * the values that will be used for marshalling.
+     *
+     * @param context The current (un)marshalling context, or {@code null} if none.
+     * @param code    The code list to wrap.
+     */
+    public CodeListProxy(final MarshalContext context, final CodeList<?> code) {
+        final String classID = CodeLists.getListName(code);
+        final String fieldID = CodeLists.getCodeName(code);
+        codeList = schema(context, "gmxCodelists.xml", classID);
+        /*
+         * Get the localized name of the field identifier, if possible.
+         * This code partially duplicates CodeList.getDescription(CodeList, Locale).
+         * This duplication exists because this constructor stores more information in
+         * an opportunist way. If this constructor is updated, please consider updating
+         * the CodeList.getDescription(CodeList, Locale) method accordingly.
+         */
+        final Locale locale = context.getLocale();
+        if (locale != null) {
+            final String key = classID + '.' + fieldID;
+            try {
+                value = ResourceBundle.getBundle("org.opengis.metadata.CodeLists", locale).getString(key);
+            } catch (MissingResourceException e) {
+                Logging.recoverableException(CodeListAdapter.class, "marshal", e);
+            }
+        }
+        if (value != null) {
+            codeSpace = Locales.getLanguageCode(locale);
+        } else {
+            // Fallback when no value is defined for the code list. Build a value from the
+            // most descriptive name (excluding the field name), which is usually the UML
+            // name except for CharacterSet in which case it is a string like "UTF-8".
+            value = CodeLists.getDescription(code);
+        }
+        codeListValue = fieldID;
+    }
+
+    /**
+     * Returns the identifier to use for fetching a {@link CodeList} instance.
+     * This is normally the {@link #codeListValue} attribute. However if the
+     * code list is actually used as an enumeration, then the above attribute
+     * is null and we have to use directly the {@linkplain #value} instead.
+     *
+     * @return The identifier to be given to the {@code CodeList.valueOf(...)} method.
+     */
+    public String identifier() {
+        String id = codeListValue;
+        if (id == null) {
+            id = value;
+        }
+        return id;
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/CodeListProxy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java?rev=1417549&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
Wed Dec  5 17:37:18 2012
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * JAXB adapters for code {@linkplain org.opengis.util.CodeList code lists}.
+ * Every time JAXB will try to marshall or unmarshall a code list, an adapter will replace
the
+ * code list value (which would otherwise be written directly by JAXB) by an element like
below:
+ *
+ * <ul>
+ *   <li>
+ *     {@linkplain org.opengis.metadata.identification.CharacterSet character set}:
+ *     {@code <gmd:MD_CharacterSetCode
+ *       codeList="http://schemas.opengis.net/iso/19139/20070417/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode"
+ *       codeListValue="utf8"/>}
+ *   </li>
+ * </ul>
+ *
+ * @author  Cédric Briançon (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ *
+ * @see javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
+ * @see org.opengis.util.CodeList
+ */
+@XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GMD, xmlns =
{
+    @XmlNs(prefix = "gmi", namespaceURI = Namespaces.GMI),
+    @XmlNs(prefix = "gmd", namespaceURI = Namespaces.GMD),
+    @XmlNs(prefix = "gco", namespaceURI = Namespaces.GCO)
+})
+package org.apache.sis.internal.jaxb.code;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlNsForm;
+import javax.xml.bind.annotation.XmlSchema;
+import org.apache.sis.xml.Namespaces;

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/code/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java?rev=1417549&r1=1417548&r2=1417549&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java Wed
Dec  5 17:37:18 2012
@@ -1267,7 +1267,8 @@ searchWordBreak:    while (true) {
      * @return The acronym, or {@code null} if the given text was null.
      */
     public static CharSequence camelCaseToAcronym(CharSequence text) {
-        if (text != null && !isUpperCase(text = trimWhitespaces(text))) {
+        text = trimWhitespaces(text);
+        if (text != null && !isUpperCase(text, 0, text.length())) {
             final int length = text.length();
             final StringBuilder buffer = new StringBuilder(8); // Acronyms are usually short.
             boolean wantChar = true;
@@ -1463,14 +1464,7 @@ cmp:    while (ia < lga) {
      *
      * @see String#toUpperCase()
      */
-    static boolean isUpperCase(final CharSequence text) {
-        return isUpperCase(text, 0, text.length());
-    }
-
-    /**
-     * Same as {@link #isUpperCase(CharSequence)}, but on a sub-sequence.
-     */
-    private static boolean isUpperCase(final CharSequence text, int lower, final int upper)
{
+    static boolean isUpperCase(final CharSequence text, int lower, final int upper) {
         while (lower < upper) {
             final int c = codePointAt(text, lower);
             if (!Character.isUpperCase(c)) {

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java?rev=1417549&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
(added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
Wed Dec  5 17:37:18 2012
@@ -0,0 +1,127 @@
+/*
+ * 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.util.type;
+
+import org.opengis.util.CodeList;
+
+
+/**
+ * The filters used by {@link CodeLists#valueOf(Class, String)}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-3.02)
+ * @version 0.3
+ * @module
+ */
+final class CodeListFilter implements CodeList.Filter {
+    /**
+     * The name to compare during filtering operation.
+     */
+    private final String codename;
+
+    /**
+     * {@code true} if {@link CodeList#valueOf} is allowed to create new code lists.
+     */
+    private final boolean canCreate;
+
+    /**
+     * Creates a new filter for the specified code name.
+     */
+    CodeListFilter(final String codename, final boolean canCreate) {
+        this.codename  = codename;
+        this.canCreate = canCreate;
+    }
+
+    /**
+     * Returns the name of the code to create, or {@code null} if no new code list shall
be created.
+     */
+    @Override
+    public String codename() {
+        return canCreate ? codename : null;
+    }
+
+    /**
+     * Returns {@code true} if the given code match the the name we are looking for.
+     */
+    @Override
+    public boolean accept(final CodeList<?> code) {
+        for (final String name : code.names()) {
+            if (matches(name, codename)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the given strings are equal, ignoring case, whitespaces and
the
+     * {@code '_'} character.
+     *
+     * @param  candidate The first string to compare.
+     * @param  search The second string to compare.
+     * @return {@code true} if the two strings are equal.
+     */
+    private static boolean matches(final String candidate, final String search) {
+        final int length = candidate.length();
+        final int searchLength = search.length();
+        int searchIndex=0, n;
+        for (int i=0; i<length; i+=n) {
+            int c = candidate.codePointAt(i);
+            n = Character.charCount(c);
+            if (isSignificant(c)) {
+                // Fetch the next significant character from the expected string.
+                int s;
+                do {
+                    if (searchIndex >= searchLength) {
+                        return false; // The name has more significant characters than expected.
+                    }
+                    s = search.codePointAt(searchIndex);
+                    searchIndex += Character.charCount(s);
+                } while (!isSignificant(s));
+
+                // Compare the characters in the same way than String.equalsIgnoreCase(String).
+                if (c != s) {
+                    c = Character.toUpperCase(c);
+                    s = Character.toUpperCase(s);
+                    if (c != s) {
+                        c = Character.toLowerCase(c);
+                        s = Character.toLowerCase(s);
+                        if (c != s) {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        while (searchIndex < searchLength) {
+            final int s = search.charAt(searchIndex);
+            if (isSignificant(s)) {
+                return false; // The name has less significant characters than expected.
+            }
+            searchIndex += Character.charCount(s);
+        }
+        return true;
+    }
+
+    /**
+     * Returns {@code true} if the given character should be taken in account when comparing
two
+     * strings. Current implementation ignores whitespace and the {@code '_'} character.
+     */
+    private static boolean isSignificant(final int c) {
+        return !Character.isWhitespace(c) && !Character.isIdentifierIgnorable(c)
&& c != '_';
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeListFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java?rev=1417549&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java Wed
Dec  5 17:37:18 2012
@@ -0,0 +1,247 @@
+/*
+ * 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.util.type;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.MissingResourceException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
+import org.opengis.util.CodeList;
+import org.opengis.annotation.UML;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.logging.Logging;
+
+
+/**
+ * Utility methods working on {@link CodeList}.
+ * This class defines a SIS {@link #valueOf(Class, String)} method which can be used instead
+ * of the GeoAPI {@code CodeList.valueOf(Class, String)} when more tolerant search is wanted.
+ * The main difference between the two methods is that the GeoAPI method is strict while
the
+ * SIS method ignores cases, whitespaces and the {@code '_'} character.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-3.02)
+ * @version 0.3
+ * @module
+ */
+public final class CodeLists extends Static {
+    /**
+     * Do not allows instantiation of this class.
+     */
+    private CodeLists() {
+    }
+
+    /**
+     * Returns the ISO classname (if available) or the Java classname (as a fallback)
+     * of the given code. This method uses the {@link UML} annotation if it exists, or
+     * fallback on the {@linkplain Class#getSimpleName() simple class name} otherwise.
+     * Examples:
+     *
+     * <ul>
+     *   <li><code>getListName({@linkplain org.opengis.referencing.cs.AxisDirection#NORTH})</code>
returns {@code "CS_AxisDirection"}.</li>
+     *   <li><code>getListName({@linkplain org.opengis.metadata.identification.CharacterSet#UTF_8})</code>
returns {@code "MD_CharacterSetCode"}.</li>
+     *   <li><code>getListName({@linkplain org.opengis.metadata.content.ImagingCondition#BLURRED_IMAGE})</code>
returns {@code "MD_ImagingConditionCode"}.</li>
+     * </ul>
+     *
+     * @param  code The code for which to get the class name, or {@code null}.
+     * @return The ISO (preferred) or Java (fallback) class name, or {@code null} if the
given code is null.
+     */
+    public static String getListName(final CodeList<?> code) {
+        if (code == null) {
+            return null;
+        }
+        final Class<?> type = code.getClass();
+        final String id = Types.getStandardName(type);
+        return (id != null) ? id : type.getSimpleName();
+    }
+
+    /**
+     * Returns the ISO name (if available) or the Java name (as a fallback) of the given
code.
+     * If the code has no {@link UML} identifier, then the programmatic name is used as a
fallback.
+     * Examples:
+     *
+     * <ul>
+     *   <li><code>getCodeName({@linkplain org.opengis.referencing.cs.AxisDirection#NORTH})</code>
returns {@code "north"}.</li>
+     *   <li><code>getCodeName({@linkplain org.opengis.metadata.identification.CharacterSet#UTF_8})</code>
returns {@code "utf8"}.</li>
+     *   <li><code>getCodeName({@linkplain org.opengis.metadata.content.ImagingCondition#BLURRED_IMAGE})</code>
returns {@code "blurredImage"}.</li>
+     * </ul>
+     *
+     * @param  code The code for which to get the name, or {@code null}.
+     * @return The UML identifiers or programmatic name for the given code,
+     *         or {@code null} if the given code is null.
+     */
+    public static String getCodeName(final CodeList<?> code) {
+        if (code == null) {
+            return null;
+        }
+        final String id = code.identifier();
+        return (id != null && !id.isEmpty()) ? id : code.name();
+    }
+
+    /**
+     * Returns a unlocalized description of the given code.
+     * This method builds a description using heuristics rules, which should give reasonable
+     * results without the need of resource bundles. For better results, consider using
+     * {@link #getDescription(CodeList, Locale)} instead.
+     *
+     * <p>The current heuristic implementation is to iterate over {@linkplain CodeList#names()
all
+     * code names}, select the longest one excluding the {@linkplain CodeList#name() field
name}
+     * if possible, then {@linkplain CharSequences#camelCaseToSentence(CharSequence) make
a sentence}
+     * from that name. Examples:</p>
+     *
+     * <ul>
+     *   <li><code>getDescription({@linkplain org.opengis.referencing.cs.AxisDirection#NORTH})</code>
returns {@code "North"}.</li>
+     *   <li><code>getDescription({@linkplain org.opengis.metadata.identification.CharacterSet#UTF_8})</code>
returns {@code "UTF-8"}.</li>
+     *   <li><code>getDescription({@linkplain org.opengis.metadata.content.ImagingCondition#BLURRED_IMAGE})</code>
returns {@code "Blurred image"}.</li>
+     * </ul>
+     *
+     * @param  code The code from which to get a description, or {@code null}.
+     * @return A unlocalized description for the given code, or {@code null} if the given
code is null.
+     */
+    public static String getDescription(final CodeList<?> code) {
+        if (code == null) {
+            return null;
+        }
+        String id = code.identifier();
+        final String name = code.name();
+        if (id == null) {
+            id = name;
+        }
+        for (final String candidate : code.names()) {
+            if (!candidate.equals(name) && candidate.length() >= id.length())
{
+                id = candidate;
+            }
+        }
+        return CharSequences.camelCaseToSentence(id).toString();
+    }
+
+    /**
+     * Returns the localized name of the given code.
+     * Special cases:
+     *
+     * <ul>
+     *   <li>If {@code code} is {@code null}, then this method returns {@code null}.</li>
+     *   <li>If {@code locale} is {@code null}, then this method uses {@link Locale#US}
+     *       as a close approximation of "unlocalized" strings since OGC standards are
+     *       defined in English.</li>
+     *   <li>If there is no localized resources for the given code, then this method
fallback
+     *       on {@link #getDescription(CodeList)}.</li>
+     * </ul>
+     *
+     * @param  code   The code for which to get the localized name, or {@code null}.
+     * @param  locale The local, or {@code null} if none.
+     * @return The localized sentence, or {@code null} if the given code is null.
+     */
+    public static String getDescription(final CodeList<?> code, Locale locale) {
+        if (code == null) {
+            return null;
+        }
+        if (locale == null) {
+            locale = Locale.US;
+        }
+        /*
+         * The code below is a duplicated - in a different way - of CodeListProxy(CodeList)
+         * constructor (org.apache.sis.internal.jaxb.code package). This duplication exists
+         * because CodeListProxy constructor stores more information in an opportunist way.
+         * If this method is updated, please update CodeListProxy(CodeList) accordingly.
+         */
+        final String key = getListName(code) + '.' + getCodeName(code);
+        try {
+            return ResourceBundle.getBundle("org.opengis.metadata.CodeLists", locale).getString(key);
+        } catch (MissingResourceException e) {
+            Logging.recoverableException(CodeLists.class, "localize", e);
+            return getDescription(code);
+        }
+    }
+
+    /**
+     * Returns all known values for the given type of code list.
+     * Note that the size of the returned array may growth between different invocations
of this method,
+     * since users can add their own codes to an existing list.
+     *
+     * @param <T> The compile-time type given as the {@code codeType} parameter.
+     * @param codeType The type of code list.
+     * @return The list of values for the given code list, or an empty array if none.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends CodeList<?>> T[] values(final Class<T> codeType)
{
+        Object values;
+        try {
+            values = codeType.getMethod("values", (Class<?>[]) null).invoke(null, (Object[])
null);
+        } catch (InvocationTargetException e) {
+            final Throwable cause = e.getCause();
+            if (cause instanceof RuntimeException) {
+                throw (RuntimeException) cause;
+            }
+            if (cause instanceof Error) {
+                throw (Error) cause;
+            }
+            throw new UndeclaredThrowableException(cause);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            values = Array.newInstance(codeType, 0);
+        }
+        return (T[]) values;
+    }
+
+    /**
+     * Returns the code of the given type that matches the given name, or returns a new one
if none
+     * match it. This method performs the same work than the GeoAPI method, except that it
is more
+     * tolerant on string comparisons (see the <a href="#skip-navbar_top">class javadoc</a>).
+     *
+     * @param <T> The compile-time type given as the {@code codeType} parameter.
+     * @param codeType The type of code list.
+     * @param name The name of the code to obtain, or {@code null}.
+     * @return A code matching the given name, or {@code null} if the name is null.
+     *
+     * @see CodeList#valueOf(Class, String)
+     */
+    public static <T extends CodeList<T>> T valueOf(final Class<T> codeType,
final String name) {
+        return valueOf(codeType, name, true);
+    }
+
+    /**
+     * Returns the code of the given type that matches the given name, as described in the
+     * {@link #valueOf(Class, String)} method. If no existing code matches, then this method
+     * creates a new code if {@code canCreate} is {@code true}, or returns {@code null} otherwise.
+     *
+     * @param <T> The compile-time type given as the {@code codeType} parameter.
+     * @param codeType The type of code list.
+     * @param name The name of the code to obtain, or {@code null}.
+     * @param canCreate {@code true} if this method is allowed to create new code.
+     * @return A code matching the given name, or {@code null} if the name is null
+     *         or if no matching code is found and {@code canCreate} is {@code false}.
+     *
+     * @see CodeList#valueOf(Class, String)
+     */
+    public static <T extends CodeList<T>> T valueOf(final Class<T> codeType,
String name, final boolean canCreate) {
+        if (name == null || (name = name.trim()).isEmpty()) {
+            return null;
+        }
+        final String typeName = codeType.getName();
+        try {
+            // Forces initialization of the given class in order
+            // to register its list of static final constants.
+            Class.forName(typeName, true, codeType.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new TypeNotPresentException(typeName, e); // Should never happen.
+        }
+        return CodeList.valueOf(codeType, new CodeListFilter(name, canCreate));
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/CodeLists.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/Types.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/Types.java?rev=1417549&r1=1417548&r2=1417549&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/Types.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/type/Types.java Wed Dec
 5 17:37:18 2012
@@ -61,11 +61,12 @@ public final class Types extends Static 
 
     /**
      * Returns the ISO name for the given class, or {@code null} if none.
+     * This method can be used for GeoAPI interfaces or {@link CodeList}.
      * Examples:
      *
      * <ul>
      *   <li><code>getStandardName({@linkplain org.opengis.metadata.citation.Citation}.class)</code>
  returns {@code "CI_Citation"}.</li>
-     *   <li><code>getStandardName({@linkplain org.opengis.referencing.cs.AxisDirection}.class)</code>
returns {@code "CS_AxisDirection"}. </li>
+     *   <li><code>getStandardName({@linkplain org.opengis.referencing.cs.AxisDirection}.class)</code>
returns {@code "CS_AxisDirection"}.</li>
      * </ul>
      *
      * @param  type The GeoAPI interface from which to get the ISO name, or {@code null}.
@@ -75,7 +76,10 @@ public final class Types extends Static 
         if (type != null) {
             final UML uml = type.getAnnotation(UML.class);
             if (uml != null) {
-                return uml.identifier();
+                final String id = uml.identifier();
+                if (id != null && !id.isEmpty()) {
+                    return id;
+                }
             }
         }
         return null;

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java?rev=1417549&r1=1417548&r2=1417549&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java Wed
Dec  5 17:37:18 2012
@@ -260,8 +260,6 @@ public final strictfp class UnitsTest ex
 
     /**
      * Tests {@link Units#valueOfEPSG(int)}.
-     *
-     * @since 3.20
      */
     @Test
     public void testValueOfEPSG() {

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java?rev=1417549&r1=1417548&r2=1417549&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
(original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
Wed Dec  5 17:37:18 2012
@@ -325,9 +325,9 @@ public final strictfp class CharSequence
      */
     @Test
     public void testIsUpperCase() {
-        assertTrue ("ABC", isUpperCase("ABC"));
-        assertFalse("AbC", isUpperCase("AbC"));
-        assertFalse("A2C", isUpperCase("A2C"));
+        assertTrue ("ABC", isUpperCase("ABC", 0, 3));
+        assertFalse("AbC", isUpperCase("AbC", 0, 3));
+        assertFalse("A2C", isUpperCase("A2C", 0, 3));
     }
 
     /**



Mime
View raw message