/** * <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.manager; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityShort; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.manager.BasicManager; import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.session.UserSessionManager; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupMemberView; import org.olat.group.DeletableGroupData; import org.olat.group.manager.ContactDAO; import org.olat.group.model.ContactViewExtended; import org.olat.instantMessaging.ImPreferences; import org.olat.instantMessaging.InstantMessage; import org.olat.instantMessaging.InstantMessageNotification; import org.olat.instantMessaging.InstantMessagingEvent; import org.olat.instantMessaging.InstantMessagingService; import org.olat.instantMessaging.model.Buddy; import org.olat.instantMessaging.model.BuddyGroup; import org.olat.instantMessaging.model.BuddyStats; import org.olat.instantMessaging.model.InstantMessageImpl; import org.olat.instantMessaging.model.Presence; import org.olat.instantMessaging.model.RosterEntryView; import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * * Initial date: 05.12.2012<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ @Service public class InstantMessagingServiceImpl extends BasicManager implements InstantMessagingService, DeletableGroupData { @Autowired private RosterDAO rosterDao; @Autowired private InstantMessageDAO imDao; @Autowired private InstantMessagePreferencesDAO prefsDao; @Autowired private CoordinatorManager coordinator; @Autowired private ContactDAO contactDao; @Autowired private UserManager userManager; @Autowired private UserSessionManager sessionManager; @Autowired private BaseSecurity securityManager; @Autowired private DB dbInstance; @Override public boolean deleteGroupDataFor(BusinessGroup group) { imDao.deleteMessages(group); dbInstance.commit(); return true; } @Override public String getStatus(Long identityKey) { return prefsDao.getStatus(identityKey); } @Override public ImPreferences getImPreferences(Identity identity) { ImPreferences prefs = prefsDao.getPreferences(identity); dbInstance.commit(); return prefs; } @Override public void updateImPreferences(Identity identity, boolean visible) { prefsDao.updatePreferences(identity, visible); dbInstance.commit(); } @Override public void updateStatus(Identity identity, String status) { prefsDao.updatePreferences(identity, status); dbInstance.commit(); } @Override public OLATResourceable getPrivateChatResource(Long identityKey1, Long identityKey2) { String resName; if(identityKey1.longValue() > identityKey2.longValue()) { resName = identityKey2 + "-" + identityKey1; } else { resName = identityKey1 + "-" + identityKey2; } long key = identityKey1.longValue() + identityKey2.longValue(); return OresHelper.createOLATResourceableInstance(resName, new Long(key)); } @Override public InstantMessage getMessageById(Identity identity, Long messageId, boolean markedAsRead) { InstantMessageImpl msg = imDao.loadMessageById(messageId); if(markedAsRead && msg != null) { OLATResourceable ores = OresHelper.createOLATResourceableInstance(msg.getResourceTypeName(), msg.getResourceId()); imDao.deleteNotification(identity, ores); } return msg; } @Override public List<InstantMessage> getMessages(Identity identity, OLATResourceable chatResource, Date from, int firstResult, int maxResults, boolean markedAsRead) { List<InstantMessage> msgs = imDao.getMessages(chatResource, from, firstResult, maxResults); if(markedAsRead) { imDao.deleteNotification(identity, chatResource); } return msgs; } @Override public InstantMessage sendMessage(Identity from, String fromNickName, boolean anonym, String body, OLATResourceable chatResource) { InstantMessage message = imDao.createMessage(from, fromNickName, anonym, body, chatResource); dbInstance.commit();//commit before sending event InstantMessagingEvent event = new InstantMessagingEvent("message", chatResource); event.setFromId(from.getKey()); event.setName(fromNickName); event.setAnonym(anonym); event.setMessageId(message.getKey()); coordinator.getCoordinator().getEventBus().fireEventToListenersOf(event, chatResource); return message; } @Override public InstantMessage sendPrivateMessage(Identity from, Long toIdentityKey, String body, OLATResourceable chatResource) { String name = userManager.getUserDisplayName(from); InstantMessage message = imDao.createMessage(from, name, false, body, chatResource); imDao.createNotification(from.getKey(), toIdentityKey, chatResource); dbInstance.commit();//commit before sending event InstantMessagingEvent event = new InstantMessagingEvent("message", chatResource); event.setFromId(from.getKey()); event.setName(name); event.setAnonym(false); event.setMessageId(message.getKey()); //general event coordinator.getCoordinator().getEventBus().fireEventToListenersOf(event, chatResource); //buddy event OLATResourceable buddy = OresHelper.createOLATResourceableInstance("Buddy", toIdentityKey); coordinator.getCoordinator().getEventBus().fireEventToListenersOf(event, buddy); return message; } @Override public void deleteMessages(OLATResourceable ores) { imDao.deleteMessages(ores); } @Override public void sendPresence(Identity me, String nickName, boolean anonym, boolean vip, OLATResourceable chatResource) { InstantMessagingEvent event = new InstantMessagingEvent("participant", chatResource); event.setAnonym(anonym); event.setVip(vip); event.setFromId(me.getKey()); if(StringHelper.containsNonWhitespace(nickName)) { event.setName(nickName); } String fullName = userManager.getUserDisplayName(me); rosterDao.updateRosterEntry(chatResource, me, fullName, nickName, anonym, vip); coordinator.getCoordinator().getEventBus().fireEventToListenersOf(event, chatResource); } @Override public List<InstantMessageNotification> getNotifications(Identity identity) { return imDao.getNotifications(identity); } @Override public Buddy getBuddyById(Long identityKey) { IdentityShort identity = securityManager.loadIdentityShortByKey(identityKey); String fullname = userManager.getUserDisplayName(identity); String status; boolean online = isOnline(identityKey); if(online) { String prefStatus = prefsDao.getStatus(identityKey); if(prefStatus == null) { status = Presence.available.name(); } else { status = prefStatus; } } else { status = Presence.unavailable.name(); } return new Buddy(identity.getKey(), identity.getName(), fullname, false, status); } @Override public BuddyStats getBuddyStats(Identity me) { BuddyStats stats = new BuddyStats(); //count all my buddies Collection<Long> buddiesColl = contactDao.getDistinctGroupOwnersParticipants(me); buddiesColl.remove(me.getKey()); List<Long> buddies = new ArrayList<Long>(buddiesColl); stats.setOfflineBuddies(buddies.size()); //filter online users for(Iterator<Long> buddyIt=buddies.iterator(); buddyIt.hasNext(); ) { Long buddyKey = buddyIt.next(); boolean online = isOnline(buddyKey); if(!online) { buddyIt.remove(); } } //count online users which are available int online = prefsDao.countAvailableBuddies(buddies); stats.setOnlineBuddies(online); return stats; } @Override public Map<Long, String> getBuddyStatus(List<Long> identityKeys) { return prefsDao.getBuddyStatus(identityKeys); } @Override public List<BuddyGroup> getBuddyGroups(Identity me, boolean offlineUsers) { List<BuddyGroup> groups = new ArrayList<BuddyGroup>(25); Map<Long,BuddyGroup> groupMap = new HashMap<Long,BuddyGroup>(); Map<Long, String> identityKeyToStatus = new HashMap<Long, String>(); List<ContactViewExtended> contactList = contactDao.getContactWithExtendedInfos(me); collectMembersStatus(contactList, identityKeyToStatus); for(ContactViewExtended contact:contactList) { addBuddyToGroupList(contact, me, groupMap, groups, identityKeyToStatus, offlineUsers); } return groups; } private void collectMembersStatus(List<? extends BusinessGroupMemberView> members, Map<Long, String> identityKeyToStatus) { Set<Long> loadStatus = new HashSet<Long>(); for(BusinessGroupMemberView member:members) { Long identityKey = member.getIdentityKey(); if(!identityKeyToStatus.containsKey(identityKey) && !loadStatus.contains(identityKey)) { boolean online = isOnline(member.getIdentityKey()); if(online) { loadStatus.add(identityKey); } else { identityKeyToStatus.put(identityKey, Presence.unavailable.name()); } } } if(loadStatus.size() > 0) { List<Long> statusToLoadList = new ArrayList<Long>(loadStatus); Map<Long,String> statusMap = prefsDao.getBuddyStatus(statusToLoadList); for(Long toLoad:statusToLoadList) { String status = statusMap.get(toLoad); if(status == null) { identityKeyToStatus.put(toLoad, Presence.available.name()); } else { identityKeyToStatus.put(toLoad, status); } } } } private void addBuddyToGroupList(ContactViewExtended member, Identity me, Map<Long,BuddyGroup> groupMap, List<BuddyGroup> groups, Map<Long, String> identityKeyToStatus, boolean offlineUsers) { if(me != null && me.getKey().equals(member.getIdentityKey())) { return; } String status = identityKeyToStatus.get(member.getIdentityKey()); if(status == null) { boolean online = isOnline(member.getIdentityKey()); if(online) { status = prefsDao.getStatus(member.getIdentityKey()); if(status == null) { status = Presence.available.name(); } } else { status = Presence.unavailable.name(); } identityKeyToStatus.put(member.getIdentityKey(), status); } if(offlineUsers || Presence.available.name().equals(status)) { BuddyGroup group = groupMap.get(member.getGroupKey()); if(group == null) { group = new BuddyGroup(member.getGroupKey(), member.getGroupName()); groupMap.put(member.getGroupKey(), group); groups.add(group); } boolean vip = GroupRoles.coach.name().equals(member.getRole()); String name = userManager.getUserDisplayName(member); group.addBuddy(new Buddy(member.getIdentityKey(), member.getUsername(), name, false, vip, status)); } } @Override public List<Buddy> getBuddiesListenTo(OLATResourceable chatResource) { List<RosterEntryView> roster = rosterDao.getRosterView(chatResource, 0, -1); List<Buddy> buddies = new ArrayList<Buddy>(); if(roster != null) { for(RosterEntryView entry:roster) { String name = entry.isAnonym() ? entry.getNickName() : entry.getFullName(); String status = getOnlineStatus(entry.getIdentityKey()); buddies.add(new Buddy(entry.getIdentityKey(), entry.getUsername(), name, entry.isAnonym(), entry.isVip(), status)); } } return buddies; } private String getOnlineStatus(Long identityKey) { return isOnline(identityKey) ? Presence.available.name() : Presence.unavailable.name(); } /** * Return true if the identity is logged in on the instance * @param identityKey * @return */ private boolean isOnline(Long identityKey) { return sessionManager.isOnline(identityKey); } @Override public void listenChat(Identity identity, OLATResourceable chatResource, String nickName, boolean anonym, boolean vip, GenericEventListener listener) { String fullName = userManager.getUserDisplayName(identity); rosterDao.updateRosterEntry(chatResource, identity, fullName, nickName, anonym, vip); coordinator.getCoordinator().getEventBus().registerFor(listener, identity, chatResource); } @Override public void unlistenChat(Identity identity, OLATResourceable chatResource, GenericEventListener listener) { rosterDao.deleteEntry(identity, chatResource); dbInstance.commit(); coordinator.getCoordinator().getEventBus().deregisterFor(listener, chatResource); } @Override public void disableChat(Identity identity) { // } @Override public void enableChat(Identity identity) { // } }