mirror of
https://github.com/google/nomulus.git
synced 2025-07-25 20:18:34 +02:00
Import code from internal repository to git
This commit is contained in:
commit
0ef0c933d2
2490 changed files with 281594 additions and 0 deletions
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import com.google.domain.registry.util.TypeUtils.TypeInstantiator;
|
||||
|
||||
import com.googlecode.objectify.impl.Path;
|
||||
import com.googlecode.objectify.impl.Property;
|
||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
||||
import com.googlecode.objectify.impl.translate.ValueTranslator;
|
||||
import com.googlecode.objectify.impl.translate.ValueTranslatorFactory;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/** Common boilerplate for translator factories. */
|
||||
public abstract class AbstractSimpleTranslatorFactory<P, D> extends ValueTranslatorFactory<P, D> {
|
||||
|
||||
public AbstractSimpleTranslatorFactory(Class<P> clazz) {
|
||||
super(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final ValueTranslator<P, D> createSafe(
|
||||
Path path, Property property, Type type, CreateContext ctx) {
|
||||
return new ValueTranslator<P, D>(path, new TypeInstantiator<D>(getClass()){}.getExactType()) {
|
||||
|
||||
SimpleTranslator<P, D> simpleTranslator = createTranslator();
|
||||
|
||||
@Override
|
||||
protected P loadValue(D datastoreValue, LoadContext ctx) {
|
||||
return simpleTranslator.loadValue(datastoreValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected D saveValue(P pojoValue, SaveContext ctx) {
|
||||
return simpleTranslator.saveValue(pojoValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Translator with reduced boilerplate. */
|
||||
interface SimpleTranslator<P, D> {
|
||||
P loadValue(D datastoreValue);
|
||||
|
||||
D saveValue(P pojoValue);
|
||||
}
|
||||
|
||||
abstract SimpleTranslator<P, D> createTranslator();
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import com.google.domain.registry.util.CidrAddressBlock;
|
||||
|
||||
/** Stores {@link CidrAddressBlock} as a canonicalized string. */
|
||||
public class CidrAddressBlockTranslatorFactory
|
||||
extends AbstractSimpleTranslatorFactory<CidrAddressBlock, String> {
|
||||
|
||||
public CidrAddressBlockTranslatorFactory() {
|
||||
super(CidrAddressBlock.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleTranslator<CidrAddressBlock, String> createTranslator() {
|
||||
return new SimpleTranslator<CidrAddressBlock, String>(){
|
||||
@Override
|
||||
public CidrAddressBlock loadValue(String datastoreValue) {
|
||||
return CidrAddressBlock.create(datastoreValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveValue(CidrAddressBlock pojoValue) {
|
||||
return pojoValue.toString();
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.domain.registry.config.RegistryEnvironment;
|
||||
import com.google.domain.registry.model.ofy.CommitLogManifest;
|
||||
|
||||
import com.googlecode.objectify.Ref;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Objectify translator for {@code ImmutableSortedMap<DateTime, Ref<CommitLogManifest>>} fields.
|
||||
*
|
||||
* <p>This translator is responsible for doing three things:
|
||||
* <ol>
|
||||
* <li>Translating the data into two lists of {@code Date} and {@code Key} objects, in a manner
|
||||
* similar to {@code @Mapify}.
|
||||
* <li>Inserting a reference to the transaction's {@link CommitLogManifest} on save.
|
||||
* <li>Truncating the map to include only the last key per day for the last 30 days.
|
||||
* </ol>
|
||||
*
|
||||
* <p>This allows you to have a field on your model object that tracks historical revisions of
|
||||
* itself, which can be binary searched for point-in-time restoration.
|
||||
*
|
||||
* <p><b>Warning:</b> Fields of this type must not be {@code null}, or else new entries can't be
|
||||
* inserted. You must take care to initialize the field to empty.
|
||||
*
|
||||
* @see com.google.domain.registry.model.EppResource
|
||||
*/
|
||||
public final class CommitLogRevisionsTranslatorFactory
|
||||
extends ImmutableSortedMapTranslatorFactory<DateTime, Ref<CommitLogManifest>> {
|
||||
|
||||
private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get();
|
||||
|
||||
/**
|
||||
* Add a reference to the current commit log to the resource's revisions map.
|
||||
*
|
||||
* <p>This method also prunes the revisions map. It guarantees to keep enough data so that floor
|
||||
* will work going back N days. It does this by making sure one entry exists before that duration,
|
||||
* and pruning everything after it. The size of the map is guaranteed to never exceed N+2.
|
||||
*
|
||||
* <p>We store a maximum of one entry per day. It will be the last transaction that happened on
|
||||
* that day.
|
||||
*
|
||||
* @see com.google.domain.registry.config.RegistryConfig#getCommitLogDatastoreRetention()
|
||||
*/
|
||||
@Override
|
||||
ImmutableSortedMap<DateTime, Ref<CommitLogManifest>> transformBeforeSave(
|
||||
ImmutableSortedMap<DateTime, Ref<CommitLogManifest>> revisions) {
|
||||
DateTime now = ofy().getTransactionTime();
|
||||
DateTime threshold = now.minus(ENVIRONMENT.config().getCommitLogDatastoreRetention());
|
||||
DateTime preThresholdTime = firstNonNull(revisions.floorKey(threshold), START_OF_TIME);
|
||||
return new ImmutableSortedMap.Builder<DateTime, Ref<CommitLogManifest>>(Ordering.natural())
|
||||
.putAll(revisions.subMap(preThresholdTime, true, now.withTimeAtStartOfDay(), false))
|
||||
.put(now, Ref.create(ofy().getCommitLogManifestKey()))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.domain.registry.model.CreateAutoTimestamp;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** Saves {@link CreateAutoTimestamp} as either its value, or the current time if it was null. */
|
||||
public class CreateAutoTimestampTranslatorFactory
|
||||
extends AbstractSimpleTranslatorFactory<CreateAutoTimestamp, Date> {
|
||||
|
||||
public CreateAutoTimestampTranslatorFactory() {
|
||||
super(CreateAutoTimestamp.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleTranslator<CreateAutoTimestamp, Date> createTranslator() {
|
||||
return new SimpleTranslator<CreateAutoTimestamp, Date>() {
|
||||
|
||||
/**
|
||||
* Load an existing timestamp. It can be assumed to be non-null since if the field is null in
|
||||
* datastore then Objectify will skip this translator and directly load a null.
|
||||
*/
|
||||
@Override
|
||||
public CreateAutoTimestamp loadValue(Date datastoreValue) {
|
||||
return CreateAutoTimestamp.create(new DateTime(datastoreValue, UTC));
|
||||
}
|
||||
|
||||
/** Save a timestamp, setting it to the current time if it did not have a previous value. */
|
||||
@Override
|
||||
public Date saveValue(CreateAutoTimestamp pojoValue) {
|
||||
return firstNonNull(pojoValue.getTimestamp(), ofy().getTransactionTime()).toDate();
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
/** Adapter to use Joda {@link CurrencyUnit} when marshalling strings. */
|
||||
public class CurrencyUnitAdapter extends XmlAdapter<String, CurrencyUnit> {
|
||||
|
||||
/** Parses a string into a {@link CurrencyUnit} object. */
|
||||
@Override
|
||||
public CurrencyUnit unmarshal(String currency) throws UnknownCurrencyException {
|
||||
try {
|
||||
return CurrencyUnit.of(nullToEmpty(currency).trim());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnknownCurrencyException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts {@link CurrencyUnit} to a string. */
|
||||
@Override
|
||||
public String marshal(CurrencyUnit currency) {
|
||||
return currency == null ? null : currency.toString();
|
||||
}
|
||||
|
||||
/** Exception to throw when failing to parse a currency. */
|
||||
public static class UnknownCurrencyException extends Exception {}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** Stores {@link CurrencyUnit} as a canonicalized string. */
|
||||
public class CurrencyUnitTranslatorFactory
|
||||
extends AbstractSimpleTranslatorFactory<CurrencyUnit, String> {
|
||||
|
||||
public CurrencyUnitTranslatorFactory() {
|
||||
super(CurrencyUnit.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleTranslator<CurrencyUnit, String> createTranslator() {
|
||||
return new SimpleTranslator<CurrencyUnit, String>(){
|
||||
@Override
|
||||
public CurrencyUnit loadValue(String datastoreValue) {
|
||||
return CurrencyUnit.of(datastoreValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveValue(CurrencyUnit pojoValue) {
|
||||
return pojoValue.toString();
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Stores {@link Duration} as a canonicalized string. */
|
||||
public class DurationTranslatorFactory extends AbstractSimpleTranslatorFactory<Duration, String> {
|
||||
|
||||
public DurationTranslatorFactory() {
|
||||
super(Duration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleTranslator<Duration, String> createTranslator() {
|
||||
return new SimpleTranslator<Duration, String>() {
|
||||
@Override
|
||||
public Duration loadValue(String datastoreValue) {
|
||||
return Duration.parse(datastoreValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveValue(Duration pojoValue) {
|
||||
return pojoValue.toString();
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
/**
|
||||
* Used by JAXB to convert enums to the peculiar EPP format that puts the value in an attribute.
|
||||
*
|
||||
* @param <E> the enum type
|
||||
*/
|
||||
public class EnumToAttributeAdapter<E extends Enum<E> & EnumToAttributeAdapter.EppEnum>
|
||||
extends XmlAdapter<EnumToAttributeAdapter.EnumShim, E> {
|
||||
|
||||
/** Interface for epp enums that can be transformed with this adapter. */
|
||||
public interface EppEnum {
|
||||
String getXmlName();
|
||||
}
|
||||
|
||||
/**
|
||||
* EPP's peculiar enum format.
|
||||
* <p>
|
||||
* It's meant to allow more information inside the element, but it's an annoyance when we want to
|
||||
* deal with pure enums.
|
||||
*/
|
||||
static class EnumShim {
|
||||
@XmlAttribute
|
||||
String s;
|
||||
}
|
||||
|
||||
// Enums that can be unmarshalled from input can override this.
|
||||
@Override
|
||||
public E unmarshal(EnumShim shim) throws Exception {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final EnumShim marshal(E enumeration) throws Exception {
|
||||
EnumShim shim = new EnumShim();
|
||||
shim.s = enumeration.getXmlName();
|
||||
return shim;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.domain.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.erase;
|
||||
import static com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector.getTypeParameter;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
import com.googlecode.objectify.impl.Node;
|
||||
import com.googlecode.objectify.impl.Path;
|
||||
import com.googlecode.objectify.impl.Property;
|
||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
||||
import com.googlecode.objectify.impl.translate.ListNodeTranslator;
|
||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
||||
import com.googlecode.objectify.impl.translate.SkipException;
|
||||
import com.googlecode.objectify.impl.translate.Translator;
|
||||
import com.googlecode.objectify.impl.translate.TranslatorFactory;
|
||||
import com.googlecode.objectify.impl.translate.TranslatorRegistry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract Objectify translator for {@link ImmutableSortedMap} fields.
|
||||
*
|
||||
* <p>This class should be extended for each set of concrete key/value types you wish to support.
|
||||
* This translator will only apply to {@code ImmutableSortedMap} model fields that have precicely
|
||||
* the same type parameters you specified.
|
||||
*
|
||||
* <p>This translator serves a similar purpose to
|
||||
* {@link com.googlecode.objectify.impl.translate.MapifyTranslatorFactory @Mapify}. Except this
|
||||
* maintains perfect immutability of the field value. Subclasses may override the
|
||||
* {@link #transformBeforeSave(ImmutableSortedMap)} methods to perform mutation on a per-concrete
|
||||
* type basis. This abstraction is also more readable than {@code @Mapify} because it shifts the
|
||||
* boilerplate into translator magic, rather than convoluting model data structures.
|
||||
*
|
||||
* <h3>Entity Data Layout</h3>
|
||||
*
|
||||
* <p>For example, if you had an {@code ImmutableSortedMap<String, String>} on a field named
|
||||
* {@code field}, then this would look like:<pre> {@code
|
||||
*
|
||||
* field.key -> [key1, key2]
|
||||
* field.value -> [value1, value2]}</pre>
|
||||
*
|
||||
* <p>If you had an {@code ImmutableSortedMap<String, EmbeddedClass>} on a field named
|
||||
* {@code field}, where {@code EmbeddedClass} defines two {@code foo} and {@code bar} fields, then
|
||||
* the embedded properties might look like:<pre> {@code
|
||||
*
|
||||
* field.key -> [key1, key2]
|
||||
* field.value.foo -> [foo1, foo2]
|
||||
* field.value.bar -> [bar1, bar2]}</pre>
|
||||
*
|
||||
* @param <K> key type for sorted map which must be {@link Comparable}
|
||||
* @param <V> value type for sorted map
|
||||
*/
|
||||
abstract class ImmutableSortedMapTranslatorFactory<K extends Comparable<? super K>, V>
|
||||
implements TranslatorFactory<ImmutableSortedMap<K, V>> {
|
||||
|
||||
private final TypeToken<K> keyType = new TypeToken<K>(getClass()) {};
|
||||
private final TypeToken<V> valueType = new TypeToken<V>(getClass()) {};
|
||||
private final String keyProperty;
|
||||
private final String valueProperty;
|
||||
|
||||
ImmutableSortedMapTranslatorFactory() {
|
||||
this("key", "value");
|
||||
}
|
||||
|
||||
/** Constructs a instance that's compatible with models migrated from {@code @Mapify}. */
|
||||
ImmutableSortedMapTranslatorFactory(String keyProperty, String valueProperty) {
|
||||
this.keyProperty = checkNotNull(keyProperty);
|
||||
this.valueProperty = checkNotNull(valueProperty);
|
||||
}
|
||||
|
||||
/** Allows for changing the field data structure before it's written to the raw entity object. */
|
||||
ImmutableSortedMap<K, V> transformBeforeSave(ImmutableSortedMap<K, V> map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Translator<ImmutableSortedMap<K, V>>
|
||||
create(Path path, Property property, Type type, CreateContext ctx) {
|
||||
if (!ImmutableSortedMap.class.equals(erase(type))) {
|
||||
return null; // skip me and try to find another matching translator
|
||||
}
|
||||
Type fieldKeyType = getTypeParameter(type, ImmutableSortedMap.class.getTypeParameters()[0]);
|
||||
Type fieldValueType = getTypeParameter(type, ImmutableSortedMap.class.getTypeParameters()[1]);
|
||||
if (fieldKeyType == null || fieldValueType == null) {
|
||||
return null; // no type information is available
|
||||
}
|
||||
if (!keyType.isSupertypeOf(fieldKeyType) || !valueType.isSupertypeOf(fieldValueType)) {
|
||||
return null; // this ImmutableSortedMap does not have the same concrete component types
|
||||
}
|
||||
ctx.enterCollection(path);
|
||||
ctx.enterEmbed(path);
|
||||
try {
|
||||
// The component types can also be translated by Objectify!
|
||||
TranslatorRegistry translators = ctx.getFactory().getTranslators();
|
||||
final Translator<K> keyTranslator =
|
||||
translators.create(path.extend(keyProperty), property, fieldKeyType, ctx);
|
||||
final Translator<V> valueTranslator =
|
||||
translators.create(path.extend(valueProperty), property, fieldValueType, ctx);
|
||||
return new ListNodeTranslator<ImmutableSortedMap<K, V>>() {
|
||||
@Override
|
||||
protected ImmutableSortedMap<K, V> loadList(Node node, LoadContext ctx) {
|
||||
ImmutableSortedMap.Builder<K, V> map =
|
||||
new ImmutableSortedMap.Builder<>(Ordering.natural());
|
||||
for (Node child : node) {
|
||||
try {
|
||||
map.put(keyTranslator.load(child.get(keyProperty), ctx),
|
||||
valueTranslator.load(child.get(valueProperty), ctx));
|
||||
} catch (SkipException e) {
|
||||
// no problem, just skip that one
|
||||
}
|
||||
}
|
||||
return map.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node saveList(
|
||||
@Nullable ImmutableSortedMap<K, V> mapFromPojo,
|
||||
Path path,
|
||||
boolean index,
|
||||
SaveContext ctx) {
|
||||
checkState(!index, "At path %s: Index not allowed", path);
|
||||
ImmutableSortedMap<K, V> mapToSave = transformBeforeSave(
|
||||
ImmutableSortedMap.copyOfSorted(nullToEmpty(mapFromPojo)));
|
||||
if (mapToSave.isEmpty()) {
|
||||
throw new SkipException(); // the datastore doesn't store empty lists
|
||||
}
|
||||
Node node = new Node(path);
|
||||
for (Map.Entry<K, V> entry : mapToSave.entrySet()) {
|
||||
Node item = new Node(path);
|
||||
item.put(keyProperty,
|
||||
keyTranslator.save(entry.getKey(), path.extend(keyProperty), index, ctx));
|
||||
item.put(valueProperty,
|
||||
valueTranslator.save(entry.getValue(), path.extend(valueProperty), index, ctx));
|
||||
node.addToList(item);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
};
|
||||
} finally {
|
||||
ctx.exitEmbed();
|
||||
ctx.exitCollection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/** Stores {@link InetAddress} as a canonicalized string. */
|
||||
public class InetAddressTranslatorFactory
|
||||
extends AbstractSimpleTranslatorFactory<InetAddress, String> {
|
||||
|
||||
public InetAddressTranslatorFactory() {
|
||||
super(InetAddress.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleTranslator<InetAddress, String> createTranslator() {
|
||||
return new SimpleTranslator<InetAddress, String>() {
|
||||
@Override
|
||||
public InetAddress loadValue(String datastoreValue) {
|
||||
return InetAddresses.forString(datastoreValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveValue(InetAddress pojoValue) {
|
||||
return pojoValue.getHostAddress();
|
||||
}};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import com.googlecode.objectify.impl.Path;
|
||||
import com.googlecode.objectify.impl.Property;
|
||||
import com.googlecode.objectify.impl.TypeUtils;
|
||||
import com.googlecode.objectify.impl.translate.CreateContext;
|
||||
import com.googlecode.objectify.impl.translate.LoadContext;
|
||||
import com.googlecode.objectify.impl.translate.SaveContext;
|
||||
import com.googlecode.objectify.impl.translate.ValueTranslator;
|
||||
import com.googlecode.objectify.impl.translate.ValueTranslatorFactory;
|
||||
import com.googlecode.objectify.repackaged.gentyref.GenericTypeReflector;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.ReadableInstant;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* Stores Joda {@link ReadableInstant} types ({@code DateTime}, etc) as a {@link java.util.Date}.
|
||||
* <p>
|
||||
* This is a fork of the {@code ReadableInstantTranslatorFactory} that comes bundled with Objectify.
|
||||
* The original reifies a {@link ReadableInstant} using the machine's local time zone. This version
|
||||
* always uses UTC.
|
||||
*/
|
||||
public class ReadableInstantUtcTranslatorFactory
|
||||
extends ValueTranslatorFactory<ReadableInstant, Date> {
|
||||
|
||||
public ReadableInstantUtcTranslatorFactory() {
|
||||
super(ReadableInstant.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ValueTranslator<ReadableInstant, Date> createSafe(
|
||||
Path path, Property property, Type type, CreateContext ctx) {
|
||||
final Class<?> clazz = GenericTypeReflector.erase(type);
|
||||
|
||||
return new ValueTranslator<ReadableInstant, Date>(path, Date.class) {
|
||||
@Override
|
||||
protected ReadableInstant loadValue(Date value, LoadContext ctx) {
|
||||
// All the Joda instants have a constructor that will take a Date and timezone.
|
||||
Constructor<?> ctor = TypeUtils.getConstructor(clazz, Object.class, DateTimeZone.class);
|
||||
return (ReadableInstant) TypeUtils.newInstance(ctor, value, DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Date saveValue(ReadableInstant value, SaveContext ctx) {
|
||||
return value.toInstant().toDate();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
|
||||
/** Adapter for {@link StatusValue}. */
|
||||
public class StatusValueAdapter extends EnumToAttributeAdapter<StatusValue> {
|
||||
@Override
|
||||
public StatusValue unmarshal(EnumShim shim) {
|
||||
// The value must be a valid enum value from the xsd, or JAXB will never get this far.
|
||||
return StatusValue.fromXmlName(shim.s);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2016 Google Inc. 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.translators;
|
||||
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.domain.registry.model.UpdateAutoTimestamp;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** Saves {@link UpdateAutoTimestamp} as the current time. */
|
||||
public class UpdateAutoTimestampTranslatorFactory
|
||||
extends AbstractSimpleTranslatorFactory<UpdateAutoTimestamp, Date> {
|
||||
|
||||
public UpdateAutoTimestampTranslatorFactory() {
|
||||
super(UpdateAutoTimestamp.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleTranslator<UpdateAutoTimestamp, Date> createTranslator() {
|
||||
return new SimpleTranslator<UpdateAutoTimestamp, Date>() {
|
||||
|
||||
/**
|
||||
* Load an existing timestamp. It can be assumed to be non-null since if the field is null in
|
||||
* datastore then Objectify will skip this translator and directly load a null.
|
||||
*/
|
||||
@Override
|
||||
public UpdateAutoTimestamp loadValue(Date datastoreValue) {
|
||||
// Load an existing timestamp, or treat it as START_OF_TIME if none exists.
|
||||
return UpdateAutoTimestamp.create(new DateTime(datastoreValue, UTC));
|
||||
}
|
||||
|
||||
/** Save a timestamp, setting it to the current time. */
|
||||
@Override
|
||||
public Date saveValue(UpdateAutoTimestamp pojoValue) {
|
||||
return ofy().getTransactionTime().toDate();
|
||||
}};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue