001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.env;
018
019import java.util.ArrayList;
020import java.util.Collections;
021import java.util.List;
022
023import joptsimple.OptionSet;
024import joptsimple.OptionSpec;
025
026import org.springframework.lang.Nullable;
027import org.springframework.util.CollectionUtils;
028import org.springframework.util.StringUtils;
029
030/**
031 * {@link CommandLinePropertySource} implementation backed by a JOpt {@link OptionSet}.
032 *
033 * <h2>Typical usage</h2>
034 *
035 * Configure and execute an {@code OptionParser} against the {@code String[]} of arguments
036 * supplied to the {@code main} method, and create a {@link JOptCommandLinePropertySource}
037 * using the resulting {@code OptionSet} object:
038 *
039 * <pre class="code">
040 * public static void main(String[] args) {
041 *     OptionParser parser = new OptionParser();
042 *     parser.accepts("option1");
043 *     parser.accepts("option2").withRequiredArg();
044 *     OptionSet options = parser.parse(args);
045 *     PropertySource<?> ps = new JOptCommandLinePropertySource(options);
046 *     // ...
047 * }</pre>
048 *
049 * See {@link CommandLinePropertySource} for complete general usage examples.
050 *
051 * <p>Requires JOpt Simple version 4.3 or higher. Tested against JOpt up until 5.0.
052 *
053 * @author Chris Beams
054 * @author Juergen Hoeller
055 * @author Dave Syer
056 * @since 3.1
057 * @see CommandLinePropertySource
058 * @see joptsimple.OptionParser
059 * @see joptsimple.OptionSet
060 */
061public class JOptCommandLinePropertySource extends CommandLinePropertySource<OptionSet> {
062
063        /**
064         * Create a new {@code JOptCommandLinePropertySource} having the default name
065         * and backed by the given {@code OptionSet}.
066         * @see CommandLinePropertySource#COMMAND_LINE_PROPERTY_SOURCE_NAME
067         * @see CommandLinePropertySource#CommandLinePropertySource(Object)
068         */
069        public JOptCommandLinePropertySource(OptionSet options) {
070                super(options);
071        }
072
073        /**
074         * Create a new {@code JOptCommandLinePropertySource} having the given name
075         * and backed by the given {@code OptionSet}.
076         */
077        public JOptCommandLinePropertySource(String name, OptionSet options) {
078                super(name, options);
079        }
080
081
082        @Override
083        protected boolean containsOption(String name) {
084                return this.source.has(name);
085        }
086
087        @Override
088        public String[] getPropertyNames() {
089                List<String> names = new ArrayList<>();
090                for (OptionSpec<?> spec : this.source.specs()) {
091                        String lastOption = CollectionUtils.lastElement(spec.options());
092                        if (lastOption != null) {
093                                // Only the longest name is used for enumerating
094                                names.add(lastOption);
095                        }
096                }
097                return StringUtils.toStringArray(names);
098        }
099
100        @Override
101        @Nullable
102        public List<String> getOptionValues(String name) {
103                List<?> argValues = this.source.valuesOf(name);
104                List<String> stringArgValues = new ArrayList<>();
105                for (Object argValue : argValues) {
106                        stringArgValues.add(argValue.toString());
107                }
108                if (stringArgValues.isEmpty()) {
109                        return (this.source.has(name) ? Collections.emptyList() : null);
110                }
111                return Collections.unmodifiableList(stringArgValues);
112        }
113
114        @Override
115        protected List<String> getNonOptionArgs() {
116                List<?> argValues = this.source.nonOptionArguments();
117                List<String> stringArgValues = new ArrayList<>();
118                for (Object argValue : argValues) {
119                        stringArgValues.add(argValue.toString());
120                }
121                return (stringArgValues.isEmpty() ? Collections.emptyList() :
122                                Collections.unmodifiableList(stringArgValues));
123        }
124
125}