2121package eu .openanalytics .containerproxy .stat ;
2222
2323import eu .openanalytics .containerproxy .backend .dispatcher .proxysharing .ProxySharingMicrometer ;
24+ import eu .openanalytics .containerproxy .spec .expression .SpecExpressionContext ;
25+ import eu .openanalytics .containerproxy .spec .expression .SpecExpressionResolver ;
26+ import eu .openanalytics .containerproxy .spec .expression .SpelField ;
2427import eu .openanalytics .containerproxy .stat .impl .InfluxDBCollector ;
2528import eu .openanalytics .containerproxy .stat .impl .JDBCCollector ;
2629import eu .openanalytics .containerproxy .stat .impl .Micrometer ;
30+ import jakarta .inject .Inject ;
31+ import lombok .AccessLevel ;
32+ import lombok .AllArgsConstructor ;
33+ import lombok .Builder ;
2734import lombok .Data ;
2835import lombok .Getter ;
36+ import lombok .NoArgsConstructor ;
2937import lombok .Setter ;
3038import org .apache .logging .log4j .LogManager ;
3139import org .apache .logging .log4j .Logger ;
32- import org .springframework .beans .BeansException ;
33- import org .springframework .beans .factory .config .BeanDefinition ;
34- import org .springframework .beans .factory .config .BeanFactoryPostProcessor ;
3540import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
36- import org .springframework .beans .factory .support .DefaultListableBeanFactory ;
37- import org .springframework .beans .factory .support .GenericBeanDefinition ;
38- import org .springframework .boot .context .properties .bind .BindResult ;
39- import org .springframework .boot .context .properties .bind .Binder ;
40- import org .springframework .context .EnvironmentAware ;
41- import org .springframework .core .env .Environment ;
42- import org .springframework .stereotype .Component ;
43-
44- import javax .annotation .Nonnull ;
41+ import org .springframework .boot .context .properties .ConfigurationProperties ;
42+ import org .springframework .context .annotation .Configuration ;
43+
44+ import javax .annotation .PostConstruct ;
4545import java .util .List ;
4646
4747
48- @ Component
49- public class StatCollectorFactory implements BeanFactoryPostProcessor , EnvironmentAware {
48+ @ Configuration
49+ @ ConfigurationProperties (prefix = "proxy" )
50+ public class StatCollectorFactory {
5051
5152 @ Setter
5253 @ Getter
5354 private List <UsageStats > usageStats ;
5455
5556 @ Setter
5657 @ Getter
57- private String usageStatsUrl ;
58+ private SpelField . String usageStatsUrl = new SpelField . String () ;
5859
5960 @ Setter
6061 @ Getter
61- private String usageStatsUsername ;
62+ private SpelField . String usageStatsUsername = new SpelField . String () ;
6263
6364 @ Setter
6465 @ Getter
65- private String usageStatsPassword ;
66+ private SpelField . String usageStatsPassword = new SpelField . String () ;
6667
6768 @ Setter
6869 @ Getter
69- private String usageStatsTableName ;
70+ private SpelField . String usageStatsTableName = new SpelField . String () ;
7071
7172 @ Setter
7273 @ Getter
7374 private List <UsageStatsAttribute > usageStatsAttributes ;
7475
7576 private final Logger log = LogManager .getLogger (StatCollectorFactory .class );
7677
77- private Environment environment ;
78-
79- @ Override
80- public void postProcessBeanFactory (@ Nonnull ConfigurableListableBeanFactory configurableListableBeanFactory ) throws BeansException {
81- BindResult <StatCollectorFactory > bindResult = Binder .get (environment ).bind ("proxy" , StatCollectorFactory .class );
82- if (!bindResult .isBound ()) {
83- return ;
78+ @ Inject
79+ private SpecExpressionResolver specExpressionResolver ;
80+
81+ @ Inject
82+ private ConfigurableListableBeanFactory beanFactory ;
83+
84+ @ PostConstruct
85+ public void init () {
86+ SpecExpressionContext specExpressionContext = SpecExpressionContext .create ();
87+ String resolvedUsageStatsUrl = usageStatsUrl .resolve (specExpressionResolver , specExpressionContext ).getValueOrNull ();
88+ if (resolvedUsageStatsUrl != null && !resolvedUsageStatsUrl .isEmpty ()) {
89+ createBean (createCollector (
90+ resolvedUsageStatsUrl ,
91+ usageStatsUsername .resolve (specExpressionResolver , specExpressionContext ).getValueOrNull (),
92+ usageStatsPassword .resolve (specExpressionResolver , specExpressionContext ).getValueOrNull (),
93+ usageStatsTableName .resolve (specExpressionResolver , specExpressionContext ).getValueOrNull (),
94+ usageStatsAttributes ), "IStatsCollector" );
8495 }
85- StatCollectorFactory result = bindResult .get ();
86- DefaultListableBeanFactory registry = (DefaultListableBeanFactory ) configurableListableBeanFactory ;
8796
88- if (result .getUsageStats () != null ) {
89- for (UsageStats usageStats : result .getUsageStats ()) {
90- createCollector (registry , usageStats .url , usageStats .username , usageStats .password , usageStats .tableName , usageStats .attributes );
97+ if (usageStats != null ) {
98+ int i = 0 ;
99+ for (UsageStats usageStats : getUsageStats ()) {
100+ UsageStats resolved = usageStats .resolve (specExpressionResolver , specExpressionContext );
101+ createBean (createCollector (
102+ resolved .url .getValueOrNull (),
103+ resolved .username .getValueOrNull (),
104+ resolved .password .getValueOrNull (),
105+ resolved .tableName .getValueOrNull (),
106+ usageStats .attributes ), "IStatsCollector-" + i );
107+ i ++;
91108 }
92109 }
93110
94- if (result .usageStatsUrl != null && !result .usageStatsUrl .isEmpty ()) {
95- createCollector (registry , result .usageStatsUrl , result .usageStatsUsername , result .usageStatsPassword , result .usageStatsTableName , result .usageStatsAttributes );
96- }
97111 }
98112
99- private void createCollector (DefaultListableBeanFactory registry , String url , String username , String password , String tableName , List <UsageStatsAttribute > usageStatsAttributes ) {
100- log .info (String . format ( "Enabled. Sending usage statistics to %s ." , url ) );
113+ private IStatCollector createCollector (String url , String username , String password , String tableName , List <UsageStatsAttribute > usageStatsAttributes ) {
114+ log .info ("Enabled. Sending usage statistics to {} ." , url );
101115
102- BeanDefinition bd = new GenericBeanDefinition ();
103116 if (url .toLowerCase ().contains ("/write?db=" )) {
104- bd .setBeanClassName (InfluxDBCollector .class .getName ());
105- bd .getConstructorArgumentValues ().addGenericArgumentValue (url );
117+ return new InfluxDBCollector (url );
106118 } else if (url .toLowerCase ().startsWith ("jdbc" )) {
107- bd .setBeanClassName (JDBCCollector .class .getName ());
108- bd .getConstructorArgumentValues ().addGenericArgumentValue (url );
109- bd .getConstructorArgumentValues ().addGenericArgumentValue (username );
110- bd .getConstructorArgumentValues ().addGenericArgumentValue (password );
111- bd .getConstructorArgumentValues ().addGenericArgumentValue (tableName == null ? "event" : tableName );
112- bd .getConstructorArgumentValues ().addGenericArgumentValue (usageStatsAttributes );
119+ return new JDBCCollector (url , username , password , tableName == null ? "event" : tableName , usageStatsAttributes );
113120 } else if (url .equalsIgnoreCase ("micrometer" )) {
114- bd .setBeanClassName (Micrometer .class .getName ());
115-
116- BeanDefinition bd2 = new GenericBeanDefinition ();
117- bd2 .setBeanClassName (ProxySharingMicrometer .class .getName ());
118- registry .registerBeanDefinition ("ProxySharingMicrometer" , bd2 );
121+ createBean (new ProxySharingMicrometer (), "ProxySharingMicrometer" );
122+ return new Micrometer ();
119123 } else {
120124 throw new IllegalArgumentException (String .format ("Base url for statistics contains an unrecognized values, baseURL %s." , url ));
121125 }
122-
123- registry .registerBeanDefinition (url , bd );
124- }
125-
126- @ Override
127- public void setEnvironment (Environment environment ) {
128- this .environment = environment ;
129126 }
130127
131128 @ Data
129+ @ Builder (toBuilder = true )
130+ @ AllArgsConstructor (access = AccessLevel .PRIVATE ) // force Spring to not use constructor
131+ @ NoArgsConstructor (force = true , access = AccessLevel .PRIVATE ) // Jackson deserialize compatibility
132132 public static class UsageStats {
133133
134- private String url ;
135- private String username ;
136- private String password ;
137- private String tableName ;
134+ @ Builder .Default
135+ private SpelField .String url = new SpelField .String ();
136+
137+ @ Builder .Default
138+ private SpelField .String username = new SpelField .String ();
139+
140+ @ Builder .Default
141+ private SpelField .String password = new SpelField .String ();
142+
143+ @ Builder .Default
144+ private SpelField .String tableName = new SpelField .String ();
145+
138146 private List <UsageStatsAttribute > attributes ;
139147
148+ public UsageStats resolve (SpecExpressionResolver specExpressionResolver , SpecExpressionContext specExpressionContext ) {
149+ return toBuilder ()
150+ .url (url .resolve (specExpressionResolver , specExpressionContext ))
151+ .username (username .resolve (specExpressionResolver , specExpressionContext ))
152+ .password (password .resolve (specExpressionResolver , specExpressionContext ))
153+ .tableName (tableName .resolve (specExpressionResolver , specExpressionContext ))
154+ .build ();
155+ }
156+
140157 }
141158
142159 @ Data
@@ -147,4 +164,10 @@ public static class UsageStatsAttribute {
147164
148165 }
149166
167+ private <T > void createBean (T bean , String beanName ) {
168+ beanFactory .autowireBean (bean );
169+ Object initializedBean = beanFactory .initializeBean (bean , beanName );
170+ beanFactory .registerSingleton (beanName , initializedBean );
171+ }
172+
150173}
0 commit comments