1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.userdirectory.sakai;
23
24 import org.opencastproject.security.api.Organization;
25 import org.opencastproject.security.api.OrganizationDirectoryService;
26 import org.opencastproject.security.api.RoleProvider;
27 import org.opencastproject.security.api.UserProvider;
28 import org.opencastproject.util.NotFoundException;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.osgi.framework.BundleContext;
32 import org.osgi.framework.ServiceRegistration;
33 import org.osgi.service.cm.ConfigurationException;
34 import org.osgi.service.cm.ManagedServiceFactory;
35 import org.osgi.service.component.ComponentContext;
36 import org.osgi.service.component.annotations.Activate;
37 import org.osgi.service.component.annotations.Component;
38 import org.osgi.service.component.annotations.Reference;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import java.lang.management.ManagementFactory;
43 import java.util.Arrays;
44 import java.util.Dictionary;
45 import java.util.HashSet;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.concurrent.ConcurrentHashMap;
49
50 import javax.management.MalformedObjectNameException;
51 import javax.management.ObjectName;
52
53
54
55
56 @Component(
57 immediate = true,
58 service = ManagedServiceFactory.class,
59 property = {
60 "service.pid=org.opencastproject.userdirectory.sakai",
61 "service.description=Provides Sakai user directory instances"
62 }
63 )
64 public class SakaiUserProviderFactory implements ManagedServiceFactory {
65
66
67 protected static final Logger logger = LoggerFactory.getLogger(SakaiUserProviderFactory.class);
68
69
70 public static final String PID = "org.opencastproject.userdirectory.sakai";
71
72
73 private static final String ORGANIZATION_KEY = "org.opencastproject.userdirectory.sakai.org";
74
75
76 private static final String SAKAI_SEARCH_USER = "org.opencastproject.userdirectory.sakai.user";
77
78
79 private static final String SEARCH_PASSWORD = "org.opencastproject.userdirectory.sakai.password";
80
81
82 private static final String SITE_PATTERN_KEY = "org.opencastproject.userdirectory.sakai.site.pattern";
83
84
85 private static final String USER_PATTERN_KEY = "org.opencastproject.userdirectory.sakai.user.pattern";
86
87
88 private static final String CACHE_SIZE = "org.opencastproject.userdirectory.sakai.cache.size";
89
90
91 private static final String SAKAI_URL_KEY = "org.opencastproject.userdirectory.sakai.url";
92
93
94 private static final String SAKAI_INSTRUCTOR_ROLES_KEY = "org.opencastproject.userdirectory.sakai.instructor.roles";
95
96
97 private static final String CACHE_EXPIRATION = "org.opencastproject.userdirectory.sakai.cache.expiration";
98
99
100 private Map<String, ServiceRegistration> providerRegistrations = new ConcurrentHashMap<String, ServiceRegistration>();
101
102
103 protected BundleContext bundleContext = null;
104
105
106 private OrganizationDirectoryService orgDirectory;
107
108
109 @Reference
110 public void setOrgDirectory(OrganizationDirectoryService orgDirectory) {
111 this.orgDirectory = orgDirectory;
112 }
113
114
115
116
117
118
119
120 @Activate
121 public void activate(ComponentContext cc) {
122 logger.debug("Activate SakaiUserProviderFactory");
123 this.bundleContext = cc.getBundleContext();
124 }
125
126
127
128
129
130
131 @Override
132 public String getName() {
133 return PID;
134 }
135
136
137
138
139
140
141 @Override
142 public void updated(String pid, Dictionary properties) throws ConfigurationException {
143
144 logger.debug("updated SakaiUserProviderFactory");
145
146 String organization = (String) properties.get(ORGANIZATION_KEY);
147 if (StringUtils.isBlank(organization)) {
148 throw new ConfigurationException(ORGANIZATION_KEY, "is not set");
149 }
150
151 String url = (String) properties.get(SAKAI_URL_KEY);
152 if (StringUtils.isBlank(url)) {
153 throw new ConfigurationException(SAKAI_URL_KEY, "is not set");
154 }
155
156 String userDn = (String) properties.get(SAKAI_SEARCH_USER);
157 String password = (String) properties.get(SEARCH_PASSWORD);
158
159 String sitePattern = (String) properties.get(SITE_PATTERN_KEY);
160 String userPattern = (String) properties.get(USER_PATTERN_KEY);
161
162 int cacheSize = 1000;
163 try {
164 if (properties.get(CACHE_SIZE) != null) {
165 Integer configuredCacheSize = Integer.parseInt(properties.get(CACHE_SIZE).toString());
166 if (configuredCacheSize != null) {
167 cacheSize = configuredCacheSize.intValue();
168 }
169 }
170 } catch (Exception e) {
171 logger.warn("{} could not be loaded, default value is used: {}", CACHE_SIZE, cacheSize);
172 }
173
174
175 int cacheExpiration = 60;
176 try {
177 if (properties.get(CACHE_EXPIRATION) != null) {
178 Integer configuredCacheExpiration = Integer.parseInt(properties.get(CACHE_EXPIRATION).toString());
179 if (configuredCacheExpiration != null) {
180 cacheExpiration = configuredCacheExpiration.intValue();
181 }
182 }
183 } catch (Exception e) {
184 logger.warn("{} could not be loaded, default value is used: {}", CACHE_EXPIRATION, cacheExpiration);
185 }
186
187
188 Set<String> instructorRoles;
189 String instructorRoleList = (String) properties.get(SAKAI_INSTRUCTOR_ROLES_KEY);
190
191 if (!StringUtils.isEmpty(instructorRoleList)) {
192 String trimmedRoles = StringUtils.trim(instructorRoleList);
193 String[] roles = trimmedRoles.split(",");
194 instructorRoles = new HashSet<String>(Arrays.asList(roles));
195 logger.info("Sakai instructor roles: {}", Arrays.toString(roles));
196 } else {
197
198 instructorRoles = new HashSet<String>();
199 instructorRoles.add("Site owner");
200 instructorRoles.add("Instructor");
201 instructorRoles.add("maintain");
202 }
203
204
205 ServiceRegistration existingRegistration = providerRegistrations.remove(pid);
206 if (existingRegistration != null) {
207 existingRegistration.unregister();
208 }
209
210 Organization org;
211 try {
212 org = orgDirectory.getOrganization(organization);
213 } catch (NotFoundException e) {
214 logger.warn("Organization {} not found!", organization);
215 throw new ConfigurationException(ORGANIZATION_KEY, "not found");
216 }
217
218 logger.debug("creating new SakaiUserProviderInstance for pid=" + pid);
219 SakaiUserProviderInstance provider = new SakaiUserProviderInstance(pid,
220 org, url, userDn, password, sitePattern, userPattern, instructorRoles, cacheSize, cacheExpiration);
221
222 providerRegistrations.put(pid, bundleContext.registerService(UserProvider.class.getName(), provider, null));
223 providerRegistrations.put(pid, bundleContext.registerService(RoleProvider.class.getName(), provider, null));
224
225 }
226
227
228
229
230
231
232 @Override
233 public void deleted(String pid) {
234 logger.debug("delete SakaiUserProviderInstance for pid=" + pid);
235 ServiceRegistration registration = providerRegistrations.remove(pid);
236 if (registration != null) {
237 registration.unregister();
238 try {
239 ManagementFactory.getPlatformMBeanServer().unregisterMBean(SakaiUserProviderFactory.getObjectName(pid));
240 } catch (Exception e) {
241 logger.warn("Unable to unregister mbean for pid='{}': {}", pid, e.getMessage());
242 }
243 }
244 }
245
246
247
248
249
250
251
252
253
254
255 public static final ObjectName getObjectName(String pid) throws MalformedObjectNameException, NullPointerException {
256 return new ObjectName(pid + ":type=SakaiRequests");
257 }
258
259 }