2013-07-03 21:05:08 +02:00
|
|
|
/*
|
2014-01-06 22:48:02 +01:00
|
|
|
* Licensed to Elasticsearch under one or more contributor
|
|
|
|
* license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright
|
|
|
|
* ownership. Elasticsearch 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
|
2013-07-03 21:05:08 +02:00
|
|
|
*
|
|
|
|
* 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.elasticsearch.common;
|
|
|
|
|
Core: Add DateFormatter interface for java time parsing (#33467)
The existing approach used date formatters when a format based string
like `date_time||epoch_millis` was used, instead of the custom code.
In order to properly solve this, a new interface called
`DateFormatter` has been added, which now can be implemented for custom
formatters. Currently there are two implementations, one using java time
and one doing the epoch_millis formatter, which simply parses a number
and then converts it to a date in UTC timezone.
The DateFormatter interface now also has a method to retrieve the name
of the formatter pattern, which is needed for mapping changes anyway.
The existing `CompoundDateTimeFormatter` class has been removed, the
name was not really nice anyway.
One more minor change is the fact, that the new java time using
FormatDateFormatter does not try to parse the date with its printer
implementation first (which might be a strict one and fail), but a
printer can now be specified in addition. This saves one potential
failure/exception when parsing less strict dates.
If only a printer is specified, the printer will also be used as a
parser.
2018-09-14 13:55:16 +02:00
|
|
|
import org.elasticsearch.common.time.DateFormatter;
|
2015-09-11 17:35:29 +09:00
|
|
|
|
2018-08-03 13:21:14 +02:00
|
|
|
import java.time.Instant;
|
|
|
|
import java.time.ZoneOffset;
|
2013-12-30 16:12:00 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2015-09-11 17:35:29 +09:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2013-07-03 21:05:08 +02:00
|
|
|
|
2015-10-02 00:18:05 +02:00
|
|
|
import static java.util.Collections.emptyMap;
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
public class Table {
|
|
|
|
|
2014-03-27 15:54:45 +01:00
|
|
|
private List<Cell> headers = new ArrayList<>();
|
|
|
|
private List<List<Cell>> rows = new ArrayList<>();
|
2015-09-09 14:14:48 -04:00
|
|
|
private Map<String, List<Cell>> map = new HashMap<>();
|
|
|
|
private Map<String, Cell> headerMap = new HashMap<>();
|
2013-12-30 16:12:00 +01:00
|
|
|
private List<Cell> currentCells;
|
|
|
|
private boolean inHeaders = false;
|
2015-09-11 17:35:29 +09:00
|
|
|
private boolean withTime = false;
|
|
|
|
public static final String EPOCH = "epoch";
|
|
|
|
public static final String TIMESTAMP = "timestamp";
|
2013-07-03 21:05:08 +02:00
|
|
|
|
|
|
|
public Table startHeaders() {
|
|
|
|
inHeaders = true;
|
2014-03-27 15:54:45 +01:00
|
|
|
currentCells = new ArrayList<>();
|
2013-07-03 21:05:08 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2015-09-11 17:35:29 +09:00
|
|
|
public Table startHeadersWithTimestamp() {
|
|
|
|
startHeaders();
|
|
|
|
this.withTime = true;
|
|
|
|
addCell("epoch", "alias:t,time;desc:seconds since 1970-01-01 00:00:00");
|
|
|
|
addCell("timestamp", "alias:ts,hms,hhmmss;desc:time in HH:MM:SS");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
public Table endHeaders() {
|
2014-02-22 17:24:01 +01:00
|
|
|
if (currentCells == null || currentCells.isEmpty()) {
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException("no headers added...");
|
2014-02-22 17:24:01 +01:00
|
|
|
}
|
2013-07-03 21:05:08 +02:00
|
|
|
inHeaders = false;
|
|
|
|
headers = currentCells;
|
|
|
|
currentCells = null;
|
2013-12-23 12:14:25 -06:00
|
|
|
|
|
|
|
/* Create associative structure for columns that
|
|
|
|
* contain the same cells as the rows:
|
|
|
|
*
|
|
|
|
* header1 => [Cell, Cell, ...]
|
|
|
|
* header2 => [Cell, Cell, ...]
|
|
|
|
* header3 => [Cell, Cell, ...]
|
2014-01-11 17:25:07 -06:00
|
|
|
*
|
|
|
|
* Also populate map to look up headers by name.
|
|
|
|
*
|
2013-12-23 12:14:25 -06:00
|
|
|
*/
|
|
|
|
for (Cell header : headers) {
|
2013-12-30 16:12:00 +01:00
|
|
|
map.put(header.value.toString(), new ArrayList<Cell>());
|
2014-01-11 17:25:07 -06:00
|
|
|
headerMap.put(header.value.toString(), header);
|
2013-12-23 12:14:25 -06:00
|
|
|
}
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2019-01-23 10:40:05 +01:00
|
|
|
private static final DateFormatter FORMATTER = DateFormatter.forPattern("HH:mm:ss").withZone(ZoneOffset.UTC);
|
2015-09-11 17:35:29 +09:00
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
public Table startRow() {
|
|
|
|
if (headers.isEmpty()) {
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException("no headers added...");
|
2013-07-03 21:05:08 +02:00
|
|
|
}
|
2014-03-27 15:54:45 +01:00
|
|
|
currentCells = new ArrayList<>(headers.size());
|
2015-09-11 17:35:29 +09:00
|
|
|
if (withTime) {
|
|
|
|
long time = System.currentTimeMillis();
|
|
|
|
addCell(TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS));
|
2018-08-03 13:21:14 +02:00
|
|
|
addCell(FORMATTER.format(Instant.ofEpochMilli(time)));
|
2015-09-11 17:35:29 +09:00
|
|
|
}
|
2013-07-03 21:05:08 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-12-23 12:12:50 -06:00
|
|
|
public Table endRow(boolean check) {
|
2014-02-22 17:24:01 +01:00
|
|
|
if (currentCells == null) {
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException("no row started...");
|
2014-02-22 17:24:01 +01:00
|
|
|
}
|
2013-12-23 12:12:50 -06:00
|
|
|
if (check && (currentCells.size() != headers.size())) {
|
2014-01-03 09:22:02 -06:00
|
|
|
StringBuilder s = new StringBuilder();
|
|
|
|
s.append("mismatch on number of cells ");
|
|
|
|
s.append(currentCells.size());
|
|
|
|
s.append(" in a row compared to header ");
|
|
|
|
s.append(headers.size());
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException(s.toString());
|
2013-07-03 21:05:08 +02:00
|
|
|
}
|
|
|
|
rows.add(currentCells);
|
|
|
|
currentCells = null;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-12-23 12:12:50 -06:00
|
|
|
public Table endRow() {
|
|
|
|
endRow(true);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
public Table addCell(Object value) {
|
|
|
|
return addCell(value, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
public Table addCell(Object value, String attributes) {
|
2014-02-22 17:24:01 +01:00
|
|
|
if (currentCells == null) {
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException("no block started...");
|
2014-02-22 17:24:01 +01:00
|
|
|
}
|
2013-07-03 21:05:08 +02:00
|
|
|
if (!inHeaders) {
|
|
|
|
if (currentCells.size() == headers.size()) {
|
2015-04-28 22:41:15 +02:00
|
|
|
throw new IllegalStateException("can't add more cells to a row than the header");
|
2013-07-03 21:05:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Map<String, String> mAttr;
|
|
|
|
if (attributes.length() == 0) {
|
|
|
|
if (inHeaders) {
|
2015-10-02 00:18:05 +02:00
|
|
|
mAttr = emptyMap();
|
2013-07-03 21:05:08 +02:00
|
|
|
} else {
|
|
|
|
// get the attributes of the header cell we are going to add to
|
|
|
|
mAttr = headers.get(currentCells.size()).attr;
|
|
|
|
}
|
|
|
|
} else {
|
2014-03-27 15:54:45 +01:00
|
|
|
mAttr = new HashMap<>();
|
2013-07-03 21:05:08 +02:00
|
|
|
if (!inHeaders) {
|
|
|
|
// get the attributes of the header cell we are going to add
|
|
|
|
mAttr.putAll(headers.get(currentCells.size()).attr);
|
|
|
|
}
|
2016-05-03 09:12:28 -04:00
|
|
|
String[] sAttrs = attributes.split(";");
|
2013-07-03 21:05:08 +02:00
|
|
|
for (String sAttr : sAttrs) {
|
|
|
|
if (sAttr.length() == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-07-04 18:58:53 -05:00
|
|
|
int idx = sAttr.indexOf(':');
|
2013-07-03 21:05:08 +02:00
|
|
|
mAttr.put(sAttr.substring(0, idx), sAttr.substring(idx + 1));
|
|
|
|
}
|
|
|
|
}
|
2013-12-24 11:01:01 -06:00
|
|
|
|
|
|
|
Cell cell = new Cell(value, mAttr);
|
2013-12-30 16:12:00 +01:00
|
|
|
int cellIndex = currentCells.size();
|
2013-12-24 11:01:01 -06:00
|
|
|
currentCells.add(cell);
|
|
|
|
|
|
|
|
// If we're in a value row, also populate the named column.
|
|
|
|
if (!inHeaders) {
|
2013-12-30 16:12:00 +01:00
|
|
|
String hdr = (String) headers.get(cellIndex).value;
|
2013-12-24 11:01:01 -06:00
|
|
|
map.get(hdr).add(cell);
|
|
|
|
}
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Cell> getHeaders() {
|
|
|
|
return this.headers;
|
|
|
|
}
|
|
|
|
|
2013-12-23 12:14:25 -06:00
|
|
|
public List<List<Cell>> getRows() {
|
2013-07-03 21:05:08 +02:00
|
|
|
return rows;
|
|
|
|
}
|
|
|
|
|
2013-12-30 16:12:00 +01:00
|
|
|
public Map<String, List<Cell>> getAsMap() {
|
|
|
|
return this.map;
|
2013-12-23 12:14:25 -06:00
|
|
|
}
|
|
|
|
|
2014-01-11 17:25:07 -06:00
|
|
|
public Map<String, Cell> getHeaderMap() {
|
|
|
|
return this.headerMap;
|
|
|
|
}
|
|
|
|
|
2013-12-30 16:12:00 +01:00
|
|
|
public Cell findHeaderByName(String header) {
|
|
|
|
for (Cell cell : headers) {
|
|
|
|
if (cell.value.toString().equals(header)) {
|
|
|
|
return cell;
|
2013-12-23 12:12:50 -06:00
|
|
|
}
|
|
|
|
}
|
2013-12-30 16:12:00 +01:00
|
|
|
return null;
|
2013-12-23 12:12:50 -06:00
|
|
|
}
|
|
|
|
|
2016-10-11 09:29:22 -07:00
|
|
|
public Map<String, String> getAliasMap() {
|
|
|
|
Map<String, String> headerAliasMap = new HashMap<>();
|
|
|
|
for (int i = 0; i < headers.size(); i++) {
|
|
|
|
Cell headerCell = headers.get(i);
|
|
|
|
String headerName = headerCell.value.toString();
|
|
|
|
if (headerCell.attr.containsKey("alias")) {
|
|
|
|
String[] aliases = Strings.splitStringByCommaToArray(headerCell.attr.get("alias"));
|
|
|
|
for (String alias : aliases) {
|
|
|
|
headerAliasMap.put(alias, headerName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
headerAliasMap.put(headerName, headerName);
|
|
|
|
}
|
|
|
|
return headerAliasMap;
|
|
|
|
}
|
|
|
|
|
2013-07-03 21:05:08 +02:00
|
|
|
public static class Cell {
|
|
|
|
public final Object value;
|
|
|
|
public final Map<String, String> attr;
|
|
|
|
|
2014-01-03 00:41:26 +01:00
|
|
|
public Cell(Object value, Cell other) {
|
|
|
|
this.value = value;
|
|
|
|
this.attr = other.attr;
|
|
|
|
}
|
|
|
|
|
2013-11-01 16:07:51 -05:00
|
|
|
public Cell(Object value) {
|
|
|
|
this.value = value;
|
2014-03-27 15:54:45 +01:00
|
|
|
this.attr = new HashMap<>();
|
2013-11-01 16:07:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public Cell(Object value, Map<String, String> attr) {
|
2013-07-03 21:05:08 +02:00
|
|
|
this.value = value;
|
|
|
|
this.attr = attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|