br.gov.jfrj.siga.vraptor.ExArquivoController.java Source code

Java tutorial

Introduction

Here is the source code for br.gov.jfrj.siga.vraptor.ExArquivoController.java

Source

/*******************************************************************************
 * Copyright (c) 2006 - 2011 SJRJ.
 * 
 *     This file is part of SIGA.
 * 
 *     SIGA 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.
 * 
 *     SIGA 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 SIGA.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
/*
 * Criado em  13/09/2005
 *
 */
package br.gov.jfrj.siga.vraptor;

import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.util.Date;

import javax.persistence.EntityManager;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.interceptor.download.Download;
import br.com.caelum.vraptor.interceptor.download.InputStreamDownload;
import br.gov.jfrj.itextpdf.Documento;
import br.gov.jfrj.siga.Service;
import br.gov.jfrj.siga.base.AplicacaoException;
import br.gov.jfrj.siga.cd.service.CdService;
import br.gov.jfrj.siga.ex.ExMobil;
import br.gov.jfrj.siga.ex.ExMovimentacao;
import br.gov.jfrj.siga.ex.ExNivelAcesso;
import br.gov.jfrj.siga.ex.bl.Ex;
import br.gov.jfrj.siga.hibernate.ExDao;
import br.gov.jfrj.siga.vraptor.builder.ExDownloadRTF;
import br.gov.jfrj.siga.vraptor.builder.ExDownloadZip;
import br.gov.jfrj.siga.vraptor.builder.ExInputStreamDownload;

import com.lowagie.text.pdf.codec.Base64;

@Resource
public class ExArquivoController extends ExController {

    private static final String TEXT_HTML = "text/html";
    private static final String APPLICATION_PDF = "application/pdf";
    private static final String TEXT_PLAIN = "text/plain";
    private static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
    private static byte[] idPattern = "/ModDate(D:20".getBytes();
    private static int[] failure = computeFailure();

    public ExArquivoController(HttpServletRequest request, HttpServletResponse response, ServletContext context,
            Result result, SigaObjects so, EntityManager em) {
        super(request, response, context, result, ExDao.getInstance(), so, em);
    }

    @Get("/app/arquivo/exibir")
    public Download aExibir(final String sigla, final boolean popup, final String arquivo, byte[] certificado,
            String hash, final String HASH_ALGORITHM, final String certificadoB64, boolean completo,
            final boolean semmarcas) {
        try {
            final String servernameport = getRequest().getServerName() + ":" + getRequest().getServerPort();
            final String contextpath = getRequest().getContextPath();
            final boolean pacoteAssinavel = (certificadoB64 != null);
            final boolean fB64 = getRequest().getHeader("Accept") != null
                    && getRequest().getHeader("Accept").startsWith("text/vnd.siga.b64encoded");
            final boolean isPdf = arquivo.endsWith(".pdf");
            final boolean isHtml = arquivo.endsWith(".html");
            boolean estampar = !semmarcas;
            final boolean somenteHash = (hash != null) || (HASH_ALGORITHM != null);
            if (somenteHash) {
                if (hash == null)
                    hash = HASH_ALGORITHM;
                if (hash != null) {
                    if (!(hash.equals("SHA1") || hash.equals("SHA-256") || hash.equals("SHA-512")
                            || hash.equals("MD5"))) {
                        throw new AplicacaoException(
                                "Algoritmo de hash invlido. Os permitidos so: SHA1, SHA-256, SHA-512 e MD5.");
                    }
                }
                completo = false;
                estampar = false;
            }
            if (pacoteAssinavel) {
                certificado = Base64.decode(certificadoB64);
                completo = false;
                estampar = false;
            }
            final ExMobil mob = Documento.getMobil(arquivo);
            if (mob == null) {
                throw new AplicacaoException("A sigla informada no corresponde a um documento da base de dados.");
            }
            if (!Ex.getInstance().getComp().podeAcessarDocumento(getTitular(), getLotaTitular(), mob)) {
                throw new AplicacaoException("Documento " + mob.getSigla() + " inacessvel ao usurio "
                        + getTitular().getSigla() + "/" + getLotaTitular().getSiglaCompleta() + ".");
            }
            final ExMovimentacao mov = Documento.getMov(mob, arquivo);
            final boolean imutavel = (mov != null) && !completo && !estampar && !somenteHash && !pacoteAssinavel;
            String cacheControl = "private";
            final Integer grauNivelAcesso = mob.doc().getExNivelAcessoDoDocumento().getGrauNivelAcesso();
            if (ExNivelAcesso.NIVEL_ACESSO_PUBLICO == grauNivelAcesso
                    || ExNivelAcesso.NIVEL_ACESSO_ENTRE_ORGAOS == grauNivelAcesso) {
                cacheControl = "public";
            }
            byte ab[] = null;
            if (isPdf) {
                if (mov != null && !completo && !estampar && hash == null) {
                    ab = mov.getConteudoBlobpdf();
                } else {
                    ab = Documento.getDocumento(mob, mov, completo, estampar, hash, null);
                }
                if (ab == null) {
                    throw new Exception("PDF invlido!");
                }
                if (pacoteAssinavel) {
                    CdService client = Service.getCdService();
                    final Date dt = dao().consultarDataEHoraDoServidor();
                    getResponse().setHeader("Atributo-Assinavel-Data-Hora", Long.toString(dt.getTime()));
                    byte[] sa = client.produzPacoteAssinavel(certificado, certificado, ab, true, dt);
                    return new InputStreamDownload(makeByteArrayInputStream(sa, fB64), APPLICATION_OCTET_STREAM,
                            arquivo);
                }
                if (hash != null) {
                    return new InputStreamDownload(makeByteArrayInputStream(ab, fB64), APPLICATION_OCTET_STREAM,
                            arquivo);
                }
            }
            if (isHtml) {
                ab = Documento.getDocumentoHTML(mob, mov, completo, contextpath, servernameport);
                if (ab == null) {
                    throw new Exception("HTML invlido!");
                }
            }
            if (imutavel) {
                getResponse().setHeader("Cache-Control", cacheControl);
                getResponse().setDateHeader("Expires", new Date().getTime() + (365 * 24 * 3600 * 1000L));
            } else {
                final MessageDigest md = MessageDigest.getInstance("MD5");
                final int m = match(ab);
                if (m != -1) {
                    md.update(ab, 0, m);
                } else {
                    md.update(ab);
                }
                final String etag = Base64.encodeBytes(md.digest());
                final String ifNoneMatch = getRequest().getHeader("If-None-Match");
                getResponse().setHeader("Cache-Control", "must-revalidate, " + cacheControl);
                getResponse().setDateHeader("Expires", (new Date()).getTime() + 30000);
                getResponse().setHeader("ETag", etag);

                if ((etag).equals(ifNoneMatch) && ifNoneMatch != null) {
                    getResponse().sendError(HttpServletResponse.SC_NOT_MODIFIED);
                    return new InputStreamDownload(makeByteArrayInputStream((new byte[0]), false), TEXT_PLAIN,
                            "arquivo invlido");
                }
            }
            getResponse().setHeader("Pragma", "");
            return new InputStreamDownload(makeByteArrayInputStream(ab, fB64), checkDownloadType(ab, isPdf, fB64),
                    arquivo);
        } catch (Exception e) {
            if (e.getClass().getSimpleName().equals("ClientAbortException")) {
                return new InputStreamDownload(makeByteArrayInputStream((new byte[0]), false), TEXT_PLAIN,
                        "arquivo invlido");
            }
            throw new RuntimeException("erro na gerao do documento.", e);
        }
    }

    @Get("/app/arquivo/download")
    public Download download(String arquivo, String hash, HttpServletResponse response) throws Exception {
        boolean isZip = arquivo.endsWith(".zip");
        boolean somenteHash = hash != null || getPar().containsKey("HASH_ALGORITHM");
        String algoritmoHash = getAlgoritmoHash(hash);
        ExMobil mob = Documento.getMobil(arquivo);
        ExMovimentacao mov = Documento.getMov(mob, arquivo);

        validarDownload(somenteHash, algoritmoHash, mob);

        if (isZip) {
            if (algoritmoHash != null) {
                return new ExDownloadZip(mov, algoritmoHash);
            }
            return iniciarDownload(mob,
                    new ExDownloadZip(mov, algoritmoHash, ExInputStreamDownload.MEDIA_TYPE_ZIP));
        } else {
            if (algoritmoHash != null) {
                return new ExDownloadRTF(mob, algoritmoHash);
            }
            return iniciarDownload(mob,
                    new ExDownloadRTF(mob, algoritmoHash, ExInputStreamDownload.MEDIA_TYPE_RTF));
        }
    }

    private Download iniciarDownload(ExMobil mob, ExInputStreamDownload exDownload) {
        try {
            // Calcula o hash do documento, mas no leva em considerao
            // para fins de hash os ltimos bytes do arquivos, pois l
            // fica armazanada a ID e as datas de criao e modificao
            // e estas so sempre diferente de um pdf para o outro.
            MessageDigest md = MessageDigest.getInstance("MD5");

            byte ab[] = exDownload.getBytes();
            int m = match(ab);
            if (m != -1)
                md.update(ab, 0, m);
            else
                md.update(ab);

            String etag = Base64.encodeBytes(md.digest());
            String ifNoneMatch = getRequest().getHeader("If-None-Match");
            getResponse().setHeader("Cache-Control", "must-revalidate, " + getCacheControl(mob));
            getResponse().setDateHeader("Expires", 0);
            getResponse().setHeader("ETag", etag);
            getResponse().setHeader("Pragma", "");

            if (ifNoneMatch != null && ifNoneMatch.equals(etag)) {
                getResponse().sendError(HttpServletResponse.SC_NOT_MODIFIED);
                return null;
            }
            return exDownload;
        } catch (Exception e) {
            throw new AplicacaoException("erro na gerao do documento.");
        }
    }

    private String getAlgoritmoHash(String hash) {
        String[] value = getPar().get("HASH_ALGORITHM");
        if (value != null && value.length > 0) {
            return value[0];
        }
        return hash;
    }

    private String getCacheControl(ExMobil mob) {
        String cacheControl = "private";
        final Integer grauNivelAcesso = mob.doc().getExNivelAcessoDoDocumento().getGrauNivelAcesso();
        if (ExNivelAcesso.NIVEL_ACESSO_PUBLICO == grauNivelAcesso
                || ExNivelAcesso.NIVEL_ACESSO_ENTRE_ORGAOS == grauNivelAcesso)
            cacheControl = "public";
        return cacheControl;
    }

    private void validarDownload(boolean somenteHash, String algoritmoHash, ExMobil mob) {
        if (somenteHash) {
            if (algoritmoHash != null) {
                if (!(algoritmoHash.equals("SHA1") || algoritmoHash.equals("SHA-256")
                        || algoritmoHash.equals("SHA-512") || algoritmoHash.equals("MD5")))
                    throw new AplicacaoException(
                            "Algoritmo de hash invlido. Os permitidos so: SHA1, SHA-256, SHA-512 e MD5.");
            }
        }

        if (mob == null) {
            throw new AplicacaoException("A sigla informada no corresponde a um documento da base de dados.");
        }

        if (!Ex.getInstance().getComp().podeAcessarDocumento(getTitular(), getLotaTitular(), mob)) {
            throw new AplicacaoException("Documento " + mob.getSigla() + " inacessvel ao usurio "
                    + getTitular().getSigla() + "/" + getLotaTitular().getSiglaCompleta() + ".");
        }
    }

    private ByteArrayInputStream makeByteArrayInputStream(final byte[] content, final boolean fB64) {
        final byte[] conteudo = (fB64 ? Base64.encodeBytes(content).getBytes() : content);
        return (new ByteArrayInputStream(conteudo));
    }

    private String checkDownloadType(final byte[] content, final boolean isPdf, final boolean isFB64) {
        String contentType;
        if (isFB64) {
            contentType = TEXT_PLAIN;
        } else {
            if (isPdf) {
                contentType = APPLICATION_PDF;
            } else {
                contentType = TEXT_HTML;
            }
        }
        return contentType;
    }

    private static int match(byte[] text) {
        int j = 0;
        if (text.length == 0) {
            return -1;
        }

        for (int i = 0; i < text.length; i++) {
            while (j > 0 && idPattern[j] != text[i]) {
                j = failure[j - 1];
            }
            if (idPattern[j] == text[i]) {
                j++;
            }
            if (j == idPattern.length) {
                return i - idPattern.length + 1;
            }
        }
        return -1;
    }

    private static int[] computeFailure() {
        failure = new int[idPattern.length];
        int j = 0;
        for (int i = 1; i < idPattern.length; i++) {
            while (j > 0 && idPattern[j] != idPattern[i]) {
                j = failure[j - 1];
            }
            if (idPattern[j] == idPattern[i]) {
                j++;
            }
            failure[i] = j;
        }
        return failure;
    }

}