org.sigmah.server.dao.impl.FileHibernateDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.sigmah.server.dao.impl.FileHibernateDAO.java

Source

package org.sigmah.server.dao.impl;

/*
 * #%L
 * Sigmah
 * %%
 * Copyright (C) 2010 - 2016 URD
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.apache.commons.collections4.CollectionUtils;
import org.sigmah.client.util.ClientUtils;
import org.sigmah.server.dao.FileDAO;
import org.sigmah.server.dao.base.AbstractDAO;
import org.sigmah.server.dispatch.impl.UserDispatch;
import org.sigmah.server.domain.User;
import org.sigmah.server.domain.element.FlexibleElement;
import org.sigmah.server.domain.value.File;
import org.sigmah.server.domain.value.FileVersion;
import org.sigmah.server.domain.value.Value;
import org.sigmah.shared.dto.value.FileDTO.LoadingScope;
import org.sigmah.shared.dto.value.FileUploadUtils;
import org.sigmah.shared.util.ValueResultUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.persist.Transactional;
import static org.sigmah.shared.util.ValueResultUtils.normalizeFileName;

/**
 * {@link FileDAO} implementation.
 * 
 * @author Denis Colliot (dcolliot@ideia.fr) (v2.0)
 */
public class FileHibernateDAO extends AbstractDAO<File, Integer> implements FileDAO {

    /**
     * Logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(UserDispatch.class);

    /**
     * {@inheritDoc}
     */
    @Override
    public List<FileVersion> findVersions(final Collection<Integer> filesIds, LoadingScope loadingScope) {

        if (CollectionUtils.isEmpty(filesIds)) {
            throw new IllegalArgumentException("Invalid files ids collection.");
        }

        if (loadingScope == null) {
            loadingScope = LoadingScope.LAST_VERSION;
        }

        // NOTE : StringBuilder has been removed here since all the strings used here are constants.
        final String request;

        switch (loadingScope) {
        case ALL_VERSIONS:
            // Retrieves all versions of each file.
            request = "SELECT " + "  fv " + "FROM " + "  File f INNER JOIN f.versions fv " + "WHERE "
                    + "  f.id IN (:filesIds)";
            break;

        case LAST_VERSION:
            // Retrieves only the last version of each file.
            request = "SELECT " + "  fv " + "FROM " + "  File f INNER JOIN f.versions fv " + "WHERE "
                    + "  f.id IN (:filesIds) " + "  AND fv.versionNumber IN ("
                    + "    SELECT max(fv2.versionNumber) FROM FileVersion fv2 WHERE fv2.parentFile = f" + "  )";
            break;

        case LAST_VERSION_FROM_NOT_DELETED_FILES:
            // Retrieves only the last version of each file if the file has not been deleted.
            request = "SELECT " + "  fv " + "FROM " + "  File f INNER JOIN f.versions fv " + "WHERE "
                    + "  f.id IN (:filesIds) " + "  AND f.dateDeleted IS NULL " + "  AND fv.versionNumber IN ("
                    + "    SELECT max(fv2.versionNumber) FROM FileVersion fv2 WHERE fv2.parentFile = f" + "  )";
            break;

        default:
            throw new IllegalArgumentException("Invalid file versions loading mode.");
        }

        final TypedQuery<FileVersion> query = em().createQuery(request, FileVersion.class);
        query.setParameter("filesIds", filesIds);

        return query.getResultList();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FileVersion getVersion(final Integer versionId) {

        final TypedQuery<FileVersion> query = em().createQuery("SELECT fv FROM FileVersion fv WHERE fv.id = :id",
                FileVersion.class);
        query.setParameter("id", versionId);

        return query.getSingleResult();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FileVersion getLastVersion(Integer fileId) {

        final TypedQuery<FileVersion> query = em().createQuery(
                "SELECT fv FROM FileVersion fv WHERE fv.parentFile.id = :fileId ORDER BY fv.versionNumber DESC",
                FileVersion.class);

        query.setParameter("fileId", fileId);
        query.setMaxResults(1);

        return query.getSingleResult();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Integer saveOrUpdate(final Map<String, String> properties, final String physicalName, final int size) {

        // Uploaded file's id.
        Integer id = ClientUtils.asInt(properties.get(FileUploadUtils.DOCUMENT_ID));

        // Author id.
        final int authorId = ClientUtils.asInt(properties.get(FileUploadUtils.DOCUMENT_AUTHOR), 0);

        try {

            if (id == null) {
                // New file (first version).
                id = saveNewFile(properties, physicalName, size, authorId);

            } else {
                // New version.
                id = saveNewVersion(properties, physicalName, size, id, authorId);
            }

        } catch (IOException e) {
            final String name = properties.get(FileUploadUtils.DOCUMENT_NAME);
            throw new IllegalStateException("Error while trying to save the file '" + name + "' (id #" + id
                    + ") for author #" + authorId + ".", e);
        }

        return id;
    }

    /**
     * Saves a new file.
     * 
     * @param properties
     *          The properties map of the uploaded file (see {@link FileUploadUtils}).
     * @param physicalName
     *          The uploaded file content.
     * @param size
     *          Size of the uploaded file.
     * @param authorId
     *          The author id.
     * @return The id of the just saved file.
     * @throws IOException
     */
    @Transactional
    protected Integer saveNewFile(Map<String, String> properties, String physicalName, int size, int authorId)
            throws IOException {

        final EntityManager em = em();

        LOGGER.debug("[saveNewFile] New file.");

        // --------------------------------------------------------------------
        // STEP 1 : saves the file.
        // --------------------------------------------------------------------
        LOGGER.debug("[saveNewFile] Saves the new file.");
        final File file = new File();

        // Gets the details of the name of the file.
        final String fullName = ValueResultUtils.normalizeFileName(properties.get(FileUploadUtils.DOCUMENT_NAME));
        final int index = fullName.indexOf('.');

        final String name = index > 0 ? fullName.substring(0, index) : fullName;
        final String extension = index > 0 && index < fullName.length() ? fullName.substring(index + 1) : null;

        file.setName(name);

        // Creates and adds the new version.
        file.addVersion(createVersion(1, name, extension, authorId, physicalName, size));

        em.persist(file);

        // --------------------------------------------------------------------
        // STEP 2 : gets the current value for this list of files.
        // --------------------------------------------------------------------

        // Element id.
        final int elementId = ClientUtils.asInt(properties.get(FileUploadUtils.DOCUMENT_FLEXIBLE_ELEMENT), 0);

        // Project id.
        final int projectId = ClientUtils.asInt(properties.get(FileUploadUtils.DOCUMENT_PROJECT), 0);

        // Retrieving the current value
        final TypedQuery<Value> query = em.createQuery(
                "SELECT v FROM Value v WHERE v.containerId = :projectId and v.element.id = :elementId",
                Value.class);
        query.setParameter("projectId", projectId);
        query.setParameter("elementId", elementId);

        Value currentValue = null;

        try {
            currentValue = query.getSingleResult();
        } catch (NoResultException nre) {
            // No current value
        }

        // --------------------------------------------------------------------
        // STEP 3 : creates or updates the value with the new file id.
        // --------------------------------------------------------------------

        // The value already exists, must update it.
        if (currentValue != null) {
            currentValue.setLastModificationAction('U');

            // Sets the value (adds a new file id).
            currentValue.setValue(currentValue.getValue() + ValueResultUtils.DEFAULT_VALUE_SEPARATOR
                    + String.valueOf(file.getId()));
        }
        // The value for this list of files doesn't exist already, must
        // create it.
        else {
            currentValue = new Value();

            // Creation of the value
            currentValue.setLastModificationAction('C');

            // Parent element
            final FlexibleElement element = em.find(FlexibleElement.class, elementId);
            currentValue.setElement(element);

            // Container
            currentValue.setContainerId(projectId);

            // Sets the value (one file id).
            currentValue.setValue(String.valueOf(file.getId()));
        }

        // Modifier
        final User user = em.find(User.class, authorId);
        currentValue.setLastModificationUser(user);

        // Last update date
        currentValue.setLastModificationDate(new Date());

        // Saves or updates the new value.
        em.merge(currentValue);

        return file.getId();
    }

    /**
     * Saves a new file.
     * 
     * @param properties
     *          The properties map of the uploaded file (see {@link FileUploadUtils}).
     * @param physicalName
     *          The uploaded file content.
     * @param size
     *          Size of the uploaded file.
     * @param id
     *          The file which gets a new version.
     * @param authorId
     *          The author id.
     * @return The file id (must be the same as the parameter).
     * @throws IOException
     */
    @Transactional
    protected Integer saveNewVersion(Map<String, String> properties, String physicalName, int size, Integer id,
            int authorId) throws IOException {

        final EntityManager em = em();

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("[save] New file version.");
        }

        // Gets the details of the name of the file.
        final String fullName = normalizeFileName(properties.get(FileUploadUtils.DOCUMENT_NAME));
        final int index = fullName.indexOf('.');

        final String name = index > 0 ? fullName.substring(0, index) : fullName;
        final String extension = index > 0 && index < fullName.length() ? fullName.substring(index + 1) : null;

        // Creates and adds the new version.
        final File file = em.find(File.class, Integer.valueOf(id));

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("[save] Found file: " + file.getName() + ".");
        }

        Integer versionNumber;

        Query query = em.createQuery(
                "SELECT max(fv.versionNumber)+1 AS newVersionNumber FROM FileVersion AS fv WHERE parentFile=:parentFile");
        query.setParameter("parentFile", file);
        versionNumber = (Integer) query.getSingleResult();
        if (versionNumber == null) {
            versionNumber = 0;
        }

        final FileVersion version = createVersion(versionNumber, name, extension, authorId, physicalName, size);
        version.setComments(properties.get(FileUploadUtils.DOCUMENT_COMMENTS));
        file.addVersion(version);

        em.persist(file);

        return file.getId();
    }

    /**
     * Creates a file version with the given number and author.
     * 
     * @param versionNumber
     *          The version number.
     * @param name
     *          The version name.
     * @param extension
     *          The version extension.
     * @param authorId
     *          The author id.
     * @param content
     *          The version content.
     * @return The version just created.
     * @throws IOException
     */
    private static FileVersion createVersion(int versionNumber, String name, String extension, int authorId,
            String physicalName, int size) throws IOException {

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("[createVersion] Creates a new file version # + " + versionNumber + ".");
        }

        final FileVersion version = new FileVersion();

        // Sets attributes.
        version.setVersionNumber(versionNumber);
        version.setName(name);
        version.setExtension(extension);
        version.setAddedDate(new Date());
        version.setSize((long) size);
        final User user = new User();
        user.setId(authorId);
        version.setAuthor(user);

        // Saves content.
        version.setPath(physicalName);

        return version;
    }

}