Merge pull request #6 from kemitix/value-deadlock-fix

Value: Avoid danger of JVM-level deadlock during initialisation
This commit is contained in:
Paul Campbell 2017-08-26 21:20:51 +01:00 committed by GitHub
commit 03eb1398bd
6 changed files with 138 additions and 94 deletions

View file

@ -5,6 +5,7 @@ CHANGELOG
----- -----
* Add `.travis-support` * Add `.travis-support`
* Avoid danger of JVM-level deadlock during `Value` initialisation
* Avoid danger of JVM-level deadlock during `Condition` initialisation * Avoid danger of JVM-level deadlock during `Condition` initialisation
* Upgrade `kemitix-parent` to 3.2.0 * Upgrade `kemitix-parent` to 3.2.0
* Upgrade `kemitix-checkstyle-parent` to 3.2.0 * Upgrade `kemitix-checkstyle-parent` to 3.2.0

View file

@ -26,7 +26,7 @@ package net.kemitix.conditional;
* *
* @author Paul Campbell (pcampbell@kemitix.net). * @author Paul Campbell (pcampbell@kemitix.net).
*/ */
public final class FalseCondition implements Condition { final class FalseCondition implements Condition {
protected static final Condition FALSE = new net.kemitix.conditional.FalseCondition(); protected static final Condition FALSE = new net.kemitix.conditional.FalseCondition();

View file

@ -0,0 +1,64 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2017 Paul Campbell
*
* 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.
*/
package net.kemitix.conditional;
import java.util.function.Supplier;
/**
* An intermediate state where the clause has evaluated to false.
*
* @param <T> the type of the value
*
* @author Paul Campbell (pcampbell@kemitix.net).
*/
class FalseValueClause<T> implements Value.ValueClause<T> {
protected static final Value.ValueClause FALSE = new FalseValueClause();
@Override
public ValueSupplier<T> then(final Supplier<T> trueSupplier) {
return new FalseValueSupplier();
}
@Override
public Value.ValueClause<T> and(final boolean clause) {
return this;
}
@Override
public Value.ValueClause<T> or(final boolean clause) {
return Value.where(clause);
}
/**
* An intermediate result of the {@link Value} where the clause has evaluated to false.
*/
private class FalseValueSupplier implements ValueSupplier<T> {
@Override
public T otherwise(final Supplier<T> falseSupplier) {
return falseSupplier.get();
}
}
}

View file

@ -26,7 +26,7 @@ package net.kemitix.conditional;
* *
* @author Paul Campbell (pcampbell@kemitix.net). * @author Paul Campbell (pcampbell@kemitix.net).
*/ */
public final class TrueCondition implements Condition { final class TrueCondition implements Condition {
protected static final Condition TRUE = new net.kemitix.conditional.TrueCondition(); protected static final Condition TRUE = new net.kemitix.conditional.TrueCondition();

View file

@ -0,0 +1,69 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2017 Paul Campbell
*
* 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.
*/
package net.kemitix.conditional;
import lombok.RequiredArgsConstructor;
import java.util.function.Supplier;
/**
* An intermediate state where the clause has evaluated to true.
*
* @param <T> the type of the value
*
* @author Paul Campbell (pcampbell@kemitix.net).
*/
class TrueValueClause<T> implements Value.ValueClause<T> {
protected static final Value.ValueClause TRUE = new TrueValueClause();
@Override
public ValueSupplier<T> then(final Supplier<T> trueSupplier) {
return new TrueValueSupplier(trueSupplier);
}
@Override
public Value.ValueClause<T> and(final boolean clause) {
return Value.where(clause);
}
@Override
public Value.ValueClause<T> or(final boolean clause) {
return this;
}
/**
* An intermediate result of the {@link Value} where the clause has evaluated to true.
*/
@RequiredArgsConstructor
private class TrueValueSupplier implements ValueSupplier<T> {
private final Supplier<T> valueSupplier;
@Override
public T otherwise(final Supplier<T> falseSupplier) {
return valueSupplier.get();
}
}
}

View file

@ -21,14 +21,7 @@
package net.kemitix.conditional; package net.kemitix.conditional;
import lombok.RequiredArgsConstructor;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collections;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* A Value from an if-then-else in a functional-style. * A Value from an if-then-else in a functional-style.
@ -37,14 +30,6 @@ import java.util.stream.Stream;
*/ */
public interface Value { public interface Value {
ValueClause TRUE = new TrueValueClause();
ValueClause FALSE = new FalseValueClause();
Map<Boolean, ValueClause> VALUE_CLAUSES = Collections.unmodifiableMap(
Stream.of(new SimpleEntry<>(true, TRUE), new SimpleEntry<>(false, FALSE))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
/** /**
* Create a new {@link ValueClause} for the clause. * Create a new {@link ValueClause} for the clause.
* *
@ -53,9 +38,9 @@ public interface Value {
* *
* @return a true or false value clause * @return a true or false value clause
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({"unchecked", "avoidinlineconditionals"})
static <T> ValueClause<T> where(final boolean clause) { static <T> ValueClause<T> where(final boolean clause) {
return (ValueClause<T>) VALUE_CLAUSES.get(clause); return (ValueClause<T>) (clause ? TrueValueClause.TRUE : FalseValueClause.FALSE);
} }
/** /**
@ -146,79 +131,4 @@ public interface Value {
} }
/**
* An intermediate state where the clause has evaluated to true.
*
* @param <T> the type of the value
*/
class TrueValueClause<T> implements ValueClause<T> {
@Override
public ValueSupplier<T> then(final Supplier<T> trueSupplier) {
return new TrueValueSupplier(trueSupplier);
}
@Override
public ValueClause<T> and(final boolean clause) {
return Value.where(clause);
}
@Override
public ValueClause<T> or(final boolean clause) {
return this;
}
/**
* An intermediate result of the {@link Value} where the clause has evaluated to true.
*/
@RequiredArgsConstructor
private class TrueValueSupplier implements ValueSupplier<T> {
private final Supplier<T> valueSupplier;
@Override
public T otherwise(final Supplier<T> falseSupplier) {
return valueSupplier.get();
}
}
}
/**
* An intermediate state where the clause has evaluated to false.
*
* @param <T> the type of the value
*/
class FalseValueClause<T> implements ValueClause<T> {
@Override
public ValueSupplier<T> then(final Supplier<T> trueSupplier) {
return new FalseValueSupplier();
}
@Override
public ValueClause<T> and(final boolean clause) {
return this;
}
@Override
public ValueClause<T> or(final boolean clause) {
return Value.where(clause);
}
/**
* An intermediate result of the {@link Value} where the clause has evaluated to false.
*/
private class FalseValueSupplier implements ValueSupplier<T> {
@Override
public T otherwise(final Supplier<T> falseSupplier) {
return falseSupplier.get();
}
}
}
} }