All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.metadata.ValueRestriction Maven / Gradle / Ivy

Go to download

Implementations of metadata derived from ISO 19115. This module provides both an implementation of the metadata interfaces defined in GeoAPI, and a framework for handling those metadata through Java reflection.

There is a newer version: 3.20-geoapi-3.0
Show newest version
/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2009-2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2011, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.geotoolkit.metadata;

import java.util.Set;
import java.io.Serializable;
import java.lang.reflect.Method;
import net.jcip.annotations.Immutable;

import org.opengis.annotation.UML;
import org.opengis.annotation.Obligation;

import org.geotoolkit.util.Utilities;
import org.geotoolkit.util.NumberRange;
import org.geotoolkit.util.converter.Classes;
import org.geotoolkit.util.collection.WeakHashSet;
import org.geotoolkit.lang.ValueRange;
import org.geotoolkit.resources.Errors;


/**
 * Restrictions that apply on a metadata property. Instances of {@code ValueRestriction}
 * are created only for properties having at least one non-null {@linkplain #obligation},
 * {@linkplain #range} or {@linkplain #validValues valid values enumeration} restriction.
 * 

* For a given metadata instances (typically an {@link AbstractMetadata} subclasses, but * other types are allowed), instances of {@code ValueRestriction} are obtained indirectly * by the {@link MetadataStandard#asRestrictionMap MetadataStandard.asRestrictionMap(...)} * method. *

* {@code ValueRestriction} objects do not contain the type of values * (except indirectly through {@link NumberRange#getElementClass()} or * {@link org.geotoolkit.util.collection.CheckedCollection#getElementType()}) * because this particular requirement is specified by other means, like * {@link MetadataStandard#asTypeMap MetadataStandard.asTypeMap(...)}. * * @author Martin Desruisseaux (Geomatys) * @version 3.05 * * @see MetadataStandard#asRestrictionMap(Object, NullValuePolicy, KeyNamePolicy) * * @since 3.04 * @module */ @Immutable public class ValueRestriction implements Serializable { /** * For cross-versions compatibility. */ private static final long serialVersionUID = 888961503200860655L; /** * A sentinel value meaning that the restriction has not yet been calculated. */ static final ValueRestriction PENDING = new ValueRestriction(null, null, null); /** * The instances created in this JVM. In many case, the same restriction will be shared * by many attributes (e.g. restricting the range of values to 0 .. 100 for percentage). */ private static final WeakHashSet POOL = WeakHashSet.newInstance(ValueRestriction.class); /** * Whatever the property is {@linkplain Obligation#MANDATORY mandatory} or * {@linkplain Obligation#FORBIDDEN forbidden}, or {@code null} if there is * no known restriction. *

* The {@linkplain Obligation#OPTIONAL optional} obligation is considered * equivalent to an absence of restriction and is replaced by {@code null} * if {@link MetadataStandard#asRestrictionMap MetadataStandard.asRestrictionMap(...)} * has been invoked with a metadata instance, since the metadata is not violating this * obligation. If {@code asRestrictionMap(...)} has been invoked with a {@link Class} * argument instead, then the obligation is provided verbatism since we are not testing * violation of restrictions. */ public final Obligation obligation; /** * The range of valid values, or {@code null} if the values are not restricted by a range. * This restriction is typically exclusive with the {@linkplain #validValues enumeration * of valid values} (i.e. only one of {@code range} or {@code validValues} is non-null), * but this is not enforced by this {@code ValueRestriction} class. */ public final NumberRange range; /** * An enumeration of valid values, or {@code null} if the values are not restricted that way. * This restriction is typically exclusive with the {@linkplain #range range of valid values} * (i.e. only one of {@code range} or {@code validValues} is non-null), but this is not * enforced by this {@code ValueRestriction} class. * * @since 3.05 */ public final Set validValues; /** * Creates a new {@code Restriction} instance. This constructor does not clone any * argument; this is caller responsibility to provide immutable instance of them, * especially {@code validValues}. * * {@note This constructor is not public in order to force subclassing. Subclasses * shall choose a policy regarding whatever the arguments are cloned. This * base class does not clone them because the same set of valid values (for * example) is often shared for many metdata attributes.} * * @param obligation Whatever the property is mandatory or forbidden, or {@code null} if unknown. * @param range The range of valid values, or {@code null} if none. * @param validValues An enumeration of valid values, or {@code null} if none. * * @since 3.05 */ protected ValueRestriction(final Obligation obligation, final NumberRange range, final Set validValues) { this.obligation = obligation; this.range = range; this.validValues = validValues; } /** * Creates a new {@code ValueRestriction} instance. If all arguments are {@code null}, * then this method returns {@code null} meaning "no restriction". * * @param obligation Whatever the property is mandatory or forbidden, or {@code null} if unknown. * @param range The range of valid values, or {@code null} if none. * @param validValues An enumeration of valid values, or {@code null} if none. * @return The restriction, or {@code null} if none. */ static ValueRestriction create(final Obligation obligation, final NumberRange range, final Set validValues) { if (range == null && validValues == null && obligation != Obligation.MANDATORY && obligation != Obligation.FORBIDDEN) { return null; } return POOL.unique(new ValueRestriction(obligation, range, validValues)); } /** * Creates a new {@code ValueRestriction} instance from the annotations on the given * getter method. If there is no restriction, then this method returns {@code null}. * * @param type The return type if it is not a collection, or the type of elements * if the return type is a collection. * @param getter The getter method defined in the interface. * @param impl The getter method defined in the implementation. * @return The restriction, or {@code null} if none. */ @SuppressWarnings({"unchecked","rawtypes"}) static ValueRestriction create(final Class type, Method getter, final Method impl) { Obligation obligation = null; NumberRange range = null; final UML uml = getter.getAnnotation(UML.class); while (true) { if (uml != null) { obligation = uml.obligation(); } final ValueRange vr = getter.getAnnotation(ValueRange.class); if (vr != null) { Class required; if ((required = Number.class).isAssignableFrom(type) && (required = Comparable.class).isAssignableFrom(type)) { range = new NumberRange((Class) type, vr); } else { throw new ClassCastException(Errors.format(Errors.Keys.ILLEGAL_CLASS_$2, type, required)); } } if (getter == impl) { break; } getter = impl; } return create(obligation, range, null); } /** * If the given value violate at least one restriction, returns the restrictions * that are violated. Otherwise returns {@code null}. * * @param value The value to test (may be {@code null}). * @return {@code null} if the given value does not violate the restrictions. */ final ValueRestriction violation(final Object value) { Obligation obligation = this.obligation; NumberRange range = this.range; Set validValues = this.validValues; boolean changed = false; /* * If the value does not violate the obligation, set the obligation to null. */ if (obligation != ((value == null) ? Obligation.MANDATORY : Obligation.FORBIDDEN)) { obligation = null; changed = true; } /* * If the value is not outside the range, set the range to null. */ if (value == null || range == null || (value instanceof Number && range.contains((Number) value))) { range = null; changed = true; } /* * If the value is a member of the set of valid values, set the valid values to null. */ if (value == null || validValues == null || validValues.contains(value)) { validValues = null; changed = true; } return changed ? create(obligation, range, validValues) : this; } /** * Compares the given object with this restriction for equality. * * @param other The object to compare with this restriction for equality. * @return {@code true} if both objects are equal. */ @Override public boolean equals(final Object other) { if (other != null && other.getClass() == getClass()) { final ValueRestriction that = (ValueRestriction) other; return (this.obligation == that.obligation) && Utilities.equals(this.range, that.range) && Utilities.equals(this.validValues, that.validValues); } return false; } /** * Returns a hash code value for this restriction. */ @Override public int hashCode() { int code = (int) serialVersionUID; if (obligation != null) { code ^= obligation.hashCode(); } if (range != null) { code ^= range.hashCode(); } if (validValues != null) { code ^= validValues.hashCode(); } return code; } /** * Returns a string representation of this restriction. */ @Override public String toString() { final StringBuilder buffer = new StringBuilder(Classes.getShortClassName(this)).append('['); String separator = ""; if (obligation != null) { buffer.append(obligation.name()); separator = ", "; } if (range != null) { buffer.append(separator).append("range=").append(range); separator = ", "; } if (validValues != null) { buffer.append(separator).append("validValues=").append(validValues); } return buffer.append(']').toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy