diff --git a/java/google/registry/config/ConfigModule.java b/java/google/registry/config/ConfigModule.java index 3258d96f1..c818bfb6e 100644 --- a/java/google/registry/config/ConfigModule.java +++ b/java/google/registry/config/ConfigModule.java @@ -47,6 +47,10 @@ import org.joda.time.Duration; * in the user's repository. For this to work, other files need to be copied too, such as * {@link google.registry.module.backend.BackendComponent BackendComponent}. This allows modules to * be substituted at the {@code @Component} level. + * + *
There's also a deprecated configuration class that needs to be overridden and supplied via a + * system property. See the instructions in {@link ProductionRegistryConfigExample} and + * {@link RegistryConfigLoader}. */ @Module public final class ConfigModule { diff --git a/java/google/registry/config/ProductionRegistryConfigExample.java b/java/google/registry/config/ProductionRegistryConfigExample.java new file mode 100644 index 000000000..ccabf8735 --- /dev/null +++ b/java/google/registry/config/ProductionRegistryConfigExample.java @@ -0,0 +1,236 @@ +// Copyright 2016 The Domain Registry Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.config; + +import static com.google.common.base.Preconditions.checkNotNull; +import static google.registry.config.ConfigUtils.makeUrl; +import static org.joda.time.Duration.standardDays; + +import com.google.appengine.api.utils.SystemProperty; +import com.google.common.base.Ascii; +import com.google.common.base.Joiner; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.net.HostAndPort; +import java.net.URL; +import javax.annotation.concurrent.Immutable; +import org.joda.time.Duration; + +/** + * Default production configuration for global constants that can't be injected. + * + *
Warning: Editing this file in a forked repository is not recommended. The recommended + * approach is to copy this file, give it a different name, and then change the system property + * described in the {@link RegistryConfigLoader} documentation. + */ +@Immutable +public final class ProductionRegistryConfigExample implements RegistryConfig { + + private final RegistryEnvironment environment; + + private static final String RESERVED_TERMS_EXPORT_DISCLAIMER = "" + + "# This list contains reserve terms for the TLD. Other terms may be reserved\n" + + "# but not included in this list, including terms EXAMPLE REGISTRY chooses not\n" + + "# to publish, and terms that ICANN commonly mandates to be reserved. This\n" + + "# list is subject to change and the most up-to-date source is always to\n" + + "# check availability directly with the Registry server.\n"; + + public ProductionRegistryConfigExample(RegistryEnvironment environment) { + this.environment = checkNotNull(environment); + } + + @Override + public String getProjectId() { + switch (environment) { + case PRODUCTION: + return "domain-registry"; + default: + return "domain-registry-" + Ascii.toLowerCase(environment.name()); + } + } + + @Override + public int getCommitLogBucketCount() { + return 100; // if you decrease this number, the world ends + } + + /** + * {@inheritDoc} + * + *
Thirty days makes a sane default, because it's highly unlikely we'll ever need to generate a
+ * deposit older than that. And if we do, we could always bring up a separate App Engine instance
+ * and replay the commit logs off GCS.
+ */
+ @Override
+ public Duration getCommitLogDatastoreRetention() {
+ return Duration.standardDays(30);
+ }
+
+ @Override
+ public String getSnapshotsBucket() {
+ return getProjectId() + "-snapshots";
+ }
+
+ @Override
+ public String getDomainListsBucket() {
+ return getProjectId() + "-domain-lists";
+ }
+
+ @Override
+ public String getCommitsBucket() {
+ return getProjectId() + "-commits";
+ }
+
+ @Override
+ public String getZoneFilesBucket() {
+ return getProjectId() + "-zonefiles";
+ }
+
+ @Override
+ public String getEscrowFileImportBucket() {
+ return getProjectId() + "-escrow-import";
+ }
+
+ @Override
+ public boolean getTmchCaTestingMode() {
+ switch (environment) {
+ case PRODUCTION:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ @Override
+ public String getTmchMarksdbUrl() {
+ switch (environment) {
+ case PRODUCTION:
+ return "https://ry.marksdb.org";
+ default:
+ return "https://test.ry.marksdb.org";
+ }
+ }
+
+ @Override
+ public Optional The goal of this custom configuration system is to have our project environments configured
* in type-safe Java code that can be refactored, rather than XML files and system properties.
diff --git a/java/google/registry/config/RegistryConfigLoader.java b/java/google/registry/config/RegistryConfigLoader.java
new file mode 100644
index 000000000..61383d230
--- /dev/null
+++ b/java/google/registry/config/RegistryConfigLoader.java
@@ -0,0 +1,75 @@
+// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package google.registry.config;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * System property loader of {@link RegistryConfig} instance.
+ *
+ * This class reflectively loads the Java class defined by the system property
+ * {@value #REGISTRY_CONFIG_PROPERTY} whose default value is {@value #REGISTRY_CONFIG_DEFAULT} and
+ * can be set in {@code appengine-web.xml}. Once the class is loaded, its constructor is called,
+ * passing the {@link RegistryEnvironment} as a single parameter.
+ */
+@ThreadSafe
+public final class RegistryConfigLoader {
+
+ public static final String REGISTRY_CONFIG_PROPERTY = "com.google.domain.registry.config";
+ public static final String REGISTRY_CONFIG_DEFAULT =
+ "google.registry.config.ProductionRegistryConfigExample";
+
+ static RegistryConfig load(RegistryEnvironment environment) {
+ String className = System.getProperty(REGISTRY_CONFIG_PROPERTY, REGISTRY_CONFIG_DEFAULT);
+ Class> clazz;
+ try {
+ clazz = Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(String.format(
+ "Failed to load '%s' as specified by system property '%s'",
+ className, REGISTRY_CONFIG_PROPERTY), e);
+ }
+ if (!RegistryConfig.class.isAssignableFrom(clazz)) {
+ throw new RuntimeException(String.format(
+ "%s does not implement %s",
+ clazz.getSimpleName(), RegistryConfig.class.getSimpleName()));
+ }
+ @SuppressWarnings("unchecked")
+ Class extends RegistryConfig> clazzy = (Class extends RegistryConfig>) clazz;
+ if (!Modifier.isPublic(clazzy.getModifiers())) {
+ throw new RuntimeException(String.format(
+ "Must be a public class: %s", clazzy.getCanonicalName()));
+ }
+ Constructor extends RegistryConfig> constructor;
+ try {
+ constructor = clazzy.getConstructor(RegistryEnvironment.class);
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new RuntimeException(String.format(
+ "Must have a public constructor(RegistryEnvironment): %s", clazzy.getCanonicalName()), e);
+ }
+ try {
+ return constructor.newInstance(environment);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(
+ String.format("%s constructor threw an exception", clazzy.getSimpleName()), e);
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException e) {
+ throw new RuntimeException(
+ String.format("Failed to instantiate: %s", clazz.getCanonicalName()), e);
+ }
+ }
+}
diff --git a/java/google/registry/config/RegistryEnvironment.java b/java/google/registry/config/RegistryEnvironment.java
index 16aec6da6..613934763 100644
--- a/java/google/registry/config/RegistryEnvironment.java
+++ b/java/google/registry/config/RegistryEnvironment.java
@@ -79,11 +79,8 @@ public enum RegistryEnvironment {
@Nullable
private static RegistryConfig configOverride;
- // TODO(b/19247780) Use true dependency injection for this. In the mean time, if you're not
- // Google, you'll need to change this to include your own config class implementation at compile
- // time.
private static final RegistryConfig testingConfig = new TestRegistryConfig();
- private final RegistryConfig config = new TestRegistryConfig();
+ private final RegistryConfig config = RegistryConfigLoader.load(this);
/** System property for configuring which environment we should use. */
public static final String PROPERTY = "google.registry.environment";