001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/sections/tags/sakai_2-4-1/sections-impl/sakai/impl/src/java/org/sakaiproject/component/section/sakai/SectionAwarenessImpl.java $
003: * $Id: SectionAwarenessImpl.java 18229 2006-11-18 01:12:05Z jholtzman@berkeley.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 The Regents of the University of California and The Regents of the University of Michigan
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.component.section.sakai;
021:
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Collections;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Locale;
029: import java.util.Set;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.sakaiproject.section.api.SectionAwareness;
034: import org.sakaiproject.section.api.coursemanagement.Course;
035: import org.sakaiproject.section.api.coursemanagement.CourseSection;
036: import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord;
037: import org.sakaiproject.section.api.coursemanagement.ParticipationRecord;
038: import org.sakaiproject.section.api.coursemanagement.User;
039: import org.sakaiproject.section.api.facade.Role;
040: import org.sakaiproject.authz.api.AuthzGroup;
041: import org.sakaiproject.authz.api.FunctionManager;
042: import org.sakaiproject.authz.api.Member;
043: import org.sakaiproject.authz.api.SecurityService;
044: import org.sakaiproject.component.section.sakai.facade.SakaiUtil;
045: import org.sakaiproject.coursemanagement.api.CourseManagementService;
046: import org.sakaiproject.coursemanagement.api.SectionCategory;
047: import org.sakaiproject.entity.api.EntityManager;
048: import org.sakaiproject.entity.api.Reference;
049: import org.sakaiproject.exception.IdUnusedException;
050: import org.sakaiproject.site.api.Group;
051: import org.sakaiproject.site.api.Site;
052: import org.sakaiproject.site.api.SiteService;
053: import org.sakaiproject.user.api.UserDirectoryService;
054: import org.sakaiproject.user.api.UserNotDefinedException;
055:
056: /**
057: * A sakai based implementation of the Section Awareness API, using the
058: * grouping capability of the framework as the persistence mechanism.
059: *
060: * @author <a href="mailto:jholtzman@berkeley.edu">Josh Holtzman</a>
061: *
062: */
063: public class SectionAwarenessImpl implements SectionAwareness {
064:
065: private static final Log log = LogFactory
066: .getLog(SectionAwarenessImpl.class);
067:
068: // Sakai services
069: protected SiteService siteService;
070: protected SecurityService securityService;
071: protected EntityManager entityManager;
072: protected FunctionManager functionManager;
073: protected UserDirectoryService userDirectoryService;
074: protected CourseManagementService courseManagementService;
075:
076: /**
077: * Bean initialization (called by spring) registers authorization functions
078: * with the AuthzGroup system.
079: */
080: public void init() {
081: if (log.isInfoEnabled())
082: log.info("init()");
083: functionManager.registerFunction("section.role.student");
084: functionManager.registerFunction("section.role.ta");
085: functionManager.registerFunction("section.role.instructor");
086: }
087:
088: public void destroy() {
089: if (log.isInfoEnabled())
090: log.info("destroy()");
091: }
092:
093: /**
094: * @inheritDoc
095: */
096: public List getSections(final String siteContext) {
097: if (log.isDebugEnabled())
098: log.debug("Getting sections for context " + siteContext);
099: List<CourseSectionImpl> sectionList = new ArrayList<CourseSectionImpl>();
100: Collection sections;
101: try {
102: sections = siteService.getSite(siteContext).getGroups();
103: } catch (IdUnusedException e) {
104: log.error("No site with id = " + siteContext);
105: return sectionList;
106: }
107: for (Iterator iter = sections.iterator(); iter.hasNext();) {
108: Group group = (Group) iter.next();
109: sectionList.add(new CourseSectionImpl(group));
110: }
111: Collections.sort(sectionList);
112: return sectionList;
113: }
114:
115: /**
116: * @inheritDoc
117: */
118: public List getSectionCategories(String siteContext) {
119: List<String> catCodes = new ArrayList<String>();
120: for (Iterator iter = courseManagementService
121: .getSectionCategories().iterator(); iter.hasNext();) {
122: SectionCategory cat = (SectionCategory) iter.next();
123: catCodes.add(cat.getCategoryCode());
124: }
125: return catCodes;
126: }
127:
128: /**
129: * @inheritDoc
130: */
131: public CourseSection getSection(final String sectionUuid) {
132: Group group;
133: group = siteService.findGroup(sectionUuid);
134: if (group == null) {
135: log.error("Unable to find section " + sectionUuid);
136: return null;
137: }
138: return new CourseSectionImpl(group);
139: }
140:
141: /**
142: * @inheritDoc
143: */
144: public List getSiteMembersInRole(final String siteContext,
145: final Role role) {
146: if (role.isInstructor()) {
147: return getSiteInstructors(siteContext);
148: } else if (role.isTeachingAssistant()) {
149: return getSiteTeachingAssistants(siteContext);
150: } else if (role.isStudent()) {
151: return getSiteEnrollments(siteContext);
152: } else {
153: log.error("Can not get site members in role " + role);
154: return new ArrayList();
155: }
156: }
157:
158: private List getSiteInstructors(String siteContext) {
159: Course course = getCourse(siteContext);
160: if (course == null) {
161: return new ArrayList();
162: }
163: List sakaiMembers = securityService.unlockUsers(
164: SectionAwareness.INSTRUCTOR_MARKER, course.getUuid());
165: List<InstructorRecordImpl> membersList = new ArrayList<InstructorRecordImpl>();
166: for (Iterator iter = sakaiMembers.iterator(); iter.hasNext();) {
167: org.sakaiproject.user.api.User sakaiUser = (org.sakaiproject.user.api.User) iter
168: .next();
169: User user = SakaiUtil.convertUser(sakaiUser);
170: InstructorRecordImpl record = new InstructorRecordImpl(
171: course, user);
172: membersList.add(record);
173: }
174: return membersList;
175: }
176:
177: private List getSiteEnrollments(String siteContext) {
178: Course course = getCourse(siteContext);
179: if (course == null) {
180: log.error("Could not find course site " + siteContext);
181: return new ArrayList();
182: }
183: List sakaiMembers = securityService.unlockUsers(
184: SectionAwareness.STUDENT_MARKER, course.getUuid());
185: if (log.isDebugEnabled())
186: log.debug("Site students size = " + sakaiMembers.size());
187: List<EnrollmentRecordImpl> membersList = new ArrayList<EnrollmentRecordImpl>();
188: for (Iterator iter = sakaiMembers.iterator(); iter.hasNext();) {
189: org.sakaiproject.user.api.User sakaiUser = (org.sakaiproject.user.api.User) iter
190: .next();
191: User user = SakaiUtil.convertUser(sakaiUser);
192: EnrollmentRecordImpl record = new EnrollmentRecordImpl(
193: course, null, user);
194: membersList.add(record);
195: }
196: return membersList;
197: }
198:
199: private List getSiteTeachingAssistants(String siteContext) {
200: Course course = getCourse(siteContext);
201: if (course == null) {
202: return new ArrayList();
203: }
204: List sakaiMembers = securityService.unlockUsers(
205: SectionAwareness.TA_MARKER, course.getUuid());
206: if (log.isDebugEnabled())
207: log.debug("Site TAs size = " + sakaiMembers.size());
208:
209: List<TeachingAssistantRecordImpl> membersList = new ArrayList<TeachingAssistantRecordImpl>();
210: for (Iterator iter = sakaiMembers.iterator(); iter.hasNext();) {
211: org.sakaiproject.user.api.User sakaiUser = (org.sakaiproject.user.api.User) iter
212: .next();
213: User user = SakaiUtil.convertUser(sakaiUser);
214: TeachingAssistantRecordImpl record = new TeachingAssistantRecordImpl(
215: course, user);
216: membersList.add(record);
217: }
218: return membersList;
219: }
220:
221: private Course getCourse(final String siteContext) {
222: if (log.isDebugEnabled())
223: log.debug("Getting course for context " + siteContext);
224: Site site;
225: try {
226: site = siteService.getSite(siteContext);
227: } catch (IdUnusedException e) {
228: log.error("Could not find site with id = " + siteContext);
229: return null;
230: }
231: return new CourseImpl(site);
232: }
233:
234: /**
235: * @inheritDoc
236: */
237: public List findSiteMembersInRole(final String siteContext,
238: final Role role, final String pattern) {
239: List fullList = getSiteMembersInRole(siteContext, role);
240: List<ParticipationRecord> filteredList = new ArrayList<ParticipationRecord>();
241: for (Iterator iter = fullList.iterator(); iter.hasNext();) {
242: ParticipationRecord record = (ParticipationRecord) iter
243: .next();
244: User user = record.getUser();
245: if (user.getDisplayName().toLowerCase().startsWith(
246: pattern.toLowerCase())
247: || user.getSortName().toLowerCase().startsWith(
248: pattern.toLowerCase())
249: || user.getDisplayId().toLowerCase().startsWith(
250: pattern.toLowerCase())) {
251: filteredList.add(record);
252: }
253: }
254: return filteredList;
255: }
256:
257: /**
258: * @inheritDoc
259: */
260: public boolean isSiteMemberInRole(String siteContext,
261: String userUid, Role role) {
262: String authzRef = getSiteReference(siteContext);
263: return isUserInRole(userUid, role, authzRef);
264: }
265:
266: /**
267: * Checks whether a user is in a role in any learningContext (site or section)
268: *
269: * @param userUid
270: * @param role
271: * @param authzRef
272: * @return
273: */
274: private boolean isUserInRole(String userUid, Role role,
275: String authzRef) {
276: org.sakaiproject.user.api.User user;
277: try {
278: user = userDirectoryService.getUser(userUid);
279: } catch (UserNotDefinedException ide) {
280: log.error("Could not find user with id " + userUid);
281: return false;
282: }
283: if (role.isNone()) {
284: // Make sure that the user is in fact NOT in any role with a role marker
285: if (securityService.unlock(user,
286: SectionAwareness.INSTRUCTOR_MARKER, authzRef)
287: || securityService.unlock(user,
288: SectionAwareness.STUDENT_MARKER, authzRef)
289: || securityService.unlock(user,
290: SectionAwareness.TA_MARKER, authzRef)) {
291: return false;
292: } else {
293: return true;
294: }
295: }
296: return securityService.unlock(user, getLock(role), authzRef);
297: }
298:
299: private String getSiteReference(String siteContext) {
300: final Reference ref = entityManager.newReference(siteService
301: .siteReference(siteContext));
302: return ref.getReference();
303: }
304:
305: /**
306: * @inheritDoc
307: */
308: public List getSectionMembers(final String sectionUuid) {
309: Group group = siteService.findGroup(sectionUuid);
310: CourseSection section = new CourseSectionImpl(group);
311: Set taRoles = getSectionTaRoles(group);
312: Set studentRoles = getSectionStudentRoles(group);
313: Set members = group.getMembers();
314:
315: List<ParticipationRecord> sectionMembershipRecords = new ArrayList<ParticipationRecord>();
316: for (Iterator iter = members.iterator(); iter.hasNext();) {
317: Member member = (Member) iter.next();
318: String roleString = member.getRole().getId();
319: User user = SakaiUtil.getUserFromSakai(member.getUserId());
320: ParticipationRecord record = null;
321: if (taRoles.contains(roleString)) {
322: record = new TeachingAssistantRecordImpl(section, user);
323: } else if (studentRoles.contains(roleString)) {
324: record = new EnrollmentRecordImpl(section, null, user);
325: }
326: if (record != null) {
327: sectionMembershipRecords.add(record);
328: }
329: }
330: return sectionMembershipRecords;
331: }
332:
333: /**
334: * Gets the group-scoped role to use when adding a student to a group.
335: *
336: * @param group The authzGroup
337: * @return The role id, or null if there is not role with the student marker.
338: */
339: private Set getSectionStudentRoles(AuthzGroup group) {
340: return group.getRolesIsAllowed(SectionAwareness.STUDENT_MARKER);
341: }
342:
343: /**
344: * Gets the group-scoped role to use when adding a TA to a group.
345: *
346: * @param group The authzGroup
347: * @return The role id, or null if there is not role with the TA marker.
348: */
349: private Set getSectionTaRoles(Group group) {
350: return group.getRolesIsAllowed(SectionAwareness.TA_MARKER);
351: }
352:
353: /**
354: * @inheritDoc
355: */
356: public List getSectionMembersInRole(final String sectionUuid,
357: final Role role) {
358: if (role.isTeachingAssistant()) {
359: return getSectionTeachingAssistants(sectionUuid);
360: } else if (role.isStudent()) {
361: return getSectionEnrollments(sectionUuid);
362: } else {
363: log.error("Can't get section members in role " + role);
364: return new ArrayList();
365: }
366: }
367:
368: private List getSectionEnrollments(String sectionUuid) {
369: Group group = siteService.findGroup(sectionUuid);
370: CourseSection section = getSection(sectionUuid);
371: if (section == null) {
372: return new ArrayList();
373: }
374: if (log.isDebugEnabled())
375: log.debug("Getting section enrollments in " + sectionUuid);
376: Set studentRoles = getSectionStudentRoles(group);
377: if (studentRoles == null || studentRoles.isEmpty()) {
378: return new ArrayList();
379: }
380: Set<String> sakaiUserUids = new HashSet<String>();
381: for (Iterator iter = studentRoles.iterator(); iter.hasNext();) {
382: String role = (String) iter.next();
383: sakaiUserUids.addAll(group.getUsersHasRole(role));
384: }
385: List sakaiUsers = userDirectoryService.getUsers(sakaiUserUids);
386:
387: List<EnrollmentRecord> membersList = new ArrayList<EnrollmentRecord>();
388: for (Iterator iter = sakaiUsers.iterator(); iter.hasNext();) {
389: User user = SakaiUtil
390: .convertUser((org.sakaiproject.user.api.User) iter
391: .next());
392: EnrollmentRecordImpl record = new EnrollmentRecordImpl(
393: section, null, user);
394: membersList.add(record);
395: }
396: return membersList;
397: }
398:
399: private List getSectionTeachingAssistants(String sectionUuid) {
400: Group group = siteService.findGroup(sectionUuid);
401: CourseSection section = getSection(sectionUuid);
402: if (section == null) {
403: return new ArrayList();
404: }
405: if (log.isDebugEnabled())
406: log.debug("Getting section enrollments in " + sectionUuid);
407: Set taRoles = getSectionTaRoles(group);
408: if (taRoles == null || taRoles.isEmpty()) {
409: if (log.isDebugEnabled())
410: log
411: .debug("There is no role for TAs in this site... returning an empty list");
412: return new ArrayList();
413: }
414: Set sakaiUserUids = new HashSet();
415: for (Iterator iter = taRoles.iterator(); iter.hasNext();) {
416: String role = (String) iter.next();
417: sakaiUserUids.addAll(group.getUsersHasRole(role));
418: }
419: List sakaiUsers = userDirectoryService.getUsers(sakaiUserUids);
420:
421: List<TeachingAssistantRecordImpl> membersList = new ArrayList<TeachingAssistantRecordImpl>();
422: for (Iterator iter = sakaiUsers.iterator(); iter.hasNext();) {
423: User user = SakaiUtil
424: .convertUser((org.sakaiproject.user.api.User) iter
425: .next());
426: TeachingAssistantRecordImpl record = new TeachingAssistantRecordImpl(
427: section, user);
428: membersList.add(record);
429: }
430: return membersList;
431: }
432:
433: //////////////////////////////////////////////////
434:
435: /**
436: * @inheritDoc
437: */
438: public boolean isSectionMemberInRole(final String sectionUuid,
439: final String userUid, final Role role) {
440: return isUserInRole(userUid, role, sectionUuid);
441: }
442:
443: /**
444: * @inheritDoc
445: */
446: public String getSectionName(final String sectionUuid) {
447: CourseSection section = getSection(sectionUuid);
448: return section.getTitle();
449: }
450:
451: /**
452: * @inheritDoc
453: */
454: public String getSectionCategory(final String sectionUuid) {
455: CourseSection section = getSection(sectionUuid);
456: return section.getCategory();
457: }
458:
459: /**
460: * @inheritDoc
461: */
462: public List getSectionsInCategory(final String siteContext,
463: final String categoryId) {
464: if (log.isDebugEnabled())
465: log.debug("Getting " + categoryId
466: + " sections for context " + siteContext);
467: List<CourseSection> sectionList = new ArrayList<CourseSection>();
468: Collection groups;
469: try {
470: groups = siteService.getSite(siteContext).getGroups();
471: } catch (IdUnusedException e) {
472: log.error("No site with id = " + siteContext);
473: return new ArrayList();
474: }
475: for (Iterator iter = groups.iterator(); iter.hasNext();) {
476: Group group = (Group) iter.next();
477: if (categoryId.equals(group.getProperties().getProperty(
478: CourseSectionImpl.CATEGORY))) {
479: sectionList.add(new CourseSectionImpl(group));
480: }
481: }
482: return sectionList;
483: }
484:
485: /**
486: * @inheritDoc
487: */
488: public String getCategoryName(String categoryId, Locale locale) {
489: String description = courseManagementService
490: .getSectionCategoryDescription(categoryId);
491: if (description == null) {
492: return categoryId;
493: }
494: return description;
495: }
496:
497: /**
498: * @inheritDoc
499: */
500: public List getUnassignedMembersInRole(final String siteContext,
501: final Role role) {
502: List siteMembers = getSiteMembersInRole(siteContext, role);
503:
504: // Get all userUids of all users in sections
505: List<String> sectionedUserUids = new ArrayList<String>();
506: List sections = getSections(siteContext);
507: for (Iterator sectionIter = sections.iterator(); sectionIter
508: .hasNext();) {
509: CourseSection section = (CourseSection) sectionIter.next();
510: List sectionUsers = securityService.unlockUsers(
511: getLock(role), section.getUuid());
512: for (Iterator userIter = sectionUsers.iterator(); userIter
513: .hasNext();) {
514: org.sakaiproject.user.api.User user = (org.sakaiproject.user.api.User) userIter
515: .next();
516: sectionedUserUids.add(user.getId());
517: }
518: }
519:
520: // Now generate the list of unsectioned enrollments by subtracting the two collections
521: // Since the APIs return different kinds of objects, we need to iterate
522: List<ParticipationRecord> unsectionedMembers = new ArrayList<ParticipationRecord>();
523: for (Iterator iter = siteMembers.iterator(); iter.hasNext();) {
524: ParticipationRecord record = (ParticipationRecord) iter
525: .next();
526: if (!sectionedUserUids.contains(record.getUser()
527: .getUserUid())) {
528: unsectionedMembers.add(record);
529: }
530: }
531: return unsectionedMembers;
532: }
533:
534: private String getLock(Role role) {
535: if (role.isInstructor()) {
536: return SectionAwareness.INSTRUCTOR_MARKER;
537: } else if (role.isTeachingAssistant()) {
538: return SectionAwareness.TA_MARKER;
539: } else if (role.isStudent()) {
540: return SectionAwareness.STUDENT_MARKER;
541: } else {
542: return null;
543: }
544: }
545:
546: // Dependency injection
547:
548: public void setSiteService(SiteService siteService) {
549: this .siteService = siteService;
550: }
551:
552: public void setFunctionManager(FunctionManager functionManager) {
553: this .functionManager = functionManager;
554: }
555:
556: public void setEntityManager(EntityManager entityManager) {
557: this .entityManager = entityManager;
558: }
559:
560: public void setSecurityService(SecurityService securityService) {
561: this .securityService = securityService;
562: }
563:
564: public void setUserDirectoryService(
565: UserDirectoryService userDirectoryService) {
566: this .userDirectoryService = userDirectoryService;
567: }
568:
569: public void setCourseManagementService(
570: CourseManagementService courseManagementService) {
571: this.courseManagementService = courseManagementService;
572: }
573:
574: }
|