You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@reef.apache.org by we...@apache.org on 2015/01/23 00:46:48 UTC
[15/51] [partial] incubator-reef git commit: [REEF-93] Move java
sources to lang/java
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/NameResolutionException.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/NameResolutionException.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/NameResolutionException.java
new file mode 100644
index 0000000..e40ab94
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/NameResolutionException.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.exceptions;
+
+/**
+ * Thrown when Tang encounters an unknown (to the current classloader) class
+ * or configuration option. NameResolutionExceptions can only be encountered
+ * if:
+ * <ol>
+ * <li> Tang is processing a configuration file from an external source </li>
+ * <li> Classes / NamedParameters are passed to Tang in String form </li>
+ * <li> Class objects are passed directly to Tang, but it is using a different
+ * classloader than the calling code.</li>
+ * <li> Tang is processing Configurations using a ClassHierarchy produced by
+ * another process </li>
+ * </ol>
+ */
+public class NameResolutionException extends BindException {
+ private static final long serialVersionUID = 1L;
+
+ public NameResolutionException(String name, String longestPrefix) {
+ super("Could not resolve " + name + ". Search ended at prefix " + longestPrefix + " This can happen due to typos in class names that are passed as strings, or because Tang is configured to use a classloader other than the one that generated the class reference (check your classpath and the code that instantiated Tang)");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/ParseException.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/ParseException.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/ParseException.java
new file mode 100644
index 0000000..8c22e81
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/ParseException.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.exceptions;
+
+/**
+ * Thrown when a string fails to parse as the requested type.
+ *
+ * @see ParameterParser for more information about string parsing.
+ */
+public class ParseException extends BindException {
+ private static final long serialVersionUID = 1L;
+
+ public ParseException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public ParseException(String msg) {
+ super(msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/package-info.java
new file mode 100644
index 0000000..0fca070
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/exceptions/package-info.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+/**
+ * Exceptions thrown by Tang, including runtime exceptions that reflect
+ * compile-time inconsistencies and other problems that can't be
+ * meaningfully handled by application code. The non-runtime exceptions
+ * in this package are thrown when an incorrect configuration file, or
+ * other post-compilation problems are detected.
+ *
+ */
+package org.apache.reef.tang.exceptions;
+
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/AvroConfigurationSerializer.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/AvroConfigurationSerializer.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/AvroConfigurationSerializer.java
new file mode 100644
index 0000000..98f455a
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/AvroConfigurationSerializer.java
@@ -0,0 +1,313 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.avro.file.DataFileReader;
+import org.apache.avro.file.DataFileWriter;
+import org.apache.avro.io.*;
+import org.apache.avro.specific.SpecificDatumReader;
+import org.apache.avro.specific.SpecificDatumWriter;
+import org.apache.commons.lang.StringUtils;
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.ConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.formats.avro.AvroConfiguration;
+import org.apache.reef.tang.formats.avro.ConfigurationEntry;
+import org.apache.reef.tang.implementation.ConfigurationBuilderImpl;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.ReflectionUtilities;
+
+import javax.inject.Inject;
+import java.io.*;
+import java.util.*;
+
+/**
+ * (De-)Serializing Configuration to and from AvroConfiguration.
+ * <p/>
+ * This class is stateless and is therefore safe to reuse.
+ */
+public final class AvroConfigurationSerializer implements ConfigurationSerializer {
+
+ /**
+ * The Charset used for the JSON encoding.
+ * <p/>
+ * Copied from <code>org.apache.avro.io.JsonDecoder.CHARSET</code>
+ */
+ private static final String JSON_CHARSET = "ISO-8859-1";
+
+ @Inject
+ public AvroConfigurationSerializer() {
+ }
+
+ private static void fromAvro(final AvroConfiguration avroConfiguration, final ConfigurationBuilder configurationBuilder) throws BindException {
+ // Note: This code is an adapted version of ConfigurationFile.processConfigFile();
+ // TODO: This method should implement list deserialization. Implement it when C# side is ready.
+ final Map<String, String> importedNames = new HashMap<>();
+
+ for (final ConfigurationEntry entry : avroConfiguration.getBindings()) {
+
+ final String longName = importedNames.get(entry.getKey().toString());
+ final String key;
+ if (null == longName) {
+ key = entry.getKey().toString();
+ } else {
+ key = longName;
+ }
+
+ // entry.getValue()'s type can be either string or array of string
+ final Object rawValue = entry.getValue();
+
+ try {
+ // TODO: Implement list deserialization
+ // rawValue is String.
+ String value = rawValue.toString();
+ if (key.equals(ConfigurationBuilderImpl.IMPORT)) {
+ configurationBuilder.getClassHierarchy().getNode(value);
+ final String[] tok = value.split(ReflectionUtilities.regexp);
+ final String lastTok = tok[tok.length - 1];
+ try {
+ configurationBuilder.getClassHierarchy().getNode(lastTok);
+ throw new IllegalArgumentException("Conflict on short name: " + lastTok);
+ } catch (final BindException e) {
+ final String oldValue = importedNames.put(lastTok, value);
+ if (oldValue != null) {
+ throw new IllegalArgumentException("Name conflict: "
+ + lastTok + " maps to " + oldValue + " and " + value);
+ }
+ }
+ } else if (value.startsWith(ConfigurationBuilderImpl.INIT)) {
+ final String[] classes = value.substring(ConfigurationBuilderImpl.INIT.length(), value.length())
+ .replaceAll("^[\\s\\(]+", "")
+ .replaceAll("[\\s\\)]+$", "")
+ .split("[\\s\\-]+");
+ configurationBuilder.registerLegacyConstructor(key, classes);
+ } else {
+ configurationBuilder.bind(key, value);
+ }
+ } catch (final BindException | ClassHierarchyException e) {
+ throw new BindException("Failed to process configuration tuple: [" + key + "=" + rawValue + "]", e);
+ }
+ }
+ }
+
+ private static AvroConfiguration avroFromFile(final File file) throws IOException {
+ final AvroConfiguration avroConfiguration;
+ try (final DataFileReader<AvroConfiguration> dataFileReader =
+ new DataFileReader<>(file, new SpecificDatumReader<>(AvroConfiguration.class))) {
+ avroConfiguration = dataFileReader.next();
+ }
+ return avroConfiguration;
+ }
+
+ private static AvroConfiguration avroFromBytes(final byte[] theBytes) throws IOException {
+ final BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(theBytes, null);
+ final SpecificDatumReader<AvroConfiguration> reader = new SpecificDatumReader<>(AvroConfiguration.class);
+ return reader.read(null, decoder);
+ }
+
+ private static AvroConfiguration avroFromString(final String theString) throws IOException {
+ final JsonDecoder decoder = DecoderFactory.get().jsonDecoder(AvroConfiguration.getClassSchema(), theString);
+ final SpecificDatumReader<AvroConfiguration> reader = new SpecificDatumReader<>(AvroConfiguration.class);
+ return reader.read(null, decoder);
+ }
+
+ public AvroConfiguration toAvro(final Configuration configuration) {
+ // Note: This code is an adapted version of ConfiurationFile.toConfigurationStringList();
+ // TODO: This method should implement list serialization. Implement it when C# side is ready.
+
+ final List<ConfigurationEntry> configurationEntries = new ArrayList<>();
+
+ for (final ClassNode<?> opt : configuration.getBoundImplementations()) {
+ configurationEntries.add(new ConfigurationEntry().newBuilder()
+ .setKey(opt.getFullName())
+ .setValue(configuration.getBoundImplementation(opt).getFullName())
+ .build());
+ }
+
+ for (final ClassNode<?> opt : configuration.getBoundConstructors()) {
+ configurationEntries.add(new ConfigurationEntry().newBuilder()
+ .setKey(opt.getFullName())
+ .setValue(configuration.getBoundConstructor(opt).getFullName())
+ .build());
+ }
+ for (final NamedParameterNode<?> opt : configuration.getNamedParameters()) {
+ configurationEntries.add(new ConfigurationEntry().newBuilder()
+ .setKey(opt.getFullName())
+ .setValue(configuration.getNamedParameter(opt))
+ .build());
+ }
+ for (final ClassNode<?> cn : configuration.getLegacyConstructors()) {
+ final String legacyConstructors = StringUtils.join(configuration.getLegacyConstructor(cn).getArgs(), "-");
+ configurationEntries.add(new ConfigurationEntry().newBuilder()
+ .setKey(cn.getFullName())
+ .setValue("" + ConfigurationBuilderImpl.INIT + "(" + legacyConstructors + ")")
+ .build());
+ }
+ for (final Map.Entry<NamedParameterNode<Set<?>>, Object> e : configuration.getBoundSets()) {
+ final String val;
+ if (e.getValue() instanceof String) {
+ val = (String) e.getValue();
+ } else if (e.getValue() instanceof Node) {
+ val = ((Node) e.getValue()).getFullName();
+ } else {
+ throw new IllegalStateException();
+ }
+ configurationEntries.add(new ConfigurationEntry().newBuilder()
+ .setKey(e.getKey().getFullName())
+ .setValue(val)
+ .build());
+ }
+ // TODO: Implement list serialization
+
+ return AvroConfiguration.newBuilder().setBindings(configurationEntries).build();
+ }
+
+ @Override
+ public void toFile(final Configuration conf, final File file) throws IOException {
+ final AvroConfiguration avroConfiguration = toAvro(conf);
+ final DatumWriter<AvroConfiguration> configurationWriter = new SpecificDatumWriter<>(AvroConfiguration.class);
+ try (DataFileWriter<AvroConfiguration> dataFileWriter = new DataFileWriter<>(configurationWriter)) {
+ dataFileWriter.create(avroConfiguration.getSchema(), file);
+ dataFileWriter.append(avroConfiguration);
+ }
+ }
+
+ @Override
+ public void toTextFile(final Configuration conf, final File file) throws IOException {
+ try (final Writer w = new FileWriter(file)) {
+ w.write(this.toString(conf));
+ }
+ }
+
+ @Override
+ public byte[] toByteArray(final Configuration conf) throws IOException {
+ final DatumWriter<AvroConfiguration> configurationWriter = new SpecificDatumWriter<>(AvroConfiguration.class);
+ final byte[] theBytes;
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ final BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
+ configurationWriter.write(toAvro(conf), encoder);
+ encoder.flush();
+ out.flush();
+ theBytes = out.toByteArray();
+ }
+ return theBytes;
+ }
+
+ @Override
+ public String toString(final Configuration configuration) {
+ final DatumWriter<AvroConfiguration> configurationWriter = new SpecificDatumWriter<>(AvroConfiguration.class);
+ final String result;
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ final JsonEncoder encoder = EncoderFactory.get().jsonEncoder(AvroConfiguration.SCHEMA$, out);
+ configurationWriter.write(toAvro(configuration), encoder);
+ encoder.flush();
+ out.flush();
+ result = out.toString(JSON_CHARSET);
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ return result;
+ }
+
+ /**
+ * Converts a given AvroConfiguration to Configuration
+ *
+ * @param avroConfiguration
+ * @return a Configuration version of the given AvroConfiguration
+ */
+ public Configuration fromAvro(final AvroConfiguration avroConfiguration) throws BindException {
+ final ConfigurationBuilder configurationBuilder = Tang.Factory.getTang().newConfigurationBuilder();
+ fromAvro(avroConfiguration, configurationBuilder);
+ return configurationBuilder.build();
+ }
+
+ /**
+ * Converts a given AvroConfiguration to Configuration
+ *
+ * @param avroConfiguration
+ * @param classHierarchy the class hierarchy used for validation.
+ * @return a Configuration version of the given AvroConfiguration
+ */
+ public Configuration fromAvro(final AvroConfiguration avroConfiguration, final ClassHierarchy classHierarchy)
+ throws BindException {
+ final ConfigurationBuilder configurationBuilder = Tang.Factory.getTang().newConfigurationBuilder(classHierarchy);
+ fromAvro(avroConfiguration, configurationBuilder);
+ return configurationBuilder.build();
+ }
+
+ @Override
+ public Configuration fromFile(final File file) throws IOException, BindException {
+ return fromAvro(avroFromFile(file));
+ }
+
+ @Override
+ public Configuration fromFile(final File file, final ClassHierarchy classHierarchy) throws IOException, BindException {
+ return fromAvro(avroFromFile(file), classHierarchy);
+ }
+
+ @Override
+ public Configuration fromTextFile(final File file) throws IOException, BindException {
+ final StringBuilder result = readFromTextFile(file);
+ return this.fromString(result.toString());
+ }
+
+ @Override
+ public Configuration fromTextFile(final File file, final ClassHierarchy classHierarchy) throws IOException, BindException {
+ final StringBuilder result = readFromTextFile(file);
+ return this.fromString(result.toString(), classHierarchy);
+ }
+
+ private StringBuilder readFromTextFile(final File file) throws IOException {
+ final StringBuilder result = new StringBuilder();
+ try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ String line = reader.readLine();
+ while (line != null) {
+ result.append(line);
+ line = reader.readLine();
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Configuration fromByteArray(final byte[] theBytes) throws IOException, BindException {
+ return fromAvro(avroFromBytes(theBytes));
+ }
+
+ @Override
+ public Configuration fromByteArray(final byte[] theBytes, final ClassHierarchy classHierarchy) throws IOException, BindException {
+ return fromAvro(avroFromBytes(theBytes), classHierarchy);
+ }
+
+ @Override
+ public Configuration fromString(final String theString) throws IOException, BindException {
+ return fromAvro(avroFromString(theString));
+ }
+
+ @Override
+ public Configuration fromString(final String theString, final ClassHierarchy classHierarchy) throws IOException, BindException {
+ return fromAvro(avroFromString(theString), classHierarchy);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/CommandLine.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/CommandLine.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/CommandLine.java
new file mode 100644
index 0000000..a299958
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/CommandLine.java
@@ -0,0 +1,218 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.commons.cli.*;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.ConfigurationBuilder;
+import org.apache.reef.tang.JavaConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.MonotonicTreeMap;
+import org.apache.reef.tang.util.ReflectionUtilities;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class CommandLine {
+
+ final Map<Option, CommandLineCallback> applicationOptions = new HashMap<>();
+ private final ConfigurationBuilder conf;
+ private final Map<String, String> shortNames = new MonotonicTreeMap<>();
+
+ public CommandLine() {
+ this.conf = Tang.Factory.getTang().newConfigurationBuilder();
+ }
+
+ public CommandLine(final ConfigurationBuilder conf) {
+ this.conf = conf;
+ }
+
+ public ConfigurationBuilder getBuilder() {
+ return this.conf;
+ }
+
+ public CommandLine registerShortNameOfClass(final String s) throws BindException {
+
+ final Node n;
+ try {
+ n = conf.getClassHierarchy().getNode(s);
+ } catch (final NameResolutionException e) {
+ throw new BindException("Problem loading class " + s, e);
+ }
+
+ if (n instanceof NamedParameterNode) {
+ final NamedParameterNode<?> np = (NamedParameterNode<?>) n;
+ final String shortName = np.getShortName();
+ final String longName = np.getFullName();
+ if (shortName == null) {
+ throw new BindException(
+ "Can't register non-existent short name of named parameter: " + longName);
+ }
+ shortNames.put(shortName, longName);
+ } else {
+ throw new BindException("Can't register short name for non-NamedParameterNode: " + n);
+ }
+
+ return this;
+ }
+
+ public CommandLine registerShortNameOfClass(
+ final Class<? extends Name<?>> c) throws BindException {
+ return registerShortNameOfClass(ReflectionUtilities.getFullName(c));
+ }
+
+ @SuppressWarnings("static-access")
+ private Options getCommandLineOptions() {
+
+ final Options opts = new Options();
+ for (final String shortName : shortNames.keySet()) {
+ final String longName = shortNames.get(shortName);
+ try {
+ opts.addOption(OptionBuilder
+ .withArgName(conf.classPrettyDefaultString(longName)).hasArg()
+ .withDescription(conf.classPrettyDescriptionString(longName))
+ .create(shortName));
+ } catch (final BindException e) {
+ throw new IllegalStateException(
+ "Could not process " + shortName + " which is the short name of " + longName, e);
+ }
+ }
+
+ for (final Option o : applicationOptions.keySet()) {
+ opts.addOption(o);
+ }
+
+ return opts;
+ }
+
+ public CommandLine addCommandLineOption(final Option option, final CommandLineCallback cb) {
+ // TODO: Check for conflicting options.
+ applicationOptions.put(option, cb);
+ return this;
+ }
+
+ /**
+ * @param args
+ * @return Selfie if the command line parsing succeeded, null (or exception) otherwise.
+ * @throws IOException
+ * @throws NumberFormatException
+ * @throws ParseException
+ */
+ @SafeVarargs
+ final public <T> CommandLine processCommandLine(
+ final String[] args, Class<? extends Name<?>>... argClasses)
+ throws IOException, BindException {
+
+ for (final Class<? extends Name<?>> c : argClasses) {
+ registerShortNameOfClass(c);
+ }
+
+ final Options o = getCommandLineOptions();
+ o.addOption(new Option("?", "help"));
+ final Parser g = new GnuParser();
+
+ final org.apache.commons.cli.CommandLine cl;
+ try {
+ cl = g.parse(o, args);
+ } catch (final ParseException e) {
+ throw new IOException("Could not parse config file", e);
+ }
+
+ if (cl.hasOption("?")) {
+ new HelpFormatter().printHelp("reef", o);
+ return null;
+ }
+
+ for (final Option option : cl.getOptions()) {
+
+ final String shortName = option.getOpt();
+ final String value = option.getValue();
+
+ if (applicationOptions.containsKey(option)) {
+ applicationOptions.get(option).process(option);
+ } else {
+ try {
+ conf.bind(shortNames.get(shortName), value);
+ } catch (final BindException e) {
+ throw new BindException("Could not bind shortName " + shortName + " to value " + value, e);
+ }
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Utility method to quickly parse a command line to a Configuration.
+ * <p/>
+ * This is equivalent to
+ * <code>parseToConfigurationBuilder(args, argClasses).build()</code>
+ *
+ * @param args the command line parameters to parse.
+ * @param argClasses the named parameters to look for.
+ * @return a Configuration with the parsed parameters
+ * @throws ParseException if the parsing of the commandline fails.
+ */
+ public static Configuration parseToConfiguration(final String[] args,
+ final Class<? extends Name<?>>... argClasses)
+ throws ParseException {
+ return parseToConfigurationBuilder(args, argClasses).build();
+ }
+
+ /**
+ * Utility method to quickly parse a command line to a ConfigurationBuilder.
+ * <p/>
+ * This is equivalent to
+ * <code>new CommandLine().processCommandLine(args, argClasses).getBuilder()</code>, but with additional checks.
+ *
+ * @param args the command line parameters to parse.
+ * @param argClasses the named parameters to look for.
+ * @return a ConfigurationBuilder with the parsed parameters
+ * @throws ParseException if the parsing of the commandline fails.
+ */
+ public static ConfigurationBuilder parseToConfigurationBuilder(final String[] args,
+ final Class<? extends Name<?>>... argClasses)
+ throws ParseException {
+ final CommandLine commandLine;
+ try {
+ commandLine = new CommandLine().processCommandLine(args, argClasses);
+ } catch (final IOException e) {
+ // processCommandLine() converts ParseException into IOException. This reverts that to make exception handling
+ // more straight forward.
+ throw new ParseException(e.getMessage());
+ }
+
+ // processCommandLine() indicates that it might return null. We need to guard users of this one from that
+ if (commandLine == null) {
+ throw new ParseException("Unable to parse the command line and the parser returned null.");
+ } else {
+ return commandLine.getBuilder();
+ }
+ }
+
+ public interface CommandLineCallback {
+ public void process(final Option option);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationFile.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationFile.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationFile.java
new file mode 100644
index 0000000..91568d1
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationFile.java
@@ -0,0 +1,253 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.ConfigurationBuilder;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.implementation.ConfigurationBuilderImpl;
+import org.apache.reef.tang.implementation.ConfigurationImpl;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.ConstructorArg;
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.ReflectionUtilities;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+@Deprecated
+public class ConfigurationFile {
+
+ /**
+ * Write Configuration to the given File.
+ *
+ * @throws IOException
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+ @Deprecated
+ public static void writeConfigurationFile(
+ final Configuration conf, final File confFile) throws IOException {
+ try (final PrintStream printStream = new PrintStream(new FileOutputStream(confFile))) {
+ printStream.print(toConfigurationString(conf));
+ }
+ }
+
+ /**
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+ @Deprecated
+ public static void addConfiguration(final ConfigurationBuilder conf,
+ final File tmpConfFile) throws IOException, BindException {
+ final PropertiesConfiguration confFile;
+ try {
+ confFile = new PropertiesConfiguration(tmpConfFile);
+ } catch (final ConfigurationException e) {
+ throw new BindException("Problem parsing config file: " + tmpConfFile, e);
+ }
+ processConfigFile(conf, confFile);
+ }
+
+ /**
+ * @param conf This configuration builder will be modified to incorporate the
+ * contents of the configuration file.
+ * @param contents A string containing the contents of the configuration file.
+ * @throws BindException
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+ @Deprecated
+ public static void addConfiguration(final ConfigurationBuilder conf,
+ final String contents) throws BindException {
+ File tmpConfFile = null;
+ try {
+ tmpConfFile = File.createTempFile("tang", "tmp");
+ try (final FileOutputStream outStream = new FileOutputStream(tmpConfFile)) {
+ outStream.write(contents.getBytes());
+ }
+ addConfiguration(conf, tmpConfFile);
+ } catch (final IOException ex) {
+ throw new BindException("Error writing config file: " + tmpConfFile, ex);
+ } finally {
+ if (tmpConfFile != null) {
+ tmpConfFile.delete();
+ }
+ }
+ }
+
+ private static void processConfigFile(ConfigurationBuilder conf,
+ PropertiesConfiguration confFile) throws IOException, BindException {
+ ConfigurationBuilderImpl ci = (ConfigurationBuilderImpl) conf;
+ Iterator<String> it = confFile.getKeys();
+ Map<String, String> importedNames = new HashMap<>();
+
+ while (it.hasNext()) {
+ String key = it.next();
+ String longName = importedNames.get(key);
+ String[] values = confFile.getStringArray(key);
+ if (longName != null) {
+ // System.err.println("Mapped " + key + " to " + longName);
+ key = longName;
+ }
+ for (String value : values) {
+ try {
+ if (key.equals(ConfigurationBuilderImpl.IMPORT)) {
+ ci.getClassHierarchy().getNode(value);
+ final String[] tok = value.split(ReflectionUtilities.regexp);
+ final String lastTok = tok[tok.length - 1];
+ try {
+ // ci.namespace.getNode(lastTok);
+ ci.getClassHierarchy().getNode(lastTok);
+ throw new IllegalArgumentException("Conflict on short name: " + lastTok);
+ } catch (BindException e) {
+ String oldValue = importedNames.put(lastTok, value);
+ if (oldValue != null) {
+ throw new IllegalArgumentException("Name conflict: "
+ + lastTok + " maps to " + oldValue + " and " + value);
+ }
+ }
+ } else if (value.startsWith(ConfigurationBuilderImpl.INIT)) {
+ String parseValue = value.substring(
+ ConfigurationBuilderImpl.INIT.length(), value.length());
+ parseValue = parseValue.replaceAll("^[\\s\\(]+", "");
+ parseValue = parseValue.replaceAll("[\\s\\)]+$", "");
+ String[] classes = parseValue.split("[\\s\\-]+");
+ ci.registerLegacyConstructor(key, classes);
+ } else {
+ ci.bind(key, value);
+ }
+ } catch (BindException e) {
+ throw new BindException("Failed to process configuration tuple: [" + key + "=" + value + "]", e);
+ } catch (ClassHierarchyException e) {
+ throw new ClassHierarchyException("Failed to process configuration tuple: [" + key + "=" + value + "]", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Replace any \'s in the input string with \\. and any "'s with \".
+ *
+ * @param in
+ * @return
+ */
+ private static String escape(String in) {
+ // After regexp escaping \\\\ = 1 slash, \\\\\\\\ = 2 slashes.
+
+ // Also, the second args of replaceAll are neither strings nor regexps, and
+ // are instead a special DSL used by Matcher. Therefore, we need to double
+ // escape slashes (4 slashes) and quotes (3 slashes + ") in those strings.
+ // Since we need to write \\ and \", we end up with 8 and 7 slashes,
+ // respectively.
+ return in.replaceAll("\\\\", "\\\\\\\\").replaceAll("\"", "\\\\\\\"");
+ }
+
+ /**
+ * Obtain the effective configuration of this ConfigurationBuilderImpl
+ * instance. This consists of string-string pairs that could be written
+ * directly to a Properties file, for example. Currently, this method does not
+ * return information about default parameter values that were specified by
+ * parameter annotations, or about the auto-discovered stuff in TypeHierarchy.
+ * All of that should be automatically imported as these keys are parsed on
+ * the other end.
+ *
+ * @return A string containing enough information to rebuild this
+ * configuration object (assuming the same classes / jars are
+ * available when the string is parsed by Tang).
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+ @Deprecated
+ public static String toConfigurationString(final Configuration c) {
+ StringBuilder sb = new StringBuilder();
+ for (String s : toConfigurationStringList(c)) {
+ sb.append(s);
+ sb.append('\n');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @deprecated in Tang 0.2 Use AvroConfigurationSerializer instead.
+ */
+ @Deprecated
+ static List<String> toConfigurationStringList(final Configuration c) {
+ ConfigurationImpl conf = (ConfigurationImpl) c;
+ List<String> l = new ArrayList<>();
+ for (ClassNode<?> opt : conf.getBoundImplementations()) {
+ l.add(opt.getFullName()
+ + '='
+ + escape(conf.getBoundImplementation(opt).getFullName()));
+ }
+ for (ClassNode<?> opt : conf.getBoundConstructors()) {
+ l.add(opt.getFullName()
+ + '='
+ + escape(conf.getBoundConstructor(opt).getFullName()));
+ }
+ for (NamedParameterNode<?> opt : conf.getNamedParameters()) {
+ l.add(opt.getFullName()
+ + '='
+ + escape(conf.getNamedParameter(opt)));
+ }
+ for (ClassNode<?> cn : conf.getLegacyConstructors()) {
+ StringBuilder sb = new StringBuilder();
+ join(sb, "-", conf.getLegacyConstructor(cn).getArgs());
+ l.add(cn.getFullName()
+ + escape('='
+ + ConfigurationBuilderImpl.INIT
+ + '('
+ + sb.toString()
+ + ')'
+ ));
+ //s.append(cn.getFullName()).append('=').append(ConfigurationBuilderImpl.INIT).append('(');
+// .append(")\n");
+ }
+ for (Entry<NamedParameterNode<Set<?>>, Object> e : conf.getBoundSets()) {
+ final String val;
+ if (e.getValue() instanceof String) {
+ val = (String) e.getValue();
+ } else if (e.getValue() instanceof Node) {
+ val = ((Node) e.getValue()).getFullName();
+ } else {
+ throw new IllegalStateException();
+ }
+ l.add(e.getKey().getFullName() + '=' + escape(val));
+// s.append(e.getKey().getFullName()).append('=').append(val).append("\n");
+ }
+ return l;//s.toString();
+ }
+
+ private static StringBuilder join(final StringBuilder sb, final String sep, final ConstructorArg[] types) {
+ if (types.length > 0) {
+ sb.append(types[0].getType());
+ for (int i = 1; i < types.length; i++) {
+ sb.append(sep).append(types[i].getType());
+ }
+ }
+ return sb;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModule.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModule.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModule.java
new file mode 100644
index 0000000..5b749ce
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModule.java
@@ -0,0 +1,299 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.util.*;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Allows applications to bundle sets of configuration options together into
+ * discrete packages. Unlike more conventional approaches,
+ * ConfigurationModules store such information in static data structures that
+ * can be statically discovered and sanity-checked.
+ *
+ * @see org.apache.reef.tang.formats.TestConfigurationModule for more information and examples.
+ */
+public class ConfigurationModule {
+ final ConfigurationModuleBuilder builder;
+ // Set of required unset parameters. Must be empty before build.
+ private final Set<Field> reqSet = new MonotonicHashSet<>();
+ private final Map<Impl<?>, Class<?>> setImpls = new MonotonicHashMap<>();
+ private final MonotonicMultiHashMap<Impl<?>, Class<?>> setImplSets = new MonotonicMultiHashMap<>();
+ private final MonotonicMultiHashMap<Impl<?>, String> setLateImplSets = new MonotonicMultiHashMap<>();
+ private final MonotonicMultiHashMap<Param<?>, String> setParamSets = new MonotonicMultiHashMap<>();
+ private final Map<Impl<?>, String> setLateImpls = new MonotonicHashMap<>();
+ private final Map<Param<?>, String> setParams = new MonotonicHashMap<>();
+ private final Map<Impl<List>, List<?>> setImplLists = new MonotonicHashMap<>();
+ private final Map<Param<List>, List<?>> setParamLists = new MonotonicHashMap<>();
+
+ protected ConfigurationModule(ConfigurationModuleBuilder builder) {
+ this.builder = builder.deepCopy();
+ }
+
+ private ConfigurationModule deepCopy() {
+ ConfigurationModule cm = new ConfigurationModule(builder.deepCopy());
+ cm.setImpls.putAll(setImpls);
+ cm.setImplSets.addAll(setImplSets);
+ cm.setLateImplSets.addAll(setLateImplSets);
+ cm.setParamSets.addAll(setParamSets);
+ cm.setLateImpls.putAll(setLateImpls);
+ cm.setParams.putAll(setParams);
+ cm.reqSet.addAll(reqSet);
+ cm.setImplLists.putAll(setImplLists);
+ cm.setParamLists.putAll(setParamLists);
+ return cm;
+ }
+
+ private final <T> void processSet(Object impl) {
+ Field f = builder.map.get(impl);
+ if (f == null) { /* throw */
+ throw new ClassHierarchyException("Unknown Impl/Param when setting " + ReflectionUtilities.getSimpleName(impl.getClass()) + ". Did you pass in a field from some other module?");
+ }
+ if (!reqSet.contains(f)) {
+ reqSet.add(f);
+ }
+ }
+
+ public final <T> ConfigurationModule set(Impl<T> opt, Class<? extends T> impl) {
+ ConfigurationModule c = deepCopy();
+ c.processSet(opt);
+ if (c.builder.setOpts.contains(opt)) {
+ c.setImplSets.put(opt, impl);
+ } else {
+ c.setImpls.put(opt, impl);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModule set(Impl<T> opt, String impl) {
+ ConfigurationModule c = deepCopy();
+ c.processSet(opt);
+ if (c.builder.setOpts.contains(opt)) {
+ c.setLateImplSets.put(opt, impl);
+ } else {
+ c.setLateImpls.put(opt, impl);
+ }
+ return c;
+ }
+
+ /**
+ * Binds a list to a specific optional/required Impl using ConfigurationModule.
+ *
+ * @param opt Target optional/required Impl
+ * @param implList List object to be injected
+ * @param <T>
+ * @return
+ */
+ public final <T> ConfigurationModule set(Impl<List> opt, List implList) {
+ ConfigurationModule c = deepCopy();
+ c.processSet(opt);
+ c.setImplLists.put(opt, implList);
+ return c;
+ }
+
+ public final <T> ConfigurationModule set(Param<T> opt, Class<? extends T> val) {
+ return set(opt, ReflectionUtilities.getFullName(val));
+ }
+
+ public final ConfigurationModule set(Param<Boolean> opt, boolean val) {
+ return set(opt, "" + val);
+ }
+
+ public final ConfigurationModule set(Param<? extends Number> opt, Number val) {
+ return set(opt, "" + val);
+ }
+
+ public final <T> ConfigurationModule set(Param<T> opt, String val) {
+ ConfigurationModule c = deepCopy();
+ c.processSet(opt);
+ if (c.builder.setOpts.contains(opt)) {
+ c.setParamSets.put(opt, val);
+ } else {
+ c.setParams.put(opt, val);
+ }
+ return c;
+ }
+
+ /**
+ * Binds a list to a specfici optional/required Param using ConfigurationModule.
+ *
+ * @param opt target optional/required Param
+ * @param implList List object to be injected
+ * @param <T>
+ * @return
+ */
+ public final <T> ConfigurationModule set(Param<List> opt, List implList) {
+ ConfigurationModule c = deepCopy();
+ c.processSet(opt);
+ c.setParamLists.put(opt, implList);
+ return c;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public Configuration build() throws BindException {
+ ConfigurationModule c = deepCopy();
+
+ if (!c.reqSet.containsAll(c.builder.reqDecl)) {
+ Set<Field> missingSet = new MonotonicHashSet<>();
+ for (Field f : c.builder.reqDecl) {
+ if (!c.reqSet.contains(f)) {
+ missingSet.add(f);
+ }
+ }
+ throw new BindException(
+ "Attempt to build configuration before setting required option(s): "
+ + builder.toString(missingSet));
+ }
+
+ for (Class<?> clazz : c.builder.freeImpls.keySet()) {
+ Impl<?> i = c.builder.freeImpls.get(clazz);
+ if (c.setImpls.containsKey(i)) {
+ c.builder.b.bind(clazz, c.setImpls.get(i));
+ } else if (c.setLateImpls.containsKey(i)) {
+ c.builder.b.bind(ReflectionUtilities.getFullName(clazz), c.setLateImpls.get(i));
+ } else if (c.setImplSets.containsKey(i) || c.setLateImplSets.containsKey(i)) {
+ for (Class<?> clz : c.setImplSets.getValuesForKey(i)) {
+ c.builder.b.bindSetEntry((Class) clazz, (Class) clz);
+ }
+ for (String s : c.setLateImplSets.getValuesForKey(i)) {
+ c.builder.b.bindSetEntry((Class) clazz, s);
+ }
+ } else if (c.setImplLists.containsKey(i)) {
+ c.builder.b.bindList((Class) clazz, c.setImplLists.get(i));
+ }
+ }
+ for (Class<? extends Name<?>> clazz : c.builder.freeParams.keySet()) {
+ Param<?> p = c.builder.freeParams.get(clazz);
+ String s = c.setParams.get(p);
+ boolean foundOne = false;
+ if (s != null) {
+ c.builder.b.bindNamedParameter(clazz, s);
+ foundOne = true;
+ }
+ // Find the bound list for the NamedParameter
+ List list = c.setParamLists.get(p);
+ if (list != null) {
+ c.builder.b.bindList((Class) clazz, list);
+ foundOne = true;
+ }
+ for (String paramStr : c.setParamSets.getValuesForKey(p)) {
+ c.builder.b.bindSetEntry((Class) clazz, paramStr);
+ foundOne = true;
+ }
+ if (!foundOne) {
+ if (!(p instanceof OptionalParameter)) {
+ throw new IllegalStateException();
+ }
+ }
+ }
+ return c.builder.b.build();
+
+ }
+
+ public Set<NamedParameterNode<?>> getBoundNamedParameters() {
+ Configuration c = this.builder.b.build();
+ Set<NamedParameterNode<?>> nps = new MonotonicSet<>();
+ nps.addAll(c.getNamedParameters());
+ for (Class<?> np : this.builder.freeParams.keySet()) {
+ try {
+ nps.add((NamedParameterNode<?>) builder.b.getClassHierarchy().getNode(ReflectionUtilities.getFullName(np)));
+ } catch (NameResolutionException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ return nps;
+ }
+
+ public List<Entry<String, String>> toStringPairs() {
+ List<Entry<String, String>> ret = new ArrayList<>();
+ class MyEntry implements Entry<String, String> {
+ final String k;
+ final String v;
+
+ public MyEntry(String k, String v) {
+ this.k = k;
+ this.v = v;
+ }
+
+ @Override
+ public String getKey() {
+ return k;
+ }
+
+ @Override
+ public String getValue() {
+ return v;
+ }
+
+ @Override
+ public String setValue(String value) {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+ for (Class<?> c : this.builder.freeParams.keySet()) {
+ ret.add(new MyEntry(ReflectionUtilities.getFullName(c), this.builder.map.get(this.builder.freeParams.get(c)).getName()));
+ }
+ for (Class<?> c : this.builder.freeImpls.keySet()) {
+ ret.add(new MyEntry(ReflectionUtilities.getFullName(c), this.builder.map.get(this.builder.freeImpls.get(c)).getName()));
+ }
+ for (String s : ConfigurationFile.toConfigurationStringList(builder.b.build())) {
+ String[] tok = s.split("=", 2);
+ ret.add(new MyEntry(tok[0], tok[1]));
+ }
+
+ return ret;
+ }
+
+ public String toPrettyString() {
+ StringBuilder sb = new StringBuilder();
+
+ for (Entry<String, String> l : toStringPairs()) {
+ sb.append(l.getKey() + "=" + l.getValue() + "\n");
+ }
+ return sb.toString();
+ }
+
+ public void assertStaticClean() throws ClassHierarchyException {
+ if (!(
+ setImpls.isEmpty() &&
+ setImplSets.isEmpty() &&
+ setLateImplSets.isEmpty() &&
+ setParamSets.isEmpty() &&
+ setLateImpls.isEmpty() &&
+ setParams.isEmpty() &&
+ setImplLists.isEmpty() &&
+ setParamLists.isEmpty()
+ )) {
+ throw new ClassHierarchyException("Detected statically set ConfigurationModule Parameter / Implementation. set() should only be used dynamically. Use bind...() instead.");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModuleBuilder.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModuleBuilder.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModuleBuilder.java
new file mode 100644
index 0000000..38359c0
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationModuleBuilder.java
@@ -0,0 +1,385 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ExternalConstructor;
+import org.apache.reef.tang.JavaConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+import org.apache.reef.tang.util.MonotonicHashMap;
+import org.apache.reef.tang.util.MonotonicHashSet;
+import org.apache.reef.tang.util.ReflectionUtilities;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class ConfigurationModuleBuilder {
+
+ private final static Set<Class<?>> paramBlacklist = new MonotonicHashSet<Class<?>>(
+ Param.class, Impl.class);
+ private final static Set<Class<?>> paramTypes = new MonotonicHashSet<Class<?>>(
+ RequiredImpl.class, OptionalImpl.class, RequiredParameter.class,
+ OptionalParameter.class);
+ final JavaConfigurationBuilder b = Tang.Factory.getTang()
+ .newConfigurationBuilder();
+ // Sets of things that have been declared
+ final Set<Field> reqDecl = new MonotonicHashSet<>();
+ final Set<Object> setOpts = new MonotonicHashSet<>();
+ // Maps from field instance variables to the fields that they
+ // are assigned to. These better be unique!
+ final Map<Object, Field> map = new MonotonicHashMap<>();
+ final Map<Class<?>, Impl<?>> freeImpls = new MonotonicHashMap<>();
+ final Map<Class<? extends Name<?>>, Param<?>> freeParams = new MonotonicHashMap<>();
+ private final Set<Field> optDecl = new MonotonicHashSet<>();
+ // Set of things that have been used in a bind. These must be equal
+ // to the decl counterparts before build() is called.
+ private final Set<Field> reqUsed = new MonotonicHashSet<>();
+ private final Set<Field> optUsed = new MonotonicHashSet<>();
+ private final Map<Class<?>, String> lateBindClazz = new MonotonicHashMap<>();
+
+ protected ConfigurationModuleBuilder() {
+ for (Field f : getClass().getDeclaredFields()) {
+ Class<?> t = f.getType();
+ if (paramBlacklist.contains(t)) {
+ throw new ClassHierarchyException(
+ "Found a field of type " + t + " which should be a Required/Optional Parameter/Implementation instead"
+ );
+ }
+ if (paramTypes.contains(t)) {
+ if (!Modifier.isPublic(f.getModifiers())) {
+ throw new ClassHierarchyException(
+ "Found a non-public configuration option in " + getClass() + ": "
+ + f);
+ }
+ if (!Modifier.isStatic(f.getModifiers())) {
+ throw new ClassHierarchyException(
+ "Found a non-static configuration option in " + getClass() + ": "
+ + f);
+ }
+ if (!Modifier.isFinal(f.getModifiers())) {
+ throw new ClassHierarchyException(
+ "Found a non-final configuration option in " + getClass() + ": "
+ + f);
+ }
+ final Object o;
+ try {
+ o = f.get(null);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new ClassHierarchyException(
+ "Could not look up field instance in " + getClass() + " field: "
+ + f, e);
+ }
+ if (map.containsKey(o)) {
+ throw new ClassHierarchyException(
+ "Detected aliased instances in class " + getClass()
+ + " for fields " + map.get(o) + " and " + f);
+ }
+ if (t == RequiredImpl.class || t == RequiredParameter.class) {
+ reqDecl.add(f);
+ } else {
+ optDecl.add(f);
+ }
+ map.put(o, f);
+ }
+ }
+ }
+
+ private ConfigurationModuleBuilder(ConfigurationModuleBuilder c) {
+ try {
+ b.addConfiguration(c.b.build());
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ reqDecl.addAll(c.reqDecl);
+ optDecl.addAll(c.optDecl);
+ reqUsed.addAll(c.reqUsed);
+ optUsed.addAll(c.optUsed);
+ setOpts.addAll(c.setOpts);
+ map.putAll(c.map);
+ freeImpls.putAll(c.freeImpls);
+ freeParams.putAll(c.freeParams);
+ lateBindClazz.putAll(c.lateBindClazz);
+
+ }
+
+ /**
+ * TODO: It would be nice if this incorporated d by reference so that static analysis / documentation tools
+ * could document the dependency between c and d.
+ */
+ public final ConfigurationModuleBuilder merge(ConfigurationModule d) {
+ if (d == null) {
+ throw new NullPointerException("If merge() was passed a static final field that is initialized to non-null, then this is almost certainly caused by a circular class dependency.");
+ }
+ try {
+ d.assertStaticClean();
+ } catch (ClassHierarchyException e) {
+ throw new ClassHierarchyException(ReflectionUtilities.getFullName(getClass()) + ": detected attempt to merge with ConfigurationModule that has had set() called on it", e);
+ }
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.addConfiguration(d.builder.b.build());
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ c.reqDecl.addAll(d.builder.reqDecl);
+ c.optDecl.addAll(d.builder.optDecl);
+ c.reqUsed.addAll(d.builder.reqUsed);
+ c.optUsed.addAll(d.builder.optUsed);
+ c.setOpts.addAll(d.builder.setOpts);
+ c.map.putAll(d.builder.map);
+ c.freeImpls.putAll(d.builder.freeImpls);
+ c.freeParams.putAll(d.builder.freeParams);
+ c.lateBindClazz.putAll(d.builder.lateBindClazz);
+
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bind(Class<?> iface, Impl<?> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeImpls.put(iface, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindSetEntry(Class<? extends Name<Set<T>>> iface, String impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindSetEntry(iface, impl);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindSetEntry(Class<? extends Name<Set<T>>> iface, Class<? extends T> impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindSetEntry(iface, impl);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindSetEntry(Class<? extends Name<Set<T>>> iface, Impl<? extends T> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeImpls.put(iface, opt);
+ if (!setOpts.contains(opt)) {
+ c.setOpts.add(opt);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindSetEntry(Class<? extends Name<Set<T>>> iface, Param<? extends T> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeParams.put(iface, opt);
+ if (!setOpts.contains(opt)) {
+ c.setOpts.add(opt);
+ }
+ return c;
+ }
+
+
+ public final <T> ConfigurationModuleBuilder bindImplementation(Class<T> iface,
+ Class<? extends T> impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindImplementation(iface, impl);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindImplementation(Class<T> iface,
+ String impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.lateBindClazz.put(iface, impl);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindImplementation(Class<T> iface,
+ Impl<? extends T> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeImpls.put(iface, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindNamedParameter(
+ Class<? extends Name<T>> name, String value) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindNamedParameter(name, value);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindNamedParameter(
+ Class<? extends Name<T>> name, Param<T> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeParams.put(name, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindNamedParameter(
+ Class<? extends Name<T>> iface, Class<? extends T> impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindNamedParameter(iface, impl);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindNamedParameter(
+ Class<? extends Name<T>> iface, Impl<? extends T> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeImpls.put(iface, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindConstructor(Class<T> clazz,
+ Class<? extends ExternalConstructor<? extends T>> constructor) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bindConstructor(clazz, constructor);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindConstructor(Class<T> cons,
+ Impl<? extends ExternalConstructor<? extends T>> v) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(v);
+ c.freeImpls.put(cons, v);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindList(Class<? extends Name<List<T>>> iface,
+ Impl<List> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeImpls.put(iface, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindList(Class<? extends Name<List<T>>> iface,
+ Param<List> opt) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.processUse(opt);
+ c.freeParams.put(iface, opt);
+ return c;
+ }
+
+ public final <T> ConfigurationModuleBuilder bindList(Class<? extends Name<List<T>>> iface, List list) {
+ ConfigurationModuleBuilder c = deepCopy();
+ c.b.bindList(iface, list);
+ return c;
+ }
+
+ private final <T> void processUse(Object impl) {
+ Field f = map.get(impl);
+ if (f == null) { /* throw */
+ throw new ClassHierarchyException("Unknown Impl/Param when binding " + ReflectionUtilities.getSimpleName(impl.getClass()) + ". Did you pass in a field from some other module?");
+ }
+ if (!reqUsed.contains(f)) {
+ reqUsed.add(f);
+ }
+ if (!optUsed.contains(f)) {
+ optUsed.add(f);
+ }
+ }
+
+ public final ConfigurationModule build() throws ClassHierarchyException {
+ ConfigurationModuleBuilder c = deepCopy();
+
+ if (!(c.reqUsed.containsAll(c.reqDecl) && c.optUsed.containsAll(c.optDecl))) {
+ Set<Field> fset = new MonotonicHashSet<>();
+ for (Field f : c.reqDecl) {
+ if (!c.reqUsed.contains(f)) {
+ fset.add(f);
+ }
+ }
+ for (Field f : c.optDecl) {
+ if (!c.optUsed.contains(f)) {
+ fset.add(f);
+ }
+ }
+ throw new ClassHierarchyException(
+ "Found declared options that were not used in binds: "
+ + toString(fset));
+ }
+ for (Class<?> clz : c.lateBindClazz.keySet()) {
+ try {
+ c.b.bind(ReflectionUtilities.getFullName(clz), c.lateBindClazz.get(clz));
+ } catch (NameResolutionException e) {
+ throw new ClassHierarchyException("ConfigurationModule refers to unknown class: " + c.lateBindClazz.get(clz), e);
+ } catch (BindException e) {
+ throw new ClassHierarchyException("bind failed while initializing ConfigurationModuleBuilder", e);
+ }
+ }
+ return new ConfigurationModule(c);
+ }
+
+/* public final <T> ConfigurationModuleBuilder bind(Class<T> iface, Class<?> impl) {
+ ConfigurationModuleBuilder c = deepCopy();
+ try {
+ c.b.bind(iface, impl);
+ } catch (BindException e) {
+ throw new ClassHierarchyException(e);
+ }
+ return c;
+ } */
+
+ final ConfigurationModuleBuilder deepCopy() {
+ // ooh... this is a dirty trick --- we strip this's type off here,
+ // fortunately, we've all ready looked at the root object's class's
+ // fields, and we copy the information we extracted from them, so
+ // everything works out OK w.r.t. field detection.
+ return new ConfigurationModuleBuilder(this) {
+ };
+ }
+
+ final String toString(Set<Field> s) {
+ StringBuilder sb = new StringBuilder("{");
+ boolean first = true;
+ for (Field f : s) {
+ sb.append((first ? " " : ", ") + f.getName());
+ first = false;
+ }
+ sb.append(" }");
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationSerializer.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationSerializer.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationSerializer.java
new file mode 100644
index 0000000..46fcaff
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ConfigurationSerializer.java
@@ -0,0 +1,154 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.annotations.DefaultImplementation;
+import org.apache.reef.tang.exceptions.BindException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A base interface for Configuration serializers.
+ */
+@DefaultImplementation(AvroConfigurationSerializer.class)
+public interface ConfigurationSerializer {
+
+
+ /**
+ * Stores the given Configuration in the given File.
+ *
+ * @param conf the Configuration to store
+ * @param file the file to store the Configuration in
+ * @throws java.io.IOException if there is an IO error in the process.
+ */
+ public void toFile(final Configuration conf, final File file) throws IOException;
+
+ /**
+ * Stores the given Configuration in the given Text File.
+ *
+ * @param conf the Configuration to store
+ * @param file the file to store the Configuration in
+ * @throws java.io.IOException if there is an IO error in the process.
+ */
+ public void toTextFile(final Configuration conf, final File file) throws IOException;
+
+ /**
+ * Writes the Configuration to a byte[].
+ *
+ * @param conf
+ * @return
+ * @throws IOException
+ */
+ public byte[] toByteArray(final Configuration conf) throws IOException;
+
+ /**
+ * Writes the Configuration as a String.
+ *
+ * @param configuration
+ * @return a String representation of the Configuration
+ */
+ public String toString(final Configuration configuration);
+
+
+ /**
+ * Loads a Configuration from a File created with toFile().
+ *
+ * @param file the File to read from.
+ * @return the Configuration stored in the file.
+ * @throws IOException if the File can't be read or parsed
+ * @throws BindException if the file contains an illegal Configuration
+ */
+ public Configuration fromFile(final File file) throws IOException, BindException;
+
+ /**
+ * Loads a Configuration from a File created with toFile().
+ *
+ * @param file the File to read from.
+ * @return the Configuration stored in the file.
+ * @throws IOException if the File can't be read or parsed
+ * @throws BindException if the file contains an illegal Configuration
+ */
+ public Configuration fromTextFile(final File file) throws IOException, BindException;
+
+ /**
+ * Loads a Configuration from a File created with toFile() with ClassHierarchy
+ *
+ * @param file
+ * @param classHierarchy
+ * @return
+ * @throws IOException
+ */
+ public Configuration fromTextFile(final File file, final ClassHierarchy classHierarchy) throws IOException;
+
+ /**
+ * Loads a Configuration from a File created with toFile().
+ *
+ * @param file the File to read from.
+ * @param classHierarchy used to validate the configuration against
+ * @return the Configuration stored in the file.
+ * @throws IOException if the File can't be read or parsed
+ * @throws BindException if the file contains an illegal Configuration
+ */
+ public Configuration fromFile(final File file, final ClassHierarchy classHierarchy) throws IOException, BindException;
+
+ /**
+ * Loads a Configuration from a byte[] created with toByteArray().
+ *
+ * @param theBytes the bytes to deserialize.
+ * @return the Configuration stored.
+ * @throws IOException if the byte[] can't be deserialized
+ * @throws BindException if the byte[] contains an illegal Configuration.
+ */
+ public Configuration fromByteArray(final byte[] theBytes) throws IOException, BindException;
+
+ /**
+ * Loads a Configuration from a byte[] created with toByteArray().
+ *
+ * @param theBytes the bytes to deserialize.
+ * @param classHierarchy used to validate the configuration against
+ * @return the Configuration stored.
+ * @throws IOException if the byte[] can't be deserialized
+ * @throws BindException if the byte[] contains an illegal Configuration.
+ */
+ public Configuration fromByteArray(final byte[] theBytes, final ClassHierarchy classHierarchy) throws IOException, BindException;
+
+ /**
+ * Decodes a String generated via toString()
+ *
+ * @param theString to be parsed
+ * @return the Configuration stored in theString.
+ * @throws IOException if theString can't be parsed.
+ * @throws BindException if theString contains an illegal Configuration.
+ */
+ public Configuration fromString(final String theString) throws IOException, BindException;
+
+ /**
+ * Decodes a String generated via toString()
+ *
+ * @param theString to be parsed
+ * @param classHierarchy used to validate the configuration against
+ * @return the Configuration stored in theString.
+ * @throws IOException if theString can't be parsed.
+ * @throws BindException if theString contains an illegal Configuration.
+ */
+ public Configuration fromString(final String theString, final ClassHierarchy classHierarchy) throws IOException, BindException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Impl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Impl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Impl.java
new file mode 100644
index 0000000..f3426fb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Impl.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public interface Impl<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalImpl.java
new file mode 100644
index 0000000..b730feb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalImpl.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public final class OptionalImpl<T> implements Impl<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalParameter.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalParameter.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalParameter.java
new file mode 100644
index 0000000..26d597b
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/OptionalParameter.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public final class OptionalParameter<T> implements Param<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Param.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Param.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Param.java
new file mode 100644
index 0000000..355030f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Param.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public interface Param<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ParameterParser.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ParameterParser.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ParameterParser.java
new file mode 100644
index 0000000..be73444
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/ParameterParser.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ExternalConstructor;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.util.MonotonicTreeMap;
+import org.apache.reef.tang.util.ReflectionUtilities;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ParameterParser {
+ private static final Set<String> BUILTIN_NAMES = new HashSet<String>() {
+ private static final long serialVersionUID = 1L;
+
+ {
+ Collections.addAll(this,
+ String.class.getName(),
+ Byte.class.getName(),
+ Character.class.getName(),
+ Short.class.getName(),
+ Integer.class.getName(),
+ Long.class.getName(),
+ Float.class.getName(),
+ Double.class.getName(),
+ Boolean.class.getName(),
+ Void.class.getName());
+ }
+ };
+ MonotonicTreeMap<String, Constructor<? extends ExternalConstructor<?>>> parsers = new MonotonicTreeMap<>();
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void addParser(Class<? extends ExternalConstructor<?>> ec) throws BindException {
+ Class<?> tc = (Class<?>) ReflectionUtilities.getInterfaceTarget(
+ ExternalConstructor.class, ec);
+ addParser((Class) tc, (Class) ec);
+ }
+
+ public <T, U extends T> void addParser(Class<U> clazz, Class<? extends ExternalConstructor<T>> ec) throws BindException {
+ Constructor<? extends ExternalConstructor<T>> c;
+ try {
+ c = ec.getDeclaredConstructor(String.class);
+ c.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ throw new BindException("Constructor "
+ + ReflectionUtilities.getFullName(ec) + "(String) does not exist!", e);
+ }
+ c.setAccessible(true);
+ parsers.put(ReflectionUtilities.getFullName(clazz), c);
+ }
+
+ public void mergeIn(ParameterParser p) {
+ for (String s : p.parsers.keySet()) {
+ if (!parsers.containsKey(s)) {
+ parsers.put(s, p.parsers.get(s));
+ } else {
+ if (!parsers.get(s).equals(p.parsers.get(s))) {
+ throw new IllegalArgumentException(
+ "Conflict detected when merging parameter parsers! To parse " + s
+ + " I have a: " + ReflectionUtilities.getFullName(parsers.get(s).getDeclaringClass())
+ + " the other instance has a: " + ReflectionUtilities.getFullName(p.parsers.get(s).getDeclaringClass()));
+ }
+ }
+ }
+ }
+
+ public <T> T parse(Class<T> c, String s) {
+ Class<?> d = ReflectionUtilities.boxClass(c);
+ for (Type e : ReflectionUtilities.classAndAncestors(d)) {
+ String name = ReflectionUtilities.getFullName(e);
+ if (parsers.containsKey(name)) {
+ T ret = parse(name, s);
+ if (c.isAssignableFrom(ret.getClass())) {
+ return ret;
+ } else {
+ throw new ClassCastException("Cannot cast from " + ret.getClass() + " to " + c);
+ }
+ }
+ }
+ return parse(ReflectionUtilities.getFullName(d), s);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T parse(String name, String value) {
+ if (parsers.containsKey(name)) {
+ try {
+ return (T) (parsers.get(name).newInstance(value).newInstance());
+ } catch (ReflectiveOperationException e) {
+ throw new IllegalArgumentException("Error invoking constructor for "
+ + name, e);
+ }
+ } else {
+ if (name.equals(String.class.getName())) {
+ return (T) value;
+ }
+ if (name.equals(Byte.class.getName())) {
+ return (T) (Byte) Byte.parseByte(value);
+ }
+ if (name.equals(Character.class.getName())) {
+ return (T) (Character) value.charAt(0);
+ }
+ if (name.equals(Short.class.getName())) {
+ return (T) (Short) Short.parseShort(value);
+ }
+ if (name.equals(Integer.class.getName())) {
+ return (T) (Integer) Integer.parseInt(value);
+ }
+ if (name.equals(Long.class.getName())) {
+ return (T) (Long) Long.parseLong(value);
+ }
+ if (name.equals(Float.class.getName())) {
+ return (T) (Float) Float.parseFloat(value);
+ }
+ if (name.equals(Double.class.getName())) {
+ return (T) (Double) Double.parseDouble(value);
+ }
+ if (name.equals(Boolean.class.getName())) {
+ return (T) (Boolean) Boolean.parseBoolean(value);
+ }
+ if (name.equals(Void.class.getName())) {
+ throw new ClassCastException("Can't instantiate void");
+ }
+ throw new UnsupportedOperationException("Don't know how to parse a " + name);
+ }
+ }
+
+ public boolean canParse(String name) {
+ return parsers.containsKey(name) || BUILTIN_NAMES.contains(name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Provides.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Provides.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Provides.java
new file mode 100644
index 0000000..a98f081
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/Provides.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public final class Provides<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredImpl.java
new file mode 100644
index 0000000..6355af0
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredImpl.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public final class RequiredImpl<T> implements Impl<T> {
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredParameter.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredParameter.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredParameter.java
new file mode 100644
index 0000000..f0fa97f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/formats/RequiredParameter.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+public final class RequiredParameter<T> implements Param<T> {
+}
\ No newline at end of file