Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ public interface GrpcLogger extends BasicLogger {
@LogMessage(level = WARN)
@Message(id = 12, value = "Weld capability not available for deployment %s; CDI injection will not be available for gRPC services.")
void weldCapabilityUnavailable(@Cause Throwable cause, String deploymentName);

@LogMessage(level = WARN)
@Message(id = 13, value = "Exception during gRPC service cleanup; resources may not have been fully released.")
void failedToCleanupGrpcResources(@Cause Throwable cause);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import static org.wildfly.extension.grpc._private.GrpcLogger.LOGGER;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Comparator;
Expand Down Expand Up @@ -60,136 +59,98 @@ class GrpcDeploymentService implements Service {
public void start(final StartContext context) throws StartException {
final WildFlyGrpcDeploymentRegistry serverService = serverServiceSupplier.get();
try {
// Interceptors are shared across all services of the deployment — instantiate once, not per service.
final List<ServerInterceptor> interceptors = createInterceptors();
for (Class<? extends BindableService> serviceType : serviceClasses) {
final List<ServerInterceptor> interceptors = createInterceptors();
final BindableService instance = createServiceInstance(serviceType);
final BindableService instance = createInstance(serviceType);
LOGGER.debugf("Registering gRPC service %s for deployment %s.", serviceType.getName(), deploymentName);
ServerServiceDefinition ssd = serverService.addService(deploymentName, instance, interceptors);
registeredServices.add(ssd);
}
} catch (StartException e) {
for (ServerServiceDefinition ssd : registeredServices) {
serverService.removeService(ssd);
}
registeredServices.clear();
for (CreationalContext<?> ctx : creationalContexts) {
ctx.release();
}
creationalContexts.clear();
} catch (StartException | RuntimeException e) {
unregister(serverService, e);
throw e;
}
}

@Override
public void stop(final StopContext context) {
final WildFlyGrpcDeploymentRegistry serverService = serverServiceSupplier.get();
for (ServerServiceDefinition ssd : registeredServices) {
serverService.removeService(ssd);
}
registeredServices.clear();
unregister(serverServiceSupplier.get(), null);
}

for (CreationalContext<?> ctx : creationalContexts) {
ctx.release();
private void unregister(final WildFlyGrpcDeploymentRegistry serverService, final Exception cause) {
if (serverService == null) {
return;
}
registeredServices.forEach(ssd -> runSafely(() -> serverService.removeService(ssd), cause));
registeredServices.clear();
creationalContexts.forEach(ctx -> runSafely(ctx::release, cause));
creationalContexts.clear();
}

private BindableService createServiceInstance(Class<? extends BindableService> serviceType) throws StartException {
if (beanManagerSupplier != null) {
final BeanManager bm = beanManagerSupplier.get();
if (bm != null) {
Set<Bean<?>> beans = bm.getBeans(serviceType);
if (!beans.isEmpty()) {
final Bean<?> bean;
try {
bean = bm.resolve(beans);
} catch (AmbiguousResolutionException e) {
throw LOGGER.failedToRegister(e, serviceType.getName(), deploymentName);
}
CreationalContext<?> ctx = bm.createCreationalContext(bean);
BindableService instance = (BindableService) bm.getReference(bean, serviceType, ctx);
creationalContexts.add(ctx);
LOGGER.debugf("Instantiating gRPC service %s as CDI bean for deployment %s.", serviceType.getName(),
deploymentName);
return instance;
}
private static void runSafely(final Runnable action, final Exception cause) {
try {
action.run();
} catch (RuntimeException suppressed) {
if (cause != null) {
cause.addSuppressed(suppressed);
} else {
LOGGER.failedToCleanupGrpcResources(suppressed);
}
}
return createViaReflection(serviceType);
}

private BindableService createViaReflection(Class<? extends BindableService> serviceType) throws StartException {
private List<ServerInterceptor> createInterceptors() throws StartException {
List<Class<? extends ServerInterceptor>> classes = new ArrayList<>();
try {
final Constructor<? extends BindableService> constructor = serviceType.getConstructor();
return constructor.newInstance();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException
| IllegalAccessException e) {
throw LOGGER.failedToRegister(e, serviceType.getName(), deploymentName);
for (String className : interceptorClassNames) {
classes.add(classLoader.loadClass(className).asSubclass(ServerInterceptor.class));
}
} catch (ClassNotFoundException e) {
throw new StartException(e);
}
}

private List<ServerInterceptor> createInterceptors() throws StartException {
List<Class<? extends ServerInterceptor>> sortedClasses = getInterceptorClasses();
// Sort by @Priority descending; unannotated interceptors come last.
classes.sort(Comparator.comparingInt((Class<? extends ServerInterceptor> clazz) -> {
Priority p = clazz.getAnnotation(Priority.class);
return p != null ? p.value() : Integer.MAX_VALUE;
}).reversed());
List<ServerInterceptor> interceptors = new ArrayList<>();
for (Class<? extends ServerInterceptor> interceptorType : sortedClasses) {
for (Class<? extends ServerInterceptor> interceptorType : classes) {
LOGGER.debugf("Registering global gRPC ServerInterceptor %s.", interceptorType.getName());
interceptors.add(createInterceptorInstance(interceptorType));
interceptors.add(createInstance(interceptorType));
}
return interceptors;
}

private ServerInterceptor createInterceptorInstance(Class<? extends ServerInterceptor> interceptorType)
throws StartException {
private <T> T createInstance(Class<T> type) throws StartException {
if (beanManagerSupplier != null) {
final BeanManager bm = beanManagerSupplier.get();
if (bm != null) {
Set<Bean<?>> beans = bm.getBeans(interceptorType);
if (bm == null) {
LOGGER.debugf("BeanManager not available for deployment %s; instantiating %s via reflection.",
deploymentName, type.getName());
} else {
Set<Bean<?>> beans = bm.getBeans(type);
if (!beans.isEmpty()) {
final Bean<?> bean;
try {
bean = bm.resolve(beans);
} catch (AmbiguousResolutionException e) {
throw LOGGER.failedToRegister(e, interceptorType.getName(), deploymentName);
throw LOGGER.failedToRegister(e, type.getName(), deploymentName);
}
CreationalContext<?> ctx = bm.createCreationalContext(bean);
ServerInterceptor instance = (ServerInterceptor) bm.getReference(bean, interceptorType, ctx);
T instance = type.cast(bm.getReference(bean, type, ctx));
creationalContexts.add(ctx);
LOGGER.debugf("Instantiating gRPC ServerInterceptor %s as CDI bean for deployment %s.",
interceptorType.getName(), deploymentName);
LOGGER.debugf("Instantiating %s as CDI bean for deployment %s.", type.getName(), deploymentName);
return instance;
}
}
}
return createInterceptorViaReflection(interceptorType);
}

private ServerInterceptor createInterceptorViaReflection(Class<? extends ServerInterceptor> interceptorType)
throws StartException {
try {
final Constructor<? extends ServerInterceptor> constructor = interceptorType.getConstructor();
return constructor.newInstance();
return type.getConstructor().newInstance();
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException
| IllegalAccessException e) {
throw LOGGER.failedToRegister(e, interceptorType.getName(), deploymentName);
throw LOGGER.failedToRegister(e, type.getName(), deploymentName);
}
}

private List<Class<? extends ServerInterceptor>> getInterceptorClasses() throws StartException {
List<Class<? extends ServerInterceptor>> classes = new ArrayList<>();
try {
for (String className : interceptorClassNames) {
classes.add(classLoader.loadClass(className).asSubclass(ServerInterceptor.class));
}
} catch (ClassNotFoundException e) {
throw new StartException(e);
}
// Sort interceptors by their @Priority annotations.
// Interceptors with the highest priority comes first.
// Interceptors with no @Priority comes last.
classes.sort(Comparator.comparingInt((Class<? extends ServerInterceptor> clazz) -> {
Priority p = clazz.getAnnotation(Priority.class);
return p != null ? p.value() : Integer.MAX_VALUE - 1;
}).reversed());
return classes;
}
}
Loading