collado-mike commented on code in PR #493:
URL: https://github.com/apache/polaris/pull/493#discussion_r1866669012
##########
polaris-service/src/main/java/org/apache/polaris/service/PolarisApplication.java:
##########
@@ -151,87 +173,195 @@ public void
initialize(Bootstrap<PolarisApplicationConfig> bootstrap) {
bootstrap.addCommand(new BootstrapRealmsCommand());
bootstrap.addCommand(new PurgeRealmsCommand());
- }
+ serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
+ SimpleValueInstantiators instantiators = new SimpleValueInstantiators();
+ ObjectMapper objectMapper = bootstrap.getObjectMapper();
- @Override
- public void run(PolarisApplicationConfig configuration, Environment
environment) {
- MetaStoreManagerFactory metaStoreManagerFactory =
configuration.getMetaStoreManagerFactory();
-
- metaStoreManagerFactory.setStorageIntegrationProvider(
- new PolarisStorageIntegrationProviderImpl(
- () -> {
- StsClientBuilder stsClientBuilder = StsClient.builder();
- AwsCredentialsProvider awsCredentialsProvider =
configuration.credentialsProvider();
- if (awsCredentialsProvider != null) {
- stsClientBuilder.credentialsProvider(awsCredentialsProvider);
+ // Register the PolarisApplicationConfig class with the ServiceLocator so
that we can inject
+ // instances of the configuration or certain of the configuration fields
into other classes.
+ // The configuration's postConstruct method registers all the configured
fields as factories
+ // so that they are used for DI.
+ ServiceLocatorUtilities.addClasses(serviceLocator,
PolarisApplicationConfig.class);
+ TypeFactory typeFactory = TypeFactory.defaultInstance();
+ instantiators.addValueInstantiator(
+ PolarisApplicationConfig.class,
+ new ServiceLocatorValueInstantiator(
+ objectMapper.getDeserializationConfig(),
+ typeFactory.constructType(PolarisApplicationConfig.class),
+ serviceLocator));
+
+ // Use the default ServiceLocator to discover the implementations of
various contract providers
+ // and register them as subtypes with the ObjectMapper. This allows
Jackson to discover the
+ // various implementations and use the type annotations to determine which
instance to use when
+ // parsing the YAML configuration.
+ serviceLocator
+ .getDescriptors((c) -> true)
+ .forEach(
+ descriptor -> {
+ try {
+ Class<?> klazz =
+ PolarisApplication.class
+ .getClassLoader()
+ .loadClass(descriptor.getImplementation());
+ String name = descriptor.getName();
+ if (name == null) {
+ objectMapper.registerSubtypes(klazz);
+ } else {
+ objectMapper.registerSubtypes(new NamedType(klazz, name));
+ }
+ } catch (ClassNotFoundException e) {
+ LOGGER.error("Error loading class {}",
descriptor.getImplementation(), e);
+ throw new RuntimeException("Unable to start Polaris
application");
}
- return stsClientBuilder.build();
- },
- configuration.getGcpCredentialsProvider()));
+ });
- PolarisMetricRegistry polarisMetricRegistry =
- new PolarisMetricRegistry(new
PrometheusMeterRegistry(PrometheusConfig.DEFAULT));
- metaStoreManagerFactory.setMetricRegistry(polarisMetricRegistry);
+ ServiceLocatorUtilities.addClasses(serviceLocator,
PolarisMetricRegistry.class);
+ ServiceLocatorUtilities.bind(
+ serviceLocator,
+ new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(new
PrometheusMeterRegistry(PrometheusConfig.DEFAULT)).to(MeterRegistry.class);
+ }
+ });
+ SimpleModule module = new SimpleModule();
+ module.setValueInstantiators(instantiators);
+ module.setMixInAnnotation(Authenticator.class, NamedAuthenticator.class);
+ objectMapper.registerModule(module);
+ }
- OpenTelemetry openTelemetry = setupTracing();
- if (metaStoreManagerFactory instanceof OpenTelemetryAware otAware) {
- otAware.setOpenTelemetry(openTelemetry);
+ /**
+ * Value instantiator that uses the ServiceLocator to create instances of
the various service
+ * types
+ */
+ private static class ServiceLocatorValueInstantiator extends
StdValueInstantiator {
+ private final ServiceLocator serviceLocator;
+
+ public ServiceLocatorValueInstantiator(
+ DeserializationConfig config, JavaType valueType, ServiceLocator
serviceLocator) {
+ super(config, valueType);
+ this.serviceLocator = serviceLocator;
}
- PolarisConfigurationStore configurationStore =
configuration.getConfigurationStore();
- if (metaStoreManagerFactory instanceof ConfigurationStoreAware) {
- ((ConfigurationStoreAware)
metaStoreManagerFactory).setConfigurationStore(configurationStore);
+
+ @Override
+ public boolean canCreateUsingDefault() {
+ return true;
}
- RealmEntityManagerFactory entityManagerFactory =
- new RealmEntityManagerFactory(metaStoreManagerFactory);
- CallContextResolver callContextResolver =
configuration.getCallContextResolver();
- callContextResolver.setMetaStoreManagerFactory(metaStoreManagerFactory);
- if (callContextResolver instanceof ConfigurationStoreAware csa) {
- csa.setConfigurationStore(configurationStore);
+
+ @Override
+ public boolean canInstantiate() {
+ return true;
}
- RealmContextResolver realmContextResolver =
configuration.getRealmContextResolver();
- realmContextResolver.setMetaStoreManagerFactory(metaStoreManagerFactory);
+ @Override
+ public Object createUsingDefault(DeserializationContext ctxt) throws
IOException {
+ return ServiceLocatorUtilities.findOrCreateService(serviceLocator,
getValueClass());
+ }
+ }
+
+ /**
+ * Authenticator uses the java Class name in the YAML configuration. Since
the Authenticator
+ * interface is owned by Dropwizard, we need to use a MixIn to tell Jackson
what field to use to
+ * discover the implementation from the configuration.
+ */
+ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "class")
+ static final class NamedAuthenticator {}
+
+ @Override
+ public void run(PolarisApplicationConfig configuration, Environment
environment) {
+ OpenTelemetry openTelemetry = setupTracing();
+ PolarisMetricRegistry polarisMetricRegistry =
+ configuration.findService(PolarisMetricRegistry.class);
+
+ MetaStoreManagerFactory metaStoreManagerFactory =
+ configuration.findService(MetaStoreManagerFactory.class);
+
+ // Use the PolarisApplicationConfig to register dependencies in the Jersey
resource
+ // configuration. This uses a different ServiceLocator from the one in the
bootstrap step
+ environment.jersey().register(configuration.binder());
+ environment
+ .jersey()
+ .register(
+ new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bind(RealmScopeContext.class)
Review Comment:
I think this should be considered the smallest change necessary to get CDI
working. There are improvements that can be made, e.g., classpath scanning for
detecting Resource and Service impls, but the primary goal right now is to have
runtime framework dependent on `@Inject` for wiring. Once that's done, lots of
other changes can happen in parallel - e.g., improvements to the authorizer,
authentication changes, as well as improvements to the CDI framework. I think
this accomplishes the smallest change necessary to allow those other changes to
progress.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]