com.btmatthews.leabharlann.view.FileContentMessageConverter.java Source code

Java tutorial

Introduction

Here is the source code for com.btmatthews.leabharlann.view.FileContentMessageConverter.java

Source

/*
 * Copyright 2012-2014 Brian Matthews
 *
 * 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.btmatthews.leabharlann.view;

import com.btmatthews.atlas.jcr.JCRAccessor;
import com.btmatthews.atlas.jcr.NodeCallback;
import com.btmatthews.atlas.jcr.RepositoryAccessException;
import com.btmatthews.leabharlann.domain.FileContent;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;

import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.Session;
import java.io.IOException;
import java.util.Calendar;
import java.util.Collections;

/**
 * A Spring MVC message converter that is used to write a file's contents to the HTTP servlet response's output stream.
 *
 * @author <a href="mailto:brian@btmatthews.com">Brian Matthews</a>
 * @since 1.0.0
 */
@Component
public class FileContentMessageConverter extends AbstractHttpMessageConverter<FileContent> {

    /**
     * The {@link JCRAccessor} API object used to access the Java Content Repository.
     */
    private JCRAccessor jcrAccessor;

    /**
     * Inject the {@link JCRAccessor} API object used to access the Java Content Repository.
     *
     * @param accessor The {@link JCRAccessor} API object.
     */
    @Autowired
    public void setJcrAccessor(final JCRAccessor accessor) {
        jcrAccessor = accessor;
    }

    /**
     * Return true if this message converter supports the class {@code clazz}.
     *
     * @param clazz A class description.
     * @return Returns true {@code clazz} can be assigned to {@link FileContent}.
     */
    @Override
    protected boolean supports(final Class<?> clazz) {
        return FileContent.class.isAssignableFrom(clazz);
    }

    /**
     * Always throws {@link HttpMessageNotReadableException} to indicate that reading {@link FileContent} descriptors is
     * not supported.
     *
     * @param clazz        A class description.
     * @param inputMessage Used to access the servlet request headers and input stream.
     * @return Always throws an exception.
     * @throws HttpMessageNotReadableException Indicates that a {@link FileContent} cannot be read.
     */
    @Override
    protected FileContent readInternal(final Class<? extends FileContent> clazz,
            final HttpInputMessage inputMessage) throws HttpMessageNotReadableException {
        throw new HttpMessageNotReadableException("Cannot read messages of this type");
    }

    /**
     * Set the HTTP headers on the servlet response and stream the file contents to the servlet response's output stream.
     *
     * @param fileContent   Describes the file content.
     * @param outputMessage Used to access the servlet response headers and output stream.
     * @throws IOException                     If there was an error streaming the file content.
     * @throws HttpMessageNotWritableException If there was problem retrieving the file content from the Java Content Repository.
     */
    @Override
    protected void writeInternal(final FileContent fileContent, final HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        try {
            jcrAccessor.withNodeId(fileContent.getWorkspace(), fileContent.getId(), new NodeCallback() {
                @Override
                public Object doInSessionWithNode(Session session, Node node) throws Exception {
                    final Node resourceNode = node.getNode(Node.JCR_CONTENT);
                    final String mimeType = jcrAccessor.getStringProperty(resourceNode, Property.JCR_MIMETYPE);
                    final Calendar lastModified = jcrAccessor.getCalendarProperty(resourceNode,
                            Property.JCR_LAST_MODIFIED);
                    final Binary data = jcrAccessor.getBinaryProperty(resourceNode, Property.JCR_DATA);
                    if (jcrAccessor.hasProperty(resourceNode, Property.JCR_ENCODING)) {
                        final String encoding = jcrAccessor.getStringProperty(resourceNode, Property.JCR_ENCODING);
                        outputMessage.getHeaders().setContentType(new MediaType(MediaType.valueOf(mimeType),
                                Collections.singletonMap("charset", encoding)));
                    } else {
                        outputMessage.getHeaders().setContentType(MediaType.valueOf(mimeType));
                    }
                    outputMessage.getHeaders().setContentLength(data.getSize());
                    if (lastModified != null) {
                        outputMessage.getHeaders().setLastModified(lastModified.getTimeInMillis());
                    }
                    outputMessage.getHeaders().set("Content-Disposition", "attachment;filename=" + node.getName());
                    IOUtils.copy(data.getStream(), outputMessage.getBody());
                    return null;
                }
            });
        } catch (final RepositoryAccessException e) {
            throw new HttpMessageNotWritableException(e.getLocalizedMessage());
        }
    }
}