blob: 7328e80800d4225947437de3ada9283d7b510ab5 [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.citation;
import java.util.Iterator;
import java.util.Collection;
import java.util.Collections;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.opengis.metadata.citation.Contact;
import org.opengis.metadata.citation.ResponsibleParty;
import org.opengis.metadata.citation.Role;
import org.opengis.util.InternationalString;
import org.apache.sis.util.iso.Types;
import org.apache.sis.internal.xml.LegacyNamespaces;
import org.apache.sis.internal.metadata.Dependencies;
import org.apache.sis.internal.metadata.legacy.LegacyPropertyAdapter;
import static org.apache.sis.internal.metadata.MetadataUtilities.valueIfDefined;
/**
* Identification of, and means of communication with, person(s) and
* organizations associated with the dataset.
* 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 CI_ResponsibleParty}
* {@code   ├─role……………………………} Function performed by the responsible party.
* {@code   └─party…………………………} Information about the parties.
* {@code       └─name…………………} Name of the party.</div>
*
* <div class="warning"><b>Upcoming API change — deprecation</b><br>
* As of ISO 19115:2014, the {@code ResponsibleParty} type has been replaced by {@code Responsibility}
* to allow more flexible associations of individuals, organisations, and roles.
* This {@code ResponsibleParty} interface may be deprecated in GeoAPI 4.0.
* </div>
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Touraïvane (IRD)
* @author Cédric Briançon (Geomatys)
* @version 1.0
* @since 0.3
* @module
*/
@XmlType(name = "CI_ResponsibleParty_Type", namespace = LegacyNamespaces.GMD, propOrder = {
"individualName",
"organisationName",
"positionName",
"contactInfo",
"role"
})
@XmlRootElement(name = "CI_ResponsibleParty", namespace = LegacyNamespaces.GMD)
public class DefaultResponsibleParty extends DefaultResponsibility implements ResponsibleParty {
/**
* Serial number for inter-operability with different versions.
*/
private static final long serialVersionUID = -1022635486627088812L;
/**
* Constructs an initially empty responsible party.
*/
public DefaultResponsibleParty() {
}
/**
* Constructs a responsibility party with the given role.
*
* @param role the function performed by the responsible party, or {@code null}.
*/
public DefaultResponsibleParty(final Role role) {
super(role, null, null);
}
/**
* 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.
*/
public DefaultResponsibleParty(final DefaultResponsibility object) {
super(object);
}
/**
* 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(ResponsibleParty)
*/
public DefaultResponsibleParty(final ResponsibleParty object) {
super(object);
if (object != null && !(object instanceof DefaultResponsibility)) {
setIndividualName(object.getIndividualName());
setOrganisationName(object.getOrganisationName());
}
}
/**
* 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 DefaultResponsibleParty}, then it is returned unchanged.</li>
* <li>Otherwise a new {@code DefaultResponsibleParty} instance is created using the
* {@linkplain #DefaultResponsibleParty(ResponsibleParty) 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 DefaultResponsibleParty castOrCopy(final ResponsibleParty object) {
if (object == null || object instanceof DefaultResponsibleParty) {
return (DefaultResponsibleParty) object;
}
return new DefaultResponsibleParty(object);
}
/**
* Returns the name or the position of the first individual. If no individual is found in the list of parties,
* then this method will search in the list of organization members. The later structure is used by our netCDF
* reader.
*
* @param position {@code true} for returning the position name instead than individual name.
* @return the name or position of the first individual, or {@code null}.
*
* @see #getIndividualName()
* @see #getPositionName()
*/
private InternationalString getIndividual(final boolean position) {
final Collection<AbstractParty> parties = getParties();
InternationalString name = getName(parties, DefaultIndividual.class, position);
if (name == null && parties != null) {
for (final AbstractParty party : parties) {
if (party instanceof DefaultOrganisation) {
name = getName(((DefaultOrganisation) party).getIndividual(), DefaultIndividual.class, position);
if (name != null) {
break;
}
}
}
}
return name;
}
/**
* Returns the name of the first party of the given type, or {@code null} if none.
*
* @param position {@code true} for returning the position name instead than individual name.
* @return the name or position of the first individual, or {@code null}.
*
* @see #getOrganisationName()
* @see #getIndividualName()
* @see #getPositionName()
*/
private static InternationalString getName(final Collection<? extends AbstractParty> parties,
final Class<? extends AbstractParty> type, final boolean position)
{
InternationalString name = null;
if (parties != null) { // May be null on marshalling.
for (final AbstractParty party : parties) {
if (type.isInstance(party)) {
if (name != null) {
LegacyPropertyAdapter.warnIgnoredExtraneous(type, DefaultResponsibleParty.class,
position ? "getPositionName" : (type == DefaultIndividual.class)
? "getIndividualName" : "getOrganisationName");
break;
}
name = position ? ((DefaultIndividual) party).getPositionName() : party.getName();
}
}
}
return name;
}
/**
* Sets the name of the first party of the given type.
*
* @return {@code true} if the name has been set, or {@code false} otherwise.
*/
private boolean setName(final Class<? extends AbstractParty> type, final boolean position, final InternationalString name) {
checkWritePermission(valueIfDefined(super.getParties()));
final Iterator<AbstractParty> it = getParties().iterator();
while (it.hasNext()) {
final AbstractParty party = it.next();
if (type.isInstance(party)) {
if (position) {
((DefaultIndividual) party).setPositionName(name);
} else {
party.setName(name);
}
if (party.isEmpty()) {
it.remove();
}
return true;
}
}
return name == null; // If no party and name is null, there is nothing to set.
}
/**
* Returns the name of the responsible person- surname, given name, title separated by a delimiter.
* Only one of {@code individualName}, {@link #getOrganisationName() organisationName}
* and {@link #getPositionName() positionName} shall be provided.
*
* <p>This implementation returns the name of the first {@code Individual} found in the collection of
* {@linkplain #getParties() parties}. If no individual is found in the parties, then this method fallbacks
* on the first organisation member.</p>
*
* @return name, surname, given name and title of the responsible person, or {@code null}.
*
* @deprecated As of ISO 19115:2014, replaced by {@code getName()} in {@link DefaultIndividual}.
*/
@Override
@Deprecated
@Dependencies("getParties")
@XmlElement(name = "individualName")
public String getIndividualName() {
final InternationalString name = getIndividual(false);
return (name != null) ? name.toString() : null;
}
/**
* Sets the name of the responsible person- surname, given name, title separated by a delimiter.
* Only one of {@code individualName}, {@link #getOrganisationName() organisationName}
* and {@link #getPositionName() positionName} shall be provided.
*
* <p>This implementation sets the name of the first {@code Individual} found in the collection of
* {@linkplain #getParties() parties}, or create a new individual if no existing instance was found.</p>
*
* @param newValue the new individual name, or {@code null} if none.
*
* @deprecated As of ISO 19115:2014, replaced by {@code setName(InternationalString)} in {@link DefaultIndividual}.
*/
@Deprecated
public void setIndividualName(final String newValue) {
if (!setName(DefaultIndividual.class, false, Types.toInternationalString(newValue))) {
getParties().add(new DefaultIndividual(newValue, null, null));
}
}
/**
* Returns the name of the responsible organization. Only one of
* {@link #getIndividualName() individualName}, {@code organisationName}
* and {@link #getPositionName() positionName} shall be provided.
*
* <p>This implementation returns the name of the first {@code Organisation}
* found in the collection of {@linkplain #getParties() parties}.</p>
*
* @return name of the responsible organization, or {@code null}.
*
* @deprecated As of ISO 19115:2014, replaced by {@code getName()} in {@link DefaultOrganisation}.
*/
@Override
@Deprecated
@XmlElement(name = "organisationName")
@Dependencies("getParties")
public InternationalString getOrganisationName() {
return getName(getParties(), DefaultOrganisation.class, false);
}
/**
* Sets the name of the responsible organization. Only one of
* {@link #getIndividualName() individualName}, {@code organisationName}
* and {@link #getPositionName() positionName} shall be provided.
*
* <p>This implementation sets the name of the first {@code Organisation} found in the collection of
* {@linkplain #getParties() parties}, or create a new organization if no existing instance was found.</p>
*
* @param newValue the new organization name, or {@code null} if none.
*
* @deprecated As of ISO 19115:2014, replaced by {@code setName(InternationalString)} in {@link DefaultOrganisation}.
*/
@Deprecated
public void setOrganisationName(final InternationalString newValue) {
if (!setName(DefaultOrganisation.class, false, Types.toInternationalString(newValue))) {
getParties().add(new DefaultOrganisation(newValue, null, null, null));
}
}
/**
* Returns the role or position of the responsible person Only one of
* {@link #getIndividualName() individualName}, {@link #getOrganisationName() organisationName}
* and {@code positionName} shall be provided.
*
* <p>This implementation returns the position of the first {@code Individual} found in the collection of
* {@linkplain #getParties() parties}. If no individual is found in the parties, then this method fallbacks
* on the first organisation member.</p>
*
* @return role or position of the responsible person, or {@code null}
*
* @deprecated As of ISO 19115:2014, replaced by {@link DefaultIndividual#getPositionName()}.
*/
@Override
@Deprecated
@XmlElement(name = "positionName")
@Dependencies("getParties")
public InternationalString getPositionName() {
return getIndividual(true);
}
/**
* set the role or position of the responsible person Only one of
* {@link #getIndividualName() individualName}, {@link #getOrganisationName() organisationName}
* and {@code positionName} shall be provided.
*
* <p>This implementation sets the position name of the first {@code Individual} found in the collection of
* {@linkplain #getParties() parties}, or create a new individual if no existing instance was found.</p>
*
* @param newValue the new position name, or {@code null} if none.
*
* @deprecated As of ISO 19115:2014, replaced by {@link DefaultIndividual#setPositionName(InternationalString)}.
*/
@Deprecated
public void setPositionName(final InternationalString newValue) {
if (!setName(DefaultIndividual.class, true, newValue)) {
getParties().add(new DefaultIndividual(null, newValue, null));
}
}
/**
* Returns the address of the responsible party.
*
* <p>This implementation returns the first non-null contact found in the collection of
* {@linkplain #getParties() parties}.</p>
*
* @return address of the responsible party, or {@code null}.
*
* @deprecated As of ISO 19115:2014, replaced by {@link AbstractParty#getContactInfo()}.
*/
@Override
@Deprecated
@XmlElement(name = "contactInfo")
@Dependencies("getParties")
public Contact getContactInfo() {
final Collection<AbstractParty> parties = getParties();
if (parties != null) { // May be null on marshalling.
for (final AbstractParty party : parties) {
final Collection<? extends Contact> contacts = party.getContactInfo();
if (contacts != null) { // May be null on marshalling.
for (final Contact contact : contacts) {
if (contact != null) { // Paranoiac check.
return contact;
}
}
}
}
}
return null;
}
/**
* Sets the address of the responsible party.
*
* <p>This implementation sets the contact info in the first party found in the collection of
* {@linkplain #getParties() parties}.</p>
*
* @param newValue the new contact info, or {@code null} if none.
*
* @deprecated As of ISO 19115:2014, replaced by {@link AbstractParty#setContactInfo(Collection)}.
*/
@Deprecated
public void setContactInfo(final Contact newValue) {
checkWritePermission(valueIfDefined(super.getParties()));
final Iterator<AbstractParty> it = getParties().iterator();
while (it.hasNext()) {
final AbstractParty party = it.next();
party.setContactInfo(newValue != null ? Collections.singleton(newValue) : null);
if (party.isEmpty()) {
it.remove();
}
return;
}
/*
* If no existing AbstractParty were found, add a new one. However there is no way to know if
* it should be an individual or an organization. Arbitrarily choose an individual for now.
*/
if (newValue != null) {
getParties().add(new DefaultIndividual(null, null, newValue));
}
}
/**
* Returns the function performed by the responsible party.
*
* @return function performed by the responsible party.
*/
@Override
@XmlElement(name = "role", required = true)
public Role getRole() {
return super.getRole();
}
/**
* Sets the function performed by the responsible party.
*
* @param newValue the new role.
*/
@Override
public void setRole(final Role newValue) {
super.setRole(newValue);
}
}