001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  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 org.apache.commons.cli2.commandline;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.Collections;
022import java.util.HashSet;
023import java.util.Iterator;
024import java.util.List;
025import java.util.Set;
026import java.util.StringTokenizer;
027import java.util.prefs.BackingStoreException;
028import java.util.prefs.Preferences;
029
030import org.apache.commons.cli2.Option;
031import org.apache.commons.cli2.option.PropertyOption;
032
033/**
034 * A CommandLine implementation using the Preferences API, useful when
035 * constructing a complex DefaultingCommandLine
036 *
037 * This implementation uses the children of a single preference node to populate
038 * the CommandLine.  Options are keyed from their preferred name and presence in
039 * the Preferences object is taken as presence in the CommandLine.  Argument
040 * values are taken from the Preference value and are optionally separated using
041 * the separator char defined, at construction time.  Switch values can be
042 * specified using a simple value of <code>true</code> or <code>false</code>;
043 * obviously this means that Switches with Arguments are not supported by this
044 * implementation.
045 *
046 * @see java.util.prefs.Preferences
047 * @see org.apache.commons.cli2.commandline.DefaultingCommandLine
048 * @see org.apache.commons.cli2.Option#getPreferredName()
049 */
050public class PreferencesCommandLine extends CommandLineImpl {
051
052    private static final char NUL = '\0';
053    private final Preferences preferences;
054    private final Option root;
055    private final char separator;
056
057    /**
058     * Creates a new PreferencesCommandLine using the specified root Option and
059     * Preferences node.  Argument values will be separated using the char 0.
060     *
061     * @param root the CommandLine's root Option
062     * @param preferences the Preferences node to get values from
063     */
064    public PreferencesCommandLine(final Option root, final Preferences preferences){
065        this(root,preferences,NUL);
066    }
067
068    /**
069     * Creates a new PreferencesCommandLine using the specified root Option,
070     * Preferences node and value separator.
071     *
072     * @param root the CommandLine's root Option
073     * @param preferences the Preferences node to get values from
074     * @param separator the character to split argument values
075     */
076    public PreferencesCommandLine(final Option root, final Preferences preferences, final char separator){
077        this.root = root;
078        this.preferences = preferences;
079        this.separator = separator;
080    }
081
082    public boolean hasOption(Option option) {
083        if(option==null){
084            return false;
085        }
086        else{
087            try {
088                return Arrays.asList(preferences.keys()).contains(option.getPreferredName());
089            } catch (BackingStoreException e) {
090                return false;
091            }
092        }
093    }
094
095    public Option getOption(String trigger) {
096        return root.findOption(trigger);
097    }
098
099    public List getValues(final Option option, final List defaultValues) {
100        final String value = preferences.get(option.getPreferredName(),null);
101
102        if(value==null){
103            return defaultValues;
104        }
105        else if(separator>NUL){
106            final List values = new ArrayList();
107            final StringTokenizer tokens = new StringTokenizer(value,String.valueOf(separator));
108
109            while(tokens.hasMoreTokens()){
110                values.add(tokens.nextToken());
111            }
112
113            return values;
114        }
115        else{
116            return Collections.singletonList(value);
117        }
118    }
119
120    public Boolean getSwitch(final Option option, final Boolean defaultValue) {
121        final String value = preferences.get(option.getPreferredName(),null);
122        if("true".equals(value)){
123            return Boolean.TRUE;
124        }
125        else if("false".equals(value)){
126            return Boolean.FALSE;
127        }
128        else{
129            return defaultValue;
130        }
131    }
132
133    public String getProperty(final String property) {
134        return getProperty(new PropertyOption(), property);
135    }
136
137    public String getProperty(final Option option, final String property, final String defaultValue) {
138        return preferences.get(property, defaultValue);
139    }
140
141        public Set getProperties(final Option option) {
142        try {
143            return new HashSet(Arrays.asList(preferences.keys()));
144        } catch (BackingStoreException e) {
145            return Collections.EMPTY_SET;
146        }
147    }
148
149    public Set getProperties() {
150        return getProperties(new PropertyOption());
151    }
152
153    public List getOptions() {
154        try {
155            final List options = new ArrayList();
156            final Iterator keys = Arrays.asList(preferences.keys()).iterator();
157            while (keys.hasNext()) {
158                final String trigger = (String) keys.next();
159                final Option option = root.findOption(trigger);
160                if (option != null) {
161                    options.add(option);
162                }
163            }
164            return Collections.unmodifiableList(options);
165        } catch (BackingStoreException e) {
166            return Collections.EMPTY_LIST;
167        }
168    }
169
170    public Set getOptionTriggers() {
171        final Set triggers = new HashSet();
172        final Iterator options = getOptions().iterator();
173        while(options.hasNext()){
174            final Option option = (Option)options.next();
175            triggers.addAll(option.getTriggers());
176        }
177        return Collections.unmodifiableSet(triggers);
178    }
179}