org.pepstock.jem.ant.AntFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.ant.AntFactory.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.ant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

import javax.xml.bind.ValidationException;

import org.apache.commons.io.IOUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.pepstock.jem.Jcl;
import org.pepstock.jem.Job;
import org.pepstock.jem.ant.validator.transformer.TransformerValidator;
import org.pepstock.jem.factories.AbstractFactory;
import org.pepstock.jem.factories.JclFactoryException;
import org.pepstock.jem.log.JemException;
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;

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

    private static final long serialVersionUID = 1L;

    /**
     * public key which indicates the JCL type for ANT
     */
    public static final String ANT_TYPE = "ant";

    private static final String ANT_TYPE_DESCRIPTION = "Apache ANT";

    private static final String ANT_BASE_DIR = ".";

    private transient TransformerValidator validator = null;

    /**
     * Empty constructor. Does nothing
     */
    public AntFactory() {
        super();
    }

    @Override
    public void init(Properties properties) throws JemException {
        super.init(properties);

        // missing enable multiple validator type like xslt, java, groovy
        String xsltvalidatorFile = getProperties().getProperty(AntKeys.ANT_XSLTPROJECTVALIDATOR);
        if (xsltvalidatorFile != null && !xsltvalidatorFile.isEmpty()) {
            if (validator == null) {
                validator = new TransformerValidator();
            }
            // load a validator and initialize it with the xslt document (this is persisted in
            // memory and watched for changed)
            try {
                validator.load(xsltvalidatorFile);
            } catch (ValidationException e) {
                throw new JemException(e.getMessage(), e);
            }
        }
    }

    /**
     * Called to create a JCL object, by the string representing source code of
     * ANT.
     * 
     * @see org.pepstock.jem.factories.JclFactory#createJcl(java.lang.String)
     * @return JCL object
     * @throws JclFactoryException if syntax is not correct, a exception occurs
     */
    @Override
    public Jcl createJcl(String content) throws JclFactoryException {
        // creates JCL object setting the source code
        Jcl jcl = new Jcl();
        jcl.setType(ANT_TYPE);
        jcl.setContent(content);

        // file reference to use to write JCL
        File file = null;
        try {
            // creates a temporary file (to delete at the end)
            file = File.createTempFile("jcl", ".jcl");

            // writes the content of JCL
            FileOutputStream fos = new FileOutputStream(file);
            IOUtils.write(jcl.getContent(), fos, CharSet.DEFAULT);
            fos.flush();
            fos.close();

            // validates jcl content
            validate(jcl, file);

        } catch (AntException e) {
            throw new JclFactoryException(jcl, e);
        } catch (IOException e) {
            throw new JclFactoryException(jcl, e);
        } finally {
            // delete anyway the JCL file (temporary)
            if (file != null) {
                boolean isDeleted = file.delete();
                if (!isDeleted) {
                    // nop
                }
            }
        }
        return jcl;
    }

    /**
     * It validates XML syntax of ANT source code. <br>
     * Creates an ANT project object, extracting all information.<br>
     * For job name, uses the <code>name</code> attribute value for property
     * element inside of project element, to set job Name. If is missing, JEM
     * uses <code>name</code> attribute value for project.
     * 
     * @param jcl JCL instance with source code
     * @param file file reference for JCL
     * @throws ValidationException if IO error or job name not set a exception
     *             occurs
     */
    private void validate(Jcl jcl, File file) throws AntException {
        // creates an ANT empty project
        Project p = new Project();
        // initializes properties
        // we need to set ant.file prop
        p.initProperties();
        // sets base dir , current directory and set property for JCL
        // file name to use
        p.setBasedir(ANT_BASE_DIR);
        p.setUserProperty("ant.file", file.getAbsolutePath());

        // initializes it
        p.init();

        // creates the helper to parse JCL ANT file
        ProjectHelper helper = ProjectHelper.getProjectHelper();
        p.addReference("ant.projectHelper", helper);

        // parse it. If there is any syntax error, throw a BuildException, 
        // but it tries to get JobName!!
        try {
            helper.parse(p, file);
        } catch (BuildException ex) {
            String jobName = (p.getName() != null) ? p.getName() : p.getProperty(AntKeys.ANT_JOB_NAME);
            jcl.setJobName(jobName);
            throw ex;
        }
        // if I'm here, JCL is correct

        // checks if project has attribute name, if yes, uses it as JOB NAME
        // otherwise get the JEM property to define it
        String jobName = (p.getName() != null) ? p.getName() : p.getProperty(AntKeys.ANT_JOB_NAME);

        // Anyway job name can't be null. if yes, exception occurs
        if (jobName == null) {
            throw new AntException(AntMessage.JEMA031E);
        }

        // 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(AntKeys.ANT_LOCKING_SCOPE);
        if (lockingScopeProperty != null && !lockingScopeProperty.equalsIgnoreCase(AntKeys.ANT_JOB_SCOPE)
                && !lockingScopeProperty.equalsIgnoreCase(AntKeys.ANT_STEP_SCOPE)
                && !lockingScopeProperty.equalsIgnoreCase(AntKeys.ANT_TASK_SCOPE)) {
            throw new AntException(AntMessage.JEMA032E, AntKeys.ANT_LOCKING_SCOPE, lockingScopeProperty);
        }

        // Extracts from ANT enviroment property
        String environment = p.getProperty(AntKeys.ANT_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(AntKeys.ANT_DOMAIN);
        // if null, uses domain default
        if (domain == null) {
            domain = Jcl.DEFAULT_DOMAIN;
        }

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

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

        // Extracts from ANT classpath property
        String classPath = p.getProperty(AntKeys.ANT_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(AntKeys.ANT_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(AntKeys.ANT_MEMORY), Jcl.DEFAULT_MEMORY);
        // Extracts from ANT hold property. If missing, default is FALSE
        boolean hold = Parser.parseBoolean(p.getProperty(AntKeys.ANT_HOLD), false);
        // Extracts from ANT priority property. If missing, default is 10
        int priority = Parser.parseInt(p.getProperty(AntKeys.ANT_PRIORITY), Jcl.DEFAULT_PRIORITY);

        // saves all info inside of JCL object for further computing
        jcl.setJobName(jobName);
        jcl.setEnvironment(environment);
        jcl.setDomain(domain);
        jcl.setAffinity(affinity);
        jcl.setHold(hold);
        jcl.setPriority(priority);
        jcl.setMemory(memory);

        // apply custom validation rules loaded from an xlst grammar
        if (validator != null) {
            try {
                validator.validate(jcl);
            } catch (ValidationException e) {
                throw new AntException(AntMessage.JEMA047E, e, e.getMessage());
            }
        }
    }

    /**
     * It returns new instance of AntTask.
     * 
     * @see AntTask
     * @see org.pepstock.jem.node.tasks.JobTask
     * @see org.pepstock.jem.factories.JobTaskFactory#createJobTask(org.pepstock.jem.Job)
     * @param job job instance to execute
     * @return Job task instance so JEM node can execute it
     */
    @Override
    public JobTask createJobTask(Job job) {
        return new AntTask(job, this);
    }

    /**
     * Returns the type of this factory. This is unique key (value "ant" means
     * ANT) to search factory loaded during startup.
     * 
     * @see org.pepstock.jem.node.Main#FACTORIES_LIST
     * @see org.pepstock.jem.node.StartUpSystem#run()
     * @see org.pepstock.jem.factories.JemFactory#getType()
     */
    @Override
    public String getType() {
        return ANT_TYPE;
    }

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

}