blob: 28a12624ede56e2af73c3172b3b772520fb04264 [file] [log] [blame]
/* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.etch.util.cmd;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
/**
* A command line value which is introduced by a specified token.
* An option is not dependent upon position on the command line
* to be recognized (but still, position on the command line might
* be important).
*/
abstract public class Option extends OptParamBase
{
/**
* @param cp
* @param tokens
* @param name
* @param method
* @param params
* @param description
* @param flags
* @param defaultValue
* @param constraint
* @throws Exception
*/
public Option( CommandParser cp, String tokens, String name, String method,
Class<?>[] params, String description, int flags, Object defaultValue,
Constraint constraint ) throws Exception
{
super( cp, name, method, params, description, (flags & REQUIRED) != 0,
constraint );
if (!setTokens( tokens ))
throw new IllegalArgumentException( "no tokens for option" );
isArray = params.length > 3 && params[3].isArray();
this.flags = flags;
if (defaultValue != null)
defaultValues = new Object[] { defaultValue };
else
defaultValues = null;
if (constraint != null && defaultValue != null)
constraint.checkValue( defaultValue );
}
/**
* @param cp
* @param tokens
* @param names
* @param method
* @param params
* @param description
* @param flags
* @param defaultValues
* @param constraints
* @throws Exception
*/
public Option( CommandParser cp, String tokens, String[] names, String method,
Class<?>[] params, String description, int flags, Object[] defaultValues,
Constraint[] constraints ) throws Exception
{
super( cp, names, method, params, description, (flags & REQUIRED) != 0,
constraints );
if (!setTokens( tokens ))
throw new IllegalArgumentException( "no tokens for option" );
if (defaultValues != null && defaultValues.length != names.length)
throw new IllegalArgumentException( "defaultValue.length != name.length" );
isArray = params.length > 3 && params[3].isArray();
this.flags = flags;
this.defaultValues = defaultValues;
if (constraints != null && defaultValues != null)
{
int n = constraints.length;
for (int i = 0; i < n; i++)
{
Constraint c = constraints[i];
Object v = defaultValues[i];
if (c != null)
c.checkValue( v );
}
}
}
private final boolean isArray;
private final int flags;
private final Object[] defaultValues;
/**
* The option has no special handling.
*/
public static final int NONE = 0;
/**
* The option is hidden from the user. It must not be specified.
* It must not be required or it must have a default value.
*/
public static final int HIDDEN = 1;
/**
* The option may only be specified once.
*/
public static final int SINGLETON = 2;
/**
* The option is required to be specified.
*/
public static final int REQUIRED = 4;
/**
* @return an iterator over the tokens of an option.
*/
public Iterator<String> getTokens()
{
return tokens.iterator();
}
/**
* @return true if the option is hidden.
*/
public boolean isHidden()
{
return matchFlags( HIDDEN );
}
/**
* @return true if the option may only appear once.
*/
public boolean isSingleton()
{
return matchFlags( SINGLETON );
}
/**
* @param flag
* @return true if the flag has been specified, false otherwise
*/
private boolean matchFlags( int flag )
{
return (flags & flag) != 0;
}
/**
* @return the default value of the option.
*/
public Object[] getDefaultValues()
{
return defaultValues;
}
@Override
public String toString()
{
return toString( primaryToken != null ? primaryToken : "(unknown)" );
}
/**
* @param token
* @return the
*/
protected String toString( String token )
{
StringBuffer sb = new StringBuffer( token );
String[] names = getNames();
if (names != null)
{
for (String name: names)
{
sb.append( ' ' );
sb.append( name );
}
}
return sb.toString();
}
////////////
// TOKENS //
////////////
private boolean setTokens( String s )
{
tokens.clear();
primaryToken = null;
StringTokenizer st = new StringTokenizer( s, "|,; \r\n\t" );
while (st.hasMoreTokens())
{
String t = st.nextToken();
tokens.add( t );
if (primaryToken == null)
primaryToken = t;
}
return tokens.size() > 0;
}
/**
* @return the first token in the token list of the option.
*/
public String getPrimaryToken()
{
return primaryToken;
}
private List<String> tokens = new ArrayList<String>();
private String primaryToken;
//////////
// HELP //
//////////
@Override
public void showShortDescription()
{
System.err.print( isRequired() ? " {" : " [" );
System.err.print( ' ' );
System.err.print( primaryToken );
if (wantsValue())
{
for (String name: getNames())
{
System.err.print( ' ' );
System.err.print( name );
}
}
System.err.print( isRequired() ? " }" : " ]" );
}
@Override
public void showLongDescription()
{
Iterator<String> i = tokens.iterator();
while (i.hasNext())
{
System.err.print( NAME_FLAG );
System.err.print( i.next() );
if (wantsValue())
{
for (String name: getNames())
{
System.err.print( ' ' );
System.err.print( name );
}
}
System.err.println();
}
showDescription();
showIsRequired();
showConstraint();
if (isSingleton())
{
System.err.print( DESC_FLAG );
System.err.println( "singleton (may only be specified once)." );
}
if (defaultValues != null)
{
int n = defaultValues.length;
System.err.print( DESC_FLAG );
if (n > 1)
System.err.print( "default: {" );
else
System.err.print( "default: " );
for (Object defaultValue: defaultValues)
{
System.err.print( ' ' );
System.err.print( defaultValue );
}
if (n > 1)
System.err.println( " }" );
else
System.err.println();
}
}
///////////
// VALUE //
///////////
/**
* @return true if this option needs a value, false otherwise.
*/
public boolean wantsValue()
{
return true;
}
/**
* @param token
* @param value value specified on the token (e.g., --count=23)
* @param tkns
* @return value from tokens converted as appropriate.
*/
public Object[] getAndConvertValue( String token, String value, Iterator<String> tkns )
{
// System.out.printf( "looking for value for token %s: value = %s\n", token, value );
Object[] values = new Object[getNames().length];
int i = 0;
for (String name: getNames())
{
if (value == null && !tkns.hasNext())
{
System.err.println( "option '"+toString( token )+"': missing value "+name );
return null;
}
values[i++] = convertValue( value != null ? value : tkns.next() );
value = null;
}
return values;
}
@Override
public boolean checkValue( String token, Object[] values )
{
return super.checkValue( "option '"+toString( token )+"'", values );
}
/**
* @param token
* @param values
* @param hiddenOk
* @return value returned by called method.
* @throws Exception
*/
public boolean deliverValue( String token, Object[] values, boolean hiddenOk )
throws Exception
{
try
{
if (!checkOkToDeliver( token, hiddenOk ))
return false;
if (isArray)
return callMethod( getArgs( token, values ) );
return callMethod( getArgs( token, values != null ? values[0] : null ) );
}
catch ( InvocationTargetException e )
{
Throwable t = e.getTargetException();
if (t instanceof Exception)
throw (Exception) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
throw new RuntimeException( "caught exception: "+t, t );
}
}
/**
* @param token
* @param hiddenOk
* @return false if flags prevent delivery of the option value.
*/
private boolean checkOkToDeliver( String token, boolean hiddenOk )
{
// allow hidden option to be specified. just don't show it in help.
// if (isHidden() && !hiddenOk)
// {
// getCommandParser().report( "option '"+toString( token )+"' not allowed", null, null );
// return false;
// }
if (getCommandParser().isAlreadySpecified( this, true ) && isSingleton())
{
getCommandParser().report( "option '"+toString( token )+"' not allowed more than once", null, null );
return false;
}
return true;
}
/**
* @param token
* @param value
* @return the args to pass to the method.
*/
protected Object[] getArgs( String token, Object value )
{
return new Object[] { getCommandParser(), this, token, value };
}
}