1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.rest.cxf;
20
21 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
22 import com.fasterxml.jackson.jaxrs.xml.JacksonXMLProvider;
23 import com.fasterxml.jackson.jaxrs.yaml.JacksonYAMLProvider;
24 import io.swagger.v3.oas.models.security.SecurityScheme;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.concurrent.ThreadPoolExecutor;
30 import java.util.stream.Collectors;
31 import javax.validation.Validator;
32 import org.apache.cxf.Bus;
33 import org.apache.cxf.endpoint.Server;
34 import org.apache.cxf.jaxrs.ext.ContextProvider;
35 import org.apache.cxf.jaxrs.ext.search.SearchContext;
36 import org.apache.cxf.jaxrs.ext.search.SearchContextImpl;
37 import org.apache.cxf.jaxrs.ext.search.SearchContextProvider;
38 import org.apache.cxf.jaxrs.ext.search.SearchUtils;
39 import org.apache.cxf.jaxrs.model.doc.JavaDocProvider;
40 import org.apache.cxf.jaxrs.openapi.OpenApiCustomizer;
41 import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
42 import org.apache.cxf.jaxrs.spring.JAXRSServerFactoryBeanDefinitionParser.SpringJAXRSServerFactoryBean;
43 import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor;
44 import org.apache.cxf.transport.common.gzip.GZIPInInterceptor;
45 import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor;
46 import org.apache.cxf.validation.BeanValidationProvider;
47 import org.apache.syncope.common.lib.jackson.SyncopeJsonMapper;
48 import org.apache.syncope.common.lib.jackson.SyncopeXmlMapper;
49 import org.apache.syncope.common.lib.jackson.SyncopeYAMLMapper;
50 import org.apache.syncope.common.lib.search.SyncopeFiqlParser;
51 import org.apache.syncope.common.rest.api.DateParamConverterProvider;
52 import org.apache.syncope.common.rest.api.service.AccessTokenService;
53 import org.apache.syncope.common.rest.api.service.AnyObjectService;
54 import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
55 import org.apache.syncope.common.rest.api.service.AnyTypeService;
56 import org.apache.syncope.common.rest.api.service.ApplicationService;
57 import org.apache.syncope.common.rest.api.service.AuditService;
58 import org.apache.syncope.common.rest.api.service.CommandService;
59 import org.apache.syncope.common.rest.api.service.DelegationService;
60 import org.apache.syncope.common.rest.api.service.DynRealmService;
61 import org.apache.syncope.common.rest.api.service.FIQLQueryService;
62 import org.apache.syncope.common.rest.api.service.GroupService;
63 import org.apache.syncope.common.rest.api.service.ImplementationService;
64 import org.apache.syncope.common.rest.api.service.JAXRSService;
65 import org.apache.syncope.common.rest.api.service.MailTemplateService;
66 import org.apache.syncope.common.rest.api.service.NotificationService;
67 import org.apache.syncope.common.rest.api.service.PolicyService;
68 import org.apache.syncope.common.rest.api.service.RealmService;
69 import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
70 import org.apache.syncope.common.rest.api.service.ReportService;
71 import org.apache.syncope.common.rest.api.service.RoleService;
72 import org.apache.syncope.common.rest.api.service.SchemaService;
73 import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
74 import org.apache.syncope.common.rest.api.service.SyncopeService;
75 import org.apache.syncope.common.rest.api.service.TaskService;
76 import org.apache.syncope.common.rest.api.service.UserSelfService;
77 import org.apache.syncope.common.rest.api.service.UserService;
78 import org.apache.syncope.core.logic.AccessTokenLogic;
79 import org.apache.syncope.core.logic.AnyObjectLogic;
80 import org.apache.syncope.core.logic.AnyTypeClassLogic;
81 import org.apache.syncope.core.logic.AnyTypeLogic;
82 import org.apache.syncope.core.logic.ApplicationLogic;
83 import org.apache.syncope.core.logic.AuditLogic;
84 import org.apache.syncope.core.logic.CommandLogic;
85 import org.apache.syncope.core.logic.DelegationLogic;
86 import org.apache.syncope.core.logic.DynRealmLogic;
87 import org.apache.syncope.core.logic.FIQLQueryLogic;
88 import org.apache.syncope.core.logic.GroupLogic;
89 import org.apache.syncope.core.logic.ImplementationLogic;
90 import org.apache.syncope.core.logic.MailTemplateLogic;
91 import org.apache.syncope.core.logic.NotificationLogic;
92 import org.apache.syncope.core.logic.PolicyLogic;
93 import org.apache.syncope.core.logic.RealmLogic;
94 import org.apache.syncope.core.logic.RelationshipTypeLogic;
95 import org.apache.syncope.core.logic.ReportLogic;
96 import org.apache.syncope.core.logic.RoleLogic;
97 import org.apache.syncope.core.logic.SchemaLogic;
98 import org.apache.syncope.core.logic.SecurityQuestionLogic;
99 import org.apache.syncope.core.logic.SyncopeLogic;
100 import org.apache.syncope.core.logic.TaskLogic;
101 import org.apache.syncope.core.logic.UserLogic;
102 import org.apache.syncope.core.persistence.api.DomainHolder;
103 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
104 import org.apache.syncope.core.persistence.api.dao.BatchDAO;
105 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
106 import org.apache.syncope.core.persistence.api.dao.UserDAO;
107 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
108 import org.apache.syncope.core.persistence.api.search.SearchCondVisitor;
109 import org.apache.syncope.core.rest.cxf.service.AccessTokenServiceImpl;
110 import org.apache.syncope.core.rest.cxf.service.AnyObjectServiceImpl;
111 import org.apache.syncope.core.rest.cxf.service.AnyTypeClassServiceImpl;
112 import org.apache.syncope.core.rest.cxf.service.AnyTypeServiceImpl;
113 import org.apache.syncope.core.rest.cxf.service.ApplicationServiceImpl;
114 import org.apache.syncope.core.rest.cxf.service.AuditServiceImpl;
115 import org.apache.syncope.core.rest.cxf.service.CommandServiceImpl;
116 import org.apache.syncope.core.rest.cxf.service.DelegationServiceImpl;
117 import org.apache.syncope.core.rest.cxf.service.DynRealmServiceImpl;
118 import org.apache.syncope.core.rest.cxf.service.FIQLQueryServiceImpl;
119 import org.apache.syncope.core.rest.cxf.service.GroupServiceImpl;
120 import org.apache.syncope.core.rest.cxf.service.ImplementationServiceImpl;
121 import org.apache.syncope.core.rest.cxf.service.MailTemplateServiceImpl;
122 import org.apache.syncope.core.rest.cxf.service.NotificationServiceImpl;
123 import org.apache.syncope.core.rest.cxf.service.PolicyServiceImpl;
124 import org.apache.syncope.core.rest.cxf.service.RealmServiceImpl;
125 import org.apache.syncope.core.rest.cxf.service.RelationshipTypeServiceImpl;
126 import org.apache.syncope.core.rest.cxf.service.ReportServiceImpl;
127 import org.apache.syncope.core.rest.cxf.service.RoleServiceImpl;
128 import org.apache.syncope.core.rest.cxf.service.SchemaServiceImpl;
129 import org.apache.syncope.core.rest.cxf.service.SecurityQuestionServiceImpl;
130 import org.apache.syncope.core.rest.cxf.service.SyncopeServiceImpl;
131 import org.apache.syncope.core.rest.cxf.service.TaskServiceImpl;
132 import org.apache.syncope.core.rest.cxf.service.UserSelfServiceImpl;
133 import org.apache.syncope.core.rest.cxf.service.UserServiceImpl;
134 import org.slf4j.Logger;
135 import org.slf4j.LoggerFactory;
136 import org.springframework.beans.factory.annotation.Qualifier;
137 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
138 import org.springframework.boot.context.properties.EnableConfigurationProperties;
139 import org.springframework.context.annotation.Bean;
140 import org.springframework.context.annotation.Configuration;
141 import org.springframework.context.annotation.PropertySource;
142 import org.springframework.core.env.Environment;
143 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
144
145 @PropertySource("classpath:errorMessages.properties")
146 @EnableConfigurationProperties(RESTProperties.class)
147 @Configuration(proxyBeanMethods = false)
148 public class IdRepoRESTCXFContext {
149
150 private static final Logger LOG = LoggerFactory.getLogger(IdRepoRESTCXFContext.class);
151
152 @Bean
153 public ThreadPoolTaskExecutor batchExecutor(final RESTProperties props) {
154 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
155 executor.setCorePoolSize(props.getBatchExecutor().getCorePoolSize());
156 executor.setMaxPoolSize(props.getBatchExecutor().getMaxPoolSize());
157 executor.setQueueCapacity(props.getBatchExecutor().getQueueCapacity());
158 executor.setAwaitTerminationSeconds(props.getBatchExecutor().getAwaitTerminationSeconds());
159 executor.setWaitForTasksToCompleteOnShutdown(true);
160 executor.setThreadNamePrefix("Batch-");
161 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
162 executor.initialize();
163 return executor;
164 }
165
166 @ConditionalOnMissingBean
167 @Bean
168 public DateParamConverterProvider dateParamConverterProvider() {
169 return new DateParamConverterProvider();
170 }
171
172 @ConditionalOnMissingBean
173 @Bean
174 public JacksonJsonProvider jsonProvider() {
175 return new JacksonJsonProvider(new SyncopeJsonMapper());
176 }
177
178 @ConditionalOnMissingBean
179 @Bean
180 public JacksonXMLProvider xmlProvider() {
181 return new JacksonXMLProvider(new SyncopeXmlMapper());
182 }
183
184 @ConditionalOnMissingBean
185 @Bean
186 public JacksonYAMLProvider yamlProvider() {
187 return new JacksonYAMLProvider(new SyncopeYAMLMapper());
188 }
189
190 @ConditionalOnMissingBean
191 @Bean
192 public MDCInInterceptor mdcInInterceptor() {
193 return new MDCInInterceptor();
194 }
195
196 @ConditionalOnMissingBean
197 @Bean
198 public JAXRSBeanValidationInInterceptor validationInInterceptor(final Validator validator) {
199 JAXRSBeanValidationInInterceptor validationInInterceptor = new JAXRSBeanValidationInInterceptor();
200 validationInInterceptor.setProvider(new BeanValidationProvider(validator));
201 return validationInInterceptor;
202 }
203
204 @ConditionalOnMissingBean
205 @Bean
206 public GZIPInInterceptor gzipInInterceptor() {
207 return new GZIPInInterceptor();
208 }
209
210 @ConditionalOnMissingBean
211 @Bean
212 public GZIPOutInterceptor gzipOutInterceptor() {
213 GZIPOutInterceptor gzipOutInterceptor = new GZIPOutInterceptor();
214 gzipOutInterceptor.setThreshold(0);
215 gzipOutInterceptor.setForce(true);
216 return gzipOutInterceptor;
217 }
218
219 @ConditionalOnMissingBean
220 @Bean
221 public ThreadLocalCleanupOutInterceptor threadLocalCleanupOutInterceptor() {
222 return new ThreadLocalCleanupOutInterceptor();
223 }
224
225 @ConditionalOnMissingBean
226 @Bean
227 public RestServiceExceptionMapper restServiceExceptionMapper(final Environment env) {
228 return new RestServiceExceptionMapper(env);
229 }
230
231 @ConditionalOnMissingBean
232 @Bean
233 public ContextProvider<SearchContext> searchContextProvider() {
234 return new SearchContextProvider();
235 }
236
237 @ConditionalOnMissingBean
238 @Bean
239 public AddDomainFilter addDomainFilter() {
240 return new AddDomainFilter();
241 }
242
243 @ConditionalOnMissingBean
244 @Bean
245 public AddETagFilter addETagFilter() {
246 return new AddETagFilter();
247 }
248
249 @ConditionalOnMissingBean(name = { "openApiCustomizer", "syncopeOpenApiCustomizer" })
250 @Bean
251 public OpenApiCustomizer openApiCustomizer(final DomainHolder domainHolder, final Environment env) {
252 JavaDocProvider javaDocProvider = JavaDocUtils.getJavaDocURLs().
253 map(JavaDocProvider::new).
254 orElseGet(() -> JavaDocUtils.getJavaDocPaths(env).
255 map(javaDocPaths -> {
256 try {
257 return new JavaDocProvider(javaDocPaths);
258 } catch (Exception e) {
259 LOG.error("Could not set javadoc paths from {}", List.of(javaDocPaths), e);
260 return null;
261 }
262 }).
263 orElse(null));
264
265 SyncopeOpenApiCustomizer openApiCustomizer = new SyncopeOpenApiCustomizer(domainHolder);
266 openApiCustomizer.setDynamicBasePath(false);
267 openApiCustomizer.setReplaceTags(false);
268 openApiCustomizer.setJavadocProvider(javaDocProvider);
269 return openApiCustomizer;
270 }
271
272 @ConditionalOnMissingBean
273 @Bean
274 public OpenApiFeature openapiFeature(final OpenApiCustomizer openApiCustomizer, final Environment env) {
275 String version = env.getProperty("version");
276 OpenApiFeature openapiFeature = new OpenApiFeature();
277 openapiFeature.setUseContextBasedConfig(true);
278 openapiFeature.setTitle("Apache Syncope");
279 openapiFeature.setVersion(version);
280 openapiFeature.setDescription("Apache Syncope " + version);
281 openapiFeature.setContactName("The Apache Syncope community");
282 openapiFeature.setContactEmail("dev@syncope.apache.org");
283 openapiFeature.setContactUrl("https://syncope.apache.org");
284 openapiFeature.setScan(false);
285 openapiFeature.setResourcePackages(Set.of("org.apache.syncope.common.rest.api.service"));
286 openapiFeature.setCustomizer(openApiCustomizer);
287 openapiFeature.setSecurityDefinitions(Map.of(
288 "BasicAuthentication", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("basic"),
289 "Bearer", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
290
291 return openapiFeature;
292 }
293
294 @ConditionalOnMissingBean
295 @Bean
296 public Server restContainer(
297 final List<JAXRSService> services,
298 final AddETagFilter addETagFilter,
299 final AddDomainFilter addDomainFilter,
300 final ContextProvider<SearchContext> searchContextProvider,
301 final JacksonYAMLProvider yamlProvider,
302 final JacksonXMLProvider xmlProvider,
303 final JacksonJsonProvider jsonProvider,
304 final DateParamConverterProvider dateParamConverterProvider,
305 final MDCInInterceptor mdcInInterceptor,
306 final JAXRSBeanValidationInInterceptor validationInInterceptor,
307 final GZIPInInterceptor gzipInInterceptor,
308 final GZIPOutInterceptor gzipOutInterceptor,
309 final ThreadLocalCleanupOutInterceptor threadLocalCleanupOutInterceptor,
310 final OpenApiFeature openapiFeature,
311 final RestServiceExceptionMapper restServiceExceptionMapper,
312 final Bus bus) {
313
314 SpringJAXRSServerFactoryBean restContainer = new SpringJAXRSServerFactoryBean();
315 restContainer.setBus(bus);
316 restContainer.setAddress("/");
317 restContainer.setStaticSubresourceResolution(true);
318
319 Map<String, Object> properties = new HashMap<>();
320 properties.put(SearchContextImpl.CUSTOM_SEARCH_PARSER_CLASS_PROPERTY, SyncopeFiqlParser.class.getName());
321 properties.put(SearchUtils.LAX_PROPERTY_MATCH, "true");
322 properties.put("convert.wadl.resources.to.dom", "false");
323 restContainer.setProperties(properties);
324
325 restContainer.setServiceBeans(services.stream().map(Object.class::cast).collect(Collectors.toList()));
326
327 restContainer.setProviders(List.of(
328 dateParamConverterProvider,
329 jsonProvider,
330 xmlProvider,
331 yamlProvider,
332 restServiceExceptionMapper,
333 searchContextProvider,
334 addDomainFilter,
335 addETagFilter));
336
337 restContainer.setInInterceptors(List.of(mdcInInterceptor, validationInInterceptor, gzipInInterceptor));
338
339 restContainer.setOutInterceptors(List.of(gzipOutInterceptor, threadLocalCleanupOutInterceptor));
340
341 restContainer.setFeatures(List.of(openapiFeature));
342
343 return restContainer.create();
344 }
345
346 @ConditionalOnMissingBean
347 @Bean
348 public AccessTokenService accessTokenService(final AccessTokenLogic accessTokenLogic) {
349 return new AccessTokenServiceImpl(accessTokenLogic);
350 }
351
352 @ConditionalOnMissingBean
353 @Bean
354 public AnyObjectService anyObjectService(final AnyObjectDAO anyObjectDAO, final AnyObjectLogic anyObjectLogic,
355 final SearchCondVisitor searchCondVisitor) {
356 return new AnyObjectServiceImpl(searchCondVisitor, anyObjectDAO, anyObjectLogic);
357 }
358
359 @ConditionalOnMissingBean
360 @Bean
361 public AnyTypeClassService anyTypeClassService(final AnyTypeClassLogic anyTypeClassLogic) {
362 return new AnyTypeClassServiceImpl(anyTypeClassLogic);
363 }
364
365 @ConditionalOnMissingBean
366 @Bean
367 public AnyTypeService anyTypeService(final AnyTypeLogic anyTypeLogic) {
368 return new AnyTypeServiceImpl(anyTypeLogic);
369 }
370
371 @ConditionalOnMissingBean
372 @Bean
373 public ApplicationService applicationService(final ApplicationLogic applicationLogic) {
374 return new ApplicationServiceImpl(applicationLogic);
375 }
376
377 @ConditionalOnMissingBean
378 @Bean
379 public AuditService auditService(final AuditLogic auditLogic) {
380 return new AuditServiceImpl(auditLogic);
381 }
382
383 @ConditionalOnMissingBean
384 @Bean
385 public CommandService commandService(final CommandLogic commandLogic) {
386 return new CommandServiceImpl(commandLogic);
387 }
388
389 @ConditionalOnMissingBean
390 @Bean
391 public FIQLQueryService fiqlQueryService(final FIQLQueryLogic fiqlQueryLogic) {
392 return new FIQLQueryServiceImpl(fiqlQueryLogic);
393 }
394
395 @ConditionalOnMissingBean
396 @Bean
397 public DelegationService delegationService(final DelegationLogic delegationLogic) {
398 return new DelegationServiceImpl(delegationLogic);
399 }
400
401 @ConditionalOnMissingBean
402 @Bean
403 public DynRealmService dynRealmService(final DynRealmLogic dynRealmLogic) {
404 return new DynRealmServiceImpl(dynRealmLogic);
405 }
406
407 @ConditionalOnMissingBean
408 @Bean
409 public GroupService groupService(final GroupDAO groupDAO, final GroupLogic groupLogic,
410 final SearchCondVisitor searchCondVisitor) {
411 return new GroupServiceImpl(searchCondVisitor, groupDAO, groupLogic);
412 }
413
414 @ConditionalOnMissingBean
415 @Bean
416 public ImplementationService implementationService(final ImplementationLogic implementationLogic) {
417 return new ImplementationServiceImpl(implementationLogic);
418 }
419
420 @ConditionalOnMissingBean
421 @Bean
422 public MailTemplateService mailTemplateService(final MailTemplateLogic mailTemplateLogic) {
423 return new MailTemplateServiceImpl(mailTemplateLogic);
424 }
425
426 @ConditionalOnMissingBean
427 @Bean
428 public NotificationService notificationService(final NotificationLogic notificationLogic) {
429 return new NotificationServiceImpl(notificationLogic);
430 }
431
432 @ConditionalOnMissingBean
433 @Bean
434 public PolicyService policyService(final PolicyLogic policyLogic) {
435 return new PolicyServiceImpl(policyLogic);
436 }
437
438 @ConditionalOnMissingBean
439 @Bean
440 public RealmService realmService(final RealmLogic realmLogic) {
441 return new RealmServiceImpl(realmLogic);
442 }
443
444 @ConditionalOnMissingBean
445 @Bean
446 public RelationshipTypeService relationshipTypeService(final RelationshipTypeLogic relationshipTypeLogic) {
447 return new RelationshipTypeServiceImpl(relationshipTypeLogic);
448 }
449
450 @ConditionalOnMissingBean
451 @Bean
452 public ReportService reportService(final ReportLogic reportLogic) {
453 return new ReportServiceImpl(reportLogic);
454 }
455
456 @ConditionalOnMissingBean
457 @Bean
458 public RoleService roleService(final RoleLogic roleLogic) {
459 return new RoleServiceImpl(roleLogic);
460 }
461
462 @ConditionalOnMissingBean
463 @Bean
464 public SchemaService schemaService(final SchemaLogic schemaLogic) {
465 return new SchemaServiceImpl(schemaLogic);
466 }
467
468 @ConditionalOnMissingBean
469 @Bean
470 public SecurityQuestionService securityQuestionService(final SecurityQuestionLogic securityQuestionLogic) {
471 return new SecurityQuestionServiceImpl(securityQuestionLogic);
472 }
473
474 @ConditionalOnMissingBean
475 @Bean
476 public SyncopeService syncopeService(
477 final Bus bus,
478 final SyncopeLogic syncopeLogic,
479 @Qualifier("batchExecutor")
480 final ThreadPoolTaskExecutor batchExecutor,
481 final BatchDAO batchDAO,
482 final EntityFactory entityFactory) {
483
484 return new SyncopeServiceImpl(syncopeLogic, batchExecutor, bus, batchDAO, entityFactory);
485 }
486
487 @ConditionalOnMissingBean
488 @Bean
489 public TaskService taskService(final TaskLogic taskLogic) {
490 return new TaskServiceImpl(taskLogic);
491 }
492
493 @ConditionalOnMissingBean
494 @Bean
495 public UserSelfService userSelfService(final UserLogic userLogic, final SyncopeLogic syncopeLogic) {
496 return new UserSelfServiceImpl(userLogic, syncopeLogic);
497 }
498
499 @ConditionalOnMissingBean
500 @Bean
501 public UserService userService(
502 final UserDAO userDAO,
503 final UserLogic userLogic,
504 final SearchCondVisitor searchCondVisitor) {
505
506 return new UserServiceImpl(searchCondVisitor, userDAO, userLogic);
507 }
508 }