org.kuali.coeus.common.impl.person.signature.PersonSignatureServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.coeus.common.impl.person.signature.PersonSignatureServiceImpl.java

Source

/*
 * Kuali Coeus, a comprehensive research administration system for higher education.
 * 
 * Copyright 2005-2015 Kuali, Inc.
 * 
 * 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.
 * 
 * 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.kuali.coeus.common.impl.person.signature;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.Overlay;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
import org.kuali.coeus.common.framework.person.signature.PersonSignature;
import org.kuali.coeus.common.framework.person.signature.PersonSignatureLocationHelper;
import org.kuali.coeus.common.framework.person.signature.PersonSignatureModule;
import org.kuali.coeus.common.framework.person.signature.PersonSignaturePrintHelper;
import org.kuali.coeus.common.framework.person.signature.PersonSignatureService;
import org.kuali.rice.coreservice.framework.parameter.ParameterConstants;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.krad.service.BusinessObjectService;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.ObjectUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;

public abstract class PersonSignatureServiceImpl implements PersonSignatureService {

    private static final String CORRESPONDENCE_SIGNATURE_TYPE = "CORRESPONDENCE_SIGNATURE_TYPE";
    private static final String CORRESPONDENCE_SIGNATURE_TAG = "CORRESPONDENCE_SIGNATURE_TAG";
    private BusinessObjectService businessObjectService;
    private ParameterService parameterService;

    private static final float ADDITIONAL_SPACE_BETWEEN_TAG_AND_IMAGE = 10f;

    protected static final String PERSON_SIGNATURE_ACTIVE = "signatureActive";
    protected static final String PERSON_SIGNATURE_PERSON_ID = "personId";
    protected static final String DEFAULT_SIGNATURE = "defaultSignature";
    protected static final String MODULE_CODE = "moduleCode";

    private static final Log LOG = LogFactory.getLog(PersonSignatureServiceImpl.class);

    /**
     * Configure signature type required
     * D - Always use Default signature
     * S - Always use signed in user signature, if not found use the default signature
     * N - No signature is required
     */
    public enum SignatureTypes {
        DEFAULT_SIGNATURE("D"), SIGNED_IN_USER_SIGNATURE("S"), NO_SIGNATURE_REQURIED("N");

        private String signatureType;

        private SignatureTypes(String signatureType) {
            this.signatureType = signatureType;
        }

        public String getSignatureType() {
            return signatureType;
        }

        public static SignatureTypes getSignatureMode(String signatureType) {
            for (SignatureTypes sType : values()) {
                if (sType.signatureType.equals(signatureType)) {
                    return sType;
                }
            }
            return null;
        }

    }

    @Override
    public byte[] applySignature(byte[] pdfBytes) throws Exception {
        byte[] pdfFileData = pdfBytes;
        ByteArrayOutputStream byteArrayOutputStream = getOriginalPdfDocumentAsOutputsStream(pdfBytes); //getFlattenedPdfForm(pdfFileData);
        byteArrayOutputStream = identifyModeAndApplySignature(byteArrayOutputStream);
        if (ObjectUtils.isNotNull(byteArrayOutputStream)) {
            pdfFileData = byteArrayOutputStream.toByteArray();
        }
        return pdfFileData;
    }

    /**
     * This method is to identify signature mode and invoke appropriate method
     * If signature is not available, return the original.
     * to sign the document.
     * @param originalByteArrayOutputStream
     * @return
     * @throws Exception
     */
    protected ByteArrayOutputStream identifyModeAndApplySignature(
            ByteArrayOutputStream originalByteArrayOutputStream) throws Exception {
        ByteArrayOutputStream outputStream = originalByteArrayOutputStream;
        String signatureTypeParam = getSignatureTypeParameter();
        SignatureTypes signatureType = SignatureTypes.NO_SIGNATURE_REQURIED;
        if (ObjectUtils.isNotNull(signatureTypeParam)) {
            signatureType = SignatureTypes.getSignatureMode(signatureTypeParam);
        }

        if (signatureType != null) {
            switch (signatureType) {
            case DEFAULT_SIGNATURE:
                outputStream = printDefaultSignature(outputStream);
                break;
            case SIGNED_IN_USER_SIGNATURE:
                String personId = GlobalVariables.getUserSession().getPerson().getPrincipalId();
                outputStream = printLoggedInUserSignature(personId, outputStream);
                break;
            case NO_SIGNATURE_REQURIED:
                break;
            }
        } else {
            LOG.warn("Invalid signature type defined in parameter");
        }

        return outputStream;
    }

    /**
     * This method is to print default module authorized signature.
     * Original document is returned if signature is not available.
     * @param originalByteArrayOutputStream
     * @return
     * @throws Exception
     */
    protected ByteArrayOutputStream printDefaultSignature(ByteArrayOutputStream originalByteArrayOutputStream)
            throws Exception {
        ByteArrayOutputStream outputStream = originalByteArrayOutputStream;
        PersonSignature authorizedSignature = getDefaultSignature();
        if (ObjectUtils.isNotNull(authorizedSignature)) {
            if (ObjectUtils.isNotNull(authorizedSignature.getAttachmentContent())) {
                outputStream = applyAutographInDocument(authorizedSignature, outputStream);
            }
        }
        return outputStream;
    }

    /**
     * This method is to print logged in user signature.
     * If logged in user signature is not available, get the default signature for applicable module.
     * Original document is returned if signature is not available.
     * @param personId
     * @param originalByteArrayOutputStream
     * @return
     * @throws Exception
     */
    protected ByteArrayOutputStream printLoggedInUserSignature(String personId,
            ByteArrayOutputStream originalByteArrayOutputStream) throws Exception {
        PersonSignature userSignature = getLoggedinPersonSignature(personId);
        ByteArrayOutputStream outputStream = originalByteArrayOutputStream;
        if (ObjectUtils.isNull(userSignature)) {
            userSignature = getDefaultSignature();
        }
        if (ObjectUtils.isNotNull(userSignature)) {
            if (ObjectUtils.isNotNull(userSignature.getAttachmentContent())) {
                outputStream = applyAutographInDocument(userSignature, outputStream);
            }
        }
        return outputStream;
    }

    /**
     * This method is to apply signature in the document.
     * @param personSignature
     * @param originalByteArrayOutputStream
     * @return
     */
    protected ByteArrayOutputStream applyAutographInDocument(PersonSignature personSignature,
            ByteArrayOutputStream originalByteArrayOutputStream) {
        ByteArrayOutputStream outputStream = originalByteArrayOutputStream;
        try {
            if (personSignature.getAttachmentContent() != null) {
                outputStream = scanAndApplyAutographInEachPage(personSignature.getAttachmentContent(),
                        outputStream);
            }
        } catch (Exception ex) {
            LOG.error("Exception while applying signature : Method applyAutographInDocument : " + ex.getMessage());
            LOG.error(ex.getMessage(), ex);
        }
        return outputStream;
    }

    /**
     * This method is to scan for signature tag in each page and apply the signature
     * at desired location.
     * @param imageData
     * @param originalByteArrayOutputStream
     */
    @SuppressWarnings("unchecked")
    protected ByteArrayOutputStream scanAndApplyAutographInEachPage(byte[] imageData,
            ByteArrayOutputStream originalByteArrayOutputStream) throws Exception {
        ByteArrayOutputStream outputStream = originalByteArrayOutputStream;
        byte[] pdfFileData = originalByteArrayOutputStream.toByteArray();
        PDDocument originalDocument = getPdfDocument(pdfFileData); //PDDocument.load(is);
        PDDocument signatureDocument = new PDDocument();
        List<PDPage> originalDocumentPages = originalDocument.getDocumentCatalog().getAllPages();
        for (PDPage page : originalDocumentPages) {
            List<String> signatureTags = new ArrayList<String>(getSignatureTagParameter());
            PersonSignatureLocationHelper printer = new PersonSignatureLocationHelper(signatureTags);
            PDStream contents = page.getContents();
            if (contents != null) {
                printer.processStream(page, page.findResources(), page.getContents().getStream());
            }
            PDPage signaturePage = new PDPage();
            if (printer.isSignatureTagExists()) {
                PDJpeg signatureImage = new PDJpeg(signatureDocument, getBufferedImage(imageData));
                PDPageContentStream stream = new PDPageContentStream(signatureDocument, signaturePage, true, true);
                for (PersonSignaturePrintHelper signatureHelper : printer.getPersonSignatureLocations()) {
                    float coordinateX = signatureHelper.getCoordinateX();
                    float coordinateY = signatureHelper.getCoordinateY() - signatureImage.getHeight()
                            - ADDITIONAL_SPACE_BETWEEN_TAG_AND_IMAGE;
                    stream.drawImage(signatureImage, coordinateX, coordinateY);
                    stream.close();
                }
            } else {
                signaturePage = page;
            }
            signatureDocument.addPage(signaturePage);
        }

        Overlay overlay = new Overlay();
        overlay.overlay(signatureDocument, originalDocument);

        originalDocument.save(outputStream);
        originalDocument.close();
        signatureDocument.close();
        return outputStream;
    }

    private PDDocument getPdfDocument(byte[] pdfFileData) throws Exception {
        InputStream is = new ByteArrayInputStream(pdfFileData);
        PDDocument originalDocument = PDDocument.load(is);
        return originalDocument;
    }

    private ByteArrayOutputStream getOriginalPdfDocumentAsOutputsStream(byte[] pdfFileData) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream is = new ByteArrayInputStream(pdfFileData);
        PDDocument originalDocument = PDDocument.load(is);
        originalDocument.save(outputStream);
        originalDocument.close();
        return outputStream;
    }

    /**
     * This method is to get buffered image from image data
     * @param imageData
     * @return
     * @throws Exception
     */
    protected BufferedImage getBufferedImage(byte[] imageData) throws Exception {
        InputStream in = new ByteArrayInputStream(imageData);
        BufferedImage image = ImageIO.read(in);
        return image;
    }

    /**
     * This method is to get the default signature for module
     * @return
     */
    protected PersonSignature getDefaultSignature() {
        List<PersonSignatureModule> moduleSignatures = getAuthorizedDefaultSignatory();
        PersonSignature authorizedSignature = null;
        if (!moduleSignatures.isEmpty()) {
            authorizedSignature = moduleSignatures.get(0).getPersonSignature();
        }
        return authorizedSignature;
    }

    /**
     * This method is to get logged in person signature
     * Check whether user is authorized to sign in given module
     * @param personId
     * @return
     */
    protected PersonSignature getLoggedinPersonSignature(String personId) {
        Map<String, Object> fieldValues = new HashMap<String, Object>();
        boolean isAuthorized = false;
        fieldValues.put(PERSON_SIGNATURE_PERSON_ID, personId);
        fieldValues.put(PERSON_SIGNATURE_ACTIVE, Boolean.TRUE);
        PersonSignature personSignature = (PersonSignature) getBusinessObjectService()
                .findByPrimaryKey(PersonSignature.class, fieldValues);
        if (ObjectUtils.isNotNull(personSignature)) {
            for (PersonSignatureModule personSignatureModule : personSignature.getPersonSignatureModules()) {
                if (personSignatureModule.getModuleCode().equalsIgnoreCase(getModuleCodeHook())
                        && personSignatureModule.isSignatureActive()) {
                    isAuthorized = true;
                    break;
                }
            }
        }
        return isAuthorized ? personSignature : null;
    }

    /**
     * This method is to get authorized default signatory for a given module.
     * get all active signatures.
     * @return
     */
    protected List<PersonSignatureModule> getAuthorizedDefaultSignatory() {
        Map<String, Object> matchingKey = new HashMap<String, Object>();
        matchingKey.put(MODULE_CODE, getModuleCodeHook());
        matchingKey.put(PERSON_SIGNATURE_ACTIVE, Boolean.TRUE);
        matchingKey.put(DEFAULT_SIGNATURE, Boolean.TRUE);
        return (List<PersonSignatureModule>) getBusinessObjectService().findMatching(PersonSignatureModule.class,
                matchingKey);
    }

    protected String getSignatureTypeParameter() {
        return getParameterService().getParameterValueAsString(getModuleNameSpaceHook(),
                ParameterConstants.DOCUMENT_COMPONENT, CORRESPONDENCE_SIGNATURE_TYPE);
    }

    protected Collection<String> getSignatureTagParameter() {
        return getParameterService().getParameterValuesAsString(getModuleNameSpaceHook(),
                ParameterConstants.DOCUMENT_COMPONENT, CORRESPONDENCE_SIGNATURE_TAG);
    }

    public ParameterService getParameterService() {
        return parameterService;
    }

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    public BusinessObjectService getBusinessObjectService() {
        return businessObjectService;
    }

    public void setBusinessObjectService(BusinessObjectService businessObjectService) {
        this.businessObjectService = businessObjectService;
    }

    protected abstract String getModuleCodeHook();

    protected abstract String getModuleNameSpaceHook();

}