org.pepstock.jem.gwt.server.services.JobsManager.java Source code

Java tutorial

Introduction

Here is the source code for org.pepstock.jem.gwt.server.services.JobsManager.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.gwt.server.services;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

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

import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.pepstock.jem.Jcl;
import org.pepstock.jem.Job;
import org.pepstock.jem.JobStatus;
import org.pepstock.jem.JobSystemActivity;
import org.pepstock.jem.OutputFileContent;
import org.pepstock.jem.OutputListItem;
import org.pepstock.jem.OutputTree;
import org.pepstock.jem.PreJob;
import org.pepstock.jem.Result;
import org.pepstock.jem.commands.util.Factory;
import org.pepstock.jem.gwt.server.UserInterfaceMessage;
import org.pepstock.jem.gwt.server.commons.DistributedTaskExecutor;
import org.pepstock.jem.gwt.server.commons.GenericDistributedTaskExecutor;
import org.pepstock.jem.log.LogAppl;
import org.pepstock.jem.node.Queues;
import org.pepstock.jem.node.executors.jobs.Cancel;
import org.pepstock.jem.node.executors.jobs.GetJclTypes;
import org.pepstock.jem.node.executors.jobs.GetJobSystemActivity;
import org.pepstock.jem.node.executors.jobs.GetOutputFileContent;
import org.pepstock.jem.node.executors.jobs.GetOutputTree;
import org.pepstock.jem.node.executors.jobs.Purge;
import org.pepstock.jem.node.security.Permissions;
import org.pepstock.jem.node.security.StringPermission;
import org.pepstock.jem.node.security.User;
import org.pepstock.jem.util.filters.Filter;
import org.pepstock.jem.util.filters.FilterToken;
import org.pepstock.jem.util.filters.fields.JobFilterFields;
import org.pepstock.jem.util.filters.predicates.JobPredicate;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.hazelcast.core.IMap;
import com.hazelcast.core.IQueue;
import com.hazelcast.core.ITopic;
import com.hazelcast.core.IdGenerator;
import com.hazelcast.query.SqlPredicate;

/**
 * This service provides all methods to access to jobs information.
 * 
 * @author Andrea "Stock" Stocchero
 * 
 */
@SuppressWarnings("deprecation")
public class JobsManager extends DefaultService {

    /**
     * Returns the list of jobs in INPUT, a filter string composed by UI filters
     * 
     * @param filter
     *            filter string
     * @return collection of jobs
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Collection<Job> getInputQueue(String filter) throws ServiceMessageException {
        return getJobsByQueue(Queues.INPUT_QUEUE, filter);
    }

    /**
     * Returns the list of jobs in RUNNING, a filter string composed by UI
     * filters
     * 
     * @param filter
     *            filter string
     * @return collection of jobs
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Collection<Job> getRunningQueue(String filter) throws ServiceMessageException {
        return getJobsByQueue(Queues.RUNNING_QUEUE, filter);
    }

    /**
     * Returns the list of jobs in OUTPUT, a filter string composed by UI
     * filters
     * 
     * @param filter
     *            filter string
     * @return collection of jobs
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Collection<Job> getOutputQueue(String filter) throws ServiceMessageException {
        return getJobsByQueue(Queues.OUTPUT_QUEUE, filter);
    }

    /**
     * Returns the list of jobs in ROUTING, a filter string composed by UI
     * filters
     * 
     * @param filter
     *            filter string
     * @return collection of jobs
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Collection<Job> getRoutingQueue(String filter) throws ServiceMessageException {
        return getJobsByQueue(Queues.ROUTING_QUEUE, filter);
    }

    /**
     * This is common method to extract jobs from different queues by filter
     * string
     * 
     * @param queueName
     *            queue name to use to get the right map
     * @param filterString
     *            filter string
     * @return collection of jobs
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    private Collection<Job> getJobsByQueue(String queueName, String filterString) throws ServiceMessageException {
        // creates a filter object
        Filter filter = null;
        try {
            filter = Filter.parse(filterString);
        } catch (Exception e) {
            LogAppl.getInstance().debug(e.getMessage(), e);
            // default case, all jobs
            filter = new Filter();
            filter.add(new FilterToken(JobFilterFields.NAME.getName(), StringUtils.EMPTY));
        }
        // extract the jobname, if it is.
        // necessary to check permission because it is based on
        // job name
        String jobName = filter.get(JobFilterFields.NAME.getName());
        // if job name is null, means all, then "*"
        if (jobName == null || jobName.trim().length() == 0) {
            jobName = "*";
        }
        // creates the right permission by job name
        String permission = Permissions.SEARCH_JOBS + jobName;
        // checks if the user is authorized to get jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(permission));

        IMap<String, Job> jobs = getInstance().getMap(queueName);
        // creates predicate
        JobPredicate predicate = new JobPredicate(filter);
        return new ArrayList<Job>(jobs.values(predicate));
    }

    /**
     * Returns a job status by filter.<br>
     * Filter must be job name (no pattern with wild-cards) or job id
     * 
     * @param filter
     *            job name (no pattern with wild-cards) or job id
     * @return job status
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public JobStatus getJobStatus(String filter) throws ServiceMessageException {
        // checks user authentication
        // if not, this method throws an exception
        checkAuthentication();

        // creates job status
        JobStatus status = new JobStatus();
        StringBuilder sb = new StringBuilder();

        // parses filter to understand if the request is done by
        // job name or job id
        try {
            MessageFormat jobIdFormat = new MessageFormat(Factory.JOBID_FORMAT);
            // checks if is by job id
            jobIdFormat.parse(filter);
            sb.append("id = '").append(filter).append("'");
        } catch (ParseException pe) {
            // otherwise is by job name
            // creates the right permission by job name
            String permission = Permissions.SEARCH_JOBS + filter;
            // checks if the user is authorized to get jobs
            // if not, this method throws an exception
            checkAuthorization(new StringPermission(permission));
            // creates SQL predicate string
            sb.append("name = '").append(filter).append("'");
        }

        // performs predicate on all maps to search job
        SqlPredicate predicate = new SqlPredicate(sb.toString());
        status.setJobsInput(loadQueuesJobs(Queues.INPUT_QUEUE, predicate));
        status.setJobsRunning(loadQueuesJobs(Queues.RUNNING_QUEUE, predicate));
        status.setJobsOutput(loadQueuesJobs(Queues.OUTPUT_QUEUE, predicate));
        status.setJobsRouting(loadQueuesJobs(Queues.ROUTING_QUEUE, predicate));
        return status;
    }

    /**
     * Performs the predicate pased as argument on a specific queue, identified
     * by name.
     * 
     * @param queueName
     *            map name
     * @param sql
     *            SQL predicate to apply on map
     * @return collection of jobs
     * @throws Exception
     *             if any exception occurs or a lock timeout on map occurs
     */
    private Collection<Job> loadQueuesJobs(String queueName, SqlPredicate sql) {
        IMap<String, Job> jobs = getInstance().getMap(queueName);
        // performs predicate to have the collection
        return new ArrayList<Job>(jobs.values(sql));
    }

    /**
     * Returns a job by its job id.
     * 
     * @param queueName
     *            map name
     * @param jobId
     *            job id to search
     * @return job, if found, otherwise null
     * @throws ServiceMessageException 
     *             if any exception occurs or a lock timeout on map occurs
     */
    public Job getJobById(String queueName, String jobId) throws ServiceMessageException {
        // checks user authentication
        // if not, this method throws an exception
        checkAuthentication();

        Job job = null;
        IMap<String, Job> queue = getInstance().getMap(queueName);
        try {
            // locks the key (job id)
            queue.lock(jobId);
            // checks if exist
            // if yes, saved it in local reference
            if (queue.containsKey(jobId)) {
                job = queue.get(jobId);
            }
        } finally {
            // unlocks always the key
            queue.unlock(jobId);
        }
        if (job != null) {
            // creates the right permission by job name
            String permission = Permissions.SEARCH_JOBS + job.getName();
            // checks if the user is authorized to get jobs
            // if not, this method throws an exception
            checkAuthorization(new StringPermission(permission));
        }
        // returns job
        return job;
    }

    /**
     * Returns a job by its job id, searching it in OUTPUT and ROUTED maps.<br>
     * If job is not in output, tries searching it in ROUTED
     * 
     * @param jobId
     *            job id
     * @return job instance
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Job getEndedJobById(String jobId) throws ServiceMessageException {
        // checks user authentication
        // if not, this method throws an exception
        checkAuthentication();

        // gets job from output.
        Job job = getJobById(Queues.OUTPUT_QUEUE, jobId);
        // if does not exist, checks on routed map
        if (job == null) {
            // Checks ROUTED QUEUE
            IMap<String, Job> routedQueue = getInstance().getMap(Queues.ROUTED_QUEUE);
            try {
                // locks the key (job id)
                routedQueue.lock(jobId);
                // checks if exist
                // if true, removes job
                if (routedQueue.containsKey(jobId)) {
                    job = routedQueue.remove(jobId);
                }
            } finally {
                // unlocks always the map
                routedQueue.unlock(jobId);
            }
            if (job != null) {
                // creates the right permission by job name
                String permission = Permissions.SEARCH_JOBS + job.getName();
                // checks if the user is authorized to get jobs
                // if not, this method throws an exception
                checkAuthorization(new StringPermission(permission));
            }
        }
        // returns job
        return job;
    }

    /**
     * Holds jobs in INPUT, OUTPUT or ROUTING queue. To set HOLD means that it
     * can't be executed or removed from queue.
     * 
     * @param jobs
     *            collections of jobs to hold
     * @param queueName
     *            map where jobs are
     * @return true is it holds them, otherwise false
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Boolean hold(Collection<Job> jobs, String queueName) throws ServiceMessageException {
        // holds ONLY jobs in input, output and routing
        if (!queueName.equalsIgnoreCase(Queues.INPUT_QUEUE) && !queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE)
                && !queueName.equalsIgnoreCase(Queues.ROUTING_QUEUE)) {
            return Boolean.FALSE;
        }
        // checks if the user is authorized to hold jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(Permissions.JOBS_HOLD));

        IMap<String, Job> queue = getInstance().getMap(queueName);
        // scans all jobs to hold
        for (Job job : jobs) {
            try {
                // lock the key (job id)
                queue.lock(job.getId());
                // checks if exist
                if (queue.containsKey(job.getId())) {
                    // gets job
                    // set hold to true if it was already in hold
                    Job storedJob = queue.get(job.getId());
                    Jcl storedJcl = storedJob.getJcl();
                    if (!storedJcl.isHold()) {
                        storedJcl.setHold(true);
                        queue.replace(storedJob.getId(), storedJob);
                    }
                }
            } finally {
                // unlocks always the key
                queue.unlock(job.getId());
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Cancel a set of jobs currently in running. If force is set to true, JEM
     * uses force mode to cancel jobs.
     * 
     * @param jobs
     *            list of jobs to cancel
     * @param force
     *            if true, uses force attribute to cancel jobs
     * @return always true!
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Boolean cancel(Collection<Job> jobs, boolean force) throws ServiceMessageException {
        // checks if the user is authorized to cancel or kill jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission((force) ? Permissions.JOBS_KILL : Permissions.JOBS_CANCEL));
        // gets user
        // that's necessary to print on log who cancel job
        Subject currentUser = SecurityUtils.getSubject();
        User user = (User) currentUser.getPrincipal();

        // scans jobs
        for (Job job : jobs) {
            Job jobSearched = job;
            String nodeKey = job.getMemberId();
            if ((nodeKey == null || job.getProcessId() == null) && job.getId() != null) {
                jobSearched = getJobById(Queues.RUNNING_QUEUE, job.getId());
                nodeKey = jobSearched.getMemberId();
            }
            // gets Hazelcast member
            // if is not able, an exception occurs
            GenericDistributedTaskExecutor task;
            try {
                task = new GenericDistributedTaskExecutor(new Cancel(jobSearched, user.getId(), force),
                        getMember(nodeKey));
                task.execute();
            } catch (Exception e) {
                LogAppl.getInstance().ignore(e.getMessage(), e);
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Releases jobs in INPUT, OUTPUT or ROUTING queue, which were previously
     * hold.
     * 
     * @param jobs
     *            collections of jobs to hold
     * @param queueName
     *            map where jobs are
     * @return true is it holds them, otherwise false
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Boolean release(Collection<Job> jobs, String queueName) throws ServiceMessageException {
        // release ONLY jobs in input, output and routing
        if (!queueName.equalsIgnoreCase(Queues.INPUT_QUEUE) && !queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE)
                && !queueName.equalsIgnoreCase(Queues.ROUTING_QUEUE)) {
            return Boolean.FALSE;
        }
        // checks if the user is authorized to release jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(Permissions.JOBS_RELEASE));

        IMap<String, Job> queue = getInstance().getMap(queueName);
        // scans all jobs to hold
        for (Job job : jobs) {
            try {
                // lock the key (job id)
                queue.lock(job.getId());
                // checks if exist
                if (queue.containsKey(job.getId())) {
                    // gets job
                    // set hold to false if it was not already in hold
                    Job storedJob = queue.get(job.getId());
                    Jcl storedJcl = storedJob.getJcl();
                    if (storedJcl.isHold()) {
                        storedJcl.setHold(false);
                        queue.replace(storedJob.getId(), storedJob);
                    }
                }
            } finally {
                // unlocks always the key
                queue.unlock(job.getId());
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Purge (removing any output) jobs from INPUT, OUTPUT or ROUTING queue.
     * 
     * @param jobs
     *            collections of jobs to purge
     * @param queueName
     *            map where jobs are
     * @return true is it holds them, otherwise false
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Boolean purge(Collection<Job> jobs, String queueName) throws ServiceMessageException {
        // release ONLY jobs in input, output and routing
        if (!queueName.equalsIgnoreCase(Queues.INPUT_QUEUE) && !queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE)
                && !queueName.equalsIgnoreCase(Queues.ROUTING_QUEUE)) {
            return Boolean.FALSE;
        }
        // checks if the user is authorized to purge jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(Permissions.JOBS_PURGE));

        // gets user
        // that's necessary to print on log who cancel job
        Subject currentUser = SecurityUtils.getSubject();
        User user = (User) currentUser.getPrincipal();

        IMap<String, Job> queue = getInstance().getMap(queueName);
        // scans jobs
        for (Job job : jobs) {
            try {
                // locks the key(job id)
                queue.lock(job.getId());
                // checks if exist
                if (queue.containsKey(job.getId())) {
                    // gets job
                    Job storedJob = queue.get(job.getId());
                    // sets the result to Cancelled
                    Result result = new Result();
                    result.setReturnCode(Result.CANCELED);
                    // sets exception, puttinh the user id
                    result.setExceptionMessage("Purge by user(" + user.getId() + ") interface");
                    storedJob.setEndedTime(new Date());
                    // store result into job
                    storedJob.setResult(result);
                    // removes from queue
                    queue.remove(storedJob.getId());

                    // if it was in OUTPUT,
                    // removes output files from file system
                    // calling a exectuor
                    if (queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE)) {
                        callPurge(storedJob);
                    }

                    if (!storedJob.isNowait()) {
                        // sends a topic to all subscribers
                        // telling them that jobs is ended
                        ITopic<Job> topic = getInstance().getTopic(Queues.ENDED_JOB_TOPIC);
                        topic.publish(storedJob);
                    }
                }
            } finally {
                // always unlocks the key
                queue.unlock(job.getId());
            }
        }
        return Boolean.TRUE;
    }

    /**
     * Calls a executor to remove the joboutput directory from file system
     * 
     * @param storedJob
     *            removed job
     */
    private void callPurge(Job storedJob) {
        try {
            GenericDistributedTaskExecutor task = new GenericDistributedTaskExecutor(new Purge(storedJob),
                    getMember());
            task.execute();
        } catch (Exception e) {
            // catches to avoid any useless message of failure but prints on log
            LogAppl.getInstance().emit(UserInterfaceMessage.JEMG054E, e, storedJob.toString());
        }
    }

    /**
     * Updates some attributes of job. Usually is used in input queue to change
     * environment, domain, affinity, memory or priority.
     * 
     * @param job
     *            job to update
     * @param queueName
     *            map where job is
     * @return true if it updated, otherwise false
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public Boolean update(Job job, String queueName) throws ServiceMessageException {
        // builds permission
        String permission = Permissions.JOBS_UPDATE;
        // checks if the user is authorized to update job
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(permission));

        IMap<String, Job> queue = getInstance().getMap(queueName);
        try {
            // locks the key(job id)
            queue.lock(job.getId());
            // checks if exist
            if (queue.containsKey(job.getId())) {
                // gets job and jcl, sets to new job
                // and stores new job
                Job storedJob = queue.get(job.getId());
                Jcl storedJcl = storedJob.getJcl();
                // sets JCL because JCL is not
                // serialized to GWT (too big)
                job.getJcl().setContent(storedJcl.getContent());
                queue.replace(job.getId(), job);
            }
        } finally {
            // unlocks always the key
            queue.unlock(job.getId());
        }
        return Boolean.TRUE;
    }

    /**
     * Retrieves job JCL from INPUT, RUNNING, OUTPUT or ROUTING queue.
     * 
     * @param job
     *            job used to extract JCl
     * @param queueName
     *            map where job is
     * @return JCL content
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public String getJcl(Job job, String queueName) throws ServiceMessageException {
        // release ONLY jobs in input, output, running and routing
        if (!queueName.equalsIgnoreCase(Queues.INPUT_QUEUE) && !queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE)
                && !queueName.equalsIgnoreCase(Queues.RUNNING_QUEUE)
                && !queueName.equalsIgnoreCase(Queues.ROUTING_QUEUE)) {
            throw new ServiceMessageException(UserInterfaceMessage.JEMG025E, queueName);
        }
        // builds permission
        String permission = Permissions.SEARCH_JOBS + job.getName();
        // checks if the user is authorized to get JCL
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(permission));

        IMap<String, Job> queue = getInstance().getMap(queueName);
        Job storedJob = null;
        try {
            // locks the key (job id)
            queue.lock(job.getId());
            // gets JOB
            // for JCL because JCL is not
            // serialized to GWT (too big)
            storedJob = queue.get(job.getId());
        } finally {
            // unlocks always the key
            queue.unlock(job.getId());
        }
        // if stored job is null
        // means the probably the view on UI is old,
        // and the job is no longer on map
        // Constant string is NOT AVAILABLE
        if (storedJob == null) {
            return Jcl.CONTENT_NOT_AVAILABLE;
        }
        // return the JCL
        return storedJob.getJcl().getContent();
    }

    /**
     * Returns all folder in tree representation of job output folder.<br>
     * Retrieves folder structure only if job is RUNNING or OUTPUT queue.
     * 
     * @param job
     *            job used to extract folder structure. Needs to have output
     *            folder
     * @param queueName
     *            map where job is
     * @return object with all folder structure
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public OutputTree getOutputTree(Job job, String queueName) throws ServiceMessageException {
        // builds permission
        String permission = Permissions.SEARCH_JOBS + job.getName();
        // checks if the user is authorized to get folder
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(permission));

        OutputTree tree;
        // release ONLY jobs in output and running
        if (queueName.equalsIgnoreCase(Queues.OUTPUT_QUEUE) || queueName.equalsIgnoreCase(Queues.RUNNING_QUEUE)) {
            DistributedTaskExecutor<OutputTree> task = new DistributedTaskExecutor<OutputTree>(
                    new GetOutputTree(job), getMember());
            tree = task.getResult();
        } else {
            tree = new OutputTree();
        }

        // now try to get JCL
        // because this method is called when you go
        // in inspect in a job
        IMap<String, Job> queue = getInstance().getMap(queueName);
        Job storedJob = null;
        try {
            // locks the key (job id)
            queue.lock(job.getId());
            // gets job
            storedJob = queue.get(job.getId());
        } finally {
            // unlocks always the key
            queue.unlock(job.getId());
        }
        // if there is the job
        // gets JCL content
        if (storedJob != null) {
            tree.setJclContent(storedJob.getJcl().getContent());
        } else {
            // otherwise NOT available
            tree.setJclContent(Jcl.CONTENT_NOT_AVAILABLE);
        }
        return tree;
    }

    /**
     * Returns the content of specific file inside of job output folder.
     * 
     * @param job
     *            job used to extract file. Needs to have output folder
     * @param item
     *            file descriptor, created by a previous call to getOutputTree
     * @return object with file content
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public OutputFileContent getOutputFileContent(Job job, OutputListItem item) throws ServiceMessageException {
        // builds permission
        String permission = Permissions.SEARCH_JOBS + job.getName();
        // checks if the user is authorized to get file
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(permission));

        DistributedTaskExecutor<OutputFileContent> task = new DistributedTaskExecutor<OutputFileContent>(
                new GetOutputFileContent(item), getMember());
        return task.getResult();
    }

    /**
     * Submits a new job (passed as argument) in JEM.
     * 
     * @param preJob
     *            job to submit
     * @return Job id after submission
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public String submit(PreJob preJob) throws ServiceMessageException {
        // checks if the user is authorized to submit jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(Permissions.JOBS_SUBMIT));

        // gets job
        Job job = preJob.getJob();

        // gets userid and org unit from
        // current session, ovverriding JOB values
        Subject currentUser = SecurityUtils.getSubject();
        Object obj = currentUser.getPrincipal();
        if (obj instanceof User) {
            User user = (User) obj;
            job.setUser(user.getId());
            job.setOrgUnit(user.getOrgUnitId());
        }

        // gets a new ID to create a unique job id
        IdGenerator generator = getInstance().getIdGenerator(Queues.JOB_ID_GENERATOR);
        long id = generator.newId();

        // creates job id and sets it
        String jobId = Factory.createJobId(job, id);
        job.setId(jobId);

        // via HTTP is not possible to wait the end of job
        job.setNowait(true);

        // puts the pre job in a queue for validating
        IQueue<PreJob> jclCheckingQueue = getInstance().getQueue(Queues.JCL_CHECKING_QUEUE);
        try {
            jclCheckingQueue.put(preJob);
        } catch (InterruptedException e) {
            LogAppl.getInstance().debug(e.getMessage(), e);
            throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, Queues.JCL_CHECKING_QUEUE);
        } catch (Exception e) {
            LogAppl.getInstance().debug(e.getMessage(), e);
            throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, Queues.JCL_CHECKING_QUEUE);
        }
        return jobId;
    }

    /**
     * Indents JCL content, for editing
     * @param content JCL
     * @return indented JCL
     * @throws ServiceMessageException 
     * @throws Exception if any XML exception occurs
     */
    public String indent(String content) throws ServiceMessageException {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(new ReaderInputStream(new StringReader(content)));
            OutputFormat format = new OutputFormat(document);
            format.setLineWidth(65);
            format.setIndenting(true);
            format.setIndent(4);

            StringWriter writer = new StringWriter();
            XMLSerializer serializer = new XMLSerializer(writer, format);
            serializer.serialize(document);
            return writer.toString();
        } catch (ParserConfigurationException e) {
            throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, e.getMessage());
        } catch (SAXException e) {
            throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, e.getMessage());
        } catch (IOException e) {
            throw new ServiceMessageException(UserInterfaceMessage.JEMG022E, e, e.getMessage());
        }
    }

    /**
     * Returns system information about resource consumption of job in running
     * phase.
     * 
     * @param job
     *            job to use to gather system information
     * @return system activity information
     * @throws ServiceMessageException 
     *             if any exception occurs
     */
    public JobSystemActivity getJobSystemActivity(Job job) throws ServiceMessageException {
        // checks if the user is authorized to search job
        // if not, this method throws an exception
        String permission = Permissions.SEARCH_JOBS + job.getName();
        checkAuthorization(new StringPermission(permission));

        Job jobToSearch = job;
        String nodeKey = job.getMemberId();
        if (nodeKey == null || job.getProcessId() == null) {
            if (job.getId() == null) {
                return null;
            } else {
                jobToSearch = getJobById(Queues.RUNNING_QUEUE, job.getId());
                if (jobToSearch == null) {
                    return null;
                }
                nodeKey = jobToSearch.getMemberId();
            }
        }
        DistributedTaskExecutor<JobSystemActivity> task = new DistributedTaskExecutor<JobSystemActivity>(
                new GetJobSystemActivity(jobToSearch), getMember(nodeKey));
        return task.getResult();

    }

    /**
     * Returns the list of JCL types and their description
     * 
     * @return map with all jcl types
     * @throws ServiceMessageException 
     * @throws Exception
     *             if any exception occurs
     */
    public Map<String, String> getJclTypes() throws ServiceMessageException {
        // checks if the user is authorized to submit jobs
        // if not, this method throws an exception
        checkAuthorization(new StringPermission(Permissions.JOBS_SUBMIT));
        DistributedTaskExecutor<Map<String, String>> task = new DistributedTaskExecutor<Map<String, String>>(
                new GetJclTypes(), getMember());
        return task.getResult();
    }

}