Example usage for org.apache.pdfbox.pdmodel.interactive.form PDSignatureField getSignature

List of usage examples for org.apache.pdfbox.pdmodel.interactive.form PDSignatureField getSignature

Introduction

In this page you can find the example usage for org.apache.pdfbox.pdmodel.interactive.form PDSignatureField getSignature.

Prototype

public PDSignature getSignature() 

Source Link

Document

Get the signature dictionary.

Usage

From source file:at.gv.egiz.pdfas.lib.impl.signing.pdfbox.PADESPDFBOXSigner.java

License:EUPL

public void signPDF(PDFObject genericPdfObject, RequestedSignature requestedSignature,
        PDFASSignatureInterface genericSigner) throws PdfAsException {
    String fisTmpFile = null;/*  ww w.  j av a  2 s .c om*/

    PDFAsVisualSignatureProperties properties = null;

    if (!(genericPdfObject instanceof PDFBOXObject)) {
        // tODO:
        throw new PdfAsException();
    }

    PDFBOXObject pdfObject = (PDFBOXObject) genericPdfObject;

    if (!(genericSigner instanceof PDFASPDFBOXSignatureInterface)) {
        // tODO:
        throw new PdfAsException();
    }

    PDFASPDFBOXSignatureInterface signer = (PDFASPDFBOXSignatureInterface) genericSigner;

    TempFileHelper helper = pdfObject.getStatus().getTempFileHelper();
    PDDocument doc = pdfObject.getDocument();
    SignatureOptions options = new SignatureOptions();
    COSDocument visualSignatureDocumentGuard = null;
    try {
        fisTmpFile = helper.getStaticFilename();

        FileOutputStream tmpOutputStream = null;
        try {
            // write to temporary file
            tmpOutputStream = new FileOutputStream(new File(fisTmpFile));
            InputStream tmpis = null;
            try {
                tmpis = pdfObject.getOriginalDocument().getInputStream();
                IOUtils.copy(tmpis, tmpOutputStream);
                tmpis.close();
            } finally {
                IOUtils.closeQuietly(tmpis);
            }

            SignaturePlaceholderData signaturePlaceholderData = PlaceholderFilter
                    .checkPlaceholderSignature(pdfObject.getStatus(), pdfObject.getStatus().getSettings());

            TablePos tablePos = null;

            if (signaturePlaceholderData != null) {
                // Placeholder found!
                logger.info("Placeholder data found.");
                if (signaturePlaceholderData.getProfile() != null) {
                    logger.debug("Placeholder Profile set to: " + signaturePlaceholderData.getProfile());
                    requestedSignature.setSignatureProfileID(signaturePlaceholderData.getProfile());
                }

                tablePos = signaturePlaceholderData.getTablePos();
                if (tablePos != null) {

                    SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                            .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

                    float minWidth = signatureProfileConfiguration.getMinWidth();

                    if (minWidth > 0) {
                        if (tablePos.getWidth() < minWidth) {
                            tablePos.width = minWidth;
                            logger.debug("Correcting placeholder with to minimum width {}", minWidth);
                        }
                    }
                    logger.debug("Placeholder Position set to: " + tablePos.toString());
                }
            }

            PDSignature signature = new PDSignature();
            signature.setFilter(COSName.getPDFName(signer.getPDFFilter())); // default
            // filter
            signature.setSubFilter(COSName.getPDFName(signer.getPDFSubFilter()));

            SignatureProfileSettings signatureProfileSettings = TableFactory.createProfile(
                    requestedSignature.getSignatureProfileID(), pdfObject.getStatus().getSettings());

            ValueResolver resolver = new ValueResolver(requestedSignature, pdfObject.getStatus());
            String signerName = resolver.resolve("SIG_SUBJECT",
                    signatureProfileSettings.getValue("SIG_SUBJECT"), signatureProfileSettings);

            signature.setName(signerName);

            // take signing time from provided signer...
            signature.setSignDate(signer.getSigningDate());
            // ...and update operation status in order to use exactly this date for the complete signing process
            requestedSignature.getStatus().setSigningDate(signer.getSigningDate());

            String signerReason = signatureProfileSettings.getSigningReason();

            if (signerReason == null) {
                signerReason = "PAdES Signature";
            }

            signature.setReason(signerReason);
            logger.debug("Signing reason: " + signerReason);

            logger.debug("Signing @ " + signer.getSigningDate().getTime().toString());

            // the signing date, needed for valid signature
            // signature.setSignDate(signer.getSigningDate());

            signer.setPDSignature(signature);

            int signatureSize = 0x1000;
            try {
                String reservedSignatureSizeString = signatureProfileSettings.getValue(SIG_RESERVED_SIZE);
                if (reservedSignatureSizeString != null) {
                    signatureSize = Integer.parseInt(reservedSignatureSizeString);
                }
                logger.debug("Reserving {} bytes for signature", signatureSize);
            } catch (NumberFormatException e) {
                logger.warn("Invalid configuration value: {} should be a number using 0x1000",
                        SIG_RESERVED_SIZE);
            }
            options.setPreferedSignatureSize(signatureSize);

            // Is visible Signature
            if (requestedSignature.isVisual()) {
                logger.debug("Creating visual signature block");

                SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                        .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

                if (tablePos == null) {
                    // ================================================================
                    // PositioningStage (visual) -> find position or use
                    // fixed
                    // position

                    String posString = pdfObject.getStatus().getSignParamter().getSignaturePosition();

                    TablePos signaturePos = null;

                    String signaturePosString = signatureProfileConfiguration.getDefaultPositioning();

                    if (signaturePosString != null) {
                        logger.debug("using signature Positioning: " + signaturePos);
                        signaturePos = new TablePos(signaturePosString);
                    }

                    logger.debug("using Positioning: " + posString);

                    if (posString != null) {
                        // Merge Signature Position
                        tablePos = new TablePos(posString, signaturePos);
                    } else {
                        // Fallback to signature Position!
                        tablePos = signaturePos;
                    }

                    if (tablePos == null) {
                        // Last Fallback default position
                        tablePos = new TablePos();
                    }
                }
                boolean legacy32Position = signatureProfileConfiguration.getLegacy32Positioning();
                boolean legacy40Position = signatureProfileConfiguration.getLegacy40Positioning();

                // create Table describtion
                Table main = TableFactory.createSigTable(signatureProfileSettings, MAIN, pdfObject.getStatus(),
                        requestedSignature);

                IPDFStamper stamper = StamperFactory.createDefaultStamper(pdfObject.getStatus().getSettings());

                IPDFVisualObject visualObject = stamper.createVisualPDFObject(pdfObject, main);

                /*
                 * PDDocument originalDocument = PDDocument .load(new
                 * ByteArrayInputStream(pdfObject.getStatus()
                 * .getPdfObject().getOriginalDocument()));
                 */

                PositioningInstruction positioningInstruction = Positioning.determineTablePositioning(tablePos,
                        "", doc, visualObject, legacy32Position, legacy40Position);

                logger.debug("Positioning: {}", positioningInstruction.toString());

                if (positioningInstruction.isMakeNewPage()) {
                    int last = doc.getNumberOfPages() - 1;
                    PDDocumentCatalog root = doc.getDocumentCatalog();
                    PDPageNode rootPages = root.getPages();
                    List<PDPage> kids = new ArrayList<PDPage>();
                    rootPages.getAllKids(kids);
                    PDPage lastPage = kids.get(last);
                    rootPages.getCOSObject().setNeedToBeUpdate(true);
                    PDPage p = new PDPage(lastPage.findMediaBox());
                    p.setResources(new PDResources());
                    p.setRotation(lastPage.findRotation());
                    doc.addPage(p);
                }

                // handle rotated page
                PDDocumentCatalog documentCatalog = doc.getDocumentCatalog();
                PDPageNode documentPages = documentCatalog.getPages();
                List<PDPage> documentPagesKids = new ArrayList<PDPage>();
                documentPages.getAllKids(documentPagesKids);
                int targetPageNumber = positioningInstruction.getPage();
                logger.debug("Target Page: " + targetPageNumber);
                // rootPages.getAllKids(kids);
                PDPage targetPage = documentPagesKids.get(targetPageNumber - 1);
                int rot = targetPage.findRotation();
                logger.debug("Page rotation: " + rot);
                // positioningInstruction.setRotation(positioningInstruction.getRotation()
                // + rot);
                logger.debug("resulting Sign rotation: " + positioningInstruction.getRotation());

                SignaturePositionImpl position = new SignaturePositionImpl();
                position.setX(positioningInstruction.getX());
                position.setY(positioningInstruction.getY());
                position.setPage(positioningInstruction.getPage());
                position.setHeight(visualObject.getHeight());
                position.setWidth(visualObject.getWidth());

                requestedSignature.setSignaturePosition(position);

                properties = new PDFAsVisualSignatureProperties(pdfObject.getStatus().getSettings(), pdfObject,
                        (PdfBoxVisualObject) visualObject, positioningInstruction, signatureProfileSettings);

                properties.buildSignature();

                /*
                 * ByteArrayOutputStream sigbos = new
                 * ByteArrayOutputStream();
                 * sigbos.write(StreamUtils.inputStreamToByteArray
                 * (properties .getVisibleSignature())); sigbos.close();
                 */

                if (signaturePlaceholderData != null) {
                    // Placeholder found!
                    // replace placeholder
                    InputStream is = null;
                    try {
                        is = PADESPDFBOXSigner.class.getResourceAsStream("/placeholder/empty.jpg");
                        PDJpeg img = new PDJpeg(doc, is);

                        img.getCOSObject().setNeedToBeUpdate(true);

                        PDDocumentCatalog root = doc.getDocumentCatalog();
                        PDPageNode rootPages = root.getPages();
                        List<PDPage> kids = new ArrayList<PDPage>();
                        rootPages.getAllKids(kids);
                        int pageNumber = positioningInstruction.getPage();
                        // rootPages.getAllKids(kids);
                        PDPage page = kids.get(pageNumber - 1);

                        logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());
                        COSDictionary xobjectsDictionary = (COSDictionary) page.findResources()
                                .getCOSDictionary().getDictionaryObject(COSName.XOBJECT);
                        xobjectsDictionary.setItem(signaturePlaceholderData.getPlaceholderName(), img);
                        xobjectsDictionary.setNeedToBeUpdate(true);
                        page.findResources().getCOSObject().setNeedToBeUpdate(true);
                        logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());
                    } finally {
                        IOUtils.closeQuietly(is);
                    }
                }

                if (signatureProfileSettings.isPDFA()) {
                    PDDocumentCatalog root = doc.getDocumentCatalog();
                    COSBase base = root.getCOSDictionary().getItem(COSName.OUTPUT_INTENTS);
                    if (base == null) {
                        InputStream colorProfile = null;
                        try {
                            colorProfile = PDDocumentCatalog.class
                                    .getResourceAsStream("/icm/sRGB Color Space Profile.icm");

                            try {
                                PDOutputIntent oi = new PDOutputIntent(doc, colorProfile);
                                oi.setInfo("sRGB IEC61966-2.1");
                                oi.setOutputCondition("sRGB IEC61966-2.1");
                                oi.setOutputConditionIdentifier("sRGB IEC61966-2.1");
                                oi.setRegistryName("http://www.color.org");

                                root.addOutputIntent(oi);
                                root.getCOSObject().setNeedToBeUpdate(true);
                                logger.info("added Output Intent");
                            } catch (Throwable e) {
                                throw new PdfAsException("Failed to add Output Intent", e);
                            }
                        } finally {
                            IOUtils.closeQuietly(colorProfile);
                        }
                    }
                }

                options.setPage(positioningInstruction.getPage());

                options.setVisualSignature(properties.getVisibleSignature());
            }

            visualSignatureDocumentGuard = options.getVisualSignature();

            doc.addSignature(signature, signer, options);

            // set need to update indirect fields array in acro form
            COSDictionary trailer = doc.getDocument().getTrailer();
            if (trailer != null) {
                COSDictionary troot = (COSDictionary) trailer.getDictionaryObject(COSName.ROOT);
                if (troot != null) {
                    COSDictionary acroForm = (COSDictionary) troot.getDictionaryObject(COSName.ACRO_FORM);
                    if (acroForm != null) {
                        COSArray tfields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS);
                        if (tfields != null && !tfields.isDirect()) {
                            tfields.setNeedToBeUpdate(true);
                        }
                    }
                }
            }

            String sigFieldName = signatureProfileSettings.getSignFieldValue();

            if (sigFieldName == null) {
                sigFieldName = "PDF-AS Signatur";
            }

            int count = PdfBoxUtils.countSignatures(doc, sigFieldName);

            sigFieldName = sigFieldName + count;

            PDAcroForm acroFormm = doc.getDocumentCatalog().getAcroForm();

            PDSignatureField signatureField = null;
            if (acroFormm != null) {
                @SuppressWarnings("unchecked")
                List<PDField> fields = acroFormm.getFields();

                if (fields != null) {
                    for (PDField pdField : fields) {
                        if (pdField != null) {
                            if (pdField instanceof PDSignatureField) {
                                PDSignatureField tmpSigField = (PDSignatureField) pdField;

                                if (tmpSigField.getSignature() != null
                                        && tmpSigField.getSignature().getDictionary() != null) {
                                    if (tmpSigField.getSignature().getDictionary()
                                            .equals(signature.getDictionary())) {
                                        signatureField = (PDSignatureField) pdField;

                                    }
                                }
                            }
                        }
                    }
                } else {
                    logger.warn("Failed to name Signature Field! [Cannot find Field list in acroForm!]");
                }

                if (signatureField != null) {
                    signatureField.setPartialName(sigFieldName);
                }
                if (properties != null) {
                    signatureField.setAlternateFieldName(properties.getAlternativeTableCaption());
                } else {
                    signatureField.setAlternateFieldName(sigFieldName);
                }
            } else {
                logger.warn("Failed to name Signature Field! [Cannot find acroForm!]");
            }

            // PDF-UA
            logger.info("Adding pdf/ua content.");
            try {
                PDDocumentCatalog root = doc.getDocumentCatalog();
                PDStructureTreeRoot structureTreeRoot = root.getStructureTreeRoot();
                if (structureTreeRoot != null) {
                    logger.info("Tree Root: {}", structureTreeRoot.toString());
                    List<Object> kids = structureTreeRoot.getKids();

                    if (kids == null) {
                        logger.info("No kid-elements in structure tree Root, maybe not PDF/UA document");
                    }

                    PDStructureElement docElement = null;
                    for (Object k : kids) {
                        if (k instanceof PDStructureElement) {
                            docElement = (PDStructureElement) k;
                            break;

                        }
                    }

                    PDStructureElement sigBlock = new PDStructureElement("Form", docElement);

                    // create object dictionary and add as child element
                    COSDictionary objectDic = new COSDictionary();
                    objectDic.setName("Type", "OBJR");
                    objectDic.setItem("Pg", signatureField.getWidget().getPage());
                    objectDic.setItem("Obj", signatureField.getWidget());

                    List<Object> l = new ArrayList<Object>();
                    l.add(objectDic);
                    sigBlock.setKids(l);
                    sigBlock.setPage(signatureField.getWidget().getPage());

                    sigBlock.setTitle("Signature Table");
                    sigBlock.setParent(docElement);
                    docElement.appendKid(sigBlock);

                    // Create and add Attribute dictionary to mitigate PAC
                    // warning
                    COSDictionary sigBlockDic = (COSDictionary) sigBlock.getCOSObject();
                    COSDictionary sub = new COSDictionary();

                    sub.setName("O", "Layout");
                    sub.setName("Placement", "Block");
                    sigBlockDic.setItem(COSName.A, sub);
                    sigBlockDic.setNeedToBeUpdate(true);

                    // Modify number tree
                    PDNumberTreeNode ntn = structureTreeRoot.getParentTree();
                    int parentTreeNextKey = structureTreeRoot.getParentTreeNextKey();
                    if (ntn == null) {
                        ntn = new PDNumberTreeNode(objectDic, null);
                        logger.info("No number-tree-node found!");
                    }

                    COSArray ntnKids = (COSArray) ntn.getCOSDictionary().getDictionaryObject(COSName.KIDS);
                    COSArray ntnNumbers = (COSArray) ntn.getCOSDictionary().getDictionaryObject(COSName.NUMS);

                    if (ntnNumbers == null && ntnKids != null) {//no number array, so continue with the kids array

                        //create dictionary with limits and nums array
                        COSDictionary pTreeEntry = new COSDictionary();
                        COSArray limitsArray = new COSArray();
                        //limits for exact one entry
                        limitsArray.add(COSInteger.get(parentTreeNextKey));
                        limitsArray.add(COSInteger.get(parentTreeNextKey));

                        COSArray numsArray = new COSArray();
                        numsArray.add(COSInteger.get(parentTreeNextKey));
                        numsArray.add(sigBlock);

                        pTreeEntry.setItem(COSName.NUMS, numsArray);
                        pTreeEntry.setItem(COSName.LIMITS, limitsArray);

                        PDNumberTreeNode newKidsElement = new PDNumberTreeNode(pTreeEntry,
                                PDNumberTreeNode.class);

                        ntnKids.add(newKidsElement);
                        ntnKids.setNeedToBeUpdate(true);

                        //working
                        //                     List<PDNumberTreeNode> treeRootKids = structureTreeRoot.getParentTree().getKids();
                        //                     PDNumberTreeNode last = (PDNumberTreeNode)treeRootKids.get(treeRootKids.size()-1);
                        //                     COSArray lim1 = (COSArray) last.getCOSDictionary().getDictionaryObject(COSName.LIMITS);
                        //                     lim1.remove(1);
                        //                     lim1.add(1, COSInteger.get(parentTreeNextKey));
                        //                     PDNumberTreeNode verylast = (PDNumberTreeNode)last.getKids().get(last.getKids().size()-1);
                        //                     COSArray numa = (COSArray) verylast.getCOSDictionary().getDictionaryObject(COSName.NUMS);
                        //                     COSArray lim = (COSArray) verylast.getCOSDictionary().getDictionaryObject(COSName.LIMITS);
                        //                     lim.remove(1);
                        //                     lim.add(1, COSInteger.get(parentTreeNextKey));
                        //
                        //                     int size = numa.size();
                        //                     numa.add(size, COSInteger.get(parentTreeNextKey));
                        //                     numa.add(sigBlock);
                        //working end

                    } else if (ntnNumbers != null && ntnKids == null) {

                        int arrindex = ntnNumbers.size();

                        ntnNumbers.add(arrindex, COSInteger.get(parentTreeNextKey));
                        ntnNumbers.add(arrindex + 1, sigBlock.getCOSObject());

                        ntnNumbers.getCOSObject().setNeedToBeUpdate(true);

                        structureTreeRoot.setParentTree(ntn);

                    } else if (ntnNumbers == null && ntnKids == null) {
                        //document is not pdfua conform before signature creation
                        throw new PdfAsException("error.pdf.sig.pdfua.1");
                    } else {
                        //this is not allowed
                        throw new PdfAsException("error.pdf.sig.pdfua.1");
                    }

                    // set StructureParent for signature field annotation
                    signatureField.getWidget().setStructParent(parentTreeNextKey);

                    //Increase the next Key value in the structure tree root
                    structureTreeRoot.setParentTreeNextKey(parentTreeNextKey + 1);

                    // add the Tabs /S Element for Tabbing through annots
                    PDPage p = signatureField.getWidget().getPage();
                    p.getCOSDictionary().setName("Tabs", "S");
                    p.getCOSObject().setNeedToBeUpdate(true);

                    //check alternative signature field name
                    if (signatureField != null) {
                        if (signatureField.getAlternateFieldName().equals(""))
                            signatureField.setAlternateFieldName(sigFieldName);
                    }

                    ntn.getCOSDictionary().setNeedToBeUpdate(true);
                    sigBlock.getCOSObject().setNeedToBeUpdate(true);
                    structureTreeRoot.getCOSObject().setNeedToBeUpdate(true);
                    objectDic.getCOSObject().setNeedToBeUpdate(true);
                    docElement.getCOSObject().setNeedToBeUpdate(true);

                }

            } catch (Throwable e) {
                if (signatureProfileSettings.isPDFUA() == true) {
                    logger.error("Could not create PDF-UA conform document!");
                    throw new PdfAsException("error.pdf.sig.pdfua.1", e);
                } else {
                    logger.info("Could not create PDF-UA conform signature");
                }
            }

            try {
                applyFilter(doc, requestedSignature);
            } catch (PDFASError e) {
                throw new PdfAsErrorCarrier(e);
            }

            FileInputStream tmpFileIs = null;

            try {
                tmpFileIs = new FileInputStream(new File(fisTmpFile));
                synchronized (doc) {
                    doc.saveIncremental(tmpFileIs, tmpOutputStream);
                }
                tmpFileIs.close();
            } finally {
                IOUtils.closeQuietly(tmpFileIs);
                if (options != null) {
                    if (options.getVisualSignature() != null) {
                        options.getVisualSignature().close();
                    }
                }
            }
            tmpOutputStream.flush();
            tmpOutputStream.close();
        } finally {
            IOUtils.closeQuietly(tmpOutputStream);
            COSDocument visualSignature = options.getVisualSignature();
            if (visualSignature != null) {
                visualSignature.close();
            }
        }

        FileInputStream readReadyFile = null;
        try {
            readReadyFile = new FileInputStream(new File(fisTmpFile));

            // write to resulting output stream
            // ByteArrayOutputStream bos = new ByteArrayOutputStream();
            // bos.write();
            // bos.close();

            pdfObject.setSignedDocument(StreamUtils.inputStreamToByteArray(readReadyFile));
            readReadyFile.close();
        } finally {
            IOUtils.closeQuietly(readReadyFile);
        }
    } catch (IOException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } catch (SignatureException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } catch (COSVisitorException e) {
        logger.info(MessageResolver.resolveMessage("error.pdf.sig.01") + ": {}", e.toString());
        throw new PdfAsException("error.pdf.sig.01", e);
    } finally {
        if (doc != null) {
            try {
                doc.close();
            } catch (IOException e) {
                logger.debug("Failed to close COS Doc!", e);
                // Ignore
            }
        }

        if (fisTmpFile != null) {
            helper.deleteFile(fisTmpFile);
        }
        logger.debug("Signature done!");

    }
}

From source file:at.gv.egiz.pdfas.lib.impl.signing.pdfbox2.PADESPDFBOXSigner.java

License:EUPL

public void signPDF(PDFObject genericPdfObject, RequestedSignature requestedSignature,
        PDFASSignatureInterface genericSigner) throws PdfAsException {
    //String fisTmpFile = null;

    PDFAsVisualSignatureProperties properties = null;

    if (!(genericPdfObject instanceof PDFBOXObject)) {
        // tODO:/*from   www  . j av  a  2s  . c  o m*/
        throw new PdfAsException();
    }

    PDFBOXObject pdfObject = (PDFBOXObject) genericPdfObject;

    if (!(genericSigner instanceof PDFASPDFBOXSignatureInterface)) {
        // tODO:
        throw new PdfAsException();
    }

    PDFASPDFBOXSignatureInterface signer = (PDFASPDFBOXSignatureInterface) genericSigner;

    String pdfaVersion = null;

    PDDocument doc = null;
    SignatureOptions options = new SignatureOptions();
    COSDocument visualSignatureDocumentGuard = null;
    try {

        doc = pdfObject.getDocument();

        SignaturePlaceholderData signaturePlaceholderData = PlaceholderFilter
                .checkPlaceholderSignature(pdfObject.getStatus(), pdfObject.getStatus().getSettings());

        TablePos tablePos = null;

        if (signaturePlaceholderData != null) {
            // Placeholder found!
            logger.info("Placeholder data found.");
            if (signaturePlaceholderData.getProfile() != null) {
                logger.debug("Placeholder Profile set to: " + signaturePlaceholderData.getProfile());
                requestedSignature.setSignatureProfileID(signaturePlaceholderData.getProfile());
            }

            tablePos = signaturePlaceholderData.getTablePos();
            if (tablePos != null) {

                SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                        .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

                float minWidth = signatureProfileConfiguration.getMinWidth();

                if (minWidth > 0) {
                    if (tablePos.getWidth() < minWidth) {
                        tablePos.width = minWidth;
                        logger.debug("Correcting placeholder with to minimum width {}", minWidth);
                    }
                }
                logger.debug("Placeholder Position set to: " + tablePos.toString());
            }
        }

        PDSignature signature = new PDSignature();
        signature.setFilter(COSName.getPDFName(signer.getPDFFilter())); // default
        // filter
        signature.setSubFilter(COSName.getPDFName(signer.getPDFSubFilter()));

        SignatureProfileSettings signatureProfileSettings = TableFactory
                .createProfile(requestedSignature.getSignatureProfileID(), pdfObject.getStatus().getSettings());

        /*
         * Check if input document is PDF-A conform
         *
        if (signatureProfileSettings.isPDFA()) {
           // TODO: run preflight parser
           runPDFAPreflight(pdfObject.getOriginalDocument());
        }
        */

        ValueResolver resolver = new ValueResolver(requestedSignature, pdfObject.getStatus());
        String signerName = resolver.resolve("SIG_SUBJECT", signatureProfileSettings.getValue("SIG_SUBJECT"),
                signatureProfileSettings);

        signature.setName(signerName);

        // take signing time from provided signer...
        signature.setSignDate(signer.getSigningDate());
        // ...and update operation status in order to use exactly this date for the complete signing process
        requestedSignature.getStatus().setSigningDate(signer.getSigningDate());

        String signerReason = signatureProfileSettings.getSigningReason();

        if (signerReason == null) {
            signerReason = "PAdES Signature";
        }

        signature.setReason(signerReason);
        logger.debug("Signing reason: " + signerReason);

        logger.debug("Signing @ " + signer.getSigningDate().getTime().toString());
        // the signing date, needed for valid signature
        // signature.setSignDate(signer.getSigningDate());

        signer.setPDSignature(signature);

        int signatureSize = 0x1000;
        try {
            String reservedSignatureSizeString = signatureProfileSettings.getValue(SIG_RESERVED_SIZE);
            if (reservedSignatureSizeString != null) {
                signatureSize = Integer.parseInt(reservedSignatureSizeString);
            }
            logger.debug("Reserving {} bytes for signature", signatureSize);
        } catch (NumberFormatException e) {
            logger.warn("Invalid configuration value: {} should be a number using 0x1000", SIG_RESERVED_SIZE);
        }
        options.setPreferredSignatureSize(signatureSize);

        if (signatureProfileSettings.isPDFA() || signatureProfileSettings.isPDFA3()) {
            pdfaVersion = getPDFAVersion(doc);
            signatureProfileSettings.setPDFAVersion(pdfaVersion);
        }

        // Is visible Signature
        if (requestedSignature.isVisual()) {
            logger.debug("Creating visual signature block");

            SignatureProfileConfiguration signatureProfileConfiguration = pdfObject.getStatus()
                    .getSignatureProfileConfiguration(requestedSignature.getSignatureProfileID());

            if (tablePos == null) {
                // ================================================================
                // PositioningStage (visual) -> find position or use
                // fixed
                // position

                String posString = pdfObject.getStatus().getSignParamter().getSignaturePosition();

                TablePos signaturePos = null;

                String signaturePosString = signatureProfileConfiguration.getDefaultPositioning();

                if (signaturePosString != null) {
                    logger.debug("using signature Positioning: " + signaturePos);
                    signaturePos = new TablePos(signaturePosString);
                }

                logger.debug("using Positioning: " + posString);

                if (posString != null) {
                    // Merge Signature Position
                    tablePos = new TablePos(posString, signaturePos);
                } else {
                    // Fallback to signature Position!
                    tablePos = signaturePos;
                }

                if (tablePos == null) {
                    // Last Fallback default position
                    tablePos = new TablePos();
                }
            }

            //Legacy Modes not supported with pdfbox2 anymore
            //            boolean legacy32Position = signatureProfileConfiguration.getLegacy32Positioning();
            //            boolean legacy40Position = signatureProfileConfiguration.getLegacy40Positioning();

            // create Table describtion
            Table main = TableFactory.createSigTable(signatureProfileSettings, MAIN, pdfObject.getStatus(),
                    requestedSignature);

            IPDFStamper stamper = StamperFactory.createDefaultStamper(pdfObject.getStatus().getSettings());

            IPDFVisualObject visualObject = stamper.createVisualPDFObject(pdfObject, main);

            /*
             * PDDocument originalDocument = PDDocument .load(new
             * ByteArrayInputStream(pdfObject.getStatus()
             * .getPdfObject().getOriginalDocument()));
             */

            PositioningInstruction positioningInstruction = Positioning.determineTablePositioning(tablePos, "",
                    doc, visualObject, pdfObject.getStatus().getSettings());

            logger.debug("Positioning: {}", positioningInstruction.toString());

            if (positioningInstruction.isMakeNewPage()) {
                int last = doc.getNumberOfPages() - 1;
                PDDocumentCatalog root = doc.getDocumentCatalog();
                PDPage lastPage = root.getPages().get(last);
                root.getPages().getCOSObject().setNeedToBeUpdated(true);
                PDPage p = new PDPage(lastPage.getMediaBox());
                p.setResources(new PDResources());
                p.setRotation(lastPage.getRotation());
                doc.addPage(p);
            }

            // handle rotated page
            int targetPageNumber = positioningInstruction.getPage();
            logger.debug("Target Page: " + targetPageNumber);
            PDPage targetPage = doc.getPages().get(targetPageNumber - 1);
            int rot = targetPage.getRotation();
            logger.debug("Page rotation: " + rot);
            // positioningInstruction.setRotation(positioningInstruction.getRotation()
            // + rot);
            logger.debug("resulting Sign rotation: " + positioningInstruction.getRotation());

            SignaturePositionImpl position = new SignaturePositionImpl();
            position.setX(positioningInstruction.getX());
            position.setY(positioningInstruction.getY());
            position.setPage(positioningInstruction.getPage());
            position.setHeight(visualObject.getHeight());
            position.setWidth(visualObject.getWidth());

            requestedSignature.setSignaturePosition(position);

            properties = new PDFAsVisualSignatureProperties(pdfObject.getStatus().getSettings(), pdfObject,
                    (PdfBoxVisualObject) visualObject, positioningInstruction, signatureProfileSettings);

            properties.buildSignature();

            /*
             * ByteArrayOutputStream sigbos = new
             * ByteArrayOutputStream();
             * sigbos.write(StreamUtils.inputStreamToByteArray
             * (properties .getVisibleSignature())); sigbos.close();
             */

            if (signaturePlaceholderData != null) {
                // Placeholder found!
                // replace placeholder

                URL fileUrl = PADESPDFBOXSigner.class.getResource("/placeholder/empty.jpg");

                PDImageXObject img = PDImageXObject.createFromFile(fileUrl.getPath(), doc);

                img.getCOSObject().setNeedToBeUpdated(true);
                //                     PDDocumentCatalog root = doc.getDocumentCatalog();
                //                     PDPageNode rootPages = root.getPages();
                //                     List<PDPage> kids = new ArrayList<PDPage>();
                //                     rootPages.getAllKids(kids);
                int pageNumber = positioningInstruction.getPage();
                PDPage page = doc.getPages().get(pageNumber - 1);

                logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());
                COSDictionary xobjectsDictionary = (COSDictionary) page.getResources().getCOSObject()
                        .getDictionaryObject(COSName.XOBJECT);
                xobjectsDictionary.setItem(signaturePlaceholderData.getPlaceholderName(), img);
                xobjectsDictionary.setNeedToBeUpdated(true);
                page.getResources().getCOSObject().setNeedToBeUpdated(true);
                logger.info("Placeholder name: " + signaturePlaceholderData.getPlaceholderName());

            }

            if (signatureProfileSettings.isPDFA() || signatureProfileSettings.isPDFA3()) {
                PDDocumentCatalog root = doc.getDocumentCatalog();
                COSBase base = root.getCOSObject().getItem(COSName.OUTPUT_INTENTS);
                if (base == null) {
                    InputStream colorProfile = null;
                    try {
                        colorProfile = PDDocumentCatalog.class
                                .getResourceAsStream("/icm/sRGB Color Space Profile.icm");

                        try {
                            PDOutputIntent oi = new PDOutputIntent(doc, colorProfile);
                            oi.setInfo("sRGB IEC61966-2.1");
                            oi.setOutputCondition("sRGB IEC61966-2.1");
                            oi.setOutputConditionIdentifier("sRGB IEC61966-2.1");
                            oi.setRegistryName("http://www.color.org");

                            root.addOutputIntent(oi);
                            root.getCOSObject().setNeedToBeUpdated(true);
                            logger.info("added Output Intent");
                        } catch (Throwable e) {
                            e.printStackTrace();
                            throw new PdfAsException("Failed to add Output Intent", e);
                        }
                    } finally {
                        IOUtils.closeQuietly(colorProfile);
                    }
                }
            }

            options.setPage(positioningInstruction.getPage());

            options.setVisualSignature(properties.getVisibleSignature());
        }

        visualSignatureDocumentGuard = options.getVisualSignature();

        doc.addSignature(signature, signer, options);

        String sigFieldName = signatureProfileSettings.getSignFieldValue();

        if (sigFieldName == null) {
            sigFieldName = "PDF-AS Signatur";
        }

        int count = PdfBoxUtils.countSignatures(doc, sigFieldName);

        sigFieldName = sigFieldName + count;

        PDAcroForm acroFormm = doc.getDocumentCatalog().getAcroForm();

        // PDStructureTreeRoot pdstRoot =
        // doc.getDocumentCatalog().getStructureTreeRoot();
        // COSDictionary dic =
        // doc.getDocumentCatalog().getCOSDictionary();
        // PDStructureElement el = new PDStructureElement("Widget",
        // pdstRoot);

        PDSignatureField signatureField = null;
        if (acroFormm != null) {
            @SuppressWarnings("unchecked")
            List<PDField> fields = acroFormm.getFields();

            if (fields != null) {
                for (PDField pdField : fields) {
                    if (pdField != null) {
                        if (pdField instanceof PDSignatureField) {
                            PDSignatureField tmpSigField = (PDSignatureField) pdField;

                            if (tmpSigField.getSignature() != null
                                    && tmpSigField.getSignature().getCOSObject() != null) {
                                if (tmpSigField.getSignature().getCOSObject()
                                        .equals(signature.getCOSObject())) {
                                    signatureField = (PDSignatureField) pdField;

                                }
                            }
                        }
                    }
                }
            } else {
                logger.warn("Failed to name Signature Field! [Cannot find Field list in acroForm!]");
            }

            if (signatureField != null) {
                signatureField.setPartialName(sigFieldName);
            }
            if (properties != null) {
                signatureField.setAlternateFieldName(properties.getAlternativeTableCaption());
            } else {
                signatureField.setAlternateFieldName(sigFieldName);
            }
        } else {
            logger.warn("Failed to name Signature Field! [Cannot find acroForm!]");
        }

        // PDF-UA
        logger.info("Adding pdf/ua content.");
        try {
            PDDocumentCatalog root = doc.getDocumentCatalog();
            PDStructureTreeRoot structureTreeRoot = root.getStructureTreeRoot();
            if (structureTreeRoot != null) {
                logger.info("Tree Root: {}", structureTreeRoot.toString());
                List<Object> kids = structureTreeRoot.getKids();

                if (kids == null) {
                    logger.info("No kid-elements in structure tree Root, maybe not PDF/UA document");
                }

                PDStructureElement docElement = null;
                for (Object k : kids) {
                    if (k instanceof PDStructureElement) {
                        docElement = (PDStructureElement) k;
                        break;

                    }
                }

                PDStructureElement sigBlock = new PDStructureElement("Form", docElement);

                // create object dictionary and add as child element
                COSDictionary objectDic = new COSDictionary();
                objectDic.setName("Type", "OBJR");
                objectDic.setItem("Pg", signatureField.getWidget().getPage());
                objectDic.setItem("Obj", signatureField.getWidget());

                List<Object> l = new ArrayList<Object>();
                l.add(objectDic);
                sigBlock.setKids(l);
                sigBlock.setPage(signatureField.getWidget().getPage());

                sigBlock.setTitle("Signature Table");
                sigBlock.setParent(docElement);
                docElement.appendKid(sigBlock);

                // Create and add Attribute dictionary to mitigate PAC
                // warning
                COSDictionary sigBlockDic = (COSDictionary) sigBlock.getCOSObject();
                COSDictionary sub = new COSDictionary();

                sub.setName("O", "Layout");
                sub.setName("Placement", "Block");
                sigBlockDic.setItem(COSName.A, sub);
                sigBlockDic.setNeedToBeUpdated(true);

                // Modify number tree
                PDNumberTreeNode ntn = structureTreeRoot.getParentTree();
                int parentTreeNextKey = structureTreeRoot.getParentTreeNextKey();
                if (ntn == null) {
                    ntn = new PDNumberTreeNode(objectDic, null);
                    logger.info("No number-tree-node found!");
                }

                COSArray ntnKids = (COSArray) ntn.getCOSObject().getDictionaryObject(COSName.KIDS);
                COSArray ntnNumbers = (COSArray) ntn.getCOSObject().getDictionaryObject(COSName.NUMS);

                if (ntnNumbers == null && ntnKids != null) {//no number array, so continue with the kids array

                    //create dictionary with limits and nums array
                    COSDictionary pTreeEntry = new COSDictionary();
                    COSArray limitsArray = new COSArray();
                    //limits for exact one entry
                    limitsArray.add(COSInteger.get(parentTreeNextKey));
                    limitsArray.add(COSInteger.get(parentTreeNextKey));

                    COSArray numsArray = new COSArray();
                    numsArray.add(COSInteger.get(parentTreeNextKey));
                    numsArray.add(sigBlock);

                    pTreeEntry.setItem(COSName.NUMS, numsArray);
                    pTreeEntry.setItem(COSName.LIMITS, limitsArray);

                    PDNumberTreeNode newKidsElement = new PDNumberTreeNode(pTreeEntry, PDNumberTreeNode.class);

                    ntnKids.add(newKidsElement);
                    ntnKids.setNeedToBeUpdated(true);

                } else if (ntnNumbers != null && ntnKids == null) {

                    int arrindex = ntnNumbers.size();

                    ntnNumbers.add(arrindex, COSInteger.get(parentTreeNextKey));
                    ntnNumbers.add(arrindex + 1, sigBlock.getCOSObject());

                    ntnNumbers.setNeedToBeUpdated(true);

                    structureTreeRoot.setParentTree(ntn);

                } else if (ntnNumbers == null && ntnKids == null) {
                    //document is not pdfua conform before signature creation
                    throw new PdfAsException("error.pdf.sig.pdfua.1");
                } else {
                    //this is not allowed
                    throw new PdfAsException("error.pdf.sig.pdfua.1");
                }

                // set StructureParent for signature field annotation
                signatureField.getWidget().setStructParent(parentTreeNextKey);

                //Increase the next Key value in the structure tree root
                structureTreeRoot.setParentTreeNextKey(parentTreeNextKey + 1);

                // add the Tabs /S Element for Tabbing through annots
                PDPage p = signatureField.getWidget().getPage();
                p.getCOSObject().setName("Tabs", "S");
                p.getCOSObject().setNeedToBeUpdated(true);

                //check alternative signature field name
                if (signatureField != null) {
                    if (signatureField.getAlternateFieldName().equals(""))
                        signatureField.setAlternateFieldName(sigFieldName);
                }

                ntn.getCOSObject().setNeedToBeUpdated(true);
                sigBlock.getCOSObject().setNeedToBeUpdated(true);
                structureTreeRoot.getCOSObject().setNeedToBeUpdated(true);
                objectDic.setNeedToBeUpdated(true);
                docElement.getCOSObject().setNeedToBeUpdated(true);

            }
        } catch (Throwable e) {
            if (signatureProfileSettings.isPDFUA() == true) {
                logger.error("Could not create PDF-UA conform document!");
                throw new PdfAsException("error.pdf.sig.pdfua.1", e);
            } else {
                logger.info("Could not create PDF-UA conform signature");
            }
        }

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            synchronized (doc) {
                doc.saveIncremental(bos);
                byte[] outputDocument = bos.toByteArray();

                /*
                Check if resulting pdf is PDF-A conform
                 */
                //if (signatureProfileSettings.isPDFA()) {
                //   // TODO: run preflight parser
                //   runPDFAPreflight(outputDocument);
                //}

                pdfObject.setSignedDocument(outputDocument);
            }

        } finally {
            if (options != null) {
                if (options.getVisualSignature() != null) {
                    options.getVisualSignature().close();
                }
            }
        }

        System.gc();
    } catch (IOException e) {
        logger.warn(MessageResolver.resolveMessage("error.pdf.sig.01"), e);
        throw new PdfAsException("error.pdf.sig.01", e);
    } finally {
        if (doc != null) {
            try {
                doc.close();
            } catch (IOException e) {
                logger.debug("Failed to close COS Doc!", e);
                // Ignore
            }
        }

        logger.debug("Signature done!");

    }
}

From source file:com.formkiq.core.service.generator.pdfbox.PdfEditorServiceImpl.java

License:Apache License

/**
 * Sets value of {@link PDSignatureField}.
 * @param doc {@link PDDocument}/*from   ww w .java 2s .  co  m*/
 * @param field {@link PDSignatureField}
 * @param signatureInputStream {@link InputStream}
 * @return {@link SignatureOptions}
 * @throws IOException IOException
 */
private SignatureOptions setValue(final PDDocument doc, final PDSignatureField field,
        final InputStream signatureInputStream) throws IOException {

    int accessPermissions = SigUtils.getMDPPermission(doc);
    if (accessPermissions == 1) {
        throw new IllegalStateException("No changes to the document are "
                + "permitted due to DocMDP transform parameters " + "dictionary");
    }

    // retrieve signature dictionary
    PDSignature signature = field.getSignature();

    if (signature == null) {
        signature = new PDSignature();
        // after solving PDFBOX-3524 - signatureField.setValue(signature)
        // until then:
        field.getCOSObject().setItem(COSName.V, signature);
    } else {
        throw new IllegalStateException(
                "The signature field " + field.getFullyQualifiedName() + " is already signed.");
    }

    // Optional: certify
    // can be done only if version is at least 1.5 and if not already set
    // doing this on a PDF/A-1b file fails validation by Adobe
    // preflight (PDFBOX-3821)
    // PDF/A-1b requires PDF version 1.4 max, so don't increase the version
    // on such files.
    final float version = 1.5f;
    if (doc.getVersion() >= version && accessPermissions == 0) {
        SigUtils.setMDPPermission(doc, signature, 2);
    }

    PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
    if (acroForm != null && acroForm.getNeedAppearances()) {
        // PDFBOX-3738 NeedAppearances true results in visible signature
        // becoming invisible
        // with Adobe Reader
        if (acroForm.getFields().isEmpty()) {
            // we can safely delete it if there are no fields
            acroForm.getCOSObject().removeItem(COSName.NEED_APPEARANCES);
            // note that if you've set MDP permissions, the removal of this
            // item
            // may result in Adobe Reader claiming that the document has
            // been changed.
            // and/or that field content won't be displayed properly.
            // ==> decide what you prefer and adjust your code accordingly.
        }
    }

    // default filter
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);

    // subfilter for basic and PAdES Part 2 signatures
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

    PDVisibleSignDesigner visibleSignDesigner = new PDVisibleSignDesigner(signatureInputStream);

    PDVisibleSigProperties visibleSigProps = new PDVisibleSigProperties();
    visibleSigProps
            //        .signerName(name)  // TODO add..
            //        .signerLocation(location) // TODO add.
            //        .signatureReason(reason)
            //        .preferredSize(preferredSize)
            //        .page(0) // TODO fix
            .visualSignEnabled(true).setPdVisibleSignature(visibleSignDesigner);

    visibleSigProps.buildSignature();

    signature.setName(visibleSigProps.getSignerName());
    signature.setLocation(visibleSigProps.getSignerLocation());
    signature.setReason(visibleSigProps.getSignatureReason());

    // the signing date, needed for valid signature
    signature.setSignDate(Calendar.getInstance());

    SignatureOptions sigOptions = new SignatureOptions();
    sigOptions.setVisualSignature(visibleSigProps.getVisibleSignature());
    sigOptions.setPage(visibleSigProps.getPage() - 1);
    doc.addSignature(signature, this, sigOptions);

    return sigOptions;
}

From source file:mj.ocraptor.extraction.tika.parser.pdf.PDF2XHTML.java

License:Apache License

private void handleSignature(AttributesImpl parentAttributes, PDSignatureField sigField,
        XHTMLContentHandler handler) throws SAXException {

    PDSignature sig = sigField.getSignature();
    if (sig == null) {
        return;//from   w w w. java  2  s.c om
    }
    Map<String, String> vals = new TreeMap<String, String>();
    vals.put("name", sig.getName());
    vals.put("contactInfo", sig.getContactInfo());
    vals.put("location", sig.getLocation());
    vals.put("reason", sig.getReason());

    Calendar cal = sig.getSignDate();
    if (cal != null) {
        dateFormat.setTimeZone(cal.getTimeZone());
        vals.put("date", dateFormat.format(cal.getTime()));
    }
    // see if there is any data
    int nonNull = 0;
    for (String val : vals.keySet()) {
        if (val != null && !val.equals("")) {
            nonNull++;
        }
    }
    // if there is, process it
    if (nonNull > 0) {
        handler.startElement("li", parentAttributes);

        AttributesImpl attrs = new AttributesImpl();
        attrs.addAttribute("", "type", "type", "CDATA", "signaturedata");

        handler.startElement("ol", attrs);
        for (Map.Entry<String, String> e : vals.entrySet()) {
            if (e.getValue() == null || e.getValue().equals("")) {
                continue;
            }
            attrs = new AttributesImpl();
            attrs.addAttribute("", "signdata", "signdata", "CDATA", e.getKey());
            handler.startElement("li", attrs);
            handler.characters(e.getValue());
            handler.endElement("li");
        }
        handler.endElement("ol");
        handler.endElement("li");
    }
}

From source file:org.apache.tika.parser.pdf.AbstractPDF2XHTML.java

License:Apache License

private void handleSignature(AttributesImpl parentAttributes, PDSignatureField sigField) throws SAXException {

    PDSignature sig = sigField.getSignature();
    if (sig == null) {
        return;//from www  . ja  va 2  s .  com
    }
    Map<String, String> vals = new TreeMap<>();
    vals.put("name", sig.getName());
    vals.put("contactInfo", sig.getContactInfo());
    vals.put("location", sig.getLocation());
    vals.put("reason", sig.getReason());

    Calendar cal = sig.getSignDate();
    if (cal != null) {
        dateFormat.setTimeZone(cal.getTimeZone());
        vals.put("date", dateFormat.format(cal.getTime()));
    }
    //see if there is any data
    int nonNull = 0;
    for (String val : vals.keySet()) {
        if (val != null && !val.equals("")) {
            nonNull++;
        }
    }
    //if there is, process it
    if (nonNull > 0) {
        xhtml.startElement("li", parentAttributes);

        AttributesImpl attrs = new AttributesImpl();
        attrs.addAttribute("", "type", "type", "CDATA", "signaturedata");

        xhtml.startElement("ol", attrs);
        for (Map.Entry<String, String> e : vals.entrySet()) {
            if (e.getValue() == null || e.getValue().equals("")) {
                continue;
            }
            attrs = new AttributesImpl();
            attrs.addAttribute("", "signdata", "signdata", "CDATA", e.getKey());
            xhtml.startElement("li", attrs);
            xhtml.characters(e.getValue());
            xhtml.endElement("li");
        }
        xhtml.endElement("ol");
        xhtml.endElement("li");
    }
}

From source file:org.apache.tika.parser.pdf.EnhancedPDF2XHTML.java

License:Apache License

private void handleSignature(AttributesImpl parentAttributes, PDSignatureField sigField,
        XHTMLContentHandler handler) throws SAXException {

    PDSignature sig = sigField.getSignature();
    if (sig == null) {
        return;// ww  w .  j  a  v  a 2  s  . com
    }
    Map<String, String> vals = new TreeMap<String, String>();
    vals.put("name", sig.getName());
    vals.put("contactInfo", sig.getContactInfo());
    vals.put("location", sig.getLocation());
    vals.put("reason", sig.getReason());

    Calendar cal = sig.getSignDate();
    if (cal != null) {
        dateFormat.setTimeZone(cal.getTimeZone());
        vals.put("date", dateFormat.format(cal.getTime()));
    }
    //see if there is any data
    int nonNull = 0;
    for (String val : vals.keySet()) {
        if (val != null && !val.equals("")) {
            nonNull++;
        }
    }
    //if there is, process it
    if (nonNull > 0) {
        handler.startElement("li", parentAttributes);

        AttributesImpl attrs = new AttributesImpl();
        attrs.addAttribute("", "type", "type", "CDATA", "signaturedata");

        handler.startElement("ol", attrs);
        for (Map.Entry<String, String> e : vals.entrySet()) {
            if (e.getValue() == null || e.getValue().equals("")) {
                continue;
            }
            attrs = new AttributesImpl();
            attrs.addAttribute("", "signdata", "signdata", "CDATA", e.getKey());
            handler.startElement("li", attrs);
            handler.characters(e.getValue());
            handler.endElement("li");
        }
        handler.endElement("ol");
        handler.endElement("li");
    }
}