1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.logic.init;
20
21 import java.lang.reflect.Modifier;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Objects;
28 import java.util.Set;
29 import java.util.stream.Collectors;
30 import org.apache.syncope.common.lib.policy.AccountRuleConf;
31 import org.apache.syncope.common.lib.policy.PasswordRuleConf;
32 import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
33 import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf;
34 import org.apache.syncope.common.lib.report.ReportConf;
35 import org.apache.syncope.common.lib.types.IdMImplementationType;
36 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
37 import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
38 import org.apache.syncope.core.logic.api.Command;
39 import org.apache.syncope.core.logic.api.LogicActions;
40 import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValueValidator;
41 import org.apache.syncope.core.provisioning.api.ImplementationLookup;
42 import org.apache.syncope.core.provisioning.api.ProvisionSorter;
43 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
44 import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
45 import org.apache.syncope.core.provisioning.api.job.report.ReportConfClass;
46 import org.apache.syncope.core.provisioning.api.job.report.ReportJobDelegate;
47 import org.apache.syncope.core.provisioning.api.notification.RecipientsProvider;
48 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
49 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
50 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
51 import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
52 import org.apache.syncope.core.provisioning.api.rules.AccountRule;
53 import org.apache.syncope.core.provisioning.api.rules.AccountRuleConfClass;
54 import org.apache.syncope.core.provisioning.api.rules.PasswordRule;
55 import org.apache.syncope.core.provisioning.api.rules.PasswordRuleConfClass;
56 import org.apache.syncope.core.provisioning.api.rules.PullCorrelationRule;
57 import org.apache.syncope.core.provisioning.api.rules.PullCorrelationRuleConfClass;
58 import org.apache.syncope.core.provisioning.api.rules.PushCorrelationRule;
59 import org.apache.syncope.core.provisioning.api.rules.PushCorrelationRuleConfClass;
60 import org.apache.syncope.core.provisioning.java.data.JEXLItemTransformerImpl;
61 import org.apache.syncope.core.provisioning.java.job.GroupMemberProvisionTaskJobDelegate;
62 import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
63 import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.springframework.beans.factory.config.BeanDefinition;
67 import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
68 import org.springframework.core.Ordered;
69 import org.springframework.core.type.filter.AssignableTypeFilter;
70 import org.springframework.util.ClassUtils;
71
72
73
74
75 public class ClassPathScanImplementationLookup implements ImplementationLookup {
76
77 private static final Logger LOG = LoggerFactory.getLogger(ImplementationLookup.class);
78
79 private static final String DEFAULT_BASE_PACKAGE = "org.apache.syncope.core";
80
81 private Map<String, Set<String>> classNames;
82
83 private Map<Class<? extends ReportConf>, Class<? extends ReportJobDelegate>> reportJobDelegateClasses;
84
85 private Map<Class<? extends AccountRuleConf>, Class<? extends AccountRule>> accountRuleClasses;
86
87 private Map<Class<? extends PasswordRuleConf>, Class<? extends PasswordRule>> passwordRuleClasses;
88
89 private Map<Class<? extends PullCorrelationRuleConf>, Class<? extends PullCorrelationRule>> pullCRClasses;
90
91 private Map<Class<? extends PushCorrelationRuleConf>, Class<? extends PushCorrelationRule>> pushCRClasses;
92
93 @Override
94 public int getOrder() {
95 return Ordered.HIGHEST_PRECEDENCE + 1;
96 }
97
98
99
100
101
102
103 protected static String getBasePackage() {
104 return DEFAULT_BASE_PACKAGE;
105 }
106
107 @SuppressWarnings("unchecked")
108 @Override
109 public void load() {
110 classNames = new HashMap<>();
111 ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
112 ImplementationTypesHolder.getInstance().getValues().forEach((typeName, typeInterface) -> {
113 classNames.put(typeName, new HashSet<>());
114 try {
115 scanner.addIncludeFilter(new AssignableTypeFilter(
116 ClassUtils.resolveClassName(typeInterface, ClassUtils.getDefaultClassLoader())));
117 } catch (IllegalArgumentException e) {
118 LOG.error("Could not find class, ignoring...", e);
119 }
120 });
121
122 Map<String, String> extImplTypes = ImplementationTypesHolder.getInstance().getValues().entrySet().stream().
123 filter(e -> !IdRepoImplementationType.values().containsKey(e.getKey())
124 && !IdMImplementationType.values().containsKey(e.getKey())).
125 collect(Collectors.toMap(Entry::getKey, Entry::getValue));
126
127 reportJobDelegateClasses = new HashMap<>();
128 accountRuleClasses = new HashMap<>();
129 passwordRuleClasses = new HashMap<>();
130 pullCRClasses = new HashMap<>();
131 pushCRClasses = new HashMap<>();
132
133 for (BeanDefinition bd : scanner.findCandidateComponents(getBasePackage())) {
134 try {
135 Class<?> clazz = ClassUtils.resolveClassName(
136 Objects.requireNonNull(bd.getBeanClassName()), ClassUtils.getDefaultClassLoader());
137 if (Modifier.isAbstract(clazz.getModifiers())) {
138 continue;
139 }
140
141 if (ReportJobDelegate.class.isAssignableFrom(clazz)) {
142 ReportConfClass annotation = clazz.getAnnotation(ReportConfClass.class);
143 if (annotation == null) {
144 LOG.warn("Found Report {} without declared configuration", clazz.getName());
145 } else {
146 classNames.get(IdRepoImplementationType.REPORT_DELEGATE).add(clazz.getName());
147 reportJobDelegateClasses.put(annotation.value(), (Class<? extends ReportJobDelegate>) clazz);
148 }
149 } else if (AccountRule.class.isAssignableFrom(clazz)) {
150 AccountRuleConfClass annotation = clazz.getAnnotation(AccountRuleConfClass.class);
151 if (annotation == null) {
152 LOG.warn("Found account policy rule {} without declared configuration", clazz.getName());
153 } else {
154 classNames.get(IdRepoImplementationType.ACCOUNT_RULE).add(clazz.getName());
155 accountRuleClasses.put(annotation.value(), (Class<? extends AccountRule>) clazz);
156 }
157 } else if (PasswordRule.class.isAssignableFrom(clazz)) {
158 PasswordRuleConfClass annotation = clazz.getAnnotation(PasswordRuleConfClass.class);
159 if (annotation == null) {
160 LOG.warn("Found password policy rule {} without declared configuration", clazz.getName());
161 } else {
162 classNames.get(IdRepoImplementationType.PASSWORD_RULE).add(clazz.getName());
163 passwordRuleClasses.put(annotation.value(), (Class<? extends PasswordRule>) clazz);
164 }
165 } else if (PullCorrelationRule.class.isAssignableFrom(clazz)) {
166 PullCorrelationRuleConfClass annotation = clazz.getAnnotation(PullCorrelationRuleConfClass.class);
167 if (annotation == null) {
168 LOG.warn("Found pull correlation rule {} without declared configuration", clazz.getName());
169 } else {
170 classNames.get(IdMImplementationType.PULL_CORRELATION_RULE).add(clazz.getName());
171 pullCRClasses.put(annotation.value(), (Class<? extends PullCorrelationRule>) clazz);
172 }
173 } else if (PushCorrelationRule.class.isAssignableFrom(clazz)) {
174 PushCorrelationRuleConfClass annotation = clazz.getAnnotation(PushCorrelationRuleConfClass.class);
175 if (annotation == null) {
176 LOG.warn("Found push correlation rule {} without declared configuration", clazz.getName());
177 } else {
178 classNames.get(IdMImplementationType.PUSH_CORRELATION_RULE).add(clazz.getName());
179 pushCRClasses.put(annotation.value(), (Class<? extends PushCorrelationRule>) clazz);
180 }
181 } else if (ItemTransformer.class.isAssignableFrom(clazz)
182 && !clazz.equals(JEXLItemTransformerImpl.class)) {
183
184 classNames.get(IdRepoImplementationType.ITEM_TRANSFORMER).add(clazz.getName());
185 } else if (SchedTaskJobDelegate.class.isAssignableFrom(clazz)
186 && !PullJobDelegate.class.isAssignableFrom(clazz)
187 && !PushJobDelegate.class.isAssignableFrom(clazz)
188 && !GroupMemberProvisionTaskJobDelegate.class.isAssignableFrom(clazz)) {
189
190 classNames.get(IdRepoImplementationType.TASKJOB_DELEGATE).add(bd.getBeanClassName());
191 } else if (ReconFilterBuilder.class.isAssignableFrom(clazz)) {
192 classNames.get(IdMImplementationType.RECON_FILTER_BUILDER).add(bd.getBeanClassName());
193 } else if (LogicActions.class.isAssignableFrom(clazz)) {
194 classNames.get(IdRepoImplementationType.LOGIC_ACTIONS).add(bd.getBeanClassName());
195 } else if (PropagationActions.class.isAssignableFrom(clazz)) {
196 classNames.get(IdMImplementationType.PROPAGATION_ACTIONS).add(bd.getBeanClassName());
197 } else if (PullActions.class.isAssignableFrom(clazz)) {
198 classNames.get(IdMImplementationType.PULL_ACTIONS).add(bd.getBeanClassName());
199 } else if (PushActions.class.isAssignableFrom(clazz)) {
200 classNames.get(IdMImplementationType.PUSH_ACTIONS).add(bd.getBeanClassName());
201 } else if (PlainAttrValueValidator.class.isAssignableFrom(clazz)) {
202 classNames.get(IdRepoImplementationType.VALIDATOR).add(bd.getBeanClassName());
203 } else if (RecipientsProvider.class.isAssignableFrom(clazz)) {
204 classNames.get(IdRepoImplementationType.RECIPIENTS_PROVIDER).add(bd.getBeanClassName());
205 } else if (ProvisionSorter.class.isAssignableFrom(clazz)) {
206 classNames.get(IdMImplementationType.PROVISION_SORTER).add(bd.getBeanClassName());
207 } else if (Command.class.isAssignableFrom(clazz)) {
208 classNames.get(IdRepoImplementationType.COMMAND).add(bd.getBeanClassName());
209 } else {
210 extImplTypes.forEach((typeName, typeInterface) -> {
211 Class<?> tic = ClassUtils.resolveClassName(typeInterface, ClassUtils.getDefaultClassLoader());
212 if (tic.isAssignableFrom(clazz)) {
213 classNames.get(typeName).add(bd.getBeanClassName());
214 }
215 });
216 }
217 } catch (Throwable t) {
218 LOG.warn("Could not inspect class {}", bd.getBeanClassName(), t);
219 }
220 }
221
222 classNames = Collections.unmodifiableMap(classNames);
223 LOG.debug("Implementation classes found: {}", classNames);
224
225 reportJobDelegateClasses = Collections.unmodifiableMap(reportJobDelegateClasses);
226 accountRuleClasses = Collections.unmodifiableMap(accountRuleClasses);
227 passwordRuleClasses = Collections.unmodifiableMap(passwordRuleClasses);
228 pullCRClasses = Collections.unmodifiableMap(pullCRClasses);
229 pushCRClasses = Collections.unmodifiableMap(pushCRClasses);
230 }
231
232 @Override
233 public Set<String> getClassNames(final String type) {
234 return classNames.get(type);
235 }
236
237 @Override
238 public Class<? extends ReportJobDelegate> getReportClass(final Class<? extends ReportConf> reportConfClass) {
239 return reportJobDelegateClasses.get(reportConfClass);
240 }
241
242 @Override
243 public Class<? extends AccountRule> getAccountRuleClass(
244 final Class<? extends AccountRuleConf> accountRuleConfClass) {
245
246 return accountRuleClasses.get(accountRuleConfClass);
247 }
248
249 @Override
250 public Class<? extends PasswordRule> getPasswordRuleClass(
251 final Class<? extends PasswordRuleConf> passwordRuleConfClass) {
252
253 return passwordRuleClasses.get(passwordRuleConfClass);
254 }
255
256 @Override
257 public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
258 final Class<? extends PullCorrelationRuleConf> correlationRuleConfClass) {
259
260 return pullCRClasses.get(correlationRuleConfClass);
261 }
262
263 @Override
264 public Class<? extends PushCorrelationRule> getPushCorrelationRuleClass(
265 final Class<? extends PushCorrelationRuleConf> correlationRuleConfClass) {
266
267 return pushCRClasses.get(correlationRuleConfClass);
268 }
269 }