org.duracloud.duradmin.util.SpaceUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.duracloud.duradmin.util.SpaceUtil.java

Source

/*
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 *     http://duracloud.org/license/
 */
package org.duracloud.duradmin.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.duracloud.client.ContentStore;
import org.duracloud.common.constant.Constants;
import org.duracloud.common.model.AclType;
import org.duracloud.common.util.TagUtil;
import org.duracloud.common.web.EncodeUtil;
import org.duracloud.domain.Content;
import org.duracloud.duradmin.config.DuradminConfig;
import org.duracloud.duradmin.domain.Acl;
import org.duracloud.duradmin.domain.ContentItem;
import org.duracloud.duradmin.domain.ContentProperties;
import org.duracloud.duradmin.domain.Space;
import org.duracloud.duradmin.domain.SpaceProperties;
import org.duracloud.error.ContentStateException;
import org.duracloud.error.ContentStoreException;
import org.duracloud.security.impl.DuracloudUserDetails;
import org.duracloud.storage.domain.StorageProviderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

/**
 * Provides utility methods for spaces.
 *
 * @author Bill Branan
 */
public class SpaceUtil {

    private static Logger log = LoggerFactory.getLogger(SpaceUtil.class);

    private SpaceUtil() {
        // Ensures no instances are made of this class, as there are only static members.
    }

    public static Space populateSpace(Space space, org.duracloud.domain.Space cloudSpace, ContentStore contentStore,
            Authentication authentication) throws ContentStoreException {
        space.setSpaceId(cloudSpace.getId());
        space.setProperties(getSpaceProperties(cloudSpace.getProperties()));
        space.setStreamingEnabled(StringUtils.isNotBlank(space.getProperties().getStreamingHost()));
        space.setHlsEnabled(StringUtils.isNotBlank(space.getProperties().getHlsStreamingHost()));

        space.setExtendedProperties(cloudSpace.getProperties());
        space.setContents(cloudSpace.getContentIds());
        Map<String, AclType> spaceAcls = contentStore.getSpaceACLs(cloudSpace.getId());
        space.setAcls(toAclList(spaceAcls));

        if (isAdmin(authentication) && isSnapshotProvider(contentStore)
                && isSnapshotInProgress(contentStore, space.getSpaceId())) {
            space.setSnapshotInProgress(true);
        }

        AclType callerAcl = resolveCallerAcl(space.getSpaceId(), contentStore, spaceAcls, authentication,
                space.isSnapshotInProgress());

        String aclName = null;
        if (null != callerAcl) {
            aclName = callerAcl.name();
        }
        space.setCallerAcl(aclName);

        space.setMillDbEnabled(DuradminConfig.isMillDbEnabled());

        return space;
    }

    private static SpaceProperties getSpaceProperties(Map<String, String> spaceProps) {
        SpaceProperties spaceProperties = new SpaceProperties();
        spaceProperties.setCreated(spaceProps.remove(ContentStore.SPACE_CREATED));
        spaceProperties.setCount(spaceProps.remove(ContentStore.SPACE_COUNT));
        spaceProperties.setSize(spaceProps.remove(ContentStore.SPACE_SIZE));
        spaceProperties.setTags(TagUtil.parseTags(spaceProps.remove(TagUtil.TAGS)));
        spaceProperties.setStreamingHost(spaceProps.get(ContentStore.STREAMING_HOST));
        spaceProperties.setStreamingType(spaceProps.get(ContentStore.STREAMING_TYPE));
        spaceProperties.setHlsStreamingHost(spaceProps.get(ContentStore.HLS_STREAMING_HOST));
        spaceProperties.setHlsStreamingType(spaceProps.get(ContentStore.HLS_STREAMING_TYPE));

        spaceProperties.setSnapshotId(spaceProps.get(Constants.SNAPSHOT_ID_PROP));

        String restoreId = spaceProps.get(Constants.RESTORE_ID_PROP);
        if (StringUtils.isNotBlank(restoreId)) {
            spaceProperties.setRestoreId(restoreId);
        }

        return spaceProperties;
    }

    public static void populateContentItem(String duradminBaseURL, ContentItem contentItem, String spaceId,
            String contentId, ContentStore store, Authentication authentication) throws ContentStoreException {
        contentItem.setSpaceId(spaceId);
        contentItem.setContentId(contentId);
        contentItem.setStoreId(store.getStoreId());
        Map<String, String> contentProperties = store.getContentProperties(spaceId, contentId);
        ContentProperties properties = populateContentProperties(contentProperties);
        contentItem.setProperties(properties);
        contentItem.setExtendedProperties(contentProperties);
        contentItem.setDurastoreURL(formatDurastoreURL(contentItem, store));
        Map<String, AclType> acls = store.getSpaceACLs(spaceId);
        contentItem.setAcls(toAclList(acls));
        AclType callerAcl = resolveCallerAcl(spaceId, store, acls, authentication);

        String aclName = null;
        if (null != callerAcl) {
            aclName = callerAcl.name();
        }
        contentItem.setCallerAcl(aclName);
        contentItem.setImageViewerBaseURL(null);
    }

    private static String formatDurastoreURL(ContentItem contentItem, ContentStore store) {
        String pattern = "{0}/{1}/{2}?storeID={3}";
        return MessageFormat.format(pattern,
                // NOTE: The https --> http swap is required by the Djatoka SimpleListResolver,
                //       see: http://sourceforge.net/apps/mediawiki/djatoka/index.php?title=Installation#Configure_a_Referent_Resolver
                //       https is not supported.
                store.getBaseURL().replace("https", "http"), contentItem.getSpaceId(),
                EncodeUtil.urlEncode(contentItem.getContentId()), store.getStoreId());
    }

    private static ContentProperties populateContentProperties(Map<String, String> contentProperties) {
        ContentProperties properties = new ContentProperties();
        properties.setMimetype(contentProperties.remove(ContentStore.CONTENT_MIMETYPE));
        properties.setSize(contentProperties.remove(ContentStore.CONTENT_SIZE));
        properties.setChecksum(contentProperties.remove(ContentStore.CONTENT_CHECKSUM));
        properties.setModified(contentProperties.remove(ContentStore.CONTENT_MODIFIED));
        properties.setTags(TagUtil.parseTags(contentProperties.remove(TagUtil.TAGS)));

        return properties;
    }

    public static void streamContent(ContentStore store, HttpServletResponse response, String spaceId,
            String contentId) throws ContentStoreException, IOException {
        Content c = store.getContent(spaceId, contentId);
        Map<String, String> m = store.getContentProperties(spaceId, contentId);
        String mimetype = m.get(ContentStore.CONTENT_MIMETYPE);
        String contentLength = m.get(ContentStore.CONTENT_SIZE);
        try (InputStream is = c.getStream()) {
            streamToResponse(is, response, mimetype, contentLength);
        }
    }

    public static void streamToResponse(InputStream is, HttpServletResponse response, String mimetype,
            String contentLength) throws ContentStoreException, IOException {

        OutputStream outStream = response.getOutputStream();

        try {
            response.setContentType(mimetype);

            if (contentLength != null) {
                response.setContentLengthLong(Long.parseLong(contentLength));
            }
            byte[] buf = new byte[1024];
            int read = -1;
            while ((read = is.read(buf)) > 0) {
                outStream.write(buf, 0, read);
            }

            response.flushBuffer();
        } catch (Exception ex) {
            if (ex.getCause() instanceof ContentStateException) {
                response.reset();
                response.setStatus(HttpStatus.SC_CONFLICT);
                String message = "The requested content item is currently in long-term storage"
                        + " with limited retrieval capability. Please contact "
                        + "DuraCloud support (https://wiki.duraspace.org/x/6gPNAQ) "
                        + "for assistance in retrieving this content item.";
                //It is necessary to pad the message in order to force Internet Explorer to
                //display the server sent text rather than display the browser default error message.
                //If the message is less than 512 bytes, the browser will ignore the message.
                //c.f. http://support.microsoft.com/kb/294807
                message += StringUtils.repeat(" ", 512);
                outStream.write(message.getBytes());
            } else {
                throw ex;
            }
        } finally {
            try {
                outStream.close();
            } catch (Exception e) {
                log.warn("failed to close outputstream ( " + outStream + "): message=" + e.getMessage(), e);
            }
        }
    }

    public static AclType resolveCallerAcl(String spaceId, ContentStore store, Map<String, AclType> acls,
            Authentication authentication) throws ContentStoreException {
        return resolveCallerAcl(spaceId, store, acls, authentication, null);
    }

    public static AclType resolveCallerAcl(String spaceId, ContentStore store, Map<String, AclType> acls,
            Authentication authentication, Boolean snapshotInProgress) throws ContentStoreException {
        //if a snapshot is in progress, read only
        // check authorities
        if (isRoot(authentication)) {
            return AclType.WRITE;
        }

        if (snapshotInProgress == null) {
            snapshotInProgress = false;
            if (isSnapshotProvider(store)) {
                snapshotInProgress = isSnapshotInProgress(store, spaceId);
            }
        }

        if (spaceId.equals(Constants.SNAPSHOT_METADATA_SPACE)) {
            return AclType.READ;
        }

        if (snapshotInProgress) {
            return AclType.READ;
        }
        // check authorities
        if (isAdmin(authentication)) {
            return AclType.WRITE;
        }

        AclType callerAcl = null;

        DuracloudUserDetails details = (DuracloudUserDetails) authentication.getPrincipal();
        List<String> userGroups = details.getGroups();

        for (Map.Entry<String, AclType> e : acls.entrySet()) {
            AclType value = e.getValue();

            if (e.getKey().equals(details.getUsername()) || userGroups.contains(e.getKey())) {
                callerAcl = value;
                if (AclType.WRITE.equals(callerAcl)) {
                    break;
                }
            }
        }

        return callerAcl;
    }

    private static boolean isSnapshotInProgress(ContentStore store, String spaceId) throws ContentStoreException {
        return store.getSpaceProperties(spaceId).containsKey(Constants.SNAPSHOT_ID_PROP);
    }

    protected static boolean isSnapshotProvider(ContentStore store) {
        String providerType = store.getStorageProviderType();
        return providerType.equals(StorageProviderType.CHRONOPOLIS.name());
    }

    public static boolean isAdmin(Authentication authentication) {
        return hasRole(authentication, "ROLE_ADMIN");
    }

    private static boolean isRoot(Authentication authentication) {
        return hasRole(authentication, "ROLE_ROOT");
    }

    protected static boolean hasRole(Authentication authentication, String role) {
        Collection authorities = authentication.getAuthorities();
        for (Object a : authorities) {
            if (((GrantedAuthority) a).getAuthority().equals(role)) {
                return true;
            }
        }
        return false;
    }

    public static List<Acl> toAclList(Map<String, AclType> spaceACLs) {
        List<Acl> acls = new LinkedList<Acl>();

        if (spaceACLs != null) {
            for (Map.Entry<String, AclType> entry : spaceACLs.entrySet()) {
                String key = entry.getKey();
                AclType value = entry.getValue();
                boolean read = false;
                boolean write = false;
                if (value.equals(AclType.READ)) {
                    read = true;
                } else if (value.equals(AclType.WRITE)) {
                    read = true;
                    write = true;
                }

                acls.add(new Acl(key, formatAclDisplayName(key), read, write));
            }
        }

        sortAcls(acls);
        return acls;

    }

    private static final Comparator<Acl> ACL_COMPARATOR = new Comparator<Acl>() {
        private String groupPrefix = "group-";

        @Override
        public int compare(Acl o1, Acl o2) {
            if (o1.name.equals(o2.name)) {
                return 0;
            }

            if (o1.isPublicGroup()) {
                return -1;
            }

            if (o2.isPublicGroup()) {
                return 1;
            }

            if (o1.name.startsWith(groupPrefix)) {
                return !o2.name.startsWith(groupPrefix) ? -1 : o1.name.compareToIgnoreCase(o2.name);
            } else {
                return o2.name.startsWith(groupPrefix) ? 1 : o1.name.compareToIgnoreCase(o2.name);
            }
        }

    };

    public static void sortAcls(List<Acl> acls) {
        Collections.sort(acls, ACL_COMPARATOR);
    }

    public static String formatAclDisplayName(String key) {
        String prefix = "group-";
        if (key.startsWith(prefix)) {
            return key.replaceFirst(prefix, "");
        }

        return key;
    }

}