| /* |
| * 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.iso.identification; |
| |
| import java.util.Collection; |
| import jakarta.xml.bind.annotation.XmlType; |
| import jakarta.xml.bind.annotation.XmlElement; |
| import jakarta.xml.bind.annotation.XmlRootElement; |
| import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; |
| import jakarta.xml.bind.annotation.adapters.CollapsedStringAdapter; |
| import org.opengis.util.ScopedName; |
| import org.opengis.metadata.citation.Citation; |
| import org.opengis.metadata.identification.DataIdentification; |
| import org.apache.sis.metadata.iso.ISOMetadata; |
| import org.apache.sis.xml.Namespaces; |
| import org.apache.sis.xml.bind.FilterByVersion; |
| import org.apache.sis.xml.bind.metadata.SV_OperationMetadata; |
| import org.apache.sis.xml.privy.LegacyNamespaces; |
| import org.apache.sis.xml.bind.gco.GO_GenericName; |
| import org.apache.sis.util.privy.Constants; |
| import org.apache.sis.util.iso.Names; |
| |
| // Specific to the main branch: |
| import org.opengis.annotation.UML; |
| import static org.opengis.annotation.Obligation.OPTIONAL; |
| import static org.opengis.annotation.Specification.ISO_19115; |
| |
| |
| /** |
| * Links a given operation name with a resource identified by an "identifier". |
| * |
| * <div class="warning"><b>Note on International Standard versions</b><br> |
| * This class is derived from a new type defined in the ISO 19115 international standard published in 2014, |
| * while GeoAPI 3.0 is based on the version published in 2003. Consequently this implementation class does |
| * not yet implement a GeoAPI interface, but is expected to do so after the next GeoAPI releases. |
| * When the interface will become available, all references to this implementation class in Apache SIS will |
| * be replaced be references to the {@code CoupledResource} interface. |
| * </div> |
| * |
| * <h2>Limitations</h2> |
| * <ul> |
| * <li>Instances of this class are not synchronized for multi-threading. |
| * Synchronization, if needed, is caller's responsibility.</li> |
| * <li>Serialized objects of this class are not guaranteed to be compatible with future Apache SIS releases. |
| * Serialization support is appropriate for short term storage or RMI between applications running the |
| * same version of Apache SIS. For long term storage, use {@link org.apache.sis.xml.XML} instead.</li> |
| * </ul> |
| * |
| * @author Rémi Maréchal (Geomatys) |
| * @author Martin Desruisseaux (Geomatys) |
| * @author Cullen Rombach (Image Matters) |
| * @version 1.4 |
| * @since 0.5 |
| */ |
| @XmlType(name = "SV_CoupledResource_Type", namespace = Namespaces.SRV, propOrder = { |
| "scopedName", // ISO 19115-3:2016 way to write scoped name |
| "resourceReference", // New in ISO 19115:2014 |
| "resource", // Ibid. |
| "operation", // Ibid. |
| "operationName", // Legacy ISO 19139:2007 |
| "id", // Ibid. |
| "legacyName" // Legacy ISO 19139:2007 way to write scoped name |
| }) |
| @XmlRootElement(name = "SV_CoupledResource", namespace = Namespaces.SRV) |
| @UML(identifier="SV_CoupledResource", specification=ISO_19115) |
| public class DefaultCoupledResource extends ISOMetadata { |
| /** |
| * Serial number for compatibility with different versions. |
| */ |
| private static final long serialVersionUID = 154704781596732747L; |
| |
| /** |
| * Scoped identifier of the resource in the context of the given service instance. |
| */ |
| @SuppressWarnings("serial") |
| private ScopedName scopedName; |
| |
| /** |
| * References to the resource on which the services operates. |
| */ |
| @SuppressWarnings("serial") |
| private Collection<Citation> resourceReferences; |
| |
| /** |
| * The tightly coupled resources. |
| */ |
| @SuppressWarnings("serial") |
| private Collection<DataIdentification> resources; |
| |
| /** |
| * The service operation. |
| */ |
| @SuppressWarnings("serial") |
| private DefaultOperationMetadata operation; |
| |
| /** |
| * Constructs an initially empty coupled resource. |
| */ |
| public DefaultCoupledResource() { |
| } |
| |
| /** |
| * Constructs a new coupled resource initialized to the specified values. |
| * |
| * @param name scoped identifier of the resource in the context of the given service instance. |
| * @param reference reference to the reference to the resource on which the services operates. |
| * @param resource the tightly coupled resource. |
| * @param operation the service operation. |
| */ |
| public DefaultCoupledResource(final ScopedName name, |
| final Citation reference, |
| final DataIdentification resource, |
| final DefaultOperationMetadata operation) |
| { |
| this.scopedName = name; |
| this.resourceReferences = singleton(reference, Citation.class); |
| this.resources = singleton(resource, DataIdentification.class); |
| this.operation = operation; |
| } |
| |
| /** |
| * Constructs a new instance initialized with the values from the specified metadata object. |
| * This is a <em>shallow</em> copy constructor, because the other metadata contained in the |
| * given object are not recursively copied. |
| * |
| * @param object the metadata to copy values from, or {@code null} if none. |
| */ |
| public DefaultCoupledResource(final DefaultCoupledResource object) { |
| super(object); |
| if (object != null) { |
| this.scopedName = object.getScopedName(); |
| this.resourceReferences = copyCollection(object.getResourceReferences(), Citation.class); |
| this.resources = copyCollection(object.getResources(), DataIdentification.class); |
| this.operation = object.getOperation(); |
| } |
| } |
| |
| /** |
| * Returns scoped identifier of the resource in the context of the given service instance. |
| * |
| * @return identifier of the resource, or {@code null} if none. |
| */ |
| @XmlElement(name = "scopedName") |
| @XmlJavaTypeAdapter(GO_GenericName.Since2014.class) |
| @UML(identifier="scopedName", obligation=OPTIONAL, specification=ISO_19115) |
| public ScopedName getScopedName() { |
| return scopedName; |
| } |
| |
| /** |
| * Sets the identifier of the resource in the context of the given service instance. |
| * |
| * @param newValue the new identifier of the resource. |
| */ |
| public void setScopedName(final ScopedName newValue) { |
| checkWritePermission(scopedName); |
| scopedName = newValue; |
| } |
| |
| /** |
| * Returns references to the resource on which the services operates. |
| * |
| * @return references to the resource on which the services operates. |
| */ |
| // @XmlElement at the end of this class. |
| @UML(identifier="resourceReference", obligation=OPTIONAL, specification=ISO_19115) |
| public Collection<Citation> getResourceReferences() { |
| return resourceReferences = nonNullCollection(resourceReferences, Citation.class); |
| } |
| |
| /** |
| * Sets references to the resource on which the services operates. |
| * |
| * @param newValues the new references to the resource on which the services operates. |
| */ |
| public void setResourceReferences(final Collection<? extends Citation> newValues) { |
| resourceReferences = writeCollection(newValues, resourceReferences, Citation.class); |
| } |
| |
| /** |
| * Returns the tightly coupled resources. |
| * |
| * @return tightly coupled resources. |
| */ |
| // @XmlElement at the end of this class. |
| @UML(identifier="resource", obligation=OPTIONAL, specification=ISO_19115) |
| public Collection<DataIdentification> getResources() { |
| return resources = nonNullCollection(resources, DataIdentification.class); |
| } |
| |
| /** |
| * Sets the tightly coupled resources. |
| * |
| * @param newValues the new tightly coupled resources. |
| */ |
| public void setResources(final Collection<? extends DataIdentification> newValues) { |
| resources = writeCollection(newValues, resources, DataIdentification.class); |
| } |
| |
| /** |
| * Returns the service operation. |
| * |
| * <div class="warning"><b>Upcoming API change — generalization</b><br> |
| * The return type will be changed to the {@code OperationMetadata} interface |
| * when GeoAPI will provide it (tentatively in GeoAPI 3.1). |
| * </div> |
| * |
| * @return the service operation, or {@code null} if none. |
| */ |
| @XmlElement(name = "operation") |
| @XmlJavaTypeAdapter(SV_OperationMetadata.Since2014.class) |
| @UML(identifier="operation", obligation=OPTIONAL, specification=ISO_19115) |
| public DefaultOperationMetadata getOperation() { |
| return operation; |
| } |
| |
| /** |
| * Sets a new service operation. |
| * |
| * <div class="warning"><b>Upcoming API change — generalization</b><br> |
| * The argument type will be changed to the {@code OperationMetadata} interface |
| * when GeoAPI will provide it (tentatively in GeoAPI 3.1). |
| * </div> |
| * |
| * @param newValue the new service operation. |
| */ |
| public void setOperation(final DefaultOperationMetadata newValue) { |
| checkWritePermission(operation); |
| this.operation = newValue; |
| } |
| |
| |
| |
| |
| /* |
| ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ |
| ┃ ┃ |
| ┃ XML support with JAXB ┃ |
| ┃ ┃ |
| ┃ The following methods are invoked by JAXB using reflection (even if ┃ |
| ┃ they are private) or are helpers for other methods invoked by JAXB. ┃ |
| ┃ Those methods can be safely removed if Geographic Markup Language ┃ |
| ┃ (GML) support is not needed. ┃ |
| ┃ ┃ |
| ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ |
| */ |
| |
| /** |
| * For JAXB marshalling of ISO 19139:2007 document only (XML based on legacy ISO 19115:2003 model). |
| */ |
| @XmlElement(name = "operationName", namespace = LegacyNamespaces.SRV) |
| private String getOperationName() { |
| if (FilterByVersion.LEGACY_METADATA.accept()) { |
| final DefaultOperationMetadata operation = getOperation(); |
| if (operation != null) { |
| return operation.getOperationName(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * For JAXB unmarhalling of ISO 19139:2007 document only. Sets {@link #operation} to a temporary |
| * {@link OperationName} placeholder. That temporary instance will be replaced by the real one |
| * when the enclosing {@link DefaultServiceIdentification} is unmarshalled. |
| */ |
| @SuppressWarnings("unused") |
| private void setOperationName(final String name) { |
| if (operation == null) { |
| operation = new OperationName(name); |
| } |
| } |
| |
| /** |
| * Returns the resource identifier, which is assumed to be the name as a string. |
| * Used in legacy ISO 19139:2007 documents. There is no setter method; we expect |
| * the XML to declare {@code <srv:operationName>} instead. |
| */ |
| @XmlElement(name = "identifier", namespace = LegacyNamespaces.SRV) |
| private String getId() { |
| if (FilterByVersion.LEGACY_METADATA.accept()) { |
| final ScopedName name = getScopedName(); |
| if (name != null) { |
| return name.tip().toString(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the {@code <gco:ScopedName>} element to marshal in legacy ISO 19139:2007 element. |
| * The {@code <srv:scopedName>} element wrapper (note the lower-case "s") was missing in that |
| * legacy specification. This departure from ISO patterns has been fixed in ISO 19115-3:2016. |
| * |
| * <p>Note that the namespace is {@value Namespaces#GCO} rather than {@value LegacyNamespaces#GCO} |
| * because this is the namespace of the {@link ScopedName} type, not the namespace of a property |
| * in {@code SV_CoupledResource}.</p> |
| */ |
| @XmlElement(name = "ScopedName", namespace = Namespaces.GCO) |
| @XmlJavaTypeAdapter(CollapsedStringAdapter.class) |
| private String getLegacyName() { |
| if (FilterByVersion.LEGACY_METADATA.accept()) { |
| final ScopedName name = getScopedName(); |
| if (name != null) return name.toString(); |
| } |
| return null; |
| } |
| |
| /** |
| * Invoked by JAXB when unmarshalling a legacy ISO 19139:2007 documents. |
| */ |
| @SuppressWarnings("unused") |
| private void setLegacyName(String value) { |
| if (value != null && !value.isEmpty()) { |
| /* |
| * If the given name does not have a namespace, add an arbitrary namespace |
| * in order to get an instanceof ScopedName instead of LocalName after parsing. |
| */ |
| if (value.indexOf(Constants.DEFAULT_SEPARATOR) < 0) { |
| value = "global" + Constants.DEFAULT_SEPARATOR + value; |
| } |
| setScopedName((ScopedName) Names.parseGenericName(null, null, value)); |
| } |
| } |
| |
| /** |
| * Invoked by JAXB at both marshalling and unmarshalling time. |
| * This attribute has been added by ISO 19115:2014 standard. |
| * If (and only if) marshalling an older standard version, we omit this attribute. |
| */ |
| @XmlElement(name = "resourceReference") |
| private Collection<Citation> getResourceReference() { |
| return FilterByVersion.CURRENT_METADATA.accept() ? getResourceReferences() : null; |
| } |
| |
| /** |
| * Invoked by JAXB at both marshalling and unmarshalling time. |
| * This attribute has been added by ISO 19115:2014 standard. |
| * If (and only if) marshalling an older standard version, we omit this attribute. |
| */ |
| @XmlElement(name = "resource") |
| private Collection<DataIdentification> getResource() { |
| return FilterByVersion.CURRENT_METADATA.accept() ? getResources() : null; |
| } |
| } |