java.time features it's own halted clock, called a fixed clock, we can
use that one.

On top of that the watcher xcontent parser does not need a clock at all,
just a timestamp when parsing happened.

Original commit: elastic/x-pack-elasticsearch@2061aeffe1
This commit is contained in:
Alexander Reelsen 2018-02-08 09:24:08 +01:00 committed by GitHub
parent 3102b94946
commit 064a0819d9
6 changed files with 29 additions and 92 deletions

View File

@ -1,47 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.common.time;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class HaltedClock extends Clock {
private final DateTime now;
public HaltedClock(DateTime now) {
this.now = now.toDateTime(DateTimeZone.UTC);
}
@Override
public ZoneId getZone() {
return ZoneOffset.UTC;
}
@Override
public Clock withZone(ZoneId zoneId) {
if (zoneId.equals(ZoneOffset.UTC)) {
return this;
}
throw new IllegalArgumentException("Halted clock time zone cannot be changed");
}
@Override
public long millis() {
return now.getMillis();
}
@Override
public Instant instant() {
return Instant.ofEpochMilli(now.getMillis());
}
}

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.xpack.core.watcher.common.secret.Secret; import org.elasticsearch.xpack.core.watcher.common.secret.Secret;
import org.elasticsearch.xpack.core.watcher.crypto.CryptoService; import org.elasticsearch.xpack.core.watcher.crypto.CryptoService;
import org.joda.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.time.Clock; import java.time.Clock;
@ -59,24 +60,17 @@ public class WatcherXContentParser implements XContentParser {
return new Secret(chars); return new Secret(chars);
} }
public static Clock clock(XContentParser parser) { private final DateTime parseTime;
if (parser instanceof WatcherXContentParser) {
return ((WatcherXContentParser) parser).getClock();
}
return Clock.systemUTC();
}
private final Clock clock;
private final XContentParser parser; private final XContentParser parser;
@Nullable private final CryptoService cryptoService; @Nullable private final CryptoService cryptoService;
public WatcherXContentParser(XContentParser parser, Clock clock, @Nullable CryptoService cryptoService) { public WatcherXContentParser(XContentParser parser, DateTime parseTime, @Nullable CryptoService cryptoService) {
this.clock = clock; this.parseTime = parseTime;
this.parser = parser; this.parser = parser;
this.cryptoService = cryptoService; this.cryptoService = cryptoService;
} }
public Clock getClock() { return clock; } public DateTime getParseDateTime() { return parseTime; }
@Override @Override
public XContentType contentType() { public XContentType contentType() {

View File

@ -22,7 +22,6 @@ import org.elasticsearch.xpack.core.watcher.support.xcontent.WatcherXContentPars
import org.joda.time.DateTime; import org.joda.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.time.Clock;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -273,7 +272,7 @@ public class WatchStatus implements ToXContentObject, Streamable {
return builder.endObject(); return builder.endObject();
} }
public static WatchStatus parse(String watchId, XContentParser parser, Clock clock) throws IOException { public static WatchStatus parse(String watchId, WatcherXContentParser parser) throws IOException {
State state = null; State state = null;
ExecutionState executionState = null; ExecutionState executionState = null;
DateTime lastChecked = null; DateTime lastChecked = null;
@ -289,7 +288,7 @@ public class WatchStatus implements ToXContentObject, Streamable {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (Field.STATE.match(currentFieldName)) { } else if (Field.STATE.match(currentFieldName)) {
try { try {
state = State.parse(parser, clock); state = State.parse(parser);
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
throw new ElasticsearchParseException("could not parse watch status for [{}]. failed to parse field [{}]", throw new ElasticsearchParseException("could not parse watch status for [{}]. failed to parse field [{}]",
e, watchId, currentFieldName); e, watchId, currentFieldName);
@ -348,7 +347,7 @@ public class WatchStatus implements ToXContentObject, Streamable {
// this is to support old watches that weren't upgraded yet to // this is to support old watches that weren't upgraded yet to
// contain the state // contain the state
if (state == null) { if (state == null) {
state = new State(true, new DateTime(WatcherXContentParser.clock(parser).millis(), UTC)); state = new State(true, parser.getParseDateTime());
} }
actions = actions == null ? emptyMap() : unmodifiableMap(actions); actions = actions == null ? emptyMap() : unmodifiableMap(actions);
@ -381,12 +380,12 @@ public class WatchStatus implements ToXContentObject, Streamable {
return builder.endObject(); return builder.endObject();
} }
public static State parse(XContentParser parser, Clock clock) throws IOException { public static State parse(XContentParser parser) throws IOException {
if (parser.currentToken() != XContentParser.Token.START_OBJECT) { if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
throw new ElasticsearchParseException("expected an object but found [{}] instead", parser.currentToken()); throw new ElasticsearchParseException("expected an object but found [{}] instead", parser.currentToken());
} }
boolean active = true; boolean active = true;
DateTime timestamp = new DateTime(clock.millis(), UTC); DateTime timestamp = DateTime.now(UTC);
String currentFieldName = null; String currentFieldName = null;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {

View File

@ -6,11 +6,10 @@
package org.elasticsearch.xpack.security.authc.saml; package org.elasticsearch.xpack.security.authc.saml;
import java.time.Clock; import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
import org.elasticsearch.xpack.common.time.HaltedClock;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before; import org.junit.Before;
import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.LogoutRequest; import org.opensaml.saml.saml2.core.LogoutRequest;
@ -67,8 +66,8 @@ public class SamlLogoutRequestMessageBuilderTests extends SamlTestCase {
"http://idp.example.com/saml/logout/artifact"); "http://idp.example.com/saml/logout/artifact");
idpRole.getSingleLogoutServices().add(sloArtifact); idpRole.getSingleLogoutServices().add(sloArtifact);
final DateTime now = DateTime.now(DateTimeZone.UTC); Clock fixedClock = Clock.fixed(Instant.now(), ZoneOffset.UTC);
final SamlLogoutRequestMessageBuilder builder = new SamlLogoutRequestMessageBuilder(new HaltedClock(now), sp, idp, nameId, session); final SamlLogoutRequestMessageBuilder builder = new SamlLogoutRequestMessageBuilder(fixedClock, sp, idp, nameId, session);
final LogoutRequest logoutRequest = builder.build(); final LogoutRequest logoutRequest = builder.build();
assertThat(logoutRequest, notNullValue()); assertThat(logoutRequest, notNullValue());
assertThat(logoutRequest.getReason(), nullValue()); assertThat(logoutRequest.getReason(), nullValue());
@ -82,7 +81,7 @@ public class SamlLogoutRequestMessageBuilderTests extends SamlTestCase {
assertThat(logoutRequest.getConsent(), nullValue()); assertThat(logoutRequest.getConsent(), nullValue());
assertThat(logoutRequest.getNotOnOrAfter(), nullValue()); assertThat(logoutRequest.getNotOnOrAfter(), nullValue());
assertThat(logoutRequest.getIssueInstant(), notNullValue()); assertThat(logoutRequest.getIssueInstant(), notNullValue());
assertThat(logoutRequest.getIssueInstant(), equalTo(now)); assertThat(logoutRequest.getIssueInstant().getMillis(), equalTo(fixedClock.millis()));
assertThat(logoutRequest.getSessionIndexes(), iterableWithSize(1)); assertThat(logoutRequest.getSessionIndexes(), iterableWithSize(1));
assertThat(logoutRequest.getSessionIndexes().get(0).getSessionIndex(), equalTo(session)); assertThat(logoutRequest.getSessionIndexes().get(0).getSessionIndex(), equalTo(session));
assertThat(logoutRequest.getDestination(), equalTo("http://idp.example.com/saml/logout/redirect")); assertThat(logoutRequest.getDestination(), equalTo("http://idp.example.com/saml/logout/redirect"));

View File

@ -32,7 +32,6 @@ import org.elasticsearch.xpack.watcher.condition.InternalAlwaysCondition;
import org.elasticsearch.xpack.watcher.input.InputRegistry; import org.elasticsearch.xpack.watcher.input.InputRegistry;
import org.elasticsearch.xpack.watcher.input.none.ExecutableNoneInput; import org.elasticsearch.xpack.watcher.input.none.ExecutableNoneInput;
import org.elasticsearch.xpack.watcher.trigger.TriggerService; import org.elasticsearch.xpack.watcher.trigger.TriggerService;
import org.elasticsearch.xpack.common.time.HaltedClock;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import java.io.IOException; import java.io.IOException;
@ -53,23 +52,22 @@ public class WatchParser extends AbstractComponent {
private final ActionRegistry actionRegistry; private final ActionRegistry actionRegistry;
private final InputRegistry inputRegistry; private final InputRegistry inputRegistry;
private final CryptoService cryptoService; private final CryptoService cryptoService;
private final Clock clock;
private final ExecutableInput defaultInput; private final ExecutableInput defaultInput;
private final ExecutableCondition defaultCondition; private final ExecutableCondition defaultCondition;
private final List<ActionWrapper> defaultActions; private final List<ActionWrapper> defaultActions;
private final Clock clock;
public WatchParser(Settings settings, TriggerService triggerService, ActionRegistry actionRegistry, InputRegistry inputRegistry, public WatchParser(Settings settings, TriggerService triggerService, ActionRegistry actionRegistry, InputRegistry inputRegistry,
@Nullable CryptoService cryptoService, Clock clock) { @Nullable CryptoService cryptoService, Clock clock) {
super(settings); super(settings);
this.triggerService = triggerService; this.triggerService = triggerService;
this.actionRegistry = actionRegistry; this.actionRegistry = actionRegistry;
this.inputRegistry = inputRegistry; this.inputRegistry = inputRegistry;
this.cryptoService = cryptoService; this.cryptoService = cryptoService;
this.clock = clock;
this.defaultInput = new ExecutableNoneInput(logger); this.defaultInput = new ExecutableNoneInput(logger);
this.defaultCondition = InternalAlwaysCondition.INSTANCE; this.defaultCondition = InternalAlwaysCondition.INSTANCE;
this.defaultActions = Collections.emptyList(); this.defaultActions = Collections.emptyList();
this.clock = clock;
} }
public Watch parse(String name, boolean includeStatus, BytesReference source, XContentType xContentType) throws IOException { public Watch parse(String name, boolean includeStatus, BytesReference source, XContentType xContentType) throws IOException {
@ -102,23 +100,17 @@ public class WatchParser extends AbstractComponent {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("parsing watch [{}] ", source.utf8ToString()); logger.trace("parsing watch [{}] ", source.utf8ToString());
} }
XContentParser parser = null;
try {
// EMPTY is safe here because we never use namedObject // EMPTY is safe here because we never use namedObject
parser = new WatcherXContentParser(xContentType.xContent().createParser(NamedXContentRegistry.EMPTY, source), try (WatcherXContentParser parser = new WatcherXContentParser(xContentType.xContent().createParser(NamedXContentRegistry.EMPTY,
new HaltedClock(now), withSecrets ? cryptoService : null); source), now, withSecrets ? cryptoService : null)) {
parser.nextToken(); parser.nextToken();
return parse(id, includeStatus, parser); return parse(id, includeStatus, parser);
} catch (IOException ioe) { } catch (IOException ioe) {
throw ioException("could not parse watch [{}]", ioe, id); throw ioException("could not parse watch [{}]", ioe, id);
} finally {
if (parser != null) {
parser.close();
}
} }
} }
public Watch parse(String id, boolean includeStatus, XContentParser parser) throws IOException { public Watch parse(String id, boolean includeStatus, WatcherXContentParser parser) throws IOException {
Trigger trigger = null; Trigger trigger = null;
ExecutableInput input = defaultInput; ExecutableInput input = defaultInput;
ExecutableCondition condition = defaultCondition; ExecutableCondition condition = defaultCondition;
@ -161,7 +153,7 @@ public class WatchParser extends AbstractComponent {
metatdata = parser.map(); metatdata = parser.map();
} else if (WatchField.STATUS.match(currentFieldName)) { } else if (WatchField.STATUS.match(currentFieldName)) {
if (includeStatus) { if (includeStatus) {
status = WatchStatus.parse(id, parser, clock); status = WatchStatus.parse(id, parser);
} else { } else {
parser.skipChildren(); parser.skipChildren();
} }
@ -185,11 +177,10 @@ public class WatchParser extends AbstractComponent {
} else { } else {
// we need to create the initial statuses for the actions // we need to create the initial statuses for the actions
Map<String, ActionStatus> actionsStatuses = new HashMap<>(); Map<String, ActionStatus> actionsStatuses = new HashMap<>();
DateTime now = new DateTime(WatcherXContentParser.clock(parser).millis(), UTC);
for (ActionWrapper action : actions) { for (ActionWrapper action : actions) {
actionsStatuses.put(action.id(), new ActionStatus(now)); actionsStatuses.put(action.id(), new ActionStatus(parser.getParseDateTime()));
} }
status = new WatchStatus(now, unmodifiableMap(actionsStatuses)); status = new WatchStatus(parser.getParseDateTime(), unmodifiableMap(actionsStatuses));
} }
return new Watch(id, trigger, input, condition, transform, throttlePeriod, actions, metatdata, status); return new Watch(id, trigger, input, condition, transform, throttlePeriod, actions, metatdata, status);

View File

@ -122,6 +122,8 @@ import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import java.time.Clock; import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -179,9 +181,8 @@ public class WatchTests extends ESTestCase {
} }
public void testParserSelfGenerated() throws Exception { public void testParserSelfGenerated() throws Exception {
DateTime now = new DateTime(UTC); Clock clock = Clock.fixed(Instant.now(), ZoneOffset.UTC);
ClockMock clock = ClockMock.frozen(); DateTime now = new DateTime(clock.millis(), UTC);
clock.setTime(now);
TransformRegistry transformRegistry = transformRegistry(); TransformRegistry transformRegistry = transformRegistry();
boolean includeStatus = randomBoolean(); boolean includeStatus = randomBoolean();
Schedule schedule = randomSchedule(); Schedule schedule = randomSchedule();
@ -207,7 +208,7 @@ public class WatchTests extends ESTestCase {
for (ActionWrapper action : actions) { for (ActionWrapper action : actions) {
actionsStatuses.put(action.id(), new ActionStatus(now)); actionsStatuses.put(action.id(), new ActionStatus(now));
} }
WatchStatus watchStatus = new WatchStatus(new DateTime(clock.millis()), unmodifiableMap(actionsStatuses)); WatchStatus watchStatus = new WatchStatus(now, unmodifiableMap(actionsStatuses));
TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10000)); TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10000));