diff --git a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java index 9be4b9be575c16bf1559f9458870e196898ef851..969a1920d50205257c083062dde9f2dc38844ea7 100644 --- a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java +++ b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java @@ -51,8 +51,6 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.generic.closablewrapper.CloseableModalWindowWrapperController; import org.olat.core.id.Identity; import org.olat.core.util.Util; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.SyncerExecutor; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; @@ -297,13 +295,7 @@ public class GroupOverviewController extends BasicController { businessGroupService.removeOwners(ureq.getIdentity(), Collections.singletonList(identity), group); } // 2) remove as participant - final BusinessGroup toRemFromGroup = group; - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor() { - public void execute() { - businessGroupService.removeParticipant(getIdentity(), identity, toRemFromGroup); - } - }); + businessGroupService.removeParticipants(getIdentity(), Collections.singletonList(identity), group); // 3) notify user about this action: if(doSendMail){ diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java index 1c4077e2c963aaee6b2eb0dc5d5bea8bc92335fd..c3475abc9491738c8ec6ff729e976e5bee6c747e 100644 --- a/src/main/java/org/olat/collaboration/CollaborationTools.java +++ b/src/main/java/org/olat/collaboration/CollaborationTools.java @@ -210,10 +210,10 @@ public class CollaborationTools implements Serializable { public final static String KEY_FOLDER_ACCESS = "folder"; //o_clusterOK by guido - Hashtable<String, Boolean> cacheToolStates; - final OLATResourceable ores; + private Hashtable<String, Boolean> cacheToolStates; + private final BusinessGroup ores; - OLog log = Tracing.createLoggerFor(this.getClass()); + private static OLog log = Tracing.createLoggerFor(CollaborationTools.class); private transient CoordinatorManager coordinatorManager; /** @@ -221,7 +221,7 @@ public class CollaborationTools implements Serializable { * * @param ores */ - CollaborationTools(CoordinatorManager coordinatorManager, OLATResourceable ores) { + CollaborationTools(CoordinatorManager coordinatorManager, BusinessGroup ores) { this.coordinatorManager = coordinatorManager; this.ores = ores; cacheToolStates = new Hashtable<String, Boolean>(); diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java b/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java index 65c3e07d679cfc9f937bd35fb9b8a25d4bde4f26..aa359141134f74269b1febd777a13fd329c52537 100644 --- a/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java +++ b/src/main/java/org/olat/collaboration/CollaborationToolsFactory.java @@ -32,6 +32,7 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.cache.n.CacheWrapper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.SyncerCallback; +import org.olat.group.BusinessGroup; /** * Description:<BR> @@ -72,7 +73,7 @@ public class CollaborationToolsFactory { * @param ores * @return CollaborationTools */ - public CollaborationTools getOrCreateCollaborationTools(final OLATResourceable ores) { + public CollaborationTools getOrCreateCollaborationTools(final BusinessGroup ores) { if (ores == null) throw new AssertException("Null is not allowed here, you have to provide an existing ores here!"); final String cacheKey = Long.valueOf(ores.getResourceableId()).toString(); //sync operation cluster wide diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java index f3bd0626a71f78c72f87fdfb8daeca5eeddddfec..ed4e99175da3f1acbb8976c3c64e187c3bbf3b6c 100644 --- a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java +++ b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java @@ -42,10 +42,10 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; -import org.olat.core.id.OLATResourceable; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.vfs.QuotaManager; +import org.olat.group.BusinessGroup; import org.olat.instantMessaging.InstantMessagingModule; /** @@ -66,13 +66,13 @@ public class CollaborationToolsSettingsController extends BasicController { boolean lastCalendarEnabledState; private Controller quotaCtr; - private OLATResourceable businessGroup; + private BusinessGroup businessGroup; /** * @param ureq * @param tools */ - public CollaborationToolsSettingsController(UserRequest ureq, WindowControl wControl, OLATResourceable businessGroup) { + public CollaborationToolsSettingsController(UserRequest ureq, WindowControl wControl, BusinessGroup businessGroup) { super(ureq, wControl); this.businessGroup = businessGroup; CollaborationTools collabTools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroup); diff --git a/src/main/java/org/olat/course/member/_content/edit_member.html b/src/main/java/org/olat/course/member/_content/edit_member.html index af17764a8cd410fdb290134bb67fca8de40d9855..a9d9b08270e429c9104af63752be9e4661a9abab 100644 --- a/src/main/java/org/olat/course/member/_content/edit_member.html +++ b/src/main/java/org/olat/course/member/_content/edit_member.html @@ -1,13 +1,17 @@ #if($r.available("infos")) - $r.render("infos") + $r.render("infos")<br/> #end #if($r.available("repoRights")) - <h4>$editTitle</h4> - $r.render("repoRights") + <fieldset> + <legend>$editTitle</legend> + $r.render("repoRights") + </fieldset> #end #if($r.available("groupList")) - <h5>$r.translate("edit.member.groups")</h5> - $r.render("groupList") + <fieldset> + <legend>$r.translate("edit.member.groups")</legend> + $r.render("groupList") + </fieldset> #end #if($r.available("buttonLayout")) $r.render("buttonLayout") diff --git a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java index 42ebb442d57a1e545bbb69db13af89b4bc5e609b..1d89925b7ad86acc9cba44571f90512e5bf3d15e 100644 --- a/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java +++ b/src/main/java/org/olat/course/nodes/en/EnrollmentManager.java @@ -25,6 +25,7 @@ package org.olat.course.nodes.en; +import java.util.Collections; import java.util.List; import org.olat.basesecurity.BaseSecurity; @@ -32,28 +33,25 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.manager.BasicManager; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.SyncerExecutor; import org.olat.core.util.mail.MailContext; import org.olat.core.util.mail.MailContextImpl; import org.olat.core.util.mail.MailHelper; import org.olat.core.util.mail.MailTemplate; import org.olat.core.util.mail.MailerResult; import org.olat.core.util.mail.MailerWithTemplate; -import org.olat.core.util.resource.OresHelper; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.ENCourseNode; import org.olat.course.properties.CoursePropertyManager; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.group.area.BGAreaManager; +import org.olat.group.model.BGMembership; +import org.olat.group.model.EnrollState; import org.olat.group.model.SearchBusinessGroupParams; import org.olat.group.ui.BGMailHelper; import org.olat.properties.Property; import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.ACService; -import org.olat.resource.accesscontrol.model.ResourceReservation; -import org.olat.testutils.codepoints.server.Codepoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -94,48 +92,16 @@ public class EnrollmentManager extends BasicManager { // and: why can't we just have a group here and a max participants count and an identity to enrol? // the group was chosen, so why do we need the groupNames and areaNames here??? - Codepoint.codepoint(EnrollmentManager.class, "beforeDoInSync"); - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ - public void execute() { - logInfo("doEnroll start: group="+OresHelper.createStringRepresenting(group), identity.getName()); - Codepoint.codepoint(EnrollmentManager.class, "doInSync1"); - // 6_1_0-RC15: reload group object here another node might have changed this in the meantime - BusinessGroup reloadedGroup = businessGroupService.loadBusinessGroup(group); - if (reloadedGroup.getMaxParticipants() != null) { - int participantsCounter = securityManager.countIdentitiesOfSecurityGroup(reloadedGroup.getPartipiciantGroup()); - int reservations = acService.countReservations(reloadedGroup.getResource()); - //reservation has the highest priority over max participant - ResourceReservation reservation = acService.getReservation(identity, reloadedGroup.getResource()); - logInfo("doEnroll - participantsCounter: " + participantsCounter + ", reservations: " + reservations + " maxParticipants: " + reloadedGroup.getMaxParticipants().intValue(), identity.getName()); - if (reservation == null && (participantsCounter + reservations) >= reloadedGroup.getMaxParticipants().intValue()) { - // already full, show error and updated choose page again - if (!reloadedGroup.getWaitingListEnabled().booleanValue()) { - // No Waiting List => List is full - enrollStatus.setErrorMessage(trans.translate("error.group.full")); - } else { - boolean done = addUserToWaitingList(identity, reloadedGroup, enNode, coursePropertyManager, wControl, trans); - enrollStatus.setIsInWaitingList(done); - } - } else { - boolean done = addUserToParticipantList(identity, reloadedGroup, enNode, coursePropertyManager, wControl, trans); - Codepoint.codepoint(EnrollmentManager.class, "doInSync2"); - enrollStatus.setIsEnrolled(done); - logInfo("doEnroll - setIsEnrolled ", identity.getName()); - if(reservation != null) { - acService.removeReservation(reservation); - } - } - } else { - if (isLogDebugEnabled()) logDebug("doEnroll beginTransaction"); - boolean done = addUserToParticipantList(identity, reloadedGroup, enNode, coursePropertyManager, wControl, trans); - enrollStatus.setIsEnrolled(done); - if (isLogDebugEnabled()) logDebug("doEnroll committed"); - } - logInfo("doEnroll end", identity.getName()); - } - });// end of doInSync - Codepoint.codepoint(EnrollmentManager.class, "afterDoInSync"); + EnrollState state =businessGroupService.enroll(group, identity); + if(state.isFailed()) { + enrollStatus.setErrorMessage(trans.translate(state.getI18nErrorMessage())); + } else { + if(state.getEnrolled() == BGMembership.participant) { + addUserToParticipantList(identity, group, enNode, coursePropertyManager, wControl, trans); + } else if(state.getEnrolled() == BGMembership.waiting) { + addUserToWaitingList(identity, group, enNode, coursePropertyManager, wControl, trans); + } + } } else { enrollStatus.setErrorMessage(trans.translate("error.group.already.enrolled")); } @@ -147,22 +113,18 @@ public class EnrollmentManager extends BasicManager { final CoursePropertyManager coursePropertyManager, WindowControl wControl, Translator trans) { if (isLogDebugEnabled()) logDebug("doCancelEnrollment"); // 1. Remove group membership, fire events, do loggin etc. - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(enrolledGroup, new SyncerExecutor(){ - public void execute() { - // Remove participant. This will also check if a waiting-list with auto-close-ranks is configurated - // and move the users accordingly - businessGroupService.removeParticipant(identity, identity, enrolledGroup); - logInfo("doCancelEnrollment in group " + enrolledGroup, identity.getName()); - // 2. Remove enrollmentdate property - // only remove last time date, not firsttime - Property lastTime = coursePropertyManager - .findCourseNodeProperty(enNode, identity, null, ENCourseNode.PROPERTY_RECENT_ENROLLMENT_DATE); - if (lastTime != null) { - coursePropertyManager.deleteProperty(lastTime); - } - }}); - + // Remove participant. This will also check if a waiting-list with auto-close-ranks is configurated + // and move the users accordingly + businessGroupService.removeParticipants(identity, Collections.singletonList(identity), enrolledGroup); + logInfo("doCancelEnrollment in group " + enrolledGroup, identity.getName()); + + logInfo("doCancelEnrollment in group " + enrolledGroup, identity.getName()); + // 2. Remove enrollmentdate property + // only remove last time date, not firsttime + Property lastTime = coursePropertyManager.findCourseNodeProperty(enNode, identity, null, ENCourseNode.PROPERTY_RECENT_ENROLLMENT_DATE); + if (lastTime != null) { + coursePropertyManager.deleteProperty(lastTime); + } // 3. Send notification mail MailTemplate mailTemplate = BGMailHelper.createRemoveMyselfMailTemplate(enrolledGroup, identity); @@ -176,19 +138,14 @@ public class EnrollmentManager extends BasicManager { public void doCancelEnrollmentInWaitingList(final Identity identity, final BusinessGroup enrolledWaitingListGroup, final ENCourseNode enNode, final CoursePropertyManager coursePropertyManager, WindowControl wControl, Translator trans) { // 1. Remove group membership, fire events, do loggin etc. - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(enrolledWaitingListGroup, new SyncerExecutor(){ - public void execute() { - businessGroupService.removeFromWaitingList(identity, identity, enrolledWaitingListGroup); - // 2. Remove enrollmentdate property - // only remove last time date, not firsttime - Property lastTime = coursePropertyManager.findCourseNodeProperty(enNode, identity, null, - ENCourseNode.PROPERTY_RECENT_WAITINGLIST_DATE); - if (lastTime != null) { - coursePropertyManager.deleteProperty(lastTime); - } - }}); + businessGroupService.removeFromWaitingList(identity, Collections.singletonList(identity), enrolledWaitingListGroup); + // 2. Remove enrollmentdate property + // only remove last time date, not firsttime + Property lastTime = coursePropertyManager.findCourseNodeProperty(enNode, identity, null, ENCourseNode.PROPERTY_RECENT_WAITINGLIST_DATE); + if (lastTime != null) { + coursePropertyManager.deleteProperty(lastTime); + } // 3. Send notification mail MailTemplate mailTemplate = BGMailHelper.createRemoveWaitinglistMailTemplate(enrolledWaitingListGroup, identity); @@ -298,9 +255,6 @@ public class EnrollmentManager extends BasicManager { // ///////////////// private boolean addUserToParticipantList(Identity identity, BusinessGroup group, ENCourseNode enNode, CoursePropertyManager coursePropertyManager, WindowControl wControl, Translator trans) { - CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); - // 1. Add user to group, fire events, do loggin etc. - businessGroupService.addParticipant(identity, identity, group); // 2. Set first enrollment date String nowString = Long.toString(System.currentTimeMillis()); Property firstTime = coursePropertyManager @@ -336,9 +290,7 @@ public class EnrollmentManager extends BasicManager { private boolean addUserToWaitingList(Identity identity, BusinessGroup group, ENCourseNode enNode, CoursePropertyManager coursePropertyManager, WindowControl wControl, Translator trans) { - CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); - // 1. Add user to group, fire events, do loggin etc. - businessGroupService.addToWaitingList(identity, identity, group); + // <- moved to bgs 1. Add user to group, fire events, do loggin etc. // 2. Set first waiting-list date String nowString = Long.toString(System.currentTimeMillis()); Property firstTime = coursePropertyManager.findCourseNodeProperty(enNode, identity, null, diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java index 432fbc54684a3e5fc63ea541b5bf702d3954b63a..c48a7cd1af769c866c38e1ba60771cf3968ea931 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java @@ -247,22 +247,23 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou final Project reloadedProject = (Project) DBFactory.getInstance().loadObject(project, true); final BusinessGroupAddResponse response = new BusinessGroupAddResponse(); final BusinessGroupService bgs = CoreSpringFactory.getImpl(BusinessGroupService.class); - //TODO gsync + + BusinessGroupAddResponse state = bgs.addParticipants(actionIdentity, identities, reloadedProject.getProjectGroup()); + response.getAddedIdentities().addAll(state.getAddedIdentities()); + response.getIdentitiesAlreadyInGroup().addAll(state.getAddedIdentities()); + Boolean result = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(project.getProjectGroup(), new SyncerCallback<Boolean>(){ public Boolean execute() { for (final Identity identity : identities) { if (!BaseSecurityManager.getInstance().isIdentityInSecurityGroup(identity, reloadedProject.getProjectGroup().getPartipiciantGroup())) { BaseSecurityManager.getInstance().removeIdentityFromSecurityGroup(identity, reloadedProject.getCandidateGroup()); - bgs.addParticipant(actionIdentity, identity, reloadedProject.getProjectGroup()); logAudit("ProjectBroker: Accept candidate, identity=" + identity + " project=" + reloadedProject); - response.getAddedIdentities().add(identity); - } else { - response.getIdentitiesAlreadyInGroup().add(identity); - } + } } return Boolean.TRUE; } });// end of doInSync + if (autoSignOut && result.booleanValue()) { ProjectBrokerManagerFactory.getProjectBrokerManager().signOutFormAllCandidateList(response.getAddedIdentities(), reloadedProject.getProjectBroker().getKey()); } diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java index b1b91211ff176979032b83f1b65596a770e0c4c1..0d6efd18656106946c9f9516cc08a73c0fa1aefc 100644 --- a/src/main/java/org/olat/course/run/RunMainController.java +++ b/src/main/java/org/olat/course/run/RunMainController.java @@ -471,16 +471,18 @@ public class RunMainController extends MainLayoutBasicController implements Gene } private void initUserRolesAndRights(final Identity identity) { - CourseGroupManager cgm = this.course.getCourseEnvironment().getCourseGroupManager(); + CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager(); // 1) course admins: users who are in repository entry owner group // if user has the role InstitutionalResourceManager and has the same institution like author // then set isCourseAdmin true - isCourseAdmin = cgm.isIdentityCourseAdministrator(identity) | RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(courseRepositoryEntry, identity); + isCourseAdmin = cgm.isIdentityCourseAdministrator(identity) + || RepositoryManager.getInstance().isInstitutionalRessourceManagerFor(courseRepositoryEntry, identity); // 2) course coaches: users who are in the owner group of any group of this // course isCourseCoach = cgm.isIdentityCourseCoach(identity); // 3) all other rights are defined in the groupmanagement using the learning // group rights + courseRightsCache.put(CourseRights.RIGHT_GROUPMANAGEMENT, new Boolean(cgm.hasRight(identity, CourseRights.RIGHT_GROUPMANAGEMENT))); courseRightsCache.put(CourseRights.RIGHT_COURSEEDITOR, new Boolean(cgm.hasRight(identity, CourseRights.RIGHT_COURSEEDITOR))); courseRightsCache.put(CourseRights.RIGHT_ARCHIVING, new Boolean(cgm.hasRight(identity, CourseRights.RIGHT_ARCHIVING))); @@ -1092,6 +1094,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene // 1) administrative tools if (isCourseAdmin || isCourseCoach || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_ARCHIVING) + || hasCourseRight(CourseRights.RIGHT_ASSESSMENT) || hasCourseRight(CourseRights.RIGHT_DB) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { myTool.addHeader(translate("header.tools")); if (hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || isCourseAdmin) { diff --git a/src/main/java/org/olat/group/BusinessGroupService.java b/src/main/java/org/olat/group/BusinessGroupService.java index 9a1d3e464cf8e66a945239015d87c748965b506c..7998037f4f6031ba3d0135c192977e3aabfe6937 100644 --- a/src/main/java/org/olat/group/BusinessGroupService.java +++ b/src/main/java/org/olat/group/BusinessGroupService.java @@ -339,21 +339,16 @@ public interface BusinessGroupService { * @return */ public EnrollState enroll(final BusinessGroup group, final Identity identity); - - /** - * Adds a user to a group as participant and does all the magic that needs to - * be done: - add to security group (optional) - add to jabber roster - fire - * multi-user event - * @param ureqIdentity - * @param identityToAdd The user who should be added - * @param group - * @param flags - */ - public void addParticipant(Identity ureqIdentity, Identity identityToAdd, BusinessGroup group); /** * Adds a list of users to a group as participant and does all the magic that needs to - * be done: - add to security group (optional) - add to jabber roster - fire multi-user + * be done: + * <ul> + * <li>add to security group (optional) + * <li>add to jabber roster + * <li>fire multi-user + * </ul> + * Method execute in doInSync * event * @param ureqIdentity * @param addIdentities The users who should be added @@ -363,21 +358,17 @@ public interface BusinessGroupService { */ public BusinessGroupAddResponse addParticipants(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup currBusinessGroup); - /** - * Remove a user from a group as participant and does all the magic that needs - * to be done: - remove from security group (optional) - remove from jabber roster - - * fire multi-user event - * @param ureqIdentity - * @param identity The user who should be removed - * @param group - * @param flags - */ - public void removeParticipant(Identity ureqIdentity, Identity identity, BusinessGroup group); - + /** * Remove a list of users from a group as participant and does all the magic that needs - * to be done: - remove from secgroup (optional) - remove from jabber roster - - * fire multi-user event + * to be done: + * <ul> + * <li>remove from secgroup (optional) + * <li>remove from jabber roster - + * <li>fire multi-user event + * </ul> + * The method is made under doInSync. + * * @param ureqIdentity * @param identities The user who should be removed * @param group @@ -395,20 +386,17 @@ public interface BusinessGroupService { */ public void removeMembers(Identity ureqIdentity, List<Identity> identities, OLATResource resource); - /** - * Adds a user to a waiting-list of a group and does all the magic that needs to - * be done: - add to security group (optional) - add to jabber roster - send - * notification email - fire multi-user event - * @param ureqIdentity - * @param identity - * @param group - */ - public void addToWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup group); /** * Adds a list of users to a waiting-list of a group and does all the magic that needs to - * be done: - add to security group (optional) - add to jabber roster - send - * notification email - fire multi user event + * be done: + * <ul> + * <li>add to security group (optional) + * <li>add to jabber roster + * <li>send notification email + * <li>fire multi user event + * </ul> + * Method executed under doInSync * @param ureqIdentity * @param addIdentities * @param currBusinessGroup @@ -417,20 +405,6 @@ public interface BusinessGroupService { */ public BusinessGroupAddResponse addToWaitingList(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup currBusinessGroup); - - - /** - * Remove a user from a waiting-list as participant and does all the magic that needs - * to be done:<br/> - * - remove from security group (optional) <br/> - * - send notification email<br/> - * - fire multi user event - * @param ureqIdentity - * @param identity - * @param waitingListGroup - */ - public void removeFromWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup waitingListGroup); - /** * Remove a list of users from a waiting-list as participant and does all the magic that needs * to be done: diff --git a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java index 06dacd6f350c2b8e4db58f89ee0f347626f505de..8f0a832ea8ac2a7a67d0179b7511888762dda0ff 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupDAO.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupDAO.java @@ -134,7 +134,7 @@ public class BusinessGroupDAO { public BusinessGroup load(Long id) { EntityManager em = dbInstance.getCurrentEntityManager(); - BusinessGroup group = em.find(BusinessGroupImpl.class, id, LockModeType.NONE); + BusinessGroup group = em.find(BusinessGroupImpl.class, id); return group; } diff --git a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java index dc5b9047192efed1adbfc4b7ed583928daf80a99..e9445859e746842f77172f08d38cfeb036eb70b6 100644 --- a/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java +++ b/src/main/java/org/olat/group/manager/BusinessGroupServiceImpl.java @@ -96,7 +96,7 @@ import org.olat.group.ui.BGMailHelper; import org.olat.group.ui.edit.BusinessGroupModifiedEvent; import org.olat.instantMessaging.IMConfigSync; import org.olat.instantMessaging.InstantMessagingModule; -import org.olat.instantMessaging.syncservice.SyncSingleUserTask; +import org.olat.instantMessaging.syncservice.SyncUserListTask; import org.olat.notifications.NotificationsManagerImpl; import org.olat.properties.Property; import org.olat.repository.RepositoryEntry; @@ -147,10 +147,12 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD userDeletionManager.registerDeletableUserData(this); } + @Override public void registerDeletableGroupDataListener(DeletableGroupData listener) { this.deleteListeners.add(listener); } + @Override public List<String> getDependingDeletablableListFor(BusinessGroup currentGroup, Locale locale) { List<String> deletableList = new ArrayList<String>(); for (DeletableGroupData deleteListener : deleteListeners) { @@ -209,7 +211,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD public BusinessGroup updateBusinessGroup(final Identity ureqIdentity, final BusinessGroup group, final String name, final String description, final Integer minParticipants, final Integer maxParticipants) { - return CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<BusinessGroup>() { + final SyncUserListTask syncIM = new SyncUserListTask(group); + BusinessGroup updatedGroup = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<BusinessGroup>() { public BusinessGroup execute() { // refresh group to prevent stale object exception and context proxy issues BusinessGroup bg = loadBusinessGroup(group); @@ -220,16 +223,20 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD bg.setMinParticipants(minParticipants); bg.setLastUsage(new Date(System.currentTimeMillis())); //auto rank if possible - autoRankCheck(ureqIdentity, bg, previousMaxParticipants); + autoRankCheck(ureqIdentity, bg, previousMaxParticipants, syncIM); return businessGroupDAO.merge(bg); } }); + syncIM(syncIM, updatedGroup); + return updatedGroup; } - + + @Override public BusinessGroup updateBusinessGroup(final Identity ureqIdentity, final BusinessGroup group, final String name, final String description, final Integer minParticipants, final Integer maxParticipants, final Boolean waitingList, final Boolean autoCloseRanks) { - return CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<BusinessGroup>() { + final SyncUserListTask syncIM = new SyncUserListTask(group); + BusinessGroup updatedGroup = CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<BusinessGroup>() { public BusinessGroup execute() { // refresh group to prevent stale object exception and context proxy issues BusinessGroup bg = loadBusinessGroup(group); @@ -247,13 +254,15 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD bg.setAutoCloseRanksEnabled(autoCloseRanks); bg.setLastUsage(new Date(System.currentTimeMillis())); //auto rank if possible - autoRankCheck(ureqIdentity, bg, previousMaxParticipants); + autoRankCheck(ureqIdentity, bg, previousMaxParticipants, syncIM); return businessGroupDAO.merge(bg); } }); + + return updatedGroup; } - private void autoRankCheck(Identity identity, BusinessGroup updatedGroup, Integer previousMaxParticipants) { + private void autoRankCheck(Identity identity, BusinessGroup updatedGroup, Integer previousMaxParticipants, SyncUserListTask syncIM) { if(updatedGroup.getWaitingListEnabled() == null || !updatedGroup.getWaitingListEnabled().booleanValue() || updatedGroup.getAutoCloseRanksEnabled() == null || !updatedGroup.getAutoCloseRanksEnabled().booleanValue()) { //do not check further, no waiting list, no automatic ranks @@ -267,7 +276,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD if(currentMaxNumber > previousMaxNumber) { //I can rank up some users - transferFirstIdentityFromWaitingToParticipant(identity, updatedGroup); + transferFirstIdentityFromWaitingToParticipant(identity, updatedGroup, syncIM); } } @@ -455,6 +464,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD @Override public BusinessGroup mergeBusinessGroups(final Identity merger, final BusinessGroup targetGroup, final List<BusinessGroup> groupsToMerge) { groupsToMerge.remove(targetGroup);//to be sure + final SyncUserListTask syncIM = new SyncUserListTask(targetGroup); CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(targetGroup, new SyncerExecutor(){ public void execute() { @@ -499,10 +509,10 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } for(Identity newOwner:newOwners) { - addOwner(merger, newOwner, targetGroup); + addOwner(merger, newOwner, targetGroup, syncIM); } for(Identity newParticipant:newParticipants) { - addParticipant(merger, newParticipant, targetGroup); + addParticipant(merger, newParticipant, targetGroup, syncIM); } for(Identity newWaiter:newWaiters) { addToWaitingList(merger, newWaiter, targetGroup); @@ -510,6 +520,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } }); + syncIM(syncIM, targetGroup); for(BusinessGroup group:groupsToMerge) { deleteBusinessGroup(group); } @@ -524,6 +535,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } private void updateMembers(final Identity identity, final MembershipModification membersMod, final BusinessGroup group) { + final SyncUserListTask syncIM = new SyncUserListTask(group); + CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ public void execute() { List<Identity> currentOwners = securityManager.getIdentitiesOfSecurityGroup(group.getOwnerGroup()); @@ -532,12 +545,12 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD for(Identity owner:membersMod.getAddOwners()) { if(!currentOwners.contains(owner)) { - addOwner(identity, owner, group); + addOwner(identity, owner, group, syncIM); } } for(Identity participant:membersMod.getAddParticipants()) { if(!currentParticipants.contains(participant)) { - addParticipant(identity, participant, group); + addParticipant(identity, participant, group, syncIM); } } for(Identity waitingIdentity:membersMod.getAddToWaitingList()) { @@ -553,7 +566,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD ownerToRemove.add(removed); } if(currentParticipants.contains(removed)) { - removeParticipant(identity, removed, group); + removeParticipant(identity, removed, group, syncIM); } if(currentWaitingList.contains(removed)) { removeFromWaitingList(identity, removed, group); @@ -561,6 +574,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } removeOwners(identity, ownerToRemove, group); }}); + + syncIM(syncIM, group); } @Override @@ -604,8 +619,11 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD List<BusinessGroup> groups = loadBusinessGroups(changesMap.keySet()); for(final BusinessGroup group:groups) { final BusinessGroupMembershipsChanges changesWrapper = changesMap.get(group.getKey()); + final SyncUserListTask syncIM = new SyncUserListTask(group); + CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor() { public void execute() { + for(Identity id:changesWrapper.addToWaitingList) { addToWaitingList(ureqIdentity, id, group); } @@ -613,19 +631,21 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD removeFromWaitingList(ureqIdentity, id, group); } for(Identity id:changesWrapper.addTutors) { - addOwner(ureqIdentity, id, group); + addOwner(ureqIdentity, id, group, syncIM); } for(Identity id:changesWrapper.removeTutors) { - removeOwner(ureqIdentity, id, group); + removeOwner(ureqIdentity, id, group, syncIM); } for(Identity id:changesWrapper.addParticipants) { - addParticipant(ureqIdentity, id, group); + addParticipant(ureqIdentity, id, group, syncIM); } for(Identity id:changesWrapper.removeParticipants) { - removeParticipant(ureqIdentity, id, group); + removeParticipant(ureqIdentity, id, group, syncIM); } } }); + + syncIM(syncIM, group); } } @@ -839,6 +859,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD @Override public BusinessGroupAddResponse addOwners(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup group) { + SyncUserListTask syncIM = new SyncUserListTask(group); BusinessGroupAddResponse response = new BusinessGroupAddResponse(); for (Identity identity : addIdentities) { group = loadBusinessGroup(group); // reload business group @@ -852,18 +873,22 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD response.getIdentitiesAlreadyInGroup().add(identity); } else { // identity has permission and is not already in group => add it - addOwner(ureqIdentity, identity, group); + addOwner(ureqIdentity, identity, group, syncIM); response.getAddedIdentities().add(identity); log.audit("added identity '" + identity.getName() + "' to securitygroup with key " + group.getOwnerGroup().getKey()); } } + syncIM(syncIM, group); return response; } - private void addOwner(Identity ureqIdentity, Identity identity, BusinessGroup group) { + private void addOwner(Identity ureqIdentity, Identity identity, BusinessGroup group, SyncUserListTask syncIM) { securityManager.addIdentityToSecurityGroup(identity, group.getOwnerGroup()); // add user to buddies rosters - addToRoster(ureqIdentity, identity, group); + if(syncIM != null) { + syncIM.addUserToAdd(identity.getName()); + } + // notify currently active users of this business group BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity); // do logging @@ -871,14 +896,15 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD // send notification mail in your controller! } - @Override - public void addParticipant(Identity ureqIdentity, Identity identityToAdd, BusinessGroup group) { + private void addParticipant(Identity ureqIdentity, Identity identityToAdd, BusinessGroup group, SyncUserListTask syncIM) { CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); securityManager.addIdentityToSecurityGroup(identityToAdd, group.getPartipiciantGroup()); - // add user to buddies rosters - addToRoster(ureqIdentity, identityToAdd, group); + if(syncIM != null) { + syncIM.addUserToAdd(identityToAdd.getName()); + } + // notify currently active users of this business group BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identityToAdd); // do logging @@ -894,6 +920,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ public void execute() { final BusinessGroup currBusinessGroup = loadBusinessGroup(group); // reload business group + SyncUserListTask syncIM = new SyncUserListTask(currBusinessGroup); + for (final Identity identity : addIdentities) { if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) { response.getIdentitiesWithoutPermission().add(identity); @@ -905,22 +933,23 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD response.getIdentitiesAlreadyInGroup().add(identity); } else { // identity has permission and is not already in group => add it - addParticipant(ureqIdentity, identity, currBusinessGroup); + addParticipant(ureqIdentity, identity, currBusinessGroup, syncIM); response.getAddedIdentities().add(identity); log.audit("added identity '" + identity.getName() + "' to securitygroup with key " + currBusinessGroup.getPartipiciantGroup().getKey()); } } + + syncIM(syncIM, group); }}); return response; } - @Override - public void removeParticipant(Identity ureqIdentity, Identity identity, BusinessGroup group) { + private void removeParticipant(Identity ureqIdentity, Identity identity, BusinessGroup group, SyncUserListTask syncIM) { CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); securityManager.removeIdentityFromSecurityGroup(identity, group.getPartipiciantGroup()); // remove user from buddies rosters - removeFromRoster(identity, group); + syncIM.addUserToRemove(identity.getName()); //remove subscriptions if user gets removed removeSubscriptions(identity, group); @@ -931,7 +960,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD // Check if a waiting-list with auto-close-ranks is configurated if ( group.getWaitingListEnabled().booleanValue() && group.getAutoCloseRanksEnabled().booleanValue() ) { // even when doOnlyPostRemovingStuff is set to true we really transfer the first Identity here - transferFirstIdentityFromWaitingToParticipant(ureqIdentity, group); + transferFirstIdentityFromWaitingToParticipant(ureqIdentity, group, syncIM); } // send notification mail in your controller! @@ -939,14 +968,18 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD @Override public void removeParticipants(final Identity ureqIdentity, final List<Identity> identities, final BusinessGroup group) { + final SyncUserListTask syncIM = new SyncUserListTask(group); + CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ public void execute() { for (Identity identity : identities) { - removeParticipant(ureqIdentity, identity, group); + removeParticipant(ureqIdentity, identity, group, syncIM); log.audit("removed identiy '" + identity.getName() + "' from securitygroup with key " + group.getPartipiciantGroup().getKey()); } } }); + + syncIM(syncIM, group); } @Override @@ -980,51 +1013,57 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD Long groupKey = currentMembership.getGroupKey(); BusinessGroup nextGroup = keyToGroupMap.get(groupKey); - - final BusinessGroup currentGroup = nextGroup; - nextGroupMembership = CoordinatorManager.getInstance().getCoordinator().getSyncer() - .doInSync(currentGroup, new SyncerCallback<BusinessGroupMembershipViewImpl>(){ - - public BusinessGroupMembershipViewImpl execute() { - BusinessGroupMembershipViewImpl previsousComputedMembership = currentMembership; - BusinessGroupMembershipViewImpl membership; - - do { - if(previsousComputedMembership != null) { - membership = previsousComputedMembership; - previsousComputedMembership = null; - } else if(itMembership.hasNext()) { - membership = itMembership.next(); - } else { - //security, nothing to do - return null; + nextGroupMembership = removeGroupMembers(ureqIdentity, currentMembership, nextGroup, keyToIdentityMap, itMembership); + } + } + + private final BusinessGroupMembershipViewImpl removeGroupMembers(final Identity ureqIdentity, final BusinessGroupMembershipViewImpl currentMembership, + final BusinessGroup currentGroup, final Map<Long,Identity> keyToIdentityMap, final Iterator<BusinessGroupMembershipViewImpl> itMembership) { + + final SyncUserListTask syncIM = new SyncUserListTask(currentGroup); + BusinessGroupMembershipViewImpl next= CoordinatorManager.getInstance().getCoordinator().getSyncer() + .doInSync(currentGroup, new SyncerCallback<BusinessGroupMembershipViewImpl>(){ + + public BusinessGroupMembershipViewImpl execute() { + BusinessGroupMembershipViewImpl previsousComputedMembership = currentMembership; + BusinessGroupMembershipViewImpl membership; + + do { + if(previsousComputedMembership != null) { + membership = previsousComputedMembership; + previsousComputedMembership = null; + } else if(itMembership.hasNext()) { + membership = itMembership.next(); + } else { + //security, nothing to do + return null; + } + + if(currentGroup.getKey().equals(membership.getGroupKey())) { + Identity id = keyToIdentityMap.get(membership.getIdentityKey()); + if(membership.getOwnerGroupKey() != null) { + removeOwner(ureqIdentity, id, currentGroup, syncIM); } - - if(currentGroup.getKey().equals(membership.getGroupKey())) { - Identity id = keyToIdentityMap.get(membership.getIdentityKey()); - if(membership.getOwnerGroupKey() != null) { - removeOwner(ureqIdentity, id, currentGroup); - } - if(membership.getParticipantGroupKey() != null) { - removeParticipant(ureqIdentity, id, currentGroup); - } - if(membership.getWaitingGroupKey() != null) { - removeFromWaitingList(ureqIdentity, id, currentGroup); - } - } else { - return membership; + if(membership.getParticipantGroupKey() != null) { + removeParticipant(ureqIdentity, id, currentGroup, syncIM); } - } while (itMembership.hasNext()); - - return null; - } - }); + if(membership.getWaitingGroupKey() != null) { + removeFromWaitingList(ureqIdentity, id, currentGroup); + } + } else { + return membership; + } + } while (itMembership.hasNext()); - } + return null; + } + }); + + syncIM(syncIM, currentGroup); + return next; } - @Override - public void addToWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup group) { + private void addToWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup group) { CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); securityManager.addIdentityToSecurityGroup(identity, group.getWaitingGroup()); @@ -1064,8 +1103,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD return response; } - @Override - public void removeFromWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup group) { + private final void removeFromWaitingList(Identity ureqIdentity, Identity identity, BusinessGroup group) { CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); securityManager.removeIdentityFromSecurityGroup(identity, group.getWaitingGroup()); // notify currently active users of this business group @@ -1106,13 +1144,14 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD final BusinessGroup currBusinessGroup) { final BusinessGroupAddResponse response = new BusinessGroupAddResponse(); + final SyncUserListTask syncIM = new SyncUserListTask(currBusinessGroup); CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(currBusinessGroup,new SyncerExecutor(){ public void execute() { for (final Identity identity : identities) { // check if idenity is allready in participant if (!securityManager.isIdentityInSecurityGroup(identity,currBusinessGroup.getPartipiciantGroup()) ) { // Idenity is not in participant-list => move idenity from waiting-list to participant-list - addParticipant(ureqIdentity, identity, currBusinessGroup); + addParticipant(ureqIdentity, identity, currBusinessGroup, syncIM); removeFromWaitingList(ureqIdentity, identity, currBusinessGroup); response.getAddedIdentities().add(identity); // notification mail is handled in controller @@ -1121,6 +1160,8 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } } }}); + + syncIM(syncIM, currBusinessGroup); return response; } @@ -1165,10 +1206,11 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD BusinessGroup reloadedGroup = loadBusinessGroup(group); ResourceReservation reservation = acService.getReservation(identity, reloadedGroup.getResource()); + SyncUserListTask syncIM = new SyncUserListTask(reloadedGroup); //reservation has the highest priority over max participant or other settings if(reservation != null) { - addParticipant(null, identity, reloadedGroup); + addParticipant(null, identity, reloadedGroup, syncIM); enrollStatus.setEnrolled(BGMembership.participant); log.info("doEnroll (reservation) - setIsEnrolled ", identity.getName()); if(reservation != null) { @@ -1191,17 +1233,18 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } } else { //enough place - addParticipant(null, identity, reloadedGroup); + addParticipant(null, identity, reloadedGroup, syncIM); enrollStatus.setEnrolled(BGMembership.participant); log.info("doEnroll - setIsEnrolled ", identity.getName()); } } else { if (log.isDebug()) log.debug("doEnroll as participant beginTransaction"); - addParticipant(null, identity, reloadedGroup); + addParticipant(null, identity, reloadedGroup, syncIM); enrollStatus.setEnrolled(BGMembership.participant); if (log.isDebug()) log.debug("doEnroll as participant committed"); } + syncIM(syncIM, reloadedGroup); log.info("doEnroll end", identity.getName()); return enrollStatus; } @@ -1224,9 +1267,11 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD List<BusinessGroup> groups = loadBusinessGroups(ownerKeys); for (BusinessGroup group : groups) { if (group != null && !securityManager.isIdentityInSecurityGroup(ident, group.getOwnerGroup())){ -// seems not to work, but would be the way to go! -// ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrap(group)); - addOwner(addingIdentity, ident, group); + //seems not to work, but would be the way to go! + //ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrap(group)); + SyncUserListTask syncIM = new SyncUserListTask(group); + addOwner(addingIdentity, ident, group, syncIM); + syncIM(syncIM, group); ownerGroupnames += group.getName() + ", "; addToAnyGroup = true; if (!notifyAboutAdd.contains(group.getKey()) && mailKeys.contains(group.getKey())) notifyAboutAdd.add(group.getKey()); @@ -1241,12 +1286,14 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD for (BusinessGroup group : participantGroups) { if (group != null && !securityManager.isIdentityInSecurityGroup(ident, group.getPartipiciantGroup())) { final BusinessGroup toAddGroup = group; -// seems not to work, but would be the way to go! -// ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrap(group)); + final SyncUserListTask syncIM = new SyncUserListTask(group); + //seems not to work, but would be the way to go! + //ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrap(group)); CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ public void execute() { - addParticipant(addingIdentity, ident, toAddGroup); + addParticipant(addingIdentity, ident, toAddGroup, syncIM); }}); + syncIM(syncIM, group); participantGroupnames += group.getName() + ", "; addToAnyGroup = true; if (!notifyAboutAdd.contains(group.getKey()) && mailKeys.contains(group.getKey())) notifyAboutAdd.add(group.getKey()); @@ -1275,7 +1322,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } - private void transferFirstIdentityFromWaitingToParticipant(Identity ureqIdentity, BusinessGroup group) { + private void transferFirstIdentityFromWaitingToParticipant(Identity ureqIdentity, BusinessGroup group, SyncUserListTask syncIM) { CoordinatorManager.getInstance().getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group); // Check if waiting-list is enabled and auto-rank-up if (group.getWaitingListEnabled() != null && group.getWaitingListEnabled().booleanValue() @@ -1307,7 +1354,7 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD // that get triggered in the next two methods to be of ActionType admin // This is needed to make sure the targetIdentity ends up in the o_loggingtable ThreadLocalUserActivityLogger.setStickyActionType(ActionType.admin); - addParticipant(ureqIdentity, firstWaitingListIdentity, group); + addParticipant(ureqIdentity, firstWaitingListIdentity, group, syncIM); removeFromWaitingList(ureqIdentity, firstWaitingListIdentity, group); } finally { ThreadLocalUserActivityLogger.setStickyActionType(formerStickyActionType); @@ -1330,21 +1377,25 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD log.warn("Called method transferFirstIdentityFromWaitingToParticipant but waiting-list or autoCloseRanks is disabled."); } } - - private void addToRoster(Identity ureqIdentity, Identity identity, BusinessGroup group) { - if (InstantMessagingModule.isEnabled()) { + + private void syncIM(SyncUserListTask task, BusinessGroup group) { + if (!task.isEmpty() && InstantMessagingModule.isEnabled()) { //evaluate whether to sync or not IMConfigSync syncGroup = InstantMessagingModule.getAdapter().getConfig().getSyncGroupsConfig(); //only sync when a group is a certain type and this type is configured that you want to sync it if(syncGroup.equals(IMConfigSync.allGroups) || (syncGroup.equals(IMConfigSync.perConfig) && isChatEnableFor(group))) { - String groupID = InstantMessagingModule.getAdapter().createChatRoomString(group); - String groupDisplayName = group.getName(); + //course group enrolment is time critial so we move this in an separate thread and catch all failures - TaskExecutorManager.getInstance().runTask(new SyncSingleUserTask(ureqIdentity, groupID, groupDisplayName, identity)); + try { + TaskExecutorManager.getInstance().runTask(task); + } catch (Exception e) { + log.error("Error trying to sync the roster of the business group: " + group, e); + } } } } + private boolean isChatEnableFor(BusinessGroup group) { CollaborationTools tools = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(group); if(tools == null) { @@ -1353,10 +1404,10 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD return tools.isToolEnabled(CollaborationTools.TOOL_CHAT); } - public void removeOwner(Identity ureqIdentity, Identity identityToRemove, BusinessGroup group) { + private void removeOwner(Identity ureqIdentity, Identity identityToRemove, BusinessGroup group, SyncUserListTask syncIM) { securityManager.removeIdentityFromSecurityGroup(identityToRemove, group.getOwnerGroup()); // remove user from buddies rosters - removeFromRoster(identityToRemove, group); + syncIM.addUserToRemove(identityToRemove.getName()); //remove subsciptions if user gets removed removeSubscriptions(identityToRemove, group); @@ -1373,10 +1424,11 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD @Override public void removeOwners(Identity ureqIdentity, Collection<Identity> identitiesToRemove, BusinessGroup group) { - //fxdiff VCRP-2: access control + SyncUserListTask syncIM = new SyncUserListTask(group); for(Identity identityToRemove:identitiesToRemove) { - removeOwner(ureqIdentity, identityToRemove, group); + removeOwner(ureqIdentity, identityToRemove, group, syncIM); } + syncIM(syncIM, group); } private void removeSubscriptions(Identity identity, BusinessGroup group) { @@ -1391,16 +1443,6 @@ public class BusinessGroupServiceImpl implements BusinessGroupService, UserDataD } } } - - private void removeFromRoster(Identity identity, BusinessGroup group) { - if (InstantMessagingModule.isEnabled()) { - // only remove user from roster if not in other security group - if (!isIdentityInBusinessGroup(identity, group)) { - String groupID = InstantMessagingModule.getAdapter().createChatRoomString(group); - InstantMessagingModule.getAdapter().removeUserFromFriendsRoster(groupID, identity.getName()); - } - } - } @Override @Transactional(readOnly=true) diff --git a/src/main/java/org/olat/group/ui/main/BGTableItem.java b/src/main/java/org/olat/group/ui/main/BGTableItem.java index 20efed0c806d1d538bc82edaaa3ee267c262168f..352de1b2a67d9686a74edba67490933cb3d7c26c 100644 --- a/src/main/java/org/olat/group/ui/main/BGTableItem.java +++ b/src/main/java/org/olat/group/ui/main/BGTableItem.java @@ -206,7 +206,7 @@ public class BGTableItem { public BGShort(BusinessGroup group) { key = group.getKey(); - name = group.getName().intern(); + name = group.getName() == null ? null : group.getName().intern(); maxParticipants = group.getMaxParticipants(); waitingListEnabled = group.getWaitingListEnabled() == null ? false : group.getWaitingListEnabled().booleanValue(); autoCloseRanksEnabled = group.getAutoCloseRanksEnabled() == null ? false : group.getAutoCloseRanksEnabled().booleanValue(); @@ -214,7 +214,7 @@ public class BGTableItem { public BGShort(BusinessGroupView group) { key = group.getKey(); - name = group.getName().intern(); + name = group.getName() == null ? null : group.getName().intern(); maxParticipants = group.getMaxParticipants(); numWaiting = group.getNumWaiting(); numOfOwners = group.getNumOfOwners(); diff --git a/src/main/java/org/olat/group/ui/portlet/BusinessGroupEntry.java b/src/main/java/org/olat/group/ui/portlet/BusinessGroupEntry.java index 028ed69e0ad83251ce7b248ad2f6cd1f3bcfe82f..38e38b67688313813e4490d1b603861dc972a87b 100644 --- a/src/main/java/org/olat/group/ui/portlet/BusinessGroupEntry.java +++ b/src/main/java/org/olat/group/ui/portlet/BusinessGroupEntry.java @@ -34,12 +34,12 @@ class BusinessGroupEntry { private final Date creationDate; public BusinessGroupEntry(String name, Date creationDate) { - this.name = name.intern(); + this.name = name == null ? null : name.intern(); this.creationDate = creationDate; } public BusinessGroupEntry(BusinessGroup group) { - this.name = group.getName().intern(); + this.name = group.getName() == null ? "???" : group.getName().intern(); this.creationDate = group.getCreationDate(); } diff --git a/src/main/java/org/olat/instantMessaging/InstantMessaging.java b/src/main/java/org/olat/instantMessaging/InstantMessaging.java index 1b7bb4bfc8aa44f862c7a71e4d312eb1db9a9fe9..29e568510c989479e6b9ce30def2c0b2bd55d103 100644 --- a/src/main/java/org/olat/instantMessaging/InstantMessaging.java +++ b/src/main/java/org/olat/instantMessaging/InstantMessaging.java @@ -26,6 +26,7 @@ package org.olat.instantMessaging; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -52,14 +53,6 @@ public interface InstantMessaging { */ public boolean synchronizeBusinessGroupsWithIMServer(); - /** - * called when OLAT server is started and needs to sync the buddygroups with the IM server. - * - * @param group - */ - //fxdiff: FXOLAT-219 decrease to load generated by synching learning groups (method not used) - //public boolean synchonizeBuddyRoster(BusinessGroup group); - /** * This method should only be called once as it creates the main controller and the groupchat controller for a single user * @param ureq @@ -87,18 +80,13 @@ public interface InstantMessaging { public GroupChatManagerController getGroupChatManagerController(UserRequest ureq); /** - * @param groupOwnerUsername + * Sync a group * @param groupId * @param groupname - * @param addedUsername - */ - public boolean addUserToFriendsRoster(String groupOwnerUsername, String groupId, String groupname, String addedUsername); - - /** - * @param groupId - * @param username an OLAT unique username + * @param addedUsers + * @param removedUsers */ - public boolean removeUserFromFriendsRoster(String groupId, String username); + public boolean syncFriendsRoster(String groupId, String groupname, Collection<String> addedUsers, Collection<String> removedUsers); /** * Delete roster group from instant messaging server diff --git a/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java b/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java index 9af6537f9a68c597a7393851f198e8a49da0b721..a1112b08bbc8a425f08190a868294975dcc736c6 100644 --- a/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java +++ b/src/main/java/org/olat/instantMessaging/SmackInstantMessagingImpl.java @@ -27,6 +27,7 @@ package org.olat.instantMessaging; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -152,13 +153,44 @@ public class SmackInstantMessagingImpl extends LogDelegator implements InstantMe boolean hasAccount = accountService.hasAccount(imUsername); if (!hasAccount) clientManager.getInstantMessagingCredentialsForUser(addedUsername); // we do not check whether a group already exists, we create it each time + + buddyGroupService.createSharedGroup(groupId, groupname); + logDebug("Adding user to roster group::" + groupId + " username: " + addedUsername); + List<String> list = new ArrayList<String>(); list.add(groupOwnerUsername); - buddyGroupService.createSharedGroup(groupId, groupname, list); + list.add(imUsername); + return buddyGroupService.addUserToSharedGroup(groupId, list); + } + + @Override + public boolean syncFriendsRoster(String groupId, String groupname, Collection<String> addedUsers, Collection<String> removedUsers) { + List<String> addedIMUserList = new ArrayList<String>(); + if(addedUsers != null) { + for(String addedUser:addedUsers) { + String imUsername = nameHelper.getIMUsernameByOlatUsername(addedUser); + addedIMUserList.add(imUsername); + boolean hasAccount = accountService.hasAccount(imUsername); + if (!hasAccount) { + clientManager.getInstantMessagingCredentialsForUser(imUsername); + } + } + } - logDebug("Adding user to roster group::" + groupId + " username: " + addedUsername); + List<String> removedIMUserList = new ArrayList<String>(); + if(removedUsers != null) { + for(String removedUser:removedUsers) { + removedIMUserList.add(nameHelper.getIMUsernameByOlatUsername(removedUser)); + } + } - return buddyGroupService.addUserToSharedGroup(groupId, imUsername); + boolean allOk = true; + if(!addedIMUserList.isEmpty()) { + allOk = buddyGroupService.createSharedGroup(groupId, groupname); + allOk = buddyGroupService.addUserToSharedGroup(groupId, addedIMUserList); + } + allOk = buddyGroupService.removeUsersFromSharedGroup(groupId, removedIMUserList); + return allOk; } /** @@ -319,8 +351,10 @@ public class SmackInstantMessagingImpl extends LogDelegator implements InstantMe } String groupId = InstantMessagingModule.getAdapter().createChatRoomString(group); if (users.size() > 0 ) { // only sync groups with users - if (!buddyGroupService.createSharedGroup(groupId, group.getName(), usernames)){ + if (!buddyGroupService.createSharedGroup(groupId, group.getName())){ logError("could not create shared group: "+groupId, null); + } else { + buddyGroupService.addUserToSharedGroup(groupId, usernames); } logDebug("synchronizing group::" + group.toString()); } else { diff --git a/src/main/java/org/olat/instantMessaging/rosterandchat/ChatController.java b/src/main/java/org/olat/instantMessaging/rosterandchat/ChatController.java index 05d902fe730e237ebda0179ae5f294a60a620939..978a53f8630fb9b81272bd1f6ccf353655f903d5 100644 --- a/src/main/java/org/olat/instantMessaging/rosterandchat/ChatController.java +++ b/src/main/java/org/olat/instantMessaging/rosterandchat/ChatController.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -50,7 +49,6 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.floatingresizabledialog.FloatingResizableDialogController; import org.olat.core.id.Identity; -import org.olat.core.id.OLATResourceable; import org.olat.core.id.UserConstants; import org.olat.core.util.event.EventBus; import org.olat.core.util.event.GenericEventListener; @@ -62,8 +60,6 @@ import org.olat.instantMessaging.InstantMessagingEvent; import org.olat.instantMessaging.InstantMessagingModule; import org.olat.instantMessaging.groupchat.SendMessageForm; -import bsh.This; - /** * Description:<br /> * Controller for a single Chat in a floating window diff --git a/src/main/java/org/olat/instantMessaging/syncservice/InstantMessagingGroupSynchronisation.java b/src/main/java/org/olat/instantMessaging/syncservice/InstantMessagingGroupSynchronisation.java index c4add3fa4eecb20008716d139cf34060e4bc0a4e..8eb1ba17f4f4745c778c82ced96b217d9c1dfebc 100644 --- a/src/main/java/org/olat/instantMessaging/syncservice/InstantMessagingGroupSynchronisation.java +++ b/src/main/java/org/olat/instantMessaging/syncservice/InstantMessagingGroupSynchronisation.java @@ -24,7 +24,7 @@ */ package org.olat.instantMessaging.syncservice; -import java.util.List; +import java.util.Collection; public interface InstantMessagingGroupSynchronisation { @@ -37,51 +37,38 @@ public interface InstantMessagingGroupSynchronisation { * @param displayName name shown in the roster * @param initialMembers array with olat usernames */ - public abstract boolean createSharedGroup(String groupId, String displayName, List<String> initialMembers); + public boolean createSharedGroup(String groupId, String displayName); - /** - * creates an empty shared group - * @param groupId - * @param displayName - */ - public abstract boolean createSharedGroup(String groupId, String displayName); - /** * Rename shared buddy group on the IM server * * @param groupId * @param displayName */ - public abstract boolean renameSharedGroup(String groupId, String displayName); + public boolean renameSharedGroup(String groupId, String displayName); /** * @param groupId */ - public abstract boolean deleteSharedGroup(String groupId); + public boolean deleteSharedGroup(String groupId); /** * * @param groupId * @param user */ - public abstract boolean addUserToSharedGroup(String groupId, String username); - - /** - * @param groupId - * @param users list of usernames - */ - public abstract boolean addUsersToSharedGroup(String groupId, List<String> usernames); + public boolean addUserToSharedGroup(String groupId, Collection<String> users); /** * @param groupId * @param username */ - public abstract boolean removeUserFromSharedGroup(String groupId, String username); + public boolean removeUserFromSharedGroup(String groupId, String username); /** * @param groupId * @param users */ - public abstract boolean removeUsersFromSharedGroup(String groupId, String[] users); + public boolean removeUsersFromSharedGroup(String groupId, Collection<String> users); } \ No newline at end of file diff --git a/src/main/java/org/olat/instantMessaging/syncservice/RemoteGroupCreationOverXMPP.java b/src/main/java/org/olat/instantMessaging/syncservice/RemoteGroupCreationOverXMPP.java index 983550e4f2d87df6f95ed9c73e7a084e93e39b89..9e4c4b9504cd041292f782a08c5aa41d39ffad50 100644 --- a/src/main/java/org/olat/instantMessaging/syncservice/RemoteGroupCreationOverXMPP.java +++ b/src/main/java/org/olat/instantMessaging/syncservice/RemoteGroupCreationOverXMPP.java @@ -24,8 +24,7 @@ */ package org.olat.instantMessaging.syncservice; -import java.util.Iterator; -import java.util.List; +import java.util.Collection; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.SmackConfiguration; @@ -66,47 +65,25 @@ public class RemoteGroupCreationOverXMPP implements InstantMessagingGroupSynchro this.adminUser = adminUser; } - /** - * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#addUserToSharedGroup(java.lang.String, org.olat.core.id.Identity) - */ - public boolean addUserToSharedGroup(String groupId, String username) { - boolean statusOk = sendPacket(new AddUserToGroup(username, groupId)); - if (!statusOk) { - log.error("failed to add user to shard group: "+groupId + " username: "+username); - } - return statusOk; - - } - - /** - * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#addUsersToSharedGroup(java.lang.String, java.util.List) - */ - public boolean addUsersToSharedGroup(String groupId, List<String> users) { - boolean statusOk = true; - for (Iterator<String> iterator = users.iterator(); iterator.hasNext();) { - String username = iterator.next(); - if (!sendPacket(new AddUserToGroup(username, groupId))) { - log.error("adding user to shard group failed. group: "+groupId+" and user: "+username); - statusOk = false; - } - } - return statusOk; - } - /** * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#createSharedGroup(java.lang.String, java.lang.String, java.util.List) */ - public boolean createSharedGroup(String groupId, String displayName, List<String> initialMembers) { - //TODO:gs: pass description from groups as well + @Override + public boolean createSharedGroup(String groupId, String displayName) { boolean statusOk = true; if (!sendPacket(new GroupCreate(groupId, displayName, null))) { log.error("could not create shared group: "+groupId); statusOk = false; } - if (initialMembers != null) { + return statusOk; + } + + @Override + public boolean addUserToSharedGroup(String groupId, Collection<String> users) { + boolean statusOk = true; + if (users != null && !users.isEmpty()) { int cnt=0; - for (Iterator<String> iterator = initialMembers.iterator(); iterator.hasNext();) { - String username = iterator.next(); + for (String username : users) { if (!sendPacket(new AddUserToGroup(username, groupId))) { log.error("adding user to shard group failed. group: "+groupId+" and user: "+username); statusOk = false; @@ -124,14 +101,11 @@ public class RemoteGroupCreationOverXMPP implements InstantMessagingGroupSynchro } return statusOk; } - - public boolean createSharedGroup(String groupId, String displayName) { - return createSharedGroup(groupId, displayName, null); - } /** * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#deleteSharedGroup(java.lang.String) */ + @Override public boolean deleteSharedGroup(String groupId) { boolean statusOk = sendPacket(new GroupDelete(groupId)); if(!statusOk) { @@ -144,6 +118,7 @@ public class RemoteGroupCreationOverXMPP implements InstantMessagingGroupSynchro /** * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#removeUserFromSharedGroup(java.lang.String, java.lang.String) */ + @Override public boolean removeUserFromSharedGroup(String groupId, String username) { boolean statusOk = sendPacket(new RemoveUserFromGroup(username, groupId)); if(!statusOk) { @@ -155,22 +130,26 @@ public class RemoteGroupCreationOverXMPP implements InstantMessagingGroupSynchro /** * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#removeUsersFromSharedGroup(java.lang.String, java.lang.String[]) */ - public boolean removeUsersFromSharedGroup(String groupId, String[] users) { - for (int i = 0; i < users.length; i++) { - String username = users[i]; - if (!sendPacket(new RemoveUserFromGroup(username, groupId))) { + @Override + public boolean removeUsersFromSharedGroup(String groupId, Collection<String> users) { + boolean allOk = true; + for (String username : users) { + Boolean ok = sendPacket(new RemoveUserFromGroup(username, groupId)); + if (!ok) { log.error("removing user from shared group failed. group: "+groupId+" and user: "+username); } + allOk &= ok; } - return true; + return allOk; } /** * @see org.olat.instantMessaging.InstantMessagingGroupSynchronisation#renameSharedGroup(java.lang.String, java.lang.String) */ + @Override public boolean renameSharedGroup(String groupId, String displayName) { //if group exists it will be renamed - return createSharedGroup(groupId, displayName, null); + return createSharedGroup(groupId, displayName); } private boolean sendPacket(IQ packet) { diff --git a/src/main/java/org/olat/instantMessaging/syncservice/SyncSingleUserTask.java b/src/main/java/org/olat/instantMessaging/syncservice/SyncSingleUserTask.java deleted file mode 100644 index f3cc65e78efd0ab7eb2518810cb25a7021bd54b7..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/instantMessaging/syncservice/SyncSingleUserTask.java +++ /dev/null @@ -1,71 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.instantMessaging.syncservice; - -import org.olat.core.id.Identity; -import org.olat.instantMessaging.InstantMessagingModule; - -/** - * Description:<br> - * Asynchronously synchronizes a single user with the instant messaging server group administration. - * This has to be done out of scope of the current thread to not disturb the enrolment mechanism which is very time critical - * when hundred of people try to enrol to a certain group within a short time. - * - * <P> - * Initial Date: 30.04.2008 <br> - * @author guido - */ -public class SyncSingleUserTask implements Runnable { - - private Identity groupowner; - private String groupId; - private String groupDisplayName; - private Identity userToAdd; - - /** - * - * @param groupowner - * @param groupId - * @param groupDisplayName - * @param userToAdd - */ - public SyncSingleUserTask(Identity groupowner, String groupId, String groupDisplayName, Identity userToAdd) { - super(); - this.groupowner = groupowner; - this.groupId = groupId; - this.groupDisplayName = groupDisplayName; - this.userToAdd = userToAdd; - } - - - - /** - * @see java.lang.Runnable#run() - */ - public void run() { - InstantMessagingModule.getAdapter().addUserToFriendsRoster(groupowner.getName(), groupId, groupDisplayName, userToAdd.getName()); - } - -} diff --git a/src/main/java/org/olat/instantMessaging/syncservice/SyncUserListTask.java b/src/main/java/org/olat/instantMessaging/syncservice/SyncUserListTask.java new file mode 100644 index 0000000000000000000000000000000000000000..c589436266a87b14be74a45b138b4dc3d0160038 --- /dev/null +++ b/src/main/java/org/olat/instantMessaging/syncservice/SyncUserListTask.java @@ -0,0 +1,77 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.instantMessaging.syncservice; + +import java.util.HashSet; +import java.util.Set; + +import org.olat.group.BusinessGroup; +import org.olat.instantMessaging.InstantMessagingModule; + +/** + * A task to sync a list of users with a roster + * + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class SyncUserListTask implements Runnable { + + private final String groupId; + private final String groupDisplayName; + private final Set<String> userToAdd = new HashSet<String>(); + private final Set<String> userToRemove = new HashSet<String>(); + + /** + * + * @param group + */ + public SyncUserListTask(BusinessGroup group) { + groupId = InstantMessagingModule.getAdapter().createChatRoomString(group); + groupDisplayName = group.getName(); + } + + public Set<String> getUserToAdd() { + return userToAdd; + } + + public void addUserToAdd(String username) { + userToAdd.add(username); + } + + public Set<String> getUserToRemove() { + return userToRemove; + } + + public void addUserToRemove(String username) { + userToRemove.add(username); + } + + public boolean isEmpty() { + return userToRemove.isEmpty() && userToAdd.isEmpty(); + } + + /** + * @see java.lang.Runnable#run() + */ + public void run() { + InstantMessagingModule.getAdapter().syncFriendsRoster(groupId, groupDisplayName, userToAdd, userToRemove); + } + +} diff --git a/src/main/java/org/olat/instantMessaging/syncservice/TestNamespaceHandlers.java b/src/main/java/org/olat/instantMessaging/syncservice/TestNamespaceHandlers.java deleted file mode 100644 index 4fb6360512e4f333bc618c3fb683dee4dbfd83e2..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/instantMessaging/syncservice/TestNamespaceHandlers.java +++ /dev/null @@ -1,187 +0,0 @@ -/** -* OLAT - Online Learning and Training<br> -* http://www.olat.org -* <p> -* Licensed under the Apache License, Version 2.0 (the "License"); <br> -* you may not use this file except in compliance with the License.<br> -* You may obtain a copy of the License at -* <p> -* http://www.apache.org/licenses/LICENSE-2.0 -* <p> -* Unless required by applicable law or agreed to in writing,<br> -* software distributed under the License is distributed on an "AS IS" BASIS, <br> -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> -* See the License for the specific language governing permissions and <br> -* limitations under the License. -* <p> -* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> -* University of Zurich, Switzerland. -* <hr> -* <a href="http://www.openolat.org"> -* OpenOLAT - Online Learning and Training</a><br> -* This file has been modified by the OpenOLAT community. Changes are licensed -* under the Apache 2.0 license as the original file. -*/ -package org.olat.instantMessaging.syncservice; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.jivesoftware.smack.ConnectionConfiguration; -import org.jivesoftware.smack.PacketCollector; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.PacketIDFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.provider.ProviderManager; - - -public class TestNamespaceHandlers { - - /** - * @param args - */ - public static void main(String[] args) { - ConnectionConfiguration connConfig = new ConnectionConfiguration("idlnxgs.unizh.ch", 5222); - connConfig.setNotMatchingDomainCheckEnabled(false); - connConfig.setSASLAuthenticationEnabled(false); - connConfig.setReconnectionAllowed(false); - connConfig.setDebuggerEnabled(true); - - ProviderManager providerMgr = ProviderManager.getInstance(); - providerMgr.addIQProvider("query", UserCreate.NAMESPACE, new UserCreate.Provider()); - providerMgr.addIQProvider("query", UserDelete.NAMESPACE, new UserCreate.Provider()); - - providerMgr.addIQProvider("query", GroupCreate.NAMESPACE, new GroupCreate.Provider()); - providerMgr.addIQProvider("query", GroupDelete.NAMESPACE, new GroupDelete.Provider()); - - providerMgr.addIQProvider("query", AddUserToGroup.NAMESPACE, new AddUserToGroup.Provider()); - providerMgr.addIQProvider("query", RemoveUserFromGroup.NAMESPACE, new RemoveUserFromGroup.Provider()); - - providerMgr.addIQProvider("query", SessionCount.NAMESPACE, new SessionCount.Provider()); - - providerMgr.addIQProvider("query", SessionItems.NAMESPACE, new SessionItems.Provider()); - - providerMgr.addIQProvider("query", UserCheck.NAMESPACE, new UserCheck.Provider()); - - providerMgr.addIQProvider("query", PluginVersion.NAMESPACE, new PluginVersion.Provider()); - - XMPPConnection connection = new XMPPConnection(connConfig); - - - try { - connection.connect(); - connection.login("admin", "admin"); - - String username="demo"; - String pw="test"; - String email="test@test.ch"; - String fullName="gregor grunz"; - int i = 7; - - List packets = new ArrayList(); -// for (int j = 1; j < 300; j++) { -// packets.add(new UserDelete(username+j)); -// -// } - //packets.add(new UserCreate(username, pw, email, fullName)); - packets.add(new UserCheck("administrator")); - packets.add(new UserCheck("author")); - //packets.add(new UserCheck("demo3")); - //packets.add(new UserCheck("demo4")); - //packets.add(new UserCheck("demo5")); - - //packets.add(new PluginVersion()); - - //packets.add(new GroupCreate("testgroup","testgroup bla", "this is the testgroup")); - //packets.add(new GroupCreate("testgroup","testgroup bla", "this is the testgroup")); - //packets.add(new AddUserToGroup(username+i, "testgroup")); - //packets.add(new AddUserToGroup("admin", "testgroup")); - //packets.add(new RemoveUserFromGroup(username+i, "testgroup")); - //packets.add(new GroupDelete("testgroup")); - //packets.add(new GroupDelete("testgroup")); - //packets.add(new UserDelete(username+i)); - //packets.add(new SessionCount()); - //packets.add(new SessionItems()); - - - - Thread.sleep(1000); - long start = System.currentTimeMillis(); - for (Iterator iterator = packets.iterator(); iterator.hasNext();) { - IQ iqPacket = (IQ) iterator.next(); - iqPacket.setFrom(connection.getUser()); - PacketCollector collector = connection.createPacketCollector(new PacketIDFilter(iqPacket.getPacketID())); - connection.sendPacket(iqPacket); - IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); - collector.cancel(); - - if (response == null) { - throw new XMPPException("No response from server on status set."); - } - if (response.getError() != null) { - throw new XMPPException("Error . Cause: "+response.getError().getMessage()); - } else if (response.getType() == IQ.Type.ERROR) { - System.out.println("could not create user...."); - throw new XMPPException("Error . Cause: "+response.getError().getMessage()); - } - if (response instanceof SessionCount) { - SessionCount sCount = (SessionCount) response; - System.out.println("number of sessions: "+sCount.getNumberOfSessions()); - } - - if (response instanceof IMSessionItems) { - IMSessionItems items = (IMSessionItems) response; - List<IMSessionItems.Item> l = items.getItems(); - for (Iterator iterator2 = l.iterator(); iterator2.hasNext();) { - IMSessionItems.Item item = (IMSessionItems.Item) iterator2.next(); - System.out.println("username: "+item.getUsername() ); - System.out.println("presence msg: "+item.getPresenceMsg() ); - System.out.println("status: "+item.getPresenceStatus() ); - System.out.println("last acivity: "+item.getLastActivity() ); - System.out.println("logintime: "+item.getLoginTime() ); - } - } - if (response instanceof UserCheck) { - UserCheck check = (UserCheck) response; - System.out.println("has account responses: "+check.hasAccount()); - } - if (response instanceof PluginVersion) { - PluginVersion version = (PluginVersion) response; - System.out.println("plugin version is: "+version.getVersion()); - } - - - - } - long stop = System.currentTimeMillis(); - System.out.println("time..."+(stop-start)); - - - Thread.sleep(1000); - - connection.disconnect(); - - Thread.sleep(10000); - System.exit(0); - } catch (XMPPException e) { - System.out.println("error occured 1: "+e); - } catch (InterruptedException e) { - System.out.println("error occured 2: "+e); - e.printStackTrace(); - } catch (Exception e) { - System.out.println("error occured 3 : "+e); - } catch (Throwable e) { - System.out.println("error occured 4: "+e); - } - try { - Thread.sleep(30000); - System.exit(0); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - -} diff --git a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java index 9ef4fec4543a05bd0da81c9437bba221d119a506..7527270fccfe87c7a3582014b5f0fcdf8d75039e 100644 --- a/src/main/java/org/olat/restapi/group/LearningGroupWebService.java +++ b/src/main/java/org/olat/restapi/group/LearningGroupWebService.java @@ -55,9 +55,6 @@ import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; -import org.olat.core.util.coordinate.CoordinatorManager; -import org.olat.core.util.coordinate.SyncerCallback; -import org.olat.core.util.coordinate.SyncerExecutor; import org.olat.core.util.notifications.SubscriptionContext; import org.olat.core.util.vfs.Quota; import org.olat.core.util.vfs.QuotaManager; @@ -65,6 +62,7 @@ import org.olat.core.util.vfs.callbacks.VFSSecurityCallback; import org.olat.core.util.vfs.restapi.VFSWebServiceSecurityCallback; import org.olat.core.util.vfs.restapi.VFSWebservice; import org.olat.group.BusinessGroup; +import org.olat.group.BusinessGroupAddResponse; import org.olat.group.BusinessGroupService; import org.olat.group.model.DisplayMembers; import org.olat.group.model.SearchBusinessGroupParams; @@ -522,15 +520,8 @@ public class LearningGroupWebService { if(identity == null || group == null) { return Response.serverError().status(Status.NOT_FOUND).build(); } - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<Boolean>(){ - public Boolean execute() { - List<Identity> identityToAdd = Collections.singletonList(identity); - bgs.addOwners(ureq.getIdentity(), identityToAdd, group); - return Boolean.TRUE; - } - });// end of doInSync - + + bgs.addOwners(ureq.getIdentity(), Collections.singletonList(identity), group); return Response.ok().build(); } catch (Exception e) { log.error("Trying to add an owner to a group", e); @@ -574,21 +565,14 @@ public class LearningGroupWebService { } final UserRequest ureq = RestSecurityHelper.getUserRequest(request); - final BusinessGroupService bgs = CoreSpringFactory.getImpl(BusinessGroupService.class); final BusinessGroup group = bgs.loadBusinessGroup(groupKey); final Identity identity = BaseSecurityManager.getInstance().loadIdentityByKey(identityKey, false); if(identity == null || group == null) { return Response.serverError().status(Status.NOT_FOUND).build(); } - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<Boolean>(){ - public Boolean execute() { - bgs.removeOwners(ureq.getIdentity(), Collections.singletonList(identity), group); - return Boolean.TRUE; - } - });// end of doInSync - + + bgs.removeOwners(ureq.getIdentity(), Collections.singletonList(identity), group); return Response.ok().build(); } catch (Exception e) { log.error("Trying to remove an owner to a group", e); @@ -637,15 +621,14 @@ public class LearningGroupWebService { if(identity == null || group == null) { return Response.serverError().status(Status.NOT_FOUND).build(); } - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerCallback<Boolean>(){ - public Boolean execute() { - bgs.addParticipant(ureq.getIdentity(), identity, group); - return Boolean.TRUE; - } - });// end of doInSync - - return Response.ok().build(); + + BusinessGroupAddResponse state = bgs.addParticipants(ureq.getIdentity(), Collections.singletonList(identity), group); + if(state.getAddedIdentities().contains(identity)) { + return Response.ok().build(); + } else if(state.getIdentitiesAlreadyInGroup().contains(identity)) { + return Response.ok().status(Status.NOT_MODIFIED).build(); + } + return Response.serverError().status(Status.PRECONDITION_FAILED).build(); } catch (Exception e) { log.error("Trying to add a participant to a group", e); return Response.serverError().status(Status.INTERNAL_SERVER_ERROR).build(); @@ -693,12 +676,7 @@ public class LearningGroupWebService { if(identity == null || group == null) { return Response.serverError().status(Status.NOT_FOUND).build(); } - //TODO gsync - CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(group, new SyncerExecutor(){ - public void execute() { - bgs.removeParticipant(ureq.getIdentity(), identity, group); - } - }); + bgs.removeParticipants(ureq.getIdentity(), Collections.singletonList(identity), group); return Response.ok().build(); } catch (Exception e) { diff --git a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java index 57ee89a4e497679efedf175d9d32141a7ed26594..66d29f75a0581d1bee6a82eacc65276ac9851f11 100644 --- a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java +++ b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerTest.java @@ -36,15 +36,22 @@ package org.olat.course.nodes.en; // DB.getInstance().loadObject(); püft ob schon in hibernate session. import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.Assert; -import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; +import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.components.Component; import org.olat.core.gui.control.WindowBackOffice; @@ -63,6 +70,7 @@ import org.olat.core.logging.Tracing; import org.olat.core.util.Util; import org.olat.core.util.resource.OresHelper; import org.olat.course.CourseFactory; +import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.course.nodes.ENCourseNode; import org.olat.course.properties.CoursePropertyManager; import org.olat.course.run.environment.CourseEnvironment; @@ -71,6 +79,7 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupService; import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryManager; import org.olat.test.JunitTestHelper; import org.olat.test.OlatTestCase; import org.springframework.beans.factory.annotation.Autowired; @@ -102,6 +111,10 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl private BusinessGroupService businessGroupService; @Autowired private EnrollmentManager enrollmentManager; + @Autowired + private BaseSecurity securityManager; + @Autowired + private DB dbInstance; /** * @see junit.framework.TestCase#setUp() @@ -116,13 +129,13 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl Boolean enableWaitinglist = new Boolean(true); Boolean enableAutoCloseRanks = new Boolean(true); RepositoryEntry resource = JunitTestHelper.createAndPersistRepositoryEntry(); - System.out.println("testAddToWaitingListAndFireEvent: resource=" + resource); + log.info("testAddToWaitingListAndFireEvent: resource=" + resource); bgWithWaitingList = businessGroupService.createBusinessGroup(id1, bgWithWaitingListName, bgWithWaitingListDesc, -1, -1, enableWaitinglist, enableAutoCloseRanks, resource); bgWithWaitingList.setMaxParticipants(new Integer(2)); - System.out.println("TEST bgWithWaitingList=" + bgWithWaitingList); - System.out.println("TEST bgWithWaitingList.getMaxParticipants()=" + bgWithWaitingList.getMaxParticipants() ); - System.out.println("TEST bgWithWaitingList.getWaitingListEnabled()=" + bgWithWaitingList.getWaitingListEnabled() ); + log.info("TEST bgWithWaitingList=" + bgWithWaitingList); + log.info("TEST bgWithWaitingList.getMaxParticipants()=" + bgWithWaitingList.getMaxParticipants() ); + log.info("TEST bgWithWaitingList.getWaitingListEnabled()=" + bgWithWaitingList.getWaitingListEnabled() ); // create mock objects String PACKAGE = Util.getPackageName(EnrollmentManagerTest.class); testTranslator = new PackageTranslator(PACKAGE, new Locale("de")); @@ -142,7 +155,7 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl * Cancel enrollment. Check size after each step. */ @Test public void testEnroll() throws Exception { - System.out.println("testEnroll: start..."); + log.info("testEnroll: start..."); ENCourseNode enNode = new ENCourseNode(); OLATResourceable ores = OresHelper.createOLATResourceableTypeWithoutCheck("TestCourse"); CourseEnvironment cenv = CourseFactory.createEmptyCourse(ores, "Test", "Test", "learningObjectives").getCourseEnvironment(); @@ -151,13 +164,13 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl ienv.setIdentity(wg1); UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, cenv); CoursePropertyManager coursePropertyManager = userCourseEnv.getCourseEnvironment().getCoursePropertyManager(); - System.out.println("enrollmentManager=" + enrollmentManager); - System.out.println("bgWithWaitingList=" + bgWithWaitingList); + log.info("enrollmentManager=" + enrollmentManager); + log.info("bgWithWaitingList=" + bgWithWaitingList); assertTrue("bgWithWaitingList is null",bgWithWaitingList != null); - System.out.println("userCourseEnv=" + userCourseEnv); - System.out.println("userCourseEnv.getCourseEnvironment()=" + userCourseEnv.getCourseEnvironment()); + log.info("userCourseEnv=" + userCourseEnv); + log.info("userCourseEnv.getCourseEnvironment()=" + userCourseEnv.getCourseEnvironment()); enrollmentManager.doEnroll(wg1,bgWithWaitingList, enNode, coursePropertyManager,this /*WindowControl mock*/,testTranslator, - new ArrayList()/*enrollableGroupNames*/, new ArrayList()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); + new ArrayList<Long>()/*enrollableGroupNames*/, new ArrayList<Long>()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); assertTrue("Enrollment failed, user='wg1'", businessGroupService.isIdentityInBusinessGroup(wg1,bgWithWaitingList)); int participantsCounter = BaseSecurityManager.getInstance().countIdentitiesOfSecurityGroup(bgWithWaitingList.getPartipiciantGroup()); assertTrue("Wrong number of participants," + participantsCounter , participantsCounter == 1); @@ -167,7 +180,7 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl userCourseEnv = new UserCourseEnvironmentImpl(ienv, cenv); coursePropertyManager = userCourseEnv.getCourseEnvironment().getCoursePropertyManager(); enrollmentManager.doEnroll(wg2,bgWithWaitingList, enNode, coursePropertyManager,this /*WindowControl mock*/,testTranslator, - new ArrayList()/*enrollableGroupNames*/, new ArrayList()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); + new ArrayList<Long>()/*enrollableGroupNames*/, new ArrayList<Long>()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); assertTrue("Enrollment failed, user='wg2'", businessGroupService.isIdentityInBusinessGroup(wg2,bgWithWaitingList)); assertTrue("Enrollment failed, user='wg1'", businessGroupService.isIdentityInBusinessGroup(wg1,bgWithWaitingList)); participantsCounter = BaseSecurityManager.getInstance().countIdentitiesOfSecurityGroup(bgWithWaitingList.getPartipiciantGroup()); @@ -178,7 +191,7 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl userCourseEnv = new UserCourseEnvironmentImpl(ienv, cenv); coursePropertyManager = userCourseEnv.getCourseEnvironment().getCoursePropertyManager(); enrollmentManager.doEnroll(wg3,bgWithWaitingList, enNode, coursePropertyManager,this /*WindowControl mock*/,testTranslator, - new ArrayList()/*enrollableGroupNames*/, new ArrayList()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); + new ArrayList<Long>()/*enrollableGroupNames*/, new ArrayList<Long>()/*enrollableAreaNames*/, userCourseEnv.getCourseEnvironment().getCourseGroupManager()); assertFalse("Wrong enrollment, user='wg3' is in PartipiciantGroup, must be on waiting-list", businessGroupService.isIdentityInBusinessGroup(wg3,bgWithWaitingList)); assertFalse("Wrong enrollment, user='wg3' is in PartipiciantGroup, must be on waiting-list", BaseSecurityManager.getInstance().isIdentityInSecurityGroup(wg3, bgWithWaitingList.getPartipiciantGroup())); assertTrue("Wrong enrollment, user='wg3' must be on waiting-list", BaseSecurityManager.getInstance().isIdentityInSecurityGroup(wg3, bgWithWaitingList.getWaitingGroup())); @@ -228,18 +241,80 @@ public class EnrollmentManagerTest extends OlatTestCase implements WindowControl waitingListCounter = BaseSecurityManager.getInstance().countIdentitiesOfSecurityGroup(bgWithWaitingList.getWaitingGroup()); assertTrue("Wrong number of waiting-list, must be 0, is " + waitingListCounter , waitingListCounter == 0); - System.out.println("testEnroll: done..."); + log.info("testEnroll: done..."); } + @Test + public void testConcurrentEnrollmentWithWaitingList() { + List<Identity> ids = new ArrayList<Identity>(30); + for(int i=0; i<30; i++) { + Identity id = JunitTestHelper.createAndPersistIdentityAsUser("enroll-a-" + i + "-" + UUID.randomUUID().toString()); + ids.add(id); + } + + ENCourseNode enNode = new ENCourseNode(); + OLATResourceable ores = OresHelper.createOLATResourceableTypeWithoutCheck("TestEnrollmentCourse"); + CourseEnvironment cenv = CourseFactory.createEmptyCourse(ores, "Test-Enroll", "Test", "Test enrollment with concurrent users").getCourseEnvironment(); + BusinessGroup group = businessGroupService.createBusinessGroup(id1, "Enrollment", "Enroll", new Integer(1), new Integer(10), true, false, null); + Assert.assertNotNull(group); + dbInstance.commitAndCloseSession(); - /** - * @see junit.framework.TestCase#tearDown() - */ - @After public void tearDown() throws Exception { + final CountDownLatch doneSignal = new CountDownLatch(ids.size()); + for(Identity id:ids) { + EnrollThread thread = new EnrollThread(id, group, enNode, cenv, doneSignal); + thread.start(); + } + try { - DBFactory.getInstance().closeSession(); - } catch (Exception e) { - log.error("tearDown failed: ", e); + boolean interrupt = doneSignal.await(360, TimeUnit.SECONDS); + assertTrue("Test takes too long (more than 10s)", interrupt); + } catch (InterruptedException e) { + fail("" + e.getMessage()); + } + + List<Identity> enrolledIds = securityManager.getIdentitiesOfSecurityGroup(group.getPartipiciantGroup()); + Assert.assertNotNull(enrolledIds); + Assert.assertEquals(10, enrolledIds.size()); + + List<Identity> waitingIds = securityManager.getIdentitiesOfSecurityGroup(group.getWaitingGroup()); + Assert.assertNotNull(waitingIds); + Assert.assertEquals(ids.size() - 10, waitingIds.size()); + } + + + + private class EnrollThread extends Thread { + private final ENCourseNode enNode; + private final Identity identity; + private final CourseEnvironment cenv; + private final BusinessGroup group; + private final CountDownLatch doneSignal; + + public EnrollThread(Identity identity, BusinessGroup group, ENCourseNode enNode, CourseEnvironment cenv, CountDownLatch doneSignal) { + this.enNode = enNode; + this.group = group; + this.identity = identity; + this.cenv = cenv; + this.doneSignal = doneSignal; + } + + @Override + public void run() { + try { + IdentityEnvironment ienv = new IdentityEnvironment(); + ienv.setIdentity(identity); + UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, cenv); + CoursePropertyManager coursePropertyManager = userCourseEnv.getCourseEnvironment().getCoursePropertyManager(); + CourseGroupManager courseGroupManager = userCourseEnv.getCourseEnvironment().getCourseGroupManager(); + + enrollmentManager.doEnroll(identity, group, enNode, coursePropertyManager, EnrollmentManagerTest.this /*WindowControl mock*/, testTranslator, + new ArrayList<Long>()/*enrollableGroupNames*/, new ArrayList<Long>()/*enrollableAreaNames*/, courseGroupManager); + } catch (Exception e) { + log.error("", e); + } finally { + doneSignal.countDown(); + DBFactory.getInstance().commitAndCloseSession(); + } } } diff --git a/src/test/java/org/olat/instantMessaging/IMUnitTest.java b/src/test/java/org/olat/instantMessaging/IMUnitTest.java index 32ddd99e0b6085b6ae2bf68ad1c3563bc156c0ed..b5942fedf4a181249e718c779a3685363dbf28ae 100644 --- a/src/test/java/org/olat/instantMessaging/IMUnitTest.java +++ b/src/test/java/org/olat/instantMessaging/IMUnitTest.java @@ -29,6 +29,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.junit.After; @@ -38,6 +40,7 @@ import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurityManager; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DBFactory; +import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.instantMessaging.ui.ConnectedUsersListEntry; @@ -53,9 +56,11 @@ import org.olat.test.OlatTestCase; * @author guido */ public class IMUnitTest extends OlatTestCase { - String testUserA = "anIdentity1"; - String testUserB = "anIdentity2"; - String testUserC = "testuser@thankyou2010.com"; + private static final OLog log = Tracing.createLoggerFor(OlatTestCase.class); + + private final String testUserA = "anIdentity1"; + private final String testUserB = "anIdentity2"; + private final String testUserC = "testuser@thankyou2010.com"; /** @@ -76,7 +81,7 @@ public class IMUnitTest extends OlatTestCase { DB db = DBFactory.getInstance(); db.closeSession(); } catch (Exception e) { - Tracing.logError("Exception in tearDown(): " + e, IMUnitTest.class); + log.error("Exception in tearDown(): ", e); } } @@ -125,7 +130,10 @@ public class IMUnitTest extends OlatTestCase { assertTrue(im.countConnectedUsers() >= 2); //there is may be as well an admin user connected //add user to roster - im.addUserToFriendsRoster(testUserA, groupId, groupName, testUserB); + List<String> userToAdd = new ArrayList<String>(2); + userToAdd.add(testUserA); + userToAdd.add(testUserB); + im.syncFriendsRoster(groupId, groupName, userToAdd, null); Thread.sleep(1000); assertEquals(1, imClientA.getRoster().getGroup(groupName).getEntryCount()); Thread.sleep(1000); @@ -133,7 +141,7 @@ public class IMUnitTest extends OlatTestCase { Thread.sleep(1000); assertEquals(1, imClientA.getRoster().getGroup(groupName+"ABC").getEntryCount()); Thread.sleep(1000); - im.removeUserFromFriendsRoster(groupId, testUserB); + im.syncFriendsRoster(groupId, groupName, null, Collections.singletonList(testUserB)); Thread.sleep(1000); im.deleteRosterGroup(groupId); Thread.sleep(1000); @@ -157,10 +165,8 @@ public class IMUnitTest extends OlatTestCase { assertTrue(InstantMessagingModule.getAdapter().deleteAccount(testUserB)); } catch (InterruptedException e) { - e.printStackTrace(); + log.error("", e); } - } } - } diff --git a/src/test/java/org/olat/instantMessaging/IMUnitTestWithoutOLAT.java b/src/test/java/org/olat/instantMessaging/IMUnitTestWithoutOLAT.java index cdfe82ecd9b6a2162c4ef84e80fa919e07d8184b..f143cbede363a42be3890a59861ea13fb8f5f34d 100644 --- a/src/test/java/org/olat/instantMessaging/IMUnitTestWithoutOLAT.java +++ b/src/test/java/org/olat/instantMessaging/IMUnitTestWithoutOLAT.java @@ -29,6 +29,9 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; +import java.util.ArrayList; +import java.util.List; + import org.junit.Test; import org.olat.test.MockServletContextWebContextLoader; import org.springframework.test.context.ContextConfiguration; @@ -74,11 +77,17 @@ public class IMUnitTestWithoutOLAT extends AbstractJUnit4SpringContextTests { assertFalse(im.hasAccount(tmpUsername)); assertTrue(im.createAccount(tmpUsername, password, fullname, username + j + email)); assertTrue(im.hasAccount(tmpUsername)); - assertTrue(im.addUserToFriendsRoster(tmpUsermaster, groupId, groupname, tmpUsername)); + List<String> userToAdd = new ArrayList<String>(); + userToAdd.add(tmpUsermaster); + userToAdd.add(tmpUsername); + assertTrue(im.syncFriendsRoster(groupId, groupname, userToAdd, null)); } assertTrue(im.renameRosterGroup(groupId, groupname + "CDEF")); - assertTrue(im.removeUserFromFriendsRoster(groupId, tmpUsermaster)); - assertTrue(im.removeUserFromFriendsRoster(groupId, username + 1)); + + List<String> userToRemove = new ArrayList<String>(); + userToRemove.add(tmpUsermaster); + userToRemove.add(username + 1); + assertTrue(im.syncFriendsRoster(groupId, groupname, null, userToRemove)); assertTrue(im.deleteRosterGroup(groupId)); for (int j = 0; j < 4; j++) { String tmpUsername = username + j;