package org.embulk.input; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Objects; import com.google.common.base.Optional; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class QueryConfig { private final String name; private final Optional value; private final Optional> values; private final boolean expand; @JsonCreator public QueryConfig( @JsonProperty("name") String name, @JsonProperty("value") Optional value, @JsonProperty("values") Optional> values, @JsonProperty("expand") boolean expand) { this.name = name; this.value = value; this.values = values; this.expand = expand; } public List expand() { List dest; if (value.isPresent()) { if (expand) { List expanded = BraceExpansion.expand(value.get()); dest = new ArrayList<>(expanded.size()); for (String s : expanded) { dest.add(new Query(name, s)); } } else { dest = new ArrayList<>(1); dest.add(new Query(name, value.get())); } } else if (values.isPresent()) { if (expand) { dest = new ArrayList<>(values.get().size()); for (String s : values.get()) { dest.add(new Query(name, s)); } } else { dest = new ArrayList<>(1); final String[] valueArr = values.get().toArray(new String[values.get().size()]); dest.add(new Query(name, valueArr)); } } else { throw new IllegalArgumentException("value or values must be specified to 'params'"); } return dest; } @JsonProperty("name") public String getName() { return name; } @JsonProperty("value") public Optional getValue() { return value; } @JsonProperty("expand") public boolean isExpand() { return expand; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof QueryConfig)) { return false; } QueryConfig other = (QueryConfig) obj; return Objects.equal(this.name, other.name) && Objects.equal(value, other.value) && Objects.equal(expand, other.expand); } @Override public int hashCode() { return Objects.hashCode(name, value, expand); } @Override public String toString() { return String.format("ParameterConfig[%s, %s, %s]", getName(), getValue(), isExpand()); } public static class Query { private final String name; private final String[] values; public Query( @JsonProperty("name") String name, @JsonProperty("values") String... values) { this.name = name; this.values = values; } public String getName() { return name; } public String[] getValues() { return values; } public Query copy() { return new Query(this.name, Arrays.copyOf(this.values, this.values.length)); } } private static class BraceExpansion { public static List expand(String s) { return expandRecursive("", s, "", new ArrayList()); } private static List expandRecursive(String prefix, String s, String suffix, List dest) { // I used the code below as reference. // http://rosettacode.org/wiki/Brace_expansion#Java int i1 = -1, i2 = 0; String noEscape = s.replaceAll("([\\\\]{2}|[\\\\][,}{])", " "); StringBuilder sb = null; outer: while ((i1 = noEscape.indexOf('{', i1 + 1)) != -1) { i2 = i1 + 1; sb = new StringBuilder(s); for (int depth = 1; i2 < s.length() && depth > 0; i2++) { char c = noEscape.charAt(i2); depth = (c == '{') ? ++depth : depth; depth = (c == '}') ? --depth : depth; if (c == ',' && depth == 1) { sb.setCharAt(i2, '\u0000'); } else if (c == '}' && depth == 0 && sb.indexOf("\u0000") != -1) { break outer; } } } if (i1 == -1) { if (suffix.length() > 0) { expandRecursive(prefix + s, suffix, "", dest); } else { final String out = String.format("%s%s%s", prefix, s, suffix). replaceAll("[\\\\]{2}", "\\").replaceAll("[\\\\]([,}{])", "$1"); dest.add(out); } } else { for (String m : sb.substring(i1 + 1, i2).split("\u0000", -1)) { expandRecursive(prefix + s.substring(0, i1), m, s.substring(i2 + 1) + suffix, dest); } } return dest; } } }