com.sastix.cms.server.services.content.impl.CommonResourceServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sastix.cms.server.services.content.impl.CommonResourceServiceImpl.java

Source

/*
 * Copyright(c) 2017 the original author or authors.
 *
 * Licensed 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 com.sastix.cms.server.services.content.impl;

import com.sastix.cms.common.content.ResourceDTO;
import com.sastix.cms.common.content.RevisionDTO;
import com.sastix.cms.common.content.exceptions.ContentValidationException;
import com.sastix.cms.common.content.exceptions.ResourceAccessError;
import com.sastix.cms.server.dataobjects.DataMaps;
import com.sastix.cms.server.domain.entities.Resource;
import com.sastix.cms.server.domain.entities.Revision;
import com.sastix.cms.server.domain.repositories.ResourceRepository;
import com.sastix.cms.server.domain.repositories.RevisionRepository;
import com.sastix.cms.server.services.content.HashedDirectoryService;
import com.sastix.cms.server.services.content.ZipFileHandlerService;
import org.apache.tika.Tika;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

@Service
public class CommonResourceServiceImpl {
    @Autowired
    RevisionRepository revisionRepository;

    @Autowired
    HashedDirectoryService hashedDirectoryService;

    @Autowired
    ResourceRepository resourceRepository;

    @Autowired
    ZipFileHandlerService zipFileHandlerService;

    private final Tika tika = new Tika();

    //TODO: is there a better way for this?
    public Resource cloneResource(Resource r) {
        Resource resource = new Resource();
        resource.setName(r.getName());
        resource.setAuthor(r.getAuthor());
        resource.setMediaType(r.getMediaType());
        resource.setPath(r.getPath());
        resource.setResource(r.getResource());
        resource.setUri(r.getUri());
        //resource.setResources(r.getResources()); //TODO: check org.hibernate.HibernateException: Found shared references to a collection: com.sastix.cms.server.domain.Resource.resources
        resource.setResourceTenantId(r.getResourceTenantId());
        resource.setUid(r.getUid());
        return resource;
    }

    public Revision getLatestRevision(String uid) {
        final List<Revision> revisions = revisionRepository.findRevisions(uid, new PageRequest(0, 1));
        return revisions.isEmpty() ? null : revisions.get(0);
    }

    public ResourceDTO convertToDTO(Resource resource) {
        return convertToDTO(resource, true);
    }

    public ResourceDTO convertToDTO(Resource resource, boolean convertChidren) {
        ResourceDTO resourceDTO = null;
        if (resource != null) {
            resourceDTO = new ResourceDTO();
            resourceDTO.setAuthor(resource.getAuthor());
            resourceDTO.setResourceUID(resource.getUid());
            resourceDTO.setResourceURI(resource.getUri());
            Set<Resource> resources = resource.getResources();
            if (convertChidren && resources != null && resources.size() > 0) {
                List<ResourceDTO> resourceList = new ArrayList<>();
                for (Resource resourceItem : resources) {
                    resourceList.add(createDTO(resourceItem));
                }
                resourceDTO.setResourcesList(resourceList);
            }
        }
        return resourceDTO;
    }

    public RevisionDTO convertToDTO(Revision revision) {
        RevisionDTO resourceDTO = null;
        if (revision != null) {
            resourceDTO = new RevisionDTO(revision.getTitle(), revision.getCreatedAt(),
                    convertToDTO(revision.getResource(), false));
            resourceDTO.setDeletedAt(revision.getDeletedAt());
            resourceDTO.setUpdatedAt(revision.getUpdatedAt());
        }
        return resourceDTO;
    }

    public ResourceDTO createDTO(Resource resource) {
        ResourceDTO resourceDTO = new ResourceDTO();
        resourceDTO.setAuthor(resource.getAuthor());
        resourceDTO.setResourceUID(resource.getUid());
        resourceDTO.setResourceURI(resource.getUri());
        return resourceDTO;
    }

    public String getRelativePath(final String uuri, final String tenantID, final byte[] binary,
            final String binaryURI) throws ContentValidationException, ResourceAccessError {
        //save resource in volume
        String relativePath;
        try {
            if (binary != null && !StringUtils.isEmpty(binaryURI)) {
                throw new ContentValidationException(
                        "Field errors: resourceBinary OR resourceExternalURI should be null");
            } else if (binary != null && binary.length > 0) {
                relativePath = hashedDirectoryService.storeFile(uuri, tenantID, binary);
            } else if (!StringUtils.isEmpty(binaryURI)) {
                relativePath = hashedDirectoryService.storeFile(uuri, tenantID, binaryURI);
            } else {
                throw new ContentValidationException(
                        "Field errors: resourceBinary OR resourceExternalURI may not be null");
            }
        } catch (Exception e) {
            if (e instanceof ContentValidationException) {
                throw (ContentValidationException) e;
            }
            throw new ResourceAccessError(e.toString());
        }
        return relativePath;
    }

    public String updateLocalFile(final String uuri, final String tenantID, final byte[] binary,
            final String binaryURI) throws ContentValidationException, ResourceAccessError {
        //save resource in volume
        String relativePath;
        try {
            if (binary != null && !StringUtils.isEmpty(binaryURI)) {
                throw new ContentValidationException(
                        "Field errors: resourceBinary OR resourceExternalURI should be null");
            } else if (binary != null && binary.length > 0) {
                relativePath = hashedDirectoryService.replaceFile(uuri, tenantID, binary);
            } else if (!StringUtils.isEmpty(binaryURI)) {
                relativePath = hashedDirectoryService.replaceFile(uuri, tenantID, binaryURI);
            } else {
                throw new ContentValidationException(
                        "Field errors: resourceBinary OR resourceExternalURI may not be null");
            }
        } catch (Exception e) {
            if (e instanceof ContentValidationException) {
                throw (ContentValidationException) e;
            }
            throw new ResourceAccessError(e.toString());
        }
        return relativePath;
    }

    public AnalyzedZipResource analyzeZipFile(String context, String resourceURI, Resource zipResource) {
        byte[] insertedBytes;
        DataMaps modifiedDataMaps = null;
        List<ResourceDTO> resourceDTOList = new ArrayList<>();
        String startPage = null;
        String scormLandingPage = null;
        Resource parentResource = null;
        boolean isScormType = false;
        boolean isResourceWithStartPage = false;
        try {
            //get the zip bytes inserted
            insertedBytes = hashedDirectoryService.getBytesByURI(resourceURI, zipResource.getResourceTenantId());
            boolean isZipFile = zipFileHandlerService.isZipFile(insertedBytes);
            if (isZipFile) {
                //unzip it
                DataMaps dataMaps = zipFileHandlerService.unzip(insertedBytes);
                //is a scorm type
                isScormType = zipFileHandlerService.isScormType(dataMaps.getBytesMap());
                //is a cms resource with a startpage
                startPage = zipFileHandlerService.getResourceStartPage(dataMaps.getBytesMap());
                isResourceWithStartPage = !StringUtils.isEmpty(startPage);
                if (isScormType || isResourceWithStartPage) {
                    /**
                     * Keep uid in a map for each resource found in zip
                     * uid: context (uuid of the zip) + filename
                     * eg
                     * 1429362943604-02f29f2a-f8df-4aaf-ad83-e2e65ffa1910-0-zaq12345/css/style.css
                     * */
                    for (Map.Entry<String, byte[]> entry : dataMaps.getBytesMap().entrySet()) {
                        String filename = entry.getKey();

                        String thisResourceURI = context + filename;
                        //String extension = filename.substring(filename.lastIndexOf("."));
                        //String queryParams = filename.indexOf("?") > 0 ? "&" + filename.substring(filename.indexOf("?")) : "";
                        //String cpath = GET_DATA_DOMAIN + "?uid=" + uuid + extension + queryParams;
                        dataMaps.getUriMap().put(filename, thisResourceURI);
                        //dataMaps.getUidPathMap().put(filename, cpath);
                    }

                    /**
                     * Replace urls in resources
                     * */
                    //modifiedDataMaps = zipFileHandlerService.replaceRelativePaths(dataMaps);
                }

                //find parent
                String parentFilename = zipFileHandlerService.findParentResource(dataMaps.getBytesMap());
                if (isResourceWithStartPage) {
                    parentFilename = startPage;
                }

                //first insert the parent file
                String parentUri = dataMaps.getUriMap().get(parentFilename);
                byte[] parentData = dataMaps.getBytesMap().get(parentFilename);
                parentResource = insertResource(parentUri, parentData, parentFilename, zipResource.getAuthor(),
                        zipResource.getResourceTenantId(), zipResource);
                //                resourceDTOList.add(this.convertToDTO(parentResource));

                //insert exploded resources
                for (Map.Entry<String, byte[]> entry : dataMaps.getBytesMap().entrySet()) {
                    String filename = entry.getKey();
                    if (!filename.equals(parentFilename)) {//we do not want to add the parent file twice
                        String uid = dataMaps.getUriMap().get(filename);
                        byte[] data = entry.getValue();
                        byte[] modifiedData = dataMaps.getBytesMap().get(filename);
                        //check if it is modified
                        if (modifiedData != null) {
                            data = modifiedData;
                        }

                        //insert
                        Resource resourceDTO = insertResource(uid, data, filename, zipResource.getAuthor(),
                                zipResource.getResourceTenantId(), parentResource);
                        resourceDTOList.add(this.convertToDTO(resourceDTO));
                    }
                }

            }
        } catch (IOException e) {
            throw new ResourceAccessError(e.toString());
        }

        AnalyzedZipResource analyzedZipResource = new AnalyzedZipResource(
                resourceDTOList.isEmpty() ? null : resourceDTOList, startPage);
        analyzedZipResource.setParentID(parentResource != null ? parentResource.getId() : null);
        return analyzedZipResource;
    }

    private Resource insertResource(String uri, byte[] data, String filename, String author, String tenantId,
            Resource parentResource) {
        // Save resource
        Resource persistedResource = new Resource();
        String mediaType = tika.detect(data);
        persistedResource.setMediaType(mediaType == null ? "unknown" : mediaType);
        persistedResource.setAuthor(author);
        persistedResource.setUri(uri);

        //save resource in volume
        String relativePath;
        try {
            if (data != null && data.length > 0) {
                relativePath = hashedDirectoryService.storeFile(uri, tenantId, data);
            } else {
                throw new ContentValidationException("Field errors: resourceBinary may not be null");
            }
        } catch (Exception e) {
            if (e instanceof ContentValidationException) {
                throw (ContentValidationException) e;
            }
            throw new ResourceAccessError(e.toString());
        }

        persistedResource.setPath(relativePath);
        persistedResource.setName(filename);
        persistedResource.setUid(hashedDirectoryService.hashText(uri));
        persistedResource.setResourceTenantId(tenantId);
        persistedResource.setResource(parentResource);
        persistedResource = resourceRepository.save(persistedResource);
        // Save revision
        Revision persistedRevision = new Revision();
        persistedRevision.setCreatedAt(new Date());
        persistedRevision.setTitle(DateTime.now().toString()); //TODO: what kind of title should we store? It is not described in specs
        persistedRevision.setResource(persistedResource);
        persistedRevision.setParentResource(parentResource);
        revisionRepository.save(persistedRevision);
        return persistedResource;
    }

    public class AnalyzedZipResource {
        List<ResourceDTO> resourceDTOs;
        String startPage;
        Integer parentID;

        public AnalyzedZipResource(List<ResourceDTO> resourceDTOs, String startPage) {
            this.resourceDTOs = resourceDTOs;
            this.startPage = startPage;
        }

        public List<ResourceDTO> getResourceDTOs() {
            return resourceDTOs;
        }

        public void setResourceDTOs(List<ResourceDTO> resourceDTOs) {
            this.resourceDTOs = resourceDTOs;
        }

        public String getStartPage() {
            return startPage;
        }

        public void setStartPage(String startPage) {
            this.startPage = startPage;
        }

        public Integer getParentID() {
            return parentID;
        }

        public void setParentID(Integer parentID) {
            this.parentID = parentID;
        }
    }
}