2424public class Operator implements LifecycleAware {
2525 private static final Logger log = LoggerFactory .getLogger (Operator .class );
2626
27- private final ControllerManager controllerManager ;
28- private final LeaderElectionManager leaderElectionManager ;
29- private final ConfigurationService configurationService ;
27+ private ControllerManager controllerManager ;
28+ private LeaderElectionManager leaderElectionManager ;
29+ private ConfigurationService configurationService ;
3030 private volatile boolean started = false ;
3131
3232 public Operator () {
33- this (( KubernetesClient ) null );
33+ init ( initConfigurationService ( null , null ), true );
3434 }
3535
3636 Operator (KubernetesClient kubernetesClient ) {
37- this (initConfigurationService (kubernetesClient , null ));
37+ init (initConfigurationService (kubernetesClient , null ), false );
3838 }
3939
4040 /**
@@ -46,12 +46,7 @@ public Operator() {
4646 * operator
4747 */
4848 public Operator (ConfigurationService configurationService ) {
49- this .configurationService = configurationService ;
50-
51- final var executorServiceManager = configurationService .getExecutorServiceManager ();
52- controllerManager = new ControllerManager (executorServiceManager );
53-
54- leaderElectionManager = new LeaderElectionManager (controllerManager , configurationService );
49+ init (configurationService , false );
5550 }
5651
5752 /**
@@ -62,10 +57,55 @@ public Operator(ConfigurationService configurationService) {
6257 * {@link ConfigurationService} values
6358 */
6459 public Operator (Consumer <ConfigurationServiceOverrider > overrider ) {
65- this (initConfigurationService (null , overrider ));
60+ init (initConfigurationService (null , overrider ), false );
61+ }
62+
63+ /**
64+ * In a deferred initialization scenario, the default constructor will typically be called to
65+ * create a proxy instance, usually to be replaced at some later time when the dependents (in this
66+ * case the ConfigurationService instance) are available. In this situation, we want to make it
67+ * possible to not perform the initialization steps directly so this implementation makes it
68+ * possible to not crash when a null ConfigurationService is passed only if deferred
69+ * initialization is allowed
70+ *
71+ * @param configurationService the potentially {@code null} {@link ConfigurationService} to use
72+ * for this operator
73+ * @param allowDeferredInit whether or not deferred initialization of the configuration service is
74+ * allowed
75+ * @throws IllegalStateException if the specified configuration service is {@code null} but
76+ * deferred initialization is not allowed
77+ */
78+ private void init (ConfigurationService configurationService , boolean allowDeferredInit ) {
79+ if (configurationService == null ) {
80+ if (!allowDeferredInit ) {
81+ throw new IllegalStateException (
82+ "Deferred initialization of ConfigurationService is not allowed" );
83+ }
84+ } else {
85+ this .configurationService = configurationService ;
86+
87+ final var executorServiceManager = configurationService .getExecutorServiceManager ();
88+ controllerManager = new ControllerManager (executorServiceManager );
89+
90+ leaderElectionManager = new LeaderElectionManager (controllerManager , configurationService );
91+ }
6692 }
6793
68- private static ConfigurationService initConfigurationService (
94+ /**
95+ * Overridable by subclasses to enable deferred configuration, useful to avoid unneeded processing
96+ * in injection scenarios, typically returning {@code null} here instead of performing any
97+ * configuration
98+ *
99+ * @param client a potentially {@code null} {@link KubernetesClient} to initialize the operator's
100+ * {@link ConfigurationService} with
101+ * @param overrider a potentially {@code null} {@link ConfigurationServiceOverrider} consumer to
102+ * override the default {@link ConfigurationService} with
103+ * @return a ready to use {@link ConfigurationService} using values provided by the specified
104+ * overrides and kubernetes client, if provided or {@code null} in case deferred
105+ * initialization is possible, in which case it is up to the extension to ensure that the
106+ * {@link ConfigurationService} is properly set before the operator instance is used
107+ */
108+ protected ConfigurationService initConfigurationService (
69109 KubernetesClient client , Consumer <ConfigurationServiceOverrider > overrider ) {
70110 // initialize the client if the user didn't provide one
71111 if (client == null ) {
@@ -232,8 +272,8 @@ public <P extends HasMetadata> RegisteredController<P> register(
232272 *
233273 * @param reconciler part of the reconciler to register
234274 * @param configOverrider consumer to use to change config values
235- * @return registered controller
236275 * @param <P> the {@code HasMetadata} type associated with the reconciler
276+ * @return registered controller
237277 */
238278 public <P extends HasMetadata > RegisteredController <P > register (
239279 Reconciler <P > reconciler , Consumer <ControllerConfigurationOverrider <P >> configOverrider ) {
@@ -266,4 +306,14 @@ boolean isStarted() {
266306 public ConfigurationService getConfigurationService () {
267307 return configurationService ;
268308 }
309+
310+ /**
311+ * Make it possible for extensions to set the {@link ConfigurationService} after the operator has
312+ * been initialized
313+ *
314+ * @param configurationService the {@link ConfigurationService} to use for this operator
315+ */
316+ protected void setConfigurationService (ConfigurationService configurationService ) {
317+ init (configurationService , false );
318+ }
269319}
0 commit comments