mirror of
https://github.com/google/nomulus.git
synced 2025-06-28 23:33:36 +02:00
mv com/google/domain/registry google/registry
This change renames directories in preparation for the great package rename. The repository is now in a broken state because the code itself hasn't been updated. However this should ensure that git correctly preserves history for each file.
This commit is contained in:
parent
a41677aea1
commit
5012893c1d
2396 changed files with 0 additions and 0 deletions
35
java/google/registry/model/common/CrossTldSingleton.java
Normal file
35
java/google/registry/model/common/CrossTldSingleton.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import static com.google.domain.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
|
||||
/** A singleton entity in the datastore. */
|
||||
public abstract class CrossTldSingleton extends ImmutableObject {
|
||||
|
||||
public static final long SINGLETON_ID = 1; // There is always exactly one of these.
|
||||
|
||||
@Id
|
||||
long id = SINGLETON_ID;
|
||||
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
}
|
47
java/google/registry/model/common/EntityGroupRoot.java
Normal file
47
java/google/registry/model/common/EntityGroupRoot.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import com.google.domain.registry.model.BackupGroupRoot;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
|
||||
/**
|
||||
* The root key for the entity group which is known as the cross-tld entity group for historical
|
||||
* reasons.
|
||||
*
|
||||
* <p>This exists as a storage place for common configuration options and global settings that
|
||||
* aren't updated too frequently. Entities in this entity group are usually cached upon load. The
|
||||
* reason this common entity group exists is because it enables strongly consistent queries and
|
||||
* updates across this seldomly updated data. This shared entity group also helps cut down on
|
||||
* a potential ballooning in the number of entity groups enlisted in transactions.
|
||||
*
|
||||
* <p>Historically, each TLD used to have a separate namespace, and all entities for a TLD were in
|
||||
* a single EntityGroupRoot for that TLD. Hence why there was a "cross-tld" entity group -- it was
|
||||
* the entity group for the single namespace where global data applicable for all TLDs lived.
|
||||
*/
|
||||
@Entity
|
||||
public class EntityGroupRoot extends BackupGroupRoot {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
/** The root key for cross-tld resources such as registrars. */
|
||||
public static final Key<EntityGroupRoot> getCrossTldKey() {
|
||||
return Key.create(EntityGroupRoot.class, "cross-tld");
|
||||
}
|
||||
}
|
78
java/google/registry/model/common/GaeUserIdConverter.java
Normal file
78
java/google/registry/model/common/GaeUserIdConverter.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.allocateId;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.annotations.NotBackedUp;
|
||||
import com.google.domain.registry.model.annotations.NotBackedUp.Reason;
|
||||
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.Work;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
|
||||
/**
|
||||
* A helper class to convert email addresses to GAE user ids. It does so by persisting a User
|
||||
* object with the email address to datastore, and then immediately reading it back.
|
||||
*/
|
||||
@Entity
|
||||
@NotBackedUp(reason = Reason.TRANSIENT)
|
||||
public class GaeUserIdConverter extends ImmutableObject {
|
||||
|
||||
@Id
|
||||
public long id;
|
||||
|
||||
User user;
|
||||
|
||||
/**
|
||||
* Converts an email address to a GAE user id.
|
||||
*
|
||||
* @return Numeric GAE user id (in String form), or null if email address has no GAE id
|
||||
*/
|
||||
public static String convertEmailAddressToGaeUserId(String emailAddress) {
|
||||
final GaeUserIdConverter gaeUserIdConverter = new GaeUserIdConverter();
|
||||
gaeUserIdConverter.id = allocateId();
|
||||
gaeUserIdConverter.user =
|
||||
new User(emailAddress, Splitter.on('@').splitToList(emailAddress).get(1));
|
||||
|
||||
try {
|
||||
// Perform these operations in a transactionless context to avoid enlisting in some outer
|
||||
// transaction (if any).
|
||||
ofy().doTransactionless(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().saveWithoutBackup().entity(gaeUserIdConverter).now();
|
||||
}});
|
||||
|
||||
// The read must be done in its own transaction to avoid reading from the session cache.
|
||||
return ofy().transactNew(new Work<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
return ofy().load().entity(gaeUserIdConverter).safe().user.getUserId();
|
||||
}});
|
||||
} finally {
|
||||
ofy().doTransactionless(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().deleteWithoutBackup().entity(gaeUserIdConverter).now();
|
||||
}});
|
||||
}
|
||||
}
|
||||
}
|
56
java/google/registry/model/common/PersistedRangeLong.java
Normal file
56
java/google/registry/model/common/PersistedRangeLong.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
|
||||
/** An object that's equivalent to a {@code Range<Long>} that can be persisted to datastore. */
|
||||
@Embed
|
||||
public class PersistedRangeLong extends ImmutableObject {
|
||||
|
||||
private Long lowerBound = null;
|
||||
private BoundType lowerBoundType = null;
|
||||
|
||||
private Long upperBound = null;
|
||||
private BoundType upperBoundType = null;
|
||||
|
||||
public Range<Long> asRange() {
|
||||
Range<Long> range = Range.all();
|
||||
if (lowerBound != null) {
|
||||
range = range.intersection(Range.downTo(lowerBound, lowerBoundType));
|
||||
}
|
||||
if (upperBound != null) {
|
||||
range = range.intersection(Range.upTo(upperBound, upperBoundType));
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
public static PersistedRangeLong create(Range<Long> range) {
|
||||
PersistedRangeLong instance = new PersistedRangeLong();
|
||||
if (range.hasLowerBound()) {
|
||||
instance.lowerBound = range.lowerEndpoint();
|
||||
instance.lowerBoundType = range.lowerBoundType();
|
||||
}
|
||||
if (range.hasUpperBound()) {
|
||||
instance.upperBound = range.upperEndpoint();
|
||||
instance.upperBoundType = range.upperBoundType();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
93
java/google/registry/model/common/TimeOfYear.java
Normal file
93
java/google/registry/model/common/TimeOfYear.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import static com.google.domain.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import com.googlecode.objectify.annotation.Index;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A time of year (month, day, millis of day) that can be stored in a sort-friendly format.
|
||||
* <p>
|
||||
* This is conceptually similar to {@code MonthDay} in Joda or more generally to Joda's
|
||||
* {@code Partial}, but the parts we need are too simple to justify a full implementation of
|
||||
* {@code Partial}.
|
||||
* <p>
|
||||
* For simplicity, the native representation of this class's data is its stored format. This allows
|
||||
* it to be embeddable with no translation needed and also delays parsing of the string on load
|
||||
* until it's actually needed.
|
||||
*/
|
||||
@Embed
|
||||
public class TimeOfYear extends ImmutableObject {
|
||||
|
||||
/**
|
||||
* The time as "month day millis" with all fields left-padded with zeroes so that lexographic
|
||||
* sorting will do the right thing.
|
||||
*/
|
||||
@Index
|
||||
String timeString;
|
||||
|
||||
/**
|
||||
* Constructs a {@link TimeOfYear} from a {@link DateTime}.
|
||||
* <p>
|
||||
* This handles leap years in an intentionally peculiar way by always treating February 29 as
|
||||
* February 28. It is impossible to construct a {@link TimeOfYear} for February 29th.
|
||||
*/
|
||||
public static TimeOfYear fromDateTime(DateTime dateTime) {
|
||||
DateTime nextYear = dateTime.plusYears(1); // This turns February 29 into February 28.
|
||||
TimeOfYear instance = new TimeOfYear();
|
||||
instance.timeString = String.format(
|
||||
"%02d %02d %08d",
|
||||
nextYear.getMonthOfYear(),
|
||||
nextYear.getDayOfMonth(),
|
||||
nextYear.getMillisOfDay());
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Get the first {@link DateTime} with this month/day/millis that is at or after the start. */
|
||||
public DateTime atOrAfter(DateTime start) {
|
||||
DateTime withSameYear = getDateTimeWithSameYear(start);
|
||||
return isAtOrAfter(withSameYear, start) ? withSameYear : withSameYear.plusYears(1);
|
||||
}
|
||||
|
||||
/** Get the first {@link DateTime} with this month/day/millis that is at or before the end. */
|
||||
public DateTime beforeOrAt(DateTime end) {
|
||||
DateTime withSameYear = getDateTimeWithSameYear(end);
|
||||
return isBeforeOrAt(withSameYear, end) ? withSameYear : withSameYear.minusYears(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new datetime with the same year as the parameter but projected to the month, day, and
|
||||
* time of day of this object.
|
||||
*/
|
||||
private DateTime getDateTimeWithSameYear(DateTime date) {
|
||||
List<String> monthDayMillis = Splitter.on(' ').splitToList(timeString);
|
||||
// Do not be clever and use Ints.stringConverter here. That does radix guessing, and bad things
|
||||
// will happen because of the leading zeroes.
|
||||
return date
|
||||
.withMonthOfYear(Integer.parseInt(monthDayMillis.get(0)))
|
||||
.withDayOfMonth(Integer.parseInt(monthDayMillis.get(1)))
|
||||
.withMillisOfDay(Integer.parseInt(monthDayMillis.get(2)));
|
||||
}
|
||||
}
|
189
java/google/registry/model/common/TimedTransitionProperty.java
Normal file
189
java/google/registry/model/common/TimedTransitionProperty.java
Normal file
|
@ -0,0 +1,189 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed 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
|
||||
//
|
||||
// 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 com.google.domain.registry.model.common;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.latestOf;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.util.TypeUtils;
|
||||
|
||||
import com.googlecode.objectify.mapper.Mapper;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* An entity property whose value transitions over time. Each value it takes on becomes active
|
||||
* at a corresponding instant, and remains active until the next transition occurs. At least one
|
||||
* "start of time" value (corresponding to START_OF_TIME, i.e. the Unix epoch) must be provided
|
||||
* so that the property will have a value for all possible times.
|
||||
* <p>
|
||||
* This concept is naturally represented by a sorted map of {@code DateTime} to {@code V}, but
|
||||
* the AppEngine datastore cannot natively represent a map keyed on non-strings. Instead, we
|
||||
* store an ordered list of transitions and use Objectify's @Mapify annotation to automatically
|
||||
* recreate the sorted map on load from the datastore, which is used as a backing map for this
|
||||
* property; the property itself also implements Map by way of extending ForwardingMap, so that
|
||||
* this property can stored directly as the @Mapify field in the entity.
|
||||
* <p>
|
||||
* The type parameter {@code T} specifies a user-defined subclass of {@code TimedTransition<V>} to
|
||||
* use for storing the list of transitions. The user is given this choice of subclass so that the
|
||||
* field of the value type stored in the transition can be given a customized name.
|
||||
*/
|
||||
public class TimedTransitionProperty<V, T extends TimedTransitionProperty.TimedTransition<V>>
|
||||
extends ForwardingMap<DateTime, T> {
|
||||
|
||||
/**
|
||||
* A transition to a value of type {@code V} at a certain time. This superclass only has a field
|
||||
* for the {@code DateTime}, which means that subclasses should supply the field of type {@code V}
|
||||
* and implementations of the abstract getter and setter methods to access that field. This design
|
||||
* is so that subclasses tagged with @Embed can define a custom field name for their value, for
|
||||
* the purpose of backwards compatibility and better readability of the datastore representation.
|
||||
* <p>
|
||||
* The public visibility of this class exists only so that it can be subclassed; clients should
|
||||
* never call any methods on this class or attempt to access its members, but should instead
|
||||
* treat it as a customizable implementation detail of {@code TimedTransitionProperty}. However,
|
||||
* note that subclasses must also have public visibility so that they can be instantiated via
|
||||
* reflection in a call to {@code fromValueMap}.
|
||||
*/
|
||||
public abstract static class TimedTransition<V> extends ImmutableObject {
|
||||
/** The time at which this value becomes the active value. */
|
||||
private DateTime transitionTime;
|
||||
|
||||
/** Returns the value that this transition will activate. */
|
||||
protected abstract V getValue();
|
||||
|
||||
/** Sets the value that will be activated at this transition's time. */
|
||||
protected abstract void setValue(V value);
|
||||
}
|
||||
|
||||
/** Mapper for use with @Mapify; extracts the time from a TimedTransition to use it as a key. */
|
||||
public static class TimeMapper implements Mapper<DateTime, TimedTransition<?>> {
|
||||
@Override
|
||||
public DateTime getKey(TimedTransition<?> transition) {
|
||||
return transition.transitionTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the provided value map into the equivalent transition map, using transition objects
|
||||
* of the given TimedTransition subclass. The value map must be sorted according to the natural
|
||||
* ordering of its DateTime keys, and keys cannot be earlier than START_OF_TIME.
|
||||
*/
|
||||
// NB: The Class<T> parameter could be eliminated by getting the class via reflection, but then
|
||||
// the callsite cannot infer T, so unless you explicitly call this as .<V, T>fromValueMap() it
|
||||
// will default to using just TimedTransition<V>, which fails at runtime.
|
||||
private static <V, T extends TimedTransition<V>> NavigableMap<DateTime, T> makeTransitionMap(
|
||||
ImmutableSortedMap<DateTime, V> valueMap,
|
||||
final Class<T> timedTransitionSubclass) {
|
||||
checkArgument(
|
||||
Ordering.natural().equals(valueMap.comparator()),
|
||||
"Timed transition value map must have transition time keys in chronological order");
|
||||
return Maps.transformEntries(valueMap, new Maps.EntryTransformer<DateTime, V, T>() {
|
||||
// For each entry in the input value map, make the output map have an entry at the
|
||||
// corresponding time that points to a transition containing that time and that value.
|
||||
@Override
|
||||
public T transformEntry(DateTime transitionTime, V value) {
|
||||
checkArgument(!transitionTime.isBefore(START_OF_TIME),
|
||||
"Timed transition times cannot be earlier than START_OF_TIME / Unix Epoch");
|
||||
T subclass = TypeUtils.instantiate(timedTransitionSubclass);
|
||||
((TimedTransition<V>) subclass).transitionTime = transitionTime;
|
||||
subclass.setValue(value);
|
||||
return subclass;
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new immutable {@code TimedTransitionProperty} representing the given map of DateTime
|
||||
* to value, with transitions constructed using the given {@code TimedTransition} subclass.
|
||||
* <p>
|
||||
* This method should be the normal method for constructing a {@TimedTransitionProperty}.
|
||||
*/
|
||||
public static <V, T extends TimedTransition<V>> TimedTransitionProperty<V, T> fromValueMap(
|
||||
ImmutableSortedMap<DateTime, V> valueMap,
|
||||
final Class<T> timedTransitionSubclass) {
|
||||
return new TimedTransitionProperty<>(ImmutableSortedMap.copyOf(
|
||||
makeTransitionMap(valueMap, timedTransitionSubclass)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new mutable {@code TimedTransitionProperty} representing the given map of DateTime
|
||||
* to value, with transitions constructed using the given {@code TimedTransition} subclass.
|
||||
* <p>
|
||||
* This method should only be used for initializing fields that are declared with the @Mapify
|
||||
* annotation. The map for those fields must be mutable so that Objectify can load values from
|
||||
* the datastore into the map, but clients should still never mutate the field's map directly.
|
||||
*/
|
||||
public static <V, T extends TimedTransition<V>> TimedTransitionProperty<V, T> forMapify(
|
||||
ImmutableSortedMap<DateTime, V> valueMap,
|
||||
Class<T> timedTransitionSubclass) {
|
||||
return new TimedTransitionProperty<>(new TreeMap<>(
|
||||
makeTransitionMap(valueMap, timedTransitionSubclass)));
|
||||
}
|
||||
|
||||
/** The backing map of DateTime to TimedTransition subclass used to store the transitions. */
|
||||
private final NavigableMap<DateTime, T> backingMap;
|
||||
|
||||
/** Returns a new {@code TimedTransitionProperty} backed by the provided map instance. */
|
||||
private TimedTransitionProperty(NavigableMap<DateTime, T> backingMap) {
|
||||
checkArgument(backingMap.get(START_OF_TIME) != null,
|
||||
"Must provide transition entry for the start of time (Unix Epoch)");
|
||||
this.backingMap = backingMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this TimedTransitionProperty is in a valid state, i.e. whether it has a
|
||||
* transition entry for START_OF_TIME, and throws IllegalStateException if not.
|
||||
*/
|
||||
public void checkValidity() {
|
||||
checkState(backingMap.get(START_OF_TIME) != null,
|
||||
"Timed transition values missing required entry for the start of time (Unix Epoch)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NavigableMap<DateTime, T> delegate() {
|
||||
return backingMap;
|
||||
}
|
||||
|
||||
/** Returns the map of DateTime to value that is the "natural" representation of this property. */
|
||||
public ImmutableSortedMap<DateTime, V> toValueMap() {
|
||||
return ImmutableSortedMap.copyOfSorted(Maps.transformValues(
|
||||
backingMap,
|
||||
new Function<T, V>() {
|
||||
@Override
|
||||
public V apply(T timedTransition) {
|
||||
return timedTransition.getValue();
|
||||
}}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the property that is active at the specified time. The active value for
|
||||
* a time before START_OF_TIME is extrapolated to be the value that is active at START_OF_TIME.
|
||||
*/
|
||||
public V getValueAtTime(DateTime time) {
|
||||
// Retrieve the current value by finding the latest transition before or at the given time,
|
||||
// where any given time earlier than START_OF_TIME is replaced by START_OF_TIME.
|
||||
return backingMap.floorEntry(latestOf(START_OF_TIME, time)).getValue().getValue();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue