Skip to content

Commit

Permalink
WFCORE-6347 Generalize service capture abstractions for use in wildfl…
Browse files Browse the repository at this point in the history
…y-service.
  • Loading branch information
pferraro committed Dec 28, 2023
1 parent fe4ebe4 commit c035c08
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.subsystem.service.capture;
package org.wildfly.service.capture;

import java.util.function.Supplier;

import org.wildfly.common.function.ExceptionFunction;

/**
* Encapsulates execution of a function.
* Encapsulates execution of a single argument function.
* @author Paul Ferraro
* @param <V> the type of the function argument
*/
public interface FunctionExecutor<V> {

/**
* Creates a function executor from the specified argument supplier.
* @param <V> the value type of the function argument
* @param reference a supplier of the function argument
* @return a new function executor instance
*/
static <V> FunctionExecutor<V> of(Supplier<V> reference) {
return new FunctionExecutor<>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.service.capture;

/**
* Registry of {@link FunctionExecutor} objects.
* @author Paul Ferraro
* @param <K> the registry key type
* @param <V> the registry value type
*/
public interface FunctionExecutorRegistry<K, V> {
/**
* Returns the executor for the specified key.
* @param key a registry key
* @return an executor, or null, if no such executor exists in the registry
*/
FunctionExecutor<V> getExecutor(K key);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.service.capture;

import java.util.function.Consumer;

import org.jboss.msc.service.ServiceName;

/**
* A registry of captured values.
* @author Paul Ferraro
* @param <V> the captured value type
*/
public interface ServiceValueExecutorRegistry<V> extends ServiceValueRegistry<V>, FunctionExecutorRegistry<ServiceName, V> {

/**
* Creates a new {@link ServiceValueExecutorRegistry}.
* @param <V> the captured value type
* @return a new value executor registry
*/
static <V> ServiceValueExecutorRegistry<V> newInstance() {
ValueExecutorRegistry<ServiceName, V> registry = ValueExecutorRegistry.newInstance();
return new ServiceValueExecutorRegistry<>() {
@Override
public Consumer<V> add(ServiceName key) {
return registry.add(key);
}

@Override
public void remove(ServiceName key) {
registry.remove(key);
}

@Override
public FunctionExecutor<V> getExecutor(ServiceName key) {
return registry.getExecutor(key);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.service.capture;

import java.util.function.Consumer;

import org.jboss.msc.service.ServiceName;
import org.wildfly.service.ServiceDependency;
import org.wildfly.service.ServiceInstaller;

/**
* A registry of service values, keyed by {@link ServiceName}.
* @author Paul Ferraro
* @param <V> the registry value type
*/
public interface ServiceValueRegistry<V> extends ValueRegistry<ServiceName, V> {

/**
* Creates a service installer to capture and release the value provided by the specified service dependency.
* @param dependency a service dependency
* @return a service installer
*/
default ServiceInstaller capture(ServiceName name) {
Consumer<V> startTask = new Consumer<>() {
@Override
public void accept(V value) {
ServiceValueRegistry.this.add(name).accept(value);
}
};
Consumer<V> stopTask = new Consumer<>() {
@Override
public void accept(V value) {
ServiceValueRegistry.this.remove(name);
}
};
ServiceDependency<V> dependency = ServiceDependency.on(name);
return ServiceInstaller.builder(dependency).onStart(startTask).onStop(stopTask).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.service.capture;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

/**
* A registry of captured values.
* @author Paul Ferraro
* @param <K> the registry key type
* @param <V> the registry value type
*/
public interface ValueExecutorRegistry<K, V> extends ValueRegistry<K, V>, FunctionExecutorRegistry<K, V> {

/**
* Creates a new registry of values.
* @param <K> the registry key type
* @param <V> the registry value type
* @return a new registry instance
*/
static <K, V> ValueExecutorRegistry<K, V> newInstance() {
return new ValueExecutorRegistry<>() {
private final Map<K, AtomicReference<V>> references = new ConcurrentHashMap<>();

private AtomicReference<V> create(K dependency) {
return new AtomicReference<>();
}

@Override
public Consumer<V> add(K key) {
AtomicReference<V> reference = this.references.computeIfAbsent(key, this::create);
return reference::set;
}

@Override
public void remove(K key) {
AtomicReference<V> reference = this.references.remove(key);
if (reference != null) {
reference.set(null);
}
}

@Override
public FunctionExecutor<V> getExecutor(K key) {
AtomicReference<V> reference = this.references.get(key);
return (reference != null) ? FunctionExecutor.of(reference::get) : null;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.service.capture;

import java.util.function.Consumer;

/**
* A registry of values.
* @author Paul Ferraro
* @param <K> the registry key type
* @param <V> the registry value type
*/
public interface ValueRegistry<K, V> {

/**
* Adds a value registration for the specified key
* @param key a registry key
* @return a consumer to capture the value
*/
Consumer<V> add(K key);

/**
* Removes the registration for the specified key
* @param key a registry key
*/
void remove(K key);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.service.capture;

import java.util.UUID;
import java.util.function.Consumer;

import org.jboss.msc.service.ServiceName;
import org.junit.Assert;
import org.junit.Test;
import org.wildfly.common.function.ExceptionFunction;

/**
* @author Paul Ferraro
*/
public class ServiceValueExecutorRegistryTestCase {

private final ServiceValueExecutorRegistry<Object> registry = ServiceValueExecutorRegistry.newInstance();

@Test
public void test() {
this.test(ServiceName.JBOSS.append("foo"), ServiceName.JBOSS.append("bar"));
}

private void test(ServiceName service1, ServiceName service2) {
Object value1 = UUID.randomUUID();
Object value2 = UUID.randomUUID();

Assert.assertNull(this.registry.getExecutor(service1));
Assert.assertNull(this.registry.getExecutor(service2));

ExceptionFunction<Object, Object, RuntimeException> function = value -> value;

Consumer<Object> captor1 = this.registry.add(service1);
Consumer<Object> captor2 = this.registry.add(service2);

FunctionExecutor<Object> executor1 = this.registry.getExecutor(service1);
FunctionExecutor<Object> executor2 = this.registry.getExecutor(service2);

Assert.assertNull(executor1.execute(function));
Assert.assertNull(executor2.execute(function));

captor1.accept(value1);
captor2.accept(value2);

Assert.assertSame(value1, executor1.execute(function));
Assert.assertSame(value2, executor2.execute(function));

captor1.accept(null);
captor2.accept(null);

Assert.assertNull(executor1.execute(function));
Assert.assertNull(executor2.execute(function));

captor1.accept(value1);
captor2.accept(value2);

// Once removed, executor should return null
this.registry.remove(service1);
this.registry.remove(service2);

Assert.assertNull(this.registry.getExecutor(service1));
Assert.assertNull(this.registry.getExecutor(service2));

Assert.assertNull(executor1.execute(function));
Assert.assertNull(executor2.execute(function));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,42 @@
*/
package org.wildfly.subsystem.service.capture;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

import org.wildfly.service.capture.FunctionExecutor;
import org.wildfly.service.capture.FunctionExecutorRegistry;
import org.wildfly.service.capture.ValueExecutorRegistry;
import org.wildfly.subsystem.service.ServiceDependency;

/**
* A registry of captured values.
* @author Paul Ferraro
* @param <V> the captured value type
*/
public interface ServiceValueExecutorRegistry<V> extends ServiceValueRegistry<V>, FunctionExecutorRegistry<V> {
public interface ServiceValueExecutorRegistry<V> extends ServiceValueRegistry<V>, FunctionExecutorRegistry<ServiceDependency<V>, V> {

/**
* Creates a new {@link ServiceValueExecutorRegistry}.
* @param <V> the captured value type
* @return a new value executor registry
*/
static <V> ServiceValueExecutorRegistry<V> create() {
static <V> ServiceValueExecutorRegistry<V> newInstance() {
ValueExecutorRegistry<ServiceDependency<V>, V> registry = ValueExecutorRegistry.newInstance();
return new ServiceValueExecutorRegistry<>() {
private final Map<ServiceDependency<V>, AtomicReference<V>> references = new ConcurrentHashMap<>();

private AtomicReference<V> create(ServiceDependency<V> dependency) {
return new AtomicReference<>();
}

@Override
public Consumer<V> add(ServiceDependency<V> dependency) {
AtomicReference<V> reference = this.references.computeIfAbsent(dependency, this::create);
return reference::set;
return registry.add(dependency);
}

@Override
public void remove(ServiceDependency<V> dependency) {
AtomicReference<V> reference = this.references.remove(dependency);
if (reference != null) {
reference.set(null);
}
registry.remove(dependency);
}

@Override
public FunctionExecutor<V> getExecutor(ServiceDependency<V> dependency) {
AtomicReference<V> reference = this.references.get(dependency);
return (reference != null) ? FunctionExecutor.of(reference::get) : null;
return registry.getExecutor(dependency);
}
};
}

}
Loading

0 comments on commit c035c08

Please sign in to comment.