diff --git a/error/src/main/java/com/pkb/common/error/ValidationException.java b/error/src/main/java/com/pkb/common/error/ValidationException.java deleted file mode 100644 index 9a01d5d7..00000000 --- a/error/src/main/java/com/pkb/common/error/ValidationException.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.pkb.common.error; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.ejb.ApplicationException; - -import com.google.common.collect.Lists; - -@ApplicationException(rollback = true) -public class ValidationException extends RuntimeException { - - private static final long serialVersionUID = 1L; - - private List errors = new ArrayList<>(); - - public ValidationException(String errorCode, String description, Object... arguments) { - this(ErrorBuilder.errorOf(errorCode, description, arguments)); - } - - public ValidationException(Error... error) { - this(Lists.newArrayList(error)); - } - - public ValidationException(List errors) { - super(); - this.errors.addAll(errors); - } - - public List getErrors() { - return Collections.unmodifiableList(errors); - } -} diff --git a/infrastructure/pom.xml b/infrastructure/pom.xml index c40bb407..e3778f66 100644 --- a/infrastructure/pom.xml +++ b/infrastructure/pom.xml @@ -63,6 +63,10 @@ com.github.karsaig approvalcrest-junit-jupiter + + org.hibernate + hibernate-core + diff --git a/infrastructure/src/main/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizer.java b/infrastructure/src/main/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizer.java new file mode 100644 index 00000000..9ee1d400 --- /dev/null +++ b/infrastructure/src/main/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizer.java @@ -0,0 +1,92 @@ +package com.pkb.infrastructure.hibernate.id.enhanced; + +import java.io.Serializable; + +import org.hibernate.id.IntegralDataTypeHolder; +import org.hibernate.id.enhanced.AccessCallback; +import org.hibernate.id.enhanced.Optimizer; +import org.hibernate.id.enhanced.PooledLoOptimizer; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import com.pkb.common.ClearableInternalState; + +/** + * Extend PooledLoOptimizer to track instances and reset internal state (for running tests) + */ +public class ResettablePooledLoOptimizer implements ClearableInternalState, Optimizer { + + public static final String OPTIMIZER_CANONICAL_NAME ="com.pkb.infrastructure.hibernate.id.enhanced.ResettablePooledLoOptimizer"; + + private PooledLoOptimizer optimizer; + + // only used for resetting state (in e2e tests) + private static final Cache clearableInstances = CacheBuilder.newBuilder() + .weakKeys() + .build(); + private boolean lazyAddedToCache = false; + + /** + * Constructs a ResettablePooledLoOptimizer. + * + * @param returnClass The Java type of the values to be generated + * @param incrementSize The increment size. + */ + @SuppressWarnings("rawtypes") + public ResettablePooledLoOptimizer(Class returnClass, int incrementSize) { + this.optimizer = newOptimizer(returnClass, incrementSize); + } + + @SuppressWarnings("rawtypes") + private PooledLoOptimizer newOptimizer(Class returnClass, int incrementSize) { + return new PooledLoOptimizer(returnClass, incrementSize); + } + + @Override + public void clearState() { + this.optimizer = newOptimizer(optimizer.getReturnClass(), optimizer.getIncrementSize()); + } + + public static void clearStateGlobal() { + for (ClearableInternalState instance : clearableInstances.asMap().keySet()) { + instance.clearState(); + } + } + + @Override + public synchronized Serializable generate(AccessCallback callback) { + if (!lazyAddedToCache) { + //noinspection AccessToStaticFieldLockedOnInstance + clearableInstances.put(this, Boolean.TRUE); + lazyAddedToCache = true; + } + return optimizer.generate(callback); + } + + @Override + public boolean applyIncrementSizeToSourceValues() { + return optimizer.applyIncrementSizeToSourceValues(); + } + + @Override + public final int getIncrementSize() { + return optimizer.getIncrementSize(); + } + + @Override + public IntegralDataTypeHolder getLastSourceValue() { + return optimizer.getLastSourceValue(); + } + + /** + * Getter for property 'returnClass'. This is the Java + * class which is used to represent the id (e.g. {@link Long}). + * + * @return Value for property 'returnClass'. + */ + @SuppressWarnings({"UnusedDeclaration", "rawtypes"}) + public final Class getReturnClass() { + return optimizer.getReturnClass(); + } +} diff --git a/infrastructure/src/test/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizerTest.java b/infrastructure/src/test/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizerTest.java new file mode 100644 index 00000000..6c445335 --- /dev/null +++ b/infrastructure/src/test/java/com/pkb/infrastructure/hibernate/id/enhanced/ResettablePooledLoOptimizerTest.java @@ -0,0 +1,144 @@ +package com.pkb.infrastructure.hibernate.id.enhanced; + +import static com.github.karsaig.approvalcrest.MatcherAssert.assertThat; +import static com.pkb.infrastructure.hibernate.id.enhanced.ResettablePooledLoOptimizer.OPTIMIZER_CANONICAL_NAME; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; + +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; +import org.hibernate.id.enhanced.AccessCallback; +import org.hibernate.id.enhanced.Optimizer; +import org.hibernate.id.enhanced.OptimizerFactory; +import org.junit.Test; + +public class ResettablePooledLoOptimizerTest { + + @Test + public void optimizerFoundByHibernate() { + Optimizer optimizer = OptimizerFactory.buildOptimizer(OPTIMIZER_CANONICAL_NAME, Long.class, 50, -1); + + assertThat(optimizer, instanceOf(ResettablePooledLoOptimizer.class)); + } + + @Test + public void optimizerBasicUsage() { + SourceMock sequence = new SourceMock(1, 3); + Optimizer optimizer = OptimizerFactory.buildOptimizer(ResettablePooledLoOptimizer.class.getCanonicalName(), Long.class, 3, 1); + + assertEquals(0, sequence.getTimesCalled()); + assertEquals(-1, sequence.getCurrentValue()); + + Long next = (Long)optimizer.generate(sequence); + assertEquals(1, next.intValue()); + assertEquals(1, sequence.getTimesCalled()); + assertEquals(1, sequence.getCurrentValue()); + + next = (Long)optimizer.generate(sequence); + assertEquals(2, next.intValue()); + assertEquals(1, sequence.getTimesCalled()); + assertEquals(1, sequence.getCurrentValue()); + + next = (Long)optimizer.generate(sequence); + assertEquals(3, next.intValue()); + assertEquals(1, sequence.getTimesCalled()); + assertEquals(1, sequence.getCurrentValue()); + + next = (Long)optimizer.generate(sequence); + assertEquals(4, next.intValue()); + assertEquals(2, sequence.getTimesCalled()); + assertEquals(4, sequence.getCurrentValue()); + } + + @Test + public void optimizerResetCausesIncrementEarlier() { + SourceMock sequence = new SourceMock(1, 3); + ResettablePooledLoOptimizer optimizer = (ResettablePooledLoOptimizer)OptimizerFactory.buildOptimizer( + ResettablePooledLoOptimizer.class.getCanonicalName(), + Long.class, + 3, + 1); + + assertEquals(0, sequence.getTimesCalled()); + assertEquals(-1, sequence.getCurrentValue()); + + Long next = (Long)optimizer.generate(sequence); + assertEquals(1, next.intValue()); + assertEquals(1, sequence.getTimesCalled()); + assertEquals(1, sequence.getCurrentValue()); + + ResettablePooledLoOptimizer.clearStateGlobal(); + + next = (Long)optimizer.generate(sequence); + assertEquals(4, next.intValue()); + assertEquals(2, sequence.getTimesCalled()); + assertEquals(4, sequence.getCurrentValue()); + + next = (Long)optimizer.generate(sequence); + assertEquals(5, next.intValue()); + assertEquals(2, sequence.getTimesCalled()); + assertEquals(4, sequence.getCurrentValue()); + } + + /** + * Largely pulled from hibernate-core's org.hibernate.id.enhanced.OptimizerUnitTest.SourceMock + */ + private static class SourceMock implements AccessCallback { + private IdentifierGeneratorHelper.BasicHolder value = new IdentifierGeneratorHelper.BasicHolder(Long.class); + private long initialValue; + private int increment; + private int timesCalled ; + + private SourceMock(long initialValue, int increment) { + this(initialValue, increment, 0 ); + } + + private SourceMock(long initialValue, int increment, int timesCalled) { + this.increment = increment; + this.timesCalled = timesCalled; + + if (timesCalled == 0) { + this.value.initialize( -1 ); + this.initialValue = initialValue; + } + else { + this.value.initialize( initialValue ); + this.initialValue = 1; + } + } + + @Override + public IntegralDataTypeHolder getNextValue() { + try { + if (timesCalled == 0) { + initValue(); + return value.copy(); + } + else { + return value.add(increment).copy(); + } + } + finally { + timesCalled++; + } + } + + @Override + public String getTenantIdentifier() { + return "test"; + } + + private void initValue() { + this.value.initialize(initialValue); + } + + private int getTimesCalled() { + return timesCalled; + } + + private long getCurrentValue() { + return value == null ? -1 : value.getActualLongValue(); + } + } + +} diff --git a/pom.xml b/pom.xml index 6c2ec6d8..6fe57f0a 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,8 @@ 1 12-a115018-86851 3.0.7-PKB + + 5.3.15.Final @@ -208,6 +210,22 @@ + + org.hibernate + hibernate-core + ${hibernate-core.version} + provided + + + com.fasterxml + classmate + + + org.dom4j + dom4j + + + diff --git a/spring-infrastructure/pom.xml b/spring-infrastructure/pom.xml index 17fa9f12..3003c2a7 100644 --- a/spring-infrastructure/pom.xml +++ b/spring-infrastructure/pom.xml @@ -54,6 +54,10 @@ com.pkb rest-assured + + org.hibernate + hibernate-core + @@ -76,4 +80,4 @@ - \ No newline at end of file + diff --git a/suppression.xml b/suppression.xml index 1c7b6b66..97a89c29 100644 --- a/suppression.xml +++ b/suppression.xml @@ -245,4 +245,11 @@ ^pkg:maven/org\.yaml/snakeyaml@.*$ CVE-2017-18640 + + + + CVE-2019-14900 +