sgf.gateway.model.metadata.DatasetImpl.java Source code

Java tutorial

Introduction

Here is the source code for sgf.gateway.model.metadata.DatasetImpl.java

Source

package sgf.gateway.model.metadata;

import org.apache.commons.collections.collection.UnmodifiableCollection;
import org.apache.commons.collections.list.UnmodifiableList;
import org.apache.commons.collections.map.UnmodifiableMap;
import org.apache.commons.lang.StringUtils;
import org.hibernate.envers.Audited;
import org.hibernate.envers.NotAudited;
import org.hibernate.envers.RelationTargetAuditMode;
import org.springframework.util.Assert;
import sgf.gateway.audit.Auditable;
import sgf.gateway.model.AbstractPersistableEntity;
import sgf.gateway.model.metadata.activities.Activity;
import sgf.gateway.model.metadata.activities.ActivityType;
import sgf.gateway.model.metadata.activities.project.Award;
import sgf.gateway.model.metadata.descriptive.DescriptiveMetadata;
import sgf.gateway.model.metadata.descriptive.Institution;
import sgf.gateway.model.metadata.factory.SoftwarePropertiesFactory;
import sgf.gateway.model.security.Group;
import sgf.gateway.model.security.Operation;
import sgf.gateway.model.security.Permission;
import sgf.gateway.model.security.Principal;
import sgf.gateway.service.security.impl.acegi.AcegiUtils;
import sgf.gateway.utils.hibernate.CollectionMerger;

import java.io.Serializable;
import java.net.URI;
import java.util.*;

@Audited
public class DatasetImpl extends AbstractPersistableEntity implements LicensedResource, Dataset, Auditable {

    private String authoritativeIdentifier;

    private String shortName;

    private String title;

    private String description;

    private Boolean brokered = Boolean.FALSE;

    private Boolean isVisible = Boolean.TRUE;

    private String doi;

    private String projectGroup;

    @NotAudited
    private Long nestedDatasetCount;

    @NotAudited
    private Dataset parentDataset;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private Dataset predecessorProject;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private Dataset successorProject;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private ContainerType containerType;

    private DescriptiveMetadata descriptiveMetadata;

    private SoftwareProperties softwareProperties;

    @NotAudited
    private MetadataProfile metadataProfile;

    @NotAudited
    private License license;

    private Institution institution;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private DataCenter dataCenter;

    private List<Dataset> nestedDatasetsReference;

    private List<DatasetVersion> datasetVersionsReference;

    @NotAudited
    private Set<Permission> permissions = new HashSet<Permission>();

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private Collection<Topic> topicsReference;

    @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
    private Collection<DataFormat> dataFormatsReference;

    @NotAudited
    private Map<ActivityType, Activity> activitiesReference;

    private List<Award> awards;

    protected DatasetImpl() {
        super(false);
    }

    public DatasetImpl(Serializable identifier, Serializable version) {
        super(identifier, version);
    }

    protected DatasetImpl(boolean createIdentifier) {
        super(createIdentifier);
    }

    /**
     * Constructor to set all immutable properties.
     * <p/>
     * FIXME - Would be better to create a builder for this so this can stay package scope (factory accessible).
     *
     * @param identifier the identifier (required)
     * @param version    the version
     * @param title      the title
     * @param shortName  the short name
     */
    public DatasetImpl(Serializable identifier, Serializable version, String title, String shortName,
            String authoritativeIdentifier) {

        this(identifier, version);

        this.title = title;
        this.shortName = shortName;
        this.topicsReference = new HashSet<Topic>();
        this.dataFormatsReference = new HashSet<DataFormat>();
        this.nestedDatasetsReference = new ArrayList<Dataset>();
        this.datasetVersionsReference = new ArrayList<DatasetVersion>();
        this.activitiesReference = new HashMap<ActivityType, Activity>();
        this.authoritativeIdentifier = authoritativeIdentifier;
        this.awards = new ArrayList<Award>();

        // TODO - Should be setting the dataset state?
        // ANSWER? - If this is a new dataset then yes, I think we should be
        // setting the state to unpublished. NCH 8/6/09
        // Also, the state is being set at attribute declaration above.
    }

    public DatasetImpl(Serializable identifier, Serializable version, String title, String shortName,
            MetadataProfile metadataProfile, String authoritativeIdentifier) {

        this(identifier, version, title, shortName, authoritativeIdentifier);
        this.metadataProfile = metadataProfile;
    }

    /**
     * {@inheritDoc}
     */
    public String getShortName() {

        return this.shortName;
    }

    /**
     * This method is only being using for the DIFMetadataHandler.
     * The logic in this class will need to be refactored in order to avoid use of a setter for short name.
     *
     * @param shortName
     */
    @Deprecated
    public void setShortName(String shortName) {
        this.shortName = shortName;
    }

    protected Dataset getParentDataset() {

        return parentDataset;
    }

    public Dataset getParent() {

        Dataset parent = this.getParentDataset();

        return parent;
    }

    public Integer getIndexOf(Dataset nestedDataset) {

        return this.getNestedDatasetsReference().indexOf(nestedDataset);
    }

    public boolean isTopLevelDataset() {

        boolean result = false;

        if (this.getParentDataset() == null) {

            result = true;
        }

        return result;
    }

    @Override
    public Dataset getRootParentDataset() {

        Dataset rootDataset = null;

        if (this.isTopLevelDataset() == true) {

            return this;
        } else {

            List<Dataset> parentList = this.getParentList();

            for (Dataset parentDataset : parentList) {

                if (parentDataset.isTopLevelDataset() == true) {

                    rootDataset = parentDataset;
                    break;
                }
            }
        }

        return rootDataset;
    }

    protected List<DatasetVersion> getDatasetVersionsReference() {

        return this.datasetVersionsReference;
    }

    public void addDatasetVersion(DatasetVersion datasetVersion) {

        this.getDatasetVersionsReference().add(datasetVersion);
    }

    public Collection<DatasetVersion> getDatasetVersions() {

        return UnmodifiableCollection.decorate(this.getDatasetVersionsReference());
    }

    public DatasetVersion getCurrentDatasetVersion() {

        DatasetVersion result = null;

        List<DatasetVersion> datasetVersionList = new ArrayList<DatasetVersion>(this.getDatasetVersionsReference());

        if (!datasetVersionList.isEmpty()) {

            int size = datasetVersionList.size();

            result = datasetVersionList.get(size - 1);
        }

        return result;
    }

    public DatasetVersion getDatasetVersion(String datasetVersionIdentifier) {

        DatasetVersion datasetVersion = null;

        for (DatasetVersion version : this.getDatasetVersionsReference()) {

            if (datasetVersionIdentifier.equals(version.getVersionIdentifier())) {

                datasetVersion = version;

                break;
            }
        }

        return datasetVersion;
    }

    /**
     * Retrieves the internal dataset list. Proxy safe.
     *
     * @return Internal list of datasets.
     */
    protected List<Dataset> getNestedDatasetsReference() {

        return this.nestedDatasetsReference;
    }

    public Collection<Dataset> getDirectlyNestedDatasets() {

        // FIXME - Why doesn't this work?
        return UnmodifiableList.decorate(this.getNestedDatasetsReference());
    }

    public Long getNestedDatasetCount() {

        Long result;

        if (null == this.nestedDatasetCount) {

            result = new Long(this.getNestedDatasetsReference().size());

        } else {

            result = this.nestedDatasetCount;
        }

        return result;
    }

    /**
     * {@inheritDoc}
     * <p/>
     * Handles all the logic for ensuring that the bidirectional parent child relationship is properly maintained.
     * <p/>
     * TODO - Need to test the alternate cases.
     */
    public final void addChildDataset(Dataset dataset) {

        // Make sure we don't have another copy of this, the storage type
        // may allow for multiple instances of the same type.
        if (this.getNestedDatasetsReference().contains(dataset)) {

            throw new IllegalStateException("Dataset already contains the specified child dataset");
        }

        this.getNestedDatasetsReference().add(dataset);
        ((DatasetImpl) dataset).setParentDataset(this);
    }

    void setParentDataset(Dataset parentDataset) {

        this.parentDataset = parentDataset;
    }

    public final void removeChildDataset(Dataset dataset) {

        List<Dataset> childDatasets = this.getNestedDatasetsReference();

        childDatasets.remove(dataset);
    }

    @Override
    public void orderChildDatasets(final List<Dataset> childDatasets) {

        Collections.sort(this.getNestedDatasetsReference(), new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return Integer.toString(childDatasets.indexOf(o1))
                        .compareTo(Integer.toString(childDatasets.indexOf(o2)));
            }
        });
    }

    //
    // STATE METHODS
    // STATE METHODS
    // STATE METHODS
    //

    /**
     * Returns the raw state value.
     * <p/>
     * In the future this may delegate to a real state implementation.
     *
     * @return the dataset state
     */
    public PublishedState getPublishedState() {

        return this.getCurrentDatasetVersion().getPublishedState();
    }

    public void delete() {

        // Remove this instance from the parent
        if (!isTopLevelDataset()) {

            this.getParent().removeChildDataset(this);
        }
    }

    public boolean isRetracted() {

        return this.getCurrentDatasetVersion().isRetracted();
    }

    public boolean isDeleted() {

        return this.getCurrentDatasetVersion().isDeleted();
    }

    public boolean isPublished() {

        return this.getCurrentDatasetVersion().isPublished();
    }

    public boolean isMetadataOnly() {

        boolean metadataOnly = false;

        if (this.getDirectlyNestedDatasets().isEmpty()
                && this.getCurrentDatasetVersion().getLogicalFiles().isEmpty()) {

            metadataOnly = true;
        }

        return metadataOnly;
    }

    public boolean isBrokered() {

        return this.brokered;
    }

    public void setBrokered(Boolean brokered) {

        this.brokered = brokered;
    }

    public String getAuthoritativeIdentifier() {

        return authoritativeIdentifier;
    }

    public void setAuthoritativeIdentifier(String authoritativeIdentifier) {

        this.authoritativeIdentifier = authoritativeIdentifier;
    }

    @Override
    public Institution getInstitution() {

        return this.institution;
    }

    @Override
    public void setInstitution(Institution newInstitution) {

        this.institution = newInstitution;
    }

    public Boolean isVisible() {

        return isVisible;
    }

    public void setVisible(Boolean isVisible) {

        this.isVisible = isVisible;
    }

    //
    // LOGICAL FILE METHODS
    // LOGICAL FILE METHODS
    // LOGICAL FILE METHODS
    //

    protected Collection<DataFormat> getDataFormatsReference() {

        return this.dataFormatsReference;
    }

    public Collection<DataFormat> getDataFormats() {

        return this.getDataFormatsReference();
    }

    public void addDataFormat(DataFormat newDataFormat) {

        this.getDataFormatsReference().add(newDataFormat);
    }

    @Override
    public void mergeDataFormats(HashSet<DataFormat> newDataFormats) {

        CollectionMerger.mergeCollection(this.getDataFormats(), newDataFormats);
    }

    public void removeDataFormat(DataFormat dataFormatToRemove) {

        if (this.getDataFormatsReference().contains(dataFormatToRemove)) {
            this.getDataFormatsReference().remove(dataFormatToRemove);
        }
    }

    public void removeAllDataFormats() {

        this.getDataFormatsReference().clear();
    }

    //
    // METADATA METHODS
    // METADATA METHODS
    // METADATA METHODS
    //

    public MetadataProfile getMetadataProfile() {

        MetadataProfile theProfile = null;

        if (this.metadataProfile != null) {

            theProfile = this.metadataProfile;

        } else if (this.getParentDataset() != null) {

            theProfile = this.getParentDataset().getMetadataProfile();

        }

        return theProfile;
    }

    public DescriptiveMetadata getDescriptiveMetadata() {

        return descriptiveMetadata;
    }

    public void initializeDescriptiveMetadata(DescriptiveMetadata descriptiveMetadata) {

        // TODO: This method only seems to be called from the
        // DatasetFactoryImpl. Should we maybe consider changing having
        // DescriptiveMetadata
        // as part of the constructor?
        Assert.notNull(descriptiveMetadata, "DescriptiveMetadata cannot be null.");

        if (null != this.getDescriptiveMetadata()) {

            throw new IllegalStateException("Cannot overwrite existing DescriptiveMetadata instance");
        }

        this.descriptiveMetadata = descriptiveMetadata;
    }

    @Override
    public List<Dataset> getParentList() {

        List<Dataset> parentList = new ArrayList<Dataset>();

        this.addParentToList(parentList, this);

        return parentList;
    }

    private void addParentToList(List<Dataset> parentList, Dataset dataset) {

        if (dataset.isTopLevelDataset() == false) {

            Dataset datasetParent = dataset.getParent();

            parentList.add(0, datasetParent);

            this.addParentToList(parentList, datasetParent);
        }
    }

    //
    // ACTIVITY METHODS
    // ACTIVITY METHODS
    // ACTIVITY METHODS
    //

    protected Map<ActivityType, Activity> getActivitiesReference() {

        return this.activitiesReference;
    }

    public void associateActivity(Activity activity) {

        this.getActivitiesReference().put(activity.getActivityType(), activity);
    }

    public void removeActivity(Activity activity) {

        if (this.getActivitiesReference().containsValue(activity)) {

            this.getActivitiesReference().remove(activity.getActivityType());
        }
    }

    public void removeAllActivities() {

        this.getActivitiesReference().clear();
    }

    public Activity getActivity(ActivityType activityType) {

        Activity activity = this.getActivitiesReference().get(activityType);

        if ((activity == null) && (this.getParentDataset() != null)) {
            activity = this.getParentDataset().getActivity(activityType); // recursion
        }

        return activity;
    }

    public Activity getActivity(String activityTypeName) {

        return this.getActivity(ActivityType.valueOf(activityTypeName.toUpperCase()));
    }

    public Map<ActivityType, Activity> getActivities() {

        return UnmodifiableMap.decorate(this.getActivitiesReference());
    }

    public Collection<Activity> getActivityList() {

        return UnmodifiableCollection.decorate(this.getActivitiesReference().values());
    }

    public Collection<Activity> getAllActivities() {

        Set<Activity> completeList = new HashSet<Activity>();

        completeList.addAll(getActivityList());

        // If were not a top level dataset, include the parents
        if (!this.isTopLevelDataset()) {

            completeList.addAll(this.getParentDataset().getAllActivities());
        }

        return UnmodifiableCollection.decorate(completeList);
    }

    protected int getInheritedActivityListCount() {

        int result = 0;

        if (!this.isTopLevelDataset()) {
            // FIXME - See if we really need this....
            result = this.getParentDataset().getAllActivities().size();
        }

        return result;
    }

    public boolean getHasAssociatedActivities() {

        int totalCount = getActivityList().size() + getInheritedActivityListCount();

        return (totalCount > 0);
    }

    protected Collection<Topic> getTopicsReference() {

        return this.topicsReference;
    }

    public Collection<Topic> getTopics() {

        return UnmodifiableCollection.decorate(this.getTopicsReference());
    }

    public Collection<Topic> getIsoTopics() {

        Collection<Topic> isoTopics = new HashSet<Topic>();

        Collection<Topic> topics = this.getTopicsReference();

        for (Topic topic : topics) {

            if (Taxonomy.ISO == topic.getType()) {

                isoTopics.add(topic);
            }

        }

        return UnmodifiableCollection.decorate(isoTopics);
    }

    @Override
    public void mergeTopics(Taxonomy taxonomy, HashSet<Topic> newTopics) {

        CollectionMerger.mergeTopicCollection(taxonomy, this.getTopicsReference(), newTopics);
    }

    @Deprecated
    public Collection<Topic> getInheritedTopics() {

        Collection<Topic> allTopics = new HashSet<Topic>(this.getTopicsReference());

        if (this.getParentDataset() != null) {

            allTopics.addAll(this.getParentDataset().getInheritedTopics());
        }

        return UnmodifiableCollection.decorate(allTopics);
    }

    public void addTopic(Topic newTopic) {

        this.getTopicsReference().add(newTopic);
    }

    public void removeTopic(Topic topicToRemove) {

        if (this.getTopicsReference().contains(topicToRemove)) {

            this.getTopicsReference().remove(topicToRemove);
            topicToRemove.removeBackLink(this);
        }
    }

    public void removeAllTopics() {

        this.topicsReference = new HashSet<Topic>();
    }

    /**
     * Method to test whether a Dataset has any associated geophysical properties.
     */
    public boolean isGeophysicalDataset() {

        return !this.isSoftwareDataset();
    }

    // FIXME: This method seem inappropriate, why whould dataset need to call
    // the create method on the softwarPropertiesFactory?
    // There should be a method called setSoftwareProperties(...) that can only
    // be called once or something like that.
    // There is a method similar to this called initalizeDescriptiveMetadata.
    // Maybe we should consider naming it more like that method.
    public SoftwareProperties createSoftwareProperties(SoftwarePropertiesFactory softwarePropertiesFactory) {

        if (this.getSoftwareProperties() == null) {

            this.softwareProperties = softwarePropertiesFactory.create(this);
        }

        return this.softwareProperties;
    }

    public SoftwareProperties getSoftwareProperties() {

        return this.softwareProperties;
    }

    /**
     * Method to test whether a Dataset has any associated software properties.
     */
    public boolean isSoftwareDataset() {

        return this.getSoftwareProperties() != null;
    }

    public boolean isVisualizable() {

        return false;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public DataCenter getDataCenter() {
        return dataCenter;
    }

    public void setDataCenter(DataCenter dataCenter) {
        this.dataCenter = dataCenter;
    }

    public String getDOI() {
        return this.doi;
    }

    public void setDOI(String doi) {
        this.doi = doi;
    }

    public ContainerType getContainerType() {
        return this.containerType;
    }

    public void setContainerType(ContainerType type) {
        this.containerType = type;
    }

    public License getLicense() {
        return this.license;
    }

    public void setLicense(License license) {
        this.license = license;
    }

    @Override
    public String getProjectGroup() {
        return projectGroup;
    }

    public void setProjectGroup(String projectGroup) {
        this.projectGroup = projectGroup;
    }

    //
    // SECURITY METHODS
    // SECURITY METHODS
    // SECURITY METHODS
    //

    /**
     * Method to return the Principals that are allowed to perform an Operation on the given Dataset. Note that this method is recursive.
     *
     * @param operation the operation
     * @return the principals for operation
     */
    @Override
    public Set<Principal> getPrincipalsForOperation(Operation operation) {

        Set<Principal> principals = new HashSet<Principal>();

        for (Permission permission : this.permissions) {
            if (permission.getOperation() == operation) {
                principals.add(permission.getPrincipal());
            }
        }

        if (principals.isEmpty() && (this.getParentDataset() != null)) {
            principals = this.getParentDataset().getPrincipalsForOperation(operation);
        }

        return principals;
    }

    public Set<Principal> getPrincipalsForRead() {
        return this.getPrincipalsForOperation(Operation.READ);
    }

    public void recursivelyAddPermissionToAllDatasets(Principal principal, Operation operation) {
        this.addPermission(principal, operation);
        for (Dataset nested : this.getDirectlyNestedDatasets()) {
            nested.recursivelyAddPermissionToAllDatasets(principal, operation);
        }
    }

    public boolean isReadRestricted() {

        boolean restricted = true;

        // retrieve the set of Principals that are allowed to execute the given Operation on this Dataset

        Set<Principal> principals = this.getPrincipalsForOperation(Operation.READ);

        // check for Guest authorization

        if (principals.size() == 0) {

            // no permissions - does this mean "free"
            // TODO: currently no principals means "no access"
            // restricted = false;
        }
        for (Principal p : principals) {

            if (p.getName().equals(Group.GROUP_GUEST)) {

                restricted = false;

                break;
            }
        }

        return restricted;
    }

    /**
     * Method to reset the {@link Principal}s that can perform the given {@link Operation} on this {@link DatasetImpl}. This method will remove any previous
     * {@link Principal} that is not contained in the given set.
     *
     * @param principals
     * @param operation
     */
    public void setPrincipalsForOperation(Set<Principal> principals, Operation operation) {

        // remove obsolete permissions
        Set<Permission> obsolete = new HashSet<Permission>();
        for (Permission permission : this.getPermissions()) {
            if (permission.getOperation().equals(operation) && !principals.contains(permission.getPrincipal())) {
                obsolete.add(permission);
            }
        }
        this.getPermissions().removeAll(obsolete);

        // add new permissions
        for (Principal principal : principals) {
            this.addPermission(principal, operation);
        }
    }

    @Override
    public int getLogicalFileCount() {
        return getCurrentDatasetVersion().getLogicalFiles().size();
    }

    @Override
    public boolean isDownloadable() {

        boolean hasLogicalFiles = getLogicalFileCount() > 0;
        boolean hasDistributionURI = false;

        URI distributionURI = this.descriptiveMetadata.getDistributionURI();

        if (distributionURI != null) {
            hasDistributionURI = !StringUtils.isBlank(distributionURI.toString());
        }
        return (hasLogicalFiles || hasDistributionURI);
    }

    public Set<Permission> getPermissions() {
        return this.permissions;
    }

    public void setPermissions(Set<Permission> permissions) {
        this.permissions = permissions;
    }

    public void addPermission(Principal principal, Operation operation) {

        boolean foundPermission = false;

        for (Permission permission : this.permissions) {

            if (permission.getPrincipal().equals(principal) && permission.getOperation().equals(operation)) {
                foundPermission = true;
            }
        }

        if (!foundPermission) {
            this.permissions.add(new Permission(this, principal, operation));
        }
    }

    /**
     * Method to return the Groups that are allowed to perform an Operation on the given Resource. Note that this method may is recursive IF the implementation
     * of the getPrincipalsForOperation() for the current object is recursive.
     *
     * @param operation the operation
     * @return the principals for operation
     */
    public Set<Group> getGroupsForOperation(Operation operation) {

        Set<Group> groups = new HashSet<Group>();

        // Note: when applied to Dataset object, principals are looked up the parent hierarchy
        // (note the 'this.' invocation).
        Set<Principal> principals = this.getPrincipalsForOperation(operation);

        for (Principal principal : principals) {
            if (principal instanceof Group) {
                groups.add((Group) principal);
            }
        }

        return groups;
    }

    public Set<Group> getReadGroups() {
        return getGroupsForOperation(Operation.READ);
    }

    public Set<Group> getWriteGroups() {
        return getGroupsForOperation(Operation.WRITE);
    }

    public String getReadGrantingAuthorities() {
        return AcegiUtils.getGrantingAuthorities(this, Operation.READ);
    }

    public String getWriteGrantingAuthorities() {
        String grantees = AcegiUtils.getGrantingAuthorities(this, Operation.WRITE);
        return grantees;
    }

    public Collection<Award> getAwards() {

        return UnmodifiableCollection.decorate(awards);
    }

    public void addAward(String awardNumber) {

        this.awards.add(new Award(awardNumber));
    }

    public Award getAward(String awardNumber) {

        Award award = null;

        for (Award selectedAward : this.awards) {

            if (selectedAward.getAwardNumber().equalsIgnoreCase(awardNumber)) {

                award = selectedAward;
                break;
            }
        }

        return award;
    }

    public void removeAward(Award award) {

        this.awards.remove(award);
    }

    @Override
    public Dataset getPredecessorProject() {
        return predecessorProject;
    }

    @Override
    public void setPredecessorProject(Dataset predecessorProject) {
        this.predecessorProject = predecessorProject;
    }

    @Override
    public Dataset getSuccessorProject() {
        return successorProject;
    }

    @Override
    public void setSuccessorProject(Dataset successorProject) {
        this.successorProject = successorProject;
    }

    @Override
    public Boolean isContainerType(ContainerType containerType) {
        return this.containerType.equals(containerType);
    }
}