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));
}
/**