Skip to content

Commit

Permalink
Add CheckingPeriod and Timeout subclasses to WaitForOption
Browse files Browse the repository at this point in the history
  • Loading branch information
mziccard committed Jun 2, 2016
1 parent e5af988 commit 71cd868
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,15 @@

package com.google.cloud.bigquery;

import static com.google.cloud.WaitForOption.Option.CHECKING_PERIOD;
import static com.google.cloud.WaitForOption.Option.TIMEOUT;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.cloud.Clock;
import com.google.cloud.WaitForOption;
import com.google.cloud.WaitForOption.CheckingPeriod;
import com.google.cloud.WaitForOption.Timeout;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
Expand Down Expand Up @@ -192,14 +189,13 @@ public boolean isDone() {
* this exception is never thrown.
*/
public Job waitFor(WaitForOption... waitOptions) throws InterruptedException, TimeoutException {
Map<WaitForOption.Option, ?> optionMap = WaitForOption.asMap(waitOptions);
CheckingPeriod checkingPeriod = firstNonNull(CHECKING_PERIOD.getCheckingPeriod(optionMap),
CheckingPeriod.defaultInstance());
long timeout = firstNonNull(TIMEOUT.getLong(optionMap), -1L);
Timeout timeout = Timeout.getOrDefault(waitOptions);
CheckingPeriod checkingPeriod = CheckingPeriod.getOrDefault(waitOptions);
long timeoutMillis = timeout.timeoutMillis();
Clock clock = options.clock();
long startTime = clock.millis();
while (!isDone()) {
if (timeout != -1 && (clock.millis() - startTime) >= timeout) {
if (timeoutMillis != -1 && (clock.millis() - startTime) >= timeoutMillis) {
throw new TimeoutException();
}
checkingPeriod.sleep();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@

package com.google.cloud.compute;

import static com.google.cloud.WaitForOption.Option.CHECKING_PERIOD;
import static com.google.cloud.WaitForOption.Option.TIMEOUT;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.cloud.Clock;
Expand Down Expand Up @@ -707,14 +704,13 @@ public boolean isDone() {
*/
public Operation waitFor(WaitForOption... waitOptions)
throws InterruptedException, TimeoutException {
Map<WaitForOption.Option, ?> optionMap = WaitForOption.asMap(waitOptions);
CheckingPeriod checkingPeriod = firstNonNull(CHECKING_PERIOD.getCheckingPeriod(optionMap),
CheckingPeriod.defaultInstance());
long timeout = firstNonNull(TIMEOUT.getLong(optionMap), -1L);
WaitForOption.Timeout timeout = WaitForOption.Timeout.getOrDefault(waitOptions);
CheckingPeriod checkingPeriod = CheckingPeriod.getOrDefault(waitOptions);
long timeoutMillis = timeout.timeoutMillis();
Clock clock = options.clock();
long startTime = clock.millis();
while (!isDone()) {
if (timeout != -1 && (clock.millis() - startTime) >= timeout) {
if (timeoutMillis != -1 && (clock.millis() - startTime) >= timeoutMillis) {
throw new TimeoutException();
}
checkingPeriod.sleep();
Expand Down
160 changes: 99 additions & 61 deletions gcloud-java-core/src/main/java/com/google/cloud/WaitForOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,47 @@

package com.google.cloud;

import static com.google.cloud.WaitForOption.Option.CHECKING_PERIOD;
import static com.google.cloud.WaitForOption.Option.TIMEOUT;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.MoreObjects;
import com.google.common.collect.Maps;

import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
* This class represents options for methods that wait for changes in the status of a resource.
*/
public final class WaitForOption implements Serializable {
public abstract class WaitForOption implements Serializable {

private static final long serialVersionUID = 8443451708032349243L;

private final Option option;
private final Object value;
private final OptionType optionType;

enum OptionType {
CHECKING_PERIOD,
TIMEOUT
}

private WaitForOption(OptionType optionType) {
this.optionType = optionType;
}

/**
* This class holds the actual period and related time unit for the checking period.
* This class represents an option to set how frequently the resource status should be checked.
* Objects of this class keep the actual period and related time unit for the checking period.
*/
public static final class CheckingPeriod implements Serializable {
public static final class CheckingPeriod extends WaitForOption {

private static final long serialVersionUID = -2481062893220539210L;
private static final CheckingPeriod DEFAULT = new CheckingPeriod(500, TimeUnit.MILLISECONDS);

private final long period;
private final TimeUnit unit;

private CheckingPeriod(long period, TimeUnit unit) {
super(OptionType.CHECKING_PERIOD);
this.period = period;
this.unit = unit;
}
Expand Down Expand Up @@ -85,12 +93,14 @@ public boolean equals(Object obj) {
return false;
}
CheckingPeriod other = (CheckingPeriod) obj;
return Objects.equals(period, other.period) && Objects.equals(unit, other.unit);
return baseEquals(other)
&& Objects.equals(period, other.period)
&& Objects.equals(unit, other.unit);
}

@Override
public int hashCode() {
return Objects.hash(period, unit);
return Objects.hash(baseHashCode(), period, unit);
}

@Override
Expand All @@ -102,73 +112,110 @@ public String toString() {
}

/**
* Returns the default checking period (500 milliseconds).
* Returns the {@code CheckingPeriod} option specified in {@code options}. If no
* {@code CheckingPeriod} could be found among {@code options}, the default checking period (500
* milliseconds) is used.
*/
public static CheckingPeriod defaultInstance() {
return new CheckingPeriod(500, TimeUnit.MILLISECONDS);
public static CheckingPeriod getOrDefault(WaitForOption... options) {
return getOrDefaultInternal(OptionType.CHECKING_PERIOD, DEFAULT, options);
}
}

public enum Option {
CHECKING_PERIOD,
TIMEOUT;
/**
* This class represents an option to set the maximum time to wait for the resource's status to
* reach the desired state.
*/
public static final class Timeout extends WaitForOption {

private static final long serialVersionUID = -7120401111985321932L;
private static final Timeout DEFAULT = new Timeout(-1);

@SuppressWarnings("unchecked")
<T> T get(Map<Option, ?> options) {
return (T) options.get(this);
private final long timeoutMillis;

private Timeout(long timeoutMillis) {
super(OptionType.TIMEOUT);
this.timeoutMillis = timeoutMillis;
}

public Long getLong(Map<Option, ?> options) {
return get(options);
/**
* Returns the timeout in milliseconds.
*/
public long timeoutMillis() {
return timeoutMillis;
}

public CheckingPeriod getCheckingPeriod(Map<Option, ?> options) {
return get(options);
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof Timeout)) {
return false;
}
Timeout other = (Timeout) obj;
return baseEquals(other) && Objects.equals(timeoutMillis, other.timeoutMillis);
}
}

private WaitForOption(Option option, Object value) {
this.option = option;
this.value = value;
@Override
public int hashCode() {
return Objects.hash(baseHashCode(), timeoutMillis);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("timeoutMillis", timeoutMillis)
.toString();
}

/**
* Returns the {@code Timeout} option specified in {@code options}. If no {@code Timeout} could
* be found among {@code options}, no timeout will be used.
*/
public static Timeout getOrDefault(WaitForOption... options) {
return getOrDefaultInternal(OptionType.TIMEOUT, DEFAULT, options);
}
}

/**
* Returns the option's type.
*/
public Option option() {
return option;
OptionType optionType() {
return optionType;
}

/**
* Returns the option's value.
*/
public Object value() {
return value;
final boolean baseEquals(WaitForOption option) {
return Objects.equals(option.optionType, option.optionType);
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof WaitForOption)) {
if (obj == null || !(obj.getClass().equals(WaitForOption.class))) {

This comment has been minimized.

Copy link
@aozarov

aozarov Jun 3, 2016

Contributor

I am not sure if you need the equals/hashCode in this class.
Also, this will always be false as this is an abstract class.

return false;
}
WaitForOption other = (WaitForOption) obj;
return Objects.equals(option, other.option) && Objects.equals(value, other.value);
return baseEquals((WaitForOption) obj);
}

final int baseHashCode() {
return Objects.hash(optionType);
}

@Override
public int hashCode() {
return Objects.hash(option, value);
return baseHashCode();
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("name", option.name().toLowerCase())
.add("value", value)
.toString();
@SuppressWarnings("unchecked")
private static <T extends WaitForOption> T getOrDefaultInternal(OptionType optionType,
T defaultValue, WaitForOption... options) {
T foundOption = null;
for (WaitForOption option : options) {
if (option.optionType.equals(optionType)) {
checkArgument(foundOption == null, "Duplicate option %s", option);
foundOption = (T) option;
}
}
return firstNonNull(foundOption, defaultValue);

This comment has been minimized.

Copy link
@aozarov

aozarov Jun 3, 2016

Contributor

Fine as is but will break if we add an option with a null default value.

}

/**
Expand All @@ -177,9 +224,9 @@ public String toString() {
* @param checkEvery the checking period
* @param unit the time unit of the checking period
*/
public static WaitForOption checkEvery(long checkEvery, TimeUnit unit) {
public static CheckingPeriod checkEvery(long checkEvery, TimeUnit unit) {
checkArgument(checkEvery >= 0, "checkEvery must be >= 0");
return new WaitForOption(CHECKING_PERIOD, new CheckingPeriod(checkEvery, unit));
return new CheckingPeriod(checkEvery, unit);
}

/**
Expand All @@ -188,17 +235,8 @@ public static WaitForOption checkEvery(long checkEvery, TimeUnit unit) {
* @param timeout the maximum time to wait, expressed in {@code unit}
* @param unit the time unit of the timeout
*/
public static WaitForOption timeout(long timeout, TimeUnit unit) {
public static Timeout timeout(long timeout, TimeUnit unit) {
checkArgument(timeout >= 0, "timeout must be >= 0");
return new WaitForOption(TIMEOUT, TimeUnit.MILLISECONDS.convert(timeout, unit));
}

public static Map<Option, Object> asMap(WaitForOption... options) {
Map<Option, Object> optionMap = Maps.newEnumMap(Option.class);
for (WaitForOption waitOption : options) {
Object prev = optionMap.put(waitOption.option(), waitOption.value());
checkArgument(prev == null, "Duplicate option %s", waitOption);
}
return optionMap;
return new Timeout(unit.toMillis(timeout));
}
}
Loading

0 comments on commit 71cd868

Please sign in to comment.