Search in sources :

Example 1 with CorruptedObjectException

use of org.apache.sis.util.CorruptedObjectException in project sis by apache.

the class MovingFeature method storeGeometry.

/**
 * Sets the geometry of the given attribute to the values collected by this {@code MovingFeatures}.
 * This method sets also the {@code "datetimes"} characteristic.
 *
 * @param  <G>              the type of the geometry value.
 * @param  featureName      the name of the feature containing the attribute to update, for logging purpose.
 * @param  index            index of the property for which geometry value is desired.
 * @param  dimension        number of dimensions for all coordinates.
 * @param  factory          the factory to use for creating the geometry object.
 * @param  dest             attribute where to store the geometry value.
 * @param  warningListener  where to report warnings. Implementation should set the source class name,
 *                          source method name and logger name, then forward to a {@code WarningListener}.
 */
public final <G> void storeGeometry(final String featureName, final int index, final int dimension, final Geometries<G> factory, final AbstractAttribute<G> dest, final Consumer<LogRecord> warningListener) {
    int n = count[index];
    final Vector[] vectors = new Vector[n];
    for (Period p = properties[index]; p != null; p = p.previous) {
        vectors[--n] = Vector.create(p.value, false);
    }
    if (n != 0) {
        // Should never happen unless this object has been modified concurrently in another thread.
        throw new CorruptedObjectException();
    }
    // Maximal number of warnings, for avoiding to flood the logger.
    int warnings = 10;
    // Total number of points in all vectors, ignoring null vectors.
    int numPts = 0;
    // If non-null, shall be non-empty.
    Vector previous = null;
    for (int i = 0; i < vectors.length; i++) {
        Vector v = vectors[i];
        int length;
        if (v == null || (length = v.size()) == 0) {
            continue;
        }
        if ((length % dimension) != 0) {
            if (--warnings >= 0) {
                Period p = properties[index];
                for (int j = i; --j >= 0; ) {
                    // This is inefficient but used only in case of warnings.
                    p = p.previous;
                }
                warningListener.accept(Resources.forLocale(null).getLogRecord(Level.WARNING, Resources.Keys.UnexpectedNumberOfOrdinates_4, featureName, new Date(p.startTime), dimension, length));
            }
            continue;
        }
        /*
             * At this point we have a non-empty valid sequence of ordinate values. If the first point of current
             * vector is equals to the last point of previous vector, assume that they form a continuous polyline.
             */
        if (previous != null) {
            if (equals(previous, v, dimension)) {
                // Skip the first coordinate.
                v = v.subList(dimension, length);
                length -= dimension;
                if (length == 0) {
                    vectors[i] = null;
                    continue;
                }
                vectors[i] = v;
            }
        }
        numPts += length;
        previous = v;
    }
    /*
         * At this point we got the list of all coordinates to join together in a polyline.
         * We will create the geometry at the end of this method. Before that, interpolate
         * the dates and times.
         */
    int i = vectors.length;
    numPts /= dimension;
    final long[] times = new long[numPts];
    for (Period p = properties[index]; p != null; p = p.previous) {
        final Vector v = vectors[--i];
        if (v != null) {
            int c = v.size() / dimension;
            if (c == 1) {
                times[--numPts] = p.endTime;
            } else {
                final long startTime = p.startTime;
                final double scale = (p.endTime - startTime) / (double) (c - 1);
                while (--c >= 0) {
                    times[--numPts] = startTime + Math.round(scale * c);
                }
            }
        }
    }
    if (numPts != 0) {
        // Should never happen unless this object has been modified concurrently in another thread.
        throw new CorruptedObjectException();
    }
    /*
         * Store the geometry and characteristics in the attribute.
         */
    dest.setValue(factory.createPolyline(dimension, vectors));
    final AbstractAttribute<Instant> c = TIME.newInstance();
    c.setValues(new DateList(times));
    dest.characteristics().values().add(c);
}
Also used : Instant(java.time.Instant) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) Vector(org.apache.sis.math.Vector) Date(java.util.Date)

Example 2 with CorruptedObjectException

use of org.apache.sis.util.CorruptedObjectException in project sis by apache.

the class FeatureTypeBuilder method build.

/**
 * Builds the feature type from the information and properties specified to this builder.
 * One of the {@code setName(…)} methods must have been invoked before this {@code build()} method (mandatory).
 * All other methods are optional, but some calls to a {@code add} method are usually needed.
 *
 * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed to the
 * {@code org.opengis.feature.FeatureType} interface. This change is pending GeoAPI revision.</div>
 *
 * <p>If a feature type has already been built and this builder state has not changed since the
 * feature type creation, then the previously created {@code FeatureType} instance is returned.</p>
 *
 * @return the feature type.
 * @throws IllegalStateException if the builder contains inconsistent information.
 *
 * @see #clear()
 */
@Override
public DefaultFeatureType build() throws IllegalStateException {
    if (feature == null) {
        /*
             * Creates an initial array of property types with up to 3 slots reserved for sis:identifier, sis:geometry
             * and sis:envelope operations. At first we presume that there is always an identifier. The identifier slot
             * will be removed later if there is none.
             */
        // Number of explicitely specified properties.
        final int numSpecified = properties.size();
        // Number of synthetic properties that may be generated.
        int numSynthetic;
        int envelopeIndex = -1;
        int geometryIndex = -1;
        final AbstractIdentifiedType[] identifierTypes;
        if (identifierCount == 0) {
            numSynthetic = 0;
            identifierTypes = null;
        } else {
            numSynthetic = 1;
            identifierTypes = new AbstractIdentifiedType[identifierCount];
        }
        if (defaultGeometry != null) {
            envelopeIndex = numSynthetic++;
            if (!AttributeConvention.GEOMETRY_PROPERTY.equals(defaultGeometry.getName())) {
                geometryIndex = numSynthetic++;
            }
        }
        final AbstractIdentifiedType[] propertyTypes = new AbstractIdentifiedType[numSynthetic + numSpecified];
        int propertyCursor = numSynthetic;
        int identifierCursor = 0;
        for (int i = 0; i < numSpecified; i++) {
            final PropertyTypeBuilder builder = properties.get(i);
            final AbstractIdentifiedType instance = builder.build();
            propertyTypes[propertyCursor] = instance;
            /*
                 * Collect the attributes to use as identifier components while we loop over all properties.
                 * A NullPointerException or an ArrayIndexOutOfBoundsException in this block would mean that
                 * identifierCount field has not been updated correctly by an addRole(AttributeRole) method.
                 */
            if (builder.isIdentifier()) {
                identifierTypes[identifierCursor++] = instance;
            }
            /*
                 * If there is a default geometry, add a link named "sis:geometry" to that geometry.
                 * It may happen that the property created by the user is already named "sis:geometry",
                 * in which case we will avoid to duplicate the property.
                 */
            if (builder == defaultGeometry && geometryIndex >= 0) {
                if (propertyTypes[geometryIndex] != null) {
                    /*
                         * Assuming that there is no bug in our implementation, this error could happen if the user
                         * has modified this FeatureTypeBuilder in another thread during this build() execution.
                         */
                    throw new CorruptedObjectException();
                }
                propertyTypes[geometryIndex] = FeatureOperations.link(name(AttributeConvention.GEOMETRY_PROPERTY), instance);
            }
            propertyCursor++;
        }
        /*
             * Create the "envelope" operation only after we created all other properties.
             * Actually it is okay if the 'propertyTypes' array still contains null elements not needed for envelope calculation
             * like "sis:identifier", since FeatureOperations.envelope(…) constructor ignores any property which is not for a value.
             */
        if (envelopeIndex >= 0)
            try {
                propertyTypes[envelopeIndex] = FeatureOperations.envelope(name(AttributeConvention.ENVELOPE_PROPERTY), null, propertyTypes);
            } catch (FactoryException e) {
                throw new IllegalStateException(e);
            }
        /*
             * If a synthetic identifier need to be created, create it now as the first property.
             * It may happen that the user provided a single identifier component already named
             * "sis:identifier", in which case we avoid to duplicate the property.
             */
        if (identifierTypes != null) {
            if (identifierCursor != identifierTypes.length) {
                /*
                     * Assuming that there is no bug in our implementation, this error could happen if the user
                     * has modified this FeatureTypeBuilder in another thread during this build() execution.
                     */
                throw new CorruptedObjectException();
            }
            if (AttributeConvention.IDENTIFIER_PROPERTY.equals(identifierTypes[0].getName())) {
                if (identifierCursor > 1) {
                    throw new IllegalStateException(Resources.format(Resources.Keys.PropertyAlreadyExists_2, getDisplayName(), AttributeConvention.IDENTIFIER_PROPERTY));
                }
                System.arraycopy(propertyTypes, 1, propertyTypes, 0, --propertyCursor);
            } else {
                propertyTypes[0] = FeatureOperations.compound(name(AttributeConvention.IDENTIFIER_PROPERTY), idDelimiter, idPrefix, idSuffix, identifierTypes);
            }
        }
        feature = new DefaultFeatureType(identification(), isAbstract(), superTypes.toArray(new DefaultFeatureType[superTypes.size()]), ArraysExt.resize(propertyTypes, propertyCursor));
    }
    return feature;
}
Also used : FactoryException(org.opengis.util.FactoryException) DefaultFeatureType(org.apache.sis.feature.DefaultFeatureType) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) AbstractIdentifiedType(org.apache.sis.feature.AbstractIdentifiedType)

Example 3 with CorruptedObjectException

use of org.apache.sis.util.CorruptedObjectException in project sis by apache.

the class SparseFeature method setPropertyValue.

/**
 * Sets the value for the property of the given name.
 *
 * @param  name   the attribute name.
 * @param  value  the new value for the given attribute (may be {@code null}).
 * @throws ClassCastException if the value is not assignable to the expected value class.
 * @throws IllegalArgumentException if the given value can not be assigned for another reason.
 */
@Override
public void setPropertyValue(final String name, final Object value) throws IllegalArgumentException {
    ArgumentChecks.ensureNonNull("name", name);
    final Integer index = getIndex(name);
    if (index < 0) {
        setOperationValue(name, value);
        return;
    }
    if (valuesKind == VALUES) {
        final Object previous = properties.put(index, value);
        /*
             * Slight optimization:  if we replaced a previous value of the same class, then we can skip the
             * checks for name and type validity since those checks have been done previously. But if we add
             * a new value or a value of a different type, then we need to check the name and type validity.
             */
        if (!canSkipVerification(previous, value)) {
            // This initial value will restore the previous value if the check fail.
            Object toStore = previous;
            try {
                toStore = verifyPropertyValue(name, value);
            } finally {
                if (toStore != value) {
                    replace(index, value, toStore);
                }
            }
        }
    } else if (valuesKind == PROPERTIES) {
        setPropertyValue(getPropertyInstance(name), value);
    } else {
        throw new CorruptedObjectException(getName());
    }
}
Also used : CorruptedObjectException(org.apache.sis.util.CorruptedObjectException)

Example 4 with CorruptedObjectException

use of org.apache.sis.util.CorruptedObjectException in project sis by apache.

the class SparseFeature method getPropertyValue.

/**
 * Returns the value for the property of the given name.
 *
 * @param  name  the property name.
 * @return the value for the given property, or {@code null} if none.
 * @throws IllegalArgumentException if the given argument is not an attribute or association name of this feature.
 */
@Override
public Object getPropertyValue(final String name) throws IllegalArgumentException {
    ArgumentChecks.ensureNonNull("name", name);
    final Integer index = getIndex(name);
    if (index < 0) {
        return getOperationValue(name);
    }
    final Object element = properties.get(index);
    if (element != null) {
        if (valuesKind == VALUES) {
            // Most common case.
            return element;
        } else if (element instanceof AbstractAttribute<?>) {
            return getAttributeValue((AbstractAttribute<?>) element);
        } else if (element instanceof AbstractAssociation) {
            return getAssociationValue((AbstractAssociation) element);
        } else if (valuesKind == PROPERTIES) {
            throw new IllegalArgumentException(unsupportedPropertyType(((Property) element).getName()));
        } else {
            throw new CorruptedObjectException(getName());
        }
    } else if (properties.containsKey(index)) {
        // Null has been explicitely set.
        return null;
    } else {
        return getDefaultValue(name);
    }
}
Also used : CorruptedObjectException(org.apache.sis.util.CorruptedObjectException)

Example 5 with CorruptedObjectException

use of org.apache.sis.util.CorruptedObjectException in project sis by apache.

the class CC_OperationParameterGroup method merge.

/**
 * Invoked by {@link DefaultParameterDescriptorGroup#setDescriptors(GeneralParameterDescriptor[])}
 * for merging into a single set the descriptors which are repeated twice in a GML document.
 *
 * <p>The {@code descriptors} argument gives the descriptors listed explicitely inside a
 * {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>} element. Those
 * descriptors are said "incomplete" (from SIS point of view) because they are missing the
 * {@link ParameterDescriptor#getValueClass()} property, which does not exist in GML but
 * is mandatory for us. However an exception to this "incompleteness" happen when SIS has
 * been able to match the {@code <gml:OperationMethod>} parent to one of the pre-defined
 * operations in the {@link org.apache.sis.internal.referencing.provider} package.</p>
 *
 * <p>The {@code fromValues} argument gives the descriptors declared in each {@code <gml:ParameterValue>}
 * instances of a {@code <gml:ParameterValueGroup>} or {@code <gml:AbstractSingleOperation>} element.
 * Contrarily to the {@code descriptors} argument, the {@code fromValues} instances should have non-null
 * {@link ParameterDescriptor#getValueClass()} property inferred by SIS from the parameter value.</p>
 *
 * <p>So the preferred descriptors from more complete to less complete are:</p>
 * <ol>
 *   <li>{@code descriptors} if and only if they contain pre-defined parameters inferred by SIS from the {@code <gml:OperationMethod>} name.</li>
 *   <li>{@code fromValues}, which contain the descriptors declared in the {@code <gml:ParameterValue>} instances.</li>
 *   <li>{@code descriptors}, which contain the descriptor listed in {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>}.</li>
 * </ol>
 *
 * <div class="note"><b>Note:</b>
 * this code is defined in this {@code CC_OperationParameterGroup} class instead than in the
 * {@link DefaultParameterDescriptorGroup} class in the hope to reduce the amount of code
 * processed by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
 *
 * @param  descriptors   the descriptors declared in the {@code ParameterDescriptorGroup}.
 * @param  fromValues    the descriptors declared in the {@code ParameterValue} instances.
 *                       They are said "valid" because they contain the mandatory {@code valueClass} property.
 * @param  replacements  an {@code IdentityHashMap} where to store the replacements that the caller needs to
 *                       apply in the {@code GeneralParameterValue} instances.
 * @return a sequence containing the merged set of parameter descriptors.
 *
 * @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
 */
public static GeneralParameterDescriptor[] merge(final List<GeneralParameterDescriptor> descriptors, final GeneralParameterDescriptor[] fromValues, final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> replacements) {
    if (descriptors.isEmpty()) {
        return fromValues;
    }
    final Map<String, GeneralParameterDescriptor> union = new LinkedHashMap<>(Containers.hashMapCapacity(descriptors.size()));
    /*
         * Collect the descriptors declared explicitely in the ParameterDescriptorGroup. We should never have
         * two descriptors of the same name since the DefaultParameterDescriptorGroup constructor checked for
         * name ambiguity. If a name collision is nevertheless detected, this would mean that a descriptor's
         * name mutated.
         */
    for (final GeneralParameterDescriptor p : descriptors) {
        final String name = p.getName().getCode();
        if (union.put(name, p) != null) {
            throw new CorruptedObjectException(name);
        }
    }
    /*
         * Verify if any descriptors found in the ParameterValue instances could replace the descriptors in the group.
         * We give precedence to the descriptors having a non-null 'valueClass' property, which normally appear in the
         * 'fromValues' array.
         */
    for (final GeneralParameterDescriptor valueDescriptor : fromValues) {
        final String name = valueDescriptor.getName().getCode();
        GeneralParameterDescriptor complete = valueDescriptor;
        GeneralParameterDescriptor previous = union.put(name, complete);
        if (previous != null) {
            if (previous instanceof ParameterDescriptor<?>) {
                verifyEquivalence(name, complete instanceof ParameterDescriptor<?>);
                final Class<?> valueClass = ((ParameterDescriptor<?>) previous).getValueClass();
                if (valueClass != null) {
                    /*
                         * This may happen if the 'descriptors' argument contain the parameters of a pre-defined
                         * method from the 'org.apache.sis.internal.referencing.provider' package instead than a
                         * descriptor from the GML file.  In such case, presume that 'previous' is actually more
                         * complete than 'complete'.
                         *
                         * Note that 'r' should never be null unless JAXB unmarshalled the elements in reverse
                         * order (e.g. <gml:ParameterValue> before <gml:OperationMethod>). Since this behavior
                         * may depend on JAXB implementation, we are better to check for such case.
                         */
                    final Class<?> r = ((ParameterDescriptor<?>) complete).getValueClass();
                    if (r != null) {
                        verifyEquivalence(name, valueClass == r);
                    }
                    // Restore the previous value in the map and swap 'previous' with 'replacement'.
                    previous = union.put(name, complete = previous);
                }
            } else if (previous instanceof ParameterDescriptorGroup) {
                verifyEquivalence(name, complete instanceof ParameterDescriptorGroup);
            }
            /*
                 * Verify that the replacement contains at least all the information provided by the previous
                 * descriptor. The replacement is allowed to contain more information however.
                 */
            final GeneralParameterDescriptor replacement = CC_GeneralOperationParameter.merge(previous, complete);
            if (replacement != valueDescriptor) {
                union.put(name, replacement);
                if (replacements.put(valueDescriptor, replacement) != null) {
                    // Should never happen, unless the parameter name changed during execution of this loop.
                    throw new CorruptedObjectException(name);
                }
            }
        }
    }
    return union.values().toArray(new GeneralParameterDescriptor[union.size()]);
}
Also used : GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) ParameterDescriptor(org.opengis.parameter.ParameterDescriptor) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) LinkedHashMap(java.util.LinkedHashMap)

Aggregations

CorruptedObjectException (org.apache.sis.util.CorruptedObjectException)9 DefaultParameterDescriptorGroup (org.apache.sis.parameter.DefaultParameterDescriptorGroup)2 GeneralParameterDescriptor (org.opengis.parameter.GeneralParameterDescriptor)2 Instant (java.time.Instant)1 Collection (java.util.Collection)1 Date (java.util.Date)1 HashSet (java.util.HashSet)1 IdentityHashMap (java.util.IdentityHashMap)1 Iterator (java.util.Iterator)1 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1 AbstractIdentifiedType (org.apache.sis.feature.AbstractIdentifiedType)1 DefaultFeatureType (org.apache.sis.feature.DefaultFeatureType)1 Cloner (org.apache.sis.internal.util.Cloner)1 Vector (org.apache.sis.math.Vector)1 AbstractMetadata (org.apache.sis.metadata.AbstractMetadata)1 InvalidMetadataException (org.apache.sis.metadata.InvalidMetadataException)1 MetadataStandard (org.apache.sis.metadata.MetadataStandard)1 ModifiableMetadata (org.apache.sis.metadata.ModifiableMetadata)1 ParameterDescriptor (org.opengis.parameter.ParameterDescriptor)1