org.soaplab.services.cmdline.CmdLineJob.java Source code

Java tutorial

Introduction

Here is the source code for org.soaplab.services.cmdline.CmdLineJob.java

Source

// CmdLineJob.java
//
// Created: November 2006
//
// Copyright 2006 Martin Senger
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package org.soaplab.services.cmdline;

import org.soaplab.share.SoaplabException;
import org.soaplab.share.SoaplabConstants;
import org.soaplab.services.AbstractJob;
import org.soaplab.services.Reporter;
import org.soaplab.services.IOData;
import org.soaplab.services.metadata.MetadataAccessor;
import org.soaplab.services.metadata.ParamDef;
import org.soaplab.services.metadata.StdParamDef;
import org.soaplab.services.metadata.IOParamDef;
import org.soaplab.services.metadata.ChoiceParamDef;
import org.soaplab.services.metadata.AnalysisDef;
import org.soaplab.tools.DefaultParameterAccessor;
import org.soaplab.tools.Substitutor;
import org.soaplab.tools.ICreator;

import org.apache.commons.lang.StringUtils;

import java.util.Map;
import java.util.Properties;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

/**
 * An abstract parent of jobs that need to create any kind of command
 * line (from metadata and from the user real inputs). Typical example
 * of such kind of job is a job invoking command-line analysis, or a
 * job creating job description files for grids. <p>
 *
 * @author <A HREF="mailto:martin.senger@gmail.com">Martin Senger</A>
 * @version $Id: CmdLineJob.java,v 1.21 2007/10/23 08:20:53 marsenger Exp $
 */

public abstract class CmdLineJob extends AbstractJob {

    public static final List<String> EMPTY_LIST = new ArrayList<String>();
    public static final Properties EMPTY_PROPS = new Properties();
    public static final IOData[] EMPTY_IODATA = new IOData[] {};
    public static final NamedValues[] EMPTY_NAMED = new NamedValues[] {};

    /**************************************************************************
     * An empty constructor (for sub-classes).
     **************************************************************************/
    protected CmdLineJob() {
    }

    /**************************************************************************
     * The main constructor.
     **************************************************************************/
    protected CmdLineJob(String jobId, MetadataAccessor metadataAccessor, Reporter reporter,
            Map<String, Object> sharedAttributes, boolean jobRecreated) throws SoaplabException {
        super(jobId, metadataAccessor, reporter, sharedAttributes, jobRecreated);
    }

    /**************************************************************************
     * From service metadata, create representations of individual
     * parameters, and store them in the shared attributes (because
     * they can be shared by all job instances of this service, they
     * are not dependent on the user real inputs). This can be done
     * only once (per service) - that's why the method is called
     * 'init'. <p>
     *
     * The name of this shared attribute is {@link #JOB_SHARED_PARAMETERS}. <p>
     *
     **************************************************************************/
    protected synchronized void init() throws SoaplabException {

        if (sharedAttributes.containsKey(JOB_SHARED_PARAMETERS) && !jobRecreated)
            return;

        // sort parameter definitions by their ordering
        ParamDef[] paramDefs = metadataAccessor.getParamDefs();
        Arrays.sort(paramDefs, new Comparator<ParamDef>() {
            public int compare(ParamDef a, ParamDef b) {
                return a.getInt(ParamDef.ORDERING) - b.getInt(ParamDef.ORDERING);
            }
        });

        Parameter[] parameters = new Parameter[paramDefs.length];
        for (int i = 0; i < paramDefs.length; i++) {
            ParamDef def = paramDefs[i];

            // try a user-defined parameter class first
            String className = def.get(ParamDef.SERVER_CLASS);
            if (StringUtils.isNotEmpty(className)) {
                try {
                    // all our Parameters have one-arg constructor but
                    // perhaps not all are ours - so try first and ignore errors
                    parameters[i] = (Parameter) ICreator.createInstance(className, new Class[] { ParamDef.class },
                            new Object[] { def });
                } catch (SoaplabException e) {
                    // ...now go for a non-args constructor
                    parameters[i] = (Parameter) ICreator.createInstance(className);
                }
                continue;
            }

            // then go for usual parameters
            switch (def.createdFor) {
            case ParamDef.BASE_PARAMETER:
                parameters[i] = new BaseParameter(def);
                break;
            case ParamDef.RANGE_PARAMETER:
                // intentionally no break here
            case ParamDef.STANDARD_PARAMETER:
                parameters[i] = new StdParameter((StdParamDef) def);
                break;
            case ParamDef.IO_PARAMETER:
                parameters[i] = new IOParameter((IOParamDef) def);
                break;
            case ParamDef.CHOICE_PARAMETER:
                parameters[i] = new ChoiceParameter((ChoiceParamDef) def);
                break;
            case ParamDef.CHOICE_LIST_PARAMETER:
                parameters[i] = new ChoiceListParameter((ChoiceParamDef) def);
                break;
            default:
                parameters[i] = new BaseParameter(def);
            }
        }
        sharedAttributes.put(JOB_SHARED_PARAMETERS, parameters);
    }

    /**************************************************************************
     * Create all arguments for a command-line from individual
     * parameters (they are in 'sharedAttributes') and from the user
     * inputs (they are in 'inputs'). <p>
     *
     * Return an empty list (not null) if there are no command-line
     * arguments.
     **************************************************************************/
    protected List<String> createArgs() throws SoaplabException {

        Parameter[] parameters = (Parameter[]) sharedAttributes.get(JOB_SHARED_PARAMETERS);
        if (parameters == null)
            return EMPTY_LIST;

        AnalysisDef analysisDef = metadataAccessor.getAnalysisDef();

        List<String> cmdline = new ArrayList<String>();
        StringBuilder errBuf = new StringBuilder();

        // be prepared for applying a global 'method'
        boolean methodUsed = StringUtils.isNotBlank(analysisDef.method);
        DefaultParameterAccessor accessor = null;
        if (methodUsed)
            accessor = new DefaultParameterAccessor();

        // concatenate all arguments created by individual parameters
        ParamDef paramDef;
        String[] args;
        for (Parameter parameter : parameters) {
            paramDef = parameter.getDefinition();
            try {
                args = parameter.createArg(inputs, this);
                if (methodUsed)
                    accessor.add(paramDef.id, paramDef.get(ParamDef.TAG), args);
                else
                    for (String arg : args) {
                        cmdline.add(arg);
                    }
            } catch (ParameterException e) {
                errBuf.append(e.getMessage());
                errBuf.append("\n");
            } catch (Exception e) {
                throw new SoaplabException(getServiceName() + ": " + "Unexpected exception. " + e.getMessage(), e);
            }
        }
        if (errBuf.length() > 0)
            throw new SoaplabException(SoaplabConstants.FAULT_NOT_VALID_INPUTS + "\n" + errBuf.toString());

        // apply global 'method' to create (finally) command-line arguments
        if (methodUsed) {
            Substitutor engine = new Substitutor(analysisDef.method, analysisDef.get(ParamDef.SEPARATOR), accessor);
            for (String arg : engine.process()) {
                cmdline.add(arg);
            }
        }

        return cmdline;
    }

    /**************************************************************************
     *
     * Return an empty list (not null) if there are no command-line
     * arguments, or if there is a global METHOD defined.
     **************************************************************************/
    protected NamedValues[] createNamedArgs() throws SoaplabException {

        Parameter[] parameters = (Parameter[]) sharedAttributes.get(JOB_SHARED_PARAMETERS);
        if (parameters == null)
            return EMPTY_NAMED;

        // be prepared for a global 'method'
        AnalysisDef analysisDef = metadataAccessor.getAnalysisDef();
        if (StringUtils.isNotBlank(analysisDef.method)) {
            NamedValues oneNamed = new NamedValues();
            oneNamed.setValues(createArgs());
            return new NamedValues[] { oneNamed };
        }

        // get named values created by individual parameters
        StringBuilder errBuf = new StringBuilder();
        List<NamedValues> result = new ArrayList<NamedValues>();
        for (Parameter parameter : parameters) {
            try {
                NamedValues named = parameter.createNamedArg(inputs, this);
                if (named != null)
                    result.add(named);
            } catch (ParameterException e) {
                errBuf.append(e.getMessage());
                errBuf.append("\n");
            } catch (Exception e) {
                throw new SoaplabException(getServiceName() + ": " + "Unexpected exception. " + e.getMessage(), e);
            }
        }
        if (errBuf.length() > 0)
            throw new SoaplabException(SoaplabConstants.FAULT_NOT_VALID_INPUTS + "\n" + errBuf.toString());
        return result.toArray(new NamedValues[] {});
    }

    /**************************************************************************
     * Create all environment variables from individual parameters
     * (from those who claim ENVAR in their metadata) and from the
     * user inputs (they are in 'inputs'). <p>
     *
     * Return an empty properties (not null) if there are no
     * environment variables to create. <p>
     **************************************************************************/
    protected Properties createEnvs() throws SoaplabException {

        Parameter[] parameters = (Parameter[]) sharedAttributes.get(JOB_SHARED_PARAMETERS);
        if (parameters == null)
            return EMPTY_PROPS;

        Properties envProps = new Properties();
        StringBuilder errBuf = new StringBuilder();

        for (Parameter parameter : parameters) {
            try {
                Properties props = parameter.createEnv(inputs, this);
                for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
                    String key = (String) en.nextElement();
                    envProps.put(key, props.get(key));
                }
            } catch (ParameterException e) {
                errBuf.append(e.getMessage());
                errBuf.append("\n");
            } catch (Exception e) {
                throw new SoaplabException(getServiceName() + ": " + "Unexpected exception. " + e.getMessage(), e);
            }
        }
        if (errBuf.length() > 0)
            throw new SoaplabException(SoaplabConstants.FAULT_NOT_VALID_INPUTS + "\n" + errBuf.toString());
        return envProps;
    }

    /**************************************************************************
     * Create an array of all data containers from individual
     * parameters (from those who represent inputs and outputs) and
     * from the user inputs (they are in 'inputs'). <p>
     *
     * Return an empty array (not null) if there are no
     * inputs/outputs to create (which is rare). <p>
     **************************************************************************/
    protected IOData[] createIO() throws SoaplabException {

        Parameter[] parameters = (Parameter[]) sharedAttributes.get(JOB_SHARED_PARAMETERS);
        if (parameters == null)
            return EMPTY_IODATA;

        List<IOData> ioList = new ArrayList<IOData>();
        StringBuilder errBuf = new StringBuilder();

        for (Parameter parameter : parameters) {
            try {
                IOData[] ioData = parameter.createIO(inputs, this);
                for (IOData io : ioData) {
                    ioList.add(io);
                }
            } catch (ParameterException e) {
                errBuf.append(e.getMessage());
                errBuf.append("\n");
            } catch (Exception e) {
                throw new SoaplabException(getServiceName() + ": " + "Unexpected exception. " + e.getMessage(), e);
            }
        }
        if (errBuf.length() > 0)
            throw new SoaplabException(SoaplabConstants.FAULT_NOT_VALID_INPUTS + "\n" + errBuf.toString());
        return ioList.toArray(new IOData[] {});
    }

    /**************************************************************************
     *
     **************************************************************************/
    protected String getExecutableName() throws SoaplabException {

        AnalysisDef analysisDef = metadataAccessor.getAnalysisDef();
        return analysisDef.file;
    }

    /**************************************************************************
     * Adding calls to individual parameters to run their own validation.
     **************************************************************************/
    protected void checkInputs() throws SoaplabException {
        super.checkInputs();

        StringBuilder errBuf = new StringBuilder();

        // call individual parameters to add their own validation
        Parameter[] parameters = (Parameter[]) sharedAttributes.get(JOB_SHARED_PARAMETERS);
        if (parameters != null) {
            for (Parameter p : parameters) {
                try {
                    p.validate(inputs, this, null);
                } catch (ParameterException e) {
                    errBuf.append(e.getMessage());
                    errBuf.append("\n");
                }
            }
        }

        // any errors to report?
        reportErrors(errBuf);
    }

}