diff --git a/.gcloudignore b/.gcloudignore index 45fa789b3..b88eae780 100644 --- a/.gcloudignore +++ b/.gcloudignore @@ -6,5 +6,4 @@ node_modules/ repos/** **/.idea/ *.jar -!third_party/**/*.jar !/gradle/wrapper/**/*.jar diff --git a/.gitignore b/.gitignore index 8df13bbd0..56c776c28 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ gjf.out *.jar *.war *.ear -!/third_party/**/*.jar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/build.gradle b/build.gradle index b83a3c33b..bcb606ade 100644 --- a/build.gradle +++ b/build.gradle @@ -355,8 +355,6 @@ subprojects { } } - if (project.name == 'third_party') return - project.tasks.test.dependsOn runPresubmits def commonlyExcludedResources = ['**/*.java', '**/BUILD'] diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index a1199ee46..51abd1124 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -43,12 +43,6 @@ by Joshua Bloch in his book Effective Java --> - - - - - - @@ -58,7 +52,7 @@ by Joshua Bloch in his book Effective Java --> - + diff --git a/core/build.gradle b/core/build.gradle index 7041faf21..e1bd92714 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -163,11 +163,6 @@ configurations { dependencies { def deps = rootProject.dependencyMap - // Custom-built objectify jar at commit ecd5165, included in Nomulus - // release. - implementation files( - "${rootDir}/third_party/objectify/v4_1/objectify-4.1.3.jar") - testRuntimeOnly files(sourceSets.test.resources.srcDirs) implementation deps['com.beust:jcommander'] diff --git a/core/src/main/java/google/registry/beam/common/RegistryPipelineWorkerInitializer.java b/core/src/main/java/google/registry/beam/common/RegistryPipelineWorkerInitializer.java index baaa861c1..0f849aa42 100644 --- a/core/src/main/java/google/registry/beam/common/RegistryPipelineWorkerInitializer.java +++ b/core/src/main/java/google/registry/beam/common/RegistryPipelineWorkerInitializer.java @@ -21,7 +21,6 @@ import com.google.common.flogger.FluentLogger; import dagger.Lazy; import google.registry.config.RegistryEnvironment; import google.registry.config.SystemPropertySetter; -import google.registry.model.AppEngineEnvironment; import google.registry.model.IdService; import google.registry.persistence.transaction.JpaTransactionManager; import google.registry.persistence.transaction.TransactionManagerFactory; @@ -63,10 +62,6 @@ public class RegistryPipelineWorkerInitializer implements JvmInitializer { transactionManagerLazy = registryPipelineComponent.getJpaTransactionManager(); } TransactionManagerFactory.setJpaTmOnBeamWorker(transactionManagerLazy::get); - // Masquerade all threads as App Engine threads, so we can create Ofy keys in the pipeline. Also - // loads all ofy entities. - new AppEngineEnvironment("s~" + registryPipelineComponent.getProjectId()) - .setEnvironmentForAllThreads(); SystemPropertySetter.PRODUCTION_IMPL.setProperty(PROPERTY, "true"); // Use self-allocated IDs if requested. Note that this inevitably results in duplicate IDs from // multiple workers, which can also collide with existing IDs in the database. So they cannot be diff --git a/core/src/main/java/google/registry/env/common/backend/WEB-INF/web.xml b/core/src/main/java/google/registry/env/common/backend/WEB-INF/web.xml index 573a57d06..a13a5b795 100644 --- a/core/src/main/java/google/registry/env/common/backend/WEB-INF/web.xml +++ b/core/src/main/java/google/registry/env/common/backend/WEB-INF/web.xml @@ -341,24 +341,4 @@ have been in the database for a certain period of time. --> CONFIDENTIAL - - - - ObjectifyFilter - com.googlecode.objectify.ObjectifyFilter - - - ObjectifyFilter - /* - - - - - OfyFilter - google.registry.model.ofy.OfyFilter - - - OfyFilter - /* - diff --git a/core/src/main/java/google/registry/env/common/default/WEB-INF/web.xml b/core/src/main/java/google/registry/env/common/default/WEB-INF/web.xml index 175dc53c5..d76ab31b0 100644 --- a/core/src/main/java/google/registry/env/common/default/WEB-INF/web.xml +++ b/core/src/main/java/google/registry/env/common/default/WEB-INF/web.xml @@ -139,24 +139,4 @@ CONFIDENTIAL - - - - ObjectifyFilter - com.googlecode.objectify.ObjectifyFilter - - - ObjectifyFilter - /* - - - - - OfyFilter - google.registry.model.ofy.OfyFilter - - - OfyFilter - /* - diff --git a/core/src/main/java/google/registry/env/common/pubapi/WEB-INF/web.xml b/core/src/main/java/google/registry/env/common/pubapi/WEB-INF/web.xml index 2cd19223d..24f2fd6a5 100644 --- a/core/src/main/java/google/registry/env/common/pubapi/WEB-INF/web.xml +++ b/core/src/main/java/google/registry/env/common/pubapi/WEB-INF/web.xml @@ -105,24 +105,4 @@ CONFIDENTIAL - - - - ObjectifyFilter - com.googlecode.objectify.ObjectifyFilter - - - ObjectifyFilter - /* - - - - - OfyFilter - google.registry.model.ofy.OfyFilter - - - OfyFilter - /* - diff --git a/core/src/main/java/google/registry/env/common/tools/WEB-INF/web.xml b/core/src/main/java/google/registry/env/common/tools/WEB-INF/web.xml index c8d46ed83..a305d6674 100644 --- a/core/src/main/java/google/registry/env/common/tools/WEB-INF/web.xml +++ b/core/src/main/java/google/registry/env/common/tools/WEB-INF/web.xml @@ -135,24 +135,4 @@ CONFIDENTIAL - - - - ObjectifyFilter - com.googlecode.objectify.ObjectifyFilter - - - ObjectifyFilter - /* - - - - - OfyFilter - google.registry.model.ofy.OfyFilter - - - OfyFilter - /* - diff --git a/core/src/main/java/google/registry/model/AppEngineEnvironment.java b/core/src/main/java/google/registry/model/AppEngineEnvironment.java deleted file mode 100644 index 80f2942d2..000000000 --- a/core/src/main/java/google/registry/model/AppEngineEnvironment.java +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2020 The Nomulus 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 google.registry.model; - -import com.google.apphosting.api.ApiProxy; -import com.google.apphosting.api.ApiProxy.Environment; -import com.google.common.collect.ImmutableMap; -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.model.ofy.ObjectifyService; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -/** - * Sets up a fake {@link Environment} so that the following operations can be performed without the - * Datastore service: - * - *
    - *
  • Create Objectify {@code Keys}. - *
  • Instantiate Objectify objects. - *
  • Convert Datastore {@code Entities} to their corresponding Objectify objects. - *
- * - *

User has the option to specify their desired {@code appId} string, which forms part of an - * Objectify {@code Key} and is included in the equality check. This feature makes it easy to - * compare a migrated object in SQL with the original in Objectify. - * - *

Note that conversion from Objectify objects to Datastore {@code Entities} still requires the - * Datastore service. - */ -@DeleteAfterMigration -public class AppEngineEnvironment { - - private Environment environment; - - /** - * Constructor for use by tests. - * - *

All test suites must use the same appId for environments, since when tearing down we do not - * clear cached environments in spawned threads. See {@link #unsetEnvironmentForAllThreads} for - * more information. - */ - public AppEngineEnvironment() { - /** - * Use AppEngineExtension's appId here so that ofy and sql entities can be compared with {@code - * Objects#equals()}. The choice of this value does not impact functional correctness. - */ - this("test"); - } - - /** Constructor for use by applications, e.g., BEAM pipelines. */ - public AppEngineEnvironment(String appId) { - environment = createAppEngineEnvironment(appId); - } - - public void setEnvironmentForCurrentThread() { - ApiProxy.setEnvironmentForCurrentThread(environment); - ObjectifyService.initOfy(); - } - - public void setEnvironmentForAllThreads() { - setEnvironmentForCurrentThread(); - ApiProxy.setEnvironmentFactory(() -> environment); - } - - public void unsetEnvironmentForCurrentThread() { - ApiProxy.clearEnvironmentForCurrentThread(); - } - - /** - * Unsets the test environment in all threads with best effort. - * - *

This method unsets the environment factory and clears the cached environment in the current - * thread (the main test runner thread). We do not clear the cache in spawned threads, even though - * they may be reused. This is not a problem as long as the appId stays the same: those threads - * are used only in AppEngine or BEAM tests, and expect the presence of an environment. - */ - public void unsetEnvironmentForAllThreads() { - unsetEnvironmentForCurrentThread(); - - try { - Method method = ApiProxy.class.getDeclaredMethod("clearEnvironmentFactory"); - method.setAccessible(true); - method.invoke(null); - } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** Returns a placeholder {@link Environment} that can return hardcoded AppId and Attributes. */ - private static Environment createAppEngineEnvironment(String appId) { - return (Environment) - Proxy.newProxyInstance( - Environment.class.getClassLoader(), - new Class[] {Environment.class}, - (Object proxy, Method method, Object[] args) -> { - switch (method.getName()) { - case "getAppId": - return appId; - case "getAttributes": - return ImmutableMap.of(); - default: - throw new UnsupportedOperationException(method.getName()); - } - }); - } - - /** Returns true if the current thread is in an App Engine Environment. */ - public static boolean isInAppEngineEnvironment() { - return ApiProxy.getCurrentEnvironment() != null; - } -} diff --git a/core/src/main/java/google/registry/model/CacheUtils.java b/core/src/main/java/google/registry/model/CacheUtils.java index 37519c3ad..567b2524f 100644 --- a/core/src/main/java/google/registry/model/CacheUtils.java +++ b/core/src/main/java/google/registry/model/CacheUtils.java @@ -18,13 +18,9 @@ import static com.google.common.base.Suppliers.memoizeWithExpiration; import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Supplier; -import google.registry.model.annotations.DeleteAfterMigration; import java.time.Duration; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; /** Utility methods related to caching Datastore entities. */ public class CacheUtils { @@ -77,29 +73,4 @@ public class CacheUtils { } return caffeine; } - - /** - * A {@link CacheLoader} that automatically masquerade the background thread where the refresh - * action runs in to be an GAE thread. - */ - @DeleteAfterMigration - public abstract static class AppEngineEnvironmentCacheLoader implements CacheLoader { - - private static final AppEngineEnvironment environment = new AppEngineEnvironment(); - - @Override - public @Nullable V reload(@NonNull K key, @NonNull V oldValue) throws Exception { - V value; - boolean isMasqueraded = false; - if (!AppEngineEnvironment.isInAppEngineEnvironment()) { - environment.setEnvironmentForCurrentThread(); - isMasqueraded = true; - } - value = load(key); - if (isMasqueraded) { - environment.unsetEnvironmentForCurrentThread(); - } - return value; - } - } } diff --git a/core/src/main/java/google/registry/model/EppResource.java b/core/src/main/java/google/registry/model/EppResource.java index 60d6c0aa1..b325ca73d 100644 --- a/core/src/main/java/google/registry/model/EppResource.java +++ b/core/src/main/java/google/registry/model/EppResource.java @@ -32,7 +32,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import google.registry.config.RegistryConfig; -import google.registry.model.CacheUtils.AppEngineEnvironmentCacheLoader; import google.registry.model.annotations.IdAllocation; import google.registry.model.eppcommon.StatusValue; import google.registry.model.transfer.TransferData; @@ -354,7 +353,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B } static final CacheLoader, EppResource> CACHE_LOADER = - new AppEngineEnvironmentCacheLoader, EppResource>() { + new CacheLoader, EppResource>() { @Override public EppResource load(VKey key) { diff --git a/core/src/main/java/google/registry/model/IdService.java b/core/src/main/java/google/registry/model/IdService.java index a375d89fc..02f4007c0 100644 --- a/core/src/main/java/google/registry/model/IdService.java +++ b/core/src/main/java/google/registry/model/IdService.java @@ -22,7 +22,6 @@ import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.common.flogger.FluentLogger; import google.registry.beam.common.RegistryPipelineWorkerInitializer; import google.registry.config.RegistryEnvironment; -import google.registry.model.annotations.DeleteAfterMigration; import google.registry.model.common.DatabaseMigrationStateSchedule; import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState; import java.math.BigInteger; @@ -33,7 +32,6 @@ import org.joda.time.DateTime; /** * Allocates a {@link long} to use as a {@code @Id}, (part) of the primary SQL key for an entity. */ -@DeleteAfterMigration public final class IdService { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); diff --git a/core/src/main/java/google/registry/model/annotations/NotBackedUp.java b/core/src/main/java/google/registry/model/annotations/NotBackedUp.java deleted file mode 100644 index 68346284e..000000000 --- a/core/src/main/java/google/registry/model/annotations/NotBackedUp.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.annotations; - -import com.googlecode.objectify.annotation.Entity; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for an Objectify {@link Entity} to indicate that it should not be backed up by the - * default Datastore backup configuration (it may be backed up by something else). - */ -@DeleteAfterMigration -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface NotBackedUp { - Reason reason(); - - /** Reasons why a given entity does not need to be be backed up. */ - enum Reason { - /** This entity is transient by design and has only a short-term useful lifetime. */ - TRANSIENT, - - /** This entity's data is already regularly pulled down from an external source. */ - EXTERNALLY_SOURCED, - - /** This entity is generated automatically by the app and will be recreated if need be. */ - AUTO_GENERATED, - - /** Commit log entities are exported separately from the regular backups, by design. */ - COMMIT_LOGS - } -} diff --git a/core/src/main/java/google/registry/model/annotations/VirtualEntity.java b/core/src/main/java/google/registry/model/annotations/VirtualEntity.java deleted file mode 100644 index 46e89c8b8..000000000 --- a/core/src/main/java/google/registry/model/annotations/VirtualEntity.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.annotations; - -import com.googlecode.objectify.annotation.Entity; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation for an Objectify {@link Entity} to indicate that it is a "virtual entity". - * - *

A virtual entity type exists only to define part of the parentage key hierarchy for its child - * entities, and is never actually persisted and thus has no fields besides its ID field. - */ -@DeleteAfterMigration -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface VirtualEntity {} diff --git a/core/src/main/java/google/registry/model/common/GaeUserIdConverter.java b/core/src/main/java/google/registry/model/common/GaeUserIdConverter.java deleted file mode 100644 index dcff7ebb7..000000000 --- a/core/src/main/java/google/registry/model/common/GaeUserIdConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.common; - -import static com.google.common.base.Preconditions.checkState; -import static google.registry.model.IdService.allocateId; -import static google.registry.model.ofy.ObjectifyService.auditedOfy; - -import com.google.appengine.api.users.User; -import com.google.common.base.Splitter; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.Id; -import google.registry.model.ImmutableObject; -import google.registry.model.annotations.NotBackedUp; -import google.registry.model.annotations.NotBackedUp.Reason; -import java.util.List; - -/** - * 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(); - List emailParts = Splitter.on('@').splitToList(emailAddress); - checkState(emailParts.size() == 2, "'%s' is not a valid email address", emailAddress); - gaeUserIdConverter.user = new User(emailAddress, emailParts.get(1)); - - try { - // Perform these operations in a transactionless context to avoid enlisting in some outer - // transaction (if any). - auditedOfy() - .doTransactionless( - () -> { - auditedOfy().saveWithoutBackup().entity(gaeUserIdConverter).now(); - return null; - }); - // The read must be done in its own transaction to avoid reading from the session cache. - return auditedOfy() - .transactNew(() -> auditedOfy().load().entity(gaeUserIdConverter).now().user.getUserId()); - } finally { - auditedOfy() - .doTransactionless( - () -> auditedOfy().deleteWithoutBackup().entity(gaeUserIdConverter).now()); - } - } -} diff --git a/core/src/main/java/google/registry/model/ofy/AugmentedDeleter.java b/core/src/main/java/google/registry/model/ofy/AugmentedDeleter.java deleted file mode 100644 index 94a6c33a9..000000000 --- a/core/src/main/java/google/registry/model/ofy/AugmentedDeleter.java +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.googlecode.objectify.ObjectifyService.ofy; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Streams; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.Result; -import com.googlecode.objectify.cmd.DeleteType; -import com.googlecode.objectify.cmd.Deleter; -import google.registry.model.annotations.DeleteAfterMigration; -import java.util.Arrays; -import java.util.stream.Stream; - -/** - * A Deleter that forwards to {@code auditedOfy().delete()}, but can be augmented via subclassing to - * do custom processing on the keys to be deleted prior to their deletion. - */ -@DeleteAfterMigration -abstract class AugmentedDeleter implements Deleter { - private final Deleter delegate = ofy().delete(); - - /** Extension method to allow this Deleter to do extra work prior to the actual delete. */ - protected abstract void handleDeletion(Iterable> keys); - - private void handleDeletionStream(Stream entityStream) { - handleDeletion(entityStream.map(Key::create).collect(toImmutableList())); - } - - @Override - public Result entities(Iterable entities) { - handleDeletionStream(Streams.stream(entities)); - return delegate.entities(entities); - } - - @Override - public Result entities(Object... entities) { - handleDeletionStream(Arrays.stream(entities)); - return delegate.entities(entities); - } - - @Override - public Result entity(Object entity) { - handleDeletionStream(Stream.of(entity)); - return delegate.entity(entity); - } - - @Override - public Result key(Key key) { - handleDeletion(ImmutableList.of(key)); - return delegate.keys(key); - } - - @Override - public Result keys(Iterable> keys) { - // Magic to convert the type Iterable> (a family of types which allows for - // homogeneous iterables of a fixed Key type, e.g. List>, and is convenient for - // callers) into the type Iterable> (a concrete type of heterogeneous keys, which is - // convenient for users). - handleDeletion(ImmutableList.copyOf(keys)); - return delegate.keys(keys); - } - - @Override - public Result keys(Key... keys) { - handleDeletion(Arrays.asList(keys)); - return delegate.keys(keys); - } - - /** Augmenting this gets ugly; you can always just use keys(Key.create(...)) instead. */ - @Override - public DeleteType type(Class clazz) { - throw new UnsupportedOperationException(); - } -} diff --git a/core/src/main/java/google/registry/model/ofy/AugmentedSaver.java b/core/src/main/java/google/registry/model/ofy/AugmentedSaver.java deleted file mode 100644 index 9896572c0..000000000 --- a/core/src/main/java/google/registry/model/ofy/AugmentedSaver.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.googlecode.objectify.ObjectifyService.ofy; - -import com.google.appengine.api.datastore.Entity; -import com.google.common.collect.ImmutableList; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.Result; -import com.googlecode.objectify.cmd.Saver; -import google.registry.model.annotations.DeleteAfterMigration; -import java.util.Arrays; -import java.util.Map; - -/** - * A Saver that forwards to {@code ofy().save()}, but can be augmented via subclassing to do custom - * processing on the entities to be saved prior to their saving. - */ -@DeleteAfterMigration -abstract class AugmentedSaver implements Saver { - private final Saver delegate = ofy().save(); - - /** Extension method to allow this Saver to do extra work prior to the actual save. */ - protected abstract void handleSave(Iterable entities); - - @Override - public Result, E>> entities(Iterable entities) { - handleSave(entities); - return delegate.entities(entities); - } - - @Override - @SafeVarargs - public final Result, E>> entities(E... entities) { - handleSave(Arrays.asList(entities)); - return delegate.entities(entities); - } - - @Override - public Result> entity(E entity) { - handleSave(ImmutableList.of(entity)); - return delegate.entity(entity); - } - - @Override - public Entity toEntity(Object pojo) { - // No call to the extension method, since toEntity() doesn't do any actual saving. - return delegate.toEntity(pojo); - } -} diff --git a/core/src/main/java/google/registry/model/ofy/CommitLoggedWork.java b/core/src/main/java/google/registry/model/ofy/CommitLoggedWork.java deleted file mode 100644 index 736d2d178..000000000 --- a/core/src/main/java/google/registry/model/ofy/CommitLoggedWork.java +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.collect.ImmutableSet; -import google.registry.model.ImmutableObject; -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.util.Clock; -import java.util.function.Supplier; - -/** Wrapper for {@link Supplier} that associates a time with each attempt. */ -@DeleteAfterMigration -public class CommitLoggedWork implements Runnable { - - private final Supplier work; - private final Clock clock; - - /** - * Temporary place to store the result of a non-void work. - * - *

We don't want to return the result directly because we are going to try to recover from a - * {@link com.google.appengine.api.datastore.DatastoreTimeoutException} deep inside Objectify when - * it tries to commit the transaction. When an exception is thrown the return value would be lost, - * but sometimes we will be able to determine that we actually succeeded despite the timeout, and - * we'll want to get the result. - */ - private R result; - - /** - * Temporary place to store the mutations belonging to the commit log manifest. - * - *

These are used along with the manifest to determine whether a transaction succeeded. - */ - protected ImmutableSet mutations = ImmutableSet.of(); - - /** Lifecycle marker to track whether {@link #run} has been called. */ - private boolean runCalled; - - CommitLoggedWork(Supplier work, Clock clock) { - this.work = work; - this.clock = clock; - } - - protected TransactionInfo createNewTransactionInfo() { - return new TransactionInfo(clock.nowUtc()); - } - - boolean hasRun() { - return runCalled; - } - - R getResult() { - checkState(runCalled, "Cannot call getResult() before run()"); - return result; - } - - @Override - public void run() { - // The previous time will generally be null, except when using transactNew. - TransactionInfo previous = Ofy.TRANSACTION_INFO.get(); - // Set the time to be used for "now" within the transaction. - try { - Ofy.TRANSACTION_INFO.set(createNewTransactionInfo()); - result = work.get(); - } finally { - Ofy.TRANSACTION_INFO.set(previous); - } - runCalled = true; - } -} diff --git a/core/src/main/java/google/registry/model/ofy/ObjectifyService.java b/core/src/main/java/google/registry/model/ofy/ObjectifyService.java deleted file mode 100644 index ff3b41abc..000000000 --- a/core/src/main/java/google/registry/model/ofy/ObjectifyService.java +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.ImmutableSet.toImmutableSet; -import static com.googlecode.objectify.ObjectifyService.factory; -import static google.registry.util.TypeUtils.hasAnnotation; - -import com.google.appengine.api.datastore.AsyncDatastoreService; -import com.google.appengine.api.datastore.DatastoreServiceConfig; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Streams; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.ObjectifyFactory; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.EntitySubclass; -import google.registry.config.RegistryEnvironment; -import google.registry.model.Buildable; -import google.registry.model.ImmutableObject; -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.model.common.GaeUserIdConverter; - -/** - * An instance of Ofy, obtained via {@code #auditedOfy()}, should be used to access all persistable - * objects. The class contains a static initializer to call factory().register(...) on all - * persistable objects in this package. - */ -@DeleteAfterMigration -public class ObjectifyService { - - /** A singleton instance of our Ofy wrapper. */ - private static final Ofy OFY = new Ofy(null); - - /** - * Returns the singleton {@link Ofy} instance, signifying that the caller has been audited for the - * Registry 3.0 conversion. - */ - public static Ofy auditedOfy() { - return OFY; - } - - static { - initOfyOnce(); - } - - /** Ensures that Objectify has been fully initialized. */ - public static void initOfy() { - // This method doesn't actually do anything; it's here so that callers have something to call - // to ensure that the static initialization of ObjectifyService has been performed (which Java - // guarantees will happen exactly once, before any static methods are invoked). - // - // See JLS section 12.4: http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4 - } - - /** - * Performs static initialization for Objectify to register types and do other setup. - * - *

This method is non-idempotent, so it should only be called exactly once, which is achieved - * by calling it from this class's static initializer block. - */ - private static void initOfyOnce() { - // Set an ObjectifyFactory that uses our extended ObjectifyImpl. - // The "false" argument means that we are not using the v5-style Objectify embedded entities. - com.googlecode.objectify.ObjectifyService.setFactory( - new ObjectifyFactory(false) { - @Override - protected AsyncDatastoreService createRawAsyncDatastoreService( - DatastoreServiceConfig cfg) { - // In the unit test environment, wrap the Datastore service in a proxy that can be used - // to examine the number of requests sent to Datastore. - AsyncDatastoreService service = super.createRawAsyncDatastoreService(cfg); - return RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST) - ? new RequestCapturingAsyncDatastoreService(service) - : service; - } - }); - - registerEntityClasses(ImmutableSet.of(GaeUserIdConverter.class)); - } - - /** Register classes that can be persisted via Objectify as Datastore entities. */ - private static void registerEntityClasses( - ImmutableSet> entityClasses) { - // Register all the @Entity classes before any @EntitySubclass classes so that we can check - // that every @Entity registration is a new kind and every @EntitySubclass registration is not. - // This is future-proofing for Objectify 5.x where the registration logic gets less lenient. - - for (Class clazz : - Streams.concat( - entityClasses.stream().filter(hasAnnotation(Entity.class)), - entityClasses.stream().filter(hasAnnotation(Entity.class).negate())) - .collect(toImmutableSet())) { - String kind = Key.getKind(clazz); - boolean registered = factory().getMetadata(kind) != null; - if (clazz.isAnnotationPresent(Entity.class)) { - // Objectify silently replaces current registration for a given kind string when a different - // class is registered again for this kind. For simplicity's sake, throw an exception on any - // re-registration. - checkState( - !registered, - "Kind '%s' already registered, cannot register new @Entity %s", - kind, - clazz.getCanonicalName()); - } else if (clazz.isAnnotationPresent(EntitySubclass.class)) { - // Ensure that any @EntitySubclass classes have also had their parent @Entity registered, - // which Objectify nominally requires but doesn't enforce in 4.x (though it may in 5.x). - checkState( - registered, - "No base entity for kind '%s' registered yet, cannot register new @EntitySubclass %s", - kind, - clazz.getCanonicalName()); - } - com.googlecode.objectify.ObjectifyService.register(clazz); - // Autogenerated ids make the commit log code very difficult since we won't always be able - // to create a key for an entity immediately when requesting a save. So, we require such - // entities to implement google.registry.model.Buildable as its build() function allocates the - // id to the entity. - if (factory().getMetadata(clazz).getKeyMetadata().isIdGeneratable()) { - checkState( - Buildable.class.isAssignableFrom(clazz), - "Can't register %s: Entity with autogenerated ids (@Id on a Long) must implement" - + " google.registry.model.Buildable.", - kind); - } - } - } -} diff --git a/core/src/main/java/google/registry/model/ofy/Ofy.java b/core/src/main/java/google/registry/model/ofy/Ofy.java deleted file mode 100644 index 5821a0fc3..000000000 --- a/core/src/main/java/google/registry/model/ofy/Ofy.java +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Maps.uniqueIndex; -import static com.googlecode.objectify.ObjectifyService.ofy; -import static google.registry.config.RegistryConfig.getBaseOfyRetryDuration; - -import com.google.appengine.api.datastore.DatastoreFailureException; -import com.google.appengine.api.datastore.DatastoreTimeoutException; -import com.google.appengine.api.taskqueue.TransientFailureException; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Streams; -import com.google.common.flogger.FluentLogger; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.Objectify; -import com.googlecode.objectify.ObjectifyFactory; -import com.googlecode.objectify.cmd.Deleter; -import com.googlecode.objectify.cmd.Loader; -import com.googlecode.objectify.cmd.Saver; -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.model.annotations.NotBackedUp; -import google.registry.model.annotations.VirtualEntity; -import google.registry.model.ofy.ReadOnlyWork.KillTransactionException; -import google.registry.util.Clock; -import google.registry.util.NonFinalForTesting; -import google.registry.util.Sleeper; -import google.registry.util.SystemClock; -import google.registry.util.SystemSleeper; -import java.lang.annotation.Annotation; -import java.util.Objects; -import java.util.function.Supplier; -import javax.inject.Inject; -import org.joda.time.DateTime; -import org.joda.time.Duration; - -/** - * A wrapper around ofy(). - * - *

The primary purpose of this class is to add functionality to support commit logs. It is - * simpler to wrap {@link Objectify} rather than extend it because this way we can remove some - * methods that we don't really want exposed and add some shortcuts. - */ -@DeleteAfterMigration -public class Ofy { - - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - - /** Default clock for transactions that don't provide one. */ - @NonFinalForTesting - static Clock clock = new SystemClock(); - - /** Default sleeper for transactions that don't provide one. */ - @NonFinalForTesting - static Sleeper sleeper = new SystemSleeper(); - - /** - * An injected clock that overrides the static clock. - * - *

Eventually the static clock should go away when we are 100% injected, but for now we need to - * preserve the old way of overriding the clock in tests by changing the static field. - */ - private final Clock injectedClock; - - /** Retry for 8^2 * 100ms = ~25 seconds. */ - private static final int NUM_RETRIES = 8; - - @Inject - public Ofy(Clock injectedClock) { - this.injectedClock = injectedClock; - } - - /** - * Thread local transaction info. There can only be one active transaction on a thread at a given - * time, and this will hold metadata for it. - */ - static final ThreadLocal TRANSACTION_INFO = new ThreadLocal<>(); - - /** Returns the wrapped Objectify's ObjectifyFactory. */ - public ObjectifyFactory factory() { - return ofy().factory(); - } - - /** Clears the session cache. */ - public void clearSessionCache() { - ofy().clear(); - } - - boolean inTransaction() { - return ofy().getTransaction() != null; - } - - public void assertInTransaction() { - checkState(inTransaction(), "Must be called in a transaction"); - } - - /** Load from Datastore. */ - public Loader load() { - return ofy().load(); - } - - /** - * Delete, augmented to enroll the deleted entities in a commit log. - * - *

We only allow this in transactions so commit logs can be written in tandem with the delete. - */ - public Deleter delete() { - return deleteIgnoringReadOnlyWithBackup(); - } - - /** - * Delete, without any augmentations except to check that we're not saving any virtual entities. - * - *

No backups get written. - */ - public Deleter deleteWithoutBackup() { - return deleteIgnoringReadOnlyWithoutBackup(); - } - - /** - * Save, augmented to enroll the saved entities in a commit log and to check that we're not saving - * virtual entities. - * - *

We only allow this in transactions so commit logs can be written in tandem with the save. - */ - public Saver save() { - return saveIgnoringReadOnlyWithBackup(); - } - - /** - * Save, without any augmentations except to check that we're not saving any virtual entities. - * - *

No backups get written. - */ - public Saver saveWithoutBackup() { - return saveIgnoringReadOnlyWithoutBackup(); - } - - /** Save, ignoring any backups or any read-only settings. */ - public Saver saveIgnoringReadOnlyWithoutBackup() { - return new AugmentedSaver() { - @Override - protected void handleSave(Iterable entities) { - checkProhibitedAnnotations(entities, VirtualEntity.class); - } - }; - } - - /** Delete, ignoring any backups or any read-only settings. */ - public Deleter deleteIgnoringReadOnlyWithoutBackup() { - return new AugmentedDeleter() { - @Override - protected void handleDeletion(Iterable> keys) { - checkProhibitedAnnotations(keys, VirtualEntity.class); - } - }; - } - - /** Save, ignoring any read-only settings (but still write commit logs). */ - public Saver saveIgnoringReadOnlyWithBackup() { - return new AugmentedSaver() { - @Override - protected void handleSave(Iterable entities) { - assertInTransaction(); - checkState( - Streams.stream(entities).allMatch(Objects::nonNull), "Can't save a null entity."); - checkProhibitedAnnotations(entities, NotBackedUp.class, VirtualEntity.class); - ImmutableMap, ?> keysToEntities = uniqueIndex(entities, Key::create); - TRANSACTION_INFO.get().putSaves(keysToEntities); - } - }; - } - - /** Delete, ignoring any read-only settings (but still write commit logs). */ - public Deleter deleteIgnoringReadOnlyWithBackup() { - return new AugmentedDeleter() { - @Override - protected void handleDeletion(Iterable> keys) { - assertInTransaction(); - checkState(Streams.stream(keys).allMatch(Objects::nonNull), "Can't delete a null key."); - checkProhibitedAnnotations(keys, NotBackedUp.class, VirtualEntity.class); - TRANSACTION_INFO.get().putDeletes(keys); - } - }; - } - - private Clock getClock() { - return injectedClock == null ? clock : injectedClock; - } - - /** Execute a transaction. */ - R transact(Supplier work) { - // If we are already in a transaction, don't wrap in a CommitLoggedWork. - return inTransaction() ? work.get() : transactNew(work); - } - - /** - * Execute a transaction. - * - *

This overload is used for transactions that don't return a value, formerly implemented using - * VoidWork. - */ - void transact(Runnable work) { - transact( - () -> { - work.run(); - return null; - }); - } - - /** Pause the current transaction (if any) and complete this one before returning to it. */ - public R transactNew(Supplier work) { - // Wrap the Work in a CommitLoggedWork so that we can give transactions a frozen view of time. - return transactCommitLoggedWork(new CommitLoggedWork<>(work, getClock())); - } - - /** - * Pause the current transaction (if any) and complete this one before returning to it. - * - *

This overload is used for transactions that don't return a value, formerly implemented using - * VoidWork. - */ - void transactNew(Runnable work) { - transactNew( - () -> { - work.run(); - return null; - }); - } - - /** - * Transact with commit logs and retry with exponential backoff. - * - *

This method is broken out from {@link #transactNew(Supplier)} for testing purposes. - */ - @VisibleForTesting - R transactCommitLoggedWork(CommitLoggedWork work) { - long baseRetryMillis = getBaseOfyRetryDuration().getMillis(); - for (long attempt = 0, sleepMillis = baseRetryMillis; - true; - attempt++, sleepMillis *= 2) { - try { - ofy().transactNew(() -> { - work.run(); - return null; - }); - return work.getResult(); - } catch (TransientFailureException - | DatastoreTimeoutException - | DatastoreFailureException e) { - // TransientFailureExceptions come from task queues and always mean nothing committed. - // TimestampInversionExceptions are thrown by our code and are always retryable as well. - // However, Datastore exceptions might get thrown even if the transaction succeeded. - if ((e instanceof DatastoreTimeoutException || e instanceof DatastoreFailureException) - && work.hasRun()) { - return work.getResult(); - } - if (attempt == NUM_RETRIES) { - throw e; // Give up. - } - sleeper.sleepUninterruptibly(Duration.millis(sleepMillis)); - logger.atInfo().withCause(e).log( - "Retrying %s, attempt %d.", e.getClass().getSimpleName(), attempt); - } - } - } - - /** A read-only transaction is useful to get strongly consistent reads at a shared timestamp. */ - R transactNewReadOnly(Supplier work) { - ReadOnlyWork readOnlyWork = new ReadOnlyWork<>(work, getClock()); - try { - ofy().transactNew(() -> { - readOnlyWork.run(); - return null; - }); - } catch (TransientFailureException | DatastoreTimeoutException | DatastoreFailureException e) { - // These are always retryable for a read-only operation. - return transactNewReadOnly(work); - } catch (KillTransactionException e) { - // Expected; we killed the transaction as a safety measure, and now we can return the result. - return readOnlyWork.getResult(); - } - throw new AssertionError(); // How on earth did we get here? - } - - void transactNewReadOnly(Runnable work) { - transactNewReadOnly( - () -> { - work.run(); - return null; - }); - } - - /** Execute some work in a transactionless context. */ - public R doTransactionless(Supplier work) { - try { - com.googlecode.objectify.ObjectifyService.push( - com.googlecode.objectify.ObjectifyService.ofy().transactionless()); - return work.get(); - } finally { - com.googlecode.objectify.ObjectifyService.pop(); - } - } - - /** - * Execute some work with a fresh session cache. - * - *

This is useful in cases where we want to load the latest possible data from Datastore but - * don't need point-in-time consistency across loads and consequently don't need a transaction. - * Note that unlike a transaction's fresh session cache, the contents of this cache will be - * discarded once the work completes, rather than being propagated into the enclosing session. - */ - public R doWithFreshSessionCache(Supplier work) { - try { - com.googlecode.objectify.ObjectifyService.push( - com.googlecode.objectify.ObjectifyService.factory().begin()); - return work.get(); - } finally { - com.googlecode.objectify.ObjectifyService.pop(); - } - } - - /** Get the time associated with the start of this particular transaction attempt. */ - DateTime getTransactionTime() { - assertInTransaction(); - return TRANSACTION_INFO.get().transactionTime; - } - - /** - * Returns the @Entity-annotated base class for an object that is either an {@code Key} or an - * object of an entity class registered with Objectify. - */ - @VisibleForTesting - static Class getBaseEntityClassFromEntityOrKey(Object entityOrKey) { - // Convert both keys and entities into keys, so that we get consistent behavior in either case. - Key key = (entityOrKey instanceof Key ? (Key) entityOrKey : Key.create(entityOrKey)); - // Get the entity class associated with this key's kind, which should be the base @Entity class - // from which the kind name is derived. Don't be tempted to use getMetadata(String kind) or - // getMetadataForEntity(T pojo) instead; the former won't throw an exception for an unknown - // kind (it just returns null) and the latter will return the @EntitySubclass if there is one. - return ofy().factory().getMetadata(key).getEntityClass(); - } - - /** - * Checks that the base @Entity classes for the provided entities or keys don't have any of the - * specified forbidden annotations. - */ - @SafeVarargs - private static void checkProhibitedAnnotations( - Iterable entitiesOrKeys, Class... annotations) { - for (Object entityOrKey : entitiesOrKeys) { - Class entityClass = getBaseEntityClassFromEntityOrKey(entityOrKey); - for (Class annotation : annotations) { - checkArgument(!entityClass.isAnnotationPresent(annotation), - "Can't save/delete a @%s entity: %s", annotation.getSimpleName(), entityClass); - } - } - } -} diff --git a/core/src/main/java/google/registry/model/ofy/OfyFilter.java b/core/src/main/java/google/registry/model/ofy/OfyFilter.java deleted file mode 100644 index b3daa3412..000000000 --- a/core/src/main/java/google/registry/model/ofy/OfyFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import google.registry.model.annotations.DeleteAfterMigration; -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -/** A filter that statically registers types with Objectify. */ -@DeleteAfterMigration -public class OfyFilter implements Filter { - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) - throws IOException, ServletException { - filterChain.doFilter(request, response); - } - - @Override - public void init(FilterConfig config) { - // Make sure that we've registered all types before we do anything else with Objectify. - ObjectifyService.initOfy(); - } - - @Override - public void destroy() {} -} diff --git a/core/src/main/java/google/registry/model/ofy/ReadOnlyWork.java b/core/src/main/java/google/registry/model/ofy/ReadOnlyWork.java deleted file mode 100644 index d3113cbcf..000000000 --- a/core/src/main/java/google/registry/model/ofy/ReadOnlyWork.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.util.Clock; -import java.util.function.Supplier; - -/** Wrapper for {@link Supplier} that disallows mutations and fails the transaction at the end. */ -@DeleteAfterMigration -class ReadOnlyWork extends CommitLoggedWork { - - ReadOnlyWork(Supplier work, Clock clock) { - super(work, clock); - } - - @Override - protected TransactionInfo createNewTransactionInfo() { - return super.createNewTransactionInfo().setReadOnly(); - } - - @Override - public void run() { - super.run(); - throw new KillTransactionException(); - } - - /** Exception used to exit a transaction. */ - static class KillTransactionException extends RuntimeException {} -} diff --git a/core/src/main/java/google/registry/model/ofy/RequestCapturingAsyncDatastoreService.java b/core/src/main/java/google/registry/model/ofy/RequestCapturingAsyncDatastoreService.java deleted file mode 100644 index f036a5abf..000000000 --- a/core/src/main/java/google/registry/model/ofy/RequestCapturingAsyncDatastoreService.java +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static java.util.Collections.synchronizedList; - -import com.google.appengine.api.datastore.AsyncDatastoreService; -import com.google.appengine.api.datastore.DatastoreAttributes; -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.Index; -import com.google.appengine.api.datastore.Index.IndexState; -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyRange; -import com.google.appengine.api.datastore.PreparedQuery; -import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Transaction; -import com.google.appengine.api.datastore.TransactionOptions; -import com.google.common.collect.ImmutableList; -import google.registry.model.annotations.DeleteAfterMigration; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Future; - -/** A proxy for {@link AsyncDatastoreService} that exposes call counts. */ -@DeleteAfterMigration -public class RequestCapturingAsyncDatastoreService implements AsyncDatastoreService { - - private final AsyncDatastoreService delegate; - - // Each outer lists represents Datastore operations, with inner lists representing the keys or - // entities involved in that operation. We use static lists because we care about overall calls to - // Datastore, not calls via a specific instance of the service. - - private static List> reads = synchronizedList(new ArrayList>()); - private static List> deletes = synchronizedList(new ArrayList>()); - private static List> puts = synchronizedList(new ArrayList>()); - - RequestCapturingAsyncDatastoreService(AsyncDatastoreService delegate) { - this.delegate = delegate; - } - - public static List> getReads() { - return reads; - } - - public static List> getDeletes() { - return deletes; - } - - public static List> getPuts() { - return puts; - } - - @Override - public Collection getActiveTransactions() { - return delegate.getActiveTransactions(); - } - - @Override - public Transaction getCurrentTransaction() { - return delegate.getCurrentTransaction(); - } - - @Override - public Transaction getCurrentTransaction(Transaction transaction) { - return delegate.getCurrentTransaction(transaction); - } - - @Override - public PreparedQuery prepare(Query query) { - return delegate.prepare(query); - } - - @Override - public PreparedQuery prepare(Transaction transaction, Query query) { - return delegate.prepare(transaction, query); - } - - @Override - public Future allocateIds(String kind, long num) { - return delegate.allocateIds(kind, num); - } - - @Override - public Future allocateIds(Key parent, String kind, long num) { - return delegate.allocateIds(parent, kind, num); - } - - @Override - public Future beginTransaction() { - return delegate.beginTransaction(); - } - - @Override - public Future beginTransaction(TransactionOptions transaction) { - return delegate.beginTransaction(transaction); - } - - @Override - public Future delete(Key... keys) { - deletes.add(ImmutableList.copyOf(keys)); - return delegate.delete(keys); - } - - @Override - public Future delete(Iterable keys) { - deletes.add(ImmutableList.copyOf(keys)); - return delegate.delete(keys); - } - - @Override - public Future delete(Transaction transaction, Key... keys) { - deletes.add(ImmutableList.copyOf(keys)); - return delegate.delete(transaction, keys); - } - - @Override - public Future delete(Transaction transaction, Iterable keys) { - deletes.add(ImmutableList.copyOf(keys)); - return delegate.delete(transaction, keys); - } - - @Override - public Future get(Key key) { - reads.add(ImmutableList.of(key)); - return delegate.get(key); - } - - @Override - public Future> get(Iterable keys) { - reads.add(ImmutableList.copyOf(keys)); - return delegate.get(keys); - } - - @Override - public Future get(Transaction transaction, Key key) { - reads.add(ImmutableList.of(key)); - return delegate.get(transaction, key); - } - - @Override - public Future> get(Transaction transaction, Iterable keys) { - reads.add(ImmutableList.copyOf(keys)); - return delegate.get(transaction, keys); - } - - @Override - public Future getDatastoreAttributes() { - return delegate.getDatastoreAttributes(); - } - - @Override - public Future> getIndexes() { - return delegate.getIndexes(); - } - - @Override - public Future put(Entity entity) { - puts.add(ImmutableList.of(entity)); - return delegate.put(entity); - } - - @Override - public Future> put(Iterable entities) { - puts.add(ImmutableList.copyOf(entities)); - return delegate.put(entities); - } - - @Override - public Future put(Transaction transaction, Entity entity) { - puts.add(ImmutableList.of(entity)); - return delegate.put(transaction, entity); - } - - @Override - public Future> put(Transaction transaction, Iterable entities) { - puts.add(ImmutableList.copyOf(entities)); - return delegate.put(transaction, entities); - } -} diff --git a/core/src/main/java/google/registry/model/ofy/TransactionInfo.java b/core/src/main/java/google/registry/model/ofy/TransactionInfo.java deleted file mode 100644 index ba3a6b357..000000000 --- a/core/src/main/java/google/registry/model/ofy/TransactionInfo.java +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.collect.Maps.toMap; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; -import com.googlecode.objectify.Key; -import google.registry.model.annotations.DeleteAfterMigration; -import java.util.Map; -import org.joda.time.DateTime; - -/** Metadata for an {@link Ofy} transaction that saves commit logs. */ -@DeleteAfterMigration -public class TransactionInfo { - - @VisibleForTesting - public enum Delete { - SENTINEL - } - - /** Logical "now" of the transaction. */ - DateTime transactionTime; - - /** Whether this is a read-only transaction. */ - private boolean readOnly; - - /** - * Accumulator of save/delete operations performed in transaction. - * - *

The {@link ImmutableMap} builder provides us the benefit of not permitting duplicates. - * This allows us to avoid potential race conditions where the same key is mutated twice in a - * transaction. - */ - private final ImmutableMap.Builder, Object> changesBuilder = new ImmutableMap.Builder<>(); - - TransactionInfo(DateTime now) { - this.transactionTime = now; - } - - TransactionInfo setReadOnly() { - this.readOnly = true; - return this; - } - - void assertNotReadOnly() { - checkState(!readOnly, "This is a read only transaction."); - } - - void putSaves(Map, ?> keysToEntities) { - assertNotReadOnly(); - changesBuilder.putAll(keysToEntities); - } - - void putDeletes(Iterable> keys) { - assertNotReadOnly(); - changesBuilder.putAll(toMap(keys, k -> Delete.SENTINEL)); - } -} diff --git a/core/src/main/java/google/registry/persistence/VKey.java b/core/src/main/java/google/registry/persistence/VKey.java index 36cd5150a..2c3fceb61 100644 --- a/core/src/main/java/google/registry/persistence/VKey.java +++ b/core/src/main/java/google/registry/persistence/VKey.java @@ -75,7 +75,7 @@ public class VKey extends ImmutableObject implements Serializable { * Constructs a {@link VKey} for an {@link EppResource } from the string representation. * *

The string representation is obtained from the {@link #stringify()} function and like this: - * {@code kind:TestObject@sql:rO0ABXQAA2Zvbw} + * {@code kind:SomeEntity@sql:rO0ABXQAA2Zvbw} */ public static VKey createEppVKeyFromString(String keyString) { ImmutableMap kvs = diff --git a/core/src/main/java/google/registry/persistence/transaction/QueryComposer.java b/core/src/main/java/google/registry/persistence/transaction/QueryComposer.java index a5be39a02..ba4270915 100644 --- a/core/src/main/java/google/registry/persistence/transaction/QueryComposer.java +++ b/core/src/main/java/google/registry/persistence/transaction/QueryComposer.java @@ -149,14 +149,6 @@ public abstract class QueryComposer { /** * Enum used to specify comparison operations, e.g. {@code where("fieldName", Comparator.NE, * "someval")'}. - * - *

These contain values that specify the comparison behavior for both objectify and criteria - * queries. For objectify, we provide a string to be appended to the field name in a {@code - * filter()} expression. For criteria queries we provide a function that knows how to obtain a - * {@link WhereOperator} from a {@link CriteriaBuilder}. - * - *

Note that the objectify strings for comparators other than equality are preceded by a space - * because {@code filter()} expects the fieldname to be separated from the operator by a space. */ public enum Comparator { /** diff --git a/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java b/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java index 6a4091336..e1c21b63b 100644 --- a/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java +++ b/core/src/main/java/google/registry/tmch/TmchCertificateAuthority.java @@ -19,12 +19,12 @@ import static google.registry.config.RegistryConfig.ConfigModule.TmchCaMode.PROD import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration; import static google.registry.util.ResourceUtils.readResourceUtf8; +import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import google.registry.config.RegistryConfig.Config; import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode; import google.registry.model.CacheUtils; -import google.registry.model.CacheUtils.AppEngineEnvironmentCacheLoader; import google.registry.model.tmch.TmchCrl; import google.registry.util.Clock; import google.registry.util.X509Utils; @@ -78,7 +78,7 @@ public final class TmchCertificateAuthority { private static final LoadingCache CRL_CACHE = CacheUtils.newCacheBuilder(getSingletonCacheRefreshDuration()) .build( - new AppEngineEnvironmentCacheLoader() { + new CacheLoader() { @Override public X509CRL load(final TmchCaMode tmchCaMode) throws GeneralSecurityException { Optional storedCrl = TmchCrl.get(); diff --git a/core/src/main/java/google/registry/tools/EntityWrapper.java b/core/src/main/java/google/registry/tools/EntityWrapper.java deleted file mode 100644 index c583f1b00..000000000 --- a/core/src/main/java/google/registry/tools/EntityWrapper.java +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.tools; - -import com.google.appengine.api.datastore.Entity; -import com.google.auto.value.AutoValue; -import com.google.common.base.Objects; - -/** - * Wraps {@link Entity} for ease of processing in collections. - * - *

Note that the {@link #hashCode}/{@link #equals} methods are based on both the entity's key and - * its properties. - */ -final class EntityWrapper { - private static final String TEST_ENTITY_KIND = "TestEntity"; - - private final Entity entity; - - EntityWrapper(Entity entity) { - this.entity = entity; - } - - public Entity getEntity() { - return entity; - } - - @Override - public boolean equals(Object that) { - if (that instanceof EntityWrapper) { - EntityWrapper thatEntity = (EntityWrapper) that; - return entity.equals(thatEntity.entity) - && entity.getProperties().equals(thatEntity.entity.getProperties()); - } - - return false; - } - - @Override - public int hashCode() { - return Objects.hashCode(entity.getKey(), entity.getProperties()); - } - - @Override - public String toString() { - return "EntityWrapper(" + entity + ")"; - } - - public static EntityWrapper from(int id, Property... properties) { - Entity entity = new Entity(TEST_ENTITY_KIND, id); - for (Property prop : properties) { - entity.setProperty(prop.name(), prop.value()); - } - return new EntityWrapper(entity); - } - - @AutoValue - abstract static class Property { - - static Property create(String name, Object value) { - return new AutoValue_EntityWrapper_Property(name, value); - } - - abstract String name(); - - abstract Object value(); - } -} diff --git a/core/src/main/java/google/registry/tools/RegistryCli.java b/core/src/main/java/google/registry/tools/RegistryCli.java index 634af8f4d..5720fcc27 100644 --- a/core/src/main/java/google/registry/tools/RegistryCli.java +++ b/core/src/main/java/google/registry/tools/RegistryCli.java @@ -29,7 +29,6 @@ import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import google.registry.config.RegistryConfig; -import google.registry.model.ofy.ObjectifyService; import google.registry.persistence.transaction.TransactionManagerFactory; import google.registry.tools.AuthModule.LoginRequiredException; import google.registry.tools.params.ParameterFactory; @@ -256,15 +255,6 @@ final class RegistryCli implements AutoCloseable, CommandRunner { } installer.install(options); - // Database setup -- we also only ever do this if "installer" is null, just so that it's - // only done once. - - // Ensure that all entity classes are loaded before command code runs. - ObjectifyService.initOfy(); - // Make sure we start the command with a clean cache, so that any previous command won't - // interfere with this one. - ObjectifyService.auditedOfy().clearSessionCache(); - // Enable Cloud SQL for command that needs remote API as they will very likely use // Cloud SQL after the database migration. Note that the DB password is stored in Datastore // and it is already initialized above. diff --git a/core/src/main/java/google/registry/tools/javascrap/CreateSyntheticDomainHistoriesCommand.java b/core/src/main/java/google/registry/tools/javascrap/CreateSyntheticDomainHistoriesCommand.java index 68fbd743c..a4bf0b103 100644 --- a/core/src/main/java/google/registry/tools/javascrap/CreateSyntheticDomainHistoriesCommand.java +++ b/core/src/main/java/google/registry/tools/javascrap/CreateSyntheticDomainHistoriesCommand.java @@ -27,7 +27,6 @@ import google.registry.config.CredentialModule; import google.registry.config.RegistryConfig; import google.registry.config.RegistryConfig.Config; import google.registry.model.domain.Domain; -import google.registry.model.ofy.ObjectifyService; import google.registry.model.reporting.HistoryEntry; import google.registry.persistence.VKey; import google.registry.tools.CommandWithConnection; @@ -199,7 +198,6 @@ public class CreateSyntheticDomainHistoriesCommand extends ConfirmingCommand } catch (IOException e) { throw new RuntimeException(e); } - ObjectifyService.initOfy(); return installer; } diff --git a/core/src/main/javascript/soyutils_usegoog.js b/core/src/main/javascript/soyutils_usegoog.js index d4eb9ef5e..600d05099 100644 --- a/core/src/main/javascript/soyutils_usegoog.js +++ b/core/src/main/javascript/soyutils_usegoog.js @@ -928,7 +928,6 @@ soy.$$cleanHtml = function(value, opt_safeTags) { }; -// LINT.IfChange(htmlToText) /** * Converts HTML to plain text by removing tags, normalizing spaces and * converting entities. @@ -1008,10 +1007,6 @@ soy.$$htmlToText = function(value) { /** @private @const */ soy.BLOCK_TAGS_RE_ = /^\/?(address|blockquote|dd|div|dl|dt|h[1-6]|hr|li|ol|p|pre|table|tr|ul)$/i; -// LINT.ThenChange( -// ../../../third_party/java_src/soy/java/com/google/template/soy/basicfunctions/HtmlToText.java, -// ../../../third_party/java_src/soy/python/runtime/sanitize.py:htmlToText) - /** * Escapes HTML, except preserves entities. diff --git a/core/src/test/java/google/registry/beam/TestPipelineExtension.java b/core/src/test/java/google/registry/beam/TestPipelineExtension.java index a983ba763..924e00288 100644 --- a/core/src/test/java/google/registry/beam/TestPipelineExtension.java +++ b/core/src/test/java/google/registry/beam/TestPipelineExtension.java @@ -20,7 +20,6 @@ package google.registry.beam; import static com.google.common.base.Preconditions.checkState; -import static com.google.common.truth.Truth.assertWithMessage; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -28,7 +27,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Strings; import com.google.common.collect.Maps; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -298,15 +296,6 @@ public class TestPipelineExtension extends Pipeline enableAbandonedNodeEnforcement(true); } - // Clear this property so that when default Guava ThreadFactory is created - // it will not think that it is in App Engine and return an unusable - // ThreadFactory. - System.clearProperty("com.google.appengine.runtime.environment"); - assertWithMessage( - "Beam pipelines don't run in an App Engine environment, and thus" - + " the tests shouldn't be mocking one either.") - .that(isAppEngine()) - .isFalse(); } @Override @@ -512,25 +501,6 @@ public class TestPipelineExtension extends Pipeline } } - // Adapted from Guava's MoreExecutors (where it is a private method) - private static boolean isAppEngine() { - if (System.getProperty("com.google.appengine.runtime.environment") == null) { - return false; - } else { - try { - return Class.forName("com.google.apphosting.api.ApiProxy") - .getMethod("getCurrentEnvironment") - .invoke(null) - != null; - } catch (ClassNotFoundException - | InvocationTargetException - | IllegalAccessException - | NoSuchMethodException e) { - return false; - } - } - } - private static class IsEmptyVisitor extends PipelineVisitor.Defaults { private boolean empty = true; diff --git a/core/src/test/java/google/registry/model/ImmutableObjectTest.java b/core/src/test/java/google/registry/model/ImmutableObjectTest.java index f645916b3..9ef72a3ad 100644 --- a/core/src/test/java/google/registry/model/ImmutableObjectTest.java +++ b/core/src/test/java/google/registry/model/ImmutableObjectTest.java @@ -25,9 +25,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.Id; +import google.registry.persistence.VKey; import google.registry.testing.AppEngineExtension; import google.registry.util.CidrAddressBlock; import java.lang.reflect.Field; @@ -38,6 +36,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.Id; import org.joda.time.DateTime; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -50,7 +50,6 @@ public class ImmutableObjectTest { AppEngineExtension.builder() .withCloudSql() .withJpaUnitTestEntities(ValueObject.class) - .withOfyTestEntities(ValueObject.class) .build(); /** Simple subclass of ImmutableObject. */ @@ -266,21 +265,19 @@ public class ImmutableObjectTest { /** Subclass of ImmutableObject with keys to other objects. */ public static class RootObject extends ImmutableObject { - Key hydrateMe; + VKey hydrateMe; - @DoNotHydrate - Key skipMe; + @DoNotHydrate VKey skipMe; - Map> map; + Map> map; - Set> set; + Set> set; } /** Simple subclass of ImmutableObject. */ @Entity - @javax.persistence.Entity public static class ValueObject extends ImmutableObject { - @Id @javax.persistence.Id long id; + @Id long id; String value; diff --git a/core/src/test/java/google/registry/model/common/GaeUserIdConverterTest.java b/core/src/test/java/google/registry/model/common/GaeUserIdConverterTest.java deleted file mode 100644 index 8b935aa7d..000000000 --- a/core/src/test/java/google/registry/model/common/GaeUserIdConverterTest.java +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.common; - -import static com.google.common.truth.Truth.assertThat; -import static google.registry.model.ofy.ObjectifyService.auditedOfy; - -import google.registry.testing.AppEngineExtension; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** Unit tests for {@link GaeUserIdConverter}. */ -public class GaeUserIdConverterTest { - - @RegisterExtension - public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build(); - - @AfterEach - void verifyNoLingeringEntities() { - assertThat(auditedOfy().load().type(GaeUserIdConverter.class).count()).isEqualTo(0); - } - - @Test - void testSuccess() { - assertThat(GaeUserIdConverter.convertEmailAddressToGaeUserId("example@example.com")) - .matches("[0-9]+"); - } - - @Test - void testSuccess_inTransaction() { - auditedOfy() - .transactNew( - () -> { - assertThat(GaeUserIdConverter.convertEmailAddressToGaeUserId("example@example.com")) - .matches("[0-9]+"); - return null; - }); - } -} diff --git a/core/src/test/java/google/registry/model/ofy/ObjectifyServiceTest.java b/core/src/test/java/google/registry/model/ofy/ObjectifyServiceTest.java deleted file mode 100644 index 4402d2091..000000000 --- a/core/src/test/java/google/registry/model/ofy/ObjectifyServiceTest.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import google.registry.testing.AppEngineExtension; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** Tests for our replacement for ObjectifyService. */ -public class ObjectifyServiceTest { - - @RegisterExtension - public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build(); - - @Test - void test_initOfy_canBeCalledTwice() { - ObjectifyService.initOfy(); - ObjectifyService.initOfy(); - } -} diff --git a/core/src/test/java/google/registry/model/ofy/OfyFilterTest.java b/core/src/test/java/google/registry/model/ofy/OfyFilterTest.java deleted file mode 100644 index e121bc6b3..000000000 --- a/core/src/test/java/google/registry/model/ofy/OfyFilterTest.java +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.model.ofy; - -import static com.google.common.truth.Truth.assertThat; -import static google.registry.model.ofy.ObjectifyService.initOfy; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig; -import com.google.appengine.tools.development.testing.LocalServiceTestHelper; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.ObjectifyFactory; -import com.googlecode.objectify.ObjectifyFilter; -import com.googlecode.objectify.ObjectifyService; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.Id; -import google.registry.model.common.GaeUserIdConverter; -import google.registry.persistence.transaction.JpaTestExtensions; -import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** Tests for our replacement Objectify filter. */ -class OfyFilterTest { - - private LocalServiceTestHelper helper; - private ObjectifyFactory factory; - - // We can't use AppEngineExtension, because it triggers the precise behavior that we are testing. - - @BeforeEach - void beforeEach() { - helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()).setUp(); - // Clear out the factory so that it requires re-registration on each test method. - // Otherwise, static registration of types in one method would persist across methods. - initOfy(); - factory = ObjectifyService.factory(); - ObjectifyService.setFactory(new ObjectifyFactory(false)); - } - - @AfterEach - void afterEach() { - ObjectifyFilter.complete(); - ObjectifyService.setFactory(factory); - ObjectifyFilter.complete(); - helper.tearDown(); - } - - @RegisterExtension - final JpaIntegrationTestExtension database = - new JpaTestExtensions.Builder().buildIntegrationTestExtension(); - - /** - * Key.create looks up kind metadata for the class of the object it is given. If this happens - * before the first reference to ObjectifyService, which statically triggers type registrations, - * then the create will fail. Note that this is only a problem if the type in question doesn't - * call ObjectifyService.allocateId() inside its own builder or create method, since if it does - * that would trigger the statics as well. In this example, Registrar has a string id, so the bug - * occurs, were it not for OfyFilter. - */ - @Test - void testFilterRegistersTypes() { - UnregisteredEntity entity = new UnregisteredEntity(5L); - IllegalStateException e = assertThrows(IllegalStateException.class, () -> Key.create(entity)); - assertThat(e) - .hasMessageThat() - .isEqualTo( - "class google.registry.model.ofy.OfyFilterTest$UnregisteredEntity " - + "has not been registered"); - } - - /** The filter should register all types for us. */ - @Test - void testKeyCreateAfterFilter() { - new OfyFilter().init(null); - GaeUserIdConverter userIdConverter = new GaeUserIdConverter(); - userIdConverter.id = 1; - Key.create(userIdConverter); - } - - @Entity - private static class UnregisteredEntity { - - @Id long id; - - UnregisteredEntity(long id) { - this.id = id; - } - } -} diff --git a/core/src/test/java/google/registry/server/RegistryTestServer.java b/core/src/test/java/google/registry/server/RegistryTestServer.java index dfe66f4ca..0b32d4204 100644 --- a/core/src/test/java/google/registry/server/RegistryTestServer.java +++ b/core/src/test/java/google/registry/server/RegistryTestServer.java @@ -21,13 +21,10 @@ import static google.registry.util.BuildPathUtils.getResourcesDir; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.net.HostAndPort; -import com.googlecode.objectify.ObjectifyFilter; -import google.registry.model.ofy.OfyFilter; import google.registry.module.backend.BackendServlet; import google.registry.module.frontend.FrontendServlet; import java.net.URL; import java.nio.file.Path; -import javax.servlet.Filter; /** Lightweight HTTP server for testing the Nomulus Admin and Registrar consoles. */ public final class RegistryTestServer { @@ -87,15 +84,11 @@ public final class RegistryTestServer { route("/registry-lock-post", FrontendServlet.class), route("/registry-lock-verify", FrontendServlet.class)); - private static final ImmutableList> FILTERS = ImmutableList.of( - ObjectifyFilter.class, - OfyFilter.class); - private final TestServer server; /** @see TestServer#TestServer(HostAndPort, ImmutableMap, ImmutableList, ImmutableList) */ public RegistryTestServer(HostAndPort address) { - server = new TestServer(address, RUNFILES, ROUTES, FILTERS); + server = new TestServer(address, RUNFILES, ROUTES); } /** @see TestServer#start() */ diff --git a/core/src/test/java/google/registry/server/ServletWrapperDelegatorServlet.java b/core/src/test/java/google/registry/server/ServletWrapperDelegatorServlet.java index d0ae0650c..762ba2b0d 100644 --- a/core/src/test/java/google/registry/server/ServletWrapperDelegatorServlet.java +++ b/core/src/test/java/google/registry/server/ServletWrapperDelegatorServlet.java @@ -18,20 +18,14 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.throwIfInstanceOf; import static google.registry.util.TypeUtils.instantiate; -import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Uninterruptibles; import java.io.IOException; -import java.util.Iterator; import java.util.Queue; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import javax.annotation.Nullable; -import javax.servlet.Filter; -import javax.servlet.FilterChain; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -39,49 +33,33 @@ import javax.servlet.http.HttpServletResponse; /** * Servlet that wraps a servlet and delegates request execution to a queue. * - *

The actual invocation of the delegate does not happen within this servlet's lifecycle. - * Therefore, the task on the queue must manually invoke filters within the queue task. - * * @see TestServer */ public final class ServletWrapperDelegatorServlet extends HttpServlet { private final Queue> requestQueue; private final Class servletClass; - private final ImmutableList> filterClasses; ServletWrapperDelegatorServlet( Class servletClass, - ImmutableList> filterClasses, Queue> requestQueue) { this.servletClass = servletClass; - this.filterClasses = filterClasses; this.requestQueue = checkNotNull(requestQueue, "requestQueue"); } @Override public void service(final HttpServletRequest req, final HttpServletResponse rsp) throws ServletException, IOException { - FutureTask task = new FutureTask<>(new Callable() { - @Nullable - @Override - public Void call() throws ServletException, IOException { - // Simulate the full filter chain with the servlet at the end. - final Iterator> filtersIter = filterClasses.iterator(); - FilterChain filterChain = - new FilterChain() { + FutureTask task = + new FutureTask<>( + new Callable() { + @Nullable @Override - public void doFilter(ServletRequest request, ServletResponse response) - throws IOException, ServletException { - if (filtersIter.hasNext()) { - instantiate(filtersIter.next()).doFilter(request, response, this); - } else { - instantiate(servletClass).service(request, response); - } - }}; - filterChain.doFilter(req, rsp); - return null; - }}); + public Void call() throws ServletException, IOException { + instantiate(servletClass).service(req, rsp); + return null; + } + }); requestQueue.add(task); try { Uninterruptibles.getUninterruptibly(task); diff --git a/core/src/test/java/google/registry/server/TestServer.java b/core/src/test/java/google/registry/server/TestServer.java index 44bded569..618bbbeef 100644 --- a/core/src/test/java/google/registry/server/TestServer.java +++ b/core/src/test/java/google/registry/server/TestServer.java @@ -34,7 +34,6 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; -import javax.servlet.Filter; import javax.servlet.http.HttpServlet; import org.mortbay.jetty.Connector; import org.mortbay.jetty.Server; @@ -85,13 +84,10 @@ public final class TestServer { * @param routes list of servlet endpoints */ public TestServer( - HostAndPort address, - ImmutableMap runfiles, - ImmutableList routes, - ImmutableList> filters) { + HostAndPort address, ImmutableMap runfiles, ImmutableList routes) { urlAddress = createUrlAddress(address); server.addConnector(createConnector(address)); - server.addHandler(createHandler(runfiles, routes, filters)); + server.addHandler(createHandler(runfiles, routes)); } /** Starts the HTTP server in a new thread and returns once it's online. */ @@ -156,10 +152,7 @@ public final class TestServer { } } - private Context createHandler( - Map runfiles, - ImmutableList routes, - ImmutableList> filters) { + private Context createHandler(Map runfiles, ImmutableList routes) { Context context = new Context(server, CONTEXT_PATH, Context.SESSIONS); context.addServlet(new ServletHolder(HealthzServlet.class), "/healthz"); for (Map.Entry runfile : runfiles.entrySet()) { @@ -168,8 +161,7 @@ public final class TestServer { runfile.getKey()); } for (Route route : routes) { - context.addServlet( - new ServletHolder(wrapServlet(route.servletClass(), filters)), route.path()); + context.addServlet(new ServletHolder(wrapServlet(route.servletClass())), route.path()); } ServletHolder holder = new ServletHolder(DefaultServlet.class); holder.setInitParameter("aliases", "1"); @@ -177,9 +169,8 @@ public final class TestServer { return context; } - private HttpServlet wrapServlet( - Class servletClass, ImmutableList> filters) { - return new ServletWrapperDelegatorServlet(servletClass, filters, requestQueue); + private HttpServlet wrapServlet(Class servletClass) { + return new ServletWrapperDelegatorServlet(servletClass, requestQueue); } private static Connector createConnector(HostAndPort address) { diff --git a/core/src/test/java/google/registry/testing/AppEngineExtension.java b/core/src/test/java/google/registry/testing/AppEngineExtension.java index 60db470e1..f6b4c84d7 100644 --- a/core/src/test/java/google/registry/testing/AppEngineExtension.java +++ b/core/src/test/java/google/registry/testing/AppEngineExtension.java @@ -39,9 +39,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.common.io.Files; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.ObjectifyFilter; -import google.registry.model.ofy.ObjectifyService; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar.State; import google.registry.model.registrar.RegistrarAddress; @@ -135,7 +132,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa private UserInfo userInfo; // Test Objectify entity classes to be used with this AppEngineExtension instance. - private ImmutableList> ofyTestEntities; private ImmutableList> jpaTestEntities; public Optional getJpaIntegrationTestExtension() { @@ -146,7 +142,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa public static class Builder { private AppEngineExtension extension = new AppEngineExtension(); - private ImmutableList.Builder> ofyTestEntities = new ImmutableList.Builder<>(); private ImmutableList.Builder> jpaTestEntities = new ImmutableList.Builder<>(); /** Turns on Cloud SQL only, for use by test data generators. */ @@ -205,24 +200,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa return this; } - /** - * Declares test-only entities to be registered with {@code ObjectifyService}. - * - *

Note that {@code ObjectifyService} silently replaces the current registration for a given - * kind when a different class is registered for this kind. Since {@code ObjectifyService} does - * not support de-registration, each test entity class must be of a unique kind across the - * entire code base. Although this requirement can be worked around by using different {@code - * ObjectifyService} instances for each test (class), the setup overhead would rise - * significantly. - * - * @see AppEngineExtension#register(Class) - */ - @SafeVarargs - public final Builder withOfyTestEntities(Class... entities) { - ofyTestEntities.add(entities); - return this; - } - public Builder withJpaUnitTestEntities(Class... entities) { jpaTestEntities.add(entities); extension.withJpaUnitTest = true; @@ -239,7 +216,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa checkState( !extension.withJpaUnitTest || !extension.enableJpaEntityCoverageCheck, "withJpaUnitTestEntities cannot be set when enableJpaEntityCoverageCheck"); - extension.ofyTestEntities = this.ofyTestEntities.build(); extension.jpaTestEntities = this.jpaTestEntities.build(); return extension; } @@ -440,9 +416,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa helper.setEnvInstance("0"); } helper.setUp(); - - ObjectifyService.initOfy(); - this.ofyTestEntities.forEach(AppEngineExtension::register); } /** Called after each test method. */ @@ -472,7 +445,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa public void tearDown() throws Exception { // Resets Objectify. Although it would seem more obvious to do this at the start of a request // instead of at the end, this is more consistent with what ObjectifyFilter does in real code. - ObjectifyFilter.complete(); helper.tearDown(); helper = null; // Test that Datastore didn't need any indexes we don't have listed in our index file. @@ -502,24 +474,6 @@ public final class AppEngineExtension implements BeforeEachCallback, AfterEachCa } } - /** - * Registers test-only Objectify entities and checks for re-registrations for the same kind by - * different classes. - */ - private static void register(Class entityClass) { - String kind = Key.getKind(entityClass); - Optional.ofNullable(com.googlecode.objectify.ObjectifyService.factory().getMetadata(kind)) - .ifPresent( - meta -> - checkState( - meta.getEntityClass() == entityClass, - "Cannot register %s. The Kind %s is already registered with %s.", - entityClass.getName(), - kind, - meta.getEntityClass().getName())); - com.googlecode.objectify.ObjectifyService.register(entityClass); - } - /** Install {@code testing/logging.properties} so logging is less noisy. */ private static void setupLogging() throws IOException { LogManager.getLogManager() diff --git a/core/src/test/java/google/registry/testing/AppEngineExtensionTest.java b/core/src/test/java/google/registry/testing/AppEngineExtensionTest.java index 3b48a0ebe..362628f9f 100644 --- a/core/src/test/java/google/registry/testing/AppEngineExtensionTest.java +++ b/core/src/test/java/google/registry/testing/AppEngineExtensionTest.java @@ -15,27 +15,15 @@ package google.registry.testing; import static com.google.common.io.Files.asCharSink; -import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; -import static google.registry.util.CollectionUtils.entriesToImmutableMap; import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.jupiter.api.Assertions.assertThrows; import com.google.common.base.Joiner; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import com.google.common.collect.Multimaps; -import com.googlecode.objectify.Key; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.Id; import google.registry.persistence.transaction.JpaTransactionManager; -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ScanResult; import java.io.File; import java.io.IOException; -import java.util.Collection; -import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -120,65 +108,7 @@ class AppEngineExtensionTest { assertThrows(AssertionError.class, () -> appEngine.afterEach(context.getContext())); } - @Test - void testRegisterOfyEntities_duplicateEntitiesWithSameName_fails() throws Exception { - AppEngineExtension appEngineExtension = - AppEngineExtension.builder() - .withCloudSql() - .withOfyTestEntities(google.registry.testing.TestObject.class, TestObject.class) - .build(); - // Thrown before JPA is set up, therefore no need to call afterEach. - IllegalStateException thrown = - assertThrows( - IllegalStateException.class, () -> appEngineExtension.beforeEach(context.getContext())); - assertThat(thrown) - .hasMessageThat() - .isEqualTo( - String.format( - "Cannot register %s. The Kind %s is already registered with %s.", - TestObject.class.getName(), - "TestObject", - google.registry.testing.TestObject.class.getName())); - // The class level extension. - appEngine.afterEach(context.getContext()); - } - - @Test - void testOfyEntities_uniqueKinds() throws Exception { - try (ScanResult scanResult = - new ClassGraph() - .enableAnnotationInfo() - .ignoreClassVisibility() - .whitelistPackages("google.registry") - .scan()) { - Multimap> kindToEntityMultiMap = - scanResult.getClassesWithAnnotation(Entity.class.getName()).stream() - .filter(clazz -> !clazz.getName().equals(TestObject.class.getName())) - .map(clazz -> clazz.loadClass()) - .collect( - Multimaps.toMultimap( - Key::getKind, - clazz -> clazz, - MultimapBuilder.hashKeys().linkedListValues()::build)); - Map>> conflictingKinds = - kindToEntityMultiMap.asMap().entrySet().stream() - .filter(e -> e.getValue().size() > 1) - .collect(entriesToImmutableMap()); - assertWithMessage( - "Conflicting Ofy kinds found. Tests will break if they are registered with " - + " AppEngineExtension in the same test executor.") - .that(conflictingKinds) - .isEmpty(); - } - appEngine.afterEach(context.getContext()); - } - private void writeAutoIndexFile(String content) throws IOException { asCharSink(new File(appEngine.tmpDir, "datastore-indexes-auto.xml"), UTF_8).write(content); } - - @Entity - private static final class TestObject { - @Id long id; - } } diff --git a/core/src/test/java/google/registry/testing/TestObject.java b/core/src/test/java/google/registry/testing/TestObject.java deleted file mode 100644 index 9d4b12997..000000000 --- a/core/src/test/java/google/registry/testing/TestObject.java +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.testing; - -import com.googlecode.objectify.Key; -import com.googlecode.objectify.annotation.Entity; -import com.googlecode.objectify.annotation.Id; -import google.registry.model.ImmutableObject; -import google.registry.model.annotations.DeleteAfterMigration; -import google.registry.model.annotations.VirtualEntity; -import google.registry.persistence.VKey; - -/** A test model object that can be persisted in any entity group. */ -@DeleteAfterMigration -@Entity -public class TestObject extends ImmutableObject { - - @Id @javax.persistence.Id String id; - - String field; - - public String getId() { - return id; - } - - public String getField() { - return field; - } - - public VKey key() { - return VKey.create(TestObject.class, id); - } - - public static TestObject create(String id) { - return create(id, null); - } - - public static TestObject create(String id, String field) { - TestObject instance = new TestObject(); - instance.id = id; - instance.field = field; - return instance; - } - - /** A test @VirtualEntity model object, which should not be persisted. */ - @Entity - @VirtualEntity - public static class TestVirtualObject extends ImmutableObject { - - @Id String id; - - /** - * Expose a factory method for testing saves of virtual entities; in real life this would never - * be needed for an actual @VirtualEntity. - */ - public static TestVirtualObject create(String id) { - TestVirtualObject instance = new TestVirtualObject(); - instance.id = id; - return instance; - } - - public static Key createKey(String id) { - return Key.create(TestVirtualObject.class, id); - } - } -} diff --git a/core/src/test/java/google/registry/tools/EntityWrapperTest.java b/core/src/test/java/google/registry/tools/EntityWrapperTest.java deleted file mode 100644 index 3f20018b1..000000000 --- a/core/src/test/java/google/registry/tools/EntityWrapperTest.java +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2017 The Nomulus 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 google.registry.tools; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.EntityTranslator; -import com.google.common.collect.ImmutableList; -import com.google.storage.onestore.v3.OnestoreEntity.EntityProto; -import com.google.storage.onestore.v3.OnestoreEntity.Property; -import google.registry.testing.AppEngineExtension; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -/** Unit tests for {@link EntityWrapper}. */ -public final class EntityWrapperTest { - - private static final String TEST_ENTITY_KIND = "TestEntity"; - private static final int ARBITRARY_KEY_ID = 1001; - - @RegisterExtension - public final AppEngineExtension appEngine = AppEngineExtension.builder().withCloudSql().build(); - - @Test - void testEquals() { - // Create an entity with a key and some properties. - Entity entity = new Entity(TEST_ENTITY_KIND, ARBITRARY_KEY_ID); - // Note that we need to specify these as long for property comparisons to work because that's - // how they are deserialized from protos. - entity.setProperty("eeny", 100L); - entity.setProperty("meeny", 200L); - entity.setProperty("miney", 300L); - - EntityProto proto1 = EntityTranslator.convertToPb(entity); - EntityProto proto2 = EntityTranslator.convertToPb(entity); - - // Reorder the property list of proto2 (the protobuf stores this as a repeated field, so - // we just have to clear and re-add them in a different order). - ImmutableList properties = - ImmutableList.of(proto2.getProperty(2), proto2.getProperty(0), proto2.getProperty(1)); - proto2.clearProperty(); - for (Property property : properties) { - proto2.addProperty(property); - } - - // Construct entity objects from the two protos. - Entity e1 = EntityTranslator.createFromPb(proto1); - Entity e2 = EntityTranslator.createFromPb(proto2); - - // Ensure that we have a normalized representation. - EntityWrapper ce1 = new EntityWrapper(e1); - EntityWrapper ce2 = new EntityWrapper(e2); - assertThat(ce1).isEqualTo(ce2); - assertThat(ce1.hashCode()).isEqualTo(ce2.hashCode()); - - // Ensure that the original entity is equal. - assertThat(new EntityWrapper(entity)).isEqualTo(ce1); - } - - @Test - void testDifferentPropertiesNotEqual() { - Entity entity = new Entity(TEST_ENTITY_KIND, ARBITRARY_KEY_ID); - // Note that we need to specify these as long for property comparisons to work because that's - // how they are deserialized from protos. - entity.setProperty("eeny", 100L); - entity.setProperty("meeny", 200L); - entity.setProperty("miney", 300L); - - EntityProto proto1 = EntityTranslator.convertToPb(entity); - - entity.setProperty("tiger!", 400); - EntityProto proto2 = EntityTranslator.convertToPb(entity); - - // Construct entity objects from the two protos. - Entity e1 = EntityTranslator.createFromPb(proto1); - Entity e2 = EntityTranslator.createFromPb(proto2); - - EntityWrapper ce1 = new EntityWrapper(e1); - EntityWrapper ce2 = new EntityWrapper(e2); - assertThat(e1).isEqualTo(e2); // The keys should still be the same. - assertThat(ce1).isNotEqualTo(ce2); - assertThat(ce1.hashCode()).isNotEqualTo(ce2.hashCode()); - } - - @Test - void testDifferentKeysNotEqual() { - EntityProto proto1 = - EntityTranslator.convertToPb(new Entity(TEST_ENTITY_KIND, ARBITRARY_KEY_ID)); - EntityProto proto2 = - EntityTranslator.convertToPb(new Entity(TEST_ENTITY_KIND, ARBITRARY_KEY_ID + 1)); - - // Construct entity objects from the two protos. - Entity e1 = EntityTranslator.createFromPb(proto1); - Entity e2 = EntityTranslator.createFromPb(proto2); - - EntityWrapper ce1 = new EntityWrapper(e1); - EntityWrapper ce2 = new EntityWrapper(e2); - assertThat(ce1).isNotEqualTo(ce2); - assertThat(ce1.hashCode()).isNotEqualTo(ce2.hashCode()); - } - - @Test - void testComparisonAgainstNonComparableEntities() { - EntityWrapper ce = new EntityWrapper(new Entity(TEST_ENTITY_KIND, ARBITRARY_KEY_ID)); - // Note: this has to be "isNotEqualTo()" and not isNotNull() because we want to test the - // equals() method and isNotNull() just checks for "ce != null". - assertThat(ce).isNotEqualTo(null); - assertThat(ce).isNotEqualTo(new Object()); - } -} diff --git a/core/src/test/java/google/registry/webdriver/OteSetupConsoleScreenshotTest.java b/core/src/test/java/google/registry/webdriver/OteSetupConsoleScreenshotTest.java index 0414eef02..2b703e271 100644 --- a/core/src/test/java/google/registry/webdriver/OteSetupConsoleScreenshotTest.java +++ b/core/src/test/java/google/registry/webdriver/OteSetupConsoleScreenshotTest.java @@ -17,8 +17,6 @@ package google.registry.webdriver; import static google.registry.server.Fixture.BASIC; import static google.registry.server.Route.route; -import com.googlecode.objectify.ObjectifyFilter; -import google.registry.model.ofy.OfyFilter; import google.registry.module.frontend.FrontendServlet; import google.registry.server.RegistryTestServer; import org.junit.jupiter.api.extension.RegisterExtension; @@ -33,7 +31,6 @@ public class OteSetupConsoleScreenshotTest extends WebDriverTestCase { new TestServerExtension.Builder() .setRunfiles(RegistryTestServer.RUNFILES) .setRoutes(route("/registrar-ote-setup", FrontendServlet.class)) - .setFilters(ObjectifyFilter.class, OfyFilter.class) .setFixtures(BASIC) .setEmail("Marla.Singer@google.com") .build(); diff --git a/core/src/test/java/google/registry/webdriver/RegistrarConsoleScreenshotTest.java b/core/src/test/java/google/registry/webdriver/RegistrarConsoleScreenshotTest.java index e72aa5e6d..afcac3959 100644 --- a/core/src/test/java/google/registry/webdriver/RegistrarConsoleScreenshotTest.java +++ b/core/src/test/java/google/registry/webdriver/RegistrarConsoleScreenshotTest.java @@ -28,10 +28,8 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT import static google.registry.util.DateTimeUtils.START_OF_TIME; import com.google.common.collect.ImmutableMap; -import com.googlecode.objectify.ObjectifyFilter; import google.registry.model.domain.Domain; import google.registry.model.domain.RegistryLock; -import google.registry.model.ofy.OfyFilter; import google.registry.model.registrar.Registrar.State; import google.registry.model.registrar.RegistrarPoc; import google.registry.module.frontend.FrontendServlet; @@ -59,7 +57,6 @@ class RegistrarConsoleScreenshotTest extends WebDriverTestCase { route("/registrar-settings", FrontendServlet.class), route("/registry-lock-get", FrontendServlet.class), route("/registry-lock-verify", FrontendServlet.class)) - .setFilters(ObjectifyFilter.class, OfyFilter.class) .setFixtures(BASIC) .setEmail("Marla.Singer@crr.com") // from AppEngineExtension.makeRegistrarContact3 .build(); diff --git a/core/src/test/java/google/registry/webdriver/RegistrarConsoleWebTest.java b/core/src/test/java/google/registry/webdriver/RegistrarConsoleWebTest.java index 4a901bcb3..d10f39945 100644 --- a/core/src/test/java/google/registry/webdriver/RegistrarConsoleWebTest.java +++ b/core/src/test/java/google/registry/webdriver/RegistrarConsoleWebTest.java @@ -21,8 +21,6 @@ import static google.registry.testing.DatabaseHelper.loadRegistrar; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.googlecode.objectify.ObjectifyFilter; -import google.registry.model.ofy.OfyFilter; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarAddress; import google.registry.model.registrar.RegistrarPoc; @@ -43,7 +41,6 @@ public class RegistrarConsoleWebTest extends WebDriverTestCase { .setRoutes( route("/registrar", FrontendServlet.class), route("/registrar-settings", FrontendServlet.class)) - .setFilters(ObjectifyFilter.class, OfyFilter.class) .setFixtures(BASIC) .setEmail("Marla.Singer@crr.com") .build(); diff --git a/core/src/test/java/google/registry/webdriver/RegistrarCreateConsoleScreenshotTest.java b/core/src/test/java/google/registry/webdriver/RegistrarCreateConsoleScreenshotTest.java index 1641ad0f1..9b5e29d80 100644 --- a/core/src/test/java/google/registry/webdriver/RegistrarCreateConsoleScreenshotTest.java +++ b/core/src/test/java/google/registry/webdriver/RegistrarCreateConsoleScreenshotTest.java @@ -17,8 +17,6 @@ package google.registry.webdriver; import static google.registry.server.Fixture.BASIC; import static google.registry.server.Route.route; -import com.googlecode.objectify.ObjectifyFilter; -import google.registry.model.ofy.OfyFilter; import google.registry.module.frontend.FrontendServlet; import google.registry.server.RegistryTestServer; import org.junit.jupiter.api.extension.RegisterExtension; @@ -33,7 +31,6 @@ class RegistrarCreateConsoleScreenshotTest extends WebDriverTestCase { new TestServerExtension.Builder() .setRunfiles(RegistryTestServer.RUNFILES) .setRoutes(route("/registrar-create", FrontendServlet.class)) - .setFilters(ObjectifyFilter.class, OfyFilter.class) .setFixtures(BASIC) .setEmail("Marla.Singer@google.com") .build(); diff --git a/core/src/test/java/google/registry/webdriver/TestServerExtension.java b/core/src/test/java/google/registry/webdriver/TestServerExtension.java index 8b8ecbb57..2b34601e3 100644 --- a/core/src/test/java/google/registry/webdriver/TestServerExtension.java +++ b/core/src/test/java/google/registry/webdriver/TestServerExtension.java @@ -37,7 +37,6 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.LinkedBlockingDeque; -import javax.servlet.Filter; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; @@ -59,7 +58,6 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC private final BlockingQueue> jobs = new LinkedBlockingDeque<>(); private final ImmutableMap runfiles; private final ImmutableList routes; - private final ImmutableList> filters; private TestServer testServer; private Thread serverThread; @@ -67,12 +65,10 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC private TestServerExtension( ImmutableMap runfiles, ImmutableList routes, - ImmutableList> filters, ImmutableList fixtures, String email) { this.runfiles = runfiles; this.routes = routes; - this.filters = filters; this.fixtures = fixtures; // We create an GAE-Admin user, and then use AuthenticatedRegistrarAccessor.bypassAdminCheck to // choose whether the user is an admin or not. @@ -96,8 +92,7 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC // can access this server. getExternalAddressOfLocalSystem().getHostAddress(), pickUnusedPort()), runfiles, - routes, - filters); + routes); } catch (UnknownHostException e) { throw new IllegalStateException(e); } @@ -239,14 +234,12 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC /** * Builder for {@link TestServerExtension}. * - *

This builder has three required fields: {@link #setRunfiles}, {@link #setRoutes}, and {@link - * #setFilters}. + *

This builder has two required fields: {@link #setRunfiles} and {@link #setRoutes}. */ public static final class Builder { private ImmutableMap runfiles; private ImmutableList routes; - ImmutableList> filters; private ImmutableList fixtures = ImmutableList.of(); private String email; @@ -263,13 +256,6 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC return this; } - /** Sets the list of servlet {@link Filter} objects for {@link TestServer}. */ - @SafeVarargs - public final Builder setFilters(Class... filters) { - this.filters = ImmutableList.copyOf(filters); - return this; - } - /** Sets an ordered list of Datastore fixtures that should be loaded on startup. */ public Builder setFixtures(Fixture... fixtures) { this.fixtures = ImmutableList.copyOf(fixtures); @@ -291,7 +277,6 @@ public final class TestServerExtension implements BeforeEachCallback, AfterEachC return new TestServerExtension( checkNotNull(this.runfiles), checkNotNull(this.routes), - checkNotNull(this.filters), checkNotNull(this.fixtures), checkNotNull(this.email)); } diff --git a/docs/install.md b/docs/install.md index b741d2362..0714815d9 100644 --- a/docs/install.md +++ b/docs/install.md @@ -49,7 +49,6 @@ also defined: incrementally. * `python` -- Some Python reporting scripts * `release` -- Configuration for our continuous integration process. -* `third_party` -- External dependencies. ## Build the codebase diff --git a/processor/build.gradle b/processor/build.gradle index aef280774..d829cef57 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -19,11 +19,6 @@ plugins { dependencies { def deps = rootProject.dependencyMap - // Custom-built objectify jar at commit ecd5165, included in Nomulus - // release. - implementation files( - "${rootDir}/third_party/objectify/v4_1/objectify-4.1.3.jar") - implementation deps['com.google.code.findbugs:jsr305'] implementation deps['com.google.guava:guava'] implementation deps['com.squareup:javapoet'] diff --git a/third_party/objectify/v4_1/LICENSE b/third_party/objectify/v4_1/LICENSE deleted file mode 100644 index 2f078a2b3..000000000 --- a/third_party/objectify/v4_1/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2009-2013 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/third_party/objectify/v4_1/README.md b/third_party/objectify/v4_1/README.md deleted file mode 100644 index d4719db18..000000000 --- a/third_party/objectify/v4_1/README.md +++ /dev/null @@ -1,19 +0,0 @@ -This library includes custom serializers for AppEngine classes in -com.google.appengine.api.* packages. This is necessary because serializers -are discovered by AppEngine using a naming pattern that requires that the -data and serializer classes be in the same package (similar to how the Java -Beans introspector finds BeanInfo classes). - -In Objectify versions 4.1 and later, the GWT emulation classes were broken -out into a separate versioned jar. Since we are jarjar repackaging the core -Objectify library to include a version number in the package, we need to -include the GWT files in this folder and apply the same changes to them. - -The specific patches are: - -* Fix ofy().load().fromEntity(...) to respect @OnLoad callbacks. -* Add Session.getKeys() to enumerate everything read in a session. - -These changes are already in upstream, but no 4.x release has been made -that incorporates them. Therefore we need to backport them and vendor the -Objectify libarary here. diff --git a/third_party/objectify/v4_1/objectify-4.1.3-src.jar b/third_party/objectify/v4_1/objectify-4.1.3-src.jar deleted file mode 100644 index 400bbfdc3..000000000 Binary files a/third_party/objectify/v4_1/objectify-4.1.3-src.jar and /dev/null differ diff --git a/third_party/objectify/v4_1/objectify-4.1.3.jar b/third_party/objectify/v4_1/objectify-4.1.3.jar deleted file mode 100644 index e6f55f557..000000000 Binary files a/third_party/objectify/v4_1/objectify-4.1.3.jar and /dev/null differ diff --git a/util/build.gradle b/util/build.gradle index 7c1ff3cf4..87d24e7ab 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -57,7 +57,6 @@ dependencies { testImplementation deps['org.mockito:mockito-core'] testImplementation deps['org.mockito:mockito-junit-jupiter'] testImplementation deps['org.testcontainers:junit-jupiter'] - testImplementation files("${rootDir}/third_party/objectify/v4_1/objectify-4.1.3.jar") testImplementation project(path: ':common', configuration: 'testing') testRuntimeOnly deps['com.google.flogger:flogger-system-backend'] annotationProcessor deps['com.google.auto.value:auto-value'] diff --git a/util/src/main/java/google/registry/util/PlaceholderEnvironment.java b/util/src/main/java/google/registry/util/PlaceholderEnvironment.java deleted file mode 100644 index c8b80401b..000000000 --- a/util/src/main/java/google/registry/util/PlaceholderEnvironment.java +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2020 The Nomulus 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 google.registry.util; - -import com.google.apphosting.api.ApiProxy.Environment; -import com.google.common.collect.ImmutableMap; -import java.util.Map; - -/** A placeholder GAE environment class that is used when masquerading a thread as a GAE thread. */ -public final class PlaceholderEnvironment implements Environment { - - private static final PlaceholderEnvironment INSTANCE = new PlaceholderEnvironment(); - - public static PlaceholderEnvironment get() { - return INSTANCE; - } - - private PlaceholderEnvironment() {} - - @Override - public String getAppId() { - return "PlaceholderAppId"; - } - - @Override - public Map getAttributes() { - return ImmutableMap.of(); - } - - @Override - public String getModuleId() { - throw new UnsupportedOperationException(); - } - - @Override - public String getVersionId() { - throw new UnsupportedOperationException(); - } - - @Override - public String getEmail() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isLoggedIn() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isAdmin() { - throw new UnsupportedOperationException(); - } - - @Override - public String getAuthDomain() { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("deprecation") - @Override - public String getRequestNamespace() { - throw new UnsupportedOperationException(); - } - - @Override - public long getRemainingMillis() { - throw new UnsupportedOperationException(); - } -}