Search in sources :

Example 1 with ScopedName

use of org.opengis.util.ScopedName in project sis by apache.

the class GO_GenericName method getValue.

/**
 * Returns the {@code LocalName} or {@code ScopedName} to marshal. Returns {@code null} if the name
 * is a {@link TypeName} or a {@link MemberName}, in order to use {@link #getName()} instead.
 * Example:
 *
 * {@preformat xml
 *   <gml:alias>
 *     <gco:LocalName codeSpace=\"A code space\">A name in a scope</gco:LocalName>
 *   </gml:alias>
 * }
 *
 * @return the code for the current name, or {@code null} if none.
 */
@XmlElementRef
public final NameValue getValue() {
    final GenericName name = this.name;
    final NameValue code;
    if (name instanceof LocalName) {
        if (name instanceof TypeName || name instanceof MemberName) {
            return null;
        } else if (FilterByVersion.LEGACY_METADATA.accept()) {
            code = new NameValue.Local();
        } else {
            // ISO 19115-3:2016 does not seem to define gco:LocalName anymore.
            code = new NameValue.Scoped();
        }
    } else if (name instanceof ScopedName) {
        code = new NameValue.Scoped();
    } else {
        return null;
    }
    code.setName(name);
    return code;
}
Also used : GenericName(org.opengis.util.GenericName) DefaultTypeName(org.apache.sis.util.iso.DefaultTypeName) TypeName(org.opengis.util.TypeName) ScopedName(org.opengis.util.ScopedName) DefaultMemberName(org.apache.sis.util.iso.DefaultMemberName) MemberName(org.opengis.util.MemberName) LocalName(org.opengis.util.LocalName) DefaultLocalName(org.apache.sis.util.iso.DefaultLocalName) XmlElementRef(javax.xml.bind.annotation.XmlElementRef)

Example 2 with ScopedName

use of org.opengis.util.ScopedName in project sis by apache.

the class DefaultFeatureType method computeTransientFields.

/**
 * Computes transient fields ({@link #assignableTo}, {@link #byName}, {@link #indices}, {@link #isSimple}).
 *
 * <p>As a side effect, this method checks for missing or duplicated names.</p>
 *
 * @param  properties  same content as {@link #properties} (may be the reference to the same list), but
 *         optionally in a temporarily modifiable list if we want to allow removal of duplicated values.
 *         See {@code scanPropertiesFrom(FeatureType, Collection)} javadoc for more explanation.
 * @throws IllegalArgumentException if two properties have the same name.
 */
private void computeTransientFields(final List<AbstractIdentifiedType> properties) {
    final int capacity = Containers.hashMapCapacity(properties.size());
    byName = new LinkedHashMap<>(capacity);
    indices = new LinkedHashMap<>(capacity);
    assignableTo = new HashSet<>(4);
    assignableTo.add(super.getName());
    scanPropertiesFrom(this, properties);
    allProperties = UnmodifiableArrayList.wrap(byName.values().toArray(new AbstractIdentifiedType[byName.size()]));
    /*
         * Now check if the feature is simple/complex or dense/sparse. We perform this check after we finished
         * to create the list of all properties, because some properties may be overridden and we want to take
         * in account only the most specific ones.
         */
    isSimple = true;
    int index = 0;
    // Count of mandatory properties.
    int mandatory = 0;
    for (final Map.Entry<String, AbstractIdentifiedType> entry : byName.entrySet()) {
        final int minimumOccurs, maximumOccurs;
        final AbstractIdentifiedType property = entry.getValue();
        if (property instanceof DefaultAttributeType<?>) {
            // Other SIS branches check for AttributeType instead.
            minimumOccurs = ((DefaultAttributeType<?>) property).getMinimumOccurs();
            maximumOccurs = ((DefaultAttributeType<?>) property).getMaximumOccurs();
            isSimple &= (minimumOccurs == maximumOccurs);
        } else if (property instanceof FieldType) {
            // TODO: check for AssociationRole instead (after GeoAPI upgrade).
            minimumOccurs = ((FieldType) property).getMinimumOccurs();
            maximumOccurs = ((FieldType) property).getMaximumOccurs();
            isSimple = false;
        } else {
            if (isParameterlessOperation(property)) {
                indices.put(entry.getKey(), OPERATION_INDEX);
            }
            // For feature operations, maximumOccurs is implicitly 0.
            continue;
        }
        if (maximumOccurs != 0) {
            isSimple &= (maximumOccurs == 1);
            indices.put(entry.getKey(), index++);
            if (minimumOccurs != 0) {
                mandatory++;
            }
        }
    }
    /*
         * If some properties use long name of the form "head:tip", creates short aliases containing only the "tip"
         * name for convenience, provided that it does not create ambiguity.  If a short alias could map to two or
         * more properties, then that alias is not added.
         *
         * In the 'aliases' map below, null values will be assigned to ambiguous short names.
         */
    final Map<String, AbstractIdentifiedType> aliases = new LinkedHashMap<>();
    for (final AbstractIdentifiedType property : allProperties) {
        GenericName name = property.getName();
        while (name instanceof ScopedName) {
            // Safety against broken implementations.
            if (name == (name = ((ScopedName) name).tail()))
                break;
            String key = name.toString();
            // Safety against broken implementations.
            if (key == null || (key = key.trim()).isEmpty())
                break;
            aliases.put(key, aliases.containsKey(key) ? null : property);
        }
    }
    for (final Map.Entry<String, AbstractIdentifiedType> entry : aliases.entrySet()) {
        final AbstractIdentifiedType property = entry.getValue();
        if (property != null) {
            final String tip = entry.getKey();
            if (byName.putIfAbsent(tip, property) == null) {
                /*
                     * This block is skipped if there is properties named "tip" and "head:tip".
                     * The 'indices' value may be null if the property is an operation.
                     */
                final Integer value = indices.get(property.getName().toString());
                if (value != null && indices.put(tip, value) != null) {
                    // Should never happen.
                    throw new AssertionError(tip);
                }
            }
        }
    }
    /*
         * Trim the collections. Especially useful when the collections have less that 2 elements.
         */
    byName = CollectionsExt.compact(byName);
    indices = CollectionsExt.compact(indices);
    assignableTo = CollectionsExt.unmodifiableOrCopy(assignableTo);
    /*
         * Rational for choosing whether the feature is sparse: By default, java.util.HashMap implementation creates
         * an internal array of length 16 (see HashMap.DEFAULT_INITIAL_CAPACITY).  In addition, the HashMap instance
         * itself consumes approximatively 8 "words" in memory.  Consequently there is no advantage in using HashMap
         * unless the number of properties is greater than 16 + 8 (note: we could specify a smaller initial capacity,
         * but the memory consumed by each internal Map.Entry quickly exceed the few saved words). Next, the default
         * HashMap threshold is 0.75, so there is again no advantage in using HashMap if we do not expect at least 25%
         * of unused properties. Our current implementation arbitrarily sets the threshold to 50%.
         */
    final int n = indices.size();
    isSparse = (n > 24) && (mandatory <= n / 2);
}
Also used : InternationalString(org.opengis.util.InternationalString) LinkedHashMap(java.util.LinkedHashMap) GenericName(org.opengis.util.GenericName) ScopedName(org.opengis.util.ScopedName) IdentityHashMap(java.util.IdentityHashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 3 with ScopedName

use of org.opengis.util.ScopedName in project sis by apache.

the class TypeBuilder method forName.

/**
 * Returns the element of the given name in the given list. The given name does not need to contains
 * all elements of a {@link ScopedName}; it can be only the tip (for example {@code "myName"} instead
 * of {@code "myScope:myName"}) provided that ignoring the name head does not create ambiguity.
 *
 * @param  types  the collection where to search for an element of the given name.
 * @param  name   name of the element to search.
 * @return element of the given name, or {@code null} if none were found.
 * @throws IllegalArgumentException if the given name is ambiguous.
 */
@SuppressWarnings("null")
final <E extends TypeBuilder> E forName(final List<E> types, final String name) {
    // Best type found so far.
    E best = null;
    // If two types are found at the same depth, the other type.
    E ambiguity = null;
    // Number of path elements that we had to ignore in the GenericName.
    int depth = Integer.MAX_VALUE;
    for (final E type : types) {
        GenericName candidate = type.getName();
        for (int d = 0; candidate != null; d++) {
            if (name.equals(candidate.toString())) {
                if (d < depth) {
                    best = type;
                    ambiguity = null;
                    depth = d;
                    break;
                }
                if (d == depth) {
                    ambiguity = type;
                    break;
                }
            }
            if (!(candidate instanceof ScopedName))
                break;
            candidate = ((ScopedName) candidate).tail();
        }
    }
    if (ambiguity != null) {
        throw new IllegalArgumentException(errors().getString(Errors.Keys.AmbiguousName_3, best.getName(), ambiguity.getName(), name));
    }
    return best;
}
Also used : GenericName(org.opengis.util.GenericName) ScopedName(org.opengis.util.ScopedName)

Example 4 with ScopedName

use of org.opengis.util.ScopedName in project sis by apache.

the class DefaultNameSpace method name.

/**
 * Represents the identifier of this namespace. Namespace identifiers shall be
 * {@linkplain AbstractName#toFullyQualifiedName() fully-qualified names} where
 * the following condition holds:
 *
 * {@preformat java
 *     assert name.scope().isGlobal() == true;
 * }
 *
 * @return the identifier of this namespace.
 */
@Override
public GenericName name() {
    final int depth;
    synchronized (this) {
        if (path != null) {
            return path;
        }
        depth = depth(this);
        final DefaultLocalName[] names = new DefaultLocalName[depth];
        DefaultNameSpace scan = this;
        for (int i = depth; --i >= 0; ) {
            names[i] = new DefaultLocalName(scan.parent, scan.name);
            scan = scan.parent;
        }
        assert depth(scan) == 0 || scan.isGlobal();
        path = DefaultScopedName.create(UnmodifiableArrayList.wrap(names));
        GenericName truncated = path;
        for (int i = depth; --i >= 0; ) {
            names[i].fullyQualified = truncated;
            truncated = (truncated instanceof ScopedName) ? ((ScopedName) truncated).path() : null;
        }
    }
    /*
         * At this point the name is created and ready to be returned. As an optimization,
         * defines the name of parents now in order to share subarea of the array we just
         * created. The goal is to have less objects in memory.
         */
    AbstractName truncated = path;
    DefaultNameSpace scan = parent;
    while (scan != null && !scan.isGlobal()) {
        /*
             * If we have a parent, then depth >= 2 and consequently the name is a ScopedName.
             * Actually it should be an instance of DefaultScopedName - we known that since we
             * created it ourself with the DefaultScopedName.create(...) method call - and we
             * know that its tail() implementation creates instance of AbstractName. Given all
             * the above, none of the casts on the line below should ever fails, unless there
             * is bug in this package.
             */
        truncated = (AbstractName) ((ScopedName) truncated).path();
        synchronized (scan) {
            if (scan.path == null || scan.path.arraySize() < depth) {
                scan.path = truncated;
            }
        }
        scan = scan.parent;
    }
    return path;
}
Also used : GenericName(org.opengis.util.GenericName) ScopedName(org.opengis.util.ScopedName)

Example 5 with ScopedName

use of org.opengis.util.ScopedName in project sis by apache.

the class NamesTest method testCreateScopedName.

/**
 * Tests {@link Names#createScopedName(GenericName, String, CharSequence)}.
 */
@Test
@DependsOnMethod("testCreateLocalName")
public void testCreateScopedName() {
    final LocalName scope = Names.createLocalName("Apache", null, "sis");
    final ScopedName name = Names.createScopedName(scope, null, "identifier");
    assertSame("path()", scope, name.path());
    assertEquals("tail()", "identifier", name.tail().toString());
    assertEquals("toString()", "sis:identifier", name.toString());
    assertEquals("full", "Apache:sis:identifier", name.toFullyQualifiedName().toString());
    assertEquals("tail().full", "Apache:sis:identifier", name.tail().toFullyQualifiedName().toString());
}
Also used : ScopedName(org.opengis.util.ScopedName) LocalName(org.opengis.util.LocalName) Test(org.junit.Test) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Aggregations

ScopedName (org.opengis.util.ScopedName)6 GenericName (org.opengis.util.GenericName)5 LocalName (org.opengis.util.LocalName)2 IdentityHashMap (java.util.IdentityHashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1 XmlElementRef (javax.xml.bind.annotation.XmlElementRef)1 DependsOnMethod (org.apache.sis.test.DependsOnMethod)1 DefaultLocalName (org.apache.sis.util.iso.DefaultLocalName)1 DefaultMemberName (org.apache.sis.util.iso.DefaultMemberName)1 DefaultTypeName (org.apache.sis.util.iso.DefaultTypeName)1 Test (org.junit.Test)1 InternationalString (org.opengis.util.InternationalString)1 MemberName (org.opengis.util.MemberName)1 TypeName (org.opengis.util.TypeName)1