/** * OLAT - Online Learning and Training
* http://www.olat.org *

* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. *

* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),
* University of Zurich, Switzerland. *

*/ package org.olat.instantMessaging; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jivesoftware.smack.packet.Presence; import org.olat.basesecurity.Manager; import org.olat.basesecurity.ManagerFactory; import org.olat.basesecurity.SecurityGroup; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.creator.AutoCreator; import org.olat.core.gui.control.creator.ControllerCreator; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.course.CourseFactory; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.course.groupsandrights.CourseGroupManager; import org.olat.group.BusinessGroup; import org.olat.group.context.BGContextManager; import org.olat.group.context.BGContextManagerImpl; import org.olat.instantMessaging.groupchat.GroupChatManagerController; import org.olat.instantMessaging.rosterandchat.InstantMessagingMainController; import org.olat.instantMessaging.syncservice.InstantMessagingGroupSynchronisation; import org.olat.instantMessaging.syncservice.InstantMessagingServerPluginVersion; import org.olat.instantMessaging.syncservice.InstantMessagingSessionCount; import org.olat.instantMessaging.syncservice.InstantMessagingSessionItems; import org.olat.instantMessaging.syncservice.RemoteAccountCreation; import org.olat.instantMessaging.ui.ConnectedUsersListEntry; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryManager; /** * * Implementation of the InstantMessaging Interface based on * the SMACK instant messaging library from jivesoftware.org * *

* Initial Date: 18.01.2005
* @author guido */ public class SmackInstantMessagingImpl implements InstantMessaging { private IMConfig config; private InstantMessagingGroupSynchronisation buddyGroupService; private InstantMessagingSessionCount sessionCountService; private InstantMessagingSessionItems sessionItemsService; private RemoteAccountCreation accountService; ClientManager clientManager; private IMNameHelper nameHelper; private AdminUserConnection adminConnecion; private String clientVersion; private InstantMessagingServerPluginVersion pluginVersion; private AutoCreator actionControllerCreator; private static OLog log = Tracing.createLoggerFor(SmackInstantMessagingImpl.class); /** * */ private SmackInstantMessagingImpl() { // } /** * @see org.olat.instantMessaging.InstantMessaging#createClientController(org.olat.core.gui.UserRequest, * org.olat.core.gui.control.WindowControl) */ public Controller createClientController(UserRequest ureq, WindowControl wControl) { InstantMessagingClient client = clientManager.getInstantMessagingClient(ureq.getIdentity().getName()); //there are two versions of the controller, either join the course chat automatically or upon request client.setGroupChatManager((GroupChatManagerController) actionControllerCreator.createController(ureq, wControl)); return new InstantMessagingMainController(ureq, wControl); } /** * [used by spring] */ public void setActionController(ControllerCreator actionControllerCreator) { this.actionControllerCreator = (AutoCreator) actionControllerCreator; } /** * @see org.olat.instantMessaging.InstantMessaging#getGroupChatManagerController() */ public GroupChatManagerController getGroupChatManagerController(UserRequest ureq) { return clientManager.getInstantMessagingClient(ureq.getIdentity().getName()).getGroupChatManagerController(); } /** * @see org.olat.instantMessaging.InstantMessaging#addUserToFriendsRoster(java.lang.String, * java.lang.String, java.lang.String, java.lang.String) * o_clusterOK by:fj - nodes can access the IM server concurrently but only one thread should add a users to a group at * the same time. * Sync over whole clazz, not time critical as accessed by backgrounded threads */ //TODO:gs does this need to be synchronized? public synchronized boolean addUserToFriendsRoster(String groupOwnerUsername, String groupId, String groupname, String addedUsername) { // we have to make sure the user has an account on the instant messaging // server // by calling this it gets created if not yet exists. addedUsername = nameHelper.getIMUsernameByOlatUsername(addedUsername); groupOwnerUsername = nameHelper.getIMUsernameByOlatUsername(groupOwnerUsername); boolean hasAccount = accountService.hasAccount(addedUsername); if (!hasAccount) clientManager.getInstantMessagingCredentialsForUser(addedUsername); // we do not check whether a group already exists, we create it each time List list = new ArrayList(); list.add(groupOwnerUsername); buddyGroupService.createSharedGroup(groupId, groupname, list); if (log.isDebug()){ log.debug("Adding user to roster group::" + groupId + "username: " + addedUsername); } return buddyGroupService.addUserToSharedGroup(groupId, addedUsername); } /** * @see org.olat.instantMessaging.InstantMessaging#removeUserFromFriendsRoster(java.lang.String, * java.lang.String) */ public boolean removeUserFromFriendsRoster(String groupId, String username) { groupId = nameHelper.getGroupnameForOlatInstance(groupId); if (log.isDebug()){ log.debug("Deleting user from roster group::" + groupId + "username: " + username); } return buddyGroupService.removeUserFromSharedGroup(groupId, nameHelper.getIMUsernameByOlatUsername(username)); } /** * @see org.olat.instantMessaging.InstantMessaging#deleteRosterGroup(java.lang.String) */ public boolean deleteRosterGroup(String groupId) { //groupId is already converted to single/multiple instance version if (log.isDebug()){ log.debug("Deleting roster group from instant messaging server::" + groupId); } return buddyGroupService.deleteSharedGroup(groupId); } /** * @param groupId * @param displayName */ public boolean renameRosterGroup(String groupId, String displayName) { groupId = nameHelper.getGroupnameForOlatInstance(groupId); if (log.isDebug()){ log.debug("Renaming roster group on instant messaging server::" + groupId); } return buddyGroupService.renameSharedGroup(groupId, displayName); } /** * @see org.olat.instantMessaging.InstantMessaging#sendStatus(java.lang.String, * java.lang.String) */ public void sendStatus(String username, String message) { //only send status if client is active otherwise course dispose may recreate an connection if (clientManager.hasActiveInstantMessagingClient(username)) { InstantMessagingClient imc = clientManager.getInstantMessagingClient(username); String recentStatus = imc.getStatus(); //awareness presence packets get only sended if not "unavailable". Otherwise the unavailable status gets overwritten by an available one. if (!recentStatus.equals(InstantMessagingConstants.PRESENCE_MODE_UNAVAILABLE)) imc.sendPresence(Presence.Type.available, message, 0, Presence.Mode.valueOf(imc.getStatus())); } } /** * * @see org.olat.instantMessaging.InstantMessaging#createAccount(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ public boolean createAccount(String username, String password, String fullname, String email) { boolean success; success = accountService.createAccount(nameHelper.getIMUsernameByOlatUsername(username), password, fullname, email); if (log.isDebug()) { log.debug("Creating new user account on IM server for user:" + username + " returned: "+success); } return success; } /** * * @see org.olat.instantMessaging.InstantMessaging#deleteAccount(java.lang.String) */ public boolean deleteAccount(String username) { boolean success; success = accountService.deleteAccount(nameHelper.getIMUsernameByOlatUsername(username)); if (log.isDebug()) { log.debug("Deleting user account on IM server for user:" + username + " returned: "+success); } return success; } /** * @see org.olat.instantMessaging.InstantMessaging#getIMPassword(java.lang.String) */ public String getIMPassword(String username) { return clientManager.getInstantMessagingClient(username).getPassword(); } /** * @return Set containing the usernames */ public Set getUsernamesFromConnectedUsers() { return new HashSet(getClients().keySet()); } /** * @see org.olat.instantMessaging.InstantMessaging#getClients() */ public Map getClients() { return clientManager.getClients(); } /** * @see org.olat.instantMessaging.InstantMessaging#enableChat(java.lang.String) */ public void enableChat(String username) { clientManager.getInstantMessagingClient(username).enableCollaboration(); if (log.isDebug()){ log.debug("Enabling chat for user::" + username); } } /** * @param username * @param reason A resason why the chat is disabled like "Doing test" * @see org.olat.instantMessaging.InstantMessaging#disableChat(java.lang.String, * java.lang.String) */ public void disableChat(String username, String reason) { clientManager.getInstantMessagingClient(username).disableCollaboration(reason); if (log.isDebug()){ log.debug("Disabling chat for user::" + username + "and reason" + reason); } } /** * @see org.olat.instantMessaging.InstantMessaging#countConnectedUsers() */ public int countConnectedUsers() { return sessionCountService.countSessions(); } /** * @see org.olat.instantMessaging.InstantMessaging#synchonizeBuddyRoster(org.olat.group.BusinessGroup) */ public boolean synchonizeBuddyRoster(BusinessGroup group) { Manager securityManager = ManagerFactory.getManager(); SecurityGroup owners = group.getOwnerGroup(); SecurityGroup participants = group.getPartipiciantGroup(); List users = securityManager.getIdentitiesOfSecurityGroup(owners); users.addAll(securityManager.getIdentitiesOfSecurityGroup(participants)); int counter = 0; List usernames = new ArrayList(); for (Iterator iter = users.iterator(); iter.hasNext();) { Identity ident = iter.next(); // as jive only adds users to a group that already exist we have to make // sure they have an account. clientManager.getInstantMessagingCredentialsForUser(ident.getName()); usernames.add(ident.getName()); if (counter %20 == 0) DBFactory.getInstance().intermediateCommit(); counter++; } String groupId = InstantMessagingModule.getAdapter().createChatRoomString(group); if (users.size() > 0 ) { // only sync groups with users if (!buddyGroupService.createSharedGroup(groupId, group.getName(), usernames)){ log.error("could not create shared group: "+groupId); } if (log.isDebug()) log.debug("synchronizing group::" + group.toString()); } else { if (log.isDebug()) log.debug("empty group: not synchronizing group::" + group.toString()); } //when looping over all buddygroups and learninggroups close transaction after each group DBFactory.getInstance().intermediateCommit(); return true; } /** * * @see org.olat.instantMessaging.InstantMessaging#synchronizeLearningGroupsWithIMServer() */ public boolean synchronizeLearningGroupsWithIMServer() { log.info("Starting synchronisation of LearningGroups with IM server"); RepositoryManager rm = RepositoryManager.getInstance(); BGContextManager contextManager = BGContextManagerImpl.getInstance(); //pull as admin Roles roles = new Roles(true, true, true, true, false); List allCourses = rm.queryByTypeLimitAccess(CourseModule.getCourseTypeName(), roles); int counter = 0; for (Iterator iterator = allCourses.iterator(); iterator.hasNext();) { RepositoryEntry entry = iterator.next(); ICourse course = null; try{ course = CourseFactory.loadCourse(entry.getOlatResource()); } catch (Exception e) { log.error("Could not load a Course! OlatResourcable: "+entry.getOlatResource(), e); continue; } CourseGroupManager groupManager = course.getCourseEnvironment().getCourseGroupManager(); List groups = groupManager.getAllLearningGroupsFromAllContexts(); for (Iterator iter = groups.iterator(); iter.hasNext();) { BusinessGroup group = iter.next(); if (!synchonizeBuddyRoster(group)) { log.error("could sync group: "+group.getResourceableTypeName()); } counter++; } if (counter%100==0) { DBFactory.getInstance(false).intermediateCommit(); } } log.info("Ended synchronisation of LearningGroups with IM server: Synched "+counter+" groups"); return true; } /** * Synchronize the groups with the IM system * To synchronize buddygroups, use the null-context. * Be aware that this action might take some time! * @param groupContext * @return true if successfull, false if IM server is not running */ public boolean synchronizeAllBuddyGroupsWithIMServer() { log.info("Started synchronisation of BuddyGroups with IM server."); BGContextManager cm = BGContextManagerImpl.getInstance(); //null as argument pulls all buddygroups List groups = cm.getGroupsOfBGContext(null); int counter = 0; for (Iterator iter = groups.iterator(); iter.hasNext();) { BusinessGroup group = iter.next(); synchonizeBuddyRoster(group); counter++; if (counter%100==0) { DBFactory.getInstance(false).intermediateCommit(); } } log.info("Ended synchronisation of BuddyGroups with IM server: Synched "+counter+" groups"); return true; } /** * @see org.olat.instantMessaging.InstantMessaging#createChatRoomString(org.olat.core.id.OLATResourceable */ public String createChatRoomString(OLATResourceable ores) { String roomName = ores.getResourceableTypeName() + "-" + ores.getResourceableId(); return nameHelper.getGroupnameForOlatInstance(roomName); } public String createChatRoomJID(OLATResourceable ores) { return createChatRoomString(ores)+"@"+config.getConferenceServer(); } /** * @see org.olat.instantMessaging.InstantMessaging#getAllConnectedUsers() */ public List getAllConnectedUsers(Identity currentUser) { return sessionItemsService.getConnectedUsers(currentUser); } /** * [used by spring] * @param sessionCountService */ public void setSessionCountService(InstantMessagingSessionCount sessionCountService) { this.sessionCountService = sessionCountService; } /** * [used by spring] * @param sessionCountService */ public void setBuddyGroupService(InstantMessagingGroupSynchronisation buddyGroupService) { this.buddyGroupService = buddyGroupService; } /** * [used by spring] * @param sessionItemsService */ public void setSessionItemsService(InstantMessagingSessionItems sessionItemsService) { this.sessionItemsService = sessionItemsService; } /** * [used by spring] * @param accountService */ public void setAccountService(RemoteAccountCreation accountService) { this.accountService = accountService; } /** * [used by spring] * @param clientManager */ public void setClientManager(ClientManager clientManager) { this.clientManager = clientManager; } /** * * @return client manager where you have access to the IM client itself */ public ClientManager getClientManager() { return clientManager; } public IMConfig getConfig() { return config; } public void setConfig(IMConfig config) { this.config = config; } /** * * @see org.olat.instantMessaging.InstantMessaging#hasAccount(java.lang.String) */ public boolean hasAccount(String username) { return accountService.hasAccount(nameHelper.getIMUsernameByOlatUsername(username)); } /** * * @see org.olat.instantMessaging.InstantMessaging#getUserJid(java.lang.String) */ public String getUserJid(String username) { return nameHelper.getIMUsernameByOlatUsername(username)+"@"+config.getServername(); } /** * * @see org.olat.instantMessaging.InstantMessaging#getUsernameFromJid(java.lang.String) */ public String getUsernameFromJid(String jid) { return nameHelper.extractOlatUsername(jid); } public String getIMUsername(String username) { return nameHelper.getIMUsernameByOlatUsername(username); } public void setNameHelper(IMNameHelper nameHelper) { this.nameHelper = nameHelper; } /** * [spring] * @param adminConnection */ public void setAdminConnection(AdminUserConnection adminConnection) { this.adminConnecion = adminConnection; } /** * * @see org.olat.instantMessaging.InstantMessaging#resetAdminConnection() */ public void resetAdminConnection() { this.adminConnecion.resetAndReconnect(); } /** * [spring] * @param clientVersion */ public void setClientVersion(String clientVersion) { this.clientVersion = clientVersion; } public void setServerPluginVersion(InstantMessagingServerPluginVersion pluginVersion) { this.pluginVersion = pluginVersion; } /** * * @see org.olat.instantMessaging.InstantMessaging#checkServerPlugin() */ public String checkServerPlugin() { if (clientVersion.equals(pluginVersion.getPluginVersion())) { return "Jupee! Server plugin and OLAT client run on the same version: "+pluginVersion.getPluginVersion(); } else if (pluginVersion.getPluginVersion() == null) { return "The server does not respond with a version. Do you have the plugin installed? Does the admin user have a running connection to the IM server?"; } return "OLAT runs on client version: "+clientVersion +" but the server version is: "+pluginVersion.getPluginVersion()+"
Plese upgrade!"; } }