groupdocs-total/GroupDocs.Total-for-Java-Spring

View on GitHub
src/main/java/com/groupdocs/ui/signature/service/SignServiceImpl.java

Summary

Maintainability
A
0 mins
Test Coverage
F
3%
package com.groupdocs.ui.signature.service;

import com.google.common.collect.Lists;
import com.groupdocs.signature.handler.SignatureHandler;
import com.groupdocs.signature.options.OutputType;
import com.groupdocs.signature.options.SignatureOptionsCollection;
import com.groupdocs.signature.options.loadoptions.LoadOptions;
import com.groupdocs.signature.options.saveoptions.SaveOptions;
import com.groupdocs.ui.exception.TotalGroupDocsException;
import com.groupdocs.ui.signature.SignatureConfiguration;
import com.groupdocs.ui.signature.XMLReaderWriter;
import com.groupdocs.ui.signature.model.request.SignDocumentRequest;
import com.groupdocs.ui.signature.model.web.SignatureDataEntity;
import com.groupdocs.ui.signature.model.web.SignedDocumentEntity;
import com.groupdocs.ui.signature.model.xml.OpticalXmlEntity;
import com.groupdocs.ui.signature.model.xml.StampXmlEntity;
import com.groupdocs.ui.signature.model.xml.StampXmlEntityList;
import com.groupdocs.ui.signature.model.xml.TextXmlEntity;
import com.groupdocs.ui.signature.signer.*;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.*;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;

import static com.groupdocs.ui.signature.SignatureType.QR_CODE;
import static com.groupdocs.ui.signature.service.SignatureHandlerFactory.createStreamHandler;
import static com.groupdocs.ui.signature.service.SignatureHandlerFactory.getFullDataPathStr;
import static com.groupdocs.ui.util.directory.SignatureDirectory.*;

@Service
public class SignServiceImpl implements SignService {
    private static final Logger logger = LoggerFactory.getLogger(SignServiceImpl.class);

    private static final List<String> supportedImageFormats = Arrays.asList("bmp", "jpeg", "jpg", "tiff", "tif", "png");

    private SignatureHandler signatureHandler;
    @Autowired
    private SignatureConfiguration signatureConfiguration;

    @PostConstruct
    public void init() {
        signatureHandler = SignatureHandlerFactory.createHandler(signatureConfiguration.getFilesDirectory(), signatureConfiguration.getDataDirectory());
    }

    @Override
    public SignedDocumentEntity sign(SignDocumentRequest signDocumentRequest) {
        String documentGuid = signDocumentRequest.getGuid();
        SignatureOptionsCollection signsCollection = buildSignOptions(signDocumentRequest);
        return signDocument(documentGuid, signDocumentRequest.getPassword(), signsCollection);
    }

    private SignatureOptionsCollection buildSignOptions(SignDocumentRequest signDocumentRequest) {
        String documentGuid = signDocumentRequest.getGuid();
        String documentType = getDocumentType(signDocumentRequest.getDocumentType(), documentGuid, FilenameUtils.getExtension(documentGuid));
        List<SignatureDataEntity> signaturesData = signDocumentRequest.getSignaturesData();
        SortedSignaturesData sortedSignaturesData = new SortedSignaturesData(signaturesData).sort();
        SignatureOptionsCollection signsCollection = new SignatureOptionsCollection();
        if (!sortedSignaturesData.digital.isEmpty()) {
            signDigital(signDocumentRequest.getPassword(), sortedSignaturesData.digital, documentType, signsCollection);
        }
        if (!sortedSignaturesData.images.isEmpty()) {
            signImage(documentType, sortedSignaturesData.images, signsCollection);
        }
        if (!sortedSignaturesData.texts.isEmpty()) {
            signText(documentType, sortedSignaturesData.texts, signsCollection);
        }
        if (!sortedSignaturesData.stamps.isEmpty()) {
            signStamp(documentType, sortedSignaturesData.stamps, signsCollection);
        }
        if (!sortedSignaturesData.codes.isEmpty()) {
            signOptical(documentType, sortedSignaturesData.codes, signsCollection);
        }
        return signsCollection;
    }

    @Override
    public InputStream signByStream(SignDocumentRequest signDocumentRequest) {
        String documentGuid = signDocumentRequest.getGuid();
        SignatureOptionsCollection signsCollection = buildSignOptions(signDocumentRequest);
        return signDocumentByStream(documentGuid, signDocumentRequest.getPassword(), signsCollection);
    }

    private InputStream signDocumentByStream(String documentGuid, String password, SignatureOptionsCollection signsCollection) {
        // set save options
        final SaveOptions saveOptions = new SaveOptions();
        saveOptions.setOutputType(OutputType.Stream);

        // set password
        LoadOptions loadOptions = new LoadOptions();
        if (password != null && !password.isEmpty()) {
            loadOptions.setPassword(password);
        }

        SignatureHandler<OutputStream> streamSignatureHandler = createStreamHandler();

        try {
            ByteArrayOutputStream bos = (ByteArrayOutputStream) streamSignatureHandler.sign(new FileInputStream(documentGuid), signsCollection, loadOptions, saveOptions);
            return new ByteArrayInputStream(bos.toByteArray());
        } catch (Exception ex) {
            logger.error("Exception occurred while signing document", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    /**
     * Sign document by digital signature
     *
     * @param digital
     * @param documentType
     * @param signsCollection
     */
    private void signDigital(String password, List<SignatureDataEntity> digital, String documentType, SignatureOptionsCollection signsCollection) {
        try {
            for (int i = 0; i < digital.size(); i++) {
                SignatureDataEntity signatureDataEntity = digital.get(i);
                // initiate digital signer
                DigitalSigner signer = new DigitalSigner(signatureDataEntity, password);
                switch (documentType) {
                    case "Portable Document Format":
                        signsCollection.add(signer.signPdf());
                        break;
                    case "Microsoft Word":
                        signsCollection.add(signer.signWord());
                        break;
                    case "Microsoft Excel":
                        signsCollection.add(signer.signCells());
                        break;
                    default:
                        throw new IllegalStateException(String.format("File format %s is not supported.", documentType));
                }
            }
        } catch (Exception ex) {
            logger.error("Exception occurred while signing by digital signature", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    /**
     * Sign document with images
     *
     * @param documentType
     * @param images
     * @param signsCollection
     * @return
     */
    private void signImage(String documentType, List<SignatureDataEntity> images, SignatureOptionsCollection signsCollection) {
        try {
            for (int i = 0; i < images.size(); i++) {
                SignatureDataEntity signatureDataEntity = images.get(i);
                // initiate image signer object
                ImageSigner signer = new ImageSigner(signatureDataEntity);
                // prepare signing options and sign document
                addSignOptions(documentType, signsCollection, signer);
            }
        } catch (Exception ex) {
            logger.error("Exception occurred while signing by image signature", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    /**
     * Sign document with stamps
     *
     * @param documentType
     * @param stamps
     * @param signsCollection
     * @return
     */
    private void signStamp(String documentType, List<SignatureDataEntity> stamps, SignatureOptionsCollection signsCollection) {
        String xmlPath = getFullDataPathStr(signatureConfiguration.getDataDirectory(), STAMP_DATA_DIRECTORY.getXMLPath());
        try {
            for (int i = 0; i < stamps.size(); i++) {
                SignatureDataEntity signatureDataEntity = stamps.get(i);
                String fileName = getXMLFileName(xmlPath, signatureDataEntity.getSignatureGuid());
                StampXmlEntityList stampData = new XMLReaderWriter<StampXmlEntityList>().read(fileName, StampXmlEntityList.class);
                // since stamp ine are added stating from the most outer line we need to reverse the stamp data array
                List<StampXmlEntity> reverse = Lists.reverse(stampData.getStampXmlEntityList());
                // initiate stamp signer
                StampSigner signer = new StampSigner(reverse, signatureDataEntity);
                // prepare signing options and sign document
                addSignOptions(documentType, signsCollection, signer);
            }
        } catch (Exception ex) {
            logger.error("Exception occurred while signing by stamp", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    /**
     * Sign document with barcodes and/or qrcodes
     *
     * @param documentType
     * @param codes
     * @param signsCollection
     * @return
     */
    private void signOptical(String documentType, List<SignatureDataEntity> codes, SignatureOptionsCollection signsCollection) {
        try {
            // prepare signing options and sign document
            for (int i = 0; i < codes.size(); i++) {
                SignatureDataEntity signatureDataEntity = codes.get(i);
                // get xml files root path
                String signatureType = signatureDataEntity.getSignatureType();
                String xmlPath = getFullDataPathStr(signatureConfiguration.getDataDirectory(), (QR_CODE.equals(signatureType)) ?
                        QRCODE_DATA_DIRECTORY.getXMLPath() :
                        BARCODE_DATA_DIRECTORY.getXMLPath());
                // get xml data of the QR-Code
                String fileName = getXMLFileName(xmlPath, signatureDataEntity.getSignatureGuid());
                OpticalXmlEntity opticalCodeData = new XMLReaderWriter<OpticalXmlEntity>().read(fileName, OpticalXmlEntity.class);
                // initiate QRCode signer object
                Signer signer = (QR_CODE.equals(signatureType)) ? new QrCodeSigner(opticalCodeData, signatureDataEntity) : new BarCodeSigner(opticalCodeData, signatureDataEntity);
                // prepare signing options and sign document
                addSignOptions(documentType, signsCollection, signer);
            }
        } catch (Exception ex) {
            logger.error("Exception occurred while signing by optical code", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    /**
     * Sign document with text signature
     *
     * @param documentType
     * @param texts
     * @param signsCollection
     * @return
     */
    private void signText(String documentType, List<SignatureDataEntity> texts, SignatureOptionsCollection signsCollection) {
        try {
            // prepare signing options and sign document
            for (int i = 0; i < texts.size(); i++) {
                SignatureDataEntity signatureDataEntity = texts.get(i);
                // get xml data of the signature
                TextXmlEntity textData = new XMLReaderWriter<TextXmlEntity>().read(signatureDataEntity.getSignatureGuid(), TextXmlEntity.class);
                // initiate QRCode signer object
                TextSigner signer = new TextSigner(textData, signatureDataEntity);
                // prepare signing options and sign document
                addSignOptions(documentType, signsCollection, signer);
            }
        } catch (Exception ex) {
            logger.error("Exception occurred while signing by text signature", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
    }

    private String getXMLFileName(String xmlPath, String signatureGuid) {
        // get xml data of the signature
        String xmlFileName = FilenameUtils.removeExtension(new File(signatureGuid).getName());
        // Load xml data
        return String.format("%s%s%s.xml", xmlPath, File.separator, xmlFileName);
    }

    /**
     * Get fixed document type
     *
     * @param documentType
     * @param documentGuid
     * @param fileExtension
     * @return
     */
    private String getDocumentType(String documentType, String documentGuid, String fileExtension) {
        // mimeType should now be something like "image/png" if the document is image
        boolean isImage = supportedImageFormats.contains(fileExtension);
        return isImage ? "image" : documentType;
    }

    /**
     * Add current signature options to signs collection
     *
     * @param documentType
     * @param signsCollection
     * @param signer
     * @throws ParseException
     */
    private void addSignOptions(String documentType, SignatureOptionsCollection signsCollection, Signer signer) throws ParseException {
        switch (documentType) {
            case "Portable Document Format":
                signsCollection.add(signer.signPdf());
                break;
            case "Microsoft Word":
                signsCollection.add(signer.signWord());
                break;
            case "Microsoft PowerPoint":
                signsCollection.add(signer.signSlides());
                break;
            case "image":
                signsCollection.add(signer.signImage());
                break;
            case "Microsoft Excel":
                signsCollection.add(signer.signCells());
                break;
            default:
                throw new IllegalStateException(String.format("File format %s is not supported.", documentType));
        }
    }

    /**
     * Sign document
     *
     * @param documentGuid
     * @param password
     * @param signsCollection
     * @return signed document
     * @throws Exception
     */
    private SignedDocumentEntity signDocument(String documentGuid, String password, SignatureOptionsCollection signsCollection) {
        // set save options
        final SaveOptions saveOptions = new SaveOptions();
        saveOptions.setOutputType(OutputType.String);
        saveOptions.setOutputFileName(FilenameUtils.getName(documentGuid));
        saveOptions.setOverwriteExistingFiles(true);

        // set password
        LoadOptions loadOptions = new LoadOptions();
        if (password != null && !password.isEmpty()) {
            loadOptions.setPassword(password);
        }

        // sign document
        SignedDocumentEntity signedDocument = new SignedDocumentEntity();
        try {
            signatureHandler.getSignatureConfig().setOutputPath(FilenameUtils.getFullPath(documentGuid));
            signedDocument.setGuid(signatureHandler.sign(documentGuid, signsCollection, loadOptions, saveOptions).toString());
        } catch (Exception ex) {
            logger.error("Exception occurred while signing document", ex);
            throw new TotalGroupDocsException(ex.getMessage(), ex);
        }
        return signedDocument;
    }
}