blob: 9da1ba222411e3fc3b4b5a80f6458abe6d1a640a [file] [log] [blame]
/*
* 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 javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.opengis.util.CodeList;
import org.opengis.util.GenericName;
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.identification.DataIdentification;
import org.opengis.metadata.distribution.StandardOrderProcess;
import org.opengis.metadata.identification.ServiceIdentification;
import org.apache.sis.internal.jaxb.code.SV_CouplingType;
import org.apache.sis.internal.jaxb.FilterByVersion;
import org.apache.sis.xml.Namespaces;
// Branch-specific imports
import org.opengis.annotation.UML;
import static org.opengis.annotation.Obligation.OPTIONAL;
import static org.opengis.annotation.Obligation.MANDATORY;
import static org.opengis.annotation.Obligation.CONDITIONAL;
import static org.opengis.annotation.Specification.ISO_19115;
/**
* Identification of capabilities which a service provider makes available to a service user
* through a set of interfaces that define a behaviour.
* The following properties are mandatory or conditional (i.e. mandatory under some circumstances)
* in a well-formed metadata according ISO 19115:
*
* <div class="preformat">{@code SV_ServiceIdentification}
* {@code   ├─citation………………………………………} Citation data for the resource(s).
* {@code   │   ├─title……………………………………} Name by which the cited resource is known.
* {@code   │   └─date………………………………………} Reference date for the cited resource.
* {@code   ├─abstract………………………………………} Brief narrative summary of the content of the resource(s).
* {@code   ├─serviceType………………………………} A service type name. For example: "view", "download", or "invoke".
* {@code   ├─coupledResource……………………} Further description of the data coupling in the case of tightly coupled services.
* {@code   ├─couplingType……………………………} Type of coupling between service and associated data (if exist).
* {@code   ├─extent……………………………………………} Bounding polygon, vertical, and temporal extent of the dataset.
* {@code   │   ├─description……………………} The spatial and temporal extent for the referring object.
* {@code   │   ├─geographicElement……} Geographic component of the extent of the referring object.
* {@code   │   ├─temporalElement…………} Temporal component of the extent of the referring object.
* {@code   │   └─verticalElement…………} Vertical component of the extent of the referring object.
* {@code   └─topicCategory…………………………} Main theme(s) of the dataset.</div>
*
* <p><b>Limitations:</b></p>
* <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 Martin Desruisseaux (IRD, Geomatys)
* @author Touraïvane (IRD)
* @author Cédric Briançon (Geomatys)
* @author Rémi Maréchal (Geomatys)
* @author Cullen Rombach (Image Matters)
* @version 1.0
* @since 0.5
* @module
*/
@XmlType(name = "SV_ServiceIdentification_Type", namespace = Namespaces.SRV, propOrder = {
"serviceType",
"serviceTypeVersions",
"accessProperties",
"couplingType", // "couplingType" and "coupledResource" were in reverse order in ISO 19115:2003.
"coupledResources",
"operatedDataset",
"profile",
"serviceStandard",
"containsOperations",
"operatesOn",
"operationChain" // Actually "containsChain"
})
@XmlRootElement(name = "SV_ServiceIdentification", namespace = Namespaces.SRV)
public class DefaultServiceIdentification extends AbstractIdentification implements ServiceIdentification {
/**
* Serial number for compatibility with different versions.
*/
private static final long serialVersionUID = 7700836694236616300L;
/**
* A service type name.
*/
private GenericName serviceType;
/**
* The version of the service, supports searching based on the version of serviceType.
*/
private Collection<String> serviceTypeVersions;
/**
* Information about the availability of the service.
*/
private StandardOrderProcess accessProperties;
/**
* Type of coupling between service and associated data (if exist).
*/
private CodeList<?> couplingType;
/**
* Further description of the data coupling in the case of tightly coupled services.
*/
private Collection<DefaultCoupledResource> coupledResources;
/**
* References to the resource on which the service operates.
*/
private Collection<Citation> operatedDatasets;
/**
* Profiles to which the service adheres.
*/
private Collection<Citation> profiles;
/**
* Standards to which the service adheres.
*/
private Collection<Citation> serviceStandards;
/**
* Information about the operations that comprise the service.
*/
private Collection<DefaultOperationMetadata> containsOperations;
/**
* Information on the resources that the service operates on.
*/
private Collection<DataIdentification> operatesOn;
/**
* Information about the chain applied by the service.
*/
private Collection<DefaultOperationChainMetadata> containsChain;
/**
* Constructs an initially empty service identification.
*/
public DefaultServiceIdentification() {
}
/**
* Constructs a service identification initialized to the specified values.
*
* @param serviceType service type name.
* @param citation citation data for the resource(s).
* @param abstracts brief narrative summary of the content of the resource(s).
*/
public DefaultServiceIdentification(final GenericName serviceType,
final Citation citation,
final CharSequence abstracts)
{
super(citation, abstracts);
this.serviceType = serviceType;
}
/**
* Constructs a new instance initialized with the values from the specified metadata object.
* This is a <cite>shallow</cite> copy constructor, since 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.
*
* @see #castOrCopy(ServiceIdentification)
*/
public DefaultServiceIdentification(final ServiceIdentification object) {
super(object);
if (object instanceof DefaultServiceIdentification) {
final DefaultServiceIdentification c = (DefaultServiceIdentification) object;
serviceType = c.getServiceType();
serviceTypeVersions = copyCollection(c.getServiceTypeVersions(), String.class);
accessProperties = c.getAccessProperties();
couplingType = c.getCouplingType();
coupledResources = copyCollection(c.getCoupledResources(), DefaultCoupledResource.class);
operatedDatasets = copyCollection(c.getOperatedDatasets(), Citation.class);
profiles = copyCollection(c.getProfiles(), Citation.class);
serviceStandards = copyCollection(c.getServiceStandards(), Citation.class);
containsOperations = copyCollection(c.getContainsOperations(), DefaultOperationMetadata.class);
operatesOn = copyCollection(c.getOperatesOn(), DataIdentification.class);
containsChain = copyCollection(c.getContainsChain(), DefaultOperationChainMetadata.class);
}
}
/**
* Returns a SIS metadata implementation with the values of the given arbitrary implementation.
* This method performs the first applicable action in the following choices:
*
* <ul>
* <li>If the given object is {@code null}, then this method returns {@code null}.</li>
* <li>Otherwise if the given object is already an instance of
* {@code DefaultServiceIdentification}, then it is returned unchanged.</li>
* <li>Otherwise a new {@code DefaultServiceIdentification} instance is created using the
* {@linkplain #DefaultServiceIdentification(ServiceIdentification) copy constructor}
* and returned. Note that this is a <cite>shallow</cite> copy operation, since the other
* metadata contained in the given object are not recursively copied.</li>
* </ul>
*
* @param object the object to get as a SIS implementation, or {@code null} if none.
* @return a SIS implementation containing the values of the given object (may be the
* given object itself), or {@code null} if the argument was null.
*/
public static DefaultServiceIdentification castOrCopy(final ServiceIdentification object) {
if (object == null || object instanceof DefaultServiceIdentification) {
return (DefaultServiceIdentification) object;
}
return new DefaultServiceIdentification(object);
}
/**
* Returns a service type name.
*
* <div class="note"><b>Examples:</b> "discovery", "view", "download", "transformation", or "invoke"</div>
*
* @return a service type name.
*/
@XmlElement(name = "serviceType", required = true)
@UML(identifier="serviceType", obligation=MANDATORY, specification=ISO_19115)
public GenericName getServiceType() {
return serviceType;
}
/**
* Sets the service type name.
*
* @param newValue the new service type name.
*/
public void setServiceType(final GenericName newValue) {
checkWritePermission(serviceType);
serviceType = newValue;
}
/**
* Returns the versions of the service.
*
* @return the versions of the service.
*/
@XmlElement(name = "serviceTypeVersion")
@UML(identifier="serviceTypeVersion", obligation=OPTIONAL, specification=ISO_19115)
public Collection<String> getServiceTypeVersions() {
return serviceTypeVersions = nonNullCollection(serviceTypeVersions, String.class);
}
/**
* Sets the versions of the service.
*
* @param newValues the new versions of the service.
*/
public void setServiceTypeVersions(final Collection<? extends String> newValues) {
serviceTypeVersions = writeCollection(newValues, serviceTypeVersions, String.class);
}
/**
* Returns information about the availability of the service.
*
* @return information about the availability of the service, or {@code null} if none.
*
* @since 0.5
*/
@XmlElement(name = "accessProperties")
@UML(identifier="accessProperties", obligation=OPTIONAL, specification=ISO_19115)
public StandardOrderProcess getAccessProperties() {
return accessProperties;
}
/**
* Sets information about the availability of the service.
*
* @param newValue the new information about the availability of the service.
*
* @since 0.5
*/
public void setAccessProperties(final StandardOrderProcess newValue) {
checkWritePermission(accessProperties);
accessProperties = newValue;
}
/**
* Returns type of coupling between service and associated data (if exist).
*
* <div class="warning"><b>Upcoming API change — specialization</b><br>
* The return type will be changed to the {@code CouplingType} code list
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @return type of coupling between service and associated data, or {@code null} if none.
*/
@XmlJavaTypeAdapter(SV_CouplingType.class)
@XmlElement(name = "couplingType")
@UML(identifier="couplingType", obligation=CONDITIONAL, specification=ISO_19115)
public CodeList<?> getCouplingType() {
return couplingType;
}
/**
* Sets the type of coupling between service and associated data.
*
* <div class="warning"><b>Upcoming API change — specialization</b><br>
* The argument type will be changed to the {@code CouplingType} code list when GeoAPI will provide it
* (tentatively in GeoAPI 3.1). In the meantime, users can define their own code list class as below:
*
* {@preformat java
* final class UnsupportedCodeList extends CodeList<UnsupportedCodeList> {
* private static final List<UnsupportedCodeList> VALUES = new ArrayList<UnsupportedCodeList>();
*
* // Need to declare at least one code list element.
* public static final UnsupportedCodeList MY_CODE_LIST = new UnsupportedCodeList("MY_CODE_LIST");
*
* private UnsupportedCodeList(String name) {
* super(name, VALUES);
* }
*
* public static UnsupportedCodeList valueOf(String code) {
* return valueOf(UnsupportedCodeList.class, code);
* }
*
* &#64;Override
* public UnsupportedCodeList[] family() {
* synchronized (VALUES) {
* return VALUES.toArray(new UnsupportedCodeList[VALUES.size()]);
* }
* }
* }
* }
* </div>
*
* @param newValue the new type of coupling between service and associated data.
*/
public void setCouplingType(final CodeList<?> newValue) {
checkWritePermission(couplingType);
couplingType = newValue;
}
/**
* Returns further description(s) of the data coupling in the case of tightly coupled services.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code CoupledResource} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @return further description(s) of the data coupling in the case of tightly coupled services.
*/
@XmlElement(name = "coupledResource")
@UML(identifier="coupledResource", obligation=CONDITIONAL, specification=ISO_19115)
public Collection<DefaultCoupledResource> getCoupledResources() {
return coupledResources = nonNullCollection(coupledResources, DefaultCoupledResource.class);
}
/**
* Sets further description(s) of the data coupling in the case of tightly coupled services.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code CoupledResource} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @param newValues the new further description(s) of the data coupling.
*/
public void setCoupledResources(final Collection<? extends DefaultCoupledResource> newValues) {
coupledResources = writeCollection(newValues, coupledResources, DefaultCoupledResource.class);
}
/**
* Returns the reference(s) to the resource on which the service operates.
*
* @return reference(s) to the resource on which the service operates.
*
* @since 0.5
*/
// @XmlElement at the end of this class.
@UML(identifier="operatedDataset", obligation=OPTIONAL, specification=ISO_19115)
public Collection<Citation> getOperatedDatasets() {
return operatedDatasets = nonNullCollection(operatedDatasets, Citation.class);
}
/**
* Sets the reference(s) to the resource on which the service operates.
*
* @param newValues the new reference(s) to the resource on which the service operates.
*
* @since 0.5
*/
public void setOperatedDatasets(final Collection<? extends Citation> newValues) {
operatedDatasets = writeCollection(newValues, operatedDatasets, Citation.class);
}
/**
* Returns the profile(s) to which the service adheres.
*
* @return profile(s) to which the service adheres.
*
* @since 0.5
*/
// @XmlElement at the end of this class.
@UML(identifier="profile", obligation=OPTIONAL, specification=ISO_19115)
public Collection<Citation> getProfiles() {
return profiles = nonNullCollection(profiles, Citation.class);
}
/**
* Sets the profile(s) to which the service adheres.
*
* @param newValues the new profile(s) to which the service adheres.
*/
public void setProfiles(final Collection<? extends Citation> newValues) {
profiles = writeCollection(newValues, profiles, Citation.class);
}
/**
* Returns the standard(s) to which the service adheres.
*
* @return standard(s) to which the service adheres.
*
* @since 0.5
*/
// @XmlElement at the end of this class.
@UML(identifier="serviceStandard", obligation=OPTIONAL, specification=ISO_19115)
public Collection<Citation> getServiceStandards() {
return serviceStandards = nonNullCollection(serviceStandards, Citation.class);
}
/**
* Sets the standard(s) to which the service adheres.
*
* @param newValues the new standard(s) to which the service adheres.
*
* @since 0.5
*/
public void setServiceStandards(final Collection<? extends Citation> newValues) {
serviceStandards = writeCollection(newValues, serviceStandards, Citation.class);
}
/**
* Provides information about the operations that comprise the service.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code OperationMetadata} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @return information about the operations that comprise the service.
*/
@XmlElement(name = "containsOperations")
@UML(identifier="containsOperations", obligation=OPTIONAL, specification=ISO_19115)
public Collection<DefaultOperationMetadata> getContainsOperations() {
return containsOperations = nonNullCollection(containsOperations, DefaultOperationMetadata.class);
}
/**
* Sets information(s) about the operations that comprise the service.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code OperationMetadata} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @param newValues the new information(s) about the operations that comprise the service.
*/
public void setContainsOperations(final Collection<? extends DefaultOperationMetadata> newValues) {
containsOperations = writeCollection(newValues, containsOperations, DefaultOperationMetadata.class);
}
/**
* Provides information on the resources that the service operates on.
*
* @return information on the resources that the service operates on.
*/
@XmlElement(name = "operatesOn")
@UML(identifier="operatesOn", obligation=OPTIONAL, specification=ISO_19115)
public Collection<DataIdentification> getOperatesOn() {
return operatesOn = nonNullCollection(operatesOn, DataIdentification.class);
}
/**
* Sets the information on the resources that the service operates on.
*
* @param newValues the new information on the resources that the service operates on.
*/
public void setOperatesOn(final Collection<? extends DataIdentification> newValues) {
operatesOn = writeCollection(newValues, operatesOn, DataIdentification.class);
}
/**
* Provides information about the chain applied by the service.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code OperationChainMetadata} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @return information about the chain applied by the service.
*
* @since 0.5
*/
// @XmlElement at the end of this class.
@UML(identifier="containsChain", obligation=OPTIONAL, specification=ISO_19115)
public Collection<DefaultOperationChainMetadata> getContainsChain() {
return containsChain = nonNullCollection(containsChain, DefaultOperationChainMetadata.class);
}
/**
* Sets the information about the chain applied by the service.
*
* <div class="warning"><b>Upcoming API change — generalization</b><br>
* The element type will be changed to the {@code OperationChainMetadata} interface
* when GeoAPI will provide it (tentatively in GeoAPI 3.1).
* </div>
*
* @param newValues the new information about the chain applied by the service.
*
* @since 0.5
*/
public void setContainsChain(final Collection<? extends DefaultOperationChainMetadata> newValues) {
containsChain = writeCollection(newValues, containsChain, DefaultOperationChainMetadata.class);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
//////// ////////
//////// 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. ////////
//////// ////////
//////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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 = "operatedDataset")
private Collection<Citation> getOperatedDataset() {
return FilterByVersion.CURRENT_METADATA.accept() ? getOperatedDatasets() : null;
}
@XmlElement(name = "profile")
private Collection<Citation> getProfile() {
return FilterByVersion.CURRENT_METADATA.accept() ? getProfiles() : null;
}
@XmlElement(name = "serviceStandard")
private Collection<Citation> getServiceStandard() {
return FilterByVersion.CURRENT_METADATA.accept() ? getServiceStandards() : null;
}
@XmlElement(name = "containsChain")
private Collection<DefaultOperationChainMetadata> getOperationChain() {
return FilterByVersion.CURRENT_METADATA.accept() ? getContainsChain() : null;
}
/**
* Invoked after JAXB has unmarshalled this object.
*/
@SuppressWarnings("unused")
private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
if (containsOperations != null && coupledResources != null) {
OperationName.resolve(containsOperations, coupledResources);
}
}
}