1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.spring.boot.autoconfigure.ldaptive;
18
19 import java.util.Objects;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.bremersee.ldaptive.LdaptiveOperations;
23 import org.bremersee.ldaptive.LdaptiveProperties;
24 import org.bremersee.ldaptive.LdaptiveProperties.ConnectionPoolProperties;
25 import org.bremersee.ldaptive.LdaptiveTemplate;
26 import org.bremersee.ldaptive.converter.DnToStringConverter;
27 import org.bremersee.ldaptive.converter.StringToDnConverter;
28 import org.bremersee.ldaptive.reactive.ReactiveLdaptiveOperations;
29 import org.bremersee.ldaptive.reactive.ReactiveLdaptiveTemplate;
30 import org.ldaptive.ConnectionConfig;
31 import org.ldaptive.ConnectionFactory;
32 import org.ldaptive.DefaultConnectionFactory;
33 import org.ldaptive.PooledConnectionFactory;
34 import org.ldaptive.dn.Dn;
35 import org.ldaptive.pool.IdlePruneStrategy;
36 import org.mapstruct.Mapper;
37 import org.mapstruct.NullValueCheckStrategy;
38 import org.mapstruct.factory.Mappers;
39 import org.springframework.boot.autoconfigure.AutoConfiguration;
40 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
41 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
42 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
43 import org.springframework.boot.context.event.ApplicationReadyEvent;
44 import org.springframework.boot.context.properties.EnableConfigurationProperties;
45 import org.springframework.context.annotation.Bean;
46 import org.springframework.context.event.EventListener;
47 import org.springframework.core.convert.converter.Converter;
48 import org.springframework.util.ClassUtils;
49
50
51
52
53
54
55 @AutoConfiguration
56 @ConditionalOnClass(name = {
57 "org.ldaptive.ConnectionFactory",
58 "org.bremersee.ldaptive.LdaptiveProperties"
59 })
60 @ConditionalOnProperty(prefix = "bremersee.ldaptive", name = "ldap-url")
61 @EnableConfigurationProperties(LdaptiveConnectionProperties.class)
62 public class LdaptiveAutoConfiguration {
63
64 private static final Log log = LogFactory.getLog(LdaptiveAutoConfiguration.class);
65
66 private final Class<? extends LdaptiveTemplate> ldaptiveTemplateClass;
67
68 private final LdaptiveProperties properties;
69
70
71
72
73
74
75 public LdaptiveAutoConfiguration(LdaptiveConnectionProperties properties) {
76 Class<?> cls = Objects
77 .requireNonNullElse(properties.getLdaptiveTemplateClass(), LdaptiveTemplate.class);
78
79 this.ldaptiveTemplateClass = LdaptiveTemplate.class.isAssignableFrom(cls)
80 ? (Class<? extends LdaptiveTemplate>) cls
81 : LdaptiveTemplate.class;
82 this.properties = PropertiesMapper.INSTANCE.map(properties);
83 }
84
85
86
87
88 @EventListener(ApplicationReadyEvent.class)
89 public void init() {
90 log.info(String.format("""
91
92 *********************************************************************************
93 * %s
94 * properties = %s
95 *********************************************************************************""",
96 ClassUtils.getUserClass(getClass()).getSimpleName(),
97 properties));
98 }
99
100
101
102
103
104
105 @ConditionalOnMissingBean(ConnectionConfig.class)
106 @Bean
107 public ConnectionConfig connectionConfig() {
108 return properties.createConnectionConfig();
109 }
110
111
112
113
114
115
116
117 @ConditionalOnMissingBean(ConnectionFactory.class)
118 @Bean(destroyMethod = "close")
119 public ConnectionFactory connectionFactory(ConnectionConfig connectionConfig) {
120
121 if (properties.isPooled()) {
122 ConnectionPoolProperties props = this.properties.getConnectionPool();
123 PooledConnectionFactory factory = PooledConnectionFactory.builder()
124 .config(connectionConfig)
125 .blockWaitTime(props.getBlockWaitTime())
126 .connectOnCreate(props.isConnectOnCreate())
127 .failFastInitialize(props.isFailFastInitialize())
128 .max(props.getMaxPoolSize())
129 .min(props.getMinPoolSize())
130 .pruneStrategy(
131 new IdlePruneStrategy(props.getPrunePeriod(), props.getIdleTime()))
132 .validateOnCheckIn(props.isValidateOnCheckIn())
133 .validateOnCheckOut(props.isValidateOnCheckOut())
134 .validatePeriodically(props.isValidatePeriodically())
135 .validator(props.getValidator().createConnectionValidator())
136 .build();
137 factory.initialize();
138 return factory;
139 }
140 return new DefaultConnectionFactory(connectionConfig);
141 }
142
143
144
145
146
147
148
149 @ConditionalOnMissingBean(LdaptiveOperations.class)
150 @Bean
151 public LdaptiveTemplate ldaptiveTemplate(ConnectionFactory connectionFactory) {
152 try {
153 return ldaptiveTemplateClass
154 .getConstructor(ConnectionFactory.class)
155 .newInstance(connectionFactory);
156 } catch (Exception e) {
157 log.warn(String.format(
158 "Could not instantiate LdaptiveTemplate %s. Instantiate default template.",
159 ldaptiveTemplateClass.getName()), e);
160 return new LdaptiveTemplate(connectionFactory);
161 }
162 }
163
164
165
166
167
168
169
170 @ConditionalOnClass(name = {"reactor.core.publisher.Mono"})
171 @ConditionalOnMissingBean(ReactiveLdaptiveOperations.class)
172 @Bean
173 public ReactiveLdaptiveTemplate reactiveLdaptiveTemplate(ConnectionFactory connectionFactory) {
174 return new ReactiveLdaptiveTemplate(connectionFactory);
175 }
176
177
178
179
180
181
182 @ConditionalOnMissingBean
183 @Bean
184 public Converter<String, Dn> stringToDnConverter() {
185 return new StringToDnConverter();
186 }
187
188
189
190
191
192
193 @ConditionalOnMissingBean
194 @Bean
195 public Converter<Dn, String> dnToStringConverter() {
196 return new DnToStringConverter();
197 }
198
199
200
201
202 @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
203 interface PropertiesMapper {
204
205
206
207
208 PropertiesMapper INSTANCE = Mappers.getMapper(PropertiesMapper.class);
209
210
211
212
213
214
215
216 LdaptiveProperties map(LdaptiveConnectionProperties properties);
217 }
218
219 }