001/**
002 * Copyright 2004 The Apache Software Foundation
003 * Copyright 2005 Stephen McConnell
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package net.dpml.cli.commandline;
018
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.HashSet;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Properties;
025import java.util.Set;
026import java.util.StringTokenizer;
027
028import net.dpml.cli.Option;
029
030/**
031 * A CommandLine implementation using a java Properties instance, useful for
032 * constructing a complex DefaultingCommandLine
033 *
034 * Options are keyed from their property name and presence in the Properties
035 * instance is taken as presence in the CommandLine.  Argument values are taken
036 * from the property value and are optionally separated using the separator
037 * char, defined at construction time.  Switch values can be specified using a
038 * simple value of <code>true</code> or <code>false</code>; obviously this means
039 * that Switches with Arguments are not supported by this implementation.
040 *
041 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
042 * @version @PROJECT-VERSION@
043 * @see java.util.Properties
044 * @see net.dpml.cli.commandline.DefaultingCommandLine
045 * @see net.dpml.cli.Option#getPreferredName() 
046 */
047public class PropertiesCommandLine extends CommandLineImpl
048{
049    
050    private static final char NUL = '\0';
051    private final Properties m_properties;
052    private final Option m_root;
053    private final char m_separator;
054    
055    /**
056     * Creates a new PropertiesCommandLine using the specified root Option,
057     * Properties instance.  The character 0 is used as the value separator.
058     *
059     * @param root the CommandLine's root Option
060     * @param properties the Properties instance to get values from
061     */
062    public PropertiesCommandLine( final Option root, final Properties properties )
063    {
064        this( root, properties, NUL );
065    }
066    
067    /**
068     * Creates a new PropertiesCommandLine using the specified root Option,
069     * Properties instance and value separator.
070     *
071     * @param root the CommandLine's root Option
072     * @param properties the Properties instance to get values from
073     * @param separator the character to split argument values
074     */
075    public PropertiesCommandLine( final Option root, final Properties properties, final char separator )
076    {
077        m_root = root;
078        m_properties = properties;
079        m_separator = separator;
080    }
081    
082    /**
083     * Detects the presence of an option in this CommandLine.
084     * 
085     * @param option the Option to search for
086     * @return true iff the option is present
087     */
088    public boolean hasOption( Option option )
089    {
090        if( option==null )
091        {
092            return false;
093        }
094        else
095        {
096            return m_properties.containsKey( option.getPreferredName() );
097        }
098    }
099
100    /**
101     * Finds the Option with the specified trigger
102     * 
103     * @param trigger the name of the option to retrieve
104     * @return the Option matching the trigger or null if none exists
105     */
106    public Option getOption( String trigger )
107    {
108        return m_root.findOption( trigger );
109    }
110
111    /**
112     * Retrieves the Argument values associated with the specified Option
113     * 
114     * @param option the Option associated with the values
115     * @param defaultValues the result to return if no values are found
116     * @return a list of values or defaultValues if none are found
117     */
118    public List getValues( final Option option, final List defaultValues )
119    {
120        final String value = m_properties.getProperty( option.getPreferredName() );
121        
122        if( value==null )
123        {
124            return defaultValues;
125        }
126        else if( m_separator > NUL )
127        {
128            final List values = new ArrayList();
129            final StringTokenizer tokens = new StringTokenizer( value, String.valueOf( m_separator ) );
130            
131            while( tokens.hasMoreTokens() )
132            {
133                values.add( tokens.nextToken() );
134            }
135            return values;
136        }
137        else
138        {
139            return Collections.singletonList( value );
140        }
141    }
142
143    /**
144     * Retrieves the Boolean value associated with the specified Switch
145     * 
146     * @param option the Option associated with the value
147     * @param defaultValue the Boolean to use if none match
148     * @return the Boolean associated with option or defaultValue if none exists
149     */
150    public Boolean getSwitch( final Option option, final Boolean defaultValue ) 
151    {
152        final String value = m_properties.getProperty( option.getPreferredName() );
153        if( "true".equals( value ) )
154        {
155            return Boolean.TRUE;
156        }
157        else if( "false".equals( value ) )
158        {
159            return Boolean.FALSE;
160        }
161        else
162        {
163            return defaultValue;
164        }
165    }
166    
167    /**
168     * Retrieves the value associated with the specified property 
169     * 
170     * @param property the property name to lookup
171     * @param defaultValue the value to use if no other is found
172     * @return the value of the property or defaultValue
173     */
174    public String getProperty( final String property, final String defaultValue )
175    {
176        return m_properties.getProperty( property, defaultValue );
177    }
178
179    /**
180     * Retrieves the set of all property names associated with this CommandLine
181     * 
182     * @return a none null set of property names 
183     */
184    public Set getProperties()
185    {
186        return m_properties.keySet();
187    }
188
189    /**
190     * Retrieves a list of all Options found in this CommandLine
191     * 
192     * @return a none null list of Options
193     */
194    public List getOptions()
195    {
196        final List options = new ArrayList();
197        final Iterator keys = m_properties.keySet().iterator();
198        while( keys.hasNext() )
199        {
200            final String trigger = (String) keys.next();
201            final Option option = m_root.findOption( trigger );
202            if( option!=null )
203            {
204                options.add( option );
205            }
206        }
207        return Collections.unmodifiableList( options );
208    }
209
210    /**
211     * Retrieves a list of all Option triggers found in this CommandLine
212     * 
213     * @return a none null list of Option triggers
214     */
215    public Set getOptionTriggers()
216    {
217        final Set triggers = new HashSet();
218        final Iterator options = getOptions().iterator();
219        while( options.hasNext() ) 
220        {
221            final Option option = (Option) options.next();
222            triggers.addAll( option.getTriggers() );
223        }
224        return Collections.unmodifiableSet( triggers );
225    }
226}