org.pepstock.jem.jbpm.JBpmFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.jbpm.JBpmFactory.java

Source

/**
JEM, the BEE - Job Entry Manager, the Batch Execution Environment
Copyright (C) 2012-2015   Andrea "Stock" Stocchero
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
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 General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.pepstock.jem.jbpm;

import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang.StringUtils;
import org.jbpm.runtime.manager.impl.SimpleRegisterableItemsFactory;
import org.jbpm.runtime.manager.impl.SimpleRuntimeEnvironment;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.internal.io.ResourceFactory;
import org.pepstock.jem.Jcl;
import org.pepstock.jem.Job;
import org.pepstock.jem.factories.AbstractFactory;
import org.pepstock.jem.factories.JclFactoryException;
import org.pepstock.jem.log.LogAppl;
import org.pepstock.jem.node.Main;
import org.pepstock.jem.node.configuration.ConfigKeys;
import org.pepstock.jem.node.tasks.JobTask;
import org.pepstock.jem.util.CharSet;
import org.pepstock.jem.util.Parser;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * This implements JemFactory interface to create, check and validate JCL for
 * JBPM. It creates JCL object.
 * 
 * @see org.pepstock.jem.factories.JemFactory
 * @author Andrea "Stock" Stocchero
 * @version 2.2
 */
public class JBpmFactory extends AbstractFactory {

    private static final long serialVersionUID = 1L;

    /**
     * public key which indicates the JCL type for JBPM
     */
    public static final String JBPM_TYPE = "jbpm";

    private static final String JBPM_TYPE_DESCRIPTION = "JBoss BPM";

    private static final String PROCESS_XML_ELEMENT = "process";

    private static final String ID_XML_ATTRIBUTE = "id";

    /**
     * Empty constructor
     */
    public JBpmFactory() {
        super();
    }

    /* (non-Javadoc)
     * @see org.pepstock.jem.factories.JemFactory#getType()
     */
    @Override
    public String getType() {
        return JBPM_TYPE;
    }

    /* (non-Javadoc)
     * @see org.pepstock.jem.factories.JemFactory#getTypeDescription()
     */
    @Override
    public String getTypeDescription() {
        return JBPM_TYPE_DESCRIPTION;
    }

    /* (non-Javadoc)
     * @see org.pepstock.jem.factories.JclFactory#createJcl(java.lang.String)
     */
    @Override
    public Jcl createJcl(String content) throws JclFactoryException {
        // creates a default JCL
        Jcl jcl = new Jcl();
        // sets type and content
        jcl.setType(JBPM_TYPE);
        jcl.setContent(content);
        try {
            // validates JCL
            validate(jcl, content);
        } catch (JBpmException e) {
            throw new JclFactoryException(jcl, e);
        }
        return jcl;
    }

    /* (non-Javadoc)
     * @see org.pepstock.jem.factories.JobTaskFactory#createJobTask(org.pepstock.jem.Job)
     */
    @Override
    public JobTask createJobTask(Job job) {
        return new JBpmTask(job, this);
    }

    /**
     * Validates the JCL content, calling the JBPM API 
     * @param jcl default JCL to store into job
     * @param content JCL content
     * @throws JBpmException if any error occurs
     */
    private void validate(Jcl jcl, String content) throws JBpmException {
        // read the BPMN Metadata, loading in properties object
        Properties p = new Properties();

        // creates all readers
        StringReader reader = new StringReader(content);
        InputSource source = new InputSource(reader);
        SimpleRuntimeEnvironment jbpmEnvironment = null;
        String jobName = null;

        // SCANS JCL to get JOBNAME
        // JOBNAME = attribute ID of PROCESS element
        try {
            // creates DOM objects
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setIgnoringComments(false);
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(source);

            // scan XML to read comment
            NodeList nl = doc.getDocumentElement().getChildNodes();
            // scans all nodes
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node.getNodeType() == Element.ELEMENT_NODE) {
                    Element el = (Element) node;

                    String tagName = null;
                    // checks if name space
                    if (el.getTagName().contains(":")) {
                        tagName = StringUtils.substringAfter(el.getTagName(), ":");
                    } else {
                        tagName = el.getTagName();
                    }
                    // checks only if is a PROCESS element
                    if (tagName.equalsIgnoreCase(PROCESS_XML_ELEMENT)) {
                        // gets ID attribute to set JOBNAME
                        String jobNameAttr = el.getAttribute(ID_XML_ATTRIBUTE);
                        if (jobNameAttr != null) {
                            // puts on properties
                            p.setProperty(JBpmKeys.JBPM_JOB_NAME, jobNameAttr);
                        } else {
                            throw new JBpmException(JBpmMessage.JEMM031E);
                        }
                    }
                }
            }

            // checks if project has attribute name, if yes, uses it as JOB NAME
            // otherwise get the JEM property to define it
            jobName = p.getProperty(JBpmKeys.JBPM_JOB_NAME);

            // Anyway job name can't be null. if yes, exception occurs
            if (jobName == null) {
                throw new JBpmException(JBpmMessage.JEMM031E);
            }
            // loads JCL jobname
            jcl.setJobName(jobName);

            // creates JBPM environment to check BPMN2 syntax
            SimpleRegisterableItemsFactory factory = new SimpleRegisterableItemsFactory();
            jbpmEnvironment = new SimpleRuntimeEnvironment(factory);
            jbpmEnvironment.setUsePersistence(false);
            Resource res = ResourceFactory.newReaderResource(new StringReader(content),
                    CharSet.DEFAULT_CHARSET_NAME);
            jbpmEnvironment.addAsset(res, ResourceType.BPMN2);
            // gets process to read metadata
            org.kie.api.definition.process.Process process = jbpmEnvironment.getKieBase().getProcess(jobName);
            // if process is null, exception
            if (process == null) {
                throw new JBpmException(JBpmMessage.JEMM063E);
            }
            // loads all METADATA
            p.putAll(process.getMetaData());

            // check again because you could put the job name on metadata
            jcl.setJobName(p.getProperty(JBpmKeys.JBPM_JOB_NAME));

            // loads the JBPM process ID in a map to reuse when a JBPM task will be scheduled
            Map<String, Object> jclMap = new HashMap<String, Object>();
            jclMap.put(JBpmKeys.JBPM_JOB_NAME, jobName);
            jcl.setProperties(jclMap);

        } catch (DOMException e) {
            throw new JBpmException(JBpmMessage.JEMM047E, e, e.getMessage());
        } catch (ParserConfigurationException e) {
            throw new JBpmException(JBpmMessage.JEMM047E, e, e.getMessage());
        } catch (SAXException e) {
            throw new JBpmException(JBpmMessage.JEMM047E, e, e.getMessage());
        } catch (Exception e) {
            throw new JBpmException(JBpmMessage.JEMM047E, e, e.getMessage());
        } finally {
            // clean up of JBPM environment
            if (jbpmEnvironment != null && jobName != null) {
                try {
                    jbpmEnvironment.getKieBase().removeProcess(jobName);
                } catch (Exception e) {
                    LogAppl.getInstance().debug(e.getMessage(), e);
                }
            }
        }

        // if I'm here, JCL is correct

        // extracts the locking scope and checks if the value is correct
        // the value is not save in JCL because is not helpful to node but
        // at runtime so it will be read again from ANT listener
        String lockingScopeProperty = p.getProperty(JBpmKeys.JBPM_LOCKING_SCOPE);
        if (lockingScopeProperty != null && !lockingScopeProperty.equalsIgnoreCase(JBpmKeys.JBPM_JOB_SCOPE)
                && !lockingScopeProperty.equalsIgnoreCase(JBpmKeys.JBPM_STEP_SCOPE)
                && !lockingScopeProperty.equalsIgnoreCase(JBpmKeys.JBPM_TASK_SCOPE)) {
            throw new JBpmException(JBpmMessage.JEMM032E, JBpmKeys.JBPM_LOCKING_SCOPE, lockingScopeProperty);
        }

        // Extracts from ANT enviroment property
        String environment = p.getProperty(JBpmKeys.JBPM_ENVIRONMENT);
        // if null, uses current environment assigned to JEM NODE
        if (environment == null) {
            environment = Main.EXECUTION_ENVIRONMENT.getEnvironment();
        }

        // Extracts from ANT domain property
        String domain = p.getProperty(JBpmKeys.JBPM_DOMAIN);
        // if null, uses domain default
        if (domain == null) {
            domain = Jcl.DEFAULT_DOMAIN;
        }

        // Extracts from ANT email addresses notification property
        String emailAddresses = p.getProperty(JBpmKeys.JBPM_EMAILS_NOTIFICATION);
        if (null != emailAddresses) {
            jcl.setEmailNotificationAddresses(emailAddresses);
        }
        // Extracts from ANT affinity property
        String affinity = p.getProperty(JBpmKeys.JBPM_AFFINITY);
        // if null, uses affinity default
        if (affinity == null) {
            affinity = Jcl.DEFAULT_AFFINITY;
        }

        // Extracts from ANT user property
        String user = p.getProperty(JBpmKeys.JBPM_USER);
        if (null != user) {
            jcl.setUser(user);
        }

        // Extracts from ANT classpath property
        String classPath = p.getProperty(JBpmKeys.JBPM_CLASSPATH);
        // if classpath is not set, changes if some variables are in
        if (classPath != null) {
            jcl.setClassPath(super.resolvePathNames(classPath, ConfigKeys.JEM_CLASSPATH_PATH_NAME));
        }

        // Extracts from ANT prior classpath property
        String priorClassPath = p.getProperty(JBpmKeys.JBPM_PRIOR_CLASSPATH);
        // if classpath is not set, changes if some variables are in
        if (priorClassPath != null) {
            jcl.setPriorClassPath(super.resolvePathNames(priorClassPath, ConfigKeys.JEM_CLASSPATH_PATH_NAME));
        }

        // Extracts from ANT memory property. If missing, default is 256 
        int memory = Parser.parseInt(p.getProperty(JBpmKeys.JBPM_MEMORY), Jcl.DEFAULT_MEMORY);
        // Extracts from ANT hold property. If missing, default is FALSE
        boolean hold = Parser.parseBoolean(p.getProperty(JBpmKeys.JBPM_HOLD), false);
        // Extracts from ANT priority property. If missing, default is 10
        int priority = Parser.parseInt(p.getProperty(JBpmKeys.JBPM_PRIORITY), Jcl.DEFAULT_PRIORITY);

        // saves all info inside of JCL object for further computing

        jcl.setEnvironment(environment);
        jcl.setDomain(domain);
        jcl.setAffinity(affinity);
        jcl.setHold(hold);
        jcl.setPriority(priority);
        jcl.setMemory(memory);

    }

}