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