/****************************************************************************
* Copyright (c) 2004 Composent, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Composent, Inc. - initial API and implementation
*****************************************************************************/
package org.eclipse.ecf.internal.provider.xmpp;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IAdapterManager;
import org.eclipse.ecf.core.ContainerCreateException;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.internal.provider.xmpp.smack.ECFConnection;
import org.eclipse.ecf.presence.chatroom.ChatRoomCreateException;
import org.eclipse.ecf.presence.chatroom.IChatRoomContainer;
import org.eclipse.ecf.presence.chatroom.IChatRoomInfo;
import org.eclipse.ecf.presence.chatroom.IChatRoomInvitationListener;
import org.eclipse.ecf.presence.chatroom.IChatRoomInvitationSender;
import org.eclipse.ecf.presence.chatroom.IChatRoomManager;
import org.eclipse.ecf.presence.history.IHistory;
import org.eclipse.ecf.presence.history.IHistoryManager;
import org.eclipse.ecf.provider.xmpp.identity.XMPPID;
import org.eclipse.ecf.provider.xmpp.identity.XMPPRoomID;
import org.eclipse.osgi.util.NLS;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.muc.HostedRoom;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.RoomInfo;
import org.jivesoftware.smackx.packet.DiscoverItems;
public class XMPPChatRoomManager implements IChatRoomManager {
private static final String PROP_XMPP_SUBJECT = "subject"; //$NON-NLS-1$
// key in the create room configuration in order to find the please to find
// the conference rooms on the XMPP server
public static final String PROP_XMPP_CONFERENCE = "conference"; //$NON-NLS-1$
private ID containerID = null;
private Namespace connectNamespace = null;
private final List invitationListeners = new ArrayList();
private ECFConnection ecfConnection = null;
private final List chatrooms = new ArrayList();
private ID connectedID = null;
private final IChatRoomInvitationSender invitationSender = new IChatRoomInvitationSender() {
public void sendInvitation(ID room, ID targetUser, String subject, String body) throws ECFException {
XMPPChatRoomManager.this.sendInvitation(room, targetUser, subject, body);
}
};
public XMPPChatRoomManager(ID containerID) {
this.containerID = containerID;
}
/**
* @param room
* @param targetUser
* @param subject
* @param body
*/
protected void sendInvitation(ID room, ID targetUser, String subject, String body) throws ECFException {
final XMPPChatRoomContainer chatRoomContainer = getChatRoomContainer(room);
if (chatRoomContainer == null)
throw new ECFException(NLS.bind(Messages.XMPPChatRoomManager_ROOM_NOT_FOUND, room.getName()));
chatRoomContainer.sendInvitation(targetUser, subject, body);
}
protected void addChat(XMPPChatRoomContainer container) {
synchronized (chatrooms) {
chatrooms.add(container);
}
}
protected void removeChat(XMPPChatRoomContainer container) {
synchronized (chatrooms) {
chatrooms.remove(container);
}
}
protected XMPPChatRoomContainer getChatRoomContainer(ID roomID) {
if (roomID == null)
return null;
List toNotify = null;
synchronized (chatrooms) {
toNotify = new ArrayList(chatrooms);
}
for (final Iterator i = toNotify.iterator(); i.hasNext();) {
final XMPPChatRoomContainer container = (XMPPChatRoomContainer) i.next();
final ID containerRoomID = container.getConnectedID();
if (containerRoomID == null)
continue;
if (containerRoomID.equals(roomID))
return container;
}
return null;
}
protected ID createRoomIDFromName(String from) {
try {
return new XMPPRoomID(connectNamespace, ecfConnection.getXMPPConnection(), from);
} catch (final URISyntaxException e) {
return null;
}
}
protected ID createUserIDFromName(String name) {
ID result = null;
try {
result = new XMPPID(connectNamespace, name);
return result;
} catch (final Exception e) {
return null;
}
}
public void setConnection(Namespace connectNamespace, ID connectedID, ECFConnection connection) {
this.connectNamespace = connectNamespace;
this.connectedID = connectedID;
this.ecfConnection = connection;
if (connection != null) {
// Setup invitation requestListener
MultiUserChat.addInvitationListener(ecfConnection.getXMPPConnection(), new InvitationListener() {
public void invitationReceived(Connection arg0, String arg1, String arg2, String arg3, String arg4, Message arg5) {
fireInvitationReceived(createRoomIDFromName(arg1), createUserIDFromName(arg2), createUserIDFromName(arg5.getTo()), arg5.getSubject(), arg3);
}
});
} else {
disposeChatRooms();
}
}
protected void disposeChatRooms() {
List toNotify = null;
synchronized (chatrooms) {
toNotify = new ArrayList(chatrooms);
chatrooms.clear();
}
for (final Iterator i = toNotify.iterator(); i.hasNext();) {
final IChatRoomContainer cc = (IChatRoomContainer) i.next();
cc.dispose();
}
}
public void dispose() {
synchronized (invitationListeners) {
invitationListeners.clear();
}
containerID = null;
connectNamespace = null;
disposeChatRooms();
setConnection(null, null, null);
}
class ECFRoomInfo implements IChatRoomInfo {
RoomInfo info;
XMPPRoomID roomID;
ID connectedID;
public ECFRoomInfo(XMPPRoomID roomID, RoomInfo info, ID connectedID) {
this.roomID = roomID;
this.info = info;
this.connectedID = connectedID;
}
public String getDescription() {
return info.getDescription();
}
public String getSubject() {
return info.getSubject();
}
public ID getRoomID() {
return roomID;
}
public int getParticipantsCount() {
return info.getOccupantsCount();
}
public String getName() {
return roomID.getLongName();
}
public boolean isPersistent() {
return info.isPersistent();
}
public boolean requiresPassword() {
return info.isPasswordProtected();
}
public boolean isModerated() {
return info.isModerated();
}
public ID getConnectedID() {
return roomID;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == null)
return null;
if (adapter.isInstance(this))
return this;
final IAdapterManager adapterManager = XmppPlugin.getDefault().getAdapterManager();
return (adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName());
}
public IChatRoomContainer createChatRoomContainer() throws ContainerCreateException {
XMPPChatRoomContainer chatContainer = null;
if (ecfConnection == null)
throw new ContainerCreateException(Messages.XMPPChatRoomManager_EXCEPTION_CONTAINER_DISCONNECTED);
try {
chatContainer = new XMPPChatRoomContainer(ecfConnection, connectNamespace);
addChat(chatContainer);
return chatContainer;
} catch (final IDCreateException e) {
throw new ContainerCreateException(Messages.XMPPChatRoomManager_EXCEPTION_CREATING_CHAT_CONTAINER, e);
}
}
public String toString() {
final StringBuffer buf = new StringBuffer("ECFRoomInfo["); //$NON-NLS-1$
buf.append("id=").append(containerID).append(";name=" + getName()); //$NON-NLS-1$ //$NON-NLS-2$
buf.append(";service=" + getConnectedID()); //$NON-NLS-1$
buf.append(";count=" + getParticipantsCount()); //$NON-NLS-1$
buf.append(";subject=" + getSubject()).append( //$NON-NLS-1$
";desc=" + getDescription()); //$NON-NLS-1$
buf.append(";pers=" + isPersistent()).append( //$NON-NLS-1$
";pw=" + requiresPassword()); //$NON-NLS-1$
buf.append(";mod=" + isModerated()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
return buf.toString();
}
}
public IChatRoomManager[] getChildren() {
return new IChatRoomManager[0];
}
protected ID createIDFromHostedRoom(HostedRoom room) {
try {
return new XMPPRoomID(connectNamespace, ecfConnection.getXMPPConnection(), room.getJid(), room.getName());
} catch (final URISyntaxException e) {
// debug output
return null;
}
}
public IChatRoomContainer findReceiverChatRoom(ID toID) {
if (toID == null)
return null;
XMPPRoomID roomID = null;
if (toID instanceof XMPPRoomID) {
roomID = (XMPPRoomID) toID;
final String mucname = roomID.getMucString();
List toNotify = null;
synchronized (chatrooms) {
toNotify = new ArrayList(chatrooms);
}
for (final Iterator i = toNotify.iterator(); i.hasNext();) {
final IChatRoomContainer cont = (IChatRoomContainer) i.next();
if (cont == null)
continue;
final ID tid = cont.getConnectedID();
if (tid != null && tid instanceof XMPPRoomID) {
final XMPPRoomID targetID = (XMPPRoomID) tid;
final String tmuc = targetID.getMucString();
if (tmuc.equals(mucname)) {
return cont;
}
}
}
}
return null;
}
protected ID[] getChatRooms() {
if (ecfConnection == null)
return null;
final XMPPConnection conn = ecfConnection.getXMPPConnection();
if (conn == null)
return null;
final Collection result = new ArrayList();
try {
final Collection svcs = MultiUserChat.getServiceNames(conn);
for (final Iterator svcsi = svcs.iterator(); svcsi.hasNext();) {
final String svc = (String) svcsi.next();
final Collection rooms = MultiUserChat.getHostedRooms(conn, svc);
for (final Iterator roomsi = rooms.iterator(); roomsi.hasNext();) {
final HostedRoom room = (HostedRoom) roomsi.next();
final ID roomID = createIDFromHostedRoom(room);
if (roomID != null)
result.add(roomID);
}
}
} catch (final XMPPException e) {
return null;
}
return (ID[]) result.toArray(new ID[] {});
}
protected IChatRoomInfo getChatRoomInfo(ID roomID) {
if (!(roomID instanceof XMPPRoomID))
return null;
final XMPPRoomID cRoomID = (XMPPRoomID) roomID;
try {
final RoomInfo info = MultiUserChat.getRoomInfo(ecfConnection.getXMPPConnection(), cRoomID.getMucString());
if (info != null) {
return new ECFRoomInfo(cRoomID, info, connectedID);
}
} catch (final XMPPException e) {
return null;
}
return null;
}
public IChatRoomInfo getChatRoomInfo(String roomname) {
try {
if (ecfConnection == null)
return null;
// Create roomid
final XMPPConnection conn = ecfConnection.getXMPPConnection();
final XMPPRoomID roomID = new XMPPRoomID(connectNamespace, conn, roomname);
final String mucName = roomID.getMucString();
final RoomInfo info = MultiUserChat.getRoomInfo(conn, mucName);
if (info != null) {
return new ECFRoomInfo(roomID, info, connectedID);
}
} catch (final Exception e) {
return null;
}
return null;
}
public IChatRoomInfo[] getChatRoomInfos() {
final ID[] chatRooms = getChatRooms();
if (chatRooms == null)
return new IChatRoomInfo[0];
final IChatRoomInfo[] res = new IChatRoomInfo[chatRooms.length];
int count = 0;
for (int i = 0; i < chatRooms.length; i++) {
final IChatRoomInfo infoResult = getChatRoomInfo(chatRooms[i]);
if (infoResult != null) {
res[count++] = infoResult;
}
}
final IChatRoomInfo[] results = new IChatRoomInfo[count];
for (int i = 0; i < count; i++) {
results[i] = res[i];
}
return results;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == null)
return null;
if (adapter.isInstance(this))
return this;
final IAdapterManager adapterManager = XmppPlugin.getDefault().getAdapterManager();
return (adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName());
}
public void addInvitationListener(IChatRoomInvitationListener listener) {
synchronized (invitationListeners) {
invitationListeners.add(listener);
}
}
public void removeInvitationListener(IChatRoomInvitationListener listener) {
synchronized (invitationListeners) {
invitationListeners.remove(listener);
}
}
protected void fireInvitationReceived(ID roomID, ID fromID, ID toID, String subject, String body) {
List toNotify = null;
synchronized (invitationListeners) {
toNotify = new ArrayList(invitationListeners);
}
for (final Iterator i = toNotify.iterator(); i.hasNext();) {
final IChatRoomInvitationListener l = (IChatRoomInvitationListener) i.next();
l.handleInvitationReceived(roomID, fromID, subject, body);
}
}
public IChatRoomManager getParent() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.presence.chatroom.IChatRoomManager#createChatRoom(java.lang.String,
* java.util.Map)
*/
public IChatRoomInfo createChatRoom(String roomname, Map properties) throws ChatRoomCreateException {
if (roomname == null)
throw new ChatRoomCreateException(roomname, Messages.XMPPChatRoomManager_EXCEPTION_ROOM_CANNOT_BE_NULL);
try {
final String nickname = ecfConnection.getXMPPConnection().getUser();
final String server = ecfConnection.getXMPPConnection().getHost();
final String domain = (properties == null) ? XMPPRoomID.DOMAIN_DEFAULT : (String) properties.get(PROP_XMPP_CONFERENCE);
final String conference = XMPPRoomID.fixConferenceDomain(domain, server);
final String roomID = roomname + XMPPRoomID.AT_SIGN + conference;
// create proxy to the room
final MultiUserChat muc = new MultiUserChat(ecfConnection.getXMPPConnection(), roomID);
if (!checkRoom(conference, roomID)) {
// otherwise create a new one
muc.create(nickname);
muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
final String subject = (properties == null) ? null : (String) properties.get(PROP_XMPP_SUBJECT);
if (subject != null)
muc.changeSubject(subject);
}
String longname = muc.getRoom();
if (longname == null || longname.length() <= 0) {
longname = roomID;
}
final RoomInfo info = MultiUserChat.getRoomInfo(ecfConnection.getXMPPConnection(), roomID);
if (info != null) {
final XMPPRoomID xid = new XMPPRoomID(connectedID.getNamespace(), ecfConnection.getXMPPConnection(), roomID, longname);
return new ECFRoomInfo(xid, info, connectedID);
} else
throw new XMPPException(NLS.bind(Messages.XMPPChatRoomManager_EXCEPTION_NO_ROOM_INFO, roomID));
} catch (final XMPPException e) {
throw new ChatRoomCreateException(roomname, e.getMessage(), e);
} catch (final URISyntaxException e) {
throw new ChatRoomCreateException(roomname, e.getMessage(), e);
}
}
/**
* check if the MultiUserChat room is already existing on the XMPP server.
*
* @param conference
* @param room
* the name of the room
* @return true, if the room exists, false otherwise
* @throws XMPPException
*/
protected boolean checkRoom(String conference, String room) throws XMPPException {
final XMPPConnection conn = ecfConnection.getXMPPConnection();
final ServiceDiscoveryManager serviceDiscoveryManager = new ServiceDiscoveryManager(conn);
final DiscoverItems result = serviceDiscoveryManager.discoverItems(conference);
for (final Iterator items = result.getItems(); items.hasNext();) {
final DiscoverItems.Item item = ((DiscoverItems.Item) items.next());
if (room.equals(item.getEntityID())) {
return true;
}
}
return false;
}
protected IHistoryManager chatRoomHistoryManager = new IHistoryManager() {
public IHistory getHistory(ID chatRoomID, Map options) {
// TODO Auto-generated method stub
return null;
}
public boolean isActive() {
// TODO Auto-generated method stub
return false;
}
public void setActive(boolean active) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if (adapter == null)
return null;
if (adapter.isInstance(this))
return this;
final IAdapterManager adapterManager = XmppPlugin.getDefault().getAdapterManager();
return (adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName());
}
};
public IHistoryManager getHistoryManager() {
return chatRoomHistoryManager;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ecf.presence.chatroom.IChatRoomManager#getInvitationSender()
*/
public IChatRoomInvitationSender getInvitationSender() {
return invitationSender;
}
}