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

Java tutorial

Introduction

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

Source

// BaseParameter.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.services.IOData;
import org.soaplab.services.Job;
import org.soaplab.services.metadata.ParamDef;
import org.soaplab.tools.DefaultParameterAccessor;
import org.soaplab.tools.ParameterAccessor;
import org.soaplab.tools.Substitutor;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ArrayUtils;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;

/**
 * A base command-line argument. It can be used on its own, or as a
 * parent class for more specialized arguments. <p>
 *
 * The BaseParameter is actually a boolean argument (an option). Its
 * value (unless defined differently using metadata <tt>METHOD</tt>)
 * is a command-line tag (or its absence). <p>
 *
 * @author <A HREF="mailto:martin.senger@gmail.com">Martin Senger</A>
 * @version $Id: BaseParameter.java,v 1.16 2008/05/16 13:19:27 marsenger Exp $
 */

public class BaseParameter implements Parameter {

    private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
            .getLog(BaseParameter.class);

    // char used for cmdline tags (if not convenient, use 'method')
    protected static final String CMD = "-";

    // definition (metadata) of this parameter
    protected ParamDef paramDef;

    /**************************************************************************
     * Constructor getting this parameter metadata.
     **************************************************************************/
    public BaseParameter(ParamDef paramDef) {
        this.paramDef = paramDef;
    }

    /*************************************************************************
     * Indicates an internal error, usually something wrong in service
     * metadata, or in general configuration. <p>
     *
     * It logs an error, and throws ParameterException.
     *************************************************************************/
    protected void configError(String msg) throws ParameterException {
        ParameterException e = new ParameterException(paramDef.id, "Configuration error: " + msg);
        log.error(e.getMessage());
        throw e;
    }

    /*************************************************************************
     * Create a command line argument from 'tag' (may be empty) and
     * 'value' (should not be null, but may be an empty string, but it
     * is unusual), separated by a space, or as defined in metadata
     * TAGSEPAR. The 'tag' is prepended by 'tagPrefix' (which is
     * usually a minus sign).
     *
     * If 'tag' is empty, both 'tagPrefix' and 'tag' are ignored, and
     * only 'value' (even if it is an empty string) is returned.
     *
     * If TAGSEPAR contains only whitespaces, the 'tag' and 'value'
     * are returned as two different strings (so they will become two
     * different command-line arguments later). Otherwise, one string
     * is returned (a typical use cas would be a TAGSEPAR equal '='
     * which would result in a returned string 'tag=value'). In the
     * latter case, 'tagPrefix' is ignored, as well.
     *************************************************************************/
    protected List<String> taggedArg(String tagPrefix, String tag, String value) {
        if (value == null)
            return CmdLineJob.EMPTY_LIST;

        if (StringUtils.isBlank(tag))
            return array2list(value);

        String tagsepar;
        if (paramDef.options.containsKey(ParamDef.TAGSEPAR)) {
            tagsepar = paramDef.get(ParamDef.TAGSEPAR);
            if (tagsepar.equals("true"))
                tagsepar = " "; // a way how to specify default tagsepar
        } else {
            tagsepar = " ";
        }
        if (StringUtils.isBlank(tagsepar) && StringUtils.isNotEmpty(tagsepar)) {
            return array2list(tagPrefix + tag, value);
        } else {
            return array2list(tag + tagsepar + value);
        }
    }

    /**************************************************************************
     *
     **************************************************************************/
    protected List<String> array2list(String... args) {
        List<String> list = new ArrayList<String>(args.length);
        for (String str : args)
            list.add(str);
        return list;
    }

    /**************************************************************************
     * Convert a list of created arguments into (environment) properties.
     *
     * TBD: for now, until we decide differently, take just the first
     * two elements
     **************************************************************************/
    protected Properties list2props(List<String> args) {

        if (args.size() == 0)
            return CmdLineJob.EMPTY_PROPS;
        Properties env = new Properties();
        if (args.size() > 1)
            env.put(args.get(0), args.get(1));
        else
            env.put(args.get(0), "true");
        return env;
    }

    /**************************************************************************
     * If the given 'value' is an array, return just its first
     * element, but log warning about it. Otherwise return the same
     * 'value'. Be aware that the given 'value' may be null, or it can
     * be a byte array.
     *
     * This is used for parameters that should not receive repetitive
     * values.
     **************************************************************************/
    protected Object ignoreArray(Object value) {
        if (value == null)
            return value;

        if (value instanceof byte[])
            return new String((byte[]) value);

        if (value.getClass().isArray()) {
            log.warn("'" + paramDef.id + "' got an array input. Second and other elements ignored.");
            Object[] vals = (Object[]) value;
            if (vals.length > 0) {
                if (vals[0] instanceof byte[])
                    return new String((byte[]) vals[0]);
                else
                    return vals[0];
            } else {
                return null;
            }
        }
        return value;
    }

    /*************************************************************************
     * Extract and return value for this parameter from 'inputs', or
     * from default. If there is no input for this parameter, return
     * false.
     *
     * TBD: Perhaps it should be changed to String[] getValues(...),
     * returning an empty array if none inputs, and one element of a
     * boolean character if an input found (as it is with other types
     * of parameters).
     *************************************************************************/
    protected boolean getValue(Map<String, Object> inputs) throws ParameterException {

        // get value (real or from default)
        Object objValue = ignoreArray(inputs.get(paramDef.id));
        if (objValue != null && StringUtils.isNotBlank(objValue.toString())) {
            return BooleanUtils.toBoolean(objValue.toString());
        } else {
            return BooleanUtils.toBoolean(getDefaultValue());
        }
    }

    /**************************************************************************
     * It returns a default value - but only if the option
     * USE_DEFAULTS is on. It returns null if there is no default
     * value, or if the USE_DEFAULTS is off.
     **************************************************************************/
    protected String getDefaultValue() {
        if (!paramDef.is(ParamDef.USE_DEFAULTS))
            return null;
        if (StringUtils.isEmpty(paramDef.dflt))
            return null;
        return paramDef.dflt;
    }

    /*************************************************************************
     * It builds an argument. The created argument does not contain
     * any value from 'inputs', but only TAG (if there was a value in
     * 'inputs'), or whatever is in METHOD.
     *
     * Sometimes, it is good to include even FALSE value (e.g for
     * setting environment variables) in the result. By default, FALSE
     * value is not considered (and empty list is returned), unless
     * 'insistOnFalse' is true.
     *************************************************************************/
    protected List<String> build(Map<String, Object> inputs, Job job, String tagPrefix, boolean insistOnFalse)
            throws ParameterException {

        // get value (real or from default)
        boolean value = getValue(inputs);

        if (!value) {
            if (insistOnFalse) {
                return taggedArg(tagPrefix, paramDef.get(ParamDef.TAG), "false");
            } else {
                return CmdLineJob.EMPTY_LIST;
            }
        }

        if (StringUtils.isBlank(paramDef.get(ParamDef.METHOD))) {

            // no METHOD defined, so do it traditionally with tags
            if (StringUtils.isNotBlank(paramDef.get(ParamDef.TAG))) {
                List<String> result = new ArrayList<String>();
                result.add(tagPrefix + paramDef.get(ParamDef.TAG));
                return result;
            } else {
                configError("No TAG defined!");
            }
        } else {
            // use parameter template METHOD
            return createArgByMethod(new DefaultParameterAccessor(paramDef.id, paramDef.get(ParamDef.TAG),
                    new String[] { paramDef.get(ParamDef.TAG) }));
        }
        return null; // never comes here
    }

    /*************************************************************************
     * Similar as 'build' but creating different structure.
     *************************************************************************/
    protected NamedValues buildNamed(Map<String, Object> inputs, Job job) throws ParameterException {

        // get value (real or from default)
        boolean value = getValue(inputs);
        if (!value)
            return null;

        // build named values
        NamedValues result = new NamedValues(paramDef.id);
        if (StringUtils.isBlank(paramDef.get(ParamDef.METHOD))) {

            // no METHOD defined, fill the tag, leave value empty or put there 'truevalue'
            if (StringUtils.isNotBlank(paramDef.get(ParamDef.TAG))) {
                result.setTag(paramDef.get(ParamDef.TAG));
                String trueValue = paramDef.get(ParamDef.TRUEVALUE);
                if (StringUtils.isNotEmpty(trueValue))
                    result.addValue(trueValue);
            } else {
                configError("No TAG defined!");
            }
        } else {
            // use parameter template METHOD
            result.setValues(createArgByMethod(new DefaultParameterAccessor(paramDef.id, paramDef.get(ParamDef.TAG),
                    new String[] { paramDef.get(ParamDef.TAG) })));
        }
        return result;
    }

    /*************************************************************************
     * It creates one or more command line arguments for a given
     * parameter using its METHOD. <p>
     *
     * The values (all repetitions) of this parameter are accessible
     * using given 'paramAccessor' (this accessor is used also by
     * class Substitutor). <p>
     *************************************************************************/
    protected List<String> createArgByMethod(ParameterAccessor paramAccessor) {
        if (paramAccessor.getCount(paramDef.id) == 0 || StringUtils.isEmpty(paramAccessor.getValue(paramDef.id, 0)))
            return CmdLineJob.EMPTY_LIST;

        Substitutor engine = new Substitutor(paramDef.get(ParamDef.METHOD), paramDef.get(ParamDef.SEPARATOR),
                paramAccessor);
        return array2list(engine.process());
    }

    //
    // Methods implementing interface Parameter
    //

    /*************************************************************************
     *
     *************************************************************************/
    public ParamDef getDefinition() {
        return paramDef;
    }

    /**************************************************************************
     *
     **************************************************************************/
    public NamedValues createNamedArg(Map<String, Object> inputs, Job job) throws ParameterException {

        if (paramDef.is(ParamDef.ENVAR))
            return null;

        return buildNamed(inputs, job);
    }

    /**************************************************************************
     *
     **************************************************************************/
    public String[] createArg(Map<String, Object> inputs, Job job) throws ParameterException {

        if (paramDef.is(ParamDef.ENVAR))
            return ArrayUtils.EMPTY_STRING_ARRAY;

        return build(inputs, job, CMD, false).toArray(new String[] {});
    }

    /**************************************************************************
     *
     **************************************************************************/
    public Properties createEnv(Map<String, Object> inputs, Job job) throws ParameterException {

        if (!paramDef.is(ParamDef.ENVAR))
            return CmdLineJob.EMPTY_PROPS;

        return list2props(build(inputs, job, "", true));
    }

    /**************************************************************************
     *
     **************************************************************************/
    public IOData[] createIO(Map<String, Object> inputs, Job job) throws ParameterException {
        return CmdLineJob.EMPTY_IODATA;
    }

    /*************************************************************************
     * Nothing implemented here.
     *************************************************************************/
    public void validate(Map<String, Object> inputs, Job job, Object testedValue) throws ParameterException {
    }

}