Skip to content

Commit

Permalink
added abstract RefreshableServiceProviderPlace
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-mlb committed Jan 13, 2025
1 parent 5eff057 commit 07d35d0
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 119 deletions.
126 changes: 126 additions & 0 deletions src/main/java/emissary/place/RefreshableServiceProviderPlace.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package emissary.place;

import emissary.config.ConfigUtil;
import emissary.config.Configurator;

import org.apache.commons.collections4.CollectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;

/**
*
*/
public abstract class RefreshableServiceProviderPlace extends ServiceProviderPlace {

private final AtomicBoolean invalid = new AtomicBoolean(false);

public RefreshableServiceProviderPlace() throws IOException {}

public RefreshableServiceProviderPlace(final String thePlaceLocation) throws IOException {
super(thePlaceLocation);
}

protected RefreshableServiceProviderPlace(final String configFile, @Nullable final String theDir, final String thePlaceLocation)
throws IOException {
super(configFile, theDir, thePlaceLocation);
}

protected RefreshableServiceProviderPlace(final InputStream configStream, @Nullable final String theDir, final String thePlaceLocation)
throws IOException {
super(configStream, theDir, thePlaceLocation);
}

protected RefreshableServiceProviderPlace(final InputStream configStream) throws IOException {
super(configStream);
}

protected RefreshableServiceProviderPlace(final String configFile, final String placeLocation) throws IOException {
super(configFile, placeLocation);
}

protected RefreshableServiceProviderPlace(final InputStream configStream, final String placeLocation) throws IOException {
super(configStream, placeLocation);
}

public boolean isInvalid() {
return this.invalid.get();
}

public void invalidate() {
this.invalid.set(true);
}

/**
* Reinitialize the place by reloading the configurator and reconfiguring the place
*/
public synchronized void refresh() {
try {
if (this.invalid.get()) {
this.configG = reloadConfigurator();
reconfigurePlace();
}
this.invalid.set(false);
} catch (IOException e) {
logger.error("Failed to reload configurator");
}
}

/**
* Reinitialize the place by reloading the configurator and reconfiguring the place
*
* @param configStream the config data as an {@link InputStream}
*/
public synchronized void refresh(final InputStream configStream) {
try {
if (this.invalid.get()) {
this.configG = reloadConfigurator(configStream);
reconfigurePlace();
}
this.invalid.set(false);
} catch (IOException e) {
logger.error("Failed to reload configStream");
}
}

protected abstract void reconfigurePlace() throws IOException;

/**
* Reload the {@link Configurator}
*
* @throws IOException if there is an issue loading the config
*/
private Configurator reloadConfigurator() throws IOException {
return reloadConfigurator(this.configLocs);
}

/**
* Reload the {@link Configurator}
*
* @param configLocations the list of configuration files to load
* @throws IOException if there is an issue loading the config
*/
private static Configurator reloadConfigurator(@Nullable final List<String> configLocations) throws IOException {
if (CollectionUtils.isNotEmpty(configLocations)) {
return ConfigUtil.getConfigInfo(configLocations);
}
throw new IOException("No config locations specified");
}

/**
* Reload the {@link Configurator}
*
* @param configStream the stream of configuration data
* @throws IOException if there is an issue loading the config
*/
private static Configurator reloadConfigurator(@Nullable final InputStream configStream) throws IOException {
if (configStream != null) {
return ConfigUtil.getConfigInfo(configStream);
}
throw new IOException("Null config stream supplied");
}

}
73 changes: 3 additions & 70 deletions src/main/java/emissary/place/ServiceProviderPlace.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import emissary.util.JMXUtil;

import com.codahale.metrics.Timer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -73,6 +72,8 @@ public abstract class ServiceProviderPlace implements IServiceProviderPlace,
@Nullable
protected Configurator configG;

protected final List<String> configLocs = new ArrayList<>();

/**
* A <i><b>local</b></i> reference to the directory that this place resides in. Every JVM that contains 'places' must
* have a local directory
Expand Down Expand Up @@ -111,8 +112,7 @@ public abstract class ServiceProviderPlace implements IServiceProviderPlace,
@Nullable
protected String serviceDescription;

private String placeLocation;
private final List<String> configLocs = new ArrayList<>();
protected String placeLocation;

/**
* Static context logger
Expand Down Expand Up @@ -928,73 +928,6 @@ protected void deregisterFromDirectory(List<String> keys) {
}
}

/**
* Reset the keys and reload the {@link Configurator}
*
* @throws IOException if there is an issue loading the config
*/
protected void refresh() throws IOException {
clearKeys();
this.configG = refreshConfigurator();
setupPlace(this.dirPlace, this.placeLocation);
}

/**
* Reset the keys and reload the {@link Configurator}
*
* @param configStream the configuration input stream to load
* @throws IOException if there is an issue loading the config
*/
protected void refresh(@Nullable final InputStream configStream) throws IOException {
clearKeys();
this.configG = refreshConfigurator(configStream);
setupPlace(this.dirPlace, this.placeLocation);
}

/**
* Reload the {@link Configurator}
*
* @throws IOException if there is an issue loading the config
*/
protected Configurator refreshConfigurator() throws IOException {
return refreshConfigurator(this.configLocs);
}

/**
* Reload the {@link Configurator}
*
* @param configLocations the list of configuration files to load
* @throws IOException if there is an issue loading the config
*/
protected Configurator refreshConfigurator(@Nullable final List<String> configLocations) throws IOException {
if (CollectionUtils.isNotEmpty(configLocations)) {
return ConfigUtil.getConfigInfo(configLocations);
}
throw new IOException("No config locations specified");
}

/**
* Reload the {@link Configurator}
*
* @param configStream the stream of configuration data
* @throws IOException if there is an issue loading the config
*/
protected Configurator refreshConfigurator(@Nullable final InputStream configStream) throws IOException {
if (configStream != null) {
return ConfigUtil.getConfigInfo(configStream);
}
throw new IOException("Null config stream supplied");
}

/**
* Unbind from the namespace and clear all loaded keys
*/
protected void clearKeys() {
unbindFromNamespace();
new ArrayList<>(this.keys).forEach(this::removeKey);
this.keys.clear();
}

/**
* Remove a service proxy from the running place. Proxy strings not found registered will be ignored Will remove all
* keys that match the supplied proxy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package emissary.place;

import emissary.core.IBaseDataObject;
import emissary.core.Namespace;
import emissary.directory.DirectoryEntry;
import emissary.test.core.junit5.UnitTest;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Nullable;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class RefreshableServiceProviderPlaceTest extends UnitTest {

private static final byte[] cfgData = ("SERVICE_KEY = \"UNKNOWN.TEST_PLACE.ID.http://localhost:8001/RefreshablePlaceTest$6050\"\n" +
"KEY_1 = 200").getBytes();
private static final byte[] cfgDataReload = ("SERVICE_KEY = \"*.TEST_PLACE.ID.http://localhost:8001/RefreshablePlaceTest$5060\"\n" +
"KEY_1 = 300").getBytes();

@Nullable
private RefreshablePlaceTest place = null;

@Override
@BeforeEach
public void setUp() throws Exception {
InputStream config = new ByteArrayInputStream(cfgData);
place = new RefreshablePlaceTest(config, null, "http://localhost:8001/RefreshablePlaceTest");
}

@Override
@AfterEach
public void tearDown() throws Exception {
super.tearDown();
assertNotNull(place);
place.shutDown();
place = null;
}

@Test
void testReconfigure() {
assertNotNull(place, "Place created and configured");
assertEquals("RefreshablePlaceTest", place.getPlaceName(), "Configured place name");
assertEquals("UNKNOWN", place.getPrimaryProxy(), "Primary proxy");
assertEquals("UNKNOWN.TEST_PLACE.ID.http://localhost:8001/RefreshablePlaceTest", place.getKey(), "Key generation");
DirectoryEntry de = place.getDirectoryEntry();
assertNotNull(de, "Directory entry");
assertEquals(60, de.getCost(), "Cost in directory entry");
assertEquals(50, de.getQuality(), "Quality in directory entry");
assertEquals("Description not available", de.getDescription(), "Description in directory entry");
assertNotNull(place.configG);
assertEquals(200, place.configG.findIntEntry("KEY_1", 0));
assertDoesNotThrow(() -> Namespace.lookup("http://localhost:8001/RefreshablePlaceTest"));

place.invalidate();
place.refresh(new ByteArrayInputStream(cfgDataReload));
assertNotNull(place, "Place created and configured");
assertEquals("RefreshablePlaceTest", place.getPlaceName(), "Configured place name");
// assertEquals("*", placeTest.getPrimaryProxy(), "Primary proxy");
assertEquals("UNKNOWN", place.getPrimaryProxy(), "Primary proxy");
// assertEquals("*.TEST_PLACE.ID.http://localhost:8001/PlaceTest", placeTest.getKey(), "Key generation");
assertEquals("UNKNOWN.TEST_PLACE.ID.http://localhost:8001/RefreshablePlaceTest", place.getKey(), "Key generation");
de = place.getDirectoryEntry();
assertNotNull(de, "Directory entry");
// assertEquals(50, de.getCost(), "Cost in directory entry");
assertEquals(60, de.getCost(), "Cost in directory entry");
// assertEquals(40, de.getQuality(), "Quality in directory entry");
assertEquals(50, de.getQuality(), "Quality in directory entry");
assertEquals("Description not available", de.getDescription(), "Description in directory entry");
assertNotNull(place.configG);
assertEquals(300, place.configG.findIntEntry("KEY_1", 0));
assertDoesNotThrow(() -> Namespace.lookup("http://localhost:8001/RefreshablePlaceTest"));
}

private static final class RefreshablePlaceTest extends RefreshableServiceProviderPlace {

public RefreshablePlaceTest(InputStream config, @Nullable String dir, @Nullable String loc) throws IOException {
super(config, dir, loc);
}

@Override
public void process(IBaseDataObject d) {
assertNotNull(d);
}

@Override
protected void reconfigurePlace() {}
}
}
49 changes: 0 additions & 49 deletions src/test/java/emissary/place/ServiceProviderPlaceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import emissary.core.EmissaryException;
import emissary.core.IBaseDataObject;
import emissary.core.Namespace;
import emissary.core.NamespaceException;
import emissary.directory.DirectoryEntry;
import emissary.directory.KeyManipulator;
import emissary.test.core.junit5.UnitTest;
Expand All @@ -25,7 +24,6 @@
import java.util.Set;
import javax.annotation.Nullable;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
Expand Down Expand Up @@ -554,53 +552,6 @@ void testDeniedServiceProxy() {
}
}

private static final byte[] cfgData = ("SERVICE_KEY = \"UNKNOWN.TEST_PLACE.ID.http://localhost:8001/PlaceTest$6050\"\n" +
"KEY_1 = 200").getBytes();
private static final byte[] cfgDataReload = ("SERVICE_KEY = \"*.TEST_PLACE.ID.http://localhost:8001/PlaceTest$5060\"\n" +
"KEY_1 = 300").getBytes();

@Test
void refreshConfigurator() throws IOException {
PlaceTest placeTest = new PlaceTest(new ByteArrayInputStream(cfgData));
assertNotNull(placeTest, "Place created and configured");
assertEquals("PlaceTest", placeTest.getPlaceName(), "Configured place name");
assertEquals("UNKNOWN", placeTest.getPrimaryProxy(), "Primary proxy");
assertEquals("UNKNOWN.TEST_PLACE.ID.http://localhost:8001/PlaceTest", placeTest.getKey(), "Key generation");
DirectoryEntry de = placeTest.getDirectoryEntry();
assertNotNull(de, "Directory entry");
assertEquals(60, de.getCost(), "Cost in directory entry");
assertEquals(50, de.getQuality(), "Quality in directory entry");
assertEquals("Description not available", de.getDescription(), "Description in directory entry");
assertNotNull(placeTest.configG);
assertEquals(200, placeTest.configG.findIntEntry("KEY_1", 0));
assertDoesNotThrow(() -> Namespace.lookup("http://localhost:8001/PlaceTest"));

placeTest.refresh(new ByteArrayInputStream(cfgDataReload));
assertNotNull(placeTest, "Place created and configured");
assertEquals("PlaceTest", placeTest.getPlaceName(), "Configured place name");
assertEquals("*", placeTest.getPrimaryProxy(), "Primary proxy");
assertEquals("*.TEST_PLACE.ID.http://localhost:8001/PlaceTest", placeTest.getKey(), "Key generation");
de = placeTest.getDirectoryEntry();
assertNotNull(de, "Directory entry");
assertEquals(50, de.getCost(), "Cost in directory entry");
assertEquals(40, de.getQuality(), "Quality in directory entry");
assertEquals("Description not available", de.getDescription(), "Description in directory entry");
assertNotNull(placeTest.configG);
assertEquals(300, placeTest.configG.findIntEntry("KEY_1", 0));
assertDoesNotThrow(() -> Namespace.lookup("http://localhost:8001/PlaceTest"));
}

@Test
void testClearKeys() throws IOException {
PlaceTest placeTest = new PlaceTest(new ByteArrayInputStream(cfgData));
assertFalse(placeTest.keys.isEmpty());
assertDoesNotThrow(() -> Namespace.lookup("http://localhost:8001/PlaceTest"));

placeTest.clearKeys();
assertTrue(placeTest.keys.isEmpty());
assertThrows(NamespaceException.class, () -> Namespace.lookup("http://localhost:8001/PlaceTest"));
}

private static final class PlaceTest extends ServiceProviderPlace {

public PlaceTest() throws IOException {
Expand Down

0 comments on commit 07d35d0

Please sign in to comment.