org.silverpeas.attachment.web.SimpleDocumentResource.java Source code

Java tutorial

Introduction

Here is the source code for org.silverpeas.attachment.web.SimpleDocumentResource.java

Source

/**
 * Copyright (C) 2000 - 2013 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of the GPL, you may
 * redistribute this Program in connection with Free/Libre Open Source Software ("FLOSS")
 * applications as described in Silverpeas's FLOSS exception. You should have received a copy of the
 * text describing the FLOSS exception, and it is also available here:
 * "http://www.silverpeas.org/docs/core/legal/floss_exception.html"
 *
 * 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
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package org.silverpeas.attachment.web;

import com.silverpeas.annotation.Authorized;
import com.silverpeas.annotation.RequestScoped;
import com.silverpeas.annotation.Service;
import com.silverpeas.util.FileUtil;
import com.silverpeas.util.ForeignPK;
import com.silverpeas.util.StringUtil;
import com.silverpeas.util.i18n.I18NHelper;
import com.silverpeas.web.UserPriviledgeValidation;
import org.apache.commons.io.FileUtils;
import org.silverpeas.attachment.ActifyDocumentProcessor;
import org.silverpeas.attachment.AttachmentServiceFactory;
import org.silverpeas.attachment.WebdavServiceFactory;
import org.silverpeas.attachment.model.SimpleDocument;
import org.silverpeas.attachment.model.SimpleDocumentPK;
import org.silverpeas.attachment.model.UnlockContext;
import org.silverpeas.attachment.model.UnlockOption;
import org.silverpeas.importExport.versioning.DocumentVersion;
import org.silverpeas.servlet.RequestParameterDecoder;

import javax.ws.rs.*;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.silverpeas.util.i18n.I18NHelper.defaultLanguage;
import static org.silverpeas.web.util.IFrameAjaxTransportUtil.AJAX_IFRAME_TRANSPORT;
import static org.silverpeas.web.util.IFrameAjaxTransportUtil.createWebApplicationExceptionWithJSonErrorInHtmlContainer;
import static org.silverpeas.web.util.IFrameAjaxTransportUtil.packObjectToJSonDataWithHtmlContainer;

@Service
@RequestScoped
@Path("documents/{componentId}/document/{id}")
@Authorized
public class SimpleDocumentResource extends AbstractSimpleDocumentResource {

    @PathParam("id")
    private String simpleDocumentId;

    public String getSimpleDocumentId() {
        return simpleDocumentId;
    }

    /**
     * Returns the specified document in the specified lang.
     *
     * @param lang the wanted language.
     * @return the specified document in the specified lang.
     */
    @GET
    @Path("{lang}")
    @Produces(MediaType.APPLICATION_JSON)
    public SimpleDocumentEntity getDocument(final @PathParam("lang") String lang) {
        SimpleDocument attachment = getSimpleDocument(lang);
        URI attachmentUri = getUriInfo().getRequestUriBuilder().path("document").path(attachment.getLanguage())
                .build();
        return SimpleDocumentEntity.fromAttachment(attachment).withURI(attachmentUri);
    }

    /**
     * Deletes the the specified document.
     */
    @DELETE
    @Produces(MediaType.APPLICATION_JSON)
    public void deleteDocument() {
        SimpleDocument document = getSimpleDocument(null);
        AttachmentServiceFactory.getAttachmentService().deleteAttachment(document);
    }

    /**
     * Deletes the the specified document.
     *
     * @param lang the lang of the content to be deleted.
     */
    @DELETE
    @Path("content/{lang}")
    @Produces(MediaType.APPLICATION_JSON)
    public void deleteContent(final @PathParam("lang") String lang) {
        SimpleDocument document = getSimpleDocument(lang);
        AttachmentServiceFactory.getAttachmentService().removeContent(document, lang, false);
    }

    /**
     * Updates the document identified by the requested URI.
     *
     * A {@link SimpleDocumentUploadData} is extracted from request parameters.
     *
     * @return an HTTP response embodied an entity in a format expected by the client (that is
     * identified by the <code>xRequestedWith</code> parameter).
     * @throws IOException if an error occurs while updating the document.
     */
    @POST
    @Path("{filename}")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response updateDocument(final @PathParam("filename") String filename) throws IOException {
        SimpleDocumentUploadData uploadData = RequestParameterDecoder.decode(getHttpRequest(),
                SimpleDocumentUploadData.class);

        try {

            // Update the attachment
            SimpleDocumentEntity entity = updateSimpleDocument(uploadData, filename);

            if (AJAX_IFRAME_TRANSPORT.equals(uploadData.getXRequestedWith())) {

                // In case of file upload performed by Ajax IFrame transport way,
                // the expected response type is text/html
                // (when FormData API doesn't exist on client side)
                return Response.ok().type(MediaType.TEXT_HTML_TYPE)
                        .entity(packObjectToJSonDataWithHtmlContainer(entity)).build();
            } else {

                // Otherwise JSON response type is expected
                return Response.ok().type(MediaType.APPLICATION_JSON_TYPE).entity(entity).build();
            }

        } catch (WebApplicationException wae) {
            if (AJAX_IFRAME_TRANSPORT.equals(uploadData.getXRequestedWith())
                    && wae.getResponse().getStatus() == Response.Status.PRECONDITION_FAILED.getStatusCode()) {

                // In case of file upload performed by Ajax IFrame transport way,
                // the exception must also be returned into a text/html response.
                wae = createWebApplicationExceptionWithJSonErrorInHtmlContainer(wae);
            }
            throw wae;
        }
    }

    protected SimpleDocumentEntity updateSimpleDocument(SimpleDocumentUploadData uploadData, String filename)
            throws IOException {
        try {
            SimpleDocument document = getSimpleDocument(uploadData.getLanguage());
            boolean isPublic = false;
            if (uploadData.getVersionType() != null) {
                isPublic = uploadData.getVersionType() == DocumentVersion.TYPE_PUBLIC_VERSION;
                document.setPublicDocument(isPublic);
            }
            document.setUpdatedBy(getUserDetail().getId());
            document.setLanguage(uploadData.getLanguage());
            document.setTitle(uploadData.getTitle());
            document.setDescription(uploadData.getDescription());
            document.setComment(uploadData.getComment());
            String uploadedFilename = filename;
            if (StringUtil.isNotDefined(filename)) {
                uploadedFilename = uploadData.getRequestFile().getName();
            }
            boolean isWebdav = false;
            InputStream uploadedInputStream;
            if (uploadData.getRequestFile() != null
                    && (uploadedInputStream = uploadData.getRequestFile().getInputStream()) != null
                    && StringUtil.isDefined(uploadedFilename) && !"no_file".equalsIgnoreCase(uploadedFilename)) {
                File tempFile = File.createTempFile("silverpeas_", uploadedFilename);
                FileUtils.copyInputStreamToFile(uploadedInputStream, tempFile);
                document.setFilename(uploadedFilename);
                document.setContentType(FileUtil.getMimeType(tempFile.getPath()));

                //check the file
                checkUploadedFile(tempFile);

                document.setSize(tempFile.length());
                InputStream content = new BufferedInputStream(new FileInputStream(tempFile));
                if (!StringUtil.isDefined(document.getEditedBy())) {
                    document.edit(getUserDetail().getId());
                }

                AttachmentServiceFactory.getAttachmentService().updateAttachment(document, content, true, true);
                content.close();
                FileUtils.deleteQuietly(tempFile);
                // in the case the document is a CAD one, process it for Actify
                ActifyDocumentProcessor.getProcessor().process(document);
            } else {
                isWebdav = document.isOpenOfficeCompatible() && document.isReadOnly();
                if (document.isVersioned()) {
                    isWebdav = document.isOpenOfficeCompatible() && document.isReadOnly();
                    File content = new File(document.getAttachmentPath());
                    AttachmentServiceFactory.getAttachmentService().lock(document.getId(), getUserDetail().getId(),
                            document.getLanguage());
                    AttachmentServiceFactory.getAttachmentService().updateAttachment(document, content, true, true);
                } else {
                    if (isWebdav) {
                        WebdavServiceFactory.getWebdavService().updateDocumentContent(document);
                    }
                    AttachmentServiceFactory.getAttachmentService().updateAttachment(document, true, true);
                }
            }
            UnlockContext unlockContext = new UnlockContext(document.getId(), getUserDetail().getId(),
                    uploadData.getLanguage(), uploadData.getComment());
            if (isWebdav) {
                unlockContext.addOption(UnlockOption.WEBDAV);
            } else {
                unlockContext.addOption(UnlockOption.UPLOAD);
            }
            if (!isPublic) {
                unlockContext.addOption(UnlockOption.PRIVATE_VERSION);
            }
            AttachmentServiceFactory.getAttachmentService().unlock(unlockContext);
            document = getSimpleDocument(uploadData.getLanguage());
            URI attachmentUri = getUriInfo().getRequestUriBuilder().path("document").path(document.getLanguage())
                    .build();
            return SimpleDocumentEntity.fromAttachment(document).withURI(attachmentUri);
        } catch (RuntimeException re) {
            performRuntimeException(re);
        }
        throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    }

    /**
     * Returns all the existing translation of a SimpleDocument.
     *
     * @return all the existing translation of a SimpleDocument.
     */
    @GET
    @Path("translations")
    @Produces(MediaType.APPLICATION_JSON)
    public SimpleDocumentEntity[] getDocumentTanslations() {
        List<SimpleDocumentEntity> result = new ArrayList<SimpleDocumentEntity>(I18NHelper.getNumberOfLanguages());
        for (String lang : I18NHelper.getAllSupportedLanguages()) {
            SimpleDocument attachment = getSimpleDocument(lang);
            if (lang.equals(attachment.getLanguage())) {
                URI attachmentUri = getUriInfo().getRequestUriBuilder().path("document").path(lang).build();
                result.add(SimpleDocumentEntity.fromAttachment(attachment).withURI(attachmentUri));
            }
        }
        return result.toArray(new SimpleDocumentEntity[result.size()]);
    }

    /**
     * Validates the authorization of the user to request this web service. For doing, the user must
     * have the rights to access the component instance that manages this web resource. The validation
     * is actually delegated to the validation service by passing it the required information.
     *
     * This method should be invoked for web service requiring an authorized access. For doing, the
     * authentication of the user must be first valdiated. Otherwise, the annotation Authorized can be
     * also used instead at class level for both authentication and authorization.
     *
     * @see UserPriviledgeValidation
     * @param validation the validation instance to use.
     * @throws WebApplicationException if the rights of the user are not enough to access this web
     * resource.
     */
    @Override
    public void validateUserAuthorization(final UserPriviledgeValidation validation)
            throws WebApplicationException {
        validation.validateUserAuthorizationOnAttachment(getHttpServletRequest(), getUserDetail(),
                getSimpleDocument(null));
    }

    /**
     * Returns the content of the specified document in the specified language.
     *
     * @param language the language of the document's content to get.
     * @return the content of the specified document in the specified language.
     */
    @GET
    @Path("content/{lang}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getFileContent(@PathParam("lang") final String language) {
        SimpleDocument document = getSimpleDocument(language);
        StreamingOutput stream = new StreamingOutput() {
            @Override
            public void write(OutputStream output) throws WebApplicationException {
                try {
                    AttachmentServiceFactory.getAttachmentService().getBinaryContent(output,
                            new SimpleDocumentPK(getSimpleDocumentId()), language);
                } catch (Exception e) {
                    throw new WebApplicationException(e);
                }
            }
        };
        return Response.ok(stream).type(document.getContentType())
                .header(HttpHeaders.CONTENT_LENGTH, document.getSize())
                .header("content-disposition", "attachment;filename=" + document.getFilename()).build();
    }

    /**
     * Locks the specified document for exclusive edition.
     *
     * @return JSON status to true if the document was locked successfully - JSON status to false
     * otherwise..
     */
    @PUT
    @Path("lock/{lang}")
    @Produces(MediaType.APPLICATION_JSON)
    public String lock(@PathParam("lang") final String language) {
        boolean result = AttachmentServiceFactory.getAttachmentService().lock(getSimpleDocumentId(),
                getUserDetail().getId(), language);
        return MessageFormat.format("'{'\"status\":{0}}", result);
    }

    /**
     * @param document
     * @return
     */
    private List<SimpleDocument> getListDocuments(SimpleDocument document) {
        List<SimpleDocument> docs = AttachmentServiceFactory.getAttachmentService()
                .listDocumentsByForeignKeyAndType(new ForeignPK(document.getForeignId(), getComponentId()),
                        document.getDocumentType(), defaultLanguage);
        return docs;
    }

    /**
     * @param docs
     * @return
     */
    private String reorderDocuments(List<SimpleDocument> docs) {
        AttachmentServiceFactory.getAttachmentService().reorderDocuments(docs);
        return MessageFormat.format("'{'\"status\":{0}}", true);
    }

    /**
     * Moves the specified document up in the list.
     *
     * @return JSON status to true if the document was locked successfully - JSON status to false
     * otherwise..
     */
    @PUT
    @Path("moveUp")
    @Produces(MediaType.APPLICATION_JSON)
    public String moveSimpleDocumentUp() {
        SimpleDocument document = getSimpleDocument(defaultLanguage);
        List<SimpleDocument> docs = getListDocuments(document);
        int position = docs.indexOf(document);
        Collections.swap(docs, position, position - 1);
        String message = reorderDocuments(docs);
        return message;
    }

    /**
     * Moves the specified document down in the list.
     *
     * @return JSON status to true if the document was locked successfully - JSON status to false
     * otherwise..
     */
    @PUT
    @Path("moveDown")
    @Produces(MediaType.APPLICATION_JSON)
    public String moveSimpleDocumentDown() {
        SimpleDocument document = getSimpleDocument(defaultLanguage);
        List<SimpleDocument> docs = getListDocuments(document);
        int position = docs.indexOf(document);
        Collections.swap(docs, position, position + 1);
        String message = reorderDocuments(docs);
        return message;
    }

    /**
     * Unlocks the specified document for exclusive edition.
     *
     * @param force if the unlocking has to be forced.
     * @param webdav if the unlock is performed while a WebDAV access.
     * @param privateVersion if the document is a private version.
     * @param comment a comment about the unlock.
     * @return JSON status to true if the document was locked successfully - JSON status to false
     * otherwise..
     */
    @POST
    @Path("unlock")
    @Produces(MediaType.APPLICATION_JSON)
    public String unlockDocument(@FormParam("force") final boolean force, @FormParam("webdav") final boolean webdav,
            @FormParam("private") final boolean privateVersion, @FormParam("comment") final String comment) {
        SimpleDocument document = getSimpleDocument(defaultLanguage);
        UnlockContext unlockContext = new UnlockContext(getSimpleDocumentId(), getUserDetail().getId(),
                defaultLanguage, comment);
        if (force) {
            unlockContext.addOption(UnlockOption.FORCE);
        }
        if (webdav) {
            unlockContext.addOption(UnlockOption.WEBDAV);
        }
        if (privateVersion) {
            unlockContext.addOption(UnlockOption.PRIVATE_VERSION);
        }
        boolean result = AttachmentServiceFactory.getAttachmentService().unlock(unlockContext);
        return MessageFormat.format("'{'\"status\":{0}, \"id\":{1,number,#}, \"attachmentId\":\"{2}\"}", result,
                document.getOldSilverpeasId(), document.getId());
    }

    /**
     * Changes the document version state.
     *
     * @param comment comment about the version state switching.
     * @param version the new version state.
     * @return JSON status to true if the document was locked successfully - JSON status to false
     * otherwise..
     */
    @PUT
    @Path("switchState")
    @Produces(MediaType.APPLICATION_JSON)
    public String switchDocumentVersionState(@FormParam("switch-version-comment") final String comment,
            @FormParam("switch-version") final String version) {
        boolean useMajor = "lastMajor".equalsIgnoreCase(version);
        SimpleDocument document = getSimpleDocument(defaultLanguage);
        SimpleDocumentPK pk = new SimpleDocumentPK(getSimpleDocumentId());
        if (document.isVersioned() && useMajor) {
            pk = document.getLastPublicVersion().getPk();
        }
        pk = AttachmentServiceFactory.getAttachmentService().changeVersionState(pk, comment);
        document = AttachmentServiceFactory.getAttachmentService().searchDocumentById(pk, defaultLanguage);
        return MessageFormat.format("'{'\"status\":{0}, \"id\":{1,number,#}, \"attachmentId\":\"{2}\"}", true,
                document.getOldSilverpeasId(), document.getId());
    }

    /**
     * Forbid or allow the download of the document for readers.
     * @return JSON download state for readers. allowedDownloadForReaders = true or false.
     */
    @POST
    @Path("switchDownloadAllowedForReaders")
    @Produces(MediaType.APPLICATION_JSON)
    public String switchDownloadAllowedForReaders(@FormParam("allowed") final boolean allowed) {

        // Performing the request
        SimpleDocument document = getSimpleDocument(null);
        AttachmentServiceFactory.getAttachmentService().switchAllowingDownloadForReaders(document.getPk(), allowed);

        // JSON Response.
        return MessageFormat.format(
                "'{'\"allowedDownloadForReaders\":{0}, \"id\":{1,number,#}, \"attachmentId\":\"{2}\"}", allowed,
                document.getOldSilverpeasId(), document.getId());
    }

    /**
     * Return the current document
     * @param lang
     * @return SimpleDocument
     */
    private SimpleDocument getSimpleDocument(String lang) {
        String language = (lang == null ? defaultLanguage : lang);
        SimpleDocument attachment = AttachmentServiceFactory.getAttachmentService()
                .searchDocumentById(new SimpleDocumentPK(getSimpleDocumentId()), language);
        if (attachment == null) {
            throw new WebApplicationException(Status.NOT_FOUND);
        }
        return attachment;
    }
}