embulk-output-td 0.1.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/build.gradle +1 -1
- data/embulk-output-td.gemspec +1 -1
- data/src/main/java/org/embulk/output/td/TdOutputPlugin.java +1 -0
- data/src/main/java/org/embulk/output/td/TimeValueConfig.java +0 -9
- data/src/main/java/org/embulk/output/td/TimeValueGenerator.java +60 -34
- data/src/main/java/org/embulk/output/td/writer/FieldWriterSet.java +80 -72
- data/src/test/java/org/embulk/output/td/writer/TestFieldWriterSet.java +2 -12
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 985479cb77ed1b156d896d1dbad073fdc6141c56
|
4
|
+
data.tar.gz: 4fde290d7d7e83a7eba0f687c22312e0ad589f8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87aba00cd303cbe98772d3e645d2336fc15091f502829eaed3064def64ac4154bc4d39110d785f30fd046e34a183a4bc131953c5d1524732f72893ddea8c9f66
|
7
|
+
data.tar.gz: a3a2281e0bcd43ef99763ae8ab7e526f8d22b1f667bb480e5c16b52bf5bcbf6cca4caeedcf5fbf35b1bd801a1cc5c8896b55f65007d522c4f877373818bbfebd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 0.2.0 - 2016-01-12
|
2
|
+
|
3
|
+
* [new feature] Not use first timestamp column as primary key [#32](https://github.com/treasure-data/embulk-output-td/pull/32)
|
4
|
+
|
1
5
|
## 0.1.8 - 2016-01-09
|
2
6
|
|
3
7
|
* [new feature] Add mode to time value option [#31](https://github.com/treasure-data/embulk-output-td/pull/31)
|
data/build.gradle
CHANGED
data/embulk-output-td.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
Gem::Specification.new do |spec|
|
3
3
|
spec.name = "embulk-output-td"
|
4
|
-
spec.version = "0.
|
4
|
+
spec.version = "0.2.0"
|
5
5
|
spec.authors = ["Muga Nishizawa"]
|
6
6
|
spec.summary = %[TreasureData output plugin for Embulk]
|
7
7
|
spec.description = %[TreasureData output plugin is an Embulk plugin that loads records to TreasureData read by any input plugins. Search the input plugins by 'embulk-output' keyword.]
|
@@ -109,6 +109,7 @@ public class TdOutputPlugin
|
|
109
109
|
@Config("time_value")
|
110
110
|
@ConfigDefault("null")
|
111
111
|
public Optional<TimeValueConfig> getTimeValue(); // TODO allow timestamp format such as {from: "2015-01-01 00:00:00 UTC", to: "2015-01-02 00:00:00 UTC"} as well as unixtime integer
|
112
|
+
public void setTimeValue(Optional<TimeValueConfig> timeValue);
|
112
113
|
|
113
114
|
@Config("unix_timestamp_unit")
|
114
115
|
@ConfigDefault("\"sec\"")
|
@@ -5,9 +5,6 @@ import org.embulk.config.Config;
|
|
5
5
|
import org.embulk.config.ConfigDefault;
|
6
6
|
import org.embulk.config.Task;
|
7
7
|
|
8
|
-
import javax.validation.constraints.Max;
|
9
|
-
import javax.validation.constraints.Min;
|
10
|
-
|
11
8
|
public interface TimeValueConfig
|
12
9
|
extends Task
|
13
10
|
{
|
@@ -17,19 +14,13 @@ public interface TimeValueConfig
|
|
17
14
|
|
18
15
|
@Config("value")
|
19
16
|
@ConfigDefault("null")
|
20
|
-
@Min(0)
|
21
|
-
@Max(253402300799L) // '9999-12-31 23:59:59 UTC'
|
22
17
|
Optional<Long> getValue();
|
23
18
|
|
24
19
|
@Config("from")
|
25
20
|
@ConfigDefault("null")
|
26
|
-
@Min(0)
|
27
|
-
@Max(253402300799L) // '9999-12-31 23:59:59 UTC'
|
28
21
|
Optional<Long> getFrom();
|
29
22
|
|
30
23
|
@Config("to")
|
31
24
|
@ConfigDefault("null")
|
32
|
-
@Min(0)
|
33
|
-
@Max(253402300799L) // '9999-12-31 23:59:59 UTC'
|
34
25
|
Optional<Long> getTo();
|
35
26
|
}
|
@@ -10,54 +10,73 @@ public abstract class TimeValueGenerator
|
|
10
10
|
public static TimeValueGenerator newGenerator(final TimeValueConfig config)
|
11
11
|
{
|
12
12
|
switch (config.getMode()) {
|
13
|
-
case "incremental_time":
|
13
|
+
case "incremental_time": // default mode
|
14
14
|
require(config.getFrom(), "'from', 'to'");
|
15
|
+
validateTimeRange(config.getFrom().get(), "'from'");
|
15
16
|
require(config.getTo(), "'to'");
|
17
|
+
validateTimeRange(config.getTo().get(), "'to'");
|
16
18
|
reject(config.getValue(), "'value'");
|
17
19
|
|
18
|
-
return new
|
19
|
-
|
20
|
-
|
21
|
-
private final long to = config.getTo().get();
|
22
|
-
|
23
|
-
private long current = from;
|
24
|
-
|
25
|
-
@Override
|
26
|
-
public long next()
|
27
|
-
{
|
28
|
-
try {
|
29
|
-
return current++;
|
30
|
-
}
|
31
|
-
finally {
|
32
|
-
if (current > to) {
|
33
|
-
current = from;
|
34
|
-
}
|
35
|
-
}
|
36
|
-
}
|
37
|
-
};
|
38
|
-
}
|
39
|
-
case "fixed_time": {
|
20
|
+
return new IncrementalTimeValueGenerator(config);
|
21
|
+
|
22
|
+
case "fixed_time":
|
40
23
|
require(config.getValue(), "'value'");
|
24
|
+
validateTimeRange(config.getValue().get(), "'value'");
|
41
25
|
reject(config.getFrom(), "'from'");
|
42
26
|
reject(config.getTo(), "'to'");
|
43
27
|
|
44
|
-
return new
|
45
|
-
{
|
46
|
-
private final long fixed = config.getValue().get();
|
28
|
+
return new FixedTimeValueGenerator(config);
|
47
29
|
|
48
|
-
|
49
|
-
public long next()
|
50
|
-
{
|
51
|
-
return fixed;
|
52
|
-
}
|
53
|
-
};
|
54
|
-
}
|
55
|
-
default: {
|
30
|
+
default:
|
56
31
|
throw new ConfigException(String.format("Unknwon mode '%s'. Supported methods are incremental_time, fixed_time.", config.getMode()));
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
public static class IncrementalTimeValueGenerator
|
36
|
+
extends TimeValueGenerator
|
37
|
+
{
|
38
|
+
private final long from;
|
39
|
+
private final long to;
|
40
|
+
|
41
|
+
private long current;
|
42
|
+
|
43
|
+
public IncrementalTimeValueGenerator(final TimeValueConfig config)
|
44
|
+
{
|
45
|
+
current = from = config.getFrom().get();
|
46
|
+
to = config.getTo().get();
|
47
|
+
}
|
48
|
+
|
49
|
+
@Override
|
50
|
+
public long next()
|
51
|
+
{
|
52
|
+
try {
|
53
|
+
return current++;
|
54
|
+
}
|
55
|
+
finally {
|
56
|
+
if (current > to) {
|
57
|
+
current = from;
|
58
|
+
}
|
57
59
|
}
|
58
60
|
}
|
59
61
|
}
|
60
62
|
|
63
|
+
public static class FixedTimeValueGenerator
|
64
|
+
extends TimeValueGenerator
|
65
|
+
{
|
66
|
+
private final long value;
|
67
|
+
|
68
|
+
public FixedTimeValueGenerator(final TimeValueConfig config)
|
69
|
+
{
|
70
|
+
value = config.getValue().get();
|
71
|
+
}
|
72
|
+
|
73
|
+
@Override
|
74
|
+
public long next()
|
75
|
+
{
|
76
|
+
return value;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
61
80
|
// ported from embulk-input-s3
|
62
81
|
private static <T> T require(Optional<T> value, String message)
|
63
82
|
{
|
@@ -69,6 +88,13 @@ public abstract class TimeValueGenerator
|
|
69
88
|
}
|
70
89
|
}
|
71
90
|
|
91
|
+
private static void validateTimeRange(long value, String message)
|
92
|
+
{
|
93
|
+
if (value < 0 || 253402300799L < value) { // should be [1970-01-01 00:00:00, 9999-12-31 23:59:59]
|
94
|
+
throw new ConfigException("The option value must be within [0, 253402300799L]: " + message);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
72
98
|
// ported from embulk-input-s3
|
73
99
|
private static <T> void reject(Optional<T> value, String message)
|
74
100
|
{
|
@@ -6,11 +6,14 @@ import com.google.common.annotations.VisibleForTesting;
|
|
6
6
|
import com.google.common.base.Optional;
|
7
7
|
import com.google.common.base.Throwables;
|
8
8
|
import org.embulk.config.ConfigException;
|
9
|
+
import org.embulk.config.ConfigSource;
|
9
10
|
import org.embulk.output.td.TdOutputPlugin;
|
11
|
+
import org.embulk.output.td.TdOutputPlugin.ConvertTimestampType;
|
10
12
|
import org.embulk.output.td.TimeValueConfig;
|
11
13
|
import org.embulk.output.td.TimeValueGenerator;
|
12
14
|
import org.embulk.spi.Column;
|
13
15
|
import org.embulk.spi.ColumnVisitor;
|
16
|
+
import org.embulk.spi.Exec;
|
14
17
|
import org.embulk.spi.PageReader;
|
15
18
|
import org.embulk.spi.Schema;
|
16
19
|
import org.embulk.spi.time.TimestampFormatter;
|
@@ -40,15 +43,14 @@ public class FieldWriterSet
|
|
40
43
|
public FieldWriterSet(Logger log, TdOutputPlugin.PluginTask task, Schema schema)
|
41
44
|
{
|
42
45
|
Optional<String> userDefinedPrimaryKeySourceColumnName = task.getTimeColumn();
|
43
|
-
|
46
|
+
ConvertTimestampType convertTimestampType = task.getConvertTimestampType();
|
44
47
|
Optional<TimeValueConfig> timeValueConfig = task.getTimeValue();
|
45
48
|
if (timeValueConfig.isPresent() && userDefinedPrimaryKeySourceColumnName.isPresent()) {
|
46
49
|
throw new ConfigException("Setting both time_column and time_value is invalid");
|
47
50
|
}
|
48
51
|
|
49
|
-
boolean
|
52
|
+
boolean foundPrimaryKey = false;
|
50
53
|
int duplicatePrimaryKeySourceIndex = -1;
|
51
|
-
int firstTimestampColumnIndex = -1;
|
52
54
|
|
53
55
|
int fc = 0;
|
54
56
|
fieldWriters = new IFieldWriter[schema.size()];
|
@@ -104,12 +106,11 @@ public class FieldWriterSet
|
|
104
106
|
log.warn("time column is converted from {} to seconds", task.getUnixTimestampUnit());
|
105
107
|
}
|
106
108
|
writer = new UnixTimestampLongFieldWriter(columnName, task.getUnixTimestampUnit().getFractionUnit());
|
107
|
-
|
109
|
+
foundPrimaryKey = true;
|
108
110
|
}
|
109
111
|
else if (columnType instanceof TimestampType) {
|
110
112
|
writer = new TimestampLongFieldWriter(columnName);
|
111
|
-
|
112
|
-
hasPkWriter = true;
|
113
|
+
foundPrimaryKey = true;
|
113
114
|
}
|
114
115
|
else {
|
115
116
|
throw new ConfigException(String.format("Type of '%s' column must be long or timestamp but got %s",
|
@@ -118,37 +119,7 @@ public class FieldWriterSet
|
|
118
119
|
break;
|
119
120
|
|
120
121
|
case SIMPLE_VALUE:
|
121
|
-
|
122
|
-
writer = new BooleanFieldWriter(columnName);
|
123
|
-
}
|
124
|
-
else if (columnType instanceof LongType) {
|
125
|
-
writer = new LongFieldWriter(columnName);
|
126
|
-
}
|
127
|
-
else if (columnType instanceof DoubleType) {
|
128
|
-
writer = new DoubleFieldWriter(columnName);
|
129
|
-
}
|
130
|
-
else if (columnType instanceof StringType) {
|
131
|
-
writer = new StringFieldWriter(columnName);
|
132
|
-
}
|
133
|
-
else if (columnType instanceof TimestampType) {
|
134
|
-
switch (convertTimestamp) {
|
135
|
-
case STRING:
|
136
|
-
writer = new TimestampStringFieldWriter(timestampFormatters[i], columnName);
|
137
|
-
break;
|
138
|
-
case SEC:
|
139
|
-
writer = new TimestampLongFieldWriter(columnName);
|
140
|
-
break;
|
141
|
-
default:
|
142
|
-
// Thread of control doesn't come here but, just in case, it throws ConfigException.
|
143
|
-
throw new ConfigException(String.format("Unknown option {} as convert_timestamp_type", convertTimestamp));
|
144
|
-
}
|
145
|
-
if (firstTimestampColumnIndex < 0) {
|
146
|
-
firstTimestampColumnIndex = i;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
else {
|
150
|
-
throw new ConfigException("Unsupported type: " + columnType);
|
151
|
-
}
|
122
|
+
writer = newSimpleFieldWriter(columnName, columnType, convertTimestampType, timestampFormatters[i]);
|
152
123
|
break;
|
153
124
|
|
154
125
|
case DUPLICATE_PRIMARY_KEY:
|
@@ -164,24 +135,24 @@ public class FieldWriterSet
|
|
164
135
|
fc += 1;
|
165
136
|
}
|
166
137
|
|
138
|
+
if (foundPrimaryKey) {
|
139
|
+
// appropriate 'time' column is found
|
140
|
+
|
141
|
+
staticTimeValue = Optional.absent();
|
142
|
+
fieldCount = fc;
|
143
|
+
return;
|
144
|
+
}
|
145
|
+
|
167
146
|
if (timeValueConfig.isPresent()) {
|
168
|
-
//
|
169
|
-
|
147
|
+
// 'time_value' option is specified
|
148
|
+
|
149
|
+
staticTimeValue = Optional.of(TimeValueGenerator.newGenerator(timeValueConfig.get()));
|
150
|
+
fieldCount = fc + 1;
|
151
|
+
return;
|
170
152
|
}
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
if (userDefinedPrimaryKeySourceColumnName.isPresent()) {
|
175
|
-
throw new ConfigException(String.format("time_column '%s' does not exist", userDefinedPrimaryKeySourceColumnName.get()));
|
176
|
-
}
|
177
|
-
else if (firstTimestampColumnIndex >= 0) {
|
178
|
-
// if time is not found, use the first timestamp column
|
179
|
-
duplicatePrimaryKeySourceIndex = firstTimestampColumnIndex;
|
180
|
-
}
|
181
|
-
else {
|
182
|
-
throw new ConfigException(String.format("TD output plugin requires at least one timestamp column, or a long column named 'time'"));
|
183
|
-
}
|
184
|
-
}
|
153
|
+
|
154
|
+
if (!foundPrimaryKey && duplicatePrimaryKeySourceIndex >= 0) {
|
155
|
+
// 'time_column' option is correctly specified
|
185
156
|
|
186
157
|
String columnName = schema.getColumnName(duplicatePrimaryKeySourceIndex);
|
187
158
|
Type columnType = schema.getColumnType(duplicatePrimaryKeySourceIndex);
|
@@ -196,18 +167,7 @@ public class FieldWriterSet
|
|
196
167
|
else if (columnType instanceof TimestampType) {
|
197
168
|
log.info("Duplicating {}:{} column to 'time' column as seconds for the data partitioning",
|
198
169
|
columnName, columnType);
|
199
|
-
IFieldWriter fw;
|
200
|
-
switch (convertTimestamp) {
|
201
|
-
case STRING:
|
202
|
-
fw = new TimestampStringFieldWriter(timestampFormatters[duplicatePrimaryKeySourceIndex], columnName);
|
203
|
-
break;
|
204
|
-
case SEC:
|
205
|
-
fw = new TimestampLongFieldWriter(columnName);
|
206
|
-
break;
|
207
|
-
default:
|
208
|
-
// Thread of control doesn't come here but, just in case, it throws ConfigException.
|
209
|
-
throw new ConfigException(String.format("Unknown option {} as convert_timestamp_type", convertTimestamp));
|
210
|
-
}
|
170
|
+
IFieldWriter fw = newSimpleTimestampFieldWriter(columnName, columnType, convertTimestampType, timestampFormatters[duplicatePrimaryKeySourceIndex]);
|
211
171
|
writer = new TimestampFieldLongDuplicator(fw, "time");
|
212
172
|
}
|
213
173
|
else {
|
@@ -217,17 +177,28 @@ public class FieldWriterSet
|
|
217
177
|
|
218
178
|
// replace existint writer
|
219
179
|
fieldWriters[duplicatePrimaryKeySourceIndex] = writer;
|
220
|
-
|
180
|
+
staticTimeValue = Optional.absent();
|
181
|
+
fieldCount = fc + 1;
|
182
|
+
return;
|
221
183
|
}
|
222
184
|
|
223
|
-
if (
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
185
|
+
if (!foundPrimaryKey) {
|
186
|
+
// primary key is not found yet
|
187
|
+
|
188
|
+
if (userDefinedPrimaryKeySourceColumnName.isPresent()) {
|
189
|
+
throw new ConfigException(String.format("A specified time_column '%s' does not exist", userDefinedPrimaryKeySourceColumnName.get()));
|
190
|
+
}
|
191
|
+
|
192
|
+
long uploadTime = System.currentTimeMillis() / 1000;
|
193
|
+
log.info("'time' column is generated and is set to a unix time {}", uploadTime);
|
194
|
+
TimeValueConfig newConfig = Exec.newConfigSource().set("mode", "fixed_time").set("value", uploadTime).loadConfig(TimeValueConfig.class);
|
195
|
+
task.setTimeValue(Optional.of(newConfig));
|
196
|
+
staticTimeValue = Optional.of(TimeValueGenerator.newGenerator(newConfig));
|
197
|
+
fieldCount = fc + 1;
|
198
|
+
return;
|
228
199
|
}
|
229
200
|
|
230
|
-
|
201
|
+
throw new AssertionError("Cannot select primary key");
|
231
202
|
}
|
232
203
|
|
233
204
|
private static String newColumnUniqueName(String originalName, Schema schema)
|
@@ -250,6 +221,43 @@ public class FieldWriterSet
|
|
250
221
|
return false;
|
251
222
|
}
|
252
223
|
|
224
|
+
private static FieldWriter newSimpleFieldWriter(String columnName, Type columnType, ConvertTimestampType convertTimestampType, TimestampFormatter timestampFormatter)
|
225
|
+
{
|
226
|
+
if (columnType instanceof BooleanType) {
|
227
|
+
return new BooleanFieldWriter(columnName);
|
228
|
+
}
|
229
|
+
else if (columnType instanceof LongType) {
|
230
|
+
return new LongFieldWriter(columnName);
|
231
|
+
}
|
232
|
+
else if (columnType instanceof DoubleType) {
|
233
|
+
return new DoubleFieldWriter(columnName);
|
234
|
+
}
|
235
|
+
else if (columnType instanceof StringType) {
|
236
|
+
return new StringFieldWriter(columnName);
|
237
|
+
}
|
238
|
+
else if (columnType instanceof TimestampType) {
|
239
|
+
return newSimpleTimestampFieldWriter(columnName, columnType, convertTimestampType, timestampFormatter);
|
240
|
+
}
|
241
|
+
else {
|
242
|
+
throw new ConfigException("Unsupported type: " + columnType);
|
243
|
+
}
|
244
|
+
}
|
245
|
+
|
246
|
+
private static FieldWriter newSimpleTimestampFieldWriter(String columnName, Type columnType, ConvertTimestampType convertTimestampType, TimestampFormatter timestampFormatter)
|
247
|
+
{
|
248
|
+
switch (convertTimestampType) {
|
249
|
+
case STRING:
|
250
|
+
return new TimestampStringFieldWriter(timestampFormatter, columnName);
|
251
|
+
|
252
|
+
case SEC:
|
253
|
+
return new TimestampLongFieldWriter(columnName);
|
254
|
+
|
255
|
+
default:
|
256
|
+
// Thread of control doesn't come here but, just in case, it throws ConfigException.
|
257
|
+
throw new ConfigException(String.format("Unknown option {} as convert_timestamp_type", convertTimestampType));
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
253
261
|
@VisibleForTesting
|
254
262
|
public IFieldWriter getFieldWriter(int index)
|
255
263
|
{
|
@@ -48,17 +48,6 @@ public class TestFieldWriterSet
|
|
48
48
|
}
|
49
49
|
}
|
50
50
|
|
51
|
-
{ // if schema doesn't have time column and the user doesn't specify time_column option, it throws ConfigError.
|
52
|
-
schema = schema("_c0", Types.STRING, "_c1", Types.STRING);
|
53
|
-
try {
|
54
|
-
new FieldWriterSet(log, pluginTask(config), schema);
|
55
|
-
fail();
|
56
|
-
}
|
57
|
-
catch (Throwable t) {
|
58
|
-
assertTrue(t instanceof ConfigException);
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
51
|
{ // if schema doesn't have a column specified as time_column column, it throws ConfigError
|
63
52
|
schema = schema("_c0", Types.STRING, "_c1", Types.STRING);
|
64
53
|
try {
|
@@ -205,6 +194,7 @@ public class TestFieldWriterSet
|
|
205
194
|
Schema schema = schema("_c0", Types.TIMESTAMP, "_c1", Types.LONG);
|
206
195
|
FieldWriterSet writers = new FieldWriterSet(log, pluginTask(config), schema);
|
207
196
|
|
208
|
-
assertTrue(writers.getFieldWriter(0) instanceof
|
197
|
+
assertTrue(writers.getFieldWriter(0) instanceof TimestampStringFieldWriter); // c0
|
198
|
+
assertTrue(writers.getFieldWriter(1) instanceof LongFieldWriter); // c1
|
209
199
|
}
|
210
200
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-output-td
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muga Nishizawa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,7 +106,7 @@ files:
|
|
106
106
|
- src/test/java/org/embulk/output/td/TestTdOutputPlugin.java
|
107
107
|
- src/test/java/org/embulk/output/td/TestTimeValueGenerator.java
|
108
108
|
- src/test/java/org/embulk/output/td/writer/TestFieldWriterSet.java
|
109
|
-
- classpath/embulk-output-td-0.
|
109
|
+
- classpath/embulk-output-td-0.2.0.jar
|
110
110
|
- classpath/javassist-3.18.1-GA.jar
|
111
111
|
- classpath/jetty-client-9.2.2.v20140723.jar
|
112
112
|
- classpath/jetty-http-9.2.2.v20140723.jar
|