forked from boskworks/bosk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
375 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
bosk-core/src/main/java/io/vena/bosk/BoskDiagnosticContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package io.vena.bosk; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
/** | ||
* A thread-local set of name-value pairs that propagate all the way from | ||
* submission of a driver update, through all the driver layers, | ||
* to the execution of hooks. | ||
*/ | ||
public final class BoskDiagnosticContext { | ||
private final ThreadLocal<MapValue<String>> currentAttributes = ThreadLocal.withInitial(MapValue::empty); | ||
|
||
public final class DiagnosticScope implements AutoCloseable { | ||
final MapValue<String> oldAttributes = currentAttributes.get(); | ||
|
||
DiagnosticScope(MapValue<String> attributes) { | ||
currentAttributes.set(attributes); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
currentAttributes.set(oldAttributes); | ||
} | ||
} | ||
|
||
/** | ||
* @return the current thread's value of the attribute with the given <code>name</code>, | ||
* or <code>null</code> if no such attribute has been defined. | ||
*/ | ||
public @Nullable String getAttribute(String name) { | ||
return currentAttributes.get().get(name); | ||
} | ||
|
||
public @NotNull MapValue<String> getAttributes() { | ||
return currentAttributes.get(); | ||
} | ||
|
||
/** | ||
* Adds a single attribute to the current thread's diagnostic context. | ||
* If the attribute already exists, it will be replaced. | ||
*/ | ||
public DiagnosticScope withAttribute(String name, String value) { | ||
return new DiagnosticScope(currentAttributes.get().with(name, value)); | ||
} | ||
|
||
/** | ||
* Adds attributes to the current thread's diagnostic context. | ||
* If an attribute already exists, it will be replaced. | ||
*/ | ||
public DiagnosticScope withAttributes(@NotNull MapValue<String> additionalAttributes) { | ||
return new DiagnosticScope(currentAttributes.get().withAll(additionalAttributes)); | ||
} | ||
|
||
/** | ||
* Replaces all attributes in the current thread's diagnostic context. | ||
* Existing attributes are removed/replaced. | ||
* <p> | ||
* This is intended for propagating context from one thread to another. | ||
* <p> | ||
* If <code>attributes</code> is null, this is a no-op, and any existing attributes on this thread are retained. | ||
* If ensuring a clean set of attributes is important, pass an empty map instead of null. | ||
*/ | ||
public DiagnosticScope withOnly(@Nullable MapValue<String> attributes) { | ||
if (attributes == null) { | ||
return new DiagnosticScope(currentAttributes.get()); | ||
} else { | ||
return new DiagnosticScope(attributes); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
bosk-core/src/test/java/io/vena/bosk/BoskDiagnosticContextTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package io.vena.bosk; | ||
|
||
import io.vena.bosk.annotations.ReferencePath; | ||
import io.vena.bosk.drivers.AbstractDriverTest; | ||
import io.vena.bosk.drivers.state.TestEntity; | ||
import io.vena.bosk.exceptions.InvalidTypeException; | ||
import java.io.IOException; | ||
import java.util.concurrent.Semaphore; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import lombok.var; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static java.util.concurrent.TimeUnit.SECONDS; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
/** | ||
* Note that context propagation for driver operations is tested by {@link io.vena.bosk.drivers.DriverConformanceTest}. | ||
*/ | ||
class BoskDiagnosticContextTest extends AbstractDriverTest { | ||
Refs refs; | ||
|
||
public interface Refs { | ||
@ReferencePath("/string") Reference<String> string(); | ||
} | ||
|
||
@BeforeEach | ||
void setupBosk() throws InvalidTypeException { | ||
bosk = new Bosk<TestEntity>( | ||
BoskDiagnosticContextTest.class.getSimpleName(), | ||
TestEntity.class, | ||
AbstractDriverTest::initialRoot, | ||
Bosk::simpleDriver | ||
); | ||
refs = bosk.buildReferences(Refs.class); | ||
} | ||
|
||
@Test | ||
void hookRegistration_propagatesDiagnosticContext() throws IOException, InterruptedException { | ||
Semaphore diagnosticsVerified = new Semaphore(0); | ||
bosk.driver().flush(); | ||
try (var __ = bosk.diagnosticContext().withAttribute("attributeName", "attributeValue")) { | ||
bosk.registerHook("contextPropagatesToHook", bosk.rootReference(), ref -> { | ||
assertEquals("attributeValue", bosk.diagnosticContext().getAttribute("attributeName")); | ||
assertEquals(MapValue.singleton("attributeName", "attributeValue"), bosk.diagnosticContext().getAttributes()); | ||
diagnosticsVerified.release(); | ||
}); | ||
} | ||
bosk.driver().flush(); | ||
assertTrue(diagnosticsVerified.tryAcquire(5, SECONDS)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.