Package org.olat.group

Source Code of org.olat.group.BusinessGroupManagerImpl

/**
* 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.
* <p>
*/

package org.olat.group;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.hibernate.StaleObjectStateException;
import org.jfree.util.Log;
import org.olat.admin.user.delete.service.UserDeletionManager;
import org.olat.basesecurity.Constants;
import org.olat.basesecurity.Manager;
import org.olat.basesecurity.ManagerFactory;
import org.olat.basesecurity.SecurityGroup;
import org.olat.collaboration.CollaborationTools;
import org.olat.collaboration.CollaborationToolsFactory;
import org.olat.commons.lifecycle.LifeCycleManager;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.commons.persistence.DBQuery;
import org.olat.core.commons.taskExecutor.TaskExecutorManager;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.DBRuntimeException;
import org.olat.core.logging.KnownIssueException;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.Tracing;
import org.olat.core.logging.activity.ActionType;
import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
import org.olat.core.util.FileUtils;
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.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.notifications.NotificationsManager;
import org.olat.core.util.notifications.Subscriber;
import org.olat.core.util.resource.OLATResourceableJustBeforeDeletedEvent;
import org.olat.course.nodes.projectbroker.service.ProjectBrokerManagerFactory;
import org.olat.group.area.BGArea;
import org.olat.group.area.BGAreaManager;
import org.olat.group.area.BGAreaManagerImpl;
import org.olat.group.context.BGContext;
import org.olat.group.context.BGContextManager;
import org.olat.group.context.BGContextManagerImpl;
import org.olat.group.delete.service.GroupDeletionManager;
import org.olat.group.properties.BusinessGroupPropertyManager;
import org.olat.group.right.BGRightManager;
import org.olat.group.right.BGRightManagerImpl;
import org.olat.group.ui.BGConfigFlags;
import org.olat.group.ui.BGMailHelper;
import org.olat.group.ui.edit.BusinessGroupModifiedEvent;
import org.olat.instantMessaging.InstantMessagingModule;
import org.olat.instantMessaging.syncservice.SyncSingleUserTask;
import org.olat.notifications.NotificationsManagerImpl;
import org.olat.repository.RepoJumpInHandlerFactory;
import org.olat.repository.RepositoryEntry;
import org.olat.testutils.codepoints.server.Codepoint;
import org.olat.user.UserDataDeletable;
import org.olat.util.logging.activity.LoggingResourceable;

import com.anthonyeden.lib.config.Configuration;
import com.anthonyeden.lib.config.ConfigurationException;
import com.anthonyeden.lib.config.Dom4jConfiguration;
import com.anthonyeden.lib.config.MutableConfiguration;
import com.anthonyeden.lib.config.XMLConfiguration;

/**
* Description:<br>
* Persisting implementation of the business group manager. Persists the data in
* the database.
* <P>
* Initial Date: Jul 28, 2004 <br>
*
* @author patrick
*/
public class BusinessGroupManagerImpl implements BusinessGroupManager, UserDataDeletable {

  private static final BusinessGroupManager INSTANCE = new BusinessGroupManagerImpl();

  private static final String EXPORT_ATTR_NAME = "name";
  private static final String EXPORT_ATTR_MAX_PARTICIPATS = "maxParticipants";
  private static final String EXPORT_ATTR_MIN_PARTICIPATS = "minParticipants";
  private static final String EXPORT_ATTR_WAITING_LIST = "waitingList";
  private static final String EXPORT_ATTR_AUTO_CLOSE_RANKS = "autoCloseRanks";
  private static final String EXPORT_KEY_AREA_RELATION = "AreaRelation";
  private static final String EXPORT_KEY_GROUP = "Group";
  private static final String EXPORT_KEY_GROUP_COLLECTION = "GroupCollection";
  private static final String EXPORT_KEY_AREA = "Area";
  private static final String EXPORT_KEY_AREA_COLLECTION = "AreaCollection";
  private static final String EXPORT_KEY_ROOT = "OLATGroupExport";
  private static final String EXPORT_KEY_DESCRIPTION = "Description";
  private static final String EXPORT_KEY_COLLABTOOLS = "CollabTools";
  private static final String EXPORT_KEY_SHOW_OWNERS = "showOwners";
  private static final String EXPORT_KEY_SHOW_PARTICIPANTS = "showParticipants";
  private static final String EXPORT_KEY_SHOW_WAITING_LIST = "showWaitingList";
  private static final String EXPORT_KEY_CALENDAR_ACCESS = "calendarAccess";
  private static final String EXPORT_KEY_NEWS = "info";

  private Manager securityManager;
  private List<DeletableGroupData> deleteListeners;
 
  /**
   * @return singleton instance
   */
  public static BusinessGroupManager getInstance() {
    return INSTANCE;
  }

  private BusinessGroupManagerImpl() {
    UserDeletionManager.getInstance().registerDeletableUserData(this);
    securityManager = ManagerFactory.getManager();
    deleteListeners = new ArrayList<DeletableGroupData>();
  }

  /**
   * @see org.olat.group.BusinessGroupManager#createAndPersistBusinessGroup(java.lang.String, org.olat.core.id.Identity, java.lang.String, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Boolean, java.lang.Boolean, org.olat.group.context.BGContext)
   */
  public BusinessGroup createAndPersistBusinessGroup(String type, Identity identity, String name, String description,
      Integer minParticipants, Integer maxParticipants, Boolean enableWaitinglist, Boolean enableAutoCloseRanks, BGContext groupContext) {
    BusinessGroup grp = BusinessGroupFactory.createAndPersistBusinessGroup(type, identity, name, description, minParticipants,
        maxParticipants, enableWaitinglist, enableAutoCloseRanks, groupContext);
    if (grp != null) {
      Tracing.logAudit("Created Business Group", grp.toString(), this.getClass());
    }
    // else no group created
    return grp;
  }

  /**
   * check if all given names in context exists.
   * @param names
   * @param groupContext
   * @return
   */
  protected boolean checkIfOneOrMoreNameExistsInContext(Set names, BGContext groupContext){
    return BusinessGroupFactory.checkIfOneOrMoreNameExistsInContext(names, groupContext);
  }
 
  /**
   * @see org.olat.group.BusinessGroupManager#findBusinessGroupsOwnedBy(java.lang.String,
   *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
   */
  public List findBusinessGroupsOwnedBy(String type, Identity identityP, BGContext bgContext) {
    // attach group context to session - maybe a proxy...
    String query = "select bgi from " + " org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi,"
        + " org.olat.group.BusinessGroupImpl as bgi" + " where bgi.ownerGroup = sgmi.securityGroup and sgmi.identity = :identId";
    if (bgContext != null) query = query + " and bgi.groupContext = :context";
    if (type != null) query = query + " and bgi.type = :type";

    DB db = DBFactory.getInstance();
    DBQuery dbq = db.createQuery(query);
    /*
     * query.append("select distinct v from" + "
     * org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi," + "
     * org.olat.repository.RepositoryEntry v" + " inner join fetch v.ownerGroup
     * as secGroup" + " inner join fetch v.olatResource as res where" + "
     * sgmsi.securityGroup = secGroup and sgmsi.identity.key=");
     */

    dbq.setLong("identId", identityP.getKey().longValue());
    if (bgContext != null) dbq.setEntity("context", bgContext);
    if (type != null) dbq.setString("type", type);

    List res = dbq.list();
    return res;
  }

  /**
   * @see org.olat.group.BusinessGroupManager#findBusinessGroupsAttendedBy(java.lang.String,
   *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
   */
  public List findBusinessGroupsAttendedBy(String type, Identity identityP, BGContext bgContext) {
    String query = "select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi "
        + ", org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi"
        + " where bgi.partipiciantGroup = sgmi.securityGroup";
    query = query + " and sgmi.identity = :identId";
    if (bgContext != null) query = query + " and bgi.groupContext = :context";
    if (type != null) query = query + " and bgi.type = :type";

    DB db = DBFactory.getInstance();
    DBQuery dbq = db.createQuery(query);
    dbq.setLong("identId", identityP.getKey().longValue());
    if (bgContext != null) dbq.setEntity("context", bgContext);
    if (type != null) dbq.setString("type", type);

    List res = dbq.list();
    return res;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#getAllBusinessGroups()
   */
  public List getAllBusinessGroups() {
    DBQuery dbq = DBFactory.getInstance().createQuery("select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi ");
    return dbq.list();
  }
 
  /**
   * @see org.olat.group.BusinessGroupManager#findBusinessGroupsAttendedBy(java.lang.String,
   *      org.olat.core.id.Identity, org.olat.group.context.BGContext)
   */
  public List findBusinessGroupsWithWaitingListAttendedBy(String type, Identity identityP, BGContext bgContext) {
    String query = "select bgi from " + "  org.olat.group.BusinessGroupImpl as bgi "
        + ", org.olat.basesecurity.SecurityGroupMembershipImpl as sgmi"
        + " where bgi.waitingGroup = sgmi.securityGroup and sgmi.identity = :identId";
    if (bgContext != null) query = query + " and bgi.groupContext = :context";
    if (type != null) query = query + " and bgi.type = :type";

    DB db = DBFactory.getInstance();
    DBQuery dbq = db.createQuery(query);
    dbq.setLong("identId", identityP.getKey().longValue());
    if (bgContext != null) dbq.setEntity("context", bgContext);
    if (type != null) dbq.setString("type", type);

    List res = dbq.list();
    return res;
  }

  /**
   * @see org.olat.group.BusinessGroupManager#updateBusinessGroup(org.olat.group.BusinessGroup)
   */
  public void updateBusinessGroup(BusinessGroup updatedBusinessGroup) {
    updatedBusinessGroup.setLastModified(new Date());
    DBFactory.getInstance().updateObject(updatedBusinessGroup);
  }

  /**
   * @see org.olat.group.BusinessGroupManager#deleteBusinessGroup(org.olat.group.BusinessGroup)
   */
  public void deleteBusinessGroup(BusinessGroup businessGroupTodelete) {
    try{
      OLATResourceableJustBeforeDeletedEvent delEv = new OLATResourceableJustBeforeDeletedEvent(businessGroupTodelete);
      // notify all (currently running) BusinessGroupXXXcontrollers
      // about the deletion which will occur.
      CoordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(delEv, businessGroupTodelete);
 
      String type = businessGroupTodelete.getType();
      // refresh object to avoid stale object exceptions
      businessGroupTodelete = loadBusinessGroup(businessGroupTodelete);
      // 0) Loop over all deletableGroupData
      for (DeletableGroupData deleteListener : deleteListeners) {
        Log.debug("deleteBusinessGroup: call deleteListener=" + deleteListener);
        deleteListener.deleteGroupDataFor(businessGroupTodelete);
      }
      ProjectBrokerManagerFactory.getProjectBrokerManager().deleteGroupDataFor(businessGroupTodelete);
      // 1) Delete all group properties
      CollaborationTools ct = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(businessGroupTodelete);
      ct.deleteTools(businessGroupTodelete);// deletes everything concerning properties&collabTools
      // 1.b)delete display member property
      BusinessGroupPropertyManager bgpm = new BusinessGroupPropertyManager(businessGroupTodelete);
      bgpm.deleteDisplayMembers();
      // 2) Delete the group areas
      if (BusinessGroup.TYPE_LEARNINGROUP.equals(type)) {
        BGAreaManagerImpl.getInstance().deleteBGtoAreaRelations(businessGroupTodelete);
      }
      // 3) Delete the group object itself on the database
      DBFactory.getInstance().deleteObject(businessGroupTodelete);
      // 4) Delete the associated security groups
      if (BusinessGroup.TYPE_BUDDYGROUP.equals(type) || BusinessGroup.TYPE_LEARNINGROUP.equals(type)) {
        SecurityGroup owners = businessGroupTodelete.getOwnerGroup();
        securityManager.deleteSecurityGroup(owners);
      }
      // in all cases the participant groups
      SecurityGroup partips = businessGroupTodelete.getPartipiciantGroup();
      securityManager.deleteSecurityGroup(partips);
      // Delete waiting-group when one exists
      if (businessGroupTodelete.getWaitingGroup() != null) {
        securityManager.deleteSecurityGroup(businessGroupTodelete.getWaitingGroup());
      }
 
      // delete the publisher attached to this group (e.g. the forum and folder
      // publisher)
      NotificationsManagerImpl.getInstance().deletePublishersOf(businessGroupTodelete);
 
      // delete potential jabber group roster
      if (InstantMessagingModule.isEnabled()) {
        String groupID = InstantMessagingModule.getAdapter().createChatRoomString(businessGroupTodelete);
        InstantMessagingModule.getAdapter().deleteRosterGroup(groupID);
      }
      Tracing.logAudit("Deleted Business Group", businessGroupTodelete.toString(), this.getClass());
    } catch(DBRuntimeException dbre) {
      Throwable th = dbre.getCause();
      if ((th instanceof StaleObjectStateException) &&
          (th.getMessage().startsWith("Row was updated or deleted by another transaction"))) {
        // known issue OLAT-3654
        Tracing.logInfo("Group was deleted by another user in the meantime. Known issue OLAT-3654", this.getClass());
        throw new KnownIssueException("Group was deleted by another user in the meantime", 3654);
      } else {
        throw dbre;
      }
    }
  }

  /**
   * @see org.olat.group.BusinessGroupManager#deleteBusinessGroupWithMail(org.olat.group.BusinessGroup,
   *      org.olat.core.gui.control.WindowControl, org.olat.core.gui.UserRequest,
   *      org.olat.core.gui.translator.Translator, java.util.List)
   */
  public void deleteBusinessGroupWithMail(BusinessGroup businessGroupTodelete, WindowControl wControl, UserRequest ureq, Translator trans,
      List contactLists) {
    Codepoint.codepoint(this.getClass(), "deleteBusinessGroupWithMail");
   
    // collect data for mail
    Manager secMgr = ManagerFactory.getManager();
    List users = new ArrayList();
    SecurityGroup ownerGroup = businessGroupTodelete.getOwnerGroup();
    if (ownerGroup != null) {
      List owner = secMgr.getIdentitiesOfSecurityGroup(ownerGroup);
      users.addAll(owner);
    }
    SecurityGroup partGroup = businessGroupTodelete.getPartipiciantGroup();
    if (partGroup != null) {
      List participants = secMgr.getIdentitiesOfSecurityGroup(partGroup);
      users.addAll(participants);
    }
    SecurityGroup watiGroup = businessGroupTodelete.getWaitingGroup();
    if (watiGroup != null) {
      List waiting = secMgr.getIdentitiesOfSecurityGroup(watiGroup);
      users.addAll(waiting);
    }
    // now delete the group first
    deleteBusinessGroup(businessGroupTodelete);
    // finally send email
    MailerWithTemplate mailer = MailerWithTemplate.getInstance();
    MailTemplate mailTemplate = BGMailHelper.createDeleteGroupMailTemplate(businessGroupTodelete, ureq.getIdentity());
    if (mailTemplate != null) {
      MailerResult mailerResult = mailer.sendMailAsSeparateMails(users, null, null, mailTemplate, null);
      MailHelper.printErrorsAndWarnings(mailerResult, wControl, ureq.getLocale());
    }
   
  }

  /**
   * @see org.olat.group.BusinessGroupManager#deleteBusinessGroups(java.util.List)
   */
  public void deleteBusinessGroups(List businessGroups) {
    Iterator iterator = businessGroups.iterator();
    while (iterator.hasNext()) {
      BusinessGroup group = (BusinessGroup) iterator.next();
      deleteBusinessGroup(group);
    }
  }

  /**
   * @see org.olat.group.BusinessGroupManager#isIdentityInBusinessGroup(org.olat.core.id.Identity,
   *      java.lang.String, org.olat.group.context.BGContext)
   */
  public boolean isIdentityInBusinessGroup(Identity identity, String groupName, BGContext groupContext) {
    DB db = DBFactory.getInstance();
    StringBuilder q = new StringBuilder();
    q.append(" select count(grp) from").append(" org.olat.group.BusinessGroupImpl as grp,").append(
        " org.olat.basesecurity.SecurityGroupMembershipImpl as secgmemb").append(" where");
    if (groupContext != null) {
      q.append(" grp.groupContext = :context and");
    }
    q.append(" grp.name = :name").append(" and ((grp.partipiciantGroup = secgmemb.securityGroup").append(" and secgmemb.identity = :id) ")
        .append(" or (grp.ownerGroup = secgmemb.securityGroup").append(" and secgmemb.identity = :id)) ");
    DBQuery query = db.createQuery(q.toString());
    query.setEntity("id", identity);
    if (groupContext != null) {
      query.setEntity("context", groupContext);
    }
    query.setString("name", groupName);
    query.setCacheable(true);
    List result = query.list();
    if (result.size() == 0) return false;
    return ( ((Long) result.get(0)).intValue() > 0);
  }

  /**
   * @see org.olat.group.BusinessGroupManager#isIdentityInBusinessGroup(org.olat.core.id.Identity,
   *      org.olat.group.BusinessGroup)
   */
  public boolean isIdentityInBusinessGroup(Identity identity, BusinessGroup businessGroup) {
    SecurityGroup participants = businessGroup.getPartipiciantGroup();
    SecurityGroup owners = businessGroup.getOwnerGroup();
    if (participants != null) {
      if (securityManager.isIdentityInSecurityGroup(identity, participants)) return true;
    }
    if (owners != null) {
      if (securityManager.isIdentityInSecurityGroup(identity, owners)) return true;
    }
    return false;
  }

  /**
   * @see org.olat.group.BusinessGroupManager#loadBusinessGroup(org.olat.group.BusinessGroup)
   */
  public BusinessGroup loadBusinessGroup(BusinessGroup currBusinessGroup) {
    return (BusinessGroup) DBFactory.getInstance().loadObject(currBusinessGroup);
  }

  /**
   * @see org.olat.group.BusinessGroupManager#loadBusinessGroup(java.lang.Long,
   *      boolean)
   */
  public BusinessGroup loadBusinessGroup(Long groupKey, boolean strict) {
    if (strict) return (BusinessGroup) DBFactory.getInstance().loadObject(BusinessGroupImpl.class, groupKey);
    return (BusinessGroup) DBFactory.getInstance().findObject(BusinessGroupImpl.class, groupKey);
  }

  /**
   * @see org.olat.group.BusinessGroupManager#copyBusinessGroup(org.olat.group.BusinessGroup,
   *      java.lang.String, java.lang.String, java.lang.Integer,
   *      java.lang.Integer, org.olat.group.context.BGContext, java.util.Map,
   *      boolean, boolean, boolean, boolean, boolean, boolean)
   */
  public BusinessGroup copyBusinessGroup(BusinessGroup sourceBusinessGroup, String targetName, String targetDescription, Integer targetMin,
      Integer targetMax, BGContext targetBgContext, Map areaLookupMap, boolean copyAreas, boolean copyCollabToolConfig, boolean copyRights,
      boolean copyOwners, boolean copyParticipants, boolean copyMemberVisibility, boolean copyWaitingList) {

    // 1. create group
    String bgType = sourceBusinessGroup.getType();
    // create group, set waitingListEnabled, enableAutoCloseRanks like source business-group
    BusinessGroup newGroup = createAndPersistBusinessGroup(bgType, null, targetName, targetDescription, targetMin, targetMax,
        sourceBusinessGroup.getWaitingListEnabled(), sourceBusinessGroup.getAutoCloseRanksEnabled(), targetBgContext);
    // return immediately with null value to indicate an already take groupname
    if (newGroup == null) { return null; }
    // 2. copy tools
    if (copyCollabToolConfig) {
      CollaborationToolsFactory toolsF = CollaborationToolsFactory.getInstance();
      // get collab tools from original group and the new group
      CollaborationTools oldTools = toolsF.getOrCreateCollaborationTools(sourceBusinessGroup);
      CollaborationTools newTools = toolsF.getOrCreateCollaborationTools(newGroup);
      // copy the collab tools settings
      for (int i = 0; i < CollaborationTools.TOOLS.length; i++) {
        String tool = CollaborationTools.TOOLS[i];
        newTools.setToolEnabled(tool, oldTools.isToolEnabled(tool));
      }     
      String oldNews = oldTools.lookupNews();
      newTools.saveNews(oldNews);
    }
    // 3. copy member visibility
    if (copyMemberVisibility) {
      BusinessGroupPropertyManager bgpm = new BusinessGroupPropertyManager(newGroup);
      bgpm.copyConfigurationFromGroup(sourceBusinessGroup);
    }
    // 4. copy areas
    if (copyAreas) {
      BGAreaManager areaManager = BGAreaManagerImpl.getInstance();
      List areas = areaManager.findBGAreasOfBusinessGroup(sourceBusinessGroup);
      Iterator iterator = areas.iterator();
      while (iterator.hasNext()) {
        BGArea area = (BGArea) iterator.next();
        if (areaLookupMap == null) {
          // reference target group to source groups areas
          areaManager.addBGToBGArea(newGroup, area);
        } else {
          // reference target group to mapped group areas
          BGArea mappedArea = (BGArea) areaLookupMap.get(area);
          areaManager.addBGToBGArea(newGroup, mappedArea);
        }
      }
    }
    // 5. copy owners
    if (copyOwners) {
      List owners = securityManager.getIdentitiesOfSecurityGroup(sourceBusinessGroup.getOwnerGroup());
      Iterator iter = owners.iterator();
      while (iter.hasNext()) {
        Identity identity = (Identity) iter.next();
        securityManager.addIdentityToSecurityGroup(identity, newGroup.getOwnerGroup());
      }
    }
    // 6. copy participants
    if (copyParticipants) {
      List participants = securityManager.getIdentitiesOfSecurityGroup(sourceBusinessGroup.getPartipiciantGroup());
      Iterator iter = participants.iterator();
      while (iter.hasNext()) {
        Identity identity = (Identity) iter.next();
        securityManager.addIdentityToSecurityGroup(identity, newGroup.getPartipiciantGroup());
      }
    }
    // 7. copy rights
    if (copyRights) {
      BGRightManager rightManager = BGRightManagerImpl.getInstance();
      List sourceRights = rightManager.findBGRights(sourceBusinessGroup);
      Iterator iterator = sourceRights.iterator();
      while (iterator.hasNext()) {
        String sourceRight = (String) iterator.next();
        rightManager.addBGRight(sourceRight, newGroup);
      }
    }
    // 8. copy waiting-lisz
    if (copyWaitingList) {
      List waitingList = securityManager.getIdentitiesOfSecurityGroup(sourceBusinessGroup.getWaitingGroup());
      Iterator iter = waitingList.iterator();
      while (iter.hasNext()) {
        Identity identity = (Identity) iter.next();
        securityManager.addIdentityToSecurityGroup(identity, newGroup.getWaitingGroup());
      }
    }
    return newGroup;

  }

  /**
   * @see org.olat.group.BusinessGroupManager#addParticipant(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void addParticipantAndFireEvent(Identity ureqIdentity, final Identity identity, final BusinessGroup group, BGConfigFlags flags,
      boolean doOnlyPostAddingStuff) {
    CoordinatorManager.getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
    if (!doOnlyPostAddingStuff) {
      securityManager.addIdentityToSecurityGroup(identity, group.getPartipiciantGroup());
    }
    // add user to buddies rosters
    addToRoster(ureqIdentity, identity, group, flags);
    // notify currently active users of this business group
    BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_PARTICIPANT_ADDED, getClass(), LoggingResourceable.wrap(identity));
    // send notification mail in your controller!
  }

  /**
   * @see org.olat.group.BusinessGroupManager#addOwner(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void addOwnerAndFireEvent(Identity ureqIdentity, Identity identity, BusinessGroup group, BGConfigFlags flags,
      boolean doOnlyPostAddingStuff) {
    if (!doOnlyPostAddingStuff) {
      securityManager.addIdentityToSecurityGroup(identity, group.getOwnerGroup());
    }
    // add user to buddies rosters
    addToRoster(ureqIdentity, identity, group, flags);
    // notify currently active users of this business group
    BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_ADDED, getClass(), LoggingResourceable.wrap(identity));
    // send notification mail in your controller!
  }

  /**
   * @see org.olat.group.BusinessGroupManager#removeOwner(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void removeOwnerAndFireEvent(Identity ureqIdentity, Identity identity, BusinessGroup group, BGConfigFlags flags,
      boolean doOnlyPostRemovingStuff) {
    if (!doOnlyPostRemovingStuff) {
      securityManager.removeIdentityFromSecurityGroup(identity, group.getOwnerGroup());
    }
    // remove user from buddies rosters
    removeFromRoster(identity, group, flags);
   
    //remove subsciptions if user gets removed
    removeSubscriptions(identity, group);
   
    // notify currently active users of this business group
    if (identity.getKey().equals(ureqIdentity.getKey()) ) {
      BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.MYSELF_ASOWNER_REMOVED_EVENT, group, identity);
    } else {
      BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, group, identity);
    }
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_OWNER_REMOVED, getClass(),
        LoggingResourceable.wrap(group), LoggingResourceable.wrap(identity));
    // send notification mail in your controller!
  }

  /**
   * @see org.olat.group.BusinessGroupManager#removeParticipant(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void removeParticipantAndFireEvent(final Identity ureqIdentity, final Identity identity, final BusinessGroup group, final BGConfigFlags flags,
      final boolean doOnlyPostRemovingStuff) {
    CoordinatorManager.getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
    if (!doOnlyPostRemovingStuff) {
      securityManager.removeIdentityFromSecurityGroup(identity, group.getPartipiciantGroup());
    }
    // remove user from buddies rosters
    removeFromRoster(identity, group, flags);
   
    //remove subsciptions if user gets removed
    removeSubscriptions(identity, group);
   
    // notify currently active users of this business group
    BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, group, identity);
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_PARTICIPANT_REMOVED, getClass(), LoggingResourceable.wrap(identity), LoggingResourceable.wrap(group));
    // 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, flags);
   
    // send notification mail in your controller!
  }

  /**
   * @see org.olat.group.BusinessGroupManager#addParticipant(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void addToWaitingListAndFireEvent(Identity ureqIdentity, final Identity identity, final BusinessGroup group,
      boolean doOnlyPostAddingStuff) {
    CoordinatorManager.getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
    if (!doOnlyPostAddingStuff) {
      securityManager.addIdentityToSecurityGroup(identity, group.getWaitingGroup());
    }
    // notify currently active users of this business group
    BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_ADDED_EVENT, group, identity);
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_TO_WAITING_LIST_ADDED, getClass(), LoggingResourceable.wrap(identity));
    // send notification mail in your controller!
  }
 
  /**
   * @see org.olat.group.BusinessGroupManager#removeFromWaitingListAndFireEvent(org.olat.core.gui.control.WindowControl,
   *      org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator,
   *      org.olat.core.id.Identity, org.olat.group.BusinessGroup,
   *      org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger,
   *      boolean)
   */
  public void removeFromWaitingListAndFireEvent(Identity userRequestIdentity, final Identity identity, final BusinessGroup group,
      boolean doOnlyPostRemovingStuff) {
    CoordinatorManager.getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
    if (!doOnlyPostRemovingStuff) {
      securityManager.removeIdentityFromSecurityGroup(identity, group.getWaitingGroup());
    }
    // notify currently active users of this business group
    BusinessGroupModifiedEvent.fireModifiedGroupEvents(BusinessGroupModifiedEvent.IDENTITY_REMOVED_EVENT, group, identity);
    // do logging
    ThreadLocalUserActivityLogger.log(GroupLoggingAction.GROUP_FROM_WAITING_LIST_REMOVED, getClass(), LoggingResourceable.wrap(identity));
    // send notification mail in your controller!
  }
 
  /**
   * @see org.olat.group.BusinessGroupManager#exportGroups(org.olat.group.context.BGContext,
   *      java.io.File)
   */
  public void exportGroups(BGContext context, File fExportFile) {
    if (context == null) return; // nothing to do... says Florian.
    Dom4jConfiguration root = new Dom4jConfiguration(EXPORT_KEY_ROOT);

    // export areas
    MutableConfiguration confAreas = root.addChild(EXPORT_KEY_AREA_COLLECTION);
    BGAreaManager am = BGAreaManagerImpl.getInstance();
    List areas = am.findBGAreasOfBGContext(context);
    for (Iterator iter = areas.iterator(); iter.hasNext();) {
      BGArea area = (BGArea) iter.next();
      MutableConfiguration newArea = confAreas.addChild(EXPORT_KEY_AREA);
      newArea.addAttribute(EXPORT_ATTR_NAME, area.getName());
      newArea.addChild(EXPORT_KEY_DESCRIPTION, area.getDescription());
    }

    // TODO fg: export group rights

    // export groups
    MutableConfiguration confGroups = root.addChild(EXPORT_KEY_GROUP_COLLECTION);
    BGContextManager cm = BGContextManagerImpl.getInstance();
    List groups = cm.getGroupsOfBGContext(context);
    for (Iterator iter = groups.iterator(); iter.hasNext();) {
      BusinessGroup group = (BusinessGroup) iter.next();
      exportGroup(fExportFile, confGroups, group);
    }

    saveGroupConfiguration(fExportFile, root);
  }

  public void exportGroup(BusinessGroup group, File fExportFile) {
    Dom4jConfiguration root = new Dom4jConfiguration(EXPORT_KEY_ROOT);
    MutableConfiguration confGroups = root.addChild(EXPORT_KEY_GROUP_COLLECTION);
    exportGroup(fExportFile, confGroups, group);
    saveGroupConfiguration(fExportFile, root);
  }

  private void exportGroup(File fExportFile, MutableConfiguration confGroups, BusinessGroup group) {
    MutableConfiguration newGroup = confGroups.addChild(EXPORT_KEY_GROUP);
    newGroup.addAttribute(EXPORT_ATTR_NAME, group.getName());
    if (group.getMinParticipants() != null) newGroup.addAttribute(EXPORT_ATTR_MIN_PARTICIPATS, group.getMinParticipants());
    if (group.getMaxParticipants() != null) newGroup.addAttribute(EXPORT_ATTR_MAX_PARTICIPATS, group.getMaxParticipants());     
    if (group.getWaitingListEnabled() != null) newGroup.addAttribute(EXPORT_ATTR_WAITING_LIST, group.getWaitingListEnabled());
    if (group.getAutoCloseRanksEnabled() != null) newGroup.addAttribute(EXPORT_ATTR_AUTO_CLOSE_RANKS, group.getAutoCloseRanksEnabled());
    newGroup.addChild(EXPORT_KEY_DESCRIPTION, group.getDescription());
    // collab tools
    MutableConfiguration toolsConfig = newGroup.addChild(EXPORT_KEY_COLLABTOOLS);
    CollaborationTools ct = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(group);
    for (int i = 0; i < CollaborationTools.TOOLS.length; i++) {
      toolsConfig.addAttribute(CollaborationTools.TOOLS[i], ct.isToolEnabled(CollaborationTools.TOOLS[i]) ? "true" : "false");
    }
    Long calendarAccess = ct.lookupCalendarAccess();
    if (calendarAccess != null) {
      newGroup.addAttribute(EXPORT_KEY_CALENDAR_ACCESS,calendarAccess);     
    }
    String info = ct.lookupNews();
    if(info!=null && !info.trim().equals("")) {
      newGroup.addAttribute(EXPORT_KEY_NEWS,info.trim());     
    }   
   
    Tracing.logDebug("fExportFile.getParent()=" + fExportFile.getParent(), this.getClass());
    ct.archive(fExportFile.getParent());
    // export membership
    List bgAreas = BGAreaManagerImpl.getInstance().findBGAreasOfBusinessGroup(group);
    for (Iterator iterator = bgAreas.iterator(); iterator.hasNext();) {
      BGArea areaRelation = (BGArea) iterator.next();
      MutableConfiguration newGroupAreaRel = newGroup.addChild(EXPORT_KEY_AREA_RELATION);
      newGroupAreaRel.setValue(areaRelation.getName());
    }
    //export properties
    BusinessGroupPropertyManager bgPropertyManager = new BusinessGroupPropertyManager(group);
    boolean showOwners = bgPropertyManager.showOwners();
    boolean showParticipants = bgPropertyManager.showPartips();
    boolean showWaitingList = bgPropertyManager.showWaitingList();
   
    newGroup.addAttribute(EXPORT_KEY_SHOW_OWNERS, showOwners);   
    newGroup.addAttribute(EXPORT_KEY_SHOW_PARTICIPANTS, showParticipants);   
    newGroup.addAttribute(EXPORT_KEY_SHOW_WAITING_LIST, showWaitingList);   
  }

  private void saveGroupConfiguration(File fExportFile, Dom4jConfiguration root) {
    FileOutputStream fOut = null;
    try {
      fOut = new FileOutputStream(fExportFile);
      root.save(fOut);
    } catch (IOException ioe) {
      throw new OLATRuntimeException("Error writing group configuration during group export.", ioe);
    } catch (ConfigurationException cfe) {
      throw new OLATRuntimeException("Error writing group configuration during group export.", cfe);
    } finally {
      FileUtils.closeSafely(fOut);
    }
  }

  /**
   * @see org.olat.group.BusinessGroupManager#importGroups(org.olat.group.context.BGContext,
   *      java.io.File)
   */
  public void importGroups(BGContext context, File fGroupExportXML) {
    if (!fGroupExportXML.exists()) return;

    Configuration groupConfig = null;
    try {
      groupConfig = new XMLConfiguration(fGroupExportXML);
    } catch (ConfigurationException ce) {
      throw new OLATRuntimeException("Error importing group config.", ce);
    }
    if (!groupConfig.getName().equals(EXPORT_KEY_ROOT)) throw new AssertException("Invalid group export file. Root does not match.");

    // get areas
    BGAreaManager am = BGAreaManagerImpl.getInstance();
    Configuration confAreas = groupConfig.getChild(EXPORT_KEY_AREA_COLLECTION);
    if (confAreas != null) {
      List areas = confAreas.getChildren(EXPORT_KEY_AREA);
      for (Iterator iter = areas.iterator(); iter.hasNext();) {
        Configuration area = (Configuration) iter.next();
        String areaName = area.getAttribute(EXPORT_ATTR_NAME);
        String areaDesc = area.getChildValue(EXPORT_KEY_DESCRIPTION);
        am.createAndPersistBGAreaIfNotExists(areaName, areaDesc, context);
      }
    }

    // TODO fg: import group rights

    // get groups
    Configuration confGroups = groupConfig.getChild(EXPORT_KEY_GROUP_COLLECTION);
    if (confGroups != null) {
      BusinessGroupManager gm = BusinessGroupManagerImpl.getInstance();
      List groups = confGroups.getChildren(EXPORT_KEY_GROUP);
      for (Iterator iter = groups.iterator(); iter.hasNext();) {
        // create group
        Configuration group = (Configuration) iter.next();
        String groupName = group.getAttribute(EXPORT_ATTR_NAME);
        String groupDesc = group.getChildValue(EXPORT_KEY_DESCRIPTION);

        // get min/max participants
        Integer groupMinParticipants = null;
        String sMinParticipants = group.getAttribute(EXPORT_ATTR_MIN_PARTICIPATS);
        if (sMinParticipants != null) groupMinParticipants = new Integer(sMinParticipants);
        Integer groupMaxParticipants = null;
        String sMaxParticipants = group.getAttribute(EXPORT_ATTR_MAX_PARTICIPATS);
        if (sMaxParticipants != null) groupMaxParticipants = new Integer(sMaxParticipants);

        // waiting list configuration
        String waitingListConfig = group.getAttribute(EXPORT_ATTR_WAITING_LIST);
        Boolean waitingList = null;
        if (waitingListConfig == null) {
          waitingList = Boolean.FALSE;
        } else {
          waitingList = Boolean.valueOf(waitingListConfig);
        }
        String enableAutoCloseRanksConfig = group.getAttribute(EXPORT_ATTR_AUTO_CLOSE_RANKS);
        Boolean enableAutoCloseRanks = null;
        if (enableAutoCloseRanksConfig == null) {
          enableAutoCloseRanks = Boolean.FALSE;
        } else {
          enableAutoCloseRanks = Boolean.valueOf(enableAutoCloseRanksConfig);
        }
       
        BusinessGroup newGroup = gm.createAndPersistBusinessGroup(context.getGroupType(), null, groupName, groupDesc, groupMinParticipants,
            groupMaxParticipants, waitingList, enableAutoCloseRanks, context);

        // get tools config
        Configuration toolsConfig = group.getChild(EXPORT_KEY_COLLABTOOLS);
        CollaborationTools ct = CollaborationToolsFactory.getInstance().getOrCreateCollaborationTools(newGroup);
        for (int i = 0; i < CollaborationTools.TOOLS.length; i++) {
          String sTool = toolsConfig.getAttribute(CollaborationTools.TOOLS[i]);
          if (sTool != null) ct.setToolEnabled(CollaborationTools.TOOLS[i], sTool.equals("true") ? true : false);
        }
        if(group.getAttribute(EXPORT_KEY_CALENDAR_ACCESS)!=null) {
          Long calendarAccess = Long.valueOf(group.getAttribute(EXPORT_KEY_CALENDAR_ACCESS));
          ct.saveCalendarAccess(calendarAccess);         
        }
        if(group.getAttribute(EXPORT_KEY_NEWS)!=null) {
          String info = group.getAttribute(EXPORT_KEY_NEWS);
          ct.saveNews(info);        
        }

        // get memberships
        List memberships = group.getChildren(EXPORT_KEY_AREA_RELATION);
        for (Iterator iterator = memberships.iterator(); iterator.hasNext();) {
          Configuration areaRelation = (Configuration) iterator.next();
          BGArea area = am.findBGArea(areaRelation.getValue(), context);
          if (area == null) throw new AssertException("Group-Area-Relationship in export, but area was not created during import.");
          am.addBGToBGArea(newGroup, area);
        }
       
        //get properties
        boolean showOwners = true;
        boolean showParticipants = true;
        boolean showWaitingList = true;       
        if(group.getAttribute(EXPORT_KEY_SHOW_OWNERS)!=null) {
          showOwners = Boolean.valueOf(group.getAttribute(EXPORT_KEY_SHOW_OWNERS));
        }
        if(group.getAttribute(EXPORT_KEY_SHOW_PARTICIPANTS)!=null) {
          showParticipants = Boolean.valueOf(group.getAttribute(EXPORT_KEY_SHOW_PARTICIPANTS));
        }
        if(group.getAttribute(EXPORT_KEY_SHOW_WAITING_LIST)!=null) {
          showWaitingList = Boolean.valueOf(group.getAttribute(EXPORT_KEY_SHOW_WAITING_LIST));
        }
        BusinessGroupPropertyManager bgPropertyManager = new BusinessGroupPropertyManager(newGroup);
        bgPropertyManager.updateDisplayMembers(showOwners, showParticipants, showWaitingList);
      }
    }
  }
 
  /**
   *
   * @see org.olat.group.BusinessGroupManager#moveIdenitFromWaitingListToParticipant(org.olat.core.id.Identity, org.olat.core.gui.control.WindowControl, org.olat.core.gui.UserRequest, org.olat.core.gui.translator.Translator, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public BusinessGroupAddResponse moveIdenityFromWaitingListToParticipant(final List<Identity> choosenIdentities, final Identity ureqIdentity, final BusinessGroup currBusinessGroup, final BGConfigFlags flags) {
    final BusinessGroupAddResponse response = new BusinessGroupAddResponse();
      CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup,new SyncerExecutor(){
        public void execute() {
          for (final Identity identity : choosenIdentities) {
            // 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
              BusinessGroupManagerImpl.this.addParticipantAndFireEvent(ureqIdentity, identity, currBusinessGroup, flags, false);
              BusinessGroupManagerImpl.this.removeFromWaitingListAndFireEvent(ureqIdentity, identity, currBusinessGroup, false);
              response.getAddedIdentities().add(identity);
              // notification mail is handled in controller
            } else {
              response.getIdentitiesAlreadyInGroup().add(identity);
            }
          }
        }});
    return response;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#getPositionInWaitingListFor(org.olat.core.id.Identity, org.olat.group.BusinessGroup)
   */
  public int getPositionInWaitingListFor(Identity identity, BusinessGroup businessGroup) {
    // get position in waiting-list
    List identities = securityManager.getIdentitiesAndDateOfSecurityGroup(businessGroup.getWaitingGroup(),true);
    int pos = 0;
    for (int i = 0; i<identities.size(); i++) {
      Object[] co = (Object[])identities.get(i);
      Identity waitingListIdentity = (Identity) co[0];
      if ( waitingListIdentity.getName().equals(identity.getName()) ) {
        pos = i+1;// '+1' because list begins with 0
      }
    }
    return pos;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#addOwnersAndFireEvent(org.olat.core.id.Identity, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public BusinessGroupAddResponse addOwnersAndFireEvent(Identity ureqIdentity, List<Identity> addIdentities, BusinessGroup currBusinessGroup, BGConfigFlags flags) {
    BusinessGroupAddResponse response = new BusinessGroupAddResponse();
    for (Identity identity : addIdentities) {
      currBusinessGroup = loadBusinessGroup(currBusinessGroup); // reload business group
      if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) {
        response.getIdentitiesWithoutPermission().add(identity);
      }
      // Check if identity is already in group. make a db query in case
      // someone in another workflow already added this user to this group. if
      // found, add user to model
      else if (securityManager.isIdentityInSecurityGroup(identity, currBusinessGroup.getOwnerGroup())) {
        response.getIdentitiesAlreadyInGroup().add(identity);
      } else {
        // identity has permission and is not already in group => add it
        addOwnerAndFireEvent(ureqIdentity, identity, currBusinessGroup, flags, false);
        response.getAddedIdentities().add(identity);
        Tracing.logAudit("added identity '" + identity.getName() + "' to securitygroup with key " + currBusinessGroup.getOwnerGroup().getKey(), this.getClass());
      }
    }
    return response;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#addParticipantsAndFireEvent(org.olat.core.id.Identity, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public BusinessGroupAddResponse addParticipantsAndFireEvent(final Identity ureqIdentity, final List<Identity> addIdentities, BusinessGroup acurrBusinessGroup, final BGConfigFlags flags) {
    final BusinessGroupAddResponse response = new BusinessGroupAddResponse();
    final BusinessGroup currBusinessGroup = loadBusinessGroup(acurrBusinessGroup); // reload business group
    CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup, new SyncerExecutor(){
      public void execute() {
        for (final Identity identity : addIdentities) {
          if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) {
            response.getIdentitiesWithoutPermission().add(identity);
          }
          // Check if identity is already in group. make a db query in case
          // someone in another workflow already added this user to this group. if
          // found, add user to model
          else if (securityManager.isIdentityInSecurityGroup(identity, currBusinessGroup.getPartipiciantGroup())) {
            response.getIdentitiesAlreadyInGroup().add(identity);
          } else {
            // identity has permission and is not already in group => add it
            addParticipantAndFireEvent(ureqIdentity, identity, currBusinessGroup, flags, false);
            response.getAddedIdentities().add(identity);
            Tracing.logAudit("added identity '" + identity.getName() + "' to securitygroup with key " + currBusinessGroup.getPartipiciantGroup().getKey(), this.getClass());
          }
        }
      }});
    return response;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#addToWaitingListAndFireEvent(org.olat.core.id.Identity, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public BusinessGroupAddResponse addToWaitingListAndFireEvent(final Identity ureqIdentity, final List<Identity> addIdentities, BusinessGroup acurrBusinessGroup, BGConfigFlags flags) {
    final BusinessGroupAddResponse response = new BusinessGroupAddResponse();
    final BusinessGroup currBusinessGroup = loadBusinessGroup(acurrBusinessGroup); // reload business group
      CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup, new SyncerExecutor(){
        public void execute() {
          for (final Identity identity : addIdentities) { 
            if (securityManager.isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_GUESTONLY)) {
              response.getIdentitiesWithoutPermission().add(identity);
            }
            // Check if identity is already in group. make a db query in case
            // someone in another workflow already added this user to this group. if
            // found, add user to model
            else if (securityManager.isIdentityInSecurityGroup(identity, currBusinessGroup.getWaitingGroup())) {
              response.getIdentitiesAlreadyInGroup().add(identity);
            } else {
              // identity has permission and is not already in group => add it
              BusinessGroupManagerImpl.this.addToWaitingListAndFireEvent(ureqIdentity, identity, currBusinessGroup, false);
              response.getAddedIdentities().add(identity);
              Tracing.logAudit("added identity '" + identity.getName() + "' to securitygroup with key " + currBusinessGroup.getPartipiciantGroup().getKey(), this.getClass());
            }
          }
        }});
    return response;
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#removeOwnersAndFireEvent(org.olat.core.id.Identity, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public void removeOwnersAndFireEvent(Identity ureqIdentity, List<Identity> identities, BusinessGroup currBusinessGroup, BGConfigFlags flags) {
    for (Identity identity : identities) {
      removeOwnerAndFireEvent(ureqIdentity, identity, currBusinessGroup, flags, false);
      Tracing.logAudit("removed identiy '" + identity.getName() + "' from securitygroup with key " + currBusinessGroup.getOwnerGroup().getKey(), this.getClass());
    }
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#removeParticipantsAndFireEvent(org.olat.core.gui.control.WindowControl, org.olat.core.id.Identity, org.olat.core.gui.translator.Translator, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public void removeParticipantsAndFireEvent(final Identity ureqIdentity, final List<Identity> identities, final BusinessGroup currBusinessGroup, final BGConfigFlags flags) {
    CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup, new SyncerExecutor(){
      public void execute() {
        for (Identity identity : identities) {
          removeParticipantAndFireEvent(ureqIdentity, identity, currBusinessGroup, flags, false);
          Tracing.logAudit("removed identiy '" + identity.getName() + "' from securitygroup with key " + currBusinessGroup.getPartipiciantGroup().getKey(), this.getClass());
        }
      }
    });
  }

  /**
   *
   * @see org.olat.group.BusinessGroupManager#removeFromWaitingListAndFireEvent(org.olat.core.id.Identity, org.olat.core.gui.translator.Translator, java.util.List, org.olat.group.BusinessGroup, org.olat.group.ui.BGConfigFlags, org.olat.core.logging.UserActivityLogger)
   */
  public void removeFromWaitingListAndFireEvent(final Identity ureqIdentity, final List<Identity> identities, final BusinessGroup currBusinessGroup, final BGConfigFlags flags) {
    CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup, new SyncerExecutor(){
      public void execute() {
        for (Identity identity : identities) {
          removeFromWaitingListAndFireEvent(ureqIdentity, identity, currBusinessGroup, false);
          Tracing.logAudit("removed identiy '" + identity.getName() + "' from securitygroup with key " + currBusinessGroup.getOwnerGroup().getKey(), this.getClass());
        }
      }
    });
  }

  //////////////////
  // Private Methods
  //////////////////
  /**
   * Get all learning resources associated with the context from the given group
   * and buid a direct jump url to this resources
   * @param group
   * @return String with direct-jumpin-urls
   */
  private String getAllLearningResourcesFor(BusinessGroup group) {
    // g
    StringBuilder learningResources = new StringBuilder();
    if (group.getGroupContext() != null) {
      BGContextManager contextManager = BGContextManagerImpl.getInstance();
      List repoEntries = contextManager.findRepositoryEntriesForBGContext(group.getGroupContext());
      Iterator iter = repoEntries.iterator();
      while (iter.hasNext()) {
        RepositoryEntry entry = (RepositoryEntry) iter.next();
        String title = entry.getDisplayname();
        String url = RepoJumpInHandlerFactory.buildRepositoryDispatchURI(entry);
        learningResources.append(title);
        learningResources.append("\n");
        learningResources.append(url);
        learningResources.append("\n\n");
      }
    }
    return learningResources.toString();
  }

  private void addToRoster(Identity ureqIdentity, Identity identity, BusinessGroup group, BGConfigFlags flags) {
    if (flags.isEnabled(BGConfigFlags.BUDDYLIST)) {
      if (InstantMessagingModule.isEnabled()) {
        //evaluate whether to sync or not
        boolean syncBuddy = InstantMessagingModule.getAdapter().getConfig().isSyncPersonalGroups();
        boolean isBuddy = group.getType().equals(BusinessGroup.TYPE_BUDDYGROUP);
       
        boolean syncLearn = InstantMessagingModule.getAdapter().getConfig().isSyncLearningGroups();
        boolean isLearn = group.getType().equals(BusinessGroup.TYPE_LEARNINGROUP);
       
        //only sync when a group is a certain type and this type is configured that you want to sync it
        if ((syncBuddy && isBuddy) || (syncLearn && isLearn)) {
          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));
        }
      }
    }
  }

  private void removeFromRoster(Identity identity, BusinessGroup group, BGConfigFlags flags) {
    if (flags.isEnabled(BGConfigFlags.BUDDYLIST)) {
      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());
        }
      }
    }
  }

  /**
   * Transfer first identity of waiting.list (if there is one) to the participant-list.
   * Not thread-safe! Do call this method only from a synchronized block!
   * @param wControl
   * @param ureq
   * @param trans
   * @param identity
   * @param group
   * @param flags
   * @param logger
   * @param secMgr
   */
  //o_clusterOK by:cg call this method only from synchronized code-block (removeParticipantAndFireEvent( ).
  private void transferFirstIdentityFromWaitingToParticipant(Identity ureqIdentity, BusinessGroup group, BGConfigFlags flags) {
    CoordinatorManager.getCoordinator().getSyncer().assertAlreadyDoInSyncFor(group);
    // Check if waiting-list is enabled and auto-rank-up
    if (group.getWaitingListEnabled().booleanValue() && group.getAutoCloseRanksEnabled().booleanValue()) {
      // Check if participant is not full
      Integer maxSize = group.getMaxParticipants();
      int waitingPartipiciantSize = securityManager.countIdentitiesOfSecurityGroup(group.getPartipiciantGroup());
      if ( (maxSize != null) && (waitingPartipiciantSize < maxSize.intValue()) ) {
        // ok it has free places => get first idenity from Waitinglist
        List identities = securityManager.getIdentitiesAndDateOfSecurityGroup(group.getWaitingGroup(), true/*sortedByAddedDate*/);
        int i = 0;
        boolean transferNotDone = true;
        while (i<identities.size() && transferNotDone) {
          // It has an identity and transfer from waiting-list to participant-group is not done
          Object[] co = (Object[])identities.get(i++);
          Identity firstWaitingListIdentity = (Identity) co[0];
          //reload group
          group = (BusinessGroup)DBFactory.getInstance().loadObject(group, true);
          // Check if firstWaitingListIdentity is not allready in participant-group
          if (!securityManager.isIdentityInSecurityGroup(firstWaitingListIdentity,group.getPartipiciantGroup())) {
            // move the identity from the waitinglist to the participant group
           
            ActionType formerStickyActionType = ThreadLocalUserActivityLogger.getStickyActionType();
            try{
              // OLAT-4955: force add-participant and remove-from-waitinglist logging actions
              //            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);
              this.addParticipantAndFireEvent(ureqIdentity, firstWaitingListIdentity, group, flags, false);
              this.removeFromWaitingListAndFireEvent(ureqIdentity, firstWaitingListIdentity, group, false);
            } finally {
              ThreadLocalUserActivityLogger.setStickyActionType(formerStickyActionType);
            }
            // send a notification mail if available
            MailTemplate mailTemplate = BGMailHelper.createWaitinglistTransferMailTemplate(group, ureqIdentity);
            if (mailTemplate != null) {
              MailerWithTemplate mailer = MailerWithTemplate.getInstance();
              MailerResult mailerResult = mailer.sendMail(firstWaitingListIdentity, null, null, mailTemplate, null);
              // Does not report errors to current screen because this is the identity who triggered the transfer
              Tracing.logWarn("Could not send WaitinglistTransferMail for identity=" + firstWaitingListIdentity.getName() , BusinessGroupManagerImpl.class);
            }           
            transferNotDone = false;
          }
        }
      }
    } else {
      Tracing.logWarn("Called method transferFirstIdentityFromWaitingToParticipant but waiting-list or autoCloseRanks is disabled.", BusinessGroupManagerImpl.class);
    }
  }

  /**
   * Delete all entries as participant, owner and waiting-list for certain identity.
   * If there is no other owner for a group, the olat-administrator (define in olat_config.xml) will be added as owner.
   *  
   * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
   */
  public void deleteUserData(Identity identity, String newDeletedUserName) {
    // remove as Participant
    List attendedGroups = findAllBusinessGroupsAttendedBy(identity);
    for (Iterator iter = attendedGroups.iterator(); iter.hasNext();) {
      securityManager.removeIdentityFromSecurityGroup(identity, ((BusinessGroup)iter.next()).getPartipiciantGroup());
    }
    Tracing.logDebug("Remove partipiciant identity=" + identity + " from " + attendedGroups.size() + " groups", this.getClass());
    // remove from waitinglist
    List waitingGroups = findBusinessGroupsWithWaitingListAttendedBy(identity);
    for (Iterator iter = waitingGroups.iterator(); iter.hasNext();) {
      securityManager.removeIdentityFromSecurityGroup(identity, ((BusinessGroup)iter.next()).getWaitingGroup());
    }
    Tracing.logDebug("Remove from waiting-list identity=" + identity + " in " + waitingGroups.size() + " groups", this.getClass());

    // remove as owner
    List ownerGroups = findAllBusinessGroupsOwnedBy(identity);
    for (Iterator iter = ownerGroups.iterator(); iter.hasNext();) {
      BusinessGroup businessGroup = (BusinessGroup) iter.next();
      securityManager.removeIdentityFromSecurityGroup(identity, businessGroup.getOwnerGroup());
      if (businessGroup.getType().equals(BusinessGroup.TYPE_BUDDYGROUP) && securityManager.countIdentitiesOfSecurityGroup(businessGroup.getOwnerGroup()) == 0 ) {
        // Buddygroup has no owner anymore => add OLAT-Admin as owner
        securityManager.addIdentityToSecurityGroup(UserDeletionManager.getInstance().getAdminIdentity(), businessGroup.getOwnerGroup());
        Tracing.logInfo("Delete user-data, add Administrator-identity as owner of businessGroup=" + businessGroup.getName(), this.getClass());
      }
    }
    Tracing.logDebug("Remove owner identity=" + identity + " from " + ownerGroups.size() + " groups", this.getClass());
    Tracing.logDebug("All entries in groups deleted for identity=" + identity, this.getClass());
  }

  private List findAllBusinessGroupsOwnedBy(Identity identity) {
    return findBusinessGroupsOwnedBy(null, identity, null);
  }

  private List findAllBusinessGroupsAttendedBy(Identity identity) {
    return findBusinessGroupsAttendedBy(null, identity, null);
  }
 
  private List findBusinessGroupsWithWaitingListAttendedBy(Identity identity) {
    return findBusinessGroupsWithWaitingListAttendedBy(null, identity, null);
  }

  public void archiveGroups(BGContext context, File exportFile) {
    BusinessGroupArchiver.getInstance().archiveBGContext(context, exportFile);   
  }
 
  private void removeSubscriptions(Identity identity, BusinessGroup group) {
    NotificationsManager notiMgr = NotificationsManager.getInstance();
    List<Subscriber> l = notiMgr.getSubscribers(identity);
    for (Iterator iterator = l.iterator(); iterator.hasNext();) {
      Subscriber subscriber = (Subscriber) iterator.next();
      Long resId = subscriber.getPublisher().getResId();
      Long groupKey = group.getKey();
      if (resId != null && groupKey != null && resId.equals(groupKey)) {
        notiMgr.unsubscribe(subscriber);
      }
    }
  }

  /**
   * @see org.olat.group.BusinessGroupManager#setLastUsageFor(org.olat.group.BusinessGroup)
   */
  public void setLastUsageFor(final BusinessGroup currBusinessGroup) {
    //o_clusterOK by:cg
    CoordinatorManager.getCoordinator().getSyncer().doInSync(currBusinessGroup, new SyncerExecutor(){
      public void execute() {
        // force a reload from db loadObject(..., true) by evicting it from
        // hibernates session
        // cache to catch up on a different thread having commited the update of
        // the launchcounter
        BusinessGroup reloadedBusinessGroup = BusinessGroupManagerImpl.getInstance().loadBusinessGroup(currBusinessGroup);
        reloadedBusinessGroup.setLastUsage(new Date());
        LifeCycleManager.createInstanceFor(reloadedBusinessGroup).deleteTimestampFor(GroupDeletionManager.SEND_DELETE_EMAIL_ACTION);
        BusinessGroupManagerImpl.getInstance().updateBusinessGroup(reloadedBusinessGroup);
      }
    });
  }

  /**
   * @see org.olat.group.BusinessGroupManager#createUniqueBusinessGroupsFor(java.util.Set, org.olat.group.context.BGContext, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.Boolean, java.lang.Boolean)
   */
  public Set<BusinessGroup> createUniqueBusinessGroupsFor(final Set<String> allNames, final BGContext bgContext, final String bgDesc, final Integer bgMin,
      final Integer bgMax, final Boolean enableWaitinglist, final Boolean enableAutoCloseRanks) {
     //o_clusterOK by:cg
    Set<BusinessGroup> createdGroups = CoordinatorManager.getCoordinator().getSyncer().doInSync(bgContext, new SyncerCallback<Set<BusinessGroup>>(){
        public Set<BusinessGroup> execute() {
          if(checkIfOneOrMoreNameExistsInContext(allNames, bgContext)){
            // set error of non existing name
            return null;
          } else {
            // create bulkgroups only if there is no name which already exists.
            Set<BusinessGroup> newGroups = new HashSet<BusinessGroup>();
            for (Iterator<String> iter = allNames.iterator(); iter.hasNext();) {
              String bgName = iter.next();
              BusinessGroup newGroup = createAndPersistBusinessGroup(bgContext.getGroupType(), null, bgName, bgDesc, bgMin, bgMax,
                  enableWaitinglist, enableAutoCloseRanks, bgContext);
              newGroups.add(newGroup);
            }
            return newGroups;
          }
        }
    });
    return createdGroups;
  }
 
  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) {
      DeletableReference deletableReference = deleteListener.checkIfReferenced(currentGroup, locale);
      if (deletableReference.isReferenced()) {
        deletableList.add(deletableReference.getName());
      }
    }
    return deletableList;
  }

}
TOP

Related Classes of org.olat.group.BusinessGroupManagerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.