001// Generated by delombok at Mon Oct 12 22:59:35 BST 2020 002/* 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 */ 020package org.apache.isis.extensions.commandreplay.secondary.clock; 021 022import java.sql.Timestamp; 023import java.util.function.Supplier; 024import javax.annotation.PostConstruct; 025import javax.inject.Named; 026import org.springframework.core.annotation.Order; 027import org.springframework.stereotype.Service; 028import org.apache.isis.applib.annotation.OrderPrecedence; 029import org.apache.isis.applib.clock.Clock; 030import org.apache.isis.core.config.IsisConfiguration; 031import org.apache.isis.testing.fixtures.applib.clock.TickingFixtureClock; 032 033/** 034 * Only enabled for the <tt>secondary</tt> profile, where it sets up the 035 036 * framework to use {@link TickingFixtureClock} so that time can be changed 037 038 * dynamically when running. 039 040 * 041 042 * <p> 043 044 * As an additional safeguard, if the configuration keys to access the 045 046 * primary are not provided, then the service will not initialize. 047 048 * </p> 049 050 * 051 052 * <p> 053 054 * IMPORTANT: the methods provided by this service are not thread-safe, 055 056 * because the clock is a globally-scoped singleton rather than a 057 058 * thread-local. These methods should therefore only be used in single-user 059 060 * systems, eg a replay secondary. 061 062 * </p> 063 */ 064@Service 065@Named("isisExtensionsCommandReplaySecondary.TickingClockService") 066@Order(OrderPrecedence.MIDPOINT) 067public class TickingClockService { 068 @java.lang.SuppressWarnings("all") 069 private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TickingClockService.class); 070 final IsisConfiguration isisConfiguration; 071 072 @PostConstruct 073 public void init() { 074 final java.util.Optional<java.lang.String> baseUrl = isisConfiguration.getExtensions().getCommandReplay().getPrimaryAccess().getBaseUrlRestful(); 075 final java.util.Optional<java.lang.String> user = isisConfiguration.getExtensions().getCommandReplay().getPrimaryAccess().getUser(); 076 final java.util.Optional<java.lang.String> password = isisConfiguration.getExtensions().getCommandReplay().getPrimaryAccess().getPassword(); 077 if (!baseUrl.isPresent() || !user.isPresent() || !password.isPresent()) { 078 log.warn("init() - skipping, one or more \'isis.extensions.command-replay.primary\' configuration properties has not been set"); 079 return; 080 } 081 log.info("init() - replacing existing clock with TickingFixtureClock"); 082 TickingFixtureClock.replaceExisting(); 083 } 084 085 public boolean isInitialized() { 086 return Clock.getInstance() instanceof TickingFixtureClock; 087 } 088 089 /** 090 * Executes the runnable, setting the clock to be the specified time 091 092 * beforehand (and reinstating it to its original time afterwards). 093 094 * 095 096 * <p> 097 098 * IMPORTANT: this method is not thread-safe, because the clock is a 099 100 * globally-scoped singleton rather than a thread-local. This method 101 102 * should therefore only be used in single-user systems, eg a replay 103 104 * secondary. 105 106 * </p> 107 */ 108 public void at(Timestamp timestamp, Runnable runnable) { 109 ensureInitialized(); 110 final org.apache.isis.testing.fixtures.applib.clock.TickingFixtureClock tickingFixtureClock = (TickingFixtureClock) TickingFixtureClock.getInstance(); 111 final long previous = TickingFixtureClock.getEpochMillis(); 112 final long wallTime0 = System.currentTimeMillis(); 113 try { 114 tickingFixtureClock.setTime(timestamp); 115 runnable.run(); 116 } finally { 117 final long wallTime1 = System.currentTimeMillis(); 118 tickingFixtureClock.setTime(previous + wallTime1 - wallTime0); 119 } 120 } 121 122 /** 123 * Executes the callable, setting the clock to be the specified time 124 125 * beforehand (and reinstating it to its original time afterwards). 126 127 * 128 129 * <p> 130 131 * IMPORTANT: this method is not thread-safe, because the clock is a 132 133 * globally-scoped singleton rather than a thread-local. This method 134 135 * should therefore only be used in single-user systems, eg a replay 136 137 * secondary. 138 139 * </p> 140 */ 141 public <T> T at(Timestamp timestamp, Supplier<T> supplier) { 142 ensureInitialized(); 143 final org.apache.isis.testing.fixtures.applib.clock.TickingFixtureClock tickingFixtureClock = (TickingFixtureClock) TickingFixtureClock.getInstance(); 144 final long previous = TickingFixtureClock.getEpochMillis(); 145 final long wallTime0 = System.currentTimeMillis(); 146 try { 147 tickingFixtureClock.setTime(timestamp); 148 return supplier.get(); 149 } finally { 150 final long wallTime1 = System.currentTimeMillis(); 151 tickingFixtureClock.setTime(previous + wallTime1 - wallTime0); 152 } 153 } 154 155 private void ensureInitialized() { 156 if (!isInitialized()) { 157 throw new IllegalStateException("Not initialized. Make sure that the application is configured as a replay secondary by configuring the \'isis.extensions.command-replay.primary\' configuration properties."); 158 } 159 } 160 161 @java.lang.SuppressWarnings("all") 162 public TickingClockService(final IsisConfiguration isisConfiguration) { 163 this.isisConfiguration = isisConfiguration; 164 } 165}