Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ########################################################################## //
- // ############################## MAIN CLASSES ############################## //
- // ########################################################################## //
- public enum Status {
- NOT_STARTED,
- IN_PROGRESS,
- COMPLETED,
- ERROR
- }
- public interface SchemaLoader {
- void loadSchema();
- }
- public class SchemaLoaderImpl {
- @Override
- public void loadSchema() {
- // Implementation goes here
- }
- }
- public class SchemaMaintainer {
- private static final long CHECK_TIMEOUT_MILLIS = 5000L; // We want to abort the check after 5 seconds so we don't block the app forever
- private volatile Status status = Status.NOT_STARTED;
- private final ExecutorService executor = Executors.newSingleThreadExecutor();
- private final SchemaLoader schemaLoader;
- public SchemaMaintainer(SchemaLoader schemaLoader) {
- this.schemaLoader = schemaLoader;
- }
- public synchronized void maintainSchema() throws TimeoutException {
- switch (status) {
- case COMPLETED:
- return;
- case ERROR:
- throw new RuntimeException("Schema maintenance finished with an error");
- case IN_PROGRESS:
- throw new RuntimeException("Schema maintenance already in progress");
- case NOT_STARTED:
- status = Status.IN_PROGRESS;
- executor.submit(this::loadSchema);
- waitForLoading();
- break;
- }
- }
- // Visible for testing
- Status getStatus() {
- return status;
- }
- private Status loadSchema() {
- try {
- // Loading the schema
- schemaLoader.loadSchema();
- // Schema loading was successful
- synchronized(this) {
- if (status == Status.ERROR) {
- // TODO store that schema loading was successful, but a timeout exception occurred in the meantime
- } else {
- status = Status.COMPLETED;
- }
- }
- } catch (Exception e) {
- synchronized(this) {
- status = Status.ERROR;
- // TODO store the exception somewhere
- }
- }
- }
- private void waitForLoading() throws TimeoutException {
- long endTimeMillis = System.currentTimeMillis() + CHECK_TIMEOUT_MILLIS;
- while (status == Status.IN_PROGRESS) {
- long remainingMillis = end - System.currentTimeMillis();
- if (remainingMillis > 0) {
- Thread.sleep(50);
- continue;
- }
- // Timeout
- synchronized(this) {
- if (status != Status.COMPLETED) {
- // We only want to throw a TimeoutException if the loading really didn't finish
- status = Status.ERROR;
- executor.shutdownNow(); // Abort the loading
- throw new TimeoutException("Schema maintenance did not finish within " + CHECK_TIMEOUT_MILLIS + " ms");
- }
- }
- }
- }
- }
- // ########################################################################## //
- // ############################## TEST CLASSES ############################## //
- // ########################################################################## //
- public class MockSchemaLoader extends SchemaLoader {
- private final CountDownLatch latch = new CountDownLatch(1);
- private boolean markError = false; // Used for simulating an error
- public void markError() {
- this.markError = true;
- }
- public void finishLoading() {
- this.latch.countDown();
- }
- @Override
- public void loadSchema() {
- this.latch.await();
- // Simulating an error
- if (this.markError) {
- throw new RuntimeException("Error while loading");
- }
- }
- }
- public class SchemaMaintainerTest {
- @Test
- public void testEverythingOK() {
- MockSchemaLoader schemaLoader = new MockSchemaLoader();
- SchemaMaintainer schemaMaintainer = new SchemaMaintainer(schemaLoader);
- schemaLoader.finishLoading();
- schemaMaintainer.maintainSchema();
- assertEquals(Status.COMPLETED, schemaMaintainer.getStatus());
- }
- @Test
- public void testAlreadyCompelted() {
- MockSchemaLoader schemaLoader = new MockSchemaLoader();
- SchemaMaintainer schemaMaintainer = new SchemaMaintainer(schemaLoader);
- schemaLoader.finishLoading();
- schemaMaintainer.maintainSchema();
- assertEquals(Status.COMPLETED, schemaMaintainer.getStatus());
- schemaMaintainer.maintainSchema(); // The previous should have already completed the maintenance and the 2nd invocation should not throw an error
- assertEquals(Status.COMPLETED, schemaMaintainer.getStatus());
- }
- @Test
- public void testInProgress() {
- MockSchemaLoader schemaLoader = new MockSchemaLoader();
- SchemaMaintainer schemaMaintainer = new SchemaMaintainer(schemaLoader);
- schemaMaintainer.maintainSchema();
- Exception ex = null;
- try {
- schemaMaintainer.maintainSchema(); // Loading still in progress, so an exception is expected
- } catch (Exception e) {
- ex = e;
- }
- schemaLoader.finishLoading();
- assertNotNull(ex);
- // TODO validate the exception
- }
- @Test
- public void testLoadingException() {
- MockSchemaLoader schemaLoader = new MockSchemaLoader();
- SchemaMaintainer schemaMaintainer = new SchemaMaintainer(schemaLoader);
- schemaLoader.markError();
- schemaLoader.finishLoading();
- schemaMaintainer.maintainSchema(); // This should mark the status as ERROR
- assertEquals(Status.ERROR, schemaMaintainer.getStatus());
- // TODO if you save the loading exception, validate it here
- }
- @Test
- public void testAlreadyError() {
- MockSchemaLoader schemaLoader = new MockSchemaLoader();
- SchemaMaintainer schemaMaintainer = new SchemaMaintainer(schemaLoader);
- schemaLoader.markError();
- schemaLoader.finishLoading();
- schemaMaintainer.maintainSchema(); // This should mark the status as ERROR
- assertEquals(Status.ERROR, schemaMaintainer.getStatus());
- Exception ex = null;
- try {
- schemaMaintainer.maintainSchema(); // Already errored, so we expect an exception
- } catch (Exception e) {
- ex = e;
- }
- assertNotNull(ex);
- // TODO validate the exception
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement