66import io .javaoperatorsdk .operator .api .ResourceController ;
77import io .javaoperatorsdk .operator .api .config .ConfigurationService ;
88import io .javaoperatorsdk .operator .api .config .ControllerConfiguration ;
9+ import io .javaoperatorsdk .operator .api .config .RetryConfiguration ;
910import io .javaoperatorsdk .quarkus .extension .ConfigurationServiceRecorder ;
11+ import io .javaoperatorsdk .quarkus .extension .ExternalConfiguration ;
12+ import io .javaoperatorsdk .quarkus .extension .ExternalControllerConfiguration ;
1013import io .javaoperatorsdk .quarkus .extension .OperatorProducer ;
1114import io .javaoperatorsdk .quarkus .extension .QuarkusConfigurationService ;
1215import io .javaoperatorsdk .quarkus .extension .QuarkusControllerConfiguration ;
@@ -49,6 +52,8 @@ class QuarkusExtensionProcessor {
4952 throw new IllegalArgumentException ();
5053 };
5154
55+ private ExternalConfiguration externalConfiguration ;
56+
5257 @ BuildStep
5358 void indexSDKDependencies (
5459 BuildProducer <IndexDependencyBuildItem > indexDependency ,
@@ -110,16 +115,6 @@ private ControllerConfiguration createControllerConfiguration(
110115 .setDefaultScope (APPLICATION_SCOPED )
111116 .build ());
112117
113- // generate configuration
114- final var controllerAnnotation = info .classAnnotation (CONTROLLER );
115- if (controllerAnnotation == null ) {
116- throw new IllegalArgumentException (
117- resourceControllerClassName
118- + " is missing the @"
119- + Controller .class .getCanonicalName ()
120- + " annotation" );
121- }
122-
123118 // load CR class
124119 final Class <CustomResource > crClass = (Class <CustomResource >) loadClass (crType );
125120
@@ -137,38 +132,45 @@ private ControllerConfiguration createControllerConfiguration(
137132 // register CR class for introspection
138133 reflectionClasses .produce (new ReflectiveClassBuildItem (true , true , crClass ));
139134
135+ // retrieve the Controller annotation if it exists
136+ final var controllerAnnotation = info .classAnnotation (CONTROLLER );
137+
138+ // retrieve the controller's name
139+ final var defaultControllerName =
140+ ControllerUtils .getDefaultResourceControllerName (resourceControllerClassName );
140141 final var name =
141- valueOrDefault (
142- controllerAnnotation ,
143- "name" ,
144- AnnotationValue ::asString ,
145- () -> ControllerUtils .getDefaultResourceControllerName (resourceControllerClassName ));
142+ annotationValueOrDefault (
143+ controllerAnnotation , "name" , AnnotationValue ::asString , () -> defaultControllerName );
144+
145+ // check if we have externalized configuration to provide values
146+ final var extContConfig = externalConfiguration .controllers .get (name );
147+
148+ final var extractor = new ValueExtractor (controllerAnnotation , extContConfig );
146149
147150 // create the configuration
148151 final var configuration =
149152 new QuarkusControllerConfiguration (
150153 resourceControllerClassName ,
151154 name ,
152155 crdName ,
153- valueOrDefault (
154- controllerAnnotation ,
156+ extractor . extract (
157+ c -> c . finalizer ,
155158 "finalizerName" ,
156159 AnnotationValue ::asString ,
157160 () -> ControllerUtils .getDefaultFinalizerName (crdName )),
158- valueOrDefault (
159- controllerAnnotation ,
161+ extractor . extract (
162+ c -> c . generationAware ,
160163 "generationAwareEventProcessing" ,
161164 AnnotationValue ::asBoolean ,
162165 () -> true ),
163166 QuarkusControllerConfiguration .asSet (
164- valueOrDefault (
165- controllerAnnotation ,
167+ extractor . extract (
168+ c -> c . namespaces . map ( l -> l . toArray ( new String [ 0 ])) ,
166169 "namespaces" ,
167170 AnnotationValue ::asStringArray ,
168171 () -> new String [] {})),
169172 crType ,
170- null // todo: fix-me
171- );
173+ retryConfiguration (extContConfig ));
172174
173175 log .infov (
174176 "Processed ''{0}'' controller named ''{1}'' for ''{2}'' CR (version ''{3}'')" ,
@@ -177,12 +179,72 @@ private ControllerConfiguration createControllerConfiguration(
177179 return configuration ;
178180 }
179181
180- private <T > T valueOrDefault (
182+ private RetryConfiguration retryConfiguration (ExternalControllerConfiguration extConfig ) {
183+ return extConfig == null ? null : RetryConfigurationResolver .resolve (extConfig .retry );
184+ }
185+
186+ private static class ValueExtractor {
187+
188+ private final AnnotationInstance controllerAnnotation ;
189+ private final ExternalControllerConfiguration extContConfig ;
190+
191+ ValueExtractor (
192+ AnnotationInstance controllerAnnotation , ExternalControllerConfiguration extContConfig ) {
193+ this .controllerAnnotation = controllerAnnotation ;
194+ this .extContConfig = extContConfig ;
195+ }
196+
197+ /**
198+ * Extracts the appropriate configuration value for the controller checking first any annotation
199+ * configuration, then potentially overriding it by a properties-provided value or returning a
200+ * default value if neither is provided.
201+ *
202+ * @param extractor a Function extracting the optional value we're interested in from the
203+ * external configuration
204+ * @param annotationField the name of the {@link Controller} annotation we're want to retrieve
205+ * if present
206+ * @param converter a Function converting the annotation value to the type we're expecting
207+ * @param defaultValue a Supplier that computes/retrieve a default value when needed
208+ * @param <T> the expected type of the configuration value we're trying to extract
209+ * @return the extracted configuration value
210+ */
211+ <T > T extract (
212+ Function <ExternalControllerConfiguration , Optional <T >> extractor ,
213+ String annotationField ,
214+ Function <AnnotationValue , T > converter ,
215+ Supplier <T > defaultValue ) {
216+ // first check if we have an external configuration
217+ if (extContConfig != null ) {
218+ // extract value from config if present
219+ return extractor
220+ .apply (extContConfig )
221+ // or get from the annotation or default
222+ .orElse (annotationValueOrDefault (annotationField , converter , defaultValue ));
223+ } else {
224+ // get from annotation or default
225+ return annotationValueOrDefault (annotationField , converter , defaultValue );
226+ }
227+ }
228+
229+ private <T > T annotationValueOrDefault (
230+ String name , Function <AnnotationValue , T > converter , Supplier <T > defaultValue ) {
231+ return QuarkusExtensionProcessor .annotationValueOrDefault (
232+ controllerAnnotation , name , converter , defaultValue );
233+ }
234+ }
235+
236+ private static <T > T annotationValueOrDefault (
181237 AnnotationInstance annotation ,
182238 String name ,
183239 Function <AnnotationValue , T > converter ,
184240 Supplier <T > defaultValue ) {
185- return Optional .ofNullable (annotation .value (name )).map (converter ).orElseGet (defaultValue );
241+ return annotation != null
242+ ?
243+ // get converted annotation value of get default
244+ Optional .ofNullable (annotation .value (name )).map (converter ).orElseGet (defaultValue )
245+ :
246+ // get default
247+ defaultValue .get ();
186248 }
187249
188250 private Class <?> loadClass (String className ) {
0 commit comments