refactor(module): Change LOGGER to instance variable and update ModuleServiceImpl to use ApplicationContext

This commit is contained in:
extio-de
2025-12-25 15:37:00 +01:00
parent fffa2b773f
commit 5f73867897
4 changed files with 43 additions and 33 deletions

View File

@@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
*/ */
public abstract class AbstractModule { public abstract class AbstractModule {
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractModule.class); protected final Logger LOGGER = LoggerFactory.getLogger(AbstractModule.class);
protected String id = "Module_" + System.identityHashCode(this); protected String id = "Module_" + System.identityHashCode(this);

View File

@@ -1,10 +1,9 @@
package de.extio.game_engine.module; package de.extio.game_engine.module;
import java.util.List;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import de.extio.game_engine.renderer.work.RendererWorkingSet; import de.extio.game_engine.renderer.work.RendererWorkingSet;
@@ -15,8 +14,8 @@ public class ModuleServiceAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
ModuleService moduleService(final List<AbstractModule> initialModules, final RendererWorkingSet rendererWorkingSet) { ModuleService moduleService(final ApplicationContext applicationContext, final RendererWorkingSet rendererWorkingSet) {
return new ModuleServiceImpl(initialModules, rendererWorkingSet); return new ModuleServiceImpl(applicationContext, rendererWorkingSet);
} }
@Bean @Bean

View File

@@ -13,16 +13,18 @@ import java.util.function.Consumer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import de.extio.game_engine.renderer.work.RendererWorkingSet; import de.extio.game_engine.renderer.work.RendererWorkingSet;
public class ModuleServiceImpl implements InitializingBean, ModuleService { public class ModuleServiceImpl implements ModuleService, ApplicationListener<ContextRefreshedEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(ModuleServiceImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(ModuleServiceImpl.class);
private final List<AbstractModule> modulesInitial; private final ApplicationContext applicationContext;
private final List<AbstractModule> modulesAll = Collections.synchronizedList(new ArrayList<>()); private final List<AbstractModule> modulesAll = Collections.synchronizedList(new ArrayList<>());
private final Map<String, AbstractModule> modulesByIdMap = new ConcurrentHashMap<>(); private final Map<String, AbstractModule> modulesByIdMap = new ConcurrentHashMap<>();
@@ -45,18 +47,19 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
private final Map<ModuleExecutorCallbacks, List<AbstractModule>> executorCallbackMap = Collections.synchronizedMap(new EnumMap<>(ModuleExecutorCallbacks.class)); private final Map<ModuleExecutorCallbacks, List<AbstractModule>> executorCallbackMap = Collections.synchronizedMap(new EnumMap<>(ModuleExecutorCallbacks.class));
public ModuleServiceImpl(final List<AbstractModule> initialModules, final RendererWorkingSet rendererWorkingSet) { public ModuleServiceImpl(ApplicationContext applicationContext, final RendererWorkingSet rendererWorkingSet) {
this.modulesInitial = initialModules; this.applicationContext = applicationContext;
this.rendererWorkingSet = rendererWorkingSet; this.rendererWorkingSet = rendererWorkingSet;
} }
@Override @Override
public void afterPropertiesSet() throws Exception { public void onApplicationEvent(ContextRefreshedEvent event) {
if (this.modulesInitial == null || this.modulesInitial.isEmpty()) { final var modulesInitial = this.applicationContext.getBeansOfType(AbstractModule.class, false, false);
if (modulesInitial == null || modulesInitial.isEmpty()) {
return; return;
} }
this.modulesInitial.forEach(this::load); modulesInitial.values().forEach(this::load);
this.modulesInitial.clear();
} }
@Override @Override
@@ -97,7 +100,7 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
synchronized (this.modulesAll) { synchronized (this.modulesAll) {
this.modulesAllView = List.copyOf(this.modulesAll); this.modulesAllView = List.copyOf(this.modulesAll);
} }
LOGGER.debug("Loaded module " + module.getClass().getName()); LOGGER.debug("Loaded module {} {}", module.getClass().getName(), module.getId());
this.invokeSafe(module, m -> m.onLoad()); this.invokeSafe(module, m -> m.onLoad());
} }
@@ -124,7 +127,7 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
this.rendererWorkingSet.clear(clientModule.getId()); this.rendererWorkingSet.clear(clientModule.getId());
} }
LOGGER.debug("Unloaded module " + id); LOGGER.info("Unloaded module {}", id);
} }
catch (final Exception e) { catch (final Exception e) {
LOGGER.error("Error unloading module " + id, e); LOGGER.error("Error unloading module " + id, e);
@@ -163,7 +166,7 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
} }
this.invokeSafe(module, AbstractModule::onDeactivate); this.invokeSafe(module, AbstractModule::onDeactivate);
LOGGER.debug("Deactivated " + id); LOGGER.info("Deactivated {}", id);
} }
}, () -> { }, () -> {
if (active) { if (active) {
@@ -191,7 +194,7 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
} }
this.invokeSafe(module, AbstractModule::onActivate); this.invokeSafe(module, AbstractModule::onActivate);
LOGGER.debug("Activated " + id); LOGGER.info("Activated {}", id);
} }
} }
}); });
@@ -216,13 +219,13 @@ public class ModuleServiceImpl implements InitializingBean, ModuleService {
if (doDisplay && !curDisplayed) { if (doDisplay && !curDisplayed) {
this.modulesDisplayed.add(clientModule); this.modulesDisplayed.add(clientModule);
clientModule.setDisplayed(true); clientModule.setDisplayed(true);
LOGGER.debug("Displayed {}", id); LOGGER.info("Displayed {}", id);
this.invokeSafe(clientModule, m -> ((AbstractClientModule) m).onShow()); this.invokeSafe(clientModule, m -> ((AbstractClientModule) m).onShow());
} }
else if (!doDisplay && curDisplayed) { else if (!doDisplay && curDisplayed) {
clientModule.setDisplayed(false); clientModule.setDisplayed(false);
this.modulesDisplayed.removeIf(mod -> mod.getId().equals(id)); this.modulesDisplayed.removeIf(mod -> mod.getId().equals(id));
LOGGER.debug("Hidden {}", id); LOGGER.info("Hidden {}", id);
this.invokeSafe(clientModule, m -> ((AbstractClientModule) m).onHide()); this.invokeSafe(clientModule, m -> ((AbstractClientModule) m).onHide());
} }
this.modulesDisplayedClientModulesView = List.copyOf(this.modulesDisplayed); this.modulesDisplayedClientModulesView = List.copyOf(this.modulesDisplayed);

View File

@@ -2,12 +2,16 @@ package de.extio.game_engine.module;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import de.extio.game_engine.renderer.work.RendererWorkingSet; import de.extio.game_engine.renderer.work.RendererWorkingSet;
@@ -24,33 +28,37 @@ public class ModuleManagerTest {
this.testModule = new TestModule(); this.testModule = new TestModule();
this.testClientModule = new TestClientModule(); this.testClientModule = new TestClientModule();
final List<AbstractModule> initialModules = new ArrayList<>(); final ApplicationContext ctx = mock(ApplicationContext.class);
initialModules.add(this.testModule); when(ctx.getBeansOfType(AbstractModule.class, false, false))
initialModules.add(this.testClientModule); .thenReturn(Map.of("testModule", this.testModule, "testClientModule", this.testClientModule));
this.moduleManager = new ModuleServiceImpl(initialModules, mock(RendererWorkingSet.class)); this.moduleManager = new ModuleServiceImpl(ctx, mock(RendererWorkingSet.class));
this.moduleManager.afterPropertiesSet(); this.moduleManager.onApplicationEvent(new ContextRefreshedEvent(ctx));
} }
@Test @Test
public void testAfterPropertiesSet() { public void testOnApplicationEvent() {
assertEquals(2, this.moduleManager.getModulesAll().size()); assertEquals(2, this.moduleManager.getModulesAll().size());
assertTrue(this.testModule.onLoadCalled); assertTrue(this.testModule.onLoadCalled);
assertTrue(this.testClientModule.onLoadCalled); assertTrue(this.testClientModule.onLoadCalled);
} }
@Test @Test
public void testAfterPropertiesSet_EmptyModules() throws Exception { public void testOnApplicationEvent_EmptyModules() throws Exception {
final ModuleServiceImpl emptyManager = new ModuleServiceImpl(List.of(), mock(RendererWorkingSet.class)); final ApplicationContext ctx = mock(ApplicationContext.class);
emptyManager.afterPropertiesSet(); when(ctx.getBeansOfType(AbstractModule.class, false, false)).thenReturn(Map.of());
final ModuleServiceImpl emptyManager = new ModuleServiceImpl(ctx, mock(RendererWorkingSet.class));
emptyManager.onApplicationEvent(new ContextRefreshedEvent(ctx));
assertTrue(emptyManager.getModulesAll().isEmpty()); assertTrue(emptyManager.getModulesAll().isEmpty());
} }
@Test @Test
public void testAfterPropertiesSet_NullModules() throws Exception { public void testOnApplicationEvent_NullModules() throws Exception {
final ModuleServiceImpl nullManager = new ModuleServiceImpl(null, mock(RendererWorkingSet.class)); final ApplicationContext ctx = mock(ApplicationContext.class);
nullManager.afterPropertiesSet(); when(ctx.getBeansOfType(AbstractModule.class, false, false)).thenReturn(null);
final ModuleServiceImpl nullManager = new ModuleServiceImpl(ctx, mock(RendererWorkingSet.class));
nullManager.onApplicationEvent(new ContextRefreshedEvent(ctx));
assertTrue(nullManager.getModulesAll().isEmpty()); assertTrue(nullManager.getModulesAll().isEmpty());
} }