Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
437dd84
Allow registering env types using their `class` - `@Internal` use only.
serhii-lekariev Jun 10, 2020
456a039
Decrease `Production` env type access level.
serhii-lekariev Jun 10, 2020
443fdeb
Fix exception type, add tests.
serhii-lekariev Jun 10, 2020
6760997
Check whether the env type has a parameterless ctor.
serhii-lekariev Jun 10, 2020
7a22182
Merge branch 'master' into stricter-env-api
serhii-lekariev Jun 10, 2020
9b3e077
Fix PMD.
serhii-lekariev Jun 10, 2020
d0b36e7
Merge remote-tracking branch 'origin/stricter-env-api' into stricter-…
serhii-lekariev Jun 10, 2020
5453ce2
Fix documentation.
serhii-lekariev Jun 10, 2020
b423355
Fix a wrong method call. Tweak the tests so that they check that the …
serhii-lekariev Jun 10, 2020
b29fc35
Tweak doc wording.
serhii-lekariev Jun 10, 2020
9b725ed
Fix tests.
serhii-lekariev Jun 10, 2020
0027d3c
Fix warning suppression wording.
serhii-lekariev Jun 10, 2020
e7f15bf
Extract a utility.
serhii-lekariev Jun 11, 2020
c1da10f
Fix formatting.
serhii-lekariev Jun 11, 2020
c5cae0c
Test env type caching.
serhii-lekariev Jun 11, 2020
a3e5602
Add a simpler env type caching test. Also `license-report` and `pom`.
serhii-lekariev Jun 11, 2020
dd59607
Fix formatting, wording, test declaration ordering. Explain a
serhii-lekariev Jun 11, 2020
252817d
Extract the instantiation utility.
serhii-lekariev Jun 11, 2020
323faeb
Expose a `setTo(Class<? extends EnvironmentType>)`.
serhii-lekariev Jun 11, 2020
90e20b2
`@Internalize` a method.
serhii-lekariev Jun 11, 2020
a26cd0c
Fix documentation and naming errors.
serhii-lekariev Jun 11, 2020
7f9655b
Cache the class of the env type instead of its instance.
serhii-lekariev Jun 11, 2020
5d79b22
Fix documentation errors.
serhii-lekariev Jun 11, 2020
b317714
Allow non package-private ctors.
serhii-lekariev Jun 11, 2020
a812734
Correct documentation errors.
serhii-lekariev Jun 11, 2020
331ca59
Correct docs.
serhii-lekariev Jun 11, 2020
5522e8c
Correct documentation errors.
serhii-lekariev Jun 11, 2020
47ed3bd
Extract utilities.
serhii-lekariev Jun 11, 2020
db60efe
Clean up.
serhii-lekariev Jun 11, 2020
044d76e
Mention erasing the registered classes.
serhii-lekariev Jun 11, 2020
38ff164
Fix documentation.
serhii-lekariev Jun 11, 2020
aa52481
Update `config`.
serhii-lekariev Jun 11, 2020
431dd04
Extract reflection utils into a single `Invokables` class.
serhii-lekariev Jun 12, 2020
18d3fd1
Add `@throws` documentation.
serhii-lekariev Jun 12, 2020
8c52731
Hide a method that looks for a parameterless constructor. Its users
serhii-lekariev Jun 12, 2020
e1a1018
Shorten a method name.
serhii-lekariev Jun 12, 2020
9013ab8
Fix Javadoc mistakes.
serhii-lekariev Jun 12, 2020
0da0c93
Fix Javadoc errors.
serhii-lekariev Jun 12, 2020
f67ff1b
Rearrange utitlity methods, fix wording mistakes.
serhii-lekariev Jun 12, 2020
2558a82
Fix a wrong link.
serhii-lekariev Jun 12, 2020
e220c60
Add a Javadoc paragraph for a `@Test` method.
serhii-lekariev Jun 13, 2020
6b4f302
`register` an env on `setTo`.
serhii-lekariev Jun 13, 2020
858bd7d
Prefer `register(Class)` over `register(EnvironmentType)` in tests.
serhii-lekariev Jun 13, 2020
459a670
Mention the fact that environment types are registered automatically.
serhii-lekariev Jun 13, 2020
36868c6
Tweak Javadoc wording.
serhii-lekariev Jun 13, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ object Versions {
val errorProne = "2.3.4"
val errorProneJavac = "9+181-r4173-1" // taken from here: https://github.com/tbroyer/gradle-errorprone-plugin/blob/v0.8/build.gradle.kts
val errorPronePlugin = "1.1.1"
val pmd = "6.20.0"
val pmd = "6.24.0"
val checkstyle = "8.29"
val protobufPlugin = "0.8.12"
val appengineApi = "1.9.79"
Expand Down
118 changes: 95 additions & 23 deletions base/src/main/java/io/spine/base/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.spine.annotation.Internal;
import io.spine.annotation.SPI;
import org.checkerframework.checker.nullness.qual.Nullable;

import static com.google.common.base.Preconditions.checkNotNull;
import static io.spine.reflect.Invokables.callParameterlessCtor;
import static io.spine.util.Exceptions.newIllegalStateException;

/**
* Provides information about the environment (current platform used, etc.).
*
* <h1>Environment Type Detection</h1>
*
* <p>Current implementation allows to {@linkplain #is(Class) check} the type of the current
* environment, or {@linkplain #type() get the instance of the current environment}.
* <p>Current implementation allows to {@linkplain #type() obtain the type} of the current
* environment, or to check whether current environment type {@linkplain #is(Class) matches
* another type}.
* Two environment types exist out of the box:
*
* <ul>
Expand Down Expand Up @@ -104,9 +107,37 @@
* }
* </pre>
*
* <h1>Caching</h1>
*
* <p>{@code Environment} caches the {@code EnvironmentType} once its calculated.
* This means that if one environment type has been found to be active, its instance is saved.
* If later it becomes logically inactive, e.g. the environment variable that's used to check the
* environment type changes, {@code Environment} is still going to return the cached value. To
* overwrite the value use {@link #setTo(EnvironmentType)}. Also, the value may be
* {@linkplain #reset}.
*
* For example:
* <pre>
* Environment environment = Environment.instance();
* EnvironmentType awsLambda = new AwsLambda();
* environment.register(awsLambda);
* assertThat(environment.is(AwsLambda.class)).isTrue();
*
* System.clearProperty(AwsLambda.AWS_ENV_VARIABLE);
*
* // Even though `AwsLambda` is not active, we have cached the value, and `is(AwsLambda.class)`
* // is `true`.
* assertThat(environment.is(AwsLambda.class)).isTrue();
*
* environment.reset();
*
* // When `reset` explicitly, cached value is erased.
* assertThat(environment.is(AwsLambda.class)).isFalse();
* </pre>
*
* <p><b>When registering custom types, please ensure</b> their mutual exclusivity.
* If two or more environment types {@linkplain EnvironmentType#enabled() consider themselves
* enabled} at the same time, the behaviour of {@link #is(Class)}} is undefined.
* enabled} at the same time, the behaviour of {@link #is(Class)} is undefined.
*
* @see EnvironmentType
* @see Tests
Expand All @@ -121,7 +152,7 @@ public final class Environment {
private static final Environment INSTANCE = new Environment();

private ImmutableList<EnvironmentType> knownEnvTypes;
private @Nullable EnvironmentType currentEnvType;
private @Nullable Class<? extends EnvironmentType> currentEnvType;

private Environment() {
this.knownEnvTypes = BASE_TYPES;
Expand Down Expand Up @@ -159,6 +190,24 @@ public Environment register(EnvironmentType environmentType) {
return this;
}

/**
* Remembers the specified environment type, allowing {@linkplain #is(Class) to
* determine whether it's enabled} later.
*
* <p>The specified {@code type} must have a parameterless constructor. The
* {@code EnvironmentType} is going to be instantiated using the parameterless constructor.
*
* @param type
* environment type to register
* @return this instance of {@code Environment}
*/
@Internal
@CanIgnoreReturnValue
Environment register(Class<? extends EnvironmentType> type) {
EnvironmentType envTypeInstance = callParameterlessCtor(type);
return register(envTypeInstance);
}

/** Returns the singleton instance. */
public static Environment instance() {
return INSTANCE;
Expand All @@ -176,7 +225,7 @@ public Environment createCopy() {
/**
* Determines whether the current environment is the same as the specified one.
*
* <p>If {@linkplain #register(EnvironmentType) custom env types have been defined},
* <p>If {@linkplain #register(EnvironmentType) custom env types have been registered},
* goes through them in the latest-registered to earliest-registered order.
* Then, checks {@link Tests} and {@link Production}.
*
Expand All @@ -200,14 +249,14 @@ public Environment createCopy() {
* @return whether the current environment type matches the specified one
*/
public boolean is(Class<? extends EnvironmentType> type) {
EnvironmentType currentEnv = cachedOrCalculated();
boolean result = type.isInstance(currentEnv);
Class<? extends EnvironmentType> currentEnv = cachedOrCalculated();
boolean result = type.isAssignableFrom(currentEnv);
return result;
}

/** Returns the instance of the current environment. */
public EnvironmentType type() {
EnvironmentType currentEnv = cachedOrCalculated();
/** Returns the type of the current environment. */
public Class<? extends EnvironmentType> type() {
Class<? extends EnvironmentType> currentEnv = cachedOrCalculated();
return currentEnv;
}

Expand All @@ -225,7 +274,7 @@ public boolean isTests() {
/**
* Verifies if the code runs in the production mode.
*
* <p>This method is opposite to {@link #isTests()}
* <p>This method is opposite to {@link #isTests()}.
*
* @return {@code true} if the code runs in the production mode, {@code false} otherwise
* @see Production
Expand All @@ -249,24 +298,43 @@ public void restoreFrom(Environment copy) {
}

/**
* Forces the specified environment type to be the current one.
* Sets the current environment type to {@code type.getClass()}. Overrides the current value.
*
* If the supplied type was not {@linkplain #register(EnvironmentType) registered} previously,
* it is registered.
*/
@VisibleForTesting
public void setTo(EnvironmentType type) {
this.currentEnvType = checkNotNull(type);
checkNotNull(type);
register(type);
this.currentEnvType = type.getClass();
}

/**
* Sets the current environment type to the specified one. Overrides the current value.
*
* If the supplied type was not {@linkplain #register(EnvironmentType) registered} previously,
* it is registered.
*/
@Internal
@VisibleForTesting
public void setTo(Class<? extends EnvironmentType> type) {
checkNotNull(type);
register(type);
this.currentEnvType = type;
}

/**
* Turns the test mode on.
*
* <p>This method is opposite to {@link #setToProduction()}.
*
* @deprecated use {@link #setTo(EnvironmentType)}
* @deprecated use {@link #setTo(Class)}
*/
@Deprecated
@VisibleForTesting
public void setToTests() {
this.currentEnvType = new Tests();
this.currentEnvType = Tests.class;
Tests.enable();
}

Expand All @@ -275,17 +343,20 @@ public void setToTests() {
*
* <p>This method is opposite to {@link #setToTests()}.
*
* @deprecated use {@link #setTo(EnvironmentType)}
* @deprecated use {@link #setTo(Class)}
*/
@Deprecated
@VisibleForTesting
public void setToProduction() {
this.currentEnvType = new Production();
this.currentEnvType = Production.class;
Tests.clearTestingEnvVariable();
}

/**
* Resets the instance and clears the {@link Tests#ENV_KEY_TESTS} variable.
*
* <p>Erases all registered environment types, leaving only {@code Tests} and {@code
* Production}.
*/
@VisibleForTesting
public void reset() {
Expand All @@ -294,17 +365,18 @@ public void reset() {
Tests.clearTestingEnvVariable();
}

private EnvironmentType cachedOrCalculated() {
EnvironmentType result = currentEnvType != null
? currentEnvType
: currentType();
private Class<? extends EnvironmentType> cachedOrCalculated() {
Class<? extends EnvironmentType> result = currentEnvType != null
? currentEnvType
: currentType();
this.currentEnvType = result;
return result;
}

private EnvironmentType currentType() {
private Class<? extends EnvironmentType> currentType() {
for (EnvironmentType type : knownEnvTypes) {
if (type.enabled()) {
return type;
return type.getClass();
}
}

Expand Down
5 changes: 4 additions & 1 deletion base/src/main/java/io/spine/base/Production.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,22 @@

package io.spine.base;

import com.google.errorprone.annotations.Immutable;

/**
* A non-testing environment.
*
* <p>If the system is not in the {@link Tests} environment, it is in the production environment.
*/
@Immutable
public final class Production extends EnvironmentType {

/**
* Creates a new instance.
*
* <p>All {@code Production} instances are immutable and equivalent.
*/
public Production() {
Production() {
super();
}

Expand Down
4 changes: 3 additions & 1 deletion base/src/main/java/io/spine/base/Tests.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;

import java.util.regex.Pattern;

Expand All @@ -33,6 +34,7 @@
*
* <p>This option is mutually exclusive with {@link Production}, i.e. one of them is always enabled.
*/
@Immutable
@SuppressWarnings("AccessOfSystemProperties" /* is necessary for this class to function */)
public final class Tests extends EnvironmentType {

Expand All @@ -56,7 +58,7 @@ public final class Tests extends EnvironmentType {
*
* <p>All {@code Tests} instances are immutable and equivalent.
*/
public Tests() {
Tests() {
super();
}

Expand Down
Loading