getNonOptionArgs() {
+ return Collections.unmodifiableList(this.nonOptionArgs);
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java
new file mode 100644
index 00000000000..1620fd427b3
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/env/CommandLinePropertySource.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Abstract base class for {@link PropertySource} implementations backed by command line
+ * arguments. The parameterized type {@code T} represents the underlying source of command
+ * line options. This may be as simple as a String array in the case of
+ * {@link SimpleCommandLinePropertySource}, or specific to a particular API such as JOpt's
+ * {@code OptionSet} in the case of {@link JOptCommandLinePropertySource}.
+ *
+ * Purpose and General Usage
+ * For use in standalone Spring-based applications, i.e. those that are bootstrapped via
+ * a traditional {@code main} method accepting a {@code String[]} of arguments from the
+ * command line. In many cases, processing command-line arguments directly within the
+ * {@code main} method may be sufficient, but in other cases, it may be desirable to
+ * inject arguments as values into Spring beans. It is this latter set of cases in which
+ * a {@code CommandLinePropertySource} becomes useful. A {@code CommandLinePropertySource}
+ * will typically be added to the {@link Environment} of the Spring
+ * {@code ApplicationContext}, at which point all command line arguments become available
+ * through the {@link Environment#getProperty(String)} family of methods. For example:
+ *
+ * public static void main(String[] args) {
+ * CommandLinePropertySource clps = ...;
+ * AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
+ * ctx.getEnvironment().getPropertySources().addFirst(clps);
+ * ctx.register(AppConfig.class);
+ * ctx.refresh();
+ * }
+ * With the bootstrap logic above, the {@code AppConfig} class may {@code @Inject} the
+ * Spring {@code Environment} and query it directly for properties:
+ *
+ * @Configuration
+ * public class AppConfig {
+ * @Inject Environment env;
+ *
+ * @Bean
+ * public void DataSource dataSource() {
+ * MyVendorDataSource dataSource = new MyVendorDataSource();
+ * dataSource.setHostname(env.getProperty("db.hostname", "localhost"));
+ * dataSource.setUsername(env.getRequiredProperty("db.username"));
+ * dataSource.setPassword(env.getRequiredProperty("db.password"));
+ * // ...
+ * return dataSource;
+ * }
+ * }
+ * Because the {@code CommandLinePropertySource} was added to the {@code Environment}'s
+ * set of {@link MutablePropertySources} using the {@code #addFirst} method, it has
+ * highest search precedence, meaning that while "db.hostname" and other properties may
+ * exist in other property sources such as the system environment variables, it will be
+ * chosen from the command line property source first. This is a reasonable approach
+ * given that arguments specified on the command line are naturally more specific than
+ * those specified as environment variables.
+ *
+ * As an alternative to injecting the {@code Environment}, Spring's {@code @Value}
+ * annotation may be used to inject these properties, given that a {@link
+ * PropertySourcesPropertyResolver} bean has been registered, either directly or through
+ * using the {@code } element. For example:
+ *
+ * @Component
+ * public class MyComponent {
+ * @Value("my.property:defaultVal")
+ * private String myProperty;
+ *
+ * public void getMyProperty() {
+ * return this.myProperty;
+ * }
+ *
+ * // ...
+ * }
+ *
+ * Working with option arguments
+ *
+ * Individual command line arguments are represented as properties through the usual
+ * {@link PropertySource#getProperty(String)} and
+ * {@link PropertySource#containsProperty(String)} methods. For example, given the
+ * following command line:
+ *
+ * --o1=v1 --o2
+ * 'o1' and 'o2' are treated as "option arguments", and the following assertions would
+ * evaluate true:
+ *
+ * CommandLinePropertySource> ps = ...
+ * assert ps.containsProperty("o1") == true;
+ * assert ps.containsProperty("o2") == true;
+ * assert ps.containsProperty("o3") == false;
+ * assert ps.getProperty("o1").equals("v1");
+ * assert ps.getProperty("o2").equals("");
+ * assert ps.getProperty("o3") == null;
+ *
+ * Note that the 'o2' option has no argument, but {@code getProperty("o2")} resolves to
+ * empty string ({@code ""}) as opposed to {@code null}, while {@code getProperty("o3")}
+ * resolves to {@code null} because it was not specified. This behavior is consistent with
+ * the general contract to be followed by all {@code PropertySource} implementations.
+ *
+ * Note also that while "--" was used in the examples above to denote an option
+ * argument, this syntax may vary across individual command line argument libraries. For
+ * example, a JOpt- or Commons CLI-based implementation may allow for single dash ("-")
+ * "short" option arguments, etc.
+ *
+ *
Working with non-option arguments
+ *
+ * Non-option arguments are also supported through this abstraction. Any arguments
+ * supplied without an option-style prefix such as "-" or "--" are considered "non-option
+ * arguments" and available through the special {@linkplain
+ * #DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME "nonOptionArgs"} property. If multiple
+ * non-option arguments are specified, the value of this property will be a
+ * comma-delimited string containing all of the arguments. This approach ensures a simple
+ * and consistent return type (String) for all properties from a {@code
+ * CommandLinePropertySource} and at the same time lends itself to conversion when used
+ * in conjunction with the Spring {@link Environment} and its built-in {@code
+ * ConversionService}. Consider the following example:
+ *
+ * --o1=v1 --o2=v2 /path/to/file1 /path/to/file2
+ * In this example, "o1" and "o2" would be considered "option arguments", while the two
+ * filesystem paths qualify as "non-option arguments". As such, the following assertions
+ * will evaluate true:
+ *
+ * CommandLinePropertySource> ps = ...
+ * assert ps.containsProperty("o1") == true;
+ * assert ps.containsProperty("o2") == true;
+ * assert ps.containsProperty("nonOptionArgs") == true;
+ * assert ps.getProperty("o1").equals("v1");
+ * assert ps.getProperty("o2").equals("v2");
+ * assert ps.getProperty("nonOptionArgs").equals("/path/to/file1,/path/to/file2");
+ *
+ * As mentioned above, when used in conjunction with the Spring {@code Environment}
+ * abstraction, this comma-delimited string may easily be converted to a String array or
+ * list:
+ *
+ * Environment env = applicationContext.getEnvironment();
+ * String[] nonOptionArgs = env.getProperty("nonOptionArgs", String[].class);
+ * assert nonOptionArgs[0].equals("/path/to/file1");
+ * assert nonOptionArgs[1].equals("/path/to/file2");
+ *
+ * The name of the special "non-option arguments" property may be customized through
+ * the {@link #setNonOptionArgsPropertyName(String)} method. Doing so is recommended as
+ * it gives proper semantic value to non-option arguments. For example, if filesystem
+ * paths are being specified as non-option arguments, it is likely preferable to refer to
+ * these as something like "file.locations" than the default of "nonOptionArgs":
+ *
+ * public static void main(String[] args) {
+ * CommandLinePropertySource clps = ...;
+ * clps.setNonOptionArgsPropertyName("file.locations");
+ *
+ * AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
+ * ctx.getEnvironment().getPropertySources().addFirst(clps);
+ * ctx.register(AppConfig.class);
+ * ctx.refresh();
+ * }
+ *
+ * Limitations
+ * This abstraction is not intended to expose the full power of underlying command line
+ * parsing APIs such as JOpt or Commons CLI. It's intent is rather just the opposite: to
+ * provide the simplest possible abstraction for accessing command line arguments
+ * after they have been parsed. So the typical case will involve fully configuring
+ * the underlying command line parsing API, parsing the {@code String[]} of arguments
+ * coming into the main method, and then simply providing the parsing results to an
+ * implementation of {@code CommandLinePropertySource}. At that point, all arguments can
+ * be considered either 'option' or 'non-option' arguments and as described above can be
+ * accessed through the normal {@code PropertySource} and {@code Environment} APIs.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ * @see PropertySource
+ * @see SimpleCommandLinePropertySource
+ * @see JOptCommandLinePropertySource
+ */
+public abstract class CommandLinePropertySource extends PropertySource {
+
+ /** The default name given to {@link CommandLinePropertySource} instances: {@value} */
+ public static final String DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";
+
+ /** The default name of the property representing non-option arguments: {@value} */
+ public static final String DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME = "nonOptionArgs";
+
+ private String nonOptionArgsPropertyName = DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME;
+
+ /**
+ * Create a new {@code CommandLinePropertySource} having the default name {@value
+ * #DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME} and backed by the given source object.
+ */
+ public CommandLinePropertySource(T source) {
+ super(DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
+ }
+
+ /**
+ * Create a new {@link CommandLinePropertySource} having the given name and backed by
+ * the given source object.
+ */
+ public CommandLinePropertySource(String name, T source) {
+ super(name, source);
+ }
+
+ /**
+ * Specify the name of the special "non-option arguments" property. The default is
+ * {@value #DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME}.
+ */
+ public void setNonOptionArgsPropertyName(String nonOptionArgsPropertyName) {
+ this.nonOptionArgsPropertyName = nonOptionArgsPropertyName;
+ }
+
+ /**
+ * Return whether this {@code PropertySource} contains the given key.
+ * This implementation first checks to see if the key specified is the special
+ * {@linkplain #setNonOptionArgsPropertyName(String) "non-option arguments" property},
+ * and if so delegates to the abstract {@link #getNonOptionArgs()} method
+ * checking to see whether it returns an empty collection. Otherwise delegates to and
+ * returns the value of the abstract {@link #containsOption(String)} method.
+ */
+ @Override
+ public final boolean containsProperty(String key) {
+ if (this.nonOptionArgsPropertyName.equals(key)) {
+ return !this.getNonOptionArgs().isEmpty();
+ }
+ return this.containsOption(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
This implementation first checks to see if the key specified is the special
+ * {@linkplain #setNonOptionArgsPropertyName(String) "non-option arguments" property},
+ * and if so delegates to the abstract {@link #getNonOptionArgs()} method. If so
+ * and the collection of non-option arguments is empty, this method returns {@code
+ * null}. If not empty, it returns a comma-separated String of all non-option
+ * arguments. Otherwise delegates to and returns the result of the abstract {@link
+ * #getOptionValues(String)} method.
+ */
+ @Override
+ public final String getProperty(String key) {
+ if (this.nonOptionArgsPropertyName.equals(key)) {
+ Collection nonOptionArguments = this.getNonOptionArgs();
+ if (nonOptionArguments.isEmpty()) {
+ return null;
+ }
+ else {
+ return StringUtils.collectionToCommaDelimitedString(nonOptionArguments);
+ }
+ }
+ Collection optionValues = this.getOptionValues(key);
+ if (optionValues == null) {
+ return null;
+ }
+ else {
+ return StringUtils.collectionToCommaDelimitedString(optionValues);
+ }
+ }
+
+ /**
+ * Return whether the set of option arguments parsed from the command line contains
+ * an option with the given name.
+ */
+ protected abstract boolean containsOption(String name);
+
+ /**
+ * Return the collection of values associated with the command line option having the
+ * given name.
+ *
+ * - if the option is present and has no argument (e.g.: "--foo"), return an empty
+ * collection ({@code []})
+ * - if the option is present and has a single value (e.g. "--foo=bar"), return a
+ * collection having one element ({@code ["bar"]})
+ * - if the option is present and the underlying command line parsing library
+ * supports multiple arguments (e.g. "--foo=bar --foo=baz"), return a collection
+ * having elements for each value ({@code ["bar", "baz"]})
+ * - if the option is not present, return {@code null}
+ *
+ */
+ protected abstract List getOptionValues(String name);
+
+ /**
+ * Return the collection of non-option arguments parsed from the command line. Never
+ * {@code null}.
+ */
+ protected abstract List getNonOptionArgs();
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/JOptCommandLinePropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/JOptCommandLinePropertySource.java
new file mode 100644
index 00000000000..48fa996c2b1
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/env/JOptCommandLinePropertySource.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import joptsimple.OptionSet;
+
+/**
+ * {@link CommandLinePropertySource} implementation backed by a JOpt {@link OptionSet}.
+ *
+ * Typical usage
+ * Configure and execute an {@code OptionParser} against the {@code String[]} of arguments
+ * supplied to the {@code main} method, and create a {@link JOptCommandLinePropertySource}
+ * using the resulting {@code OptionSet} object:
+ *
+ * public static void main(String[] args) {
+ * OptionParser parser = new OptionParser();
+ * parser.accepts("option1");
+ * parser.accepts("option2").withRequiredArg();
+ * OptionSet options = parser.parse(args);
+ * PropertySource> ps = new JOptCommandLinePropertySource(options);
+ * // ...
+ * }
+ *
+ * See {@link CommandLinePropertySource} for complete general usage examples.
+ *
+ * Requirements
+ *
+ * Use of this class requires adding the jopt-simple JAR to your application classpath.
+ * Versions 3.0 and better are supported.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ * @see CommandLinePropertySource
+ * @see joptsimple.OptionParser
+ * @see joptsimple.OptionSet
+ */
+public class JOptCommandLinePropertySource extends CommandLinePropertySource {
+
+ /**
+ * Create a new {@code JOptCommandLinePropertySource} having the default name
+ * and backed by the given {@code OptionSet}.
+ * @see CommandLinePropertySource#DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME
+ * @see CommandLinePropertySource#CommandLinePropertySource(Object)
+ */
+ public JOptCommandLinePropertySource(OptionSet options) {
+ super(options);
+ }
+
+ /**
+ * Create a new {@code JOptCommandLinePropertySource} having the given name
+ * and backed by the given {@code OptionSet}.
+ */
+ public JOptCommandLinePropertySource(String name, OptionSet options) {
+ super(name, options);
+ }
+
+ @Override
+ protected boolean containsOption(String key) {
+ return this.source.has(key);
+ }
+
+ @Override
+ public List getOptionValues(String key) {
+ List> argValues = this.source.valuesOf(key);
+ List stringArgValues = new ArrayList();
+ for(Object argValue : argValues) {
+ if (!(argValue instanceof String)) {
+ throw new IllegalArgumentException("argument values must be of type String");
+ }
+ stringArgValues.add((String)argValue);
+ }
+ if (stringArgValues.size() == 0) {
+ if (this.source.has(key)) {
+ return Collections.emptyList();
+ }
+ else {
+ return null;
+ }
+ }
+ return Collections.unmodifiableList(stringArgValues);
+ }
+
+ @Override
+ protected List getNonOptionArgs() {
+ return this.source.nonOptionArguments();
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java b/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java
new file mode 100644
index 00000000000..d0e21979987
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+/**
+ * Parses a {@code String[]} of command line arguments in order to populate a
+ * {@link CommandLineArgs} object.
+ *
+ * Working with option arguments
+ * Option arguments must adhere to the exact syntax:
+ * --optName[=optValue]
+ * That is, options must be prefixed with "{@code --}", and may or may not specify a value.
+ * If a value is specified, the name and value must be separated without spaces
+ * by an equals sign ("=").
+ *
+ * Valid examples of option arguments
+ *
+ * --foo
+ * --foo=bar
+ * --foo="bar then baz"
+ * --foo=bar,baz,biz
+ *
+ * Invalid examples of option arguments
+ *
+ * -foo
+ * --foo bar
+ * --foo = bar
+ * --foo=bar --foo=baz --foo=biz
+ *
+ * Working with non-option arguments
+ * Any and all arguments specified at the command line without the "{@code --}" option
+ * prefix will be considered as "non-option arguments" and made available through the
+ * {@link CommandLineArgs#getNonOptionArgs()} method.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ */
+class SimpleCommandLineArgsParser {
+
+ /**
+ * Parse the given {@code String} array based on the rules described {@linkplain
+ * SimpleCommandLineArgsParser above}, returning a fully-populated
+ * {@link CommandLineArgs} object.
+ * @param args command line arguments, typically from a {@code main()} method
+ */
+ public CommandLineArgs parse(String... args) {
+ CommandLineArgs commandLineArgs = new CommandLineArgs();
+ for (String arg : args) {
+ if (arg.startsWith("--")) {
+ String optionText = arg.substring(2, arg.length());
+ String optionName;
+ String optionValue = null;
+ if (optionText.contains("=")) {
+ optionName = optionText.substring(0, optionText.indexOf("="));
+ optionValue = optionText.substring(optionText.indexOf("=")+1, optionText.length());
+ }
+ else {
+ optionName = optionText;
+ }
+ if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
+ throw new IllegalArgumentException("Invalid argument syntax: " + arg);
+ }
+ commandLineArgs.addOptionArg(optionName, optionValue);
+ }
+ else {
+ commandLineArgs.addNonOptionArg(arg);
+ }
+ }
+ return commandLineArgs;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java b/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java
new file mode 100644
index 00000000000..17a1d36e7d1
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/env/SimpleCommandLinePropertySource.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import java.util.List;
+
+/**
+ * {@link CommandLinePropertySource} implementation backed by a simple String array.
+ *
+ * Purpose
+ * This {@code CommandLinePropertySource} implementation aims to provide the simplest
+ * possible approach to parsing command line arguments. As with all {@code
+ * CommandLinePropertySource} implementations, command line arguments are broken into two
+ * distinct groups: option arguments and non-option arguments, as
+ * described below (some sections copied from Javadoc for {@link SimpleCommandLineArgsParser}):
+ *
+ * Working with option arguments
+ * Option arguments must adhere to the exact syntax:
+ * --optName[=optValue]
+ * That is, options must be prefixed with "{@code --}", and may or may not specify a value.
+ * If a value is specified, the name and value must be separated without spaces
+ * by an equals sign ("=").
+ *
+ * Valid examples of option arguments
+ *
+ * --foo
+ * --foo=bar
+ * --foo="bar then baz"
+ * --foo=bar,baz,biz
+ *
+ * Invalid examples of option arguments
+ *
+ * -foo
+ * --foo bar
+ * --foo = bar
+ * --foo=bar --foo=baz --foo=biz
+ *
+ * Working with non-option arguments
+ * Any and all arguments specified at the command line without the "{@code --}" option
+ * prefix will be considered as "non-option arguments" and made available through the
+ * {@link #getNonOptionArgs()} method.
+ *
+ * Typical usage
+ *
+ * public static void main(String[] args) {
+ * PropertySource> ps = new SimpleCommandLinePropertySource(args);
+ * // ...
+ * }
+ *
+ * See {@link CommandLinePropertySource} for complete general usage examples.
+ *
+ * Beyond the basics
+ *
+ * When more fully-featured command line parsing is necessary, consider using
+ * the provided {@link JOptCommandLinePropertySource}, or implement your own
+ * {@code CommandLinePropertySource} against the command line parsing library of your
+ * choice!
+ *
+ * @author Chris Beams
+ * @since 3.1
+ * @see CommandLinePropertySource
+ * @see JOptCommandLinePropertySource
+ */
+public class SimpleCommandLinePropertySource extends CommandLinePropertySource {
+
+ /**
+ * Create a new {@code SimpleCommandLinePropertySource} having the default name
+ * and backed by the given {@code String[]} of command line arguments.
+ * @see CommandLinePropertySource#DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME
+ * @see CommandLinePropertySource#CommandLinePropertySource(Object)
+ */
+ public SimpleCommandLinePropertySource(String... args) {
+ super(new SimpleCommandLineArgsParser().parse(args));
+ }
+
+ /**
+ * Create a new {@code SimpleCommandLinePropertySource} having the given name
+ * and backed by the given {@code String[]} of command line arguments.
+ */
+ public SimpleCommandLinePropertySource(String name, String[] args) {
+ super(name, new SimpleCommandLineArgsParser().parse(args));
+ }
+
+ @Override
+ protected boolean containsOption(String key) {
+ return this.source.containsOption(key);
+ }
+
+ @Override
+ protected List getOptionValues(String key) {
+ return this.source.getOptionValues(key);
+ }
+
+ @Override
+ protected List getNonOptionArgs() {
+ return this.source.getNonOptionArgs();
+ }
+
+}
diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java
new file mode 100644
index 00000000000..6eced35d0d5
--- /dev/null
+++ b/org.springframework.core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link JOptCommandLinePropertySource}.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ */
+public class JOptCommandLinePropertySourceTests {
+
+ @Test
+ public void withRequiredArg_andArgIsPresent() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("foo").withRequiredArg();
+ OptionSet options = parser.parse("--foo=bar");
+
+ PropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertThat((String)ps.getProperty("foo"), equalTo("bar"));
+ }
+
+ @Test
+ public void withOptionalArg_andArgIsMissing() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("foo").withOptionalArg();
+ OptionSet options = parser.parse("--foo");
+
+ PropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertThat(ps.containsProperty("foo"), is(true));
+ assertThat((String)ps.getProperty("foo"), equalTo(""));
+ }
+
+ @Test
+ public void withNoArg() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("o1");
+ parser.accepts("o2");
+ OptionSet options = parser.parse("--o1");
+
+ PropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(false));
+ assertThat((String)ps.getProperty("o1"), equalTo(""));
+ assertThat(ps.getProperty("o2"), nullValue());
+ }
+
+ @Test
+ public void withRequiredArg_andMultipleArgsPresent_usingDelimiter() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(',');
+ OptionSet options = parser.parse("--foo=bar,baz,biz");
+
+ CommandLinePropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertEquals(Arrays.asList("bar","baz","biz"), ps.getOptionValues("foo"));
+ assertThat(ps.getProperty("foo"), equalTo("bar,baz,biz"));
+ }
+
+ @Test
+ public void withRequiredArg_andMultipleArgsPresent_usingRepeatedOption() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(',');
+ OptionSet options = parser.parse("--foo=bar", "--foo=baz", "--foo=biz");
+
+ CommandLinePropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertEquals(Arrays.asList("bar","baz","biz"), ps.getOptionValues("foo"));
+ assertThat(ps.getProperty("foo"), equalTo("bar,baz,biz"));
+ }
+
+ @Test
+ public void withMissingOption() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(',');
+ OptionSet options = parser.parse(); // <-- no options whatsoever
+
+ PropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertThat(ps.getProperty("foo"), nullValue());
+ }
+
+ @Test
+ public void withDottedOptionName() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("spring.profiles.active").withRequiredArg();
+ OptionSet options = parser.parse("--spring.profiles.active=p1");
+
+ CommandLinePropertySource> ps = new JOptCommandLinePropertySource(options);
+ assertThat(ps.getProperty("spring.profiles.active"), equalTo("p1"));
+ }
+
+ @Test
+ public void withDefaultNonOptionArgsNameAndNoNonOptionArgsPresent() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("o1").withRequiredArg();
+ parser.accepts("o2");
+ OptionSet optionSet = parser.parse("--o1=v1", "--o2");
+ PropertySource> ps = new JOptCommandLinePropertySource(optionSet);
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.getProperty("nonOptionArgs"), nullValue());
+ }
+
+ @Test
+ public void withDefaultNonOptionArgsNameAndNonOptionArgsPresent() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("o1").withRequiredArg();
+ parser.accepts("o2");
+ OptionSet optionSet = parser.parse("--o1=v1", "noa1", "--o2", "noa2");
+ PropertySource> ps = new JOptCommandLinePropertySource(optionSet);
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(true));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+
+ String nonOptionArgs = (String)ps.getProperty("nonOptionArgs");
+ assertThat(nonOptionArgs, equalTo("noa1,noa2"));
+ }
+
+ @Test
+ public void withCustomNonOptionArgsNameAndNoNonOptionArgsPresent() {
+ OptionParser parser = new OptionParser();
+ parser.accepts("o1").withRequiredArg();
+ parser.accepts("o2");
+ OptionSet optionSet = parser.parse("--o1=v1", "noa1", "--o2", "noa2");
+ CommandLinePropertySource> ps = new JOptCommandLinePropertySource(optionSet);
+ ps.setNonOptionArgsPropertyName("NOA");
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.containsProperty("NOA"), is(true));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+ String nonOptionArgs = ps.getProperty("NOA");
+ assertThat(nonOptionArgs, equalTo("noa1,noa2"));
+ }
+}
diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java
new file mode 100644
index 00000000000..08111c70e56
--- /dev/null
+++ b/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+public class SimpleCommandLineParserTests {
+
+ @Test
+ public void withNoOptions() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ assertThat(parser.parse().getOptionValues("foo"), nullValue());
+ }
+
+ @Test
+ public void withSingleOptionAndNoValue() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ CommandLineArgs args = parser.parse("--o1");
+ assertThat(args.containsOption("o1"), is(true));
+ assertThat(args.getOptionValues("o1"), equalTo(Collections.EMPTY_LIST));
+ }
+
+ @Test
+ public void withSingleOptionAndValue() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ CommandLineArgs args = parser.parse("--o1=v1");
+ assertThat(args.containsOption("o1"), is(true));
+ assertThat(args.getOptionValues("o1").get(0), equalTo("v1"));
+ }
+
+ @Test
+ public void withMixOfOptionsHavingValueAndOptionsHavingNoValue() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ CommandLineArgs args = parser.parse("--o1=v1", "--o2");
+ assertThat(args.containsOption("o1"), is(true));
+ assertThat(args.containsOption("o2"), is(true));
+ assertThat(args.containsOption("o3"), is(false));
+ assertThat(args.getOptionValues("o1").get(0), equalTo("v1"));
+ assertThat(args.getOptionValues("o2"), equalTo(Collections.EMPTY_LIST));
+ assertThat(args.getOptionValues("o3"), nullValue());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void withEmptyOptionText() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ parser.parse("--");
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void withEmptyOptionName() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ parser.parse("--=v1");
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void withEmptyOptionValue() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ parser.parse("--o1=");
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void withEmptyOptionNameAndEmptyOptionValue() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ parser.parse("--=");
+ }
+
+ @Test
+ public void withNonOptionArguments() {
+ SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser();
+ CommandLineArgs args = parser.parse("--o1=v1", "noa1", "--o2=v2", "noa2");
+ assertThat(args.getOptionValues("o1").get(0), equalTo("v1"));
+ assertThat(args.getOptionValues("o2").get(0), equalTo("v2"));
+
+ List nonOptions = args.getNonOptionArgs();
+ assertThat(nonOptions.get(0), equalTo("noa1"));
+ assertThat(nonOptions.get(1), equalTo("noa2"));
+ assertThat(nonOptions.size(), equalTo(2));
+ }
+
+ @Test(expected=UnsupportedOperationException.class)
+ public void assertOptionNamesIsUnmodifiable() {
+ CommandLineArgs args = new SimpleCommandLineArgsParser().parse();
+ args.getOptionNames().add("bogus");
+ }
+
+ @Test(expected=UnsupportedOperationException.class)
+ public void assertNonOptionArgsIsUnmodifiable() {
+ CommandLineArgs args = new SimpleCommandLineArgsParser().parse();
+ args.getNonOptionArgs().add("foo");
+ }
+
+}
diff --git a/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java b/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java
new file mode 100644
index 00000000000..79b502946ec
--- /dev/null
+++ b/org.springframework.core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed 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.springframework.core.env;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link SimpleCommandLinePropertySource}.
+ *
+ * @author Chris Beams
+ * @since 3.1
+ */
+public class SimpleCommandLinePropertySourceTests {
+
+ @Test
+ public void withDefaultName() {
+ PropertySource> ps = new SimpleCommandLinePropertySource();
+ assertThat(ps.getName(),
+ equalTo(CommandLinePropertySource.DEFAULT_COMMAND_LINE_PROPERTY_SOURCE_NAME));
+ }
+
+ @Test
+ public void withCustomName() {
+ PropertySource> ps = new SimpleCommandLinePropertySource("ps1", new String[0]);
+ assertThat(ps.getName(), equalTo("ps1"));
+ }
+
+ @Test
+ public void withNoArgs() {
+ PropertySource> ps = new SimpleCommandLinePropertySource();
+ assertThat(ps.containsProperty("foo"), is(false));
+ assertThat(ps.getProperty("foo"), nullValue());
+ }
+
+ @Test
+ public void withOptionArgsOnly() {
+ CommandLinePropertySource> ps =
+ new SimpleCommandLinePropertySource("--o1=v1", "--o2");
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+ assertThat(ps.containsProperty("o3"), is(false));
+ assertThat(ps.getProperty("o1"), equalTo("v1"));
+ assertThat(ps.getProperty("o2"), equalTo(""));
+ assertThat(ps.getProperty("o3"), nullValue());
+ }
+
+ @Test
+ public void withDefaultNonOptionArgsNameAndNoNonOptionArgsPresent() {
+ PropertySource> ps = new SimpleCommandLinePropertySource("--o1=v1", "--o2");
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.getProperty("nonOptionArgs"), nullValue());
+ }
+
+ @Test
+ public void withDefaultNonOptionArgsNameAndNonOptionArgsPresent() {
+ CommandLinePropertySource> ps =
+ new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2");
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(true));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+
+ String nonOptionArgs = ps.getProperty("nonOptionArgs");
+ assertThat(nonOptionArgs, equalTo("noa1,noa2"));
+ }
+
+ @Test
+ public void withCustomNonOptionArgsNameAndNoNonOptionArgsPresent() {
+ CommandLinePropertySource> ps =
+ new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2");
+ ps.setNonOptionArgsPropertyName("NOA");
+
+ assertThat(ps.containsProperty("nonOptionArgs"), is(false));
+ assertThat(ps.containsProperty("NOA"), is(true));
+ assertThat(ps.containsProperty("o1"), is(true));
+ assertThat(ps.containsProperty("o2"), is(true));
+ String nonOptionArgs = ps.getProperty("NOA");
+ assertThat(nonOptionArgs, equalTo("noa1,noa2"));
+ }
+
+ @Test
+ public void covertNonOptionArgsToStringArrayAndList() {
+ CommandLinePropertySource> ps =
+ new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2");
+ StandardEnvironment env = new StandardEnvironment();
+ env.getPropertySources().addFirst(ps);
+
+ String nonOptionArgs = env.getProperty("nonOptionArgs");
+ assertThat(nonOptionArgs, equalTo("noa1,noa2"));
+
+ String[] nonOptionArgsArray = env.getProperty("nonOptionArgs", String[].class);
+ assertThat(nonOptionArgsArray[0], equalTo("noa1"));
+ assertThat(nonOptionArgsArray[1], equalTo("noa2"));
+
+ @SuppressWarnings("unchecked")
+ List nonOptionArgsList = env.getProperty("nonOptionArgs", List.class);
+ assertThat(nonOptionArgsList.get(0), equalTo("noa1"));
+ assertThat(nonOptionArgsList.get(1), equalTo("noa2"));
+ }
+}
diff --git a/org.springframework.core/template.mf b/org.springframework.core/template.mf
index 3197d0d629a..d964ac37f4f 100644
--- a/org.springframework.core/template.mf
+++ b/org.springframework.core/template.mf
@@ -11,6 +11,7 @@ Import-Template:
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.springframework.asm.*;version=${spring.osgi.range};resolution:=optional,
org.apache.log4j.*;version="[1.2.15, 2.0.0)";resolution:=optional,
+ joptsimple.*;version="[3.0.0, 4.0.0)";resolution:=optional,
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
org.xml.sax.*;version="0";resolution:=optional,
org.w3c.dom.*;version="0";resolution:=optional