/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-util/util/src/java/org/sakaiproject/portal/util/PortalSiteHelper.java $
* $Id: PortalSiteHelper.java 21708 2007-02-18 21:59:28Z ian@caret.cam.ac.uk $
***********************************************************************************
*
* Copyright (c) 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.
*
**********************************************************************************/
package org.sakaiproject.chat2.model.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.sakaiproject.authz.cover.FunctionManager;
import org.sakaiproject.authz.cover.SecurityService;
import org.sakaiproject.chat2.model.ChatChannel;
import org.sakaiproject.chat2.model.ChatManager;
import org.sakaiproject.chat2.model.RoomObserver;
import org.sakaiproject.chat2.model.ChatFunctions;
import org.sakaiproject.chat2.model.ChatMessage;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.Summary;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.exception.IdInvalidException;
import org.sakaiproject.exception.IdUsedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.util.FormattedText;
import org.sakaiproject.site.cover.SiteService;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.cover.TimeService;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.cover.UserDirectoryService;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
*
* @author andersjb
*
*/
public class ChatManagerImpl extends HibernateDaoSupport implements ChatManager, Observer {
private int messagesMax = 100;
protected final transient Log logger = LogFactory.getLog(getClass());
/** the clients listening to the various rooms */
protected Map<String,List<RoomObserver>> roomListeners = new HashMap<String,List<RoomObserver>>();
private EntityManager entityManager;
private ChatChannel defaultChannelSettings;
static Comparator<ChatMessage> channelComparatorAsc = new Comparator<ChatMessage>() {
public int compare(ChatMessage o1, ChatMessage o2) {
return (o1.getMessageDate().compareTo(o2.getMessageDate()));
}
};
static Comparator<ChatMessage> channelComparatorDesc = new Comparator<ChatMessage>() {
public int compare(ChatMessage o1, ChatMessage o2) {
return -1 * (o1.getMessageDate().compareTo(o2.getMessageDate()));
}
};
// part of HibernateDaoSupport; this is the only context in which it is OK
// to modify the template configuration
protected void initDao() throws Exception {
super.initDao();
getHibernateTemplate().setCacheQueries(true);
logger.info("initDao template " + getHibernateTemplate());
}
/**
* Called on after the startup of the singleton. This sets the global
* list of functions which will have permission managed by sakai
* @throws Exception
*/
protected void init() throws Exception
{
logger.info("init()");
try {
EventTrackingService.addObserver(this);
// register functions
if(FunctionManager.getRegisteredFunctions(ChatFunctions.CHAT_FUNCTION_PREFIX).size() == 0) {
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_READ);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_NEW);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_DELETE_ANY);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_DELETE_OWN);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_NEW_CHANNEL);
FunctionManager.registerFunction(ChatFunctions.CHAT_FUNCTION_EDIT_CHANNEL);
}
}
catch (Exception e) {
logger.warn("Error with ChatManager.init()", e);
}
}
/**
* Destroy
*/
public void destroy()
{
EventTrackingService.deleteObserver(this);
logger.info("destroy()");
}
/**
* {@inheritDoc}
*/
public ChatChannel createNewChannel(String context, String title, boolean placementDefaultChannel, boolean checkAuthz, String placement) throws PermissionException {
if (checkAuthz)
checkPermission(ChatFunctions.CHAT_FUNCTION_NEW_CHANNEL, context);
ChatChannel channel = new ChatChannel(getDefaultChannelSettings());
channel.setCreationDate(new Date());
channel.setContext(context);
channel.setTitle(title);
channel.setPlacementDefaultChannel(placementDefaultChannel);
if (placementDefaultChannel) {
channel.setPlacement(placement);
}
return channel;
}
/**
* {@inheritDoc}
*/
public void updateChannel(ChatChannel channel, boolean checkAuthz) throws PermissionException {
if (channel == null)
return;
if (checkAuthz)
checkPermission(ChatFunctions.CHAT_FUNCTION_EDIT_CHANNEL, channel.getContext());
getHibernateTemplate().saveOrUpdate(channel);
}
/**
* {@inheritDoc}
*/
public void deleteChannel(ChatChannel channel) throws PermissionException {
if (channel == null)
return;
checkPermission(ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL, channel.getContext());
getHibernateTemplate().delete(channel);
sendDeleteChannel(channel);
}
/**
* {@inheritDoc}
*/
public ChatChannel getChatChannel(String chatChannelId) {
return (ChatChannel)getHibernateTemplate().get(
ChatChannel.class, chatChannelId);
}
/**
* {@inheritDoc}
*/
public Date calculateDateByOffset(int offset) {
Calendar tmpDate = Calendar.getInstance();
tmpDate.set(Calendar.DAY_OF_MONTH, tmpDate.get(Calendar.DAY_OF_MONTH)-offset);
return new Date(tmpDate.getTimeInMillis());
}
/* (non-Javadoc)
* @see org.sakaiproject.chat2.model.ChatManager#getChannelMessages(org.sakaiproject.chat2.model.ChatChannel, java.lang.String, java.util.Date, int, boolean)
*/
public List<ChatMessage> getChannelMessages(ChatChannel channel, String context, Date date, int start, int max, boolean sortAsc) throws PermissionException {
if (channel == null) {
List<ChatMessage> allMessages = new ArrayList<ChatMessage>();
List<ChatChannel> channels = getContextChannels(context, true);
for (Iterator<ChatChannel> i = channels.iterator(); i.hasNext();) {
ChatChannel tmpChannel = i.next();
allMessages.addAll(getChannelMessages(tmpChannel, date, start, max, sortAsc));
}
// Why resorting here? -AZ
if (sortAsc) {
Collections.sort(allMessages, channelComparatorAsc);
} else {
Collections.sort(allMessages, channelComparatorDesc);
}
return allMessages;
}
else
return getChannelMessages(channel, date, start, max, sortAsc);
}
/**
*
* @see getChannelMessages
*/
@SuppressWarnings("unchecked")
protected List<ChatMessage> getChannelMessages(ChatChannel channel, Date date, int start, int max, boolean sortAsc) throws PermissionException {
List<ChatMessage> messages = new ArrayList<ChatMessage>();
if (channel == null || max == 0) {
// no channel or no items causes nothing to be returned
return messages;
}
checkPermission(ChatFunctions.CHAT_FUNCTION_READ, channel.getContext());
int localMax = max;
int localStart = start;
Date localDate = date;
// Find out which values to use.
// If the settings of the channel have more strict values then the passed info, use them instead.
if (channel.getFilterType().equals(ChatChannel.FILTER_BY_NUMBER) ||
channel.getFilterType().equals(ChatChannel.FILTER_NONE)) {
if (!channel.isEnableUserOverride()) {
localMax = Math.min(localMax, channel.getFilterParam());
}
} else if (channel.getFilterType().equals(ChatChannel.FILTER_BY_TIME)) {
int days = channel.getFilterParam();
Date tmpDate = calculateDateByOffset(days);
if (!channel.isEnableUserOverride()) {
localDate = tmpDate;
}
}
// enforce maximum number of messages returned
if (localStart < 0) {
localStart = 0;
}
if (localMax < 0 || localMax > messagesMax) {
localMax = messagesMax;
}
Criteria c = this.getSession().createCriteria(ChatMessage.class);
c.add(Expression.eq("chatChannel", channel));
if (localDate != null) {
c.add(Expression.ge("messageDate", localDate));
}
// Always sort desc so we get the newest messages, reorder after we get the final list
c.addOrder(Order.desc("messageDate"));
if (localMax != 0) {
if (localMax > 0) {
c.setMaxResults(localMax);
}
if (localStart > 0) {
c.setFirstResult(localStart);
}
messages = c.list();
}
//Reorder the list
if (sortAsc) {
Collections.sort(messages, channelComparatorAsc);
} else {
Collections.sort(messages, channelComparatorDesc);
}
return messages;
}
/* (non-Javadoc)
* @see org.sakaiproject.chat2.model.ChatManager#countChannelMessages(org.sakaiproject.chat2.model.ChatChannel)
*/
public int countChannelMessages(ChatChannel channel) {
return getChannelMessagesCount(channel, null, null);
// use getChannelMessagesCount since it is more efficient
// Criteria c = this.getSession().createCriteria(ChatMessage.class);
// if (channel != null) {
// c.add(Expression.eq("chatChannel", channel));
// }
// List<ChatMessage> messages = c.list();
// return messages.size();
}
/* (non-Javadoc)
* @see org.sakaiproject.chat2.model.ChatManager#getChannelMessagesCount(org.sakaiproject.chat2.model.ChatChannel, java.lang.String, java.util.Date)
*/
public int getChannelMessagesCount(ChatChannel channel, String context, Date date) {
if (channel == null) {
// default to the first one
List<ChatChannel> channels = getContextChannels(context, true);
if (channels != null && channels.size() > 0) {
channel = channels.iterator().next();
}
}
int count = 0;
if (channel != null) {
Criteria c = this.getSession().createCriteria(ChatMessage.class);
c.add(Expression.eq("chatChannel", channel));
if (date != null) {
c.add(Expression.ge("messageDate", date));
}
c.setProjection(Projections.rowCount());
Integer countInt = (Integer) c.uniqueResult();
if (countInt != null) {
count = countInt.intValue();
}
}
return count;
}
/**
* {@inheritDoc}
*/
public ChatMessage createNewMessage(ChatChannel channel, String owner) throws PermissionException {
if (channel == null) {
throw new IllegalArgumentException("Must specify a channel");
}
// We don't support posting by anonymous users
if (owner == null) {
throw new PermissionException(null, ChatFunctions.CHAT_FUNCTION_NEW, channel.getContext());
}
checkPermission(ChatFunctions.CHAT_FUNCTION_NEW, channel.getContext());
ChatMessage message = new ChatMessage();
message.setChatChannel(channel);
message.setOwner(owner);
message.setMessageDate(new Date());
return message;
}
/**
* {@inheritDoc}
*/
public void updateMessage(ChatMessage message)
{
getHibernateTemplate().saveOrUpdate(message);
}
/**
* {@inheritDoc}
*/
public void migrateMessage(String sql, Object[] values) {
//String statement = "insert into CHAT2_MESSAGE (MESSAGE_ID, CHANNEL_ID, OWNER, MESSAGE_DATE, BODY, migratedMessageId) " +
// "select ?, ?, ?, ?, ?, ? from dual where not exists " +
// "(select * from CHAT2_MESSAGE m2 where m2.migratedMessageId=?)";
try {
String messageId = (String) values[0];
String channelId = (String) values[1];
String owner = (String) values[2];
Date messageDate = (Date) values[3];
String body = (String) values[4];
String migratedId= (String) values[5];
logger.debug("migrate message: "+messageId+", "+channelId);
ChatMessage message = getMigratedMessage(messageId);
if (owner == null) {
logger.warn("can't migrate message, owner is null. messageId: ["+messageId
+"] channelId: ["+channelId+"]");
return;
}
if(message == null && body != null && !body.equals("")) {
ChatChannel channel = getChatChannel(channelId);
message = new ChatMessage();
message.setId(messageId);
message.setChatChannel(channel);
message.setOwner(owner);
message.setMessageDate(messageDate);
message.setBody(FormattedText.convertPlaintextToFormattedText(body));
message.setMigratedMessageId(migratedId);
getHibernateTemplate().save(message);
}
} catch (Exception e) {
logger.error("migrateMessage: "+e);
}
}
/**
* {@inheritDoc}
*/
public boolean getCanDelete(ChatMessage message) {
if (message == null)
return false;
String context = message.getChatChannel().getContext();
boolean canDeleteAny = can(ChatFunctions.CHAT_FUNCTION_DELETE_ANY, context);
boolean canDeleteOwn = can(ChatFunctions.CHAT_FUNCTION_DELETE_OWN, context);
boolean isOwner = SessionManager.getCurrentSessionUserId() != null ?
SessionManager.getCurrentSessionUserId().equals(message.getOwner()) : false;
boolean canDelete = canDeleteAny;
if(canDeleteOwn && isOwner)
canDelete = true;
return canDelete;
}
/**
* {@inheritDoc}
*/
public boolean getCanDeleteAnyMessage(String context) {
return can(ChatFunctions.CHAT_FUNCTION_DELETE_ANY, context);
}
/**
* {@inheritDoc}
*/
public boolean getCanDelete(ChatChannel channel)
{
return channel == null ? false : can(ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL, channel.getContext());
}
/**
* {@inheritDoc}
*/
public boolean getCanEdit(ChatChannel channel)
{
return channel == null ? false : can(ChatFunctions.CHAT_FUNCTION_EDIT_CHANNEL, channel.getContext());
}
/**
* {@inheritDoc}
*/
public boolean getCanCreateChannel(String context)
{
return can(ChatFunctions.CHAT_FUNCTION_NEW_CHANNEL, context);
}
/**
* {@inheritDoc}
*/
public boolean getCanReadMessage(ChatChannel channel)
{
return channel == null ? false : can(ChatFunctions.CHAT_FUNCTION_READ, channel.getContext());
}
/**
* {@inheritDoc}
*/
public boolean getCanPostMessage(ChatChannel channel)
{
// We don't currently support posting messages by anonymous users
if (SessionManager.getCurrentSessionUserId() == null)
return false;
boolean allowed = false;
if (channel != null) {
allowed = can(ChatFunctions.CHAT_FUNCTION_NEW, channel.getContext());
if (allowed) {
// check the dates if they are set (https://jira.sakaiproject.org/browse/SAK-24207)
Date today = new Date();
Date start = channel.getStartDate();
if (start == null) {
start = today;
} else {
// fix up the date to shift to be beginning or end of the day (drop any time component)
start = DateUtils.truncate(start, Calendar.DATE);
}
Date end = channel.getEndDate();
if (end == null) {
end = today;
} else {
// fix up the date to shift to be beginning or end of the day (drop any time component)
end = DateUtils.truncate(end, Calendar.DATE);
end = DateUtils.addSeconds(end, 86398); // just short of a full day in seconds
}
if ( today.before(start) || today.after(end) ) {
// today is outside the configured dates so no posting allowed
allowed = false;
}
}
}
return allowed;
}
/**
* delete a Chat Message
* @param ChatMessage the message to delete
*/
public void deleteMessage(ChatMessage message) throws PermissionException
{
if(message==null) return;
if(!getCanDelete(message))
checkPermission(ChatFunctions.CHAT_FUNCTION_DELETE_ANY, message.getChatChannel().getContext());
getHibernateTemplate().delete(message);
sendDeleteMessage(message);
}
/**
* {@inheritDoc}
*/
public void deleteChannelMessages(ChatChannel channel) throws PermissionException {
if (channel == null)
return;
if (!getCanDeleteAnyMessage(channel.getContext()))
checkPermission(ChatFunctions.CHAT_FUNCTION_DELETE_ANY, channel.getContext());
channel = getChatChannel(channel.getId());
if (channel != null) {
channel.getMessages().size();
channel.getMessages().clear();
updateChannel(channel, false);
}
sendDeleteChannelMessages(channel);
}
/**
* {@inheritDoc}
*/
public ChatMessage getMessage(String chatMessageId) {
return (ChatMessage)getHibernateTemplate().get(
ChatMessage.class, chatMessageId);
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
protected ChatMessage getMigratedMessage(String migratedMessageId) {
List<ChatMessage> messages = getHibernateTemplate().findByNamedQuery("findMigratedMessage", migratedMessageId);
ChatMessage message = null;
if (messages.size() > 0)
message = messages.get(0);
return message;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public List<ChatChannel> getContextChannels(String context, boolean lazy) {
List<ChatChannel> channels = getHibernateTemplate().findByNamedQuery("findChannelsInContext", context);
if (!lazy) {
for (Iterator<ChatChannel> i = channels.iterator(); i.hasNext();) {
ChatChannel channel = i.next();
channel.getMessages().size();
}
}
return channels;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public List<ChatChannel> getContextChannels(String context, String defaultNewTitle, String placement) {
List<ChatChannel> channels = getHibernateTemplate().findByNamedQuery("findChannelsInContext", context);
if(channels.size() == 0) {
try {
ChatChannel channel = createNewChannel(context, defaultNewTitle, true, false, placement);
getHibernateTemplate().save(channel);
channels.add(channel);
}
catch (PermissionException e) {
logger.debug("Ignoring exception since it shouldn't be thrown here as we're not checking");
}
}
return channels;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public ChatChannel getDefaultChannel(String contextId, String placement) {
List<ChatChannel> channels = getHibernateTemplate().findByNamedQuery("findDefaultChannelsInContext", new Object[] {contextId, placement});
if (channels.size() == 0) {
channels = getContextChannels(contextId, "", placement);
}
if (channels.size() >= 1)
return (ChatChannel)channels.get(0);
return null;
}
/**
* {@inheritDoc}
*/
public void addRoomListener(RoomObserver observer, String roomId)
{
List<RoomObserver> roomObservers;
synchronized(roomListeners) {
if(roomListeners.get(roomId) == null)
roomListeners.put(roomId, new ArrayList<RoomObserver>());
roomObservers = roomListeners.get(roomId);
}
synchronized(roomObservers) {
roomObservers.add(observer);
}
if (logger.isDebugEnabled()) {
logger.debug("after add roomObservers " + roomObservers);
}
}
/**
* {@inheritDoc}
*/
public void removeRoomListener(RoomObserver observer, String roomId)
{
if(roomListeners.get(roomId) != null) {
List<RoomObserver> roomObservers = roomListeners.get(roomId);
if(roomObservers != null) {
synchronized(roomObservers) {
roomObservers.remove(observer);
if(roomObservers.size() == 0) {
synchronized(roomListeners) {
roomListeners.remove(roomId);
}
}
}
} // end if(roomObservers != null)
if (logger.isDebugEnabled()) {
logger.debug("after remove roomObservers " + roomObservers);
}
}
}
/**
* {@inheritDoc}
*/
public void sendMessage(ChatMessage message) {
ChatMessageTxSync txSync = new ChatMessageTxSync(message);
getHibernateTemplate().flush();
txSync.afterCompletion(ChatMessageTxSync.STATUS_COMMITTED);
}
/**
* {@inheritDoc}
*/
public void sendDeleteMessage(ChatMessage message) {
ChatMessageDeleteTxSync txSync = new ChatMessageDeleteTxSync(message);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(txSync);
}
else {
txSync.afterCompletion(ChatMessageDeleteTxSync.STATUS_COMMITTED);
}
}
/**
* {@inheritDoc}
*/
public void sendDeleteChannel(ChatChannel channel) {
ChatChannelDeleteTxSync txSync = new ChatChannelDeleteTxSync(channel);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(txSync);
}
else {
txSync.afterCompletion(ChatChannelDeleteTxSync.STATUS_COMMITTED);
}
}
/**
* {@inheritDoc}
*/
public void sendDeleteChannelMessages(ChatChannel channel) {
ChatChannelMessagesDeleteTxSync txSync = new ChatChannelMessagesDeleteTxSync(channel);
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(txSync);
}
else {
txSync.afterCompletion(ChatChannelMessagesDeleteTxSync.STATUS_COMMITTED);
}
}
/**
* This helps to send out the message when the record is placed in the database
* @author andersjb
*
*/
private class ChatMessageDeleteTxSync extends TransactionSynchronizationAdapter {
private ChatMessage message;
public ChatMessageDeleteTxSync(ChatMessage message) {
this.message = message;
}
public void afterCompletion(int status) {
Event event = null;
String function = ChatFunctions.CHAT_FUNCTION_DELETE_ANY;
if (message.getOwner().equals(SessionManager.getCurrentSessionUserId()))
{
// own or any
function = ChatFunctions.CHAT_FUNCTION_DELETE_OWN;
}
event = EventTrackingService.newEvent(function,
message.getReference(), false);
if (event != null)
EventTrackingService.post(event);
}
}
/**
* This helps to send out the message when the record is placed in the database
* @author andersjb
*
*/
private class ChatMessageTxSync extends TransactionSynchronizationAdapter {
private ChatMessage message;
public ChatMessageTxSync(ChatMessage message) {
this.message = message;
}
public void afterCompletion(int status) {
Event event = null;
event = EventTrackingService.newEvent(ChatFunctions.CHAT_FUNCTION_NEW,
message.getReference(), false);
if (event != null)
EventTrackingService.post(event);
}
}
/**
* This helps to send out the message when the record is placed in the database
* @author andersjb
*
*/
private class ChatChannelDeleteTxSync extends TransactionSynchronizationAdapter {
private ChatChannel channel;
public ChatChannelDeleteTxSync(ChatChannel channel) {
this.channel = channel;
}
public void afterCompletion(int status) {
Event event = null;
event = EventTrackingService.newEvent(ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL,
channel.getReference(), false);
if (event != null)
EventTrackingService.post(event);
}
}
/**
* This helps to send out the message when the messages are all deleted
* @author andersjb
*
*/
private class ChatChannelMessagesDeleteTxSync extends TransactionSynchronizationAdapter {
private ChatChannel channel;
public ChatChannelMessagesDeleteTxSync(ChatChannel channel) {
this.channel = channel;
}
public void afterCompletion(int status) {
Event event = null;
event = EventTrackingService.newEvent(ChatFunctions.CHAT_FUNCTION_DELETE_ANY,
channel.getReference(), false);
if (event != null)
EventTrackingService.post(event);
}
}
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* This operates within its own Thread so normal rules and conditions don't apply
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
@SuppressWarnings("unchecked")
public void update(Observable o, Object arg) {
if (arg instanceof Event) {
Event event = (Event)arg;
Reference ref = getEntityManager().newReference(event.getResource());
if (event.getEvent().equals(ChatFunctions.CHAT_FUNCTION_NEW)) {
// get the actual message and distribute it. Otherwise each
// observer will fetch their own copy of the message.
String id = ref.getId();
if (id == null)
return;
ChatMessage message = getMessage(ref.getId());
if (message == null)
return;
//String[] messageParams = event.getResource().split(":");
ArrayList<RoomObserver> observers = (ArrayList<RoomObserver>) roomListeners.get(ref.getContainer());
// originally we did the iteration inside synchronized.
// however that turns out to hold the lock too long
// a shallow copy of an arraylist shouldn't be bad.
// we currently call removeRoom from receivedMessage in
// some cases, so it can't be locked or we will deadlock
if(observers != null) {
synchronized(observers) {
observers = (ArrayList)observers.clone();
}
for(Iterator<RoomObserver> i = observers.iterator(); i.hasNext(); ) {
RoomObserver observer = i.next();
observer.receivedMessage(ref.getContainer(), message);
}
}
} else if (event.getEvent().equals(ChatFunctions.CHAT_FUNCTION_DELETE_CHANNEL)) {
//String chatChannelId = event.getResource();
ArrayList<RoomObserver> observers = (ArrayList<RoomObserver>) roomListeners.get(ref.getId());
if(observers != null) {
synchronized(observers) {
observers = (ArrayList)observers.clone();
}
for(Iterator<RoomObserver> i = observers.iterator(); i.hasNext(); ) {
RoomObserver observer = i.next();
observer.roomDeleted(ref.getId());
}
}
}
}
}
/**
* Resets the passed context's default channel
*
*/
protected void resetPlacementDefaultChannel(String context, String placement) {
Session session = null;
Connection conn = null;
PreparedStatement statement = null;
String query="update CHAT2_CHANNEL c set c.placementDefaultChannel=?, c.PLACEMENT_ID=? " +
"WHERE c.context=? and c.PLACEMENT_ID=?";
try{
session = getSession();
conn = session.connection();
statement = conn.prepareStatement(query);
statement.setBoolean(1, false);
statement.setString(2, null);
statement.setString(3, context);
statement.setString(4, placement);
statement.executeUpdate();
}
catch(Exception e){
logger.warn(e.getMessage());
}
finally{
if (statement != null) {
//ensure the statement is closed
try {
statement.close();
}
catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug(e);
}
}
}
try{
if (conn !=null) conn.close();
}
catch(Exception ex){
logger.warn(ex.getMessage());
}
}
}
/**
* {@inheritDoc}
*/
public void makeDefaultContextChannel(ChatChannel channel, String placement) {
//reset context's defaults
if (isMaintainer(channel.getContext())) {
try {
resetPlacementDefaultChannel(channel.getContext(), placement);
//set new one as default
channel.setPlacementDefaultChannel(true);
channel.setPlacement(placement);
updateChannel(channel, false);
}
catch (PermissionException e) {
logger.debug("Ignoring PermissionException since it is unchecked here.");
}
}
}
protected void checkPermission(String function, String context) throws PermissionException {
if (!SecurityService.unlock(function, SiteService.siteReference(context)))
{
String user = SessionManager.getCurrentSessionUserId();
throw new PermissionException(user, function, context);
}
}
protected boolean can(String function, String context) {
return SecurityService.unlock(function, SiteService.siteReference(context));
}
/**
* {@inheritDoc}
*/
public boolean isMaintainer(String context) {
return SecurityService.unlock(SiteService.SECURE_UPDATE_SITE, SiteService.siteReference(context));
}
protected String getSummaryFromHeader(ChatMessage item) throws UserNotDefinedException
{
String body = item.getBody();
if ( body.length() > 50 ) body = body.substring(1,49);
User user = UserDirectoryService.getUser(item.getOwner());
Time messageTime = TimeService.newTime(item.getMessageDate().getTime());
String newText = body + ", " + user.getDisplayName() + ", " + messageTime.toStringLocalFull();
return newText;
}
/**********************************************************************************************************************************************************************************************************************************************************
* getSummary implementation
*********************************************************************************************************************************************************************************************************************************************************/
public Map<String,String> getSummary(String channel, int items, int days)
throws IdUsedException, IdInvalidException, PermissionException
{
long startTime = System.currentTimeMillis() - (days * 24l * 60l * 60l * 1000l);
List<ChatMessage> messages = getChannelMessages(getChatChannel(channel), new Date(startTime), 0, items, true);
Iterator<ChatMessage> iMsg = messages.iterator();
Time pubDate = null;
String summaryText = null;
Map<String,String> m = new HashMap<String,String>();
while (iMsg.hasNext()) {
ChatMessage item = iMsg.next();
//MessageHeader header = item.getHeader();
Time newTime = TimeService.newTime(item.getMessageDate().getTime());
if ( pubDate == null || newTime.before(pubDate) ) pubDate = newTime;
try {
String newText = getSummaryFromHeader(item);
if ( summaryText == null ) {
summaryText = newText;
} else {
summaryText = summaryText + "<br>\r\n" + newText;
}
}
catch (UserNotDefinedException e) {
logger.warn("Skipping the chat message for user: " + item.getOwner() + " since they cannot be found");
}
}
if ( pubDate != null ) {
m.put(Summary.PROP_PUBDATE, pubDate.toStringRFC822Local());
}
if ( summaryText != null ) {
m.put(Summary.PROP_DESCRIPTION, summaryText);
return m;
}
return null;
}
/**
* @return the entityManager
*/
public EntityManager getEntityManager() {
return entityManager;
}
/**
* @param entityManager the entityManager to set
*/
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* Access the partial URL that forms the root of resource URLs.
*
* @param relative
* if true, form within the access path only (i.e. starting with /msg)
* @return the partial URL that forms the root of resource URLs.
*/
protected String getAccessPoint(boolean relative)
{
return (relative ? "" : ServerConfigurationService.getAccessUrl()) + REFERENCE_ROOT;
} // getAccessPoint
/**
* {@inheritDoc}
*/
public String[] summarizableToolIds() {
String[] toolIds = { CHAT_TOOL_ID };
return toolIds;
}
/**
* {@inheritDoc}
*/
public String getSummarizableReference(String siteId, String toolIdentifier) {
//I think this should just return null so we get all channels.
return null;
}
/**
* {@inheritDoc}
*/
public String getLabel() {
return CHAT;
}
/**
* {@inheritDoc}
*/
public ChatChannel getDefaultChannelSettings() {
return defaultChannelSettings;
}
/**
* {@inheritDoc}
*/
public void setDefaultChannelSettings(ChatChannel defaultChannelSettings) {
this.defaultChannelSettings = defaultChannelSettings;
}
public void setMessagesMax(int messagesMax) {
this.messagesMax = messagesMax;
}
public int getMessagesMax() {
return messagesMax;
}
}