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     */
017    package net.dpml.cli.commandline;
018    
019    import java.util.ArrayList;
020    import java.util.Arrays;
021    import java.util.Collections;
022    import java.util.HashSet;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Set;
026    import java.util.StringTokenizer;
027    import java.util.prefs.BackingStoreException;
028    import java.util.prefs.Preferences;
029    
030    import net.dpml.cli.Option;
031    
032    /**
033     * A CommandLine implementation using the Preferences API, useful when
034     * constructing a complex DefaultingCommandLine
035     *
036     * This implementation uses the children of a single preference node to populate
037     * the CommandLine.  Options are keyed from their preferred name and presence in
038     * the Preferences object is taken as presence in the CommandLine.  Argument
039     * values are taken from the Preference value and are optionally separated using
040     * the separator char defined, at construction time.  Switch values can be
041     * specified using a simple value of <code>true</code> or <code>false</code>;
042     * obviously this means that Switches with Arguments are not supported by this
043     * implementation.
044     *
045     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
046     * @version 1.0.0
047     * @see java.util.prefs.Preferences
048     * @see net.dpml.cli.commandline.DefaultingCommandLine
049     * @see net.dpml.cli.Option#getPreferredName() 
050     */
051    public class PreferencesCommandLine extends CommandLineImpl
052    {
053        private static final char NUL = '\0';
054        private final Preferences m_preferences;
055        private final Option m_root;
056        private final char m_separator;
057        
058        /**
059         * Creates a new PreferencesCommandLine using the specified root Option and
060         * Preferences node.  Argument values will be separated using the char 0.
061         * 
062         * @param root the CommandLine's root Option
063         * @param preferences the Preferences node to get values from
064         */
065        public PreferencesCommandLine( final Option root, final Preferences preferences )
066        {
067            this( root, preferences, NUL );
068        }
069        
070        /**
071         * Creates a new PreferencesCommandLine using the specified root Option,
072         * Preferences node and value separator.
073         * 
074         * @param root the CommandLine's root Option
075         * @param preferences the Preferences node to get values from
076         * @param separator the character to split argument values
077         */
078        public PreferencesCommandLine(
079          final Option root, final Preferences preferences, final char separator )
080        {
081            m_root = root;
082            m_preferences = preferences;
083            m_separator = separator;
084        }
085        
086        /**
087         * Detects the presence of an option in this CommandLine.
088         * 
089         * @param option the Option to search for
090         * @return true iff the option is present
091         */
092        public boolean hasOption( Option option )
093        {
094            if( option==null )
095            {
096                return false;
097            }
098            else
099            {
100                try 
101                {
102                    return Arrays.asList( m_preferences.keys() ).contains( option.getPreferredName() );
103                } 
104                catch( BackingStoreException e )
105                {
106                    return false;
107                }
108            }
109        }
110    
111        /**
112         * Finds the Option with the specified trigger
113         * 
114         * @param trigger the name of the option to retrieve
115         * @return the Option matching the trigger or null if none exists
116         */
117        public Option getOption( String trigger )
118        {
119            return m_root.findOption( trigger );
120        }
121    
122        /**
123         * Retrieves the Argument values associated with the specified Option
124         * 
125         * @param option the Option associated with the values
126         * @param defaultValues the result to return if no values are found
127         * @return a list of values or defaultValues if none are found
128         */
129        public List getValues( final Option option, final List defaultValues )
130        {
131            final String value = m_preferences.get( option.getPreferredName(), null );
132            if( value==null )
133            {
134                return defaultValues;
135            }
136            else if( m_separator>NUL )
137            {
138                final List values = new ArrayList();
139                final StringTokenizer tokens = new StringTokenizer( value, String.valueOf( m_separator ) );
140                
141                while( tokens.hasMoreTokens() )
142                {
143                    values.add( tokens.nextToken() );
144                }
145                
146                return values;
147            }
148            else
149            {
150                return Collections.singletonList( value );
151            }
152        }
153    
154        /**
155         * Retrieves the Boolean value associated with the specified Switch
156         * 
157         * @param option the Option associated with the value
158         * @param defaultValue the Boolean to use if none match
159         * @return the Boolean associated with option or defaultValue if none exists
160         */
161        public Boolean getSwitch( final Option option, final Boolean defaultValue )
162        {
163            final String value = m_preferences.get( option.getPreferredName(), null );
164            if( "true".equals( value ) )
165            {
166                return Boolean.TRUE;
167            }
168            else if( "false".equals( value ) )
169            {
170                return Boolean.FALSE;
171            }
172            else
173            {
174                return defaultValue;
175            }
176        }
177        
178        /**
179         * Retrieves the value associated with the specified property 
180         * 
181         * @param property the property name to lookup
182         * @param defaultValue the value to use if no other is found
183         * @return the value of the property or defaultValue
184         */
185        public String getProperty( final String property, final String defaultValue )
186        {
187            return m_preferences.get( property, defaultValue );
188        }
189    
190        /**
191         * Retrieves the set of all property names associated with this CommandLine
192         * 
193         * @return a none null set of property names 
194         */
195        public Set getProperties()
196        {
197            try 
198            {
199                return new HashSet( Arrays.asList( m_preferences.keys() ) );
200            }
201            catch( BackingStoreException e )
202            {
203                return Collections.EMPTY_SET;
204            }
205        }
206    
207        /**
208         * Retrieves a list of all Options found in this CommandLine
209         * 
210         * @return a none null list of Options
211         */
212        public List getOptions()
213        {
214            try 
215            {
216                final List options = new ArrayList();
217                final Iterator keys = Arrays.asList( m_preferences.keys() ).iterator();
218                while( keys.hasNext() ) 
219                {
220                    final String trigger = (String) keys.next();
221                    final Option option = m_root.findOption( trigger );
222                    if( option != null )
223                    {
224                        options.add( option );
225                    }
226                }
227                return Collections.unmodifiableList( options );
228            } 
229            catch( BackingStoreException e )
230            {
231                return Collections.EMPTY_LIST;
232            }
233        }
234    
235        /**
236         * Retrieves a list of all Option triggers found in this CommandLine
237         * 
238         * @return a none null list of Option triggers
239         */
240        public Set getOptionTriggers()
241        {
242            final Set triggers = new HashSet();
243            final Iterator options = getOptions().iterator();
244            while( options.hasNext() )
245            {
246                final Option option = (Option) options.next();
247                triggers.addAll( option.getTriggers() );
248            }
249            return Collections.unmodifiableSet( triggers );
250        }
251    }