1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package edu.internet2.middleware.subject.provider;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.LinkedHashSet;
34 import java.util.Map;
35 import java.util.Set;
36
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.xml.sax.SAXException;
41
42 import edu.internet2.middleware.grouper.cache.GrouperCacheDatabase;
43 import edu.internet2.middleware.grouper.cache.GrouperCacheDatabaseClear;
44 import edu.internet2.middleware.grouper.cache.GrouperCacheDatabaseClearInput;
45 import edu.internet2.middleware.grouper.cfg.GrouperConfig;
46 import edu.internet2.middleware.grouper.cfg.dbConfig.GrouperConfigHibernate;
47 import edu.internet2.middleware.grouper.externalSubjects.ExternalSubjectAutoSourceAdapter;
48 import edu.internet2.middleware.grouperClient.util.ExpirableCache;
49 import edu.internet2.middleware.subject.Source;
50 import edu.internet2.middleware.subject.SourceUnavailableException;
51 import edu.internet2.middleware.subject.Subject;
52 import edu.internet2.middleware.subject.SubjectType;
53 import edu.internet2.middleware.subject.SubjectUtils;
54 import edu.internet2.middleware.subject.config.SubjectConfig;
55
56
57
58
59
60
61
62 public class SourceManager {
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 public static class SourceManagerStatusBean {
83
84
85
86
87
88 public Map<String, SubjectStatusConfig> getSourceIdToStatusConfigs() {
89 return this.sourceIdToStatusConfigs;
90 }
91
92
93
94
95 private Map<String, SubjectStatusConfig> sourceIdToStatusConfigs = new HashMap<String, SubjectStatusConfig>();
96
97
98
99
100 private Set<String> statusLabels = new HashSet<String>();
101
102
103
104
105 private Set<String> statusesFromUser = new HashSet<String>();
106
107
108
109
110 private Set<String> statusAllFromUser = new HashSet<String>();
111
112
113
114
115
116 public Set<String> getStatusLabels() {
117 return this.statusLabels;
118 }
119
120
121
122
123
124 public Set<String> getStatusesFromUser() {
125 return this.statusesFromUser;
126 }
127
128
129
130
131
132 public Set<String> getStatusAllFromUser() {
133 return this.statusAllFromUser;
134 }
135
136
137
138
139 public void processConfigBeans() {
140
141 for (SubjectStatusConfig subjectStatusConfig : this.sourceIdToStatusConfigs.values()) {
142
143 {
144 String statusLabel = subjectStatusConfig.getStatusLabel();
145 if (!StringUtils.isBlank(statusLabel)) {
146 this.statusLabels.add(statusLabel);
147 }
148 }
149
150 {
151 Set<String> statusesFromUser = subjectStatusConfig.getStatusesFromUser();
152 this.statusesFromUser.addAll(statusesFromUser);
153 }
154
155 {
156 String statusAllFromUser = subjectStatusConfig.getStatusAllFromUser();
157 if (!StringUtils.isBlank(statusAllFromUser)) {
158 this.statusAllFromUser.add(statusAllFromUser);
159 }
160 }
161 }
162 }
163 }
164
165 public static void clearAllSources() {
166 manager = null;
167 }
168
169
170
171
172 private static ExpirableCache<Boolean, SourceManagerStatusBean> sourceManagerStatusBeanCache =
173 new ExpirableCache<Boolean, SourceManagerStatusBean>();
174
175
176
177
178
179 public SourceManagerStatusBean getSourceManagerStatusBean() {
180 SourceManagerStatusBean sourceManagerStatusBean = sourceManagerStatusBeanCache.get(true);
181 if (sourceManagerStatusBean == null) {
182 synchronized (sourceManagerStatusBeanCache) {
183 sourceManagerStatusBean = sourceManagerStatusBeanCache.get(true);
184 if (sourceManagerStatusBean == null) {
185
186 sourceManagerStatusBean = new SourceManagerStatusBean();
187
188 for (Source source : getInstance().getSources()) {
189
190 SubjectStatusConfigatusConfig.html#SubjectStatusConfig">SubjectStatusConfig subjectStatusConfig = new SubjectStatusConfig(source);
191 sourceManagerStatusBean.getSourceIdToStatusConfigs().put(source.getId(), subjectStatusConfig);
192
193 }
194
195 sourceManagerStatusBean.processConfigBeans();
196
197 sourceManagerStatusBeanCache.put(Boolean.TRUE, sourceManagerStatusBean);
198
199 }
200 }
201 }
202 return sourceManagerStatusBean;
203 }
204
205
206
207
208
209 public String printConfig() {
210 try {
211 StringBuilder result = new StringBuilder();
212
213 File subjectPropertiesFile = SubjectUtils.fileFromResourceName("subject.properties");
214 String subjectPropertiesFileLocation = subjectPropertiesFile == null ? " [cant find subject.properties]"
215 : SubjectUtils.fileCanonicalPath(subjectPropertiesFile);
216 result.append("subject.properties read from: " + subjectPropertiesFileLocation + "\n");
217
218 result.append("sources configured in: subject.properties\n");
219 File sourcesXmlFile = SubjectUtils.fileFromResourceName("sources.xml");
220 if (sourcesXmlFile != null && sourcesXmlFile.exists() && sourcesXmlFile.isFile()) {
221 String sourcesError = "NON-FATAL ERROR: subject sources are read from subject.properties but you "
222 + "still have a sources.xml on the classpath which is confusing, please backup and remove this file: " + sourcesXmlFile.getAbsolutePath();
223 result.append(sourcesError + "\n");
224 log.error(sourcesError);
225 }
226
227
228 Collection<Source> sources = SourceManager.getInstance().getSources();
229 for (Source source : sources) {
230 result.append(source.printConfig()).append("\n");
231 }
232
233 if (result.toString().endsWith("\n")) {
234 result.deleteCharAt(result.length() - 1);
235 }
236 return result.toString();
237 } catch (Exception e) {
238 log.error("Cant print subject API configs", e);
239 }
240 return "Cant print subject API configs";
241
242 }
243
244
245 private static Log log = edu.internet2.middleware.grouper.util.GrouperUtil.getLog(SourceManager.class);
246
247
248 private static SourceManager manager;
249
250
251 private Map<SubjectType, Set<Source>> source2TypeMap = new HashMap<SubjectType, Set<Source>>();
252
253
254 Map<String, Source> sourceMap = new HashMap<String, Source>();
255
256 private static Set<String> registeredDatabaseCacheNames = Collections.synchronizedSet(new HashSet<String>());
257
258 private static boolean grouperCacheClearDatabaseInitted;
259
260
261
262 private SourceManager() {
263 init();
264
265 if (!grouperCacheClearDatabaseInitted) {
266 String cacheName = "edu.internet2.middleware.subject.provider.SourceManager.reloadSource";
267 GrouperCacheDatabase.customRegisterDatabaseClearable(cacheName, new GrouperCacheDatabaseClear() {
268
269 @Override
270 public void clear(GrouperCacheDatabaseClearInput grouperCacheDatabaseClearInput) {
271 String cacheName = grouperCacheDatabaseClearInput.getCacheName();
272 String sourceId = StringUtils.substringAfterLast(cacheName, "____");
273 GrouperConfigHibernate.clearConfigsInMemory();
274 SourceManager.getInstance().reloadSource(sourceId);
275 }
276 });
277 grouperCacheClearDatabaseInitted = true;
278 }
279
280
281 }
282
283
284
285
286
287
288 public static SourceManager getInstance() {
289 if (manager == null) {
290 synchronized(SourceManager.class) {
291 if (manager == null) {
292 manager = new SourceManager();
293 }
294 }
295 }
296 return manager;
297 }
298
299
300
301
302
303
304
305 public Source getSource(String sourceId) throws SourceUnavailableException {
306 Source source = this.sourceMap.get(sourceId);
307 if (source == null) {
308
309 StringBuilder allSources = new StringBuilder();
310 int i=0;
311 for (String theSourceId : this.sourceMap.keySet()) {
312 allSources.append(theSourceId);
313 if (i != this.sourceMap.size() - 1) {
314 allSources.append(", ");
315 }
316 i++;
317 }
318
319 throw new SourceUnavailableException("Source not found: '" + sourceId + "', available sources are: " + allSources);
320 }
321 return source;
322 }
323
324
325
326
327
328 public Collection<Source> getSources() {
329 return new LinkedHashSet<Source>(this.sourceMap.values());
330 }
331
332
333
334
335
336
337
338 public Collection<Source> getSources(SubjectType type) {
339 if (this.source2TypeMap.containsKey(type)) {
340 return this.source2TypeMap.get(type);
341 }
342 return new HashSet<Source>();
343 }
344
345
346
347
348
349 private void init() throws RuntimeException {
350 try {
351 parseConfig();
352
353 if (GrouperConfig.retrieveConfig().propertyValueBoolean("externalSubjects.autoCreateSource", true)) {
354
355 this.loadSource(ExternalSubjectAutoSourceAdapter.instance());
356
357 }
358
359
360 } catch (Exception ex) {
361 log.error("Error initializing SourceManager: " + ex.getMessage(), ex);
362 throw new RuntimeException("Error initializing SourceManager", ex);
363 }
364 }
365
366 public synchronized void reloadSource(String sourceId) {
367 Source source = SubjectConfig.retrieveConfig().reloadSourceConfigs(sourceId);
368 if (source != null) {
369 loadSource(source);
370 } else {
371 sourceMap.remove(sourceId);
372 }
373 }
374
375
376
377
378
379 public void loadSource(Source source) {
380 log.debug("Loading source: " + source.getId());
381
382
383 this.sourceMap.put(source.getId(), source);
384
385 String cacheName = "edu.internet2.middleware.subject.provider.SourceManager.reloadSource____" + source.getId();
386 if (!registeredDatabaseCacheNames.contains(cacheName)) {
387 registeredDatabaseCacheNames.add(cacheName);
388 GrouperCacheDatabase.customRegisterDatabaseClearable(cacheName, new GrouperCacheDatabaseClear() {
389
390 private String sourceId = source.getId();
391
392 @Override
393 public void clear(GrouperCacheDatabaseClearInput grouperCacheDatabaseClearInput) {
394 GrouperConfigHibernate.clearConfigsInMemory();
395 SourceManager.getInstance().reloadSource(sourceId);
396 }
397 });
398 }
399
400 for (Iterator it = source.getSubjectTypes().iterator(); it.hasNext();) {
401 SubjectType../../../../edu/internet2/middleware/subject/SubjectType.html#SubjectType">SubjectType type = (SubjectType) it.next();
402 Set<Source> sources = this.source2TypeMap.get(type);
403 if (sources == null) {
404 sources = new HashSet<Source>();
405 this.source2TypeMap.put(type, sources);
406 }
407 sources.add(source);
408 }
409
410
411 source.init();
412
413 source.getSearchAttributes();
414 source.getSortAttributes();
415 source.getSubjectIdentifierAttributes();
416 source.getSubjectIdentifierAttributesAll();
417 }
418
419
420
421
422
423
424 private void parseConfig() throws IOException, SAXException {
425 for (Source source : SubjectConfig.retrieveConfig().retrieveSourceConfigs().values()) {
426 loadSource(source);
427 }
428 }
429
430
431
432
433
434 public static boolean usingSubjectProperties() {
435 return true;
436 }
437
438
439
440
441
442
443 public static void main(String[] args) {
444
445 try {
446 SourceManager mgr = SourceManager.getInstance();
447 for (Iterator iter = mgr.getSources().iterator(); iter.hasNext();) {
448 BaseSourceAdapter/../edu/internet2/middleware/subject/provider/BaseSourceAdapter.html#BaseSourceAdapter">BaseSourceAdapter source = (BaseSourceAdapter) iter.next();
449 log.debug("Source init params: " + "id = " + source.getId() + ", params = "
450 + source.initParams());
451 source.init();
452 if (source.getId().equals("example")) {
453
454 Subject subject = source.getSubject("70061854", true);
455
456 log.debug("getSubject id: " + subject.getId() + " name: " + subject.getName()
457 + " description:" + subject.getDescription());
458 subject = source.getSubjectByIdentifier("esluss", true);
459 log.debug("getSubjectByIdentifier id: " + subject.getId() + " name: "
460 + subject.getName() + " description:" + subject.getDescription());
461 log.debug("Starting barton search");
462 Set subjectSet = source.search("barton");
463 log.debug("num elements found: " + subjectSet.size());
464 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
465 subject = (Subject) it.next();
466 log.debug("id: " + subject.getId() + " name: " + subject.getName()
467 + " description:" + subject.getDescription());
468 Map attrs = subject.getAttributes();
469 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
470 .debug(it2.next()))
471 ;
472 }
473
474 } else if (source.getId().equals("jdbc")) {
475 Subject subject = source.getSubject("37413", true);
476
477
478 log.debug("getSubject id: " + subject.getId() + " name: " + subject.getName()
479 + " description:" + subject.getDescription());
480 subject = source.getSubjectByIdentifier("abean", true);
481 log.debug("getSubjectByIdentifier id: " + subject.getId() + " name: "
482 + subject.getName() + " description:" + subject.getDescription());
483 log.debug("Starting barton search");
484 Set subjectSet = source.search("smith");
485 log.debug("num elements found: " + subjectSet.size());
486 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
487 subject = (Subject) it.next();
488 log.debug("id: " + subject.getId() + " name: " + subject.getName()
489 + " description:" + subject.getDescription());
490 Map attrs = subject.getAttributes();
491 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
492 .debug(it2.next()))
493 ;
494 }
495 subjectSet = source.search("bean");
496 log.debug("num elements found: " + subjectSet.size());
497 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
498 subject = (Subject) it.next();
499 log.debug("id: " + subject.getId() + " name: " + subject.getName()
500 + " description:" + subject.getDescription());
501 Map attrs = subject.getAttributes();
502 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
503 .debug(it2.next()))
504 ;
505 }
506 subjectSet = source.search("smith");
507 log.debug("num elements found: " + subjectSet.size());
508 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
509 subject = (Subject) it.next();
510 log.debug("id: " + subject.getId() + " name: " + subject.getName()
511 + " description:" + subject.getDescription());
512 Map attrs = subject.getAttributes();
513 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
514 .debug(it2.next()))
515 ;
516 }
517 subjectSet = source.search("bean");
518 log.debug("num elements found: " + subjectSet.size());
519 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
520 subject = (Subject) it.next();
521 log.debug("id: " + subject.getId() + " name: " + subject.getName()
522 + " description:" + subject.getDescription());
523 Map attrs = subject.getAttributes();
524 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
525 .debug(it2.next()))
526 ;
527 }
528 subjectSet = source.search("smith");
529 log.debug("num elements found: " + subjectSet.size());
530 for (Iterator it = subjectSet.iterator(); it.hasNext();) {
531 subject = (Subject) it.next();
532 log.debug("id: " + subject.getId() + " name: " + subject.getName()
533 + " description:" + subject.getDescription());
534 Map attrs = subject.getAttributes();
535 for (Iterator it2 = attrs.keySet().iterator(); it2.hasNext(); log
536 .debug(it2.next()))
537 ;
538 }
539
540 }
541 }
542 } catch (Exception ex) {
543 log.error("Exception occurred: " + ex.getMessage(), ex);
544 }
545 }
546
547
548
549
550
551 public void internal_removeSource(String sourceId) {
552 sourceMap.remove(sourceId);
553 }
554 }