Package org.jbpm.ui.util

Source Code of org.jbpm.ui.util.InfoPathSupport

package org.jbpm.ui.util;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.xml.DOMParser;
import org.eclipse.core.resources.IFile;
import org.jbpm.ui.DesignerLogger;
import org.jbpm.ui.DesignerPlugin;
import org.jbpm.ui.PluginConstants;
import org.jbpm.ui.common.model.FormNode;
import org.jbpm.ui.common.model.Variable;
import org.jbpm.ui.infopath.TypeMapper;
import org.jbpm.ui.infopath.ValidationMapper;
import org.jbpm.ui.validation.ValidatorConfig;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

public class InfoPathSupport extends Thread {
    private static final String TEMPLATE_XML_FILE_NAME = "template.xml";

    private static final Pattern NAME_ATTR_PATTERN = Pattern.compile("name=\"(.[^\"]*)\"");

    private static final Pattern PUBLISH_URL_ATTR_PATTERN = Pattern.compile("publishUrl=\"(.[^\"]*)\"");

    private static final File ASSEMBLY_TMP_FOLDER = new File(DesignerPlugin.getDefault().getStateLocation().toFile(), "infopathassembly");

    private static final String MYSCHEMA_XSD_FILE_NAME = "myschema.xsd";

    private static final String MANIFEST_FILE_NAME = "manifest.xsf";

    private static final int BUFFER_SIZE = 4096;

    static {
        System.loadLibrary("RunaGPDInfoPathSupport");
        if (!ASSEMBLY_TMP_FOLDER.exists()) {
            ASSEMBLY_TMP_FOLDER.mkdirs();
        }
    }

    private static Object nativeDllLock = new Object();

    private static native boolean isXSNFileValid(String fullPath) throws Exception;

    private static native void createInfoPathXSNFile(String templatesFolderPath, String xsnFilePath) throws Exception;

    private static native void extractFileFromXSN(String xsnFolderPath, String xsnFileName, String extractedFolderPath, String extractedFileName)
            throws Exception;

    private static native void extractAllFilesFromXSN(String xsnFolderPath, String xsnFileName, String extractedFolderPath) throws Exception;

    private final File xsnFormFile;

    private final FormNode formNode;

    private final IFile file;

    private final File tmpFolder;

    private Process process;

    public InfoPathSupport(FormNode formNode, IFile file, String xsnFilePath) {
        this.formNode = formNode;
        this.file = file;
        this.tmpFolder = new File(ASSEMBLY_TMP_FOLDER, formNode.getName());
        this.xsnFormFile = new File(xsnFilePath);
        setName(PluginConstants.NON_GUI_THREAD_NAME);
    }

    public boolean init() throws Exception {
        if (this.tmpFolder.exists()) {
            this.tmpFolder.delete();
        }
        this.tmpFolder.mkdir();
        synchronized (nativeDllLock) {
            if (!xsnFormFile.exists() || !isXSNFileValid(xsnFormFile.getAbsolutePath())) {
                createXSN(xsnFormFile);
            } else {
                republishXSN(xsnFormFile);
            }
            Thread.sleep(700);
        }
        return true;
    }

    public boolean rewriteXsnFileWithAnotherTemplateId() throws Exception {
        if (this.tmpFolder.exists()) {
            return false;
        }
        try {
            this.tmpFolder.mkdir();
            synchronized (nativeDllLock) {
                if (xsnFormFile.exists()) {
                    republishXSN(xsnFormFile);
                }
            }
            return true;
        } finally {
            File[] files = tmpFolder.listFiles();
            for (int i = 0; i < files.length; i++) {
                deleteFile(files[i]);
            }
            deleteFile(tmpFolder);
        }
    }

    public void setProcess(Process process) {
        this.process = process;
    }

    @Override
    public void run() {
        try {
            process.waitFor();
            synchronized (nativeDllLock) {
                transform();
            }
        } catch (Throwable e) {
            DesignerLogger.logErrorWithoutDialog("InfoPath process error", e);
        }
        try {
            File[] files = tmpFolder.listFiles();
            for (int i = 0; i < files.length; i++) {
                deleteFile(files[i]);
            }
            deleteFile(tmpFolder);
        } catch (Throwable e) {
            DesignerLogger.logErrorWithoutDialog("InfoPath, remove files error", e);
        }
    }

    private void republishXSN(File xsnFile) throws Exception {
        extractAllFilesFromXSN(xsnFile.getParent() + "\\", xsnFile.getName(), tmpFolder.getAbsolutePath() + "\\");
        xsnFile.delete();
        publishXSN(xsnFile);
    }

    private void createXSN(File xsnFormFile) throws Exception {
        String[] fileNames = { "myschema.xsd", "sampledata.xml", TEMPLATE_XML_FILE_NAME, "view1.xsl", MANIFEST_FILE_NAME };
        for (int i = 0; i < fileNames.length; i++) {
            InputStream is = InfoPathSupport.class.getResourceAsStream("/infopathform/" + fileNames[i]);
            if (is != null) {
                copyFile(is, new File(tmpFolder, fileNames[i]));
            }
        }
        publishXSN(xsnFormFile);
    }

    private void publishXSN(File xsnFile) throws Exception {
        xsnFile.createNewFile();

        // "urn:schemas-microsoft-com:office:infopath:ID:-myXSD-2008-01-19T14-43-23"
        StringBuffer templateIdBuffer = new StringBuffer("urn:office:infopath:");
        templateIdBuffer.append(String.valueOf(System.currentTimeMillis())).append(":-myXSD-");
        templateIdBuffer.append(new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss").format(new Date()));
        String infoPathFormTemplateId = templateIdBuffer.toString().replaceAll(" ", "");
        logDebug("Using INFOPATHFORMTEMPLATEID: " + infoPathFormTemplateId);

        byte[] xsfManifestData = readBytesFromStream(new FileInputStream(new File(tmpFolder, MANIFEST_FILE_NAME)));
        String xsfManifest = new String(xsfManifestData, PluginConstants.UTF_ENCODING);

        Matcher m = NAME_ATTR_PATTERN.matcher(xsfManifest);
        StringBuffer buffer = new StringBuffer();
        if (m.find()) {
            m.appendReplacement(buffer, Matcher.quoteReplacement("name=\"" + infoPathFormTemplateId + "\""));
        }
        m.appendTail(buffer);
        String content = buffer.toString();

        // delete publishUrl attribute
        m = PUBLISH_URL_ATTR_PATTERN.matcher(content);
        buffer = new StringBuffer();
        if (m.find()) {
            logDebug("Found attribute 'publishUrl', deleting");
            m.appendReplacement(buffer, "");
        }
        m.appendTail(buffer);
        content = buffer.toString();
        //

        copyFile(new ByteArrayInputStream(content.getBytes(PluginConstants.UTF_ENCODING)), new File(tmpFolder, MANIFEST_FILE_NAME));

        byte[] xmlTemplateData = readBytesFromStream(new FileInputStream(new File(tmpFolder, "template.xml")));
        String xmlTemplate = new String(xmlTemplateData, PluginConstants.UTF_ENCODING);

        m = NAME_ATTR_PATTERN.matcher(xmlTemplate);
        buffer = new StringBuffer();
        while (m.find()) {
            m.appendReplacement(buffer, Matcher.quoteReplacement("name=\"" + infoPathFormTemplateId + "\""));
        }
        m.appendTail(buffer);
        xmlTemplate = buffer.toString();
        copyFile(new ByteArrayInputStream(xmlTemplate.getBytes(PluginConstants.UTF_ENCODING)), new File(tmpFolder, "template.xml"));

        createInfoPathXSNFile(tmpFolder.getAbsolutePath() + "\\", xsnFile.getAbsolutePath());
    }

    private void copyFile(InputStream inputStream, File destFile) throws IOException {
        destFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(destFile);
        byte[] buff = new byte[32 * 1024];
        int length;
        while (inputStream.available() > 0) {
            length = inputStream.read(buff);
            if (length > 0)
                fos.write(buff, 0, length);
        }
        inputStream.close();
        closeStream(fos);
    }

    private byte[] readXsnFile(File xsnFile, String fileName) throws Exception {
        extractFileFromXSN(xsnFile.getParent() + "\\", xsnFile.getName(), tmpFolder.getAbsolutePath() + "\\", fileName);
        return readBytesFromStream(new FileInputStream(new File(tmpFolder, fileName)));
    }

    private byte[] readBytesFromStream(InputStream inputStream) throws IOException {
        byte[] data = new byte[BUFFER_SIZE];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        OutputStream bos = new BufferedOutputStream(baos, BUFFER_SIZE);
        try {
            int bytesRead;
            while ((bytesRead = inputStream.read(data)) != -1) {
                bos.write(data, 0, bytesRead);
            }
        } finally {
            closeStream(baos);
            closeStream(bos);
            inputStream.close();
        }
        return baos.toByteArray();
    }

    private void closeStream(OutputStream outputStream) throws IOException {
        if (outputStream != null) {
            outputStream.flush();
            outputStream.close();
        }
    }

    private void deleteFile(File file) {
        if (file.exists()) {
            if (!file.delete()) {
                DesignerLogger.logInfo("WARNING: File " + file.getAbsolutePath() + " was not deleted.");
            }
        }
    }

    private void logDebug(String str) {
        DesignerLogger.logInfo("InfoPath [DEBUG]: " + str);
    }

    private void transform() throws Exception {
        byte[] xsdData = readXsnFile(xsnFormFile, MYSCHEMA_XSD_FILE_NAME);
        Document xsd = (Document) new DOMParser().parseXML(new ByteArrayInputStream(xsdData));
        byte[] xsfData = readXsnFile(xsnFormFile, MANIFEST_FILE_NAME);
        Document xsf = (Document) new DOMParser().parseXML(new ByteArrayInputStream(xsfData));

        List<Variable> formVariables = new ArrayList<Variable>();

        String namespace = "my";
        String rootGroup = "myFields";

        JXPathContext xsdDocContext = JXPathContext.newContext(xsd);
        JXPathContext xsfDocContext = JXPathContext.newContext(xsf);

        // extracting xsf properties
        String namespacePropValue = (String) xsfDocContext.getValue("//xsf:property[@name=\"namespace\"]/@value");
        NamedNodeMap attrs = xsf.getElementsByTagName("xsf:xDocumentClass").item(0).getAttributes();
        for (int j = 0; j < attrs.getLength(); j++) {
            Node attr = attrs.item(j);
            if (namespacePropValue.equals(attr.getNodeValue())) {
                namespace = attr.getNodeName().toLowerCase().substring(6);
                break;
            }
        }
        rootGroup = (String) xsfDocContext.getValue("//xsf:property[@name=\"rootElement\"]/@value");
        logDebug("Using namespace property: " + namespace);
        logDebug("Using rootElement property: " + rootGroup);

        // extracting all form variables
        List<String> rootGroupElementNames = new ArrayList<String>();

        Node rootNode = (Node) xsdDocContext.selectSingleNode("/xsd:schema/xsd:element[@name=\"" + rootGroup + "\"]");
        JXPathContext rootGroupContext = JXPathContext.newContext(xsdDocContext, rootNode);
        List<Node> nodes = rootGroupContext.selectNodes("//xsd:element");
        for (Node node : nodes) {
            JXPathContext elementContext = JXPathContext.newContext(xsdDocContext, node);
            String globalName = (String) elementContext.getValue("@ref");
            rootGroupElementNames.add(globalName.substring(namespace.length() + 1));
        }
        nodes = xsdDocContext.selectNodes("/xsd:schema/xsd:element[@type]");
        for (Node node : nodes) {
            String varName = (String) JXPathContext.newContext(xsdDocContext, node).getValue("@name");
            String varType = (String) JXPathContext.newContext(xsdDocContext, node).getValue("@type");
            if ((varType != null) && (varType.length() > 0)) {
                // if (rootGroupElementNames.contains(varName)) { // this check
                // for single elements
                logDebug("Found variable: " + varName + " of type " + varType);
                Variable variable = new Variable(varName);
                variable.setFormat(TypeMapper.getWfeTypeForInfopathType(varType));
                formVariables.add(variable);
            }
        }

        List<String> variableNames = formNode.getProcessDefinition().getVariableNames(true);

        // Base Validation, do not remove
        Map<String, Map<String, ValidatorConfig>> validators = new HashMap<String, Map<String, ValidatorConfig>>();
        for (Variable var : formVariables) {
            validators.put(var.getName(), new HashMap<String, ValidatorConfig>());
            if (!variableNames.contains(var.getName())) {
                formNode.getProcessDefinition().addVariable(var);
            }
        }

        // Additional validation starts here
        ValidationMapper.init(validators, namespace, rootGroup);
        // extracting form validation
        nodes = xsfDocContext.selectNodes("//xsf:errorCondition");
        for (Node node : nodes) {
            JXPathContext context = JXPathContext.newContext(xsfDocContext, node);
            String match = (String) context.getValue("@match");
            String expressionContext = (String) context.getValue("@expressionContext");
            String expression = (String) context.getValue("@expression");

            String shortErrorMessage = (String) context.getValue("xsf:errorMessage/@shortMessage");
            String errorMessage = (String) context.getValue("xsf:errorMessage");
            if (shortErrorMessage.length() > errorMessage.length()) {
                errorMessage = shortErrorMessage;
            }

            logDebug("Found validation rule: " + match + " | " + expressionContext + " | " + expression + " | " + errorMessage);
            ValidationMapper.apply(match, expressionContext, expression, errorMessage);
        }
        // Additional validation ends here

        // creating validation for form do not remove
        ValidationUtil.rewriteValidation(file, formNode.getValidationFileName(), validators);
    }

}
TOP

Related Classes of org.jbpm.ui.util.InfoPathSupport

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.