/*
* Copyright (c) 2007-2012 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.buddies.internal.server;
import org.eclipse.net4j.buddies.common.IAccount;
import org.eclipse.net4j.buddies.common.IBuddy;
import org.eclipse.net4j.buddies.common.IBuddyStateEvent;
import org.eclipse.net4j.buddies.common.ICollaboration;
import org.eclipse.net4j.buddies.common.ISession;
import org.eclipse.net4j.buddies.internal.common.Account;
import org.eclipse.net4j.buddies.internal.common.Buddy;
import org.eclipse.net4j.buddies.internal.common.Collaboration;
import org.eclipse.net4j.buddies.internal.common.CollaborationContainer;
import org.eclipse.net4j.buddies.internal.common.Membership;
import org.eclipse.net4j.buddies.internal.common.protocol.BuddyStateNotification;
import org.eclipse.net4j.buddies.internal.server.bundle.OM;
import org.eclipse.net4j.buddies.internal.server.protocol.BuddiesServerProtocol;
import org.eclipse.net4j.buddies.internal.server.protocol.BuddyRemovedNotification;
import org.eclipse.net4j.buddies.internal.server.protocol.CollaborationInitiatedNotification;
import org.eclipse.net4j.buddies.server.IBuddyAdmin;
import org.eclipse.net4j.buddies.spi.common.ServerFacilityFactory;
import org.eclipse.net4j.channel.IChannel;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.lifecycle.ILifecycleEvent;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author Eike Stepper
*/
public class BuddyAdmin extends CollaborationContainer implements IBuddyAdmin
{
public static final BuddyAdmin INSTANCE = new BuddyAdmin();
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, BuddyAdmin.class);
private ConcurrentMap<String, IAccount> accounts = new ConcurrentHashMap<String, IAccount>();
private ConcurrentMap<String, ISession> sessions = new ConcurrentHashMap<String, ISession>();
private long lastCollaborationID;
public BuddyAdmin()
{
activate();
}
public Map<String, IAccount> getAccounts()
{
return accounts;
}
public ISession getSession(IBuddy buddy)
{
return getSession(buddy.getUserID());
}
public ISession getSession(String userID)
{
return sessions.get(userID);
}
public ISession[] getSessions()
{
return sessions.values().toArray(new ISession[sessions.size()]);
}
public IBuddy[] getBuddies()
{
List<IBuddy> buddies = new ArrayList<IBuddy>();
for (ISession session : sessions.values())
{
buddies.add(session.getSelf());
}
return buddies.toArray(new IBuddy[buddies.size()]);
}
public IBuddy getBuddy(String userID)
{
ISession session = getSession(userID);
if (session == null)
{
return null;
}
return session.getSelf();
}
public synchronized ISession openSession(IChannel channel, String userID, String password, String[] facilityTypes)
{
if (sessions.containsKey(userID))
{
return null;
}
IAccount account = accounts.get(userID);
if (account != null)
{
if (!account.authenticate(password))
{
return null;
}
}
else
{
account = new Account(userID, password);
accounts.put(userID, account);
}
ServerBuddy buddy = new ServerBuddy(account, facilityTypes);
buddy.activate();
buddy.addListener(this);
BuddiesServerProtocol protocol = (BuddiesServerProtocol)channel.getReceiveHandler();
ServerSession session = new ServerSession(protocol, buddy);
protocol.setInfraStructure(session);
session.addListener(this);
buddy.setSession(session);
LifecycleUtil.activate(session);
if (TRACER.isEnabled())
{
TRACER.trace("Opened session: " + userID); //$NON-NLS-1$
}
sessions.put(userID, session);
return session;
}
public ICollaboration initiateCollaboration(IBuddy initiator, String... userIDs)
{
long collaborationID;
synchronized (this)
{
collaborationID = ++lastCollaborationID;
}
Collaboration collaboration = new Collaboration(collaborationID);
collaboration.activate();
Membership.create(initiator, collaboration);
Set<IBuddy> buddies = new HashSet<IBuddy>();
buddies.add(initiator);
for (String userID : userIDs)
{
Buddy buddy = (Buddy)getBuddy(userID);
if (buddy != null)
{
buddies.add(buddy);
Membership.create(buddy, collaboration);
}
}
addCollaboration(collaboration);
Set<IBuddy> invitations = new HashSet<IBuddy>(buddies);
for (IBuddy buddy : buddies)
{
if (buddy != initiator)
{
try
{
invitations.remove(buddy);
BuddiesServerProtocol protocol = (BuddiesServerProtocol)buddy.getSession().getProtocol();
new CollaborationInitiatedNotification(protocol, collaborationID, invitations, null).sendAsync();
}
catch (Exception ex)
{
OM.LOG.error(ex);
}
finally
{
invitations.add(buddy);
}
}
}
return collaboration;
}
@Override
public void notifyEvent(IEvent event)
{
if (event.getSource() instanceof ServerSession)
{
if (event instanceof ILifecycleEvent)
{
if (((ILifecycleEvent)event).getKind() == ILifecycleEvent.Kind.DEACTIVATED)
{
String userID = ((ServerSession)event.getSource()).getSelf().getUserID();
synchronized (this)
{
ServerSession removed = (ServerSession)sessions.remove(userID);
if (removed != null)
{
removed.removeListener(this);
removed.getSelf().removeListener(this);
for (ISession session : sessions.values())
{
try
{
BuddiesServerProtocol protocol = (BuddiesServerProtocol)session.getProtocol();
new BuddyRemovedNotification(protocol, userID).sendAsync();
}
catch (Exception ex)
{
OM.LOG.error(ex);
}
}
}
}
}
}
}
else if (event.getSource() instanceof ServerBuddy)
{
if (event instanceof IBuddyStateEvent)
{
IBuddyStateEvent e = (IBuddyStateEvent)event;
synchronized (this)
{
for (ISession session : sessions.values())
{
try
{
if (!ObjectUtil.equals(session.getSelf(), e.getSource()))
{
BuddiesServerProtocol protocol = (BuddiesServerProtocol)session.getProtocol();
new BuddyStateNotification(protocol, e.getSource().getUserID(), e.getNewState()).sendAsync();
}
}
catch (Exception ex)
{
OM.LOG.error(ex);
}
}
}
}
}
}
public static Set<String> getFacilityTypes()
{
return IPluginContainer.INSTANCE.getFactoryTypes(ServerFacilityFactory.PRODUCT_GROUP);
}
}