Author: desruisseaux
Date: Wed Feb 27 23:35:54 2013
New Revision: 1451035
URL: http://svn.apache.org/r1451035
Log:
First draft of metadata PropertyDescriptor.
Added:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
(with props)
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
(with props)
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
Added:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java?rev=1451035&view=auto
==============================================================================
---
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
(added)
+++
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
[UTF-8] Wed Feb 27 23:35:54 2013
@@ -0,0 +1,330 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.lang.reflect.Method;
+import net.jcip.annotations.Immutable;
+import javax.measure.unit.Unit;
+import org.opengis.annotation.UML;
+import org.opengis.util.GenericName;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.referencing.ReferenceIdentifier;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.ValueRange;
+import org.apache.sis.internal.simple.SimpleReferenceIdentifier;
+
+// Related to JDK7
+import java.util.Objects;
+
+
+/**
+ * Description of a metadata property inferred from Java reflection.
+ * For a given metadata instances (typically an {@link AbstractMetadata}
subclasses,
+ * but other types are allowed), instances of {@code PropertyDescriptor} are
obtained
+ * indirectly by the {@link MetadataStandard#asDescriptorMap(Object,
KeyNamePolicy,
+ * NullValuePolicy)} method.
+ *
+ * @param <T> The value type, either the method return type if not a
collection,
+ * or the type of elements in the collection otherwise.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.05)
+ * @version 0.3
+ * @module
+ *
+ * @see MetadataStandard#asDescriptorMap(Object, KeyNamePolicy,
NullValuePolicy)
+ */
+@Immutable
+class PropertyDescriptor<T> extends SimpleReferenceIdentifier implements
ParameterDescriptor<T> {
+ /**
+ * For cross-versions compatibility.
+ */
+ private static final long serialVersionUID = 888961503200860655L;
+
+ /**
+ * ISO name of the interface which contain this property.
+ *
+ * @see #getCodeSpace()
+ */
+ private final String container;
+
+ /**
+ * The value type, either the method return type if not a collection,
+ * or the type of elements in the collection otherwise.
+ *
+ * @see #getValueClass()
+ */
+ private final Class<T> elementType;
+
+ /**
+ * Minimal and maximal occurrences of this property, packed as below:
+ *
+ * <ul>
+ * <li>Rightmost bit encodes the minimal occurrence.</li>
+ * <li>All other bits encode the maximal occurrence.</li>
+ * </ul>
+ *
+ * @see #getMinimumOccurs()
+ * @see #getMaximumOccurs()
+ */
+ private final byte cardinality;
+
+ /**
+ * Specialization of {@link PropertyDescriptor} when the range of legal
values is
+ * specified by a {@link ValueRange} annotation. Those values must be
numeric.
+ *
+ * <p>Bounded properties are represented by a different class because the
requirement
+ * for numerical values put additional constraints on the {@code <T>}
parameterized type,
+ * and because bounded properties are relatively rare so we can avoid to
carry a null
+ * range fields for the properties that don't need it.</p>
+ *
+ * @param <T> The numeric value type.
+ */
+ static final class Bounded<T extends Number & Comparable<T>> extends
PropertyDescriptor<T> {
+ /** For cross versions compatibility. */
+ private static final long serialVersionUID = 7869130373802184834L;
+
+ /** The range of valid values. */
+ private final NumberRange<T> range;
+
+ /** Creates a new descriptor for the given range of values. */
+ Bounded(final String container, final Class<T> type, final Citation
standard,
+ final String property, final Method getter, final ValueRange
range)
+ {
+ super(container, type, standard, property, getter);
+ this.range = new NumberRange<>(type, range);
+ }
+
+ /** Returns the minimum parameter value, assumed inclusive. */
+ @Override
+ public Comparable<T> getMinimumValue() {
+ return range.getMinValue();
+ }
+
+ /** Returns the maximum parameter value, assumed inclusive. */
+ @Override
+ public Comparable<T> getMaximumValue() {
+ return range.getMaxValue();
+ }
+
+ /** Compares the given object for equality. */
+ @Override
+ public boolean equals(final Object obj) {
+ if (super.equals(obj)) {
+ return Objects.equals(range, ((Bounded) obj).range);
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Creates a new {@code PropertyDescriptor} instance from the annotations
on the given
+ * getter method. If there is no restriction, then this method returns
{@code null}.
+ *
+ * @param container ISO name of the interface which contain this
property.
+ * @param elementType The value type, either the method return type if
not a collection,
+ * or the type of elements in the collection otherwise.
+ * @param standard The international standard that define the
property, or {@code null} if none.
+ * @param property The property name as defined by the international
{@linkplain #standard}.
+ * @param getter The getter method defined in the interface.
+ */
+ @SuppressWarnings({"unchecked","rawtypes"})
+ PropertyDescriptor(final String container, final Class<T> elementType,
+ final Citation standard, final String property, final Method
getter)
+ {
+ super(standard, property);
+ this.container = container;
+ this.elementType = elementType;
+ final UML uml = getter.getAnnotation(UML.class);
+ byte cardinality = 2;
+ if (uml != null) {
+ switch (uml.obligation()) {
+ case MANDATORY: cardinality = 3; break; // minOccurs =
1, maxOccurs = 1;
+ case FORBIDDEN: this.cardinality = 0; return; // minOccurs =
0, maxOccurs = 0;
+ }
+ }
+ final Class<?> c = getter.getReturnType();
+ if (c.isArray() || Collection.class.isAssignableFrom(c)) {
+ cardinality |= 0xFE; // Set all bits except the rightmost one,
which is left unchanged.
+ }
+ this.cardinality = cardinality;
+ }
+
+ /**
+ * Returns the primary name by which this object is identified.
+ * This is fixed to {@code this} for more efficient storage of
+ * potentially large amount of {@code PropertyDescriptor}s.
+ *
+ * <p>Users invoke this method in order to get access to the {@link
#getCode()},
+ * {@link #getCodeSpace()}, {@link #getVersion()} and {@link
#getAuthority()} methods.</p>
+ */
+ @Override
+ public final ReferenceIdentifier getName() {
+ return this;
+ }
+
+ /**
+ * Returns the code space of the property name.
+ */
+ @Override
+ public final String getCodeSpace() {
+ return container;
+ }
+
+ /**
+ * An identifier which references elsewhere the object's defining
information.
+ * The current implementation returns an empty set.
+ */
+ @Override
+ public final Set<ReferenceIdentifier> getIdentifiers() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * An alternative name by which this object is identified.
+ * The current implementation returns an empty set.
+ * Future implementation may return the JavaBeans property name.
+ */
+ @Override
+ public final Collection<GenericName> getAlias() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * Comments about this property, or {@code null} if none.
+ */
+ @Override
+ public InternationalString getRemarks() {
+ return null; // TODO use Types.getDescription
+ }
+
+ /**
+ * Returns the class that describe the type of the parameter.
+ * This is the type given at construction time.
+ */
+ @Override
+ public final Class<T> getValueClass() {
+ return elementType;
+ }
+
+ /**
+ * Returns the default value for the parameter, or {@code null} if none.
+ * Current implementation unconditionally return {@code null}.
+ */
+ @Override
+ public T getDefaultValue() {
+ return null;
+ }
+
+ /**
+ * Returns the minimum parameter value, or {@code null} if none.
+ * The {@link ValueRange#minimum()} value is assumed inclusive
+ * (this is not verified).
+ */
+ @Override
+ public Comparable<T> getMinimumValue() {
+ return null;
+ }
+
+ /**
+ * Returns the minimum parameter value, or {@code null} if none.
+ * The {@link ValueRange#maximum()} value is assumed inclusive
+ * (this is not verified).
+ */
+ @Override
+ public Comparable<T> getMaximumValue() {
+ return null;
+ }
+
+ /**
+ * Returns the set of allowed values when these are restricted to some
finite set.
+ * The default implementation returns {@code null} since there is no
restriction even
+ * on code list (we can not return the set of all code list elements since
this list
+ * may growth at runtime).
+ *
+ * However if we want to restrict the set of applicable code list values,
we can do
+ * that here using {@link org.apache.sis.util.collection.CodeListSet}.
+ */
+ @Override
+ public Set<T> getValidValues() {
+ return null;
+ }
+
+ /**
+ * Returns the unit of measurement. The current implementation returns
{@code null}.
+ */
+ @Override
+ public Unit<?> getUnit() {
+ return null;
+ }
+
+ /**
+ * The minimum number of times that values for this parameter group or
+ * parameter are required.
+ */
+ @Override
+ public int getMinimumOccurs() {
+ return cardinality & 1;
+ }
+
+ /**
+ * The maximum number of times that values for this parameter group or
+ * parameter are required.
+ */
+ @Override
+ public int getMaximumOccurs() {
+ return ((int) cardinality) >>> 1;
+ }
+
+ @Override
+ public ParameterValue<T> createValue() {
+ throw new UnsupportedOperationException("Not supported yet."); //To
change body of generated methods, choose Tools | Templates.
+ }
+
+ /**
+ * Compares the given object with this descriptor for equality.
+ *
+ * @param obj The object to compare with this descriptor for equality.
+ * @return {@code true} if both objects are equal.
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (super.equals(obj)) {
+ final PropertyDescriptor<?> that = (PropertyDescriptor<?>) obj;
+ return (this.cardinality == that.cardinality) &&
+ Objects.equals(this.container, that.container) &&
+ Objects.equals(this.elementType, that.elementType);
+ }
+ return false;
+ }
+
+ /**
+ * Computes a hash code value only from the code space and property name.
+ * We don't need to use the other properties, because the fully qualified
+ * property name should be a sufficient discriminator.
+ */
+ @Override
+ public final int hashCode() {
+ return (container.hashCode() + 31 * code.hashCode()) ^ (int)
serialVersionUID;
+ }
+}
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyDescriptor.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java?rev=1451035&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
[UTF-8] Wed Feb 27 23:35:54 2013
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.simple;
+
+import java.io.Serializable;
+import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.citation.Citation;
+import org.apache.sis.internal.util.Citations;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Classes;
+
+// Related to JDK7
+import java.util.Objects;
+
+
+/**
+ * An implementation of {@link ReferenceIdentifier} as a wrapper around a
{@link Citation}.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+public class SimpleReferenceIdentifier implements ReferenceIdentifier,
Serializable {
+ /**
+ * For cross-version compatibility.
+ */
+ private static final long serialVersionUID = -2838613660030835519L;
+
+ /**
+ * Organization or party responsible for definition and maintenance of the
+ * {@linkplain #code}, or {@code null} if none.
+ *
+ * @see #getAuthority()
+ * @see #getCodeSpace()
+ * @see #getVersion()
+ */
+ protected final Citation authority;
+
+ /**
+ * The property name as defined by the international {@linkplain
#authority}.
+ *
+ * @see #getCode()
+ */
+ protected final String code;
+
+ /**
+ * Creates a new reference identifier.
+ *
+ * @param authority Responsible party for definition and maintenance of
the code, or null.
+ * @param code Alphanumeric value identifying an instance in the namespace.
+ */
+ public SimpleReferenceIdentifier(final Citation authority, final String
code) {
+ this.authority = authority;
+ this.code = code;
+ }
+
+ /**
+ * Organization or party responsible for definition and maintenance of the
+ * {@linkplain #getCode() code}, or {@code null} if none.
+ */
+ @Override
+ public Citation getAuthority() {
+ return authority;
+ }
+
+ /**
+ * Returns the shortest identifier of the {@linkplain #getAuthority()
authority}.
+ * May be {@code null}.
+ */
+ @Override
+ public String getCodeSpace() {
+ return Citations.getIdentifier(authority);
+ }
+
+ /**
+ * Alphanumeric value identifying an instance in the namespace.
+ * This is defined by the international standard given by {@link
#getAuthority()}.
+ */
+ @Override
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * Version identifier for the namespace, as specified by the code
authority.
+ * When appropriate, the edition is identified by the effective date, coded
+ * using ISO 8601 date format.
+ */
+ @Override
+ public String getVersion() {
+ if (authority != null) {
+ final InternationalString version = authority.getEdition();
+ if (version != null) {
+ return version.toString();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if the given object is of the same class than this
+ * {@code SimpleReferenceIdentifier} and has the same values.
+ *
+ * @param obj The object to compare with this {@code
SimpleReferenceIdentifier} for equality.
+ * @return {@code true} if both objects are equal.
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj != null && obj.getClass() == getClass()) {
+ final SimpleReferenceIdentifier that = (SimpleReferenceIdentifier)
obj;
+ return Objects.equals(code, that.code) &&
Objects.equals(authority, that.authority);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a hash code value for this identifier.
+ *
+ * @return A hash code value for this identifier.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(authority, code);
+ }
+
+ /**
+ * Returns a string representation of this identifier.
+ */
+ @Override
+ public String toString() {
+ final String classname = Classes.getShortClassName(this);
+ final StringBuilder buffer = new StringBuilder(classname.length() +
CharSequences.length(code) + 10);
+ buffer.append(classname).append('[');
+ final String codespace = getCodeSpace(); // Subclasses may have
overridden this method.
+ boolean open = false;
+ if (codespace != null) {
+ buffer.append('“').append(codespace);
+ open = true;
+ }
+ if (code != null) {
+ buffer.append(open ? '.' : '“').append(code);
+ open = true;
+ }
+ if (open) {
+ buffer.append('”');
+ }
+ return buffer.append(']').toString();
+ }
+
+ /**
+ * Returns a pseudo Well Known Text for this identifier.
+ *
+ * @return Pseudo Well Known Text for this identifier.
+ */
+ public String toWKT() {
+ final StringBuilder buffer = new
StringBuilder(40).append("AUTHORITY[");
+ append(buffer, Citations.getIdentifier(authority)); // Do not invoke
getCodeSpace().
+ append(buffer.append(','), code);
+ return buffer.append(']').toString();
+ }
+
+ /**
+ * Appends the given value in the given buffer between quotes, except if
the
+ * given value is null in which case {@code null} is appended without
quotes.
+ */
+ private static void append(final StringBuilder buffer, final String value)
{
+ if (value == null) {
+ buffer.append("null");
+ } else {
+ buffer.append('"').append(value).append('"');
+ }
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/simple/SimpleReferenceIdentifier.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1451035&r1=1451034&r2=1451035&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
[UTF-8] Wed Feb 27 23:35:54 2013
@@ -226,7 +226,7 @@ public final class Types extends Static
* </ul>
*
* @param code The code for which to get the localized name, or {@code
null}.
- * @param locale The local, or {@code null} if none.
+ * @param locale The locale, or {@code null} if none.
* @return The localized title, or {@code null} if the given code is null.
*
* @see #getDescription(CodeList, Locale)
@@ -272,7 +272,7 @@ public final class Types extends Static
* see {@link Types#getDescription(Class, Locale)}.
*
* @param code The code for which to get the localized description, or
{@code null}.
- * @param locale The desired local, or {@code null} for the default
locale.
+ * @param locale The desired locale, or {@code null} for the default
locale.
* @return The localized description, or {@code null} if the given code is
null.
*
* @see #getCodeTitle(CodeList, Locale)
@@ -288,7 +288,7 @@ public final class Types extends Static
* Special cases:
*
* <ul>
- * <li>If {@code code} is {@code null}, then this method returns {@code
null}.</li>
+ * <li>If {@code type} is {@code null}, then this method returns {@code
null}.</li>
* <li>If {@code locale} is {@code null}, then this method uses the
* {@linkplain Locale#getDefault() default locale} - there is no
such thing
* like "unlocalized" description.</li>
@@ -299,8 +299,8 @@ public final class Types extends Static
* </ul>
*
* @param type The GeoAPI interface or code list from which to get the
description, or {@code null}.
- * @param locale The desired local, or {@code null} for the default
locale.
- * @return The ISO name for the given type, or {@code null} if none or if
the type is {@code null}.
+ * @param locale The desired locale, or {@code null} for the default
locale.
+ * @return The localized description, or {@code null} if none or if the
given type is {@code null}.
*
* @see #getDescription(CodeList, Locale)
*/
@@ -309,6 +309,38 @@ public final class Types extends Static
}
/**
+ * Returns a localized description for the given property, or {@code null}
if none.
+ * The given property name shall be a UML identifier.
+ * Special cases:
+ *
+ * <ul>
+ * <li>If {@code type} or {@code property} is {@code null}, then this
method returns {@code null}.</li>
+ * <li>If {@code locale} is {@code null}, then this method uses the
+ * {@linkplain Locale#getDefault() default locale} - there is no
such thing
+ * like "unlocalized" description.</li>
+ * <li>If there is no resources for the given property in the given
language, then this method
+ * fallback on other languages as described in {@link
ResourceBundle} javadoc.</li>
+ * <li>If there is no localized resources for the given property, then
this method returns
+ * {@code null} - there is no fallback.</li>
+ * </ul>
+ *
+ * @param type The GeoAPI interface from which to get the description
of a property, or {@code null}.
+ * @param property The ISO name of the property for which to get the
description, or {@code null}.
+ * @param locale The desired locale, or {@code null} for the default
locale.
+ * @return The localized description, or {@code null} if none or if the
given type
+ * or property name is {@code null}.
+ */
+ public static String getDescription(final Class<?> type, final String
property, final Locale locale) {
+ if (property != null) {
+ final String name = getStandardName(type);
+ if (name != null) {
+ return getDescription(name + '.' + property, locale);
+ }
+ }
+ return null;
+ }
+
+ /**
* Returns the descriptions for the given key in the given locale.
*
* @param key The ISO identifier of a class, or a class property, or
a code list value.
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java?rev=1451035&r1=1451034&r2=1451035&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
[UTF-8] (original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
[UTF-8] Wed Feb 27 23:35:54 2013
@@ -20,6 +20,7 @@ import java.util.Set;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
+import org.opengis.metadata.citation.Address;
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.citation.OnLineFunction;
import org.opengis.metadata.content.ImagingCondition;
@@ -89,6 +90,17 @@ public final strictfp class TypesTest ex
}
/**
+ * Tests the {@link Types#getDescription(Class, String, Locale)} method.
+ */
+ @Test
+ public void testGetPropertyDescription() {
+ assertEquals("The city of the location.",
+ Types.getDescription(Address.class, "city", Locale.ROOT));
+ assertEquals("Country of the physical address.",
+ Types.getDescription(Address.class, "country",
Locale.ENGLISH));
+ }
+
+ /**
* Tests the {@link Types#getDescription(CodeList, Locale)} method.
*/
@Test