|
After Width: | Height: | Size: 635 B |
|
After Width: | Height: | Size: 399 B |
|
After Width: | Height: | Size: 560 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 404 B |
|
After Width: | Height: | Size: 316 B |
|
After Width: | Height: | Size: 337 B |
|
After Width: | Height: | Size: 796 B |
|
After Width: | Height: | Size: 844 B |
|
After Width: | Height: | Size: 461 B |
|
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,480 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.jabber;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jivesoftware.smack.*;
|
||||
import org.jivesoftware.smack.filter.*;
|
||||
import org.jivesoftware.smack.packet.*;
|
||||
import org.jivesoftware.smack.provider.*;
|
||||
import org.jivesoftware.smack.util.*;
|
||||
import org.jivesoftware.smackx.*;
|
||||
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.Message;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.service.protocol.jabberconstants.*;
|
||||
|
||||
/**
|
||||
* A straightforward implementation of the basic instant messaging operation
|
||||
* set.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class OperationSetBasicInstantMessagingJabberImpl
|
||||
implements OperationSetBasicInstantMessaging
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OperationSetBasicInstantMessagingJabberImpl.class);
|
||||
|
||||
/**
|
||||
* KeepAlive interval for sending packets
|
||||
*/
|
||||
private static long KEEPALIVE_INTERVAL = 180000l; // 3 minutes
|
||||
|
||||
/**
|
||||
* The interval after which a packet is considered to be lost
|
||||
*/
|
||||
private static long KEEPALIVE_WAIT = 20000l;
|
||||
|
||||
/**
|
||||
* The task sending packets
|
||||
*/
|
||||
private KeepAliveSendTask keepAliveSendTask = null;
|
||||
/**
|
||||
* The timer executing tasks on specified intervals
|
||||
*/
|
||||
private Timer keepAliveTimer = new Timer();
|
||||
/**
|
||||
* The queue holding the received packets
|
||||
*/
|
||||
private LinkedList receivedKeepAlivePackets = new LinkedList();
|
||||
|
||||
/**
|
||||
* A list of listeneres registered for message events.
|
||||
*/
|
||||
private Vector messageListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceJabberImpl jabberProvider = null;
|
||||
|
||||
/**
|
||||
* A reference to the persistent presence operation set that we use
|
||||
* to match incoming messages to <tt>Contact</tt>s and vice versa.
|
||||
*/
|
||||
private OperationSetPersistentPresenceJabberImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this operation set.
|
||||
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
|
||||
* that created us and that we'll use for retrieving the underlying aim
|
||||
* connection.
|
||||
*/
|
||||
OperationSetBasicInstantMessagingJabberImpl(
|
||||
ProtocolProviderServiceJabberImpl provider)
|
||||
{
|
||||
this.jabberProvider = provider;
|
||||
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
|
||||
|
||||
// register the KeepAlive Extension in the smack library
|
||||
ProviderManager.addExtensionProvider(KeepAliveEventProvider.ELEMENT_NAME,
|
||||
KeepAliveEventProvider.NAMESPACE,
|
||||
new KeepAliveEventProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registeres a MessageListener with this operation set so that it gets
|
||||
* notifications of successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to register.
|
||||
*/
|
||||
public void addMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
if(!messageListeners.contains(listener))
|
||||
{
|
||||
this.messageListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisteres <tt>listener</tt> so that it won't receive any further
|
||||
* notifications upon successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to unregister.
|
||||
*/
|
||||
public void removeMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
this.messageListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending arbitrary MIME-encoding content.
|
||||
*
|
||||
* @param content content value
|
||||
* @param contentType the MIME-type for <tt>content</tt>
|
||||
* @param contentEncoding encoding used for <tt>content</tt>
|
||||
* @param subject a <tt>String</tt> subject or <tt>null</tt> for now subject.
|
||||
* @return the newly created message.
|
||||
*/
|
||||
public Message createMessage(byte[] content, String contentType,
|
||||
String contentEncoding, String subject)
|
||||
{
|
||||
return new MessageJabberImpl(new String(content), contentType
|
||||
, contentEncoding, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending a simple text messages with
|
||||
* default (text/plain) content type and encoding.
|
||||
*
|
||||
* @param messageText the string content of the message.
|
||||
* @return Message the newly created message
|
||||
*/
|
||||
public Message createMessage(String messageText)
|
||||
{
|
||||
return new MessageJabberImpl(messageText, DEFAULT_MIME_TYPE
|
||||
, DEFAULT_MIME_ENCODING, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the <tt>message</tt> to the destination indicated by the
|
||||
* <tt>to</tt> contact.
|
||||
*
|
||||
* @param to the <tt>Contact</tt> to send <tt>message</tt> to
|
||||
* @param message the <tt>Message</tt> to send.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
* @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
|
||||
* instance of ContactImpl.
|
||||
*/
|
||||
public void sendInstantMessage(Contact to, Message message)
|
||||
throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
try
|
||||
{
|
||||
assertConnected();
|
||||
|
||||
Chat chat =
|
||||
jabberProvider.getConnection().
|
||||
createChat(to.getAddress());
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg = chat.createMessage();
|
||||
msg.setBody(message.getContent());
|
||||
|
||||
MessageEventManager.
|
||||
addNotificationsRequests(msg, true, false, false, true);
|
||||
|
||||
chat.sendMessage(msg);
|
||||
|
||||
MessageDeliveredEvent msgDeliveredEvt
|
||||
= new MessageDeliveredEvent(
|
||||
message, to, new Date());
|
||||
|
||||
fireMessageEvent(msgDeliveredEvt);
|
||||
}
|
||||
catch (XMPPException ex)
|
||||
{
|
||||
logger.error("message not send", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method throwing an exception if the stack is not properly
|
||||
* initialized.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
*/
|
||||
private void assertConnected() throws IllegalStateException
|
||||
{
|
||||
if (jabberProvider == null)
|
||||
throw new IllegalStateException(
|
||||
"The provider must be non-null and signed on the "
|
||||
+"service before being able to communicate.");
|
||||
if (!jabberProvider.isRegistered())
|
||||
throw new IllegalStateException(
|
||||
"The provider must be signed on the service before "
|
||||
+"being able to communicate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Our listener that will tell us when we're registered to
|
||||
*/
|
||||
private class RegistrationStateListener
|
||||
implements RegistrationStateChangeListener
|
||||
{
|
||||
/**
|
||||
* The method is called by a ProtocolProvider implementation whenver
|
||||
* a change in the registration state of the corresponding provider had
|
||||
* occurred.
|
||||
* @param evt ProviderStatusChangeEvent the event describing the status
|
||||
* change.
|
||||
*/
|
||||
public void registrationStateChanged(RegistrationStateChangeEvent evt)
|
||||
{
|
||||
logger.debug("The provider changed state from: "
|
||||
+ evt.getOldState()
|
||||
+ " to: " + evt.getNewState());
|
||||
|
||||
if (evt.getNewState() == RegistrationState.REGISTERED)
|
||||
{
|
||||
opSetPersPresence = (OperationSetPersistentPresenceJabberImpl)
|
||||
jabberProvider.getSupportedOperationSets()
|
||||
.get(OperationSetPersistentPresence.class.getName());
|
||||
|
||||
jabberProvider.getConnection().addPacketListener(
|
||||
new SmackMessageListener(),
|
||||
new PacketTypeFilter(
|
||||
org.jivesoftware.smack.packet.Message.class));
|
||||
|
||||
// run keepalive thread
|
||||
if(keepAliveSendTask == null)
|
||||
{
|
||||
keepAliveSendTask = new KeepAliveSendTask();
|
||||
|
||||
keepAliveTimer.scheduleAtFixedRate(
|
||||
keepAliveSendTask, KEEPALIVE_INTERVAL, KEEPALIVE_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers the specified event to all registered message listeners.
|
||||
* @param evt the <tt>EventObject</tt> that we'd like delivered to all
|
||||
* registered message listerners.
|
||||
*/
|
||||
private void fireMessageEvent(EventObject evt)
|
||||
{
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
if (evt instanceof MessageDeliveredEvent)
|
||||
{
|
||||
listener.messageDelivered( (MessageDeliveredEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageReceivedEvent)
|
||||
{
|
||||
listener.messageReceived( (MessageReceivedEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageDeliveryFailedEvent)
|
||||
{
|
||||
listener.messageDeliveryFailed(
|
||||
(MessageDeliveryFailedEvent) evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
private class SmackMessageListener
|
||||
implements PacketListener
|
||||
{
|
||||
public void processPacket(Packet packet)
|
||||
{
|
||||
if(!(packet instanceof org.jivesoftware.smack.packet.Message))
|
||||
return;
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg =
|
||||
(org.jivesoftware.smack.packet.Message)packet;
|
||||
|
||||
if(msg.getBody() == null)
|
||||
return;
|
||||
|
||||
String fromUserID = StringUtils.parseBareAddress(msg.getFrom());
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Received from "
|
||||
+ fromUserID
|
||||
+ " the message "
|
||||
+ msg.getBody());
|
||||
}
|
||||
|
||||
KeepAliveEvent keepAliveEvent =
|
||||
(KeepAliveEvent)packet.getExtension(
|
||||
KeepAliveEventProvider.ELEMENT_NAME,
|
||||
KeepAliveEventProvider.NAMESPACE);
|
||||
if(keepAliveEvent != null)
|
||||
{
|
||||
logger.info("received keepalive");
|
||||
keepAliveEvent.setFromUserID(fromUserID);
|
||||
receivedKeepAlivePackets.addLast(keepAliveEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
Message newMessage = createMessage(msg.getBody());
|
||||
|
||||
Contact sourceContact =
|
||||
opSetPersPresence.findContactByID(fromUserID);
|
||||
|
||||
if(msg.getType() == org.jivesoftware.smack.packet.Message.Type.ERROR)
|
||||
{
|
||||
logger.info("Message error received from " + fromUserID);
|
||||
|
||||
int errorCode = packet.getError().getCode();
|
||||
int errorResultCode = MessageDeliveryFailedEvent.UNKNOWN_ERROR;
|
||||
|
||||
if(errorCode == 503)
|
||||
{
|
||||
org.jivesoftware.smackx.packet.MessageEvent msgEvent =
|
||||
(org.jivesoftware.smackx.packet.MessageEvent)
|
||||
packet.getExtension("x", "jabber:x:event");
|
||||
if(msgEvent != null && msgEvent.isOffline())
|
||||
{
|
||||
errorResultCode =
|
||||
MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
MessageDeliveryFailedEvent ev =
|
||||
new MessageDeliveryFailedEvent(newMessage,
|
||||
sourceContact,
|
||||
errorResultCode,
|
||||
new Date());
|
||||
fireMessageEvent(ev);
|
||||
return;
|
||||
}
|
||||
|
||||
if(sourceContact == null)
|
||||
{
|
||||
logger.debug("received a message from an unknown contact: "
|
||||
+ fromUserID);
|
||||
//create the volatile contact
|
||||
sourceContact = opSetPersPresence
|
||||
.createVolatileContact(fromUserID);
|
||||
}
|
||||
|
||||
MessageReceivedEvent msgReceivedEvt
|
||||
= new MessageReceivedEvent(
|
||||
newMessage, sourceContact , new Date() );
|
||||
|
||||
fireMessageEvent(msgReceivedEvt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task sending packets on intervals.
|
||||
* The task is runned on specified intervals by the keepAliveTimer
|
||||
*/
|
||||
private class KeepAliveSendTask
|
||||
extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
// if we are not registerd do nothing
|
||||
if(!jabberProvider.isRegistered())
|
||||
return;
|
||||
|
||||
Chat chat =
|
||||
jabberProvider.getConnection().
|
||||
createChat(jabberProvider.getAccountID().getUserID());
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg = chat.createMessage();
|
||||
msg.setBody("SYSTEM MESSAGE!");
|
||||
|
||||
KeepAliveEvent keepAliveEvent = new KeepAliveEvent();
|
||||
|
||||
keepAliveEvent.setSrcOpSetHash(
|
||||
OperationSetBasicInstantMessagingJabberImpl.this.hashCode());
|
||||
keepAliveEvent.setSrcProviderHash(jabberProvider.hashCode());
|
||||
|
||||
// add keepalive data
|
||||
msg.addExtension(keepAliveEvent);
|
||||
|
||||
// schedule the check task
|
||||
keepAliveTimer.schedule(
|
||||
new KeepAliveCheckTask(), KEEPALIVE_WAIT);
|
||||
|
||||
logger.trace("send keepalive");
|
||||
chat.sendMessage(msg);
|
||||
}
|
||||
catch (XMPPException ex)
|
||||
{
|
||||
logger.error("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the first received packet in the queue
|
||||
* is ok and if its not or the queue has no received packets
|
||||
* the this means there is some network problem, so fire event
|
||||
*/
|
||||
private class KeepAliveCheckTask
|
||||
extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
// check till we find a correct message
|
||||
// or if NoSuchElementException is thrown
|
||||
// there is no message
|
||||
while(!checkFirstPacket());
|
||||
}
|
||||
catch (NoSuchElementException ex)
|
||||
{
|
||||
fireUnregisterd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether first packet in queue is ok
|
||||
* @return boolean
|
||||
* @throws NoSuchElementException
|
||||
*/
|
||||
boolean checkFirstPacket()
|
||||
throws NoSuchElementException
|
||||
{
|
||||
KeepAliveEvent receivedEvent =
|
||||
(KeepAliveEvent)receivedKeepAlivePackets.removeLast();
|
||||
|
||||
if(jabberProvider.hashCode() != receivedEvent.getSrcProviderHash() ||
|
||||
OperationSetBasicInstantMessagingJabberImpl.this.hashCode() !=
|
||||
receivedEvent.getSrcOpSetHash() ||
|
||||
!jabberProvider.getAccountID().getUserID().
|
||||
equals(receivedEvent.getFromUserID()) )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire Unregistered event
|
||||
*/
|
||||
void fireUnregisterd()
|
||||
{
|
||||
jabberProvider.fireRegistrationStateChanged(
|
||||
jabberProvider.getRegistrationState(),
|
||||
RegistrationState.CONNECTION_FAILED,
|
||||
RegistrationStateChangeEvent.REASON_INTERNAL_ERROR, null);
|
||||
|
||||
opSetPersPresence.fireProviderPresenceStatusChangeEvent(
|
||||
opSetPersPresence.getPresenceStatus(),
|
||||
JabberStatusEnum.OFFLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,486 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.jabber;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jivesoftware.smack.*;
|
||||
import org.jivesoftware.smack.filter.*;
|
||||
import org.jivesoftware.smack.packet.*;
|
||||
import org.jivesoftware.smack.provider.*;
|
||||
import org.jivesoftware.smack.util.*;
|
||||
import org.jivesoftware.smackx.*;
|
||||
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.Message;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.service.protocol.jabberconstants.*;
|
||||
|
||||
/**
|
||||
* A straightforward implementation of the basic instant messaging operation
|
||||
* set.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class OperationSetBasicInstantMessagingJabberImpl
|
||||
implements OperationSetBasicInstantMessaging
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OperationSetBasicInstantMessagingJabberImpl.class);
|
||||
|
||||
/**
|
||||
* KeepAlive interval for sending packets
|
||||
*/
|
||||
private static long KEEPALIVE_INTERVAL = 180000l; // 3 minutes
|
||||
|
||||
/**
|
||||
* The interval after which a packet is considered to be lost
|
||||
*/
|
||||
private static long KEEPALIVE_WAIT = 20000l;
|
||||
|
||||
/**
|
||||
* The task sending packets
|
||||
*/
|
||||
private KeepAliveSendTask keepAliveSendTask = null;
|
||||
/**
|
||||
* The timer executing tasks on specified intervals
|
||||
*/
|
||||
private Timer keepAliveTimer = new Timer();
|
||||
/**
|
||||
* The queue holding the received packets
|
||||
*/
|
||||
private LinkedList receivedKeepAlivePackets = new LinkedList();
|
||||
|
||||
/**
|
||||
* A list of listeneres registered for message events.
|
||||
*/
|
||||
private Vector messageListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceJabberImpl jabberProvider = null;
|
||||
|
||||
/**
|
||||
* A reference to the persistent presence operation set that we use
|
||||
* to match incoming messages to <tt>Contact</tt>s and vice versa.
|
||||
*/
|
||||
private OperationSetPersistentPresenceJabberImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this operation set.
|
||||
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
|
||||
* that created us and that we'll use for retrieving the underlying aim
|
||||
* connection.
|
||||
*/
|
||||
OperationSetBasicInstantMessagingJabberImpl(
|
||||
ProtocolProviderServiceJabberImpl provider)
|
||||
{
|
||||
this.jabberProvider = provider;
|
||||
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
|
||||
|
||||
// register the KeepAlive Extension in the smack library
|
||||
ProviderManager.addExtensionProvider(KeepAliveEventProvider.ELEMENT_NAME,
|
||||
KeepAliveEventProvider.NAMESPACE,
|
||||
new KeepAliveEventProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registeres a MessageListener with this operation set so that it gets
|
||||
* notifications of successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to register.
|
||||
*/
|
||||
public void addMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
if(!messageListeners.contains(listener))
|
||||
{
|
||||
this.messageListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisteres <tt>listener</tt> so that it won't receive any further
|
||||
* notifications upon successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to unregister.
|
||||
*/
|
||||
public void removeMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
this.messageListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending arbitrary MIME-encoding content.
|
||||
*
|
||||
* @param content content value
|
||||
* @param contentType the MIME-type for <tt>content</tt>
|
||||
* @param contentEncoding encoding used for <tt>content</tt>
|
||||
* @param subject a <tt>String</tt> subject or <tt>null</tt> for now subject.
|
||||
* @return the newly created message.
|
||||
*/
|
||||
public Message createMessage(byte[] content, String contentType,
|
||||
String contentEncoding, String subject)
|
||||
{
|
||||
return new MessageJabberImpl(new String(content), contentType
|
||||
, contentEncoding, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending a simple text messages with
|
||||
* default (text/plain) content type and encoding.
|
||||
*
|
||||
* @param messageText the string content of the message.
|
||||
* @return Message the newly created message
|
||||
*/
|
||||
public Message createMessage(String messageText)
|
||||
{
|
||||
return new MessageJabberImpl(messageText, DEFAULT_MIME_TYPE
|
||||
, DEFAULT_MIME_ENCODING, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the <tt>message</tt> to the destination indicated by the
|
||||
* <tt>to</tt> contact.
|
||||
*
|
||||
* @param to the <tt>Contact</tt> to send <tt>message</tt> to
|
||||
* @param message the <tt>Message</tt> to send.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
* @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
|
||||
* instance of ContactImpl.
|
||||
*/
|
||||
public void sendInstantMessage(Contact to, Message message)
|
||||
throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
try
|
||||
{
|
||||
assertConnected();
|
||||
|
||||
Chat chat =
|
||||
jabberProvider.getConnection().
|
||||
createChat(to.getAddress());
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg = chat.createMessage();
|
||||
msg.setBody(message.getContent());
|
||||
|
||||
MessageEventManager.
|
||||
addNotificationsRequests(msg, true, false, false, true);
|
||||
|
||||
chat.sendMessage(msg);
|
||||
|
||||
MessageDeliveredEvent msgDeliveredEvt
|
||||
= new MessageDeliveredEvent(
|
||||
message, to, new Date());
|
||||
|
||||
fireMessageEvent(msgDeliveredEvt);
|
||||
}
|
||||
catch (XMPPException ex)
|
||||
{
|
||||
logger.error("message not send", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method throwing an exception if the stack is not properly
|
||||
* initialized.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
*/
|
||||
private void assertConnected() throws IllegalStateException
|
||||
{
|
||||
if (jabberProvider == null)
|
||||
throw new IllegalStateException(
|
||||
"The provider must be non-null and signed on the "
|
||||
+"service before being able to communicate.");
|
||||
if (!jabberProvider.isRegistered())
|
||||
throw new IllegalStateException(
|
||||
"The provider must be signed on the service before "
|
||||
+"being able to communicate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Our listener that will tell us when we're registered to
|
||||
*/
|
||||
private class RegistrationStateListener
|
||||
implements RegistrationStateChangeListener
|
||||
{
|
||||
/**
|
||||
* The method is called by a ProtocolProvider implementation whenver
|
||||
* a change in the registration state of the corresponding provider had
|
||||
* occurred.
|
||||
* @param evt ProviderStatusChangeEvent the event describing the status
|
||||
* change.
|
||||
*/
|
||||
public void registrationStateChanged(RegistrationStateChangeEvent evt)
|
||||
{
|
||||
logger.debug("The provider changed state from: "
|
||||
+ evt.getOldState()
|
||||
+ " to: " + evt.getNewState());
|
||||
|
||||
if (evt.getNewState() == RegistrationState.REGISTERED)
|
||||
{
|
||||
opSetPersPresence = (OperationSetPersistentPresenceJabberImpl)
|
||||
jabberProvider.getSupportedOperationSets()
|
||||
.get(OperationSetPersistentPresence.class.getName());
|
||||
|
||||
jabberProvider.getConnection().addPacketListener(
|
||||
new SmackMessageListener(),
|
||||
new PacketTypeFilter(
|
||||
org.jivesoftware.smack.packet.Message.class));
|
||||
|
||||
// run keepalive thread
|
||||
if(keepAliveSendTask == null)
|
||||
{
|
||||
keepAliveSendTask = new KeepAliveSendTask();
|
||||
|
||||
keepAliveTimer.scheduleAtFixedRate(
|
||||
keepAliveSendTask, KEEPALIVE_INTERVAL, KEEPALIVE_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers the specified event to all registered message listeners.
|
||||
* @param evt the <tt>EventObject</tt> that we'd like delivered to all
|
||||
* registered message listerners.
|
||||
*/
|
||||
private void fireMessageEvent(EventObject evt)
|
||||
{
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
if (evt instanceof MessageDeliveredEvent)
|
||||
{
|
||||
listener.messageDelivered( (MessageDeliveredEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageReceivedEvent)
|
||||
{
|
||||
listener.messageReceived( (MessageReceivedEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageDeliveryFailedEvent)
|
||||
{
|
||||
listener.messageDeliveryFailed(
|
||||
(MessageDeliveryFailedEvent) evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
private class SmackMessageListener
|
||||
implements PacketListener
|
||||
{
|
||||
public void processPacket(Packet packet)
|
||||
{
|
||||
if(!(packet instanceof org.jivesoftware.smack.packet.Message))
|
||||
return;
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg =
|
||||
(org.jivesoftware.smack.packet.Message)packet;
|
||||
|
||||
if(msg.getBody() == null)
|
||||
return;
|
||||
|
||||
String fromUserID = StringUtils.parseBareAddress(msg.getFrom());
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Received from "
|
||||
+ fromUserID
|
||||
+ " the message "
|
||||
+ msg.getBody());
|
||||
}
|
||||
|
||||
KeepAliveEvent keepAliveEvent =
|
||||
(KeepAliveEvent)packet.getExtension(
|
||||
KeepAliveEventProvider.ELEMENT_NAME,
|
||||
KeepAliveEventProvider.NAMESPACE);
|
||||
if(keepAliveEvent != null)
|
||||
{
|
||||
logger.info("received keepalive");
|
||||
keepAliveEvent.setFromUserID(fromUserID);
|
||||
receivedKeepAlivePackets.addLast(keepAliveEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
Message newMessage = createMessage(msg.getBody());
|
||||
|
||||
Contact sourceContact =
|
||||
opSetPersPresence.findContactByID(fromUserID);
|
||||
|
||||
if(msg.getType() == org.jivesoftware.smack.packet.Message.Type.ERROR)
|
||||
{
|
||||
logger.info("Message error received from " + fromUserID);
|
||||
|
||||
int errorCode = packet.getError().getCode();
|
||||
int errorResultCode = MessageDeliveryFailedEvent.UNKNOWN_ERROR;
|
||||
|
||||
if(errorCode == 503)
|
||||
{
|
||||
org.jivesoftware.smackx.packet.MessageEvent msgEvent =
|
||||
(org.jivesoftware.smackx.packet.MessageEvent)
|
||||
packet.getExtension("x", "jabber:x:event");
|
||||
if(msgEvent != null && msgEvent.isOffline())
|
||||
{
|
||||
errorResultCode =
|
||||
MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
MessageDeliveryFailedEvent ev =
|
||||
new MessageDeliveryFailedEvent(newMessage,
|
||||
sourceContact,
|
||||
errorResultCode,
|
||||
new Date());
|
||||
fireMessageEvent(ev);
|
||||
return;
|
||||
}
|
||||
|
||||
if(sourceContact == null)
|
||||
{
|
||||
logger.debug("received a message from an unknown contact: "
|
||||
+ fromUserID);
|
||||
//create the volatile contact
|
||||
sourceContact = opSetPersPresence
|
||||
.createVolatileContact(fromUserID);
|
||||
}
|
||||
|
||||
MessageReceivedEvent msgReceivedEvt
|
||||
= new MessageReceivedEvent(
|
||||
newMessage, sourceContact , new Date() );
|
||||
|
||||
fireMessageEvent(msgReceivedEvt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task sending packets on intervals.
|
||||
* The task is runned on specified intervals by the keepAliveTimer
|
||||
*/
|
||||
private class KeepAliveSendTask
|
||||
extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
// if we are not registerd do nothing
|
||||
if(!jabberProvider.isRegistered())
|
||||
{
|
||||
logger.trace("provider not registered. "
|
||||
+"won't send keep alive. acc.id="
|
||||
+ jabberProvider.getAccountID()
|
||||
.getAccountUniqueID());
|
||||
return;
|
||||
}
|
||||
|
||||
Chat chat =
|
||||
jabberProvider.getConnection().
|
||||
createChat(jabberProvider.getAccountID().getUserID());
|
||||
|
||||
org.jivesoftware.smack.packet.Message msg = chat.createMessage();
|
||||
msg.setBody("SYSTEM MESSAGE!");
|
||||
|
||||
KeepAliveEvent keepAliveEvent = new KeepAliveEvent();
|
||||
|
||||
keepAliveEvent.setSrcOpSetHash(
|
||||
OperationSetBasicInstantMessagingJabberImpl.this.hashCode());
|
||||
keepAliveEvent.setSrcProviderHash(jabberProvider.hashCode());
|
||||
|
||||
// add keepalive data
|
||||
msg.addExtension(keepAliveEvent);
|
||||
|
||||
// schedule the check task
|
||||
keepAliveTimer.schedule(
|
||||
new KeepAliveCheckTask(), KEEPALIVE_WAIT);
|
||||
|
||||
logger.trace("send keepalive");
|
||||
chat.sendMessage(msg);
|
||||
}
|
||||
catch (XMPPException ex)
|
||||
{
|
||||
logger.error("", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the first received packet in the queue
|
||||
* is ok and if its not or the queue has no received packets
|
||||
* the this means there is some network problem, so fire event
|
||||
*/
|
||||
private class KeepAliveCheckTask
|
||||
extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
// check till we find a correct message
|
||||
// or if NoSuchElementException is thrown
|
||||
// there is no message
|
||||
while(!checkFirstPacket());
|
||||
}
|
||||
catch (NoSuchElementException ex)
|
||||
{
|
||||
fireUnregisterd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether first packet in queue is ok
|
||||
* @return boolean
|
||||
* @throws NoSuchElementException
|
||||
*/
|
||||
boolean checkFirstPacket()
|
||||
throws NoSuchElementException
|
||||
{
|
||||
KeepAliveEvent receivedEvent =
|
||||
(KeepAliveEvent)receivedKeepAlivePackets.removeLast();
|
||||
|
||||
if(jabberProvider.hashCode() != receivedEvent.getSrcProviderHash() ||
|
||||
OperationSetBasicInstantMessagingJabberImpl.this.hashCode() !=
|
||||
receivedEvent.getSrcOpSetHash() ||
|
||||
!jabberProvider.getAccountID().getUserID().
|
||||
equals(receivedEvent.getFromUserID()) )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire Unregistered event
|
||||
*/
|
||||
void fireUnregisterd()
|
||||
{
|
||||
jabberProvider.fireRegistrationStateChanged(
|
||||
jabberProvider.getRegistrationState(),
|
||||
RegistrationState.CONNECTION_FAILED,
|
||||
RegistrationStateChangeEvent.REASON_INTERNAL_ERROR, null);
|
||||
|
||||
opSetPersPresence.fireProviderPresenceStatusChangeEvent(
|
||||
opSetPersPresence.getPresenceStatus(),
|
||||
JabberStatusEnum.OFFLINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The Msn implementation of the service.protocol.ContactGroup interface. There
|
||||
* are two types of groups possible here. <tt>RootContactGroupMsnImpl</tt>
|
||||
* which is the root node of the ContactList itself and
|
||||
* <tt>ContactGroupMsnImpl</tt> which represents standard groups. The
|
||||
* reason for having those 2 is that generally, Msn groups may not contain
|
||||
* subgroups. A contact list on the other hand may not directly contain buddies.
|
||||
*
|
||||
*
|
||||
* The reason for having an abstract class is only - being able to esily
|
||||
* recognize our own (Msn) contacts.
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public abstract class AbstractContactGroupMsnImpl
|
||||
implements ContactGroup
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.sf.jml.MsnGroup;
|
||||
import net.sf.jml.MsnContact;
|
||||
|
||||
/**
|
||||
* The Msn implementation of the ContactGroup interface. Intances of this class
|
||||
* (contrary to <tt>RootContactGroupMsnImpl</tt>) may only contain buddies
|
||||
* and cannot have sub groups. Note that instances of this class only use the
|
||||
* corresponding smack source group for reading their names and only
|
||||
* initially fill their <tt>buddies</tt> <tt>java.util.List</tt> with
|
||||
* the ContactMsnImpl objects corresponding to those contained in the source
|
||||
* group at the moment it is being created. They would, however, never try to
|
||||
* sync or update their contents ulteriorly. This would have to be done through
|
||||
* the addContact()/removeContact() methods.
|
||||
* The content of buddies is created on creating of the group and when the smack
|
||||
* source group is changed.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class ContactGroupMsnImpl
|
||||
extends AbstractContactGroupMsnImpl
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ContactGroupMsnImpl.class);
|
||||
|
||||
private List buddies = new LinkedList();
|
||||
private boolean isResolved = false;
|
||||
|
||||
/**
|
||||
* The Msn Group corresponding to this contact group.
|
||||
*/
|
||||
private MsnGroup msnGroup = null;
|
||||
|
||||
/**
|
||||
* a list that would always remain empty. We only use it so that we're able
|
||||
* to extract empty iterators
|
||||
*/
|
||||
private List dummyGroupsList = new LinkedList();
|
||||
|
||||
private ServerStoredContactListMsnImpl ssclCallback = null;
|
||||
|
||||
/**
|
||||
* Creates an Msn group using the specified <tt>RosterGroup</tt> as
|
||||
* a source. The newly created group will always return the name of the
|
||||
* underlying RosterGroup and would thus automatically adapt to changes.
|
||||
* It would, however, not receive or try to poll for modifications of the
|
||||
* buddies it contains and would therefore have to be updated manually by
|
||||
* ServerStoredContactListImpl update will only be done if source group
|
||||
* is changed.
|
||||
|
||||
* @param rosterGroup the Msn Group correspoinding to the group
|
||||
* @param groupMembers the group members that we should add to the group.
|
||||
* @param ssclCallback a callback to the server stored contact list
|
||||
* we're creating.
|
||||
* @param isResolved a boolean indicating whether or not the group has been
|
||||
* resolved against the server.
|
||||
*/
|
||||
ContactGroupMsnImpl(
|
||||
MsnGroup msnGroup,
|
||||
MsnContact[] groupMembers,
|
||||
ServerStoredContactListMsnImpl ssclCallback,
|
||||
boolean isResolved)
|
||||
{
|
||||
this.msnGroup = msnGroup;
|
||||
this.isResolved = isResolved;
|
||||
this.ssclCallback = ssclCallback;
|
||||
|
||||
for (int i = 0; i < groupMembers.length; i++)
|
||||
{
|
||||
addContact(
|
||||
new ContactMsnImpl(groupMembers[i], ssclCallback, true, true) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of <tt>Contact</tt> members of this
|
||||
* <tt>ContactGroup</tt>
|
||||
*
|
||||
* @return an int indicating the number of <tt>Contact</tt>s,
|
||||
* members of this <tt>ContactGroup</tt>.
|
||||
*/
|
||||
public int countContacts()
|
||||
{
|
||||
return buddies.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the root group which in Msn is the parent of
|
||||
* any other group since the protocol does not support subgroups.
|
||||
* @return a reference to the root group.
|
||||
*/
|
||||
public ContactGroup getParentContactGroup()
|
||||
{
|
||||
return ssclCallback.getRootGroup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact at the specified position.
|
||||
* @param contact the new contact to add to this group
|
||||
* @param index the position where the new contact should be added.
|
||||
*/
|
||||
void addContact(int index, ContactMsnImpl contact)
|
||||
{
|
||||
buddies.add(index, contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact to the end of this group.
|
||||
* @param contact the new contact to add to this group
|
||||
*/
|
||||
void addContact(ContactMsnImpl contact)
|
||||
{
|
||||
addContact(countContacts(), contact);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified contact from this contact group
|
||||
* @param contact the contact to remove.
|
||||
*/
|
||||
void removeContact(ContactMsnImpl contact)
|
||||
{
|
||||
removeContact(buddies.indexOf(contact));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the contact with the specified index.
|
||||
* @param index the index of the cntact to remove
|
||||
*/
|
||||
void removeContact(int index)
|
||||
{
|
||||
buddies.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all buddies in this group and reinsterts them as specified
|
||||
* by the <tt>newOrder</tt> param. Contacts not contained in the
|
||||
* newOrder list are left at the end of this group.
|
||||
*
|
||||
* @param newOrder a list containing all contacts in the order that is
|
||||
* to be applied.
|
||||
*
|
||||
*/
|
||||
void reorderContacts(List newOrder)
|
||||
{
|
||||
buddies.removeAll(newOrder);
|
||||
buddies.addAll(0, newOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator over all contacts, member of this
|
||||
* <tt>ContactGroup</tt>.
|
||||
*
|
||||
* @return a java.util.Iterator over all contacts inside this
|
||||
* <tt>ContactGroup</tt>. In case the group doesn't contain any
|
||||
* memebers it will return an empty iterator.
|
||||
*/
|
||||
public Iterator contacts()
|
||||
{
|
||||
return buddies.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>Contact</tt> with the specified index.
|
||||
*
|
||||
* @param index the index of the <tt>Contact</tt> to return.
|
||||
* @return the <tt>Contact</tt> with the specified index.
|
||||
*/
|
||||
public Contact getContact(int index)
|
||||
{
|
||||
return (ContactMsnImpl) buddies.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>Contact</tt> with the specified address or
|
||||
* identifier.
|
||||
* @param id the addres or identifier of the <tt>Contact</tt> we are
|
||||
* looking for.
|
||||
* @return the <tt>Contact</tt> with the specified id or address.
|
||||
*/
|
||||
public Contact getContact(String id)
|
||||
{
|
||||
return this.findContact(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this group.
|
||||
* @return a String containing the name of this group.
|
||||
*/
|
||||
public String getGroupName()
|
||||
{
|
||||
return msnGroup.getGroupName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the group may contain subgroups or not.
|
||||
*
|
||||
* @return always false since only the root group may contain subgroups.
|
||||
*/
|
||||
public boolean canContainSubgroups()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified index (i.e. always null since
|
||||
* this group may not contain subgroups).
|
||||
*
|
||||
* @param index the index of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return always null
|
||||
*/
|
||||
public ContactGroup getGroup(int index)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified name.
|
||||
* @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return the <tt>ContactGroup</tt> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(String groupName)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an empty iterator. Subgroups may only be present in the root
|
||||
* group.
|
||||
*
|
||||
* @return an empty iterator
|
||||
*/
|
||||
public Iterator subgroups()
|
||||
{
|
||||
return dummyGroupsList.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of subgroups contained by this group, which is
|
||||
* always 0 since sub groups in the protocol may only be contained
|
||||
* by the root group - <tt>RootContactGroupImpl</tt>.
|
||||
* @return a 0 int.
|
||||
*/
|
||||
public int countSubgroups()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object, which is actually the hashcode
|
||||
* value of the groupname.
|
||||
*
|
||||
* @return a hash code value for this ContactGroup.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return getGroupName().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this group.
|
||||
*
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <tt>true</tt> if this object is the same as the obj
|
||||
* argument; <tt>false</tt> otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if( obj == this )
|
||||
return true;
|
||||
|
||||
if (obj == null
|
||||
|| !(obj instanceof ContactGroupMsnImpl) )
|
||||
return false;
|
||||
|
||||
if(!((ContactGroup)obj).getGroupName().equals(getGroupName()))
|
||||
return false;
|
||||
|
||||
//since Msn does not support having two groups with the same name
|
||||
// at this point we could bravely state that the groups are the same
|
||||
// and not bother to compare buddies. (gotta check that though)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol provider that this group belongs to.
|
||||
* @return a regerence to the ProtocolProviderService instance that this
|
||||
* ContactGroup belongs to.
|
||||
*/
|
||||
public ProtocolProviderService getProtocolProvider()
|
||||
{
|
||||
return this.ssclCallback.getParentProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this group, in the form
|
||||
* MsnGroup.GroupName[size]{ buddy1.toString(), buddy2.toString(), ...}.
|
||||
* @return a String representation of the object.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer("MSnGroup.");
|
||||
buff.append(getGroupName());
|
||||
buff.append(", childContacts="+countContacts()+":[");
|
||||
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactMsnImpl contact = (ContactMsnImpl) contacts.next();
|
||||
buff.append(contact.toString());
|
||||
if(contacts.hasNext())
|
||||
buff.append(", ");
|
||||
}
|
||||
return buff.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact encapsulating with the spcieified name or
|
||||
* null if no such contact was found.
|
||||
*
|
||||
* @param id the id for the contact we're looking for.
|
||||
* @return the <tt>ContactMsnImpl</tt> corresponding to the specified
|
||||
* screnname or null if no such contact existed.
|
||||
*/
|
||||
ContactMsnImpl findContact(String id)
|
||||
{
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactMsnImpl item = (ContactMsnImpl) contacts.next();
|
||||
if(item.getAddress().equals(id))
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact group is being stored by the
|
||||
* server. Non persistent contact groups exist for the sole purpose of
|
||||
* containing non persistent contacts.
|
||||
* @return true if the contact group is persistent and false otherwise.
|
||||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return !(msnGroup instanceof VolatileGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as no persistent data is required and the contact address is
|
||||
* sufficient for restoring the contact.
|
||||
* <p>
|
||||
* @return null as no such data is needed.
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact group has been resolved against
|
||||
* the server. Unresolved group are used when initially loading a contact
|
||||
* list that has been stored in a local file until the presence operation
|
||||
* set has managed to retrieve all the contact list from the server and has
|
||||
* properly mapped contacts and groups to their corresponding on-line
|
||||
* buddies.
|
||||
* @return true if the contact has been resolved (mapped against a buddy)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isResolved()
|
||||
{
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve this contact group against the specified group
|
||||
* @param source the server stored group
|
||||
*/
|
||||
void setResolved(MsnGroup msnGroup)
|
||||
{
|
||||
if(isResolved)
|
||||
return;
|
||||
|
||||
this.isResolved = true;
|
||||
|
||||
this.msnGroup = msnGroup;
|
||||
|
||||
MsnContact[] contacts = msnGroup.getContacts();
|
||||
for (int i = 0; i < contacts.length; i++)
|
||||
{
|
||||
MsnContact item = contacts[i];
|
||||
|
||||
ContactMsnImpl contact =
|
||||
ssclCallback.findContactById(item.getEmail().getEmailAddress());
|
||||
if(contact != null)
|
||||
{
|
||||
contact.setResolved(item);
|
||||
|
||||
ssclCallback.fireContactResolved(this, contact);
|
||||
}
|
||||
else
|
||||
{
|
||||
ContactMsnImpl newContact =
|
||||
new ContactMsnImpl(item, ssclCallback, true, true);
|
||||
addContact(newContact);
|
||||
|
||||
ssclCallback.fireContactAdded(this, newContact);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>String</tt> that uniquely represnets the group. In this we
|
||||
* use the name of the group as an identifier. This may cause problems
|
||||
* though, in clase the name is changed by some other application between
|
||||
* consecutive runs of the sip-communicator.
|
||||
*
|
||||
* @return a String representing this group in a unique and persistent
|
||||
* way.
|
||||
*/
|
||||
public String getUID()
|
||||
{
|
||||
return getGroupName();
|
||||
}
|
||||
|
||||
/**
|
||||
* The source group we are encapsulating
|
||||
* @return MsnGroup
|
||||
*/
|
||||
MsnGroup getSourceGroup()
|
||||
{
|
||||
return msnGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the source group
|
||||
* change the buddies
|
||||
*
|
||||
* @param newGroup MsnGroup
|
||||
*/
|
||||
void setSourceGroup(MsnGroup newGroup)
|
||||
{
|
||||
this.msnGroup = newGroup;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.msnconstants.*;
|
||||
import net.sf.jml.MsnContact;
|
||||
|
||||
/**
|
||||
* The Msn implementation of the service.protocol.Contact interface.
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class ContactMsnImpl
|
||||
implements Contact
|
||||
{
|
||||
private MsnContact contact = null;
|
||||
private boolean isLocal = false;
|
||||
private byte[] image = null;
|
||||
private PresenceStatus status = MsnStatusEnum.OFFLINE;
|
||||
private ServerStoredContactListMsnImpl ssclCallback = null;
|
||||
private boolean isPersistent = false;
|
||||
private boolean isResolved = false;
|
||||
|
||||
/**
|
||||
* Creates an MsnContactImpl
|
||||
* @param rosterEntry the RosterEntry object that we will be encapsulating.
|
||||
* @param ssclCallback a reference to the ServerStoredContactListImpl
|
||||
* instance that created us.
|
||||
* @param isPersistent determines whether this contact is persistent or not.
|
||||
* @param isResolved specifies whether the contact has been resolved against
|
||||
* the server contact list
|
||||
*/
|
||||
ContactMsnImpl(MsnContact contact,
|
||||
ServerStoredContactListMsnImpl ssclCallback,
|
||||
boolean isPersistent,
|
||||
boolean isResolved)
|
||||
{
|
||||
this.contact = contact;
|
||||
this.isLocal = isLocal;
|
||||
this.ssclCallback = ssclCallback;
|
||||
this.isPersistent = isPersistent;
|
||||
this.isResolved = isResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Msn Userid of this contact
|
||||
* @return the Msn Userid of this contact
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
if(isResolved)
|
||||
return contact.getEmail().getEmailAddress();
|
||||
else
|
||||
return contact.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this Contact instance represents the user used
|
||||
* by this protocol provider to connect to the service.
|
||||
*
|
||||
* @return true if this Contact represents us (the local user) and false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isLocal()
|
||||
{
|
||||
return isLocal;
|
||||
}
|
||||
|
||||
public byte[] getImage()
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashCode for this contact. The returned hashcode is actually
|
||||
* that of the Contact's Address
|
||||
* @return the hashcode of this Contact
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return getAddress().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one.
|
||||
* <p>
|
||||
*
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <tt>true</tt> if this object is the same as the obj
|
||||
* argument; <tt>false</tt> otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null
|
||||
|| !(obj instanceof ContactMsnImpl)
|
||||
|| !(((ContactMsnImpl)obj).getAddress().equals(getAddress())
|
||||
&& ((ContactMsnImpl)obj).getProtocolProvider()
|
||||
== getProtocolProvider()))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this contact, containing most of its
|
||||
* representative details.
|
||||
*
|
||||
* @return a string representation of this contact.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer("MsnContact[ id=");
|
||||
buff.append(getAddress()).append("]");
|
||||
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status that this contact is currently in. The method is to
|
||||
* only be called as a result of a status update received from the server.
|
||||
*
|
||||
* @param status the MsnStatusEnum that this contact is currently in.
|
||||
*/
|
||||
void updatePresenceStatus(PresenceStatus status)
|
||||
{
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the contact as per the last status update we've
|
||||
* received for it. Note that this method is not to perform any network
|
||||
* operations and will simply return the status received in the last
|
||||
* status update message. If you want a reliable way of retrieving someone's
|
||||
* status, you should use the <tt>queryContactStatus()</tt> method in
|
||||
* <tt>OperationSetPresence</tt>.
|
||||
* @return the PresenceStatus that we've received in the last status update
|
||||
* pertaining to this contact.
|
||||
*/
|
||||
public PresenceStatus getPresenceStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String that could be used by any user interacting modules for
|
||||
* referring to this contact. An alias is not necessarily unique but is
|
||||
* often more human readable than an address (or id).
|
||||
* @return a String that can be used for referring to this contact when
|
||||
* interacting with the user.
|
||||
*/
|
||||
public String getDisplayName()
|
||||
{
|
||||
String name = contact.getDisplayName();
|
||||
|
||||
if (name == null)
|
||||
name = getAddress();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the contact group that this contact is currently
|
||||
* a child of or null if the underlying protocol does not suppord persistent
|
||||
* presence.
|
||||
* @return a reference to the contact group that this contact is currently
|
||||
* a child of or null if the underlying protocol does not suppord persistent
|
||||
* presence.
|
||||
*/
|
||||
public ContactGroup getParentContactGroup()
|
||||
{
|
||||
return ssclCallback.findContactGroup(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a reference to the protocol provider that created the contact.
|
||||
* @return a refererence to an instance of the ProtocolProviderService
|
||||
*/
|
||||
public ProtocolProviderService getProtocolProvider()
|
||||
{
|
||||
return ssclCallback.getParentProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact is being stored by the server.
|
||||
* Non persistent contacts are common in the case of simple, non-persistent
|
||||
* presence operation sets. They could however also be seen in persistent
|
||||
* presence operation sets when for example we have received an event
|
||||
* from someone not on our contact list. Non persistent contacts are
|
||||
* volatile even when coming from a persistent presence op. set. They would
|
||||
* only exist until the application is closed and will not be there next
|
||||
* time it is loaded.
|
||||
* @return true if the contact is persistent and false otherwise.
|
||||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return isPersistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether this contact is to be considered persistent or not. The
|
||||
* method is to be used _only_ when a non-persistent contact has been added
|
||||
* to the contact list and its encapsulated VolatileBuddy has been repalced
|
||||
* with a standard buddy.
|
||||
* @param persistent true if the buddy is to be considered persistent and
|
||||
* false for volatile.
|
||||
*/
|
||||
void setPersistent(boolean persistent)
|
||||
{
|
||||
this.isPersistent = persistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve this contact against the given entry
|
||||
* @param entry the server stored entry
|
||||
*/
|
||||
void setResolved(MsnContact entry)
|
||||
{
|
||||
if(isResolved)
|
||||
return;
|
||||
|
||||
this.isResolved = true;
|
||||
contact = entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the persistent data
|
||||
* @return the persistent data
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact has been resolved against the
|
||||
* server. Unresolved contacts are used when initially loading a contact
|
||||
* list that has been stored in a local file until the presence operation
|
||||
* set has managed to retrieve all the contact list from the server and has
|
||||
* properly mapped contacts to their on-line buddies.
|
||||
* @return true if the contact has been resolved (mapped against a buddy)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isResolved()
|
||||
{
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
public void setPersistentData(String persistentData)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get source contact
|
||||
* @return MsnContact
|
||||
*/
|
||||
MsnContact getSourceContact()
|
||||
{
|
||||
return contact;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.sf.jml.*;
|
||||
|
||||
/**
|
||||
* Contactlist modification listener receives events
|
||||
* for successful chngings
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class EventAdapter
|
||||
implements EventListener
|
||||
{
|
||||
/**
|
||||
* Message is successfully delivered
|
||||
* @param transactionID int the transaction that send the message
|
||||
*/
|
||||
public void messageDelivered(int transactionID){}
|
||||
/**
|
||||
* Message is not delivered
|
||||
* @param transactionID int the transaction that send the message
|
||||
*/
|
||||
public void messageDeliveredFailed(int transactionID){}
|
||||
/**
|
||||
* Indicates that a contact is successfully added
|
||||
* @param contact MsnContact the contact
|
||||
*/
|
||||
public void contactAdded(MsnContact contact){}
|
||||
/**
|
||||
* Indicates that a contact is successfully added to the group
|
||||
* @param contact MsnContact the contact
|
||||
* @param group MsnGroup the group
|
||||
*/
|
||||
public void contactAddedInGroup(MsnContact contact, MsnGroup group){}
|
||||
/**
|
||||
* Indicates successful removing of a contact
|
||||
* @param contact MsnContact the removed contact
|
||||
*/
|
||||
public void contactRemoved(MsnContact contact){}
|
||||
/**
|
||||
* Indicates successful removing of a contact from a group
|
||||
* @param contact MsnContact the contact removed
|
||||
* @param group MsnGroup the group
|
||||
*/
|
||||
public void contactRemovedFromGroup(MsnContact contact, MsnGroup group){}
|
||||
/**
|
||||
* Indicates that a group is successfully added
|
||||
* @param group MsnGroup the added group
|
||||
*/
|
||||
public void groupAdded(MsnGroup group){}
|
||||
/**
|
||||
* Indicates that a group is successfully renamed
|
||||
* @param group MsnGroup the renmaed group with the new name
|
||||
*/
|
||||
public void groupRenamed(MsnGroup group){}
|
||||
/**
|
||||
* Indicates successful removing of a group
|
||||
* @param id String the id of the removed group
|
||||
*/
|
||||
public void groupRemoved(String id){}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.sf.jml.*;
|
||||
|
||||
/**
|
||||
* Contactlist modification listener receives events
|
||||
* for successful chngings
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public interface EventListener
|
||||
{
|
||||
/**
|
||||
* Message is successfully delivered
|
||||
* @param transactionID int the transaction that send the message
|
||||
*/
|
||||
public void messageDelivered(int transactionID);
|
||||
/**
|
||||
* Message is not delivered
|
||||
* @param transactionID int the transaction that send the message
|
||||
*/
|
||||
public void messageDeliveredFailed(int transactionID);
|
||||
/**
|
||||
* Indicates that a contact is successfully added
|
||||
* @param contact MsnContact the contact
|
||||
*/
|
||||
public void contactAdded(MsnContact contact);
|
||||
/**
|
||||
* Indicates that a contact is successfully added to the group
|
||||
* @param contact MsnContact the contact
|
||||
* @param group MsnGroup the group
|
||||
*/
|
||||
public void contactAddedInGroup(MsnContact contact, MsnGroup group);
|
||||
/**
|
||||
* Indicates successful removing of a contact
|
||||
* @param contact MsnContact the removed contact
|
||||
*/
|
||||
public void contactRemoved(MsnContact contact);
|
||||
/**
|
||||
* Indicates successful removing of a contact from a group
|
||||
* @param contact MsnContact the contact removed
|
||||
* @param group MsnGroup the group
|
||||
*/
|
||||
public void contactRemovedFromGroup(MsnContact contact, MsnGroup group);
|
||||
/**
|
||||
* Indicates that a group is successfully added
|
||||
* @param group MsnGroup the added group
|
||||
*/
|
||||
public void groupAdded(MsnGroup group);
|
||||
/**
|
||||
* Indicates that a group is successfully renamed
|
||||
* @param group MsnGroup the renmaed group with the new name
|
||||
*/
|
||||
public void groupRenamed(MsnGroup group);
|
||||
/**
|
||||
* Indicates successful removing of a group
|
||||
* @param id String the id of the removed group
|
||||
*/
|
||||
public void groupRemoved(String id);
|
||||
}
|
||||
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.sf.cindy.*;
|
||||
import net.sf.jml.*;
|
||||
import net.sf.jml.impl.*;
|
||||
import net.sf.jml.protocol.*;
|
||||
import net.sf.jml.protocol.incoming.*;
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
|
||||
/**
|
||||
* Manager which listens for changing of the contact list
|
||||
* and fires some events
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class EventManager
|
||||
extends SessionAdapter
|
||||
{
|
||||
private static final Logger logger = Logger.getLogger(EventManager.class);
|
||||
|
||||
private BasicMessenger msnMessenger = null;
|
||||
private Vector listeners = new Vector();
|
||||
|
||||
/**
|
||||
* Creates the manager
|
||||
* @param msnMessenger BasicMessenger the messanger
|
||||
*/
|
||||
public EventManager(BasicMessenger msnMessenger)
|
||||
{
|
||||
this.msnMessenger = msnMessenger;
|
||||
|
||||
msnMessenger.addSessionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds listener of the modification fired events
|
||||
* @param listener EventListener
|
||||
*/
|
||||
public void addModificationListener(EventListener listener)
|
||||
{
|
||||
synchronized(listeners)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listener of the modification fired events
|
||||
* @param listener EventListener
|
||||
*/
|
||||
public void removeModificationListener(EventListener listener)
|
||||
{
|
||||
synchronized(listeners)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the underling lib when message is sent to the server
|
||||
* @param session Session
|
||||
* @param message Message
|
||||
* @throws Exception
|
||||
*/
|
||||
public void messageSent(Session session, Message message) throws Exception
|
||||
{
|
||||
logger.trace(msnMessenger.getOwner().getEmail().getEmailAddress() +
|
||||
" outgoing " + message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the underling lib when message is received from the server
|
||||
* @param session Session
|
||||
* @param message Message
|
||||
* @throws Exception
|
||||
*/
|
||||
public void messageReceived(Session session, Message message)
|
||||
throws Exception
|
||||
{
|
||||
MsnIncomingMessage incoming = (MsnIncomingMessage)((WrapperMessage)message)
|
||||
.getMessage();
|
||||
|
||||
logger.trace(msnMessenger.getOwner().getEmail().getEmailAddress() +
|
||||
" incoming : " + incoming);
|
||||
|
||||
// These are the incoming messages that are NOT handled
|
||||
//IncomingADC,IncomingANS,IncomingBLP,IncomingBPR,IncomingBYE
|
||||
//IncomingCAL,IncomingCHL,IncomingCHG,IncomingCVR,IncomingFLN
|
||||
//IncomingGTC,IncomingILN,IncomingIRO,IncomingJOI,IncomingLSG
|
||||
//IncomingLST,IncomingMSG,IncomingNLN
|
||||
//IncomingOUT - The notice message that logout. Maybe because of MSN
|
||||
// server maintenance or someone login in other place.
|
||||
//IncomingPRP,IncomingQNG,IncomingQRY,IncomingREA,IncomingRNG
|
||||
//IncomingSYN,IncomingUBX,IncomingURL,IncomingUSR,IncomingUUX
|
||||
//IncomingUnknown,IncomingVER,IncomingXFR
|
||||
|
||||
if(incoming instanceof IncomingACK)
|
||||
{
|
||||
//indicate the message has successed send to remote user.
|
||||
fireMessageDelivered(((IncomingACK)incoming).getTransactionId());
|
||||
}
|
||||
else if(incoming instanceof IncomingADC)
|
||||
{
|
||||
// add user to contact list
|
||||
IncomingADC incomingADC = (IncomingADC) incoming;
|
||||
if (incomingADC.getId() != null &&
|
||||
incomingADC.getList().equals(MsnList.FL))
|
||||
{
|
||||
MsnContact contact = msnMessenger.getContactList().
|
||||
getContactById(incomingADC.getId());
|
||||
|
||||
if (incomingADC.getGroupId() != null)
|
||||
{
|
||||
MsnGroup group = msnMessenger.getContactList().
|
||||
getGroup(incomingADC.getGroupId());
|
||||
|
||||
fireContactAddedInGroup(contact, group);
|
||||
}
|
||||
else
|
||||
fireContactAdded(contact);
|
||||
}
|
||||
|
||||
}
|
||||
else if(incoming instanceof IncomingADG)
|
||||
{
|
||||
//indicate add a group success
|
||||
IncomingADG incomingADG = (IncomingADG)incoming;
|
||||
|
||||
MsnGroupImpl group =
|
||||
(MsnGroupImpl)msnMessenger.getContactList().getGroup(incomingADG.getGroupId());
|
||||
|
||||
fireGroupAdded(group);
|
||||
}
|
||||
else if(incoming instanceof IncomingNAK)
|
||||
{
|
||||
//indicate the message has not successed send to remote user.
|
||||
fireMessageDeliveredFailed(((IncomingNAK)incoming).getTransactionId());
|
||||
}
|
||||
else if(incoming instanceof IncomingREG)
|
||||
{
|
||||
//indicate the group name has changed successfully.
|
||||
IncomingREG incomingREG = (IncomingREG)incoming;
|
||||
|
||||
MsnGroupImpl group = (MsnGroupImpl)msnMessenger.getContactList().
|
||||
getGroup(incomingREG.getGroupId());
|
||||
fireGroupRenamed(group);
|
||||
}
|
||||
else if(incoming instanceof IncomingRMG)
|
||||
{
|
||||
// indicate delete the group successfully.
|
||||
IncomingRMG incomingRMG = (IncomingRMG)incoming;
|
||||
fireGroupRemoved(incomingRMG.getGroupId());
|
||||
}
|
||||
else if(incoming instanceof IncomingREM)
|
||||
{
|
||||
// indicate delete the contact successfully.
|
||||
IncomingREM incomingREM = (IncomingREM)incoming;
|
||||
|
||||
if(incomingREM.getList().equals(MsnList.FL))
|
||||
{
|
||||
if(incomingREM.getGroupId() == null)
|
||||
{
|
||||
// just contact removed
|
||||
MsnContactImpl contact = (MsnContactImpl)
|
||||
msnMessenger.getContactList().getContactById(incomingREM.getId());
|
||||
|
||||
if(contact != null)
|
||||
{
|
||||
fireContactRemoved(contact);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// contact removed from group
|
||||
MsnContact contact =
|
||||
msnMessenger.getContactList().
|
||||
getContactById(incomingREM.getId());
|
||||
|
||||
MsnGroup group =
|
||||
msnMessenger.getContactList().
|
||||
getGroup(incomingREM.getGroupId());
|
||||
|
||||
fireContactRemovedFromGroup(contact, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a message is delivered successfully
|
||||
* @param transactionID int
|
||||
*/
|
||||
private void fireMessageDelivered(int transactionID)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).
|
||||
messageDelivered(transactionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a message is not delivered successfully
|
||||
* @param transactionID int
|
||||
*/
|
||||
private void fireMessageDeliveredFailed(int transactionID)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).
|
||||
messageDeliveredFailed(transactionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a contact is added successfully
|
||||
* @param contact MsnContact
|
||||
*/
|
||||
private void fireContactAdded(MsnContact contact)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).contactAdded(contact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a contact is added in a group successfully
|
||||
* @param contact MsnContact
|
||||
* @param group MsnGroup
|
||||
*/
|
||||
private void fireContactAddedInGroup(MsnContact contact, MsnGroup group)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).
|
||||
contactAddedInGroup(contact, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a contact is removed successfully
|
||||
* @param contact MsnContact
|
||||
*/
|
||||
private void fireContactRemoved(MsnContact contact)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).contactRemoved(contact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a contact is removed from group successfully
|
||||
* @param contact MsnContact
|
||||
* @param group MsnGroup
|
||||
*/
|
||||
private void fireContactRemovedFromGroup(MsnContact contact, MsnGroup group)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).
|
||||
contactRemovedFromGroup(contact, group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a group is added successfully
|
||||
* @param group MsnGroup
|
||||
*/
|
||||
private void fireGroupAdded(MsnGroup group)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).groupAdded(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a group is renamed successfully
|
||||
* @param group MsnGroup
|
||||
*/
|
||||
private void fireGroupRenamed(MsnGroup group)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).groupRenamed(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a group is removed successfully
|
||||
* @param id String
|
||||
*/
|
||||
private void fireGroupRemoved(String id)
|
||||
{
|
||||
synchronized(listeners){
|
||||
Iterator iter = listeners.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
((EventListener)iter.next()).groupRemoved(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* A simple implementation of the <tt>Message</tt> interface. Right now the
|
||||
* message only supports test contents and no binary data.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MessageMsnImpl
|
||||
implements Message
|
||||
{
|
||||
/**
|
||||
* The content of this message.
|
||||
*/
|
||||
private String textContent = null;
|
||||
|
||||
/**
|
||||
* The content type of text. Right now only text content types (such as
|
||||
* text/plain or text/html) are supported.
|
||||
*/
|
||||
private String contentType = null;
|
||||
|
||||
/**
|
||||
* The encoding under which the contennt of this message is encoded.
|
||||
*/
|
||||
private String contentEncoding = null;
|
||||
|
||||
/**
|
||||
* An String uniquely identifying this Message.
|
||||
*/
|
||||
private String messageUID = null;
|
||||
|
||||
/**
|
||||
* The subject of the message if any (may remain null).
|
||||
*/
|
||||
private String subject = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this Message with the specified parameters.
|
||||
*
|
||||
* @param content the text content of the message.
|
||||
* @param contentType a MIME string indicating the content type of the
|
||||
* <tt>content</tt> String.
|
||||
* @param contentEncoding a MIME String indicating the content encoding of
|
||||
* the <tt>content</tt> String.
|
||||
* @param subject the subject of the message or null for empty.
|
||||
*/
|
||||
public MessageMsnImpl(String content,
|
||||
String contentType,
|
||||
String contentEncoding,
|
||||
String subject)
|
||||
{
|
||||
this.textContent = content;
|
||||
this.contentType = contentType;
|
||||
this.contentEncoding = contentEncoding;
|
||||
this.subject = subject;
|
||||
|
||||
//generate the uid
|
||||
this.messageUID = String.valueOf( System.currentTimeMillis())
|
||||
+ String.valueOf(hashCode());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of this message if representable in text form or
|
||||
* null if this message does not contain text data.
|
||||
*
|
||||
* @return a String containing the content of this message or null if
|
||||
* the message does not contain data representable in text form.
|
||||
*/
|
||||
public String getContent()
|
||||
{
|
||||
return textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MIME type for the message content.
|
||||
*
|
||||
* @return a String containing the mime type of the message contant.
|
||||
*/
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MIME content encoding of this message.
|
||||
*
|
||||
* @return a String indicating the MIME encoding of this message.
|
||||
*/
|
||||
public String getEncoding()
|
||||
{
|
||||
return contentEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique identifier of this message.
|
||||
*
|
||||
* @return a String that uniquely represents this message in the scope
|
||||
* of this protocol.
|
||||
*/
|
||||
public String getMessageUID()
|
||||
{
|
||||
return messageUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw/binary content of an instant message.
|
||||
*
|
||||
* @return a byte[] array containing message bytes.
|
||||
*/
|
||||
public byte[] getRawData()
|
||||
{
|
||||
return getContent().getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the content stored in this message.
|
||||
*
|
||||
* @return an int indicating the number of bytes that this message
|
||||
* contains.
|
||||
*/
|
||||
public int getSize()
|
||||
{
|
||||
return getContent().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject of this message or null if the message contains no
|
||||
* subject.
|
||||
*
|
||||
* @return the subject of this message or null if the message contains
|
||||
* no subject.
|
||||
*/
|
||||
public String getSubject()
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The Msn implementation of a sip-communicator AccountID
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MsnAccountID
|
||||
extends AccountID
|
||||
{
|
||||
/**
|
||||
* Creates an account id from the specified id and account properties.
|
||||
* @param id the id identifying this account
|
||||
* @param accountProperties any other properties necessary for the account.
|
||||
*/
|
||||
MsnAccountID(String id, Map accountProperties )
|
||||
{
|
||||
super(id, accountProperties, ProtocolNames.MSN, "msn.com");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Loads the MSN provider factory and registers it with service in the OSGI
|
||||
* bundle context.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MsnActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private ServiceRegistration msnPpFactoryServReg = null;
|
||||
private static BundleContext bundleContext = null;
|
||||
private static ConfigurationService configurationService = null;
|
||||
|
||||
private static ProtocolProviderFactoryMsnImpl msnProviderFactory = null;
|
||||
|
||||
/**
|
||||
* Called when this bundle is started so the Framework can perform the
|
||||
* bundle-specific activities necessary to start this bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being started.
|
||||
* @throws Exception If this method throws an exception, this bundle is
|
||||
* marked as stopped and the Framework will remove this bundle's
|
||||
* listeners, unregister all services registered by this bundle, and
|
||||
* release all services used by this bundle.
|
||||
*/
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
this.bundleContext = context;
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(ProtocolProviderFactory.PROTOCOL, ProtocolNames.MSN);
|
||||
|
||||
msnProviderFactory = new ProtocolProviderFactoryMsnImpl();
|
||||
|
||||
//load all msn providers
|
||||
msnProviderFactory.loadStoredAccounts();
|
||||
|
||||
//reg the msn account man.
|
||||
msnPpFactoryServReg = context.registerService(
|
||||
ProtocolProviderFactory.class.getName(),
|
||||
msnProviderFactory,
|
||||
hashtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a ConfigurationService implementation currently
|
||||
* registered in the bundle context or null if no such implementation was
|
||||
* found.
|
||||
*
|
||||
* @return ConfigurationService a currently valid implementation of the
|
||||
* configuration service.
|
||||
*/
|
||||
public static ConfigurationService getConfigurationService()
|
||||
{
|
||||
if(configurationService == null)
|
||||
{
|
||||
ServiceReference confReference
|
||||
= bundleContext.getServiceReference(
|
||||
ConfigurationService.class.getName());
|
||||
configurationService
|
||||
= (ConfigurationService) bundleContext.getService(confReference);
|
||||
}
|
||||
return configurationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the bundle context that we were started with.
|
||||
* @return a reference to the BundleContext instance that we were started
|
||||
* witn.
|
||||
*/
|
||||
public static BundleContext getBundleContext()
|
||||
{
|
||||
return bundleContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrurns a reference to the protocol provider factory that we have
|
||||
* registered.
|
||||
* @return a reference to the <tt>ProtocolProviderFactoryMsnImpl</tt>
|
||||
* instance that we have registered from this package.
|
||||
*/
|
||||
static ProtocolProviderFactoryMsnImpl getProtocolProviderFactory()
|
||||
{
|
||||
return msnProviderFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being stopped.
|
||||
* @throws Exception If this method throws an exception, the bundle is
|
||||
* still marked as stopped, and the Framework will remove the bundle's
|
||||
* listeners, unregister all services registered by the bundle, and
|
||||
* release all services used by the bundle.
|
||||
*/
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
msnProviderFactory.stop();
|
||||
msnPpFactoryServReg.unregister();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.service.protocol.msnconstants.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.sf.jml.*;
|
||||
import net.sf.jml.event.*;
|
||||
import net.sf.jml.message.*;
|
||||
|
||||
/**
|
||||
* A straightforward implementation of the basic instant messaging operation
|
||||
* set.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class OperationSetBasicInstantMessagingMsnImpl
|
||||
implements OperationSetBasicInstantMessaging
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OperationSetBasicInstantMessagingMsnImpl.class);
|
||||
|
||||
/**
|
||||
* A list of listeneres registered for message events.
|
||||
*/
|
||||
private Vector messageListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceMsnImpl msnProvider = null;
|
||||
|
||||
/**
|
||||
* A reference to the persistent presence operation set that we use
|
||||
* to match incoming messages to <tt>Contact</tt>s and vice versa.
|
||||
*/
|
||||
private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this operation set.
|
||||
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
|
||||
* that created us and that we'll use for retrieving the underlying aim
|
||||
* connection.
|
||||
*/
|
||||
OperationSetBasicInstantMessagingMsnImpl(
|
||||
ProtocolProviderServiceMsnImpl provider)
|
||||
{
|
||||
this.msnProvider = provider;
|
||||
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registeres a MessageListener with this operation set so that it gets
|
||||
* notifications of successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to register.
|
||||
*/
|
||||
public void addMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
if(!messageListeners.contains(listener))
|
||||
{
|
||||
this.messageListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisteres <tt>listener</tt> so that it won't receive any further
|
||||
* notifications upon successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to unregister.
|
||||
*/
|
||||
public void removeMessageListener(MessageListener listener)
|
||||
{
|
||||
synchronized(messageListeners)
|
||||
{
|
||||
this.messageListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending arbitrary MIME-encoding content.
|
||||
*
|
||||
* @param content content value
|
||||
* @param contentType the MIME-type for <tt>content</tt>
|
||||
* @param contentEncoding encoding used for <tt>content</tt>
|
||||
* @param subject a <tt>String</tt> subject or <tt>null</tt> for now subject.
|
||||
* @return the newly created message.
|
||||
*/
|
||||
public Message createMessage(byte[] content, String contentType,
|
||||
String contentEncoding, String subject)
|
||||
{
|
||||
return new MessageMsnImpl(new String(content), contentType
|
||||
, contentEncoding, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending a simple text messages with
|
||||
* default (text/plain) content type and encoding.
|
||||
*
|
||||
* @param messageText the string content of the message.
|
||||
* @return Message the newly created message
|
||||
*/
|
||||
public Message createMessage(String messageText)
|
||||
{
|
||||
return new MessageMsnImpl(messageText, DEFAULT_MIME_TYPE
|
||||
, DEFAULT_MIME_ENCODING, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the <tt>message</tt> to the destination indicated by the
|
||||
* <tt>to</tt> contact.
|
||||
*
|
||||
* @param to the <tt>Contact</tt> to send <tt>message</tt> to
|
||||
* @param message the <tt>Message</tt> to send.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
* @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
|
||||
* instance of ContactImpl.
|
||||
*/
|
||||
public void sendInstantMessage(Contact to, Message message)
|
||||
throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
assertConnected();
|
||||
|
||||
if(to.getPresenceStatus().equals(MsnStatusEnum.OFFLINE))
|
||||
{
|
||||
MessageDeliveryFailedEvent evt =
|
||||
new MessageDeliveryFailedEvent(
|
||||
message,
|
||||
to,
|
||||
MessageDeliveryFailedEvent.OFFLINE_MESSAGES_NOT_SUPPORTED,
|
||||
new Date());
|
||||
fireMessageEvent(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
msnProvider.getMessenger().
|
||||
sendText(
|
||||
((ContactMsnImpl)to).getSourceContact().getEmail(),
|
||||
message.getContent()
|
||||
);
|
||||
MessageDeliveredEvent msgDeliveredEvt
|
||||
= new MessageDeliveredEvent(
|
||||
message, to, new Date());
|
||||
|
||||
fireMessageEvent(msgDeliveredEvt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method throwing an exception if the stack is not properly
|
||||
* initialized.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
*/
|
||||
private void assertConnected() throws IllegalStateException
|
||||
{
|
||||
if (msnProvider == null)
|
||||
throw new IllegalStateException(
|
||||
"The provider must be non-null and signed on the "
|
||||
+"service before being able to communicate.");
|
||||
if (!msnProvider.isRegistered())
|
||||
throw new IllegalStateException(
|
||||
"The provider must be signed on the service before "
|
||||
+"being able to communicate.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Our listener that will tell us when we're registered to
|
||||
*/
|
||||
private class RegistrationStateListener
|
||||
implements RegistrationStateChangeListener
|
||||
{
|
||||
/**
|
||||
* The method is called by a ProtocolProvider implementation whenver
|
||||
* a change in the registration state of the corresponding provider had
|
||||
* occurred.
|
||||
* @param evt ProviderStatusChangeEvent the event describing the status
|
||||
* change.
|
||||
*/
|
||||
public void registrationStateChanged(RegistrationStateChangeEvent evt)
|
||||
{
|
||||
logger.debug("The provider changed state from: "
|
||||
+ evt.getOldState()
|
||||
+ " to: " + evt.getNewState());
|
||||
|
||||
if (evt.getNewState() == RegistrationState.REGISTERED)
|
||||
{
|
||||
opSetPersPresence = (OperationSetPersistentPresenceMsnImpl)
|
||||
msnProvider.getSupportedOperationSets()
|
||||
.get(OperationSetPersistentPresence.class.getName());
|
||||
|
||||
msnProvider.getMessenger().
|
||||
addMessageListener(new MsnMessageListener());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers the specified event to all registered message listeners.
|
||||
* @param evt the <tt>EventObject</tt> that we'd like delivered to all
|
||||
* registered message listerners.
|
||||
*/
|
||||
private void fireMessageEvent(EventObject evt)
|
||||
{
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
if (evt instanceof MessageDeliveredEvent)
|
||||
{
|
||||
listener.messageDelivered( (MessageDeliveredEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageReceivedEvent)
|
||||
{
|
||||
listener.messageReceived( (MessageReceivedEvent) evt);
|
||||
}
|
||||
else if (evt instanceof MessageDeliveryFailedEvent)
|
||||
{
|
||||
listener.messageDeliveryFailed(
|
||||
(MessageDeliveryFailedEvent) evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MsnMessageListener
|
||||
extends MsnMessageAdapter
|
||||
{
|
||||
public void instantMessageReceived(MsnSwitchboard switchboard,
|
||||
MsnInstantMessage message,
|
||||
MsnContact contact)
|
||||
{
|
||||
Message newMessage = createMessage(message.getContent());
|
||||
Contact sourceContact = opSetPersPresence.
|
||||
findContactByID(contact.getEmail().getEmailAddress());
|
||||
|
||||
if(sourceContact == null)
|
||||
{
|
||||
logger.debug("received a message from an unknown contact: "
|
||||
+ contact);
|
||||
//create the volatile contact
|
||||
sourceContact = opSetPersPresence
|
||||
.createVolatileContact(contact.getEmail().getEmailAddress());
|
||||
}
|
||||
|
||||
MessageReceivedEvent msgReceivedEvt
|
||||
= new MessageReceivedEvent(
|
||||
newMessage, sourceContact , new Date() );
|
||||
|
||||
fireMessageEvent(msgReceivedEvt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Maps SIP Communicator typing notifications to those going and coming from
|
||||
* smack lib.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class OperationSetTypingNotificationsMsnImpl
|
||||
implements OperationSetTypingNotifications
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OperationSetTypingNotificationsMsnImpl.class);
|
||||
|
||||
/**
|
||||
* All currently registered TN listeners.
|
||||
*/
|
||||
private List typingNotificationsListeners = new ArrayList();
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceMsnImpl msnProvider = null;
|
||||
|
||||
/**
|
||||
* An active instance of the opSetPersPresence operation set. We're using
|
||||
* it to map incoming events to contacts in our contact list.
|
||||
*/
|
||||
private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
|
||||
* that created us and that we'll use for retrieving the underlying aim
|
||||
* connection.
|
||||
*/
|
||||
OperationSetTypingNotificationsMsnImpl(
|
||||
ProtocolProviderServiceMsnImpl provider)
|
||||
{
|
||||
this.msnProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>l</tt> to the list of listeners registered for receiving
|
||||
* <tt>TypingNotificationEvent</tt>s
|
||||
*
|
||||
* @param l the <tt>TypingNotificationsListener</tt> listener that we'd
|
||||
* like to add
|
||||
* method
|
||||
*/
|
||||
public void addTypingNotificationsListener(TypingNotificationsListener l)
|
||||
{
|
||||
synchronized(typingNotificationsListeners)
|
||||
{
|
||||
typingNotificationsListeners.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes <tt>l</tt> from the list of listeners registered for receiving
|
||||
* <tt>TypingNotificationEvent</tt>s
|
||||
*
|
||||
* @param l the <tt>TypingNotificationsListener</tt> listener that we'd
|
||||
* like to remove
|
||||
*/
|
||||
public void removeTypingNotificationsListener(TypingNotificationsListener l)
|
||||
{
|
||||
synchronized(typingNotificationsListeners)
|
||||
{
|
||||
typingNotificationsListeners.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers a <tt>TypingNotificationEvent</tt> to all registered listeners.
|
||||
* @param sourceContact the contact who has sent the notification.
|
||||
* @param evtCode the code of the event to deliver.
|
||||
*/
|
||||
private void fireTypingNotificationsEvent(Contact sourceContact
|
||||
,int evtCode)
|
||||
{
|
||||
logger.debug("Dispatching a TypingNotif. event to "
|
||||
+ typingNotificationsListeners.size()+" listeners. Contact "
|
||||
+ sourceContact.getAddress() + " has now a typing status of "
|
||||
+ evtCode);
|
||||
|
||||
TypingNotificationEvent evt = new TypingNotificationEvent(
|
||||
sourceContact, evtCode);
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (typingNotificationsListeners)
|
||||
{
|
||||
listeners = new ArrayList(typingNotificationsListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
TypingNotificationsListener listener
|
||||
= (TypingNotificationsListener) listeners.next();
|
||||
|
||||
listener.typingNotificationReceifed(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to <tt>notifiedContatct</tt> that we have entered
|
||||
* <tt>typingState</tt>.
|
||||
*
|
||||
* @param notifiedContact the <tt>Contact</tt> to notify
|
||||
* @param typingState the typing state that we have entered.
|
||||
*
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
* @throws java.lang.IllegalArgumentException if <tt>notifiedContact</tt> is
|
||||
* not an instance belonging to the underlying implementation.
|
||||
*/
|
||||
public void sendTypingNotification(Contact notifiedContact, int typingState)
|
||||
throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
assertConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method throwing an exception if the stack is not properly
|
||||
* initialized.
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
*/
|
||||
private void assertConnected() throws IllegalStateException
|
||||
{
|
||||
if (msnProvider == null)
|
||||
throw new IllegalStateException(
|
||||
"The msn provider must be non-null and signed on the "
|
||||
+"service before being able to communicate.");
|
||||
if (!msnProvider.isRegistered())
|
||||
throw new IllegalStateException(
|
||||
"The msn provider must be signed on the service before "
|
||||
+"being able to communicate.");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The Msn implementation of the ProtocolProviderFactory.
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class ProtocolProviderFactoryMsnImpl
|
||||
extends ProtocolProviderFactory
|
||||
{
|
||||
/**
|
||||
* The table that we store our accounts in.
|
||||
*/
|
||||
private Hashtable registeredAccounts = new Hashtable();
|
||||
|
||||
/**
|
||||
* Creates an instance of the ProtocolProviderFactoryMsnImpl.
|
||||
*/
|
||||
protected ProtocolProviderFactoryMsnImpl()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the list containing all accounts currently
|
||||
* registered in this protocol provider.
|
||||
*
|
||||
* @return a copy of the llist containing all accounts currently installed
|
||||
* in the protocol provider.
|
||||
*/
|
||||
public ArrayList getRegisteredAccounts()
|
||||
{
|
||||
return new ArrayList(registeredAccounts.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ServiceReference for the protocol provider corresponding to
|
||||
* the specified accountID or null if the accountID is unknown.
|
||||
* @param accountID the accountID of the protocol provider we'd like to get
|
||||
* @return a ServiceReference object to the protocol provider with the
|
||||
* specified account id and null if the account id is unknwon to the
|
||||
* provider factory.
|
||||
*/
|
||||
public ServiceReference getProviderForAccount(AccountID accountID)
|
||||
{
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.get(accountID);
|
||||
|
||||
return (registration == null )
|
||||
? null
|
||||
: registration.getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and creates an account corresponding to the specified
|
||||
* accountProperties and registers the resulting ProtocolProvider in the
|
||||
* <tt>context</tt> BundleContext parameter. This method has a persistent
|
||||
* effect. Once created the resulting account will remain installed until
|
||||
* removed through the uninstall account method.
|
||||
*
|
||||
* @param userIDStr the user identifier for the new account
|
||||
* @param accountProperties a set of protocol (or implementation)
|
||||
* specific properties defining the new account.
|
||||
* @return the AccountID of the newly created account
|
||||
*/
|
||||
public AccountID installAccount( String userIDStr,
|
||||
Map accountProperties)
|
||||
{
|
||||
BundleContext context
|
||||
= MsnActivator.getBundleContext();
|
||||
if (context == null)
|
||||
throw new NullPointerException("The specified BundleContext was null");
|
||||
|
||||
if (userIDStr == null)
|
||||
throw new NullPointerException("The specified AccountID was null");
|
||||
|
||||
if (accountProperties == null)
|
||||
throw new NullPointerException("The specified property map was null");
|
||||
|
||||
accountProperties.put(USER_ID, userIDStr);
|
||||
|
||||
AccountID accountID = new MsnAccountID(userIDStr, accountProperties);
|
||||
|
||||
//make sure we haven't seen this account id before.
|
||||
if( registeredAccounts.containsKey(accountID) )
|
||||
throw new IllegalStateException(
|
||||
"An account for id " + userIDStr + " was already installed!");
|
||||
|
||||
//first store the account and only then load it as the load generates
|
||||
//an osgi event, the osgi event triggers (trhgough the UI) a call to
|
||||
//the register() method and it needs to acces the configuration service
|
||||
//and check for a password.
|
||||
this.storeAccount(
|
||||
MsnActivator.getBundleContext()
|
||||
, accountID);
|
||||
|
||||
accountID = loadAccount(accountProperties);
|
||||
|
||||
return accountID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and creates an account corresponding to the specified
|
||||
* accountProperties and registers the resulting ProtocolProvider in the
|
||||
* <tt>context</tt> BundleContext parameter.
|
||||
*
|
||||
* @param accountProperties a set of protocol (or implementation)
|
||||
* specific properties defining the new account.
|
||||
* @return the AccountID of the newly created account
|
||||
*/
|
||||
public AccountID loadAccount( Map accountProperties)
|
||||
{
|
||||
BundleContext context
|
||||
= MsnActivator.getBundleContext();
|
||||
if(context == null)
|
||||
throw new NullPointerException("The specified BundleContext was null");
|
||||
|
||||
String userIDStr = (String)accountProperties.get(USER_ID);
|
||||
|
||||
AccountID accountID = new MsnAccountID(userIDStr, accountProperties);
|
||||
|
||||
//get a reference to the configuration service and register whatever
|
||||
//properties we have in it.
|
||||
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put(PROTOCOL, ProtocolNames.MSN);
|
||||
properties.put(USER_ID, userIDStr);
|
||||
|
||||
ProtocolProviderServiceMsnImpl msnProtocolProvider
|
||||
= new ProtocolProviderServiceMsnImpl();
|
||||
|
||||
msnProtocolProvider.initialize(userIDStr, accountID);
|
||||
|
||||
ServiceRegistration registration
|
||||
= context.registerService( ProtocolProviderService.class.getName(),
|
||||
msnProtocolProvider,
|
||||
properties);
|
||||
|
||||
registeredAccounts.put(accountID, registration);
|
||||
return accountID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified account from the list of accounts that this
|
||||
* provider factory is handling. If the specified accountID is unknown to
|
||||
* the ProtocolProviderFactory, the call has no effect and false is returned.
|
||||
* This method is persistent in nature and once called the account
|
||||
* corresponding to the specified ID will not be loaded during future runs
|
||||
* of the project.
|
||||
*
|
||||
* @param accountID the ID of the account to remove.
|
||||
* @return true if an account with the specified ID existed and was removed
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean uninstallAccount(AccountID accountID)
|
||||
{
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.remove(accountID);
|
||||
|
||||
if(registration == null)
|
||||
return false;
|
||||
|
||||
//kill the service
|
||||
registration.unregister();
|
||||
|
||||
return removeStoredAccount(
|
||||
MsnActivator.getBundleContext()
|
||||
, accountID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads (and hence installs) all accounts previously stored in the
|
||||
* configuration service.
|
||||
*/
|
||||
public void loadStoredAccounts()
|
||||
{
|
||||
super.loadStoredAccounts( MsnActivator.getBundleContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the factory for bundle shutdown.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
Enumeration registrations = this.registeredAccounts.elements();
|
||||
|
||||
while(registrations.hasMoreElements())
|
||||
{
|
||||
ServiceRegistration reg
|
||||
= ((ServiceRegistration)registrations.nextElement());
|
||||
|
||||
reg.unregister();
|
||||
}
|
||||
|
||||
Enumeration idEnum = registeredAccounts.keys();
|
||||
|
||||
while(idEnum.hasMoreElements())
|
||||
{
|
||||
registeredAccounts.remove(idEnum.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuraiton service property name prefix that we use to
|
||||
* store properties concerning the account with the specified id.
|
||||
* @param accountID the AccountID whose property name prefix we're looking
|
||||
* for.
|
||||
* @return the prefix of the configuration service property name that
|
||||
* we're using when storing properties for the specified account.
|
||||
*/
|
||||
public String findAccountPrefix(AccountID accountID)
|
||||
{
|
||||
return super.findAccountPrefix(MsnActivator.getBundleContext()
|
||||
, accountID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the password for the specified account after scrambling it a bit
|
||||
* so that it is not visible from first sight (Method remains highly
|
||||
* insecure).
|
||||
*
|
||||
* @param accountID the AccountID for the account whose password we're
|
||||
* storing.
|
||||
* @param passwd the password itself.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if no account corresponding
|
||||
* to <tt>accountID</tt> has been previously stored.
|
||||
*/
|
||||
public void storePassword(AccountID accountID, String passwd)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super.storePassword(MsnActivator.getBundleContext()
|
||||
, accountID
|
||||
, passwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password last saved for the specified account.
|
||||
*
|
||||
* @param accountID the AccountID for the account whose password we're
|
||||
* looking for..
|
||||
*
|
||||
* @return a String containing the password for the specified accountID.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if no account corresponding
|
||||
* to <tt>accountID</tt> has been previously stored.
|
||||
*/
|
||||
public String loadPassword(AccountID accountID)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
return super.loadPassword(MsnActivator.getBundleContext()
|
||||
, accountID );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.sf.jml.*;
|
||||
import net.sf.jml.event.*;
|
||||
import net.sf.jml.impl.*;
|
||||
|
||||
/**
|
||||
* An implementation of the protocol provider service over the Msn protocol
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class ProtocolProviderServiceMsnImpl
|
||||
implements ProtocolProviderService
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ProtocolProviderServiceMsnImpl.class);
|
||||
|
||||
/**
|
||||
* The hashtable with the operation sets that we support locally.
|
||||
*/
|
||||
private Hashtable supportedOperationSets = new Hashtable();
|
||||
|
||||
private MsnMessenger messenger = null;
|
||||
|
||||
/**
|
||||
* indicates whether or not the provider is initialized and ready for use.
|
||||
*/
|
||||
private boolean isInitialized = false;
|
||||
|
||||
/**
|
||||
* We use this to lock access to initialization.
|
||||
*/
|
||||
private Object initializationLock = new Object();
|
||||
|
||||
/**
|
||||
* A list of all listeners registered for
|
||||
* <tt>RegistrationStateChangeEvent</tt>s.
|
||||
*/
|
||||
private List registrationListeners = new ArrayList();
|
||||
|
||||
/**
|
||||
* The identifier of the account that this provider represents.
|
||||
*/
|
||||
private AccountID accountID = null;
|
||||
|
||||
/**
|
||||
* Used when we need to re-register
|
||||
*/
|
||||
private SecurityAuthority authority = null;
|
||||
|
||||
private OperationSetPersistentPresenceMsnImpl persistentPresence = null;
|
||||
|
||||
/**
|
||||
* Returns the state of the registration of this protocol provider
|
||||
* @return the <tt>RegistrationState</tt> that this provider is
|
||||
* currently in or null in case it is in a unknown state.
|
||||
*/
|
||||
public RegistrationState getRegistrationState()
|
||||
{
|
||||
if(messenger.getConnection() == null)
|
||||
return RegistrationState.UNREGISTERED;
|
||||
else
|
||||
return RegistrationState.REGISTERED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the registration process. Connection details such as
|
||||
* registration server, user name/number are provided through the
|
||||
* configuration service through implementation specific properties.
|
||||
*
|
||||
* @param authority the security authority that will be used for resolving
|
||||
* any security challenges that may be returned during the
|
||||
* registration or at any moment while wer're registered.
|
||||
* @throws OperationFailedException with the corresponding code it the
|
||||
* registration fails for some reason (e.g. a networking error or an
|
||||
* implementation problem).
|
||||
*/
|
||||
public void register(final SecurityAuthority authority)
|
||||
throws OperationFailedException
|
||||
{
|
||||
if(authority == null)
|
||||
throw new IllegalArgumentException(
|
||||
"The register method needs a valid non-null authority impl "
|
||||
+ " in order to be able and retrieve passwords.");
|
||||
|
||||
this.authority = authority;
|
||||
|
||||
connectAndLogin(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects and logins to the server
|
||||
* @param authority SecurityAuthority
|
||||
* @throws XMPPException if we cannot connect to the server - network problem
|
||||
* @throws OperationFailedException if login parameters
|
||||
* as server port are not correct
|
||||
*/
|
||||
private void connectAndLogin(SecurityAuthority authority)
|
||||
throws OperationFailedException
|
||||
{
|
||||
synchronized(initializationLock)
|
||||
{
|
||||
//verify whether a password has already been stored for this account
|
||||
String password = MsnActivator.
|
||||
getProtocolProviderFactory().loadPassword(getAccountID());
|
||||
|
||||
//decode
|
||||
if (password == null)
|
||||
{
|
||||
//create a default credentials object
|
||||
UserCredentials credentials = new UserCredentials();
|
||||
credentials.setUserName(getAccountID().getUserID());
|
||||
|
||||
//request a password from the user
|
||||
credentials = authority.obtainCredentials(ProtocolNames.MSN
|
||||
, credentials);
|
||||
|
||||
//extract the password the user passed us.
|
||||
char[] pass = credentials.getPassword();
|
||||
|
||||
// the user didn't provide us a password (canceled the operation)
|
||||
if(pass == null)
|
||||
{
|
||||
fireRegistrationStateChanged(
|
||||
getRegistrationState(),
|
||||
RegistrationState.UNREGISTERED,
|
||||
RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
|
||||
return;
|
||||
}
|
||||
password = new String(pass);
|
||||
|
||||
|
||||
if (credentials.isPasswordPersistent())
|
||||
{
|
||||
MsnActivator.getProtocolProviderFactory()
|
||||
.storePassword(getAccountID(), password);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
messenger = MsnMessengerFactory.createMsnMessenger(
|
||||
getAccountID().getUserID(),
|
||||
password);
|
||||
|
||||
messenger.addMessengerListener(new MsnConnectionListener());
|
||||
|
||||
persistentPresence.setMessenger(messenger);
|
||||
|
||||
messenger.login();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the registration of this protocol provider with the service.
|
||||
*/
|
||||
public void unregister()
|
||||
{
|
||||
unregister(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister and fire the event if requested
|
||||
* @param fireEvent boolean
|
||||
*/
|
||||
private void unregister(boolean fireEvent)
|
||||
{
|
||||
RegistrationState currRegState = getRegistrationState();
|
||||
|
||||
messenger.logout();
|
||||
|
||||
if(fireEvent)
|
||||
{
|
||||
fireRegistrationStateChanged(
|
||||
currRegState,
|
||||
RegistrationState.UNREGISTERED,
|
||||
RegistrationStateChangeEvent.REASON_USER_REQUEST, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not this provider is signed on the service
|
||||
* @return true if the provider is currently signed on (and hence online)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isRegistered()
|
||||
{
|
||||
return getRegistrationState().equals(RegistrationState.REGISTERED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the short name of the protocol that the implementation of this
|
||||
* provider is based upon (like SIP, Msn, ICQ/AIM, or others for
|
||||
* example).
|
||||
*
|
||||
* @return a String containing the short name of the protocol this
|
||||
* service is taking care of.
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return ProtocolNames.MSN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all operation sets supported by the
|
||||
* current implementation.
|
||||
*
|
||||
* @return an array of OperationSet-s supported by this protocol
|
||||
* provider implementation.
|
||||
*/
|
||||
public Map getSupportedOperationSets()
|
||||
{
|
||||
return supportedOperationSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the operation set corresponding to the specified class or null
|
||||
* if this operation set is not supported by the provider implementation.
|
||||
*
|
||||
* @param opsetClass the <tt>Class</tt> of the operation set that we're
|
||||
* looking for.
|
||||
* @return returns an OperationSet of the specified <tt>Class</tt> if the
|
||||
* undelying implementation supports it or null otherwise.
|
||||
*/
|
||||
public OperationSet getOperationSet(Class opsetClass)
|
||||
{
|
||||
return (OperationSet)getSupportedOperationSets()
|
||||
.get(opsetClass.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialized the service implementation, and puts it in a sate where it
|
||||
* could interoperate with other services. It is strongly recomended that
|
||||
* properties in this Map be mapped to property names as specified by
|
||||
* <tt>AccountProperties</tt>.
|
||||
*
|
||||
* @param screenname the account id/uin/screenname of the account that
|
||||
* we're about to create
|
||||
* @param accountID the identifier of the account that this protocol
|
||||
* provider represents.
|
||||
*
|
||||
* @see net.java.sip.communicator.service.protocol.AccountID
|
||||
*/
|
||||
protected void initialize(String screenname,
|
||||
AccountID accountID)
|
||||
{
|
||||
synchronized(initializationLock)
|
||||
{
|
||||
this.accountID = accountID;
|
||||
|
||||
//initialize the presence operationset
|
||||
persistentPresence = new OperationSetPersistentPresenceMsnImpl(this);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetPersistentPresence.class.getName(),
|
||||
persistentPresence);
|
||||
|
||||
//register it once again for those that simply need presence
|
||||
supportedOperationSets.put( OperationSetPresence.class.getName(),
|
||||
persistentPresence);
|
||||
|
||||
//initialize the IM operation set
|
||||
OperationSetBasicInstantMessagingMsnImpl basicInstantMessaging =
|
||||
new OperationSetBasicInstantMessagingMsnImpl(this);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetBasicInstantMessaging.class.getName(),
|
||||
basicInstantMessaging);
|
||||
|
||||
//initialize the typing notifications operation set
|
||||
OperationSetTypingNotifications typingNotifications =
|
||||
new OperationSetTypingNotificationsMsnImpl(this);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetTypingNotifications.class.getName(),
|
||||
typingNotifications);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the service implementation close all open sockets and release
|
||||
* any resources that it might have taken and prepare for
|
||||
* shutdown/garbage collection.
|
||||
*/
|
||||
public void shutdown()
|
||||
{
|
||||
synchronized(initializationLock){
|
||||
messenger.logout();
|
||||
messenger = null;
|
||||
isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider service implementation is initialized and
|
||||
* ready for use by other services, and false otherwise.
|
||||
*
|
||||
* @return true if the provider is initialized and ready for use and false
|
||||
* otherwise
|
||||
*/
|
||||
public boolean isInitialized()
|
||||
{
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified registration state change listener so that it does
|
||||
* not receive any further notifications upon changes of the
|
||||
* RegistrationState of this provider.
|
||||
*
|
||||
* @param listener the listener to register for
|
||||
* <tt>RegistrationStateChangeEvent</tt>s.
|
||||
*/
|
||||
public void removeRegistrationStateChangeListener(
|
||||
RegistrationStateChangeListener listener)
|
||||
{
|
||||
synchronized(registrationListeners)
|
||||
{
|
||||
registrationListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified listener with this provider so that it would
|
||||
* receive notifications on changes of its state or other properties such
|
||||
* as its local address and display name.
|
||||
*
|
||||
* @param listener the listener to register.
|
||||
*/
|
||||
public void addRegistrationStateChangeListener(
|
||||
RegistrationStateChangeListener listener)
|
||||
{
|
||||
synchronized(registrationListeners)
|
||||
{
|
||||
if (!registrationListeners.contains(listener))
|
||||
registrationListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AccountID that uniquely identifies the account represented
|
||||
* by this instance of the ProtocolProviderService.
|
||||
* @return the id of the account represented by this provider.
|
||||
*/
|
||||
public AccountID getAccountID()
|
||||
{
|
||||
return accountID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>XMPPConnection</tt>opened by this provider
|
||||
* @return a reference to the <tt>XMPPConnection</tt> last opened by this
|
||||
* provider.
|
||||
*/
|
||||
MsnMessenger getMessenger()
|
||||
{
|
||||
return messenger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a RegistrationStateChange event corresponding to the specified
|
||||
* old and new states and notifies all currently registered listeners.
|
||||
*
|
||||
* @param oldState the state that the provider had before the change
|
||||
* occurred
|
||||
* @param newState the state that the provider is currently in.
|
||||
* @param reasonCode a value corresponding to one of the REASON_XXX fields
|
||||
* of the RegistrationStateChangeEvent class, indicating the reason for
|
||||
* this state transition.
|
||||
* @param reason a String further explaining the reason code or null if
|
||||
* no such explanation is necessary.
|
||||
*/
|
||||
void fireRegistrationStateChanged( RegistrationState oldState,
|
||||
RegistrationState newState,
|
||||
int reasonCode,
|
||||
String reason)
|
||||
{
|
||||
RegistrationStateChangeEvent event =
|
||||
new RegistrationStateChangeEvent(
|
||||
this, oldState, newState, reasonCode, reason);
|
||||
|
||||
logger.debug("Dispatching " + event + " to "
|
||||
+ registrationListeners.size()+ " listeners.");
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (registrationListeners)
|
||||
{
|
||||
listeners = new ArrayList(registrationListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
RegistrationStateChangeListener listener
|
||||
= (RegistrationStateChangeListener) listeners.next();
|
||||
|
||||
listener.registrationStateChanged(event);
|
||||
}
|
||||
|
||||
logger.trace("Done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens when we are logged in or out from the server
|
||||
* or incoming exception in the lib impl.
|
||||
*/
|
||||
private class MsnConnectionListener
|
||||
implements MsnMessengerListener
|
||||
{
|
||||
public void loginCompleted(MsnMessenger msnMessenger)
|
||||
{
|
||||
logger.trace("loginCompleted " + msnMessenger.getActualMsnProtocol());
|
||||
fireRegistrationStateChanged(
|
||||
getRegistrationState(),
|
||||
RegistrationState.REGISTERED,
|
||||
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
|
||||
}
|
||||
|
||||
public void logout(MsnMessenger msnMessenger)
|
||||
{
|
||||
logger.trace("logout");
|
||||
|
||||
}
|
||||
|
||||
public void exceptionCaught(MsnMessenger msnMessenger, Throwable throwable)
|
||||
{
|
||||
logger.error("Error in Msn lib ", throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* A dummy ContactGroup implementation representing the ContactList root for
|
||||
* Msn contact lists.
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class RootContactGroupMsnImpl
|
||||
extends AbstractContactGroupMsnImpl
|
||||
{
|
||||
private String ROOT_CONTACT_GROUP_NAME = "ContactListRoot";
|
||||
private List subGroups = new LinkedList();
|
||||
private boolean isResolved = false;
|
||||
|
||||
private List contacts = new LinkedList();
|
||||
|
||||
private ProtocolProviderServiceMsnImpl ownerProvider = null;
|
||||
|
||||
/**
|
||||
* Creates a ContactGroup instance.
|
||||
*/
|
||||
RootContactGroupMsnImpl(){}
|
||||
|
||||
/**
|
||||
* Sets the currently valid provider
|
||||
* @param ownerProvider ProtocolProviderServiceImpl
|
||||
*/
|
||||
void setOwnerProvider(ProtocolProviderServiceMsnImpl ownerProvider)
|
||||
{
|
||||
this.ownerProvider = ownerProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* The ContactListRoot is the only group that can contain subgroups.
|
||||
*
|
||||
* @return true (always)
|
||||
*/
|
||||
public boolean canContainSubgroups()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this group which is always
|
||||
* <tt>ROOT_CONTACT_GROUP_NAME</tt>.
|
||||
*
|
||||
* @return a String containing the name of this group.
|
||||
*/
|
||||
public String getGroupName()
|
||||
{
|
||||
return ROOT_CONTACT_GROUP_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified contact from this contact group
|
||||
* @param contact the contact to remove.
|
||||
*/
|
||||
void removeContact(ContactMsnImpl contact)
|
||||
{
|
||||
contacts.remove(contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact to the end of this group.
|
||||
* @param contact the new contact to add to this group
|
||||
*/
|
||||
void addContact(ContactMsnImpl contact)
|
||||
{
|
||||
contacts.add(contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified group to the end of the list of sub groups.
|
||||
* @param group the group to add.
|
||||
*/
|
||||
void addSubGroup(ContactGroupMsnImpl group)
|
||||
{
|
||||
subGroups.add(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified from the list of sub groups
|
||||
* @param group the group to remove.
|
||||
*/
|
||||
void removeSubGroup(ContactGroupMsnImpl group)
|
||||
{
|
||||
removeSubGroup(subGroups.indexOf(group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the sub group with the specified index.
|
||||
* @param index the index of the group to remove
|
||||
*/
|
||||
void removeSubGroup(int index)
|
||||
{
|
||||
subGroups.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all contact sub groups and reinsterts them as specified
|
||||
* by the <tt>newOrder</tt> param. Contact groups not contained in the
|
||||
* newOrder list are left at the end of this group.
|
||||
*
|
||||
* @param newOrder a list containing all contact groups in the order that is
|
||||
* to be applied.
|
||||
*
|
||||
*/
|
||||
void reorderSubGroups(List newOrder)
|
||||
{
|
||||
subGroups.removeAll(newOrder);
|
||||
subGroups.addAll(0, newOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of subgroups contained by this
|
||||
* <tt>RootContactGroupImpl</tt>.
|
||||
*
|
||||
* @return an int indicating the number of subgroups that this
|
||||
* ContactGroup contains.
|
||||
*/
|
||||
public int countSubgroups()
|
||||
{
|
||||
return subGroups.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as this is the root contact group.
|
||||
* @return null as this is the root contact group.
|
||||
*/
|
||||
public ContactGroup getParentContactGroup()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified index.
|
||||
*
|
||||
* @param index the index of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return the <tt>ContactGroup</tt> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(int index)
|
||||
{
|
||||
return (ContactGroupMsnImpl) subGroups.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified name.
|
||||
* @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return the <tt>ContactGroup</tt> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(String groupName)
|
||||
{
|
||||
Iterator subgroups = subgroups();
|
||||
while (subgroups.hasNext())
|
||||
{
|
||||
ContactGroupMsnImpl grp = (ContactGroupMsnImpl) subgroups.next();
|
||||
|
||||
if (grp.getGroupName().equals(groupName))
|
||||
return grp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the sub groups that this
|
||||
* <tt>ContactGroup</tt> contains.
|
||||
*
|
||||
* @return a java.util.Iterator over the <tt>ContactGroup</tt>
|
||||
* children of this group (i.e. subgroups).
|
||||
*/
|
||||
public Iterator subgroups()
|
||||
{
|
||||
return subGroups.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number, which is always 0, of <tt>Contact</tt> members
|
||||
* of this <tt>ContactGroup</tt>
|
||||
* @return an int indicating the number of <tt>Contact</tt>s, members
|
||||
* of this <tt>ContactGroup</tt>.
|
||||
*/
|
||||
public int countContacts()
|
||||
{
|
||||
return contacts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator over all contacts, member of this
|
||||
* <tt>ContactGroup</tt>.
|
||||
* @return a java.util.Iterator over all contacts inside this
|
||||
* <tt>ContactGroup</tt>
|
||||
*/
|
||||
public Iterator contacts()
|
||||
{
|
||||
return contacts.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* A dummy impl of the corresponding interface method - always returns null.
|
||||
*
|
||||
* @param index the index of the <tt>Contact</tt> to return.
|
||||
* @return the <tt>Contact</tt> with the specified index, i.e. always
|
||||
* null.
|
||||
*/
|
||||
public Contact getContact(int index)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>Contact</tt> with the specified address or
|
||||
* identifier.
|
||||
* @param id the addres or identifier of the <tt>Contact</tt> we are
|
||||
* looking for.
|
||||
* @return the <tt>Contact</tt> with the specified id or address.
|
||||
*/
|
||||
public Contact getContact(String id)
|
||||
{
|
||||
//no contacts in the root group for this msn impl.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a string representation of the root contact group that contains
|
||||
* all subgroups and subcontacts of this group.
|
||||
*
|
||||
* @return a string representation of this root contact group.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff = new StringBuffer(getGroupName());
|
||||
buff.append(".subGroups=" + countSubgroups() + ":\n");
|
||||
|
||||
Iterator subGroups = subgroups();
|
||||
while (subGroups.hasNext())
|
||||
{
|
||||
ContactGroup group = (ContactGroup) subGroups.next();
|
||||
buff.append(group.toString());
|
||||
if (subGroups.hasNext())
|
||||
buff.append("\n");
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol provider that this group belongs to.
|
||||
* @return a regerence to the ProtocolProviderService instance that this
|
||||
* ContactGroup belongs to.
|
||||
*/
|
||||
public ProtocolProviderService getProtocolProvider()
|
||||
{
|
||||
return this.ownerProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact group is being stored by the
|
||||
* server. Non persistent contact groups exist for the sole purpose of
|
||||
* containing non persistent contacts.
|
||||
* @return true if the contact group is persistent and false otherwise.
|
||||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as no persistent data is required and the group name is
|
||||
* sufficient for restoring the contact.
|
||||
* <p>
|
||||
* @return null as no such data is needed.
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this group has been resolved against the
|
||||
* server. Unresolved groups are used when initially loading a contact
|
||||
* list that has been stored in a local file until the presence operation
|
||||
* set has managed to retrieve all the contact list from the server and has
|
||||
* properly mapped groups to their on-line buddies.
|
||||
* @return true if the group has been resolved (mapped against a buddy)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isResolved()
|
||||
{
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>String</tt> that uniquely represnets the group. In this we
|
||||
* use the name of the group as an identifier. This may cause problems
|
||||
* though, in clase the name is changed by some other application between
|
||||
* consecutive runs of the sip-communicator.
|
||||
*
|
||||
* @return a String representing this group in a unique and persistent
|
||||
* way.
|
||||
*/
|
||||
public String getUID()
|
||||
{
|
||||
return getGroupName();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
[PropertyInfo]
|
||||
contactListModManager,net.java.sip.communicator.impl.protocol.msn.EventManager,false,false, , ,false,<default>
|
||||
messenger,net.sf.jml.MsnMessenger,false,false, , ,false,<default>
|
||||
msnProvider,net.java.sip.communicator.impl.protocol.msn.ProtocolProviderServiceMsnImpl,false,false, , ,false,<default>
|
||||
parentOperationSet,net.java.sip.communicator.impl.protocol.msn.OperationSetPersistentPresenceMsnImpl,false,false, , ,false,<default>
|
||||
rootGroup,net.java.sip.communicator.service.protocol.ContactGroup,false,false, , ,true,<default>
|
||||
serverStoredGroupListeners,java.util.Vector,false,false, , ,false,<default>
|
||||
[IconNames]
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.sf.jml.*;
|
||||
|
||||
/**
|
||||
* The Msn implementation for Volatile Contact
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class VolatileContact
|
||||
implements MsnContact
|
||||
{
|
||||
private String contactId = null;
|
||||
|
||||
VolatileContact(String id)
|
||||
{
|
||||
this.contactId = id;
|
||||
}
|
||||
|
||||
public MsnContactList getContactList(){return null;}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public String getFriendlyName()
|
||||
{
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public boolean isInList(MsnList msnList){return false;}
|
||||
|
||||
public MsnGroup[] getBelongGroups(){return null;}
|
||||
|
||||
public boolean belongGroup(MsnGroup msnGroup){return false;}
|
||||
|
||||
public Email getEmail(){return null;}
|
||||
|
||||
public String getDisplayName(){return "";}
|
||||
|
||||
public MsnUserStatus getStatus(){return null;}
|
||||
|
||||
public MsnClientId getClientId(){return null;}
|
||||
|
||||
public MsnUserProperties getProperties(){return null;}
|
||||
|
||||
public String getOldDisplayName(){return "";}
|
||||
|
||||
public MsnUserStatus getOldStatus(){return null;}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.msn;
|
||||
|
||||
import net.sf.jml.*;
|
||||
|
||||
/**
|
||||
* The Msn implementation of the Volatile ContactGroup interface.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class VolatileGroup
|
||||
implements MsnGroup
|
||||
{
|
||||
private String groupName = new String("NotInContactList");
|
||||
|
||||
public MsnContactList getContactList(){return null;}
|
||||
|
||||
public String getGroupId()
|
||||
{
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public String getGroupName()
|
||||
{
|
||||
return getGroupId();
|
||||
}
|
||||
|
||||
public MsnContact[] getContacts(){return null;}
|
||||
|
||||
public boolean containContact(MsnContact contact){return false;}
|
||||
|
||||
public boolean isDefaultGroup(){return false;}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
Bundle-Activator: net.java.sip.communicator.impl.protocol.msn.MsnActivator
|
||||
Bundle-Name: Msn Protocol Provider Implementation
|
||||
Bundle-Description: An Msn implementation of the Protocol Provider Service.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
javax.net.ssl,
|
||||
javax.swing,
|
||||
javax.xml.parsers,
|
||||
javax.naming,
|
||||
javax.naming.directory,
|
||||
org.xml.sax,
|
||||
sun.security.action,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.msnconstants,
|
||||
net.java.sip.communicator.service.protocol.event
|
||||
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The <tt>FirstWizardPage</tt> is the page, where user could enter the uin
|
||||
* and the password of the account.
|
||||
*
|
||||
* @author Yana Stamcheva
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class FirstWizardPage extends JPanel
|
||||
implements WizardPage, DocumentListener {
|
||||
|
||||
public static final String FIRST_PAGE_IDENTIFIER = "FirstPageIdentifier";
|
||||
|
||||
private JPanel uinPassPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
private JPanel labelsPanel = new JPanel(new GridLayout(0, 1, 10, 10));
|
||||
|
||||
private JPanel valuesPanel = new JPanel(new GridLayout(0, 1, 10, 10));
|
||||
|
||||
private JLabel uinLabel = new JLabel(Resources.getString("uin"));
|
||||
|
||||
private JLabel passLabel = new JLabel(Resources.getString("password"));
|
||||
|
||||
private JTextField uinField = new JTextField();
|
||||
|
||||
private JPasswordField passField = new JPasswordField();
|
||||
|
||||
private JCheckBox rememberPassBox = new JCheckBox(
|
||||
Resources.getString("rememberPassword"));
|
||||
|
||||
private JPanel mainPanel = new JPanel();
|
||||
|
||||
private MsnAccountRegistration registration;
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>FirstWizardPage</tt>.
|
||||
* @param registration the <tt>MsnAccountRegistration</tt>, where
|
||||
* all data through the wizard are stored
|
||||
* @param wizardContainer the wizardContainer, where this page will
|
||||
* be added
|
||||
*/
|
||||
public FirstWizardPage(MsnAccountRegistration registration,
|
||||
WizardContainer wizardContainer) {
|
||||
|
||||
super(new BorderLayout());
|
||||
|
||||
this.wizardContainer = wizardContainer;
|
||||
|
||||
this.registration = registration;
|
||||
|
||||
this.setPreferredSize(new Dimension(300, 150));
|
||||
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
this.init();
|
||||
|
||||
this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all panels, buttons, etc.
|
||||
*/
|
||||
private void init() {
|
||||
this.uinField.getDocument().addDocumentListener(this);
|
||||
this.rememberPassBox.setSelected(true);
|
||||
|
||||
labelsPanel.add(uinLabel);
|
||||
labelsPanel.add(passLabel);
|
||||
|
||||
valuesPanel.add(uinField);
|
||||
valuesPanel.add(passField);
|
||||
|
||||
uinPassPanel.add(labelsPanel, BorderLayout.WEST);
|
||||
uinPassPanel.add(valuesPanel, BorderLayout.CENTER);
|
||||
uinPassPanel.add(rememberPassBox, BorderLayout.SOUTH);
|
||||
|
||||
uinPassPanel.setBorder(BorderFactory
|
||||
.createTitledBorder(Resources.getString("uinAndPassword")));
|
||||
|
||||
mainPanel.add(uinPassPanel);
|
||||
this.add(mainPanel, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getIdentifier</code> to return
|
||||
* this page identifier.
|
||||
*/
|
||||
public Object getIdentifier() {
|
||||
return FIRST_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getNextPageIdentifier</code> to return
|
||||
* the next page identifier - the summary page.
|
||||
*/
|
||||
public Object getNextPageIdentifier() {
|
||||
return WizardPage.SUMMARY_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getBackPageIdentifier</code> to return
|
||||
* the next back identifier - the default page.
|
||||
*/
|
||||
public Object getBackPageIdentifier() {
|
||||
return WizardPage.DEFAULT_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getWizardForm</code> to return
|
||||
* this panel.
|
||||
*/
|
||||
public Object getWizardForm() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before this page is displayed enables or disables the "Next" wizard
|
||||
* button according to whether the UIN field is empty.
|
||||
*/
|
||||
public void pageShowing() {
|
||||
this.setNextButtonAccordingToUIN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the user input when the "Next" wizard buttons is clicked.
|
||||
*/
|
||||
public void pageNext() {
|
||||
registration.setUin(uinField.getText());
|
||||
registration.setPassword(new String(passField.getPassword()));
|
||||
registration.setRememberPassword(rememberPassBox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the "Next" wizard button according to whether the
|
||||
* UIN field is empty.
|
||||
*/
|
||||
private void setNextButtonAccordingToUIN() {
|
||||
if (uinField.getText() == null || uinField.getText().equals("")) {
|
||||
wizardContainer.setNextFinishButtonEnabled(false);
|
||||
}
|
||||
else {
|
||||
wizardContainer.setNextFinishButtonEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user types in the
|
||||
* UIN field. Enables or disables the "Next" wizard button according to
|
||||
* whether the UIN field is empty.
|
||||
*/
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
this.setNextButtonAccordingToUIN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user deletes letters
|
||||
* from the UIN field. Enables or disables the "Next" wizard button
|
||||
* according to whether the UIN field is empty.
|
||||
*/
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
this.setNextButtonAccordingToUIN();
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
}
|
||||
|
||||
public void pageHiding() {
|
||||
}
|
||||
|
||||
public void pageShown() {
|
||||
}
|
||||
|
||||
public void pageBack() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the UIN and Password fields in this panel with the data comming
|
||||
* from the given protocolProvider.
|
||||
* @param protocolProvider The <tt>ProtocolProviderService</tt> to load the
|
||||
* data from.
|
||||
*/
|
||||
public void loadAccount(ProtocolProviderService protocolProvider) {
|
||||
AccountID accountID = protocolProvider.getAccountID();
|
||||
String password = (String)accountID.getAccountProperties()
|
||||
.get(ProtocolProviderFactory.PASSWORD);
|
||||
|
||||
this.uinField.setText(accountID.getUserID());
|
||||
|
||||
if(password != null) {
|
||||
this.passField.setText(password);
|
||||
this.rememberPassBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Registers the <tt>MsnAccountRegistrationWizard</tt> in the UI Service.
|
||||
*
|
||||
* @author Yana Stamcheva
|
||||
*/
|
||||
public class MsnAccRegWizzActivator implements BundleActivator {
|
||||
|
||||
public static BundleContext bundleContext;
|
||||
|
||||
private static Logger logger = Logger.getLogger(
|
||||
MsnAccRegWizzActivator.class.getName());
|
||||
|
||||
private static ConfigurationService configService;
|
||||
|
||||
/**
|
||||
* Starts this bundle.
|
||||
* @param bc BundleContext
|
||||
* @throws Exception
|
||||
*/
|
||||
public void start(BundleContext bc) throws Exception {
|
||||
|
||||
bundleContext = bc;
|
||||
|
||||
ServiceReference uiServiceRef = bundleContext
|
||||
.getServiceReference(UIService.class.getName());
|
||||
|
||||
UIService uiService
|
||||
= (UIService) bundleContext.getService(uiServiceRef);
|
||||
|
||||
AccountRegistrationWizardContainer wizardContainer
|
||||
= uiService.getAccountRegWizardContainer();
|
||||
|
||||
MsnAccountRegistrationWizard msnWizard
|
||||
= new MsnAccountRegistrationWizard(wizardContainer);
|
||||
|
||||
wizardContainer.addAccountRegistrationWizard(msnWizard);
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>ProtocolProviderFactory</tt> for the Msn protocol.
|
||||
* @return the <tt>ProtocolProviderFactory</tt> for the Msn protocol
|
||||
*/
|
||||
public static ProtocolProviderFactory getMsnProtocolProviderFactory() {
|
||||
|
||||
ServiceReference[] serRefs = null;
|
||||
|
||||
String osgiFilter = "("
|
||||
+ ProtocolProviderFactory.PROTOCOL
|
||||
+ "="+ProtocolNames.MSN+")";
|
||||
|
||||
try {
|
||||
serRefs = bundleContext.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(), osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex){
|
||||
logger.error("MsnAccRegWizzActivator : " + ex);
|
||||
}
|
||||
|
||||
return (ProtocolProviderFactory) bundleContext.getService(serRefs[0]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
/**
|
||||
* The <tt>MsnAccountRegistration</tt> is used to store all user input data
|
||||
* through the <tt>MsnAccountRegistrationWizard</tt>.
|
||||
*
|
||||
* @author Yana Stamcheva
|
||||
*/
|
||||
public class MsnAccountRegistration {
|
||||
|
||||
private String uin;
|
||||
|
||||
private String password;
|
||||
|
||||
private boolean rememberPassword;
|
||||
|
||||
/**
|
||||
* Returns the password of the msn registration account.
|
||||
* @return the password of the msn registration account.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password of the msn registration account.
|
||||
* @param password the password of the msn registration account.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if password has to remembered, FALSE otherwise.
|
||||
* @return TRUE if password has to remembered, FALSE otherwise
|
||||
*/
|
||||
public boolean isRememberPassword() {
|
||||
return rememberPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rememberPassword value of this msn account registration.
|
||||
* @param rememberPassword TRUE if password has to remembered, FALSE
|
||||
* otherwise
|
||||
*/
|
||||
public void setRememberPassword(boolean rememberPassword) {
|
||||
this.rememberPassword = rememberPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UIN of the msn registration account.
|
||||
* @return the UIN of the msn registration account.
|
||||
*/
|
||||
public String getUin() {
|
||||
return uin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UIN of the msn registration account.
|
||||
* @param uin the UIN of the msn registration account.
|
||||
*/
|
||||
public void setUin(String uin) {
|
||||
this.uin = uin;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The <tt>MsnAccountRegistrationWizard</tt> is an implementation of the
|
||||
* <tt>AccountRegistrationWizard</tt> for the Msn protocol. It should allow
|
||||
* the user to create and configure a new Msn account.
|
||||
*
|
||||
* @author Yana Stamcheva
|
||||
*/
|
||||
public class MsnAccountRegistrationWizard implements AccountRegistrationWizard {
|
||||
|
||||
private FirstWizardPage firstWizardPage;
|
||||
|
||||
private MsnAccountRegistration registration
|
||||
= new MsnAccountRegistration();
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
private ProtocolProviderService protocolProvider;
|
||||
|
||||
private String propertiesPackage = "net.java.sip.communicator.plugin.msnaccregwizz";
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>MsnAccountRegistrationWizard</tt>.
|
||||
* @param wizardContainer the wizard container, where this wizard
|
||||
* is added
|
||||
*/
|
||||
public MsnAccountRegistrationWizard(WizardContainer wizardContainer) {
|
||||
this.wizardContainer = wizardContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getIcon</code> method.
|
||||
* Returns the icon to be used for this wizard.
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getIcon() {
|
||||
return Resources.getImage(Resources.MSN_LOGO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getProtocolName</code>
|
||||
* method. Returns the protocol name for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolName() {
|
||||
return Resources.getString("protocolName");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getProtocolDescription
|
||||
* </code> method. Returns the description of the protocol for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolDescription() {
|
||||
return Resources.getString("protocolDescription");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of pages contained in this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getPages() {
|
||||
ArrayList pages = new ArrayList();
|
||||
firstWizardPage = new FirstWizardPage(registration, wizardContainer);
|
||||
|
||||
pages.add(firstWizardPage);
|
||||
|
||||
return pages.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of data that user has entered through this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getSummary() {
|
||||
Hashtable summaryTable = new Hashtable();
|
||||
|
||||
summaryTable.put("UIN", registration.getUin());
|
||||
summaryTable.put("Remember password",
|
||||
new Boolean(registration.isRememberPassword()));
|
||||
|
||||
return summaryTable.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the account created through this wizard.
|
||||
* @return ProtocolProviderService
|
||||
*/
|
||||
public ProtocolProviderService finish() {
|
||||
firstWizardPage = null;
|
||||
ProtocolProviderFactory factory
|
||||
= MsnAccRegWizzActivator.getMsnProtocolProviderFactory();
|
||||
|
||||
return this.installAccount(factory,
|
||||
registration.getUin(), registration.getPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an account for the given user and password.
|
||||
* @param providerFactory the ProtocolProviderFactory which will create
|
||||
* the account
|
||||
* @param user the user identifier
|
||||
* @param passwd the password
|
||||
* @return the <tt>ProtocolProviderService</tt> for the new account.
|
||||
*/
|
||||
public ProtocolProviderService installAccount(
|
||||
ProtocolProviderFactory providerFactory,
|
||||
String user,
|
||||
String passwd) {
|
||||
|
||||
Hashtable accountProperties = new Hashtable();
|
||||
|
||||
if(registration.isRememberPassword()) {
|
||||
accountProperties.put(ProtocolProviderFactory.PASSWORD, passwd);
|
||||
}
|
||||
|
||||
if(protocolProvider != null) {
|
||||
providerFactory.uninstallAccount(protocolProvider.getAccountID());
|
||||
this.protocolProvider = null;
|
||||
}
|
||||
|
||||
AccountID accountID = providerFactory.installAccount(
|
||||
user, accountProperties);
|
||||
|
||||
ServiceReference serRef = providerFactory
|
||||
.getProviderForAccount(accountID);
|
||||
|
||||
ProtocolProviderService protocolProvider
|
||||
= (ProtocolProviderService) MsnAccRegWizzActivator.bundleContext
|
||||
.getService(serRef);
|
||||
|
||||
return protocolProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the UIN and Password fields in this panel with the data comming
|
||||
* from the given protocolProvider.
|
||||
* @param protocolProvider The <tt>ProtocolProviderService</tt> to load the
|
||||
* data from.
|
||||
*/
|
||||
public void loadAccount(ProtocolProviderService protocolProvider) {
|
||||
|
||||
this.protocolProvider = protocolProvider;
|
||||
|
||||
this.firstWizardPage.loadAccount(protocolProvider);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.util.*;
|
||||
/**
|
||||
* The Messages class manages the access to the internationalization
|
||||
* properties files.
|
||||
* @author Yana Stamcheva
|
||||
*/
|
||||
public class Resources {
|
||||
|
||||
private static Logger log = Logger.getLogger(Resources.class);
|
||||
|
||||
private static final String BUNDLE_NAME
|
||||
= "net.java.sip.communicator.plugin.msnaccregwizz.resources";
|
||||
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
public static ImageID MSN_LOGO = new ImageID("protocolIcon");
|
||||
|
||||
/**
|
||||
* Returns an internationalized string corresponding to the given key.
|
||||
* @param key The key of the string.
|
||||
* @return An internationalized string corresponding to the given key.
|
||||
*/
|
||||
public static String getString(String key) {
|
||||
try {
|
||||
return RESOURCE_BUNDLE.getString(key);
|
||||
|
||||
} catch (MissingResourceException e) {
|
||||
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image from a given image identifier.
|
||||
* @param imageID The identifier of the image.
|
||||
* @return The image for the given identifier.
|
||||
*/
|
||||
public static byte[] getImage(ImageID imageID) {
|
||||
byte[] image = new byte[100000];
|
||||
|
||||
String path = Resources.getString(imageID.getId());
|
||||
try {
|
||||
Resources.class.getClassLoader()
|
||||
.getResourceAsStream(path).read(image);
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to load image:" + path, e);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the Image Identifier.
|
||||
*/
|
||||
public static class ImageID {
|
||||
private String id;
|
||||
|
||||
private ImageID(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.msnaccregwizz;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
|
||||
public class SecondWizardPage extends JPanel
|
||||
implements WizardPage {
|
||||
|
||||
public static final String SECOND_PAGE_IDENTIFIER = "SecondPageIdentifier";
|
||||
|
||||
public Object getIdentifier() {
|
||||
return SECOND_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
public Object getNextPageIdentifier() {
|
||||
return FINISH_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
public Object getBackPageIdentifier() {
|
||||
return FirstWizardPage.FIRST_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
public Object getWizardForm() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void pageHiding() {
|
||||
}
|
||||
|
||||
public void pageShown() {
|
||||
}
|
||||
|
||||
public void pageShowing() {
|
||||
}
|
||||
|
||||
public void pageNext() {
|
||||
}
|
||||
|
||||
public void pageBack() {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
Bundle-Activator: net.java.sip.communicator.plugin.msnaccregwizz.MsnAccRegWizzActivator
|
||||
Bundle-Name: Msn account registration wizard
|
||||
Bundle-Description: Msn account registration wizard.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.icqconstants,
|
||||
net.java.sip.communicator.service.protocol.event,
|
||||
net.java.sip.communicator.service.contactlist,
|
||||
net.java.sip.communicator.service.contactlist.event,
|
||||
net.java.sip.communicator.service.gui,
|
||||
net.java.sip.communicator.service.gui.event,
|
||||
javax.swing,
|
||||
javax.swing.event,
|
||||
javax.swing.table,
|
||||
javax.swing.text,
|
||||
javax.swing.text.html,
|
||||
javax.accessibility,
|
||||
javax.swing.plaf,
|
||||
javax.swing.plaf.metal,
|
||||
javax.swing.plaf.basic,
|
||||
javax.imageio,
|
||||
javax.swing.filechooser,
|
||||
javax.swing.tree,
|
||||
javax.swing.undo,
|
||||
javax.swing.event,
|
||||
javax.swing.border
|
||||
@ -0,0 +1,31 @@
|
||||
Bundle-Activator: net.java.sip.communicator.plugin.msnaccregwizz.MsnAccRegWizzActivator
|
||||
Bundle-Name: Msn account registration wizard
|
||||
Bundle-Description: Msn account registration wizard.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.icqconstants,
|
||||
net.java.sip.communicator.service.protocol.event,
|
||||
net.java.sip.communicator.service.contactlist,
|
||||
net.java.sip.communicator.service.contactlist.event,
|
||||
net.java.sip.communicator.service.gui,
|
||||
net.java.sip.communicator.service.gui.event,
|
||||
javax.swing,
|
||||
javax.swing.event,
|
||||
javax.swing.table,
|
||||
javax.swing.text,
|
||||
javax.swing.text.html,
|
||||
javax.accessibility,
|
||||
javax.swing.plaf,
|
||||
javax.swing.plaf.metal,
|
||||
javax.swing.plaf.basic,
|
||||
javax.imageio,
|
||||
javax.swing.filechooser,
|
||||
javax.swing.tree,
|
||||
javax.swing.undo,
|
||||
javax.swing.event,
|
||||
javax.swing.border
|
||||
@ -0,0 +1,8 @@
|
||||
protocolName=MSN
|
||||
protocolDescription=The Msn service protocol
|
||||
uin=Email:
|
||||
password=Password:
|
||||
rememberPassword=Remember password
|
||||
uinAndPassword=ID and Password
|
||||
|
||||
protocolIcon=net/java/sip/communicator/plugin/msnaccregwizz/resources/msn.gif
|
||||
@ -0,0 +1,8 @@
|
||||
protocolName=Msn
|
||||
protocolDescription=The Msn service protocol
|
||||
uin=Email:
|
||||
password=Password:
|
||||
rememberPassword=Remember password
|
||||
uinAndPassword=ID and Password
|
||||
|
||||
protocolIcon=net/java/sip/communicator/plugin/msnaccregwizz/resources/msn.gif
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.service.protocol.msnconstants;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* An enumeration containing all status instances that MUST be supported by
|
||||
* an implementation of the msn protocol. Implementations may
|
||||
* support other forms of PresenceStatus but they MUST ALL support those
|
||||
* enumerated here.
|
||||
* <p>
|
||||
* For testing purposes, this class also provides a <tt>List</tt> containing
|
||||
* all of the status fields.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MsnStatusEnum
|
||||
extends PresenceStatus
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(MsnStatusEnum.class);
|
||||
|
||||
/**
|
||||
* The Online status. Indicate that the user is able and willing to
|
||||
* communicate.
|
||||
*/
|
||||
public static final MsnStatusEnum ONLINE
|
||||
= new MsnStatusEnum(65, "Online",
|
||||
loadIcon("resources/images/msn/msn16x16-online.png"));
|
||||
|
||||
/**
|
||||
* The Idle status. Indicates that the user is not using the messanger.
|
||||
*/
|
||||
public static final MsnStatusEnum IDLE
|
||||
= new MsnStatusEnum(55, "Idle",
|
||||
loadIcon("resources/images/msn/msn16x16-na.png"));
|
||||
|
||||
/**
|
||||
* The Invisible status. Indicates that the user has connectivity even
|
||||
* though it may appear otherwise to others, to whom she would appear to be
|
||||
* offline.
|
||||
*/
|
||||
public static final MsnStatusEnum HIDE
|
||||
= new MsnStatusEnum(45, "Hide",
|
||||
loadIcon("resources/images/msn/msn16x16-invisible.png"));
|
||||
|
||||
/**
|
||||
* The Away status. Indicates that the user has connectivity but might
|
||||
* not be able to immediately act upon initiation of communication.
|
||||
*/
|
||||
public static final MsnStatusEnum AWAY
|
||||
= new MsnStatusEnum(40, "Away",
|
||||
loadIcon("resources/images/msn/msn16x16-away.png"));
|
||||
|
||||
/**
|
||||
* The Out to lunch status. Indicates that the user is eating.
|
||||
*/
|
||||
public static final MsnStatusEnum OUT_TO_LUNCH
|
||||
= new MsnStatusEnum(39, "Out to lunch",
|
||||
loadIcon("resources/images/msn/msn16x16-lunch.png"));
|
||||
|
||||
/**
|
||||
* The On the phone status. Indicates that the user is talking to the phone.
|
||||
*/
|
||||
public static final MsnStatusEnum ON_THE_PHONE
|
||||
= new MsnStatusEnum(37, "On the phone",
|
||||
loadIcon("resources/images/msn/msn16x16-phone.png"));
|
||||
|
||||
/**
|
||||
* The Not Available status. Indicates that the user has connectivity
|
||||
* but might not be able to immediately act (i.e. even less immediately than
|
||||
* when in an Away status ;-P ) upon initiation of communication.
|
||||
*
|
||||
*/
|
||||
public static final MsnStatusEnum BE_RIGHT_BACK
|
||||
= new MsnStatusEnum(35, "Be Right Back",
|
||||
loadIcon("resources/images/msn/msn16x16-brb.png"));
|
||||
|
||||
/**
|
||||
* The DND status. Indicates that the user has connectivity but prefers
|
||||
* not to be contacted.
|
||||
*/
|
||||
public static final MsnStatusEnum BUSY
|
||||
= new MsnStatusEnum(30, "Busy",
|
||||
loadIcon("resources/images/msn/msn16x16-busy.png"));
|
||||
|
||||
/**
|
||||
* The Offline status. Indicates the user does not seem to be connected
|
||||
* to the network or at least does not want us to know she is
|
||||
*/
|
||||
public static final MsnStatusEnum OFFLINE
|
||||
= new MsnStatusEnum(0, "Offline",
|
||||
loadIcon("resources/images/msn/msn16x16-offline.png"));
|
||||
|
||||
/**
|
||||
* The minimal set of states that any implementation must support.
|
||||
*/
|
||||
public static final ArrayList msnStatusSet =new ArrayList();
|
||||
static{
|
||||
msnStatusSet.add(OUT_TO_LUNCH);
|
||||
msnStatusSet.add(ON_THE_PHONE);
|
||||
msnStatusSet.add(ONLINE);
|
||||
msnStatusSet.add(OFFLINE);
|
||||
msnStatusSet.add(IDLE);
|
||||
msnStatusSet.add(HIDE);
|
||||
msnStatusSet.add(BUSY);
|
||||
msnStatusSet.add(BE_RIGHT_BACK);
|
||||
msnStatusSet.add(AWAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a status with the specified connectivity coeff, name and icon.
|
||||
* @param status the connectivity coefficient for the specified status
|
||||
* @param statusName String
|
||||
* @param statusIcon the icon associated with this status
|
||||
*/
|
||||
protected MsnStatusEnum(int status, String statusName, byte[] statusIcon)
|
||||
{
|
||||
super(status, statusName, statusIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image from a given image path.
|
||||
* @param imagePath The identifier of the image.
|
||||
* @return The image for the given identifier.
|
||||
*/
|
||||
public static byte[] loadIcon(String imagePath) {
|
||||
InputStream is = MsnStatusEnum.class.getClassLoader()
|
||||
.getResourceAsStream(imagePath);
|
||||
logger.info("loadIcon " + imagePath);
|
||||
byte[] icon = null;
|
||||
try {
|
||||
icon = new byte[is.available()];
|
||||
is.read(icon);
|
||||
} catch (IOException exc) {
|
||||
logger.error("Failed to load icon: " + imagePath, exc);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
|
||||
/**
|
||||
* Msn specific testing for a Msn Protocol Provider Service implementation.
|
||||
* The test suite registers two accounts for
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MsnProtocolProviderServiceLick
|
||||
extends TestSuite
|
||||
implements BundleActivator
|
||||
{
|
||||
/**
|
||||
* The prefix used for property names containing settings for our first
|
||||
* testing account.
|
||||
*/
|
||||
public static final String ACCOUNT_1_PREFIX
|
||||
= "accounts.msn.account1.";
|
||||
|
||||
/**
|
||||
* The prefix used for property names containing settings for our second
|
||||
* testing account.
|
||||
*/
|
||||
public static final String ACCOUNT_2_PREFIX
|
||||
= "accounts.msn.account2.";
|
||||
|
||||
/**
|
||||
* The name of the property that indicates whether the user would like to
|
||||
* only run the offline tests.
|
||||
*/
|
||||
public static final String DISABLE_ONLINE_TESTS_PROPERTY_NAME
|
||||
= "accounts.msn.DISABLE_ONLINE_TESTING";
|
||||
|
||||
/**
|
||||
* The name of the property the value of which is a formatted string that
|
||||
* contains the contact list that.
|
||||
*/
|
||||
public static final String CONTACT_LIST_PROPERTY_NAME
|
||||
= "accounts.msn.CONTACT_LIST";
|
||||
|
||||
/**
|
||||
* Initializes and registers all tests that we'll run as a part of this
|
||||
* slick.
|
||||
*
|
||||
* @param context a currently valid bundle context.
|
||||
*/
|
||||
public void start(BundleContext context)
|
||||
{
|
||||
setName("MsnProtocolProviderSlick");
|
||||
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put("service.pid", getName());
|
||||
|
||||
MsnSlickFixture.bc = context;
|
||||
|
||||
// verify whether the user wants to avoid online testing
|
||||
String offlineMode = System.getProperty(
|
||||
DISABLE_ONLINE_TESTS_PROPERTY_NAME, null);
|
||||
|
||||
if (offlineMode != null && offlineMode.equalsIgnoreCase("true"))
|
||||
MsnSlickFixture.onlineTestingDisabled = true;
|
||||
|
||||
|
||||
addTestSuite(TestAccountInstallation.class);
|
||||
addTestSuite(TestProtocolProviderServiceMsnImpl.class);
|
||||
|
||||
addTest(TestOperationSetPresence.suite());
|
||||
|
||||
//the following should only be run when we want online testing.
|
||||
if(!MsnSlickFixture.onlineTestingDisabled)
|
||||
{
|
||||
// addTest(TestOperationSetPersistentPresence.suite());
|
||||
//
|
||||
// addTest(TestOperationSetBasicInstantMessaging.suite());
|
||||
//
|
||||
// addTest(TestOperationSetTypingNotifications.suite());
|
||||
}
|
||||
//
|
||||
//
|
||||
addTest(TestAccountUninstallation.suite());
|
||||
addTestSuite(TestAccountUninstallationPersistence.class);
|
||||
|
||||
context.registerService(getClass().getName(), this, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the slick for shutdown.
|
||||
*
|
||||
* @param context a currently valid bundle context.
|
||||
*/
|
||||
public void stop(BundleContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Contains fields and methods used by most or all tests in the msn slick.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MsnSlickFixture
|
||||
extends TestCase
|
||||
{
|
||||
/**
|
||||
* To be set by the slick itself upon activation.
|
||||
*/
|
||||
public static BundleContext bc = null;
|
||||
|
||||
/**
|
||||
* An osgi service reference for the protocol provider corresponding to our
|
||||
* first testing account.
|
||||
*/
|
||||
public ServiceReference provider1ServiceRef = null;
|
||||
|
||||
/**
|
||||
* The protocol provider corresponding to our first testing account.
|
||||
*/
|
||||
public ProtocolProviderService provider1 = null;
|
||||
|
||||
/**
|
||||
* The user ID associated with testing account 1.
|
||||
*/
|
||||
public String userID1 = null;
|
||||
|
||||
/**
|
||||
* An osgi service reference for the protocol provider corresponding to our
|
||||
* second testing account.
|
||||
*/
|
||||
public ServiceReference provider2ServiceRef = null;
|
||||
|
||||
/**
|
||||
* The protocol provider corresponding to our first testing account.
|
||||
*/
|
||||
public ProtocolProviderService provider2 = null;
|
||||
|
||||
/**
|
||||
* The user ID associated with testing account 2.
|
||||
*/
|
||||
public String userID2 = null;
|
||||
|
||||
|
||||
/**
|
||||
* The tested protocol provider factory.
|
||||
*/
|
||||
public ProtocolProviderFactory providerFactory = null;
|
||||
|
||||
/**
|
||||
* A reference to the bundle containing the tested pp implementation. This
|
||||
* reference is set during the accoung uninstallation testing and used during
|
||||
* the account uninstallation persistence testing.
|
||||
*/
|
||||
public static Bundle providerBundle = null;
|
||||
|
||||
/**
|
||||
* Indicates whether the user has requested for onlline tests not to be run.
|
||||
* (e.g. due to lack of network connectivity or ... time constraints ;)).
|
||||
*/
|
||||
public static boolean onlineTestingDisabled = false;
|
||||
|
||||
/**
|
||||
* A Hashtable containing group names mapped against array lists of buddy
|
||||
* screen names. This is a snapshot of the server stored buddy list for
|
||||
* the account that is going to be used by the tested implementation.
|
||||
* It is filled in by the tester agent who'd login with that account
|
||||
* and initialise the ss contact list before the tested implementation has
|
||||
* actually done so.
|
||||
*/
|
||||
public static Hashtable preInstalledBuddyList = null;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes protocol provider references and whatever else there is to
|
||||
* initialize.
|
||||
*
|
||||
* @throws java.lang.Exception in case we meet problems while retriving
|
||||
* protocol providers through OSGI
|
||||
*/
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
// first obtain a reference to the provider factory
|
||||
ServiceReference[] serRefs = null;
|
||||
String osgiFilter = "(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "="+ProtocolNames.MSN+")";
|
||||
try{
|
||||
serRefs = bc.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(), osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex){
|
||||
//this really shouldhn't occur as the filter expression is static.
|
||||
fail(osgiFilter + " is not a valid osgi filter");
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
"Failed to find a provider factory service for protocol msn",
|
||||
serRefs != null || serRefs.length > 0);
|
||||
|
||||
//Keep the reference for later usage.
|
||||
providerFactory = (ProtocolProviderFactory)bc.getService(serRefs[0]);
|
||||
|
||||
userID1 =
|
||||
System.getProperty(
|
||||
MsnProtocolProviderServiceLick.ACCOUNT_1_PREFIX
|
||||
+ ProtocolProviderFactory.USER_ID);
|
||||
|
||||
userID2 =
|
||||
System.getProperty(
|
||||
MsnProtocolProviderServiceLick.ACCOUNT_2_PREFIX
|
||||
+ ProtocolProviderFactory.USER_ID);
|
||||
|
||||
//find the protocol providers exported for the two accounts
|
||||
ServiceReference[] msnProvider1Refs
|
||||
= bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(&"
|
||||
+"("+ProtocolProviderFactory.PROTOCOL+"="+ProtocolNames.MSN+")"
|
||||
+"("+ProtocolProviderFactory.USER_ID+"="
|
||||
+ userID1 +")"
|
||||
+")");
|
||||
|
||||
//make sure we found a service
|
||||
assertNotNull("No Protocol Provider was found for msn account1:"
|
||||
+ userID1
|
||||
, msnProvider1Refs);
|
||||
assertTrue("No Protocol Provider was found for msn account1:"+ userID1,
|
||||
msnProvider1Refs.length > 0);
|
||||
|
||||
ServiceReference[] msnProvider2Refs
|
||||
= bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(&"
|
||||
+"("+ProtocolProviderFactory.PROTOCOL+"="+ProtocolNames.MSN+")"
|
||||
+"("+ProtocolProviderFactory.USER_ID+"="
|
||||
+ userID2 +")"
|
||||
+")");
|
||||
|
||||
//again make sure we found a service.
|
||||
assertNotNull("No Protocol Provider was found for msn account2:"
|
||||
+ userID2
|
||||
, msnProvider2Refs);
|
||||
assertTrue("No Protocol Provider was found for msn account2:"+ userID2,
|
||||
msnProvider2Refs.length > 0);
|
||||
|
||||
//save the service for other tests to use.
|
||||
provider1ServiceRef = msnProvider1Refs[0];
|
||||
provider1 = (ProtocolProviderService)bc.getService(provider1ServiceRef);
|
||||
provider2ServiceRef = msnProvider2Refs[0];
|
||||
provider2 = (ProtocolProviderService)bc.getService(provider2ServiceRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un get service references used in here.
|
||||
*/
|
||||
public void tearDown()
|
||||
{
|
||||
bc.ungetService(provider1ServiceRef);
|
||||
bc.ungetService(provider2ServiceRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle that has registered the protocol provider service
|
||||
* implementation that we're currently testing. The method would go through
|
||||
* all bundles currently installed in the framework and return the first
|
||||
* one that exports the same protocol provider instance as the one we test
|
||||
* in this slick.
|
||||
* @param provider the provider whose bundle we're looking for.
|
||||
* @return the Bundle that has registered the protocol provider service
|
||||
* we're testing in the slick.
|
||||
*/
|
||||
public static Bundle findProtocolProviderBundle(
|
||||
ProtocolProviderService provider)
|
||||
{
|
||||
Bundle[] bundles = bc.getBundles();
|
||||
|
||||
for (int i = 0; i < bundles.length; i++)
|
||||
{
|
||||
ServiceReference[] registeredServices
|
||||
= bundles[i].getRegisteredServices();
|
||||
|
||||
if (registeredServices == null)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < registeredServices.length; j++)
|
||||
{
|
||||
Object service
|
||||
= bc.getService(registeredServices[j]);
|
||||
if (service == provider)
|
||||
return bundles[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearProvidersLists()
|
||||
throws Exception
|
||||
{
|
||||
Map supportedOperationSets1 = provider1.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets1 == null
|
||||
|| supportedOperationSets1.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this msn implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
OperationSetPersistentPresence opSetPersPresence1 =
|
||||
(OperationSetPersistentPresence)supportedOperationSets1.get(
|
||||
OperationSetPersistentPresence.class.getName());
|
||||
|
||||
//if still null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (opSetPersPresence1 == null)
|
||||
throw new NullPointerException(
|
||||
"An implementation of the msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
|
||||
// lets do it once again for the second provider
|
||||
Map supportedOperationSets2 = provider2.getSupportedOperationSets();
|
||||
|
||||
if (supportedOperationSets2 == null
|
||||
|| supportedOperationSets2.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+ "this msn implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
OperationSetPersistentPresence opSetPersPresence2 =
|
||||
(OperationSetPersistentPresence) supportedOperationSets2.get(
|
||||
OperationSetPersistentPresence.class.getName());
|
||||
|
||||
//if still null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (opSetPersPresence2 == null)
|
||||
throw new NullPointerException(
|
||||
"An implementation of the msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
|
||||
ContactGroup rootGroup1 = opSetPersPresence1.getServerStoredContactListRoot();
|
||||
|
||||
// first delete the groups
|
||||
Vector groupsToRemove = new Vector();
|
||||
Iterator iter = rootGroup1.subgroups();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
groupsToRemove.add(iter.next());
|
||||
}
|
||||
|
||||
iter = groupsToRemove.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
ContactGroup item = (ContactGroup) iter.next();
|
||||
opSetPersPresence1.removeServerStoredContactGroup(item);
|
||||
}
|
||||
|
||||
//then delete contacts if any in root list
|
||||
Vector contactsToRemove = new Vector();
|
||||
iter = rootGroup1.contacts();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
contactsToRemove.add(iter.next());
|
||||
}
|
||||
iter = contactsToRemove.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
opSetPersPresence1.unsubscribe((Contact)iter.next());
|
||||
}
|
||||
|
||||
ContactGroup rootGroup2 = opSetPersPresence2.getServerStoredContactListRoot();
|
||||
|
||||
// delete groups
|
||||
groupsToRemove = new Vector();
|
||||
iter = rootGroup2.subgroups();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
groupsToRemove.add(iter.next());
|
||||
}
|
||||
|
||||
iter = groupsToRemove.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
ContactGroup item = (ContactGroup) iter.next();
|
||||
opSetPersPresence2.removeServerStoredContactGroup(item);
|
||||
}
|
||||
|
||||
//then delete contacts if any in root list
|
||||
contactsToRemove = new Vector();
|
||||
iter = rootGroup2.contacts();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
contactsToRemove.add(iter.next());
|
||||
}
|
||||
iter = contactsToRemove.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
opSetPersPresence2.unsubscribe( (Contact) iter.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
public class TestAccountInstallation
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestAccountInstallation.class);
|
||||
|
||||
/**
|
||||
* Creates the test with the specified method name.
|
||||
* @param name the name of the method to execute.
|
||||
*/
|
||||
public TestAccountInstallation(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* JUnit setup method.
|
||||
* @throws Exception in case anything goes wrong.
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* JUnit teardown method.
|
||||
* @throws Exception in case anything goes wrong.
|
||||
*/
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs an account and verifies whether the installation has gone well.
|
||||
*/
|
||||
public void testInstallAccount()
|
||||
{
|
||||
// first obtain a reference to the provider factory
|
||||
ServiceReference[] serRefs = null;
|
||||
String osgiFilter = "(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "="+ProtocolNames.MSN+")";
|
||||
try{
|
||||
serRefs = MsnSlickFixture.bc.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(), osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
//this really shouldhn't occur as the filter expression is static.
|
||||
fail(osgiFilter + " is not a valid osgi filter");
|
||||
}
|
||||
|
||||
assertTrue(
|
||||
"Failed to find a provider factory service for protocol Msn",
|
||||
serRefs != null && serRefs.length > 0);
|
||||
|
||||
//Keep the reference for later usage.
|
||||
ProtocolProviderFactory msnProviderFactory = (ProtocolProviderFactory)
|
||||
MsnSlickFixture.bc.getService(serRefs[0]);
|
||||
|
||||
//make sure the account is empty
|
||||
assertTrue("There was an account registered with the account mananger "
|
||||
+"before we've installed any",
|
||||
msnProviderFactory.getRegisteredAccounts().size() == 0);
|
||||
|
||||
|
||||
//Prepare the properties of the first msn account.
|
||||
|
||||
Hashtable msnAccount1Properties = getAccountProperties(
|
||||
MsnProtocolProviderServiceLick.ACCOUNT_1_PREFIX);
|
||||
Hashtable msnAccount2Properties = getAccountProperties(
|
||||
MsnProtocolProviderServiceLick.ACCOUNT_2_PREFIX);
|
||||
|
||||
//try to install an account with a null account id
|
||||
try{
|
||||
msnProviderFactory.installAccount(
|
||||
null, msnAccount1Properties);
|
||||
fail("installing an account with a null account id must result "
|
||||
+"in a NullPointerException");
|
||||
}catch(NullPointerException exc)
|
||||
{
|
||||
//that's what had to happen
|
||||
}
|
||||
|
||||
//now really install the accounts
|
||||
msnProviderFactory.installAccount(
|
||||
(String)msnAccount1Properties.get(ProtocolProviderFactory.USER_ID)
|
||||
, msnAccount1Properties);
|
||||
msnProviderFactory.installAccount(
|
||||
(String)msnAccount2Properties.get(ProtocolProviderFactory.USER_ID)
|
||||
, msnAccount2Properties);
|
||||
|
||||
|
||||
//try to install one of the accounts one more time and verify that an
|
||||
//excepion is thrown.
|
||||
try{
|
||||
msnProviderFactory.installAccount(
|
||||
(String)msnAccount1Properties.get(ProtocolProviderFactory.USER_ID)
|
||||
, msnAccount1Properties);
|
||||
|
||||
fail("An IllegalStateException must be thrown when trying to "+
|
||||
"install a duplicate account");
|
||||
|
||||
}catch(IllegalStateException exc)
|
||||
{
|
||||
//that's what supposed to happen.
|
||||
}
|
||||
|
||||
//Verify that the provider factory is aware of our installation
|
||||
assertTrue(
|
||||
"The newly installed account was not in the acc man's "
|
||||
+"registered accounts!",
|
||||
msnProviderFactory.getRegisteredAccounts().size() == 2);
|
||||
|
||||
//Verify protocol providers corresponding to the new account have
|
||||
//been properly registered with the osgi framework.
|
||||
|
||||
osgiFilter =
|
||||
"(&("+ProtocolProviderFactory.PROTOCOL +"="+ProtocolNames.MSN+")"
|
||||
+"(" + ProtocolProviderFactory.USER_ID
|
||||
+ "=" + (String)msnAccount1Properties.get(
|
||||
ProtocolProviderFactory.USER_ID)
|
||||
+ "))";
|
||||
|
||||
try
|
||||
{
|
||||
serRefs = MsnSlickFixture.bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
//this really shouldhn't occur as the filter expression is static.
|
||||
fail(osgiFilter + "is not a valid osgi filter");
|
||||
}
|
||||
|
||||
assertTrue("An protocol provider was apparently not installed as "
|
||||
+ "requested."
|
||||
, serRefs != null && serRefs.length > 0);
|
||||
|
||||
Object msnProtocolProvider
|
||||
= MsnSlickFixture.bc.getService(serRefs[0]);
|
||||
|
||||
assertTrue("The installed protocol provider does not implement "
|
||||
+ "the protocol provider service."
|
||||
,msnProtocolProvider instanceof ProtocolProviderService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all properties necessary for the intialization of the account
|
||||
* with <tt>accountPrefix</tt>.
|
||||
* @param accountPrefix the prefix contained by all property names for the
|
||||
* the account we'd like to initialized
|
||||
* @return a Hashtable that can be used when creating the account in a
|
||||
* protocol provider factory.
|
||||
*/
|
||||
private Hashtable getAccountProperties(String accountPrefix)
|
||||
{
|
||||
Hashtable table = new Hashtable();
|
||||
|
||||
String userID = System.getProperty(
|
||||
accountPrefix + ProtocolProviderFactory.USER_ID, null);
|
||||
|
||||
assertNotNull(
|
||||
"The system property named "
|
||||
+ accountPrefix + ProtocolProviderFactory.USER_ID
|
||||
+" has to tontain a valid msn address that could be used during "
|
||||
+"SIP Communicator's tests."
|
||||
, userID);
|
||||
|
||||
table.put(ProtocolProviderFactory.USER_ID, userID);
|
||||
|
||||
String passwd = System.getProperty(
|
||||
accountPrefix + ProtocolProviderFactory.PASSWORD, null );
|
||||
|
||||
assertNotNull(
|
||||
"The system property named "
|
||||
+ accountPrefix + ProtocolProviderFactory.PASSWORD
|
||||
+" has to contain the password corresponding to the account "
|
||||
+ "specified in "
|
||||
+ accountPrefix + ProtocolProviderFactory.USER_ID
|
||||
, passwd);
|
||||
|
||||
table.put(ProtocolProviderFactory.PASSWORD, passwd);
|
||||
|
||||
String serverAddress = System.getProperty(
|
||||
accountPrefix + ProtocolProviderFactory.SERVER_ADDRESS, null);
|
||||
|
||||
// optional
|
||||
if(serverAddress != null)
|
||||
table.put(ProtocolProviderFactory.SERVER_ADDRESS, serverAddress);
|
||||
|
||||
String serverPort = System.getProperty(
|
||||
accountPrefix + ProtocolProviderFactory.SERVER_PORT, null);
|
||||
|
||||
// optional
|
||||
if(serverPort != null)
|
||||
table.put(ProtocolProviderFactory.SERVER_PORT, serverPort);
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether accaounts are uninstalled properly. It is important that
|
||||
* tests from this class be called last since they will install the accounts
|
||||
* that have been used to test the implementations. Apart from uninstallation
|
||||
* tests the class also contains tests that remove and reinstall the protocol
|
||||
* provider bundle in order to verify that accounts are persistent.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class TestAccountUninstallation
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestAccountUninstallation.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
|
||||
/**
|
||||
* Constructs a test instance
|
||||
* @param name The name of the test.
|
||||
*/
|
||||
public TestAccountUninstallation(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* JUnit setup method.
|
||||
* @throws Exception in case anything goes wrong.
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* JUnit teardown method.
|
||||
* @throws Exception in case anything goes wrong.
|
||||
*/
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
fixture.tearDown();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a suite containing tests in this class in the order that we'd
|
||||
* like them executed.
|
||||
* @return a Test suite containing tests in this class in the order that
|
||||
* we'd like them executed.
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
suite.addTest(
|
||||
new TestAccountUninstallation("testInstallationPersistency"));
|
||||
suite.addTest(
|
||||
new TestAccountUninstallation("testUninstallAccount"));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops and removes the tested bundle, verifies that it has unregistered
|
||||
* its provider, then reloads and restarts the bundle and verifies that
|
||||
* the protocol provider is reRegistered in the bundle context.
|
||||
*
|
||||
* @throws java.lang.Exception if an exception occurs during testing.
|
||||
*/
|
||||
public void testInstallationPersistency() throws Exception
|
||||
{
|
||||
Bundle providerBundle
|
||||
= fixture.findProtocolProviderBundle(fixture.provider1);
|
||||
|
||||
//set the global providerBundle reference that we will be using
|
||||
//in the last series of tests (Account uninstallation persistency)
|
||||
MsnSlickFixture.providerBundle = providerBundle;
|
||||
|
||||
assertNotNull("Couldn't find a bundle for the tested provider"
|
||||
, providerBundle);
|
||||
|
||||
providerBundle.stop();
|
||||
|
||||
assertTrue("Couldn't stop the protocol provider bundle. State was "
|
||||
+ providerBundle.getState()
|
||||
, Bundle.ACTIVE != providerBundle.getState()
|
||||
&& Bundle.STOPPING != providerBundle.getState());
|
||||
|
||||
providerBundle.uninstall();
|
||||
|
||||
assertEquals("Couldn't stop the protocol provider bundle."
|
||||
, Bundle.UNINSTALLED, providerBundle.getState());
|
||||
|
||||
//verify that the provider is no longer available
|
||||
ServiceReference[] msnProviderRefs = null;
|
||||
try
|
||||
{
|
||||
msnProviderRefs = fixture.bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(&"
|
||||
+ "(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" +ProtocolNames.MSN + ")"
|
||||
+ "(" + ProtocolProviderFactory.USER_ID
|
||||
+ "="+ fixture.userID1 + ")"
|
||||
+ ")");
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
fail("We apparently got our filter wrong: " + ex.getMessage());
|
||||
}
|
||||
|
||||
//make sure we didn't see a service
|
||||
assertTrue("A Protocol Provider Service was still regged as an osgi service "
|
||||
+"for msn URI:" + fixture.userID1
|
||||
+ "After it was explicitly uninstalled"
|
||||
,msnProviderRefs == null || msnProviderRefs.length == 0);
|
||||
|
||||
//verify that the provider factory knows that we have uninstalled the
|
||||
//provider.
|
||||
assertTrue(
|
||||
"The msn provider factory kept a reference to the provider we just "
|
||||
+"uninstalled (uri="+fixture.userID1+")",
|
||||
fixture.providerFactory.getRegisteredAccounts().isEmpty()
|
||||
&& fixture.providerFactory.getProviderForAccount(
|
||||
fixture.provider1.getAccountID())
|
||||
== null);
|
||||
|
||||
//Now reinstall the bundle
|
||||
providerBundle = fixture.bc.installBundle(providerBundle.getLocation());
|
||||
|
||||
//set the global providerBundle reference that we will be using
|
||||
//in the last series of tests (Account uninstallation persistency)
|
||||
MsnSlickFixture.providerBundle = providerBundle;
|
||||
|
||||
assertEquals("Couldn't re-install protocol provider bundle."
|
||||
, Bundle.INSTALLED, providerBundle.getState());
|
||||
|
||||
providerBundle.start();
|
||||
assertEquals("Couldn't re-start protocol provider bundle."
|
||||
, Bundle.ACTIVE, providerBundle.getState());
|
||||
|
||||
//Make sure that the provider is there again.
|
||||
//verify that the provider is no longer available
|
||||
try
|
||||
{
|
||||
msnProviderRefs = fixture.bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(&"
|
||||
+ "(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" +ProtocolNames.MSN + ")"
|
||||
+ "(" + ProtocolProviderFactory.USER_ID
|
||||
+ "="+ fixture.userID1 + ")"
|
||||
+ ")");
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
fail("We apparently got our filter wrong " + ex.getMessage());
|
||||
}
|
||||
|
||||
//make sure we didn't see a service
|
||||
assertTrue("A Protocol Provider Service was not restored after being"
|
||||
+"reinstalled. msn URI:" + fixture.userID1
|
||||
,msnProviderRefs != null && msnProviderRefs.length > 0);
|
||||
|
||||
ServiceReference[] msnFactoryRefs = null;
|
||||
try
|
||||
{
|
||||
msnFactoryRefs = fixture.bc.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(),
|
||||
"(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" +ProtocolNames.MSN + ")");
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
fail("We apparently got our filter wrong " + ex.getMessage());
|
||||
}
|
||||
|
||||
//we're the ones who've reinstalled the factory so it's our
|
||||
//responsibility to update the fixture.
|
||||
fixture.providerFactory
|
||||
= (ProtocolProviderFactory)fixture.bc.getService(msnFactoryRefs[0]);
|
||||
fixture.provider1
|
||||
= (ProtocolProviderService)fixture.bc.getService(msnProviderRefs[0]);
|
||||
|
||||
|
||||
//verify that the provider is also restored in the provider factory
|
||||
//itself
|
||||
assertTrue(
|
||||
"The msn provider did not restore its own reference to the provider "
|
||||
+"that we just reinstalled (URI="+fixture.userID1+")",
|
||||
!fixture.providerFactory.getRegisteredAccounts().isEmpty()
|
||||
&& fixture.providerFactory.getProviderForAccount(
|
||||
fixture.provider1.getAccountID())
|
||||
!= null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Uinstalls our test account and makes sure it really has been removed.
|
||||
*
|
||||
*/
|
||||
public void testUninstallAccount()
|
||||
{
|
||||
assertFalse("No installed accounts found",
|
||||
fixture.providerFactory.getRegisteredAccounts().isEmpty());
|
||||
|
||||
assertNotNull(
|
||||
"Found no provider corresponding to URI " + fixture.userID1
|
||||
,fixture.providerFactory.getProviderForAccount(
|
||||
fixture.provider1.getAccountID()));
|
||||
|
||||
assertTrue(
|
||||
"Failed to remove a provider corresponding to URI "
|
||||
+ fixture.userID1
|
||||
,fixture.providerFactory.uninstallAccount(
|
||||
fixture.provider1.getAccountID()));
|
||||
assertTrue(
|
||||
"Failed to remove a provider corresponding to URI "
|
||||
+ fixture.userID1
|
||||
,fixture.providerFactory.uninstallAccount(
|
||||
fixture.provider2.getAccountID()));
|
||||
|
||||
//make sure no providers have remained installed.
|
||||
ServiceReference[] msnProviderRefs = null;
|
||||
try
|
||||
{
|
||||
msnProviderRefs = fixture.bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" +ProtocolNames.MSN + ")");
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
fail("We apparently got our filter wrong " + ex.getMessage());
|
||||
}
|
||||
|
||||
//make sure we didn't see a service
|
||||
assertTrue("A Protocol Provider Service was still regged as an osgi "
|
||||
+ "service for msn URI:" + fixture.userID1
|
||||
+ "After it was explicitly uninstalled"
|
||||
,msnProviderRefs == null || msnProviderRefs.length == 0);
|
||||
|
||||
//verify that the provider factory knows that we have uninstalled the
|
||||
//provider.
|
||||
assertTrue(
|
||||
"The msn provider factory kept a reference to the provider we just "
|
||||
+"uninstalled (uri="+fixture.userID1+")",
|
||||
fixture.providerFactory.getRegisteredAccounts().isEmpty()
|
||||
&& fixture.providerFactory.getProviderForAccount(
|
||||
fixture.provider1.getAccountID())
|
||||
== null);
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Contains tests verifying persistence of account uninstallation. In other
|
||||
* words we try to make sure that once uninstalled an account remains
|
||||
* uninstalled.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class TestAccountUninstallationPersistence
|
||||
extends TestCase
|
||||
{
|
||||
/**
|
||||
* Creates a new test instance wrapper around the test with the specified
|
||||
* name.
|
||||
* @param testName the name of the test that we will be executing.
|
||||
*/
|
||||
public TestAccountUninstallationPersistence(String testName)
|
||||
{
|
||||
super(testName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the msn bundle, stops it and uninstalls it and
|
||||
* then reinstalls it in order to make sure that accounts are not reloaded
|
||||
* once removed.
|
||||
*
|
||||
* @throws java.lang.Exception if something goes wrong while manipulating
|
||||
* the bundles.
|
||||
*/
|
||||
public void testAccountUninstallationPersistence()
|
||||
throws Exception
|
||||
{
|
||||
Bundle providerBundle = MsnSlickFixture.providerBundle;
|
||||
|
||||
providerBundle.stop();
|
||||
|
||||
assertTrue("Couldn't stop the protocol provider bundle. State was "
|
||||
+ providerBundle.getState()
|
||||
, Bundle.ACTIVE != providerBundle.getState()
|
||||
&& Bundle.STOPPING != providerBundle.getState());
|
||||
|
||||
providerBundle.uninstall();
|
||||
|
||||
assertEquals("Couldn't stop the protocol provider bundle."
|
||||
, Bundle.UNINSTALLED, providerBundle.getState());
|
||||
|
||||
//Now reinstall the bundle and restart the provider
|
||||
providerBundle
|
||||
= MsnSlickFixture.bc.installBundle(providerBundle.getLocation());
|
||||
|
||||
assertEquals("Couldn't re-install protocol provider bundle."
|
||||
, Bundle.INSTALLED, providerBundle.getState());
|
||||
|
||||
providerBundle.start();
|
||||
assertEquals("Couldn't re-start protocol provider bundle."
|
||||
, Bundle.ACTIVE, providerBundle.getState());
|
||||
|
||||
|
||||
//verify that the provider is not reinstalled
|
||||
ServiceReference[] msnProviderRefs = null;
|
||||
try
|
||||
{
|
||||
msnProviderRefs = MsnSlickFixture.bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
"(" + ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" +ProtocolNames.MSN + ")");
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
fail("We apparently got our filter wrong " + ex.getMessage());
|
||||
}
|
||||
|
||||
//make sure we didn't retrieve a service
|
||||
assertTrue("A msn Protocol Provider Service was still regged as an "
|
||||
+"osgi service after it was explicitly uninstalled"
|
||||
,msnProviderRefs == null || msnProviderRefs.length == 0);
|
||||
|
||||
//and a nasty hack at the end - delete the configuration file so that
|
||||
//we get a fresh start on next run.
|
||||
ServiceReference confReference
|
||||
= MsnSlickFixture.bc.getServiceReference(
|
||||
ConfigurationService.class.getName());
|
||||
ConfigurationService configurationService
|
||||
= (ConfigurationService) MsnSlickFixture.bc.getService(confReference);
|
||||
|
||||
configurationService.purgeStoredConfiguration();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.Message;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Performs testing of the basic instant messaging operation set. Tests include
|
||||
* going over basic functionality such as sending a message from the tested
|
||||
* implementation and asserting reception by the tester agent and vice versa.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class TestOperationSetBasicInstantMessaging
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestOperationSetBasicInstantMessaging.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
|
||||
private OperationSetBasicInstantMessaging opSetBasicIM1 = null;
|
||||
private OperationSetBasicInstantMessaging opSetBasicIM2 = null;
|
||||
|
||||
private OperationSetPresence opSetPresence1 = null;
|
||||
private OperationSetPresence opSetPresence2 = null;
|
||||
|
||||
public TestOperationSetBasicInstantMessaging(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the basic IM operation set.
|
||||
* @throws Exception if this is not a good day.
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
|
||||
Map supportedOperationSets1 =
|
||||
fixture.provider1.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets1 == null
|
||||
|| supportedOperationSets1.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetBasicIM1 =
|
||||
(OperationSetBasicInstantMessaging)supportedOperationSets1.get(
|
||||
OperationSetBasicInstantMessaging.class.getName());
|
||||
|
||||
if (opSetBasicIM1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for basic IM was found");
|
||||
}
|
||||
|
||||
//we also need the presence op set in order to retrieve contacts.
|
||||
opSetPresence1 =
|
||||
(OperationSetPresence)supportedOperationSets1.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null show that we're not happy.
|
||||
if (opSetPresence1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the service must provide an "
|
||||
+ "implementation of at least one of the PresenceOperationSets");
|
||||
}
|
||||
|
||||
Map supportedOperationSets2 =
|
||||
fixture.provider2.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets2 == null
|
||||
|| supportedOperationSets2.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetBasicIM2 =
|
||||
(OperationSetBasicInstantMessaging)supportedOperationSets2.get(
|
||||
OperationSetBasicInstantMessaging.class.getName());
|
||||
|
||||
if (opSetBasicIM2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for basic IM was found");
|
||||
}
|
||||
|
||||
opSetPresence2 =
|
||||
(OperationSetPresence) supportedOperationSets2.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null show that we're not happy.
|
||||
if (opSetPresence2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the service must provide an "
|
||||
+ "implementation of at least one of the PresenceOperationSets");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
|
||||
fixture.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test suite containing tests of this class in a specific order.
|
||||
* We'll first execute tests beginning with the "test" prefix and then go to
|
||||
* ordered tests.We first execture tests for receiving messagese, so that
|
||||
* a volatile contact is created for the sender. we'll then be able to
|
||||
* retrieve this volatile contact and send them a message on our turn.
|
||||
* We need to do things this way as the contact corresponding to the tester
|
||||
* agent has been removed in the previous test and we no longer have it
|
||||
* in our contact list.
|
||||
*
|
||||
* @return Test a testsuite containing all tests to execute.
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
suite.addTest(new TestOperationSetBasicInstantMessaging(
|
||||
"prepareContactList"));
|
||||
|
||||
suite.addTestSuite(TestOperationSetBasicInstantMessaging.class);
|
||||
|
||||
//the following 2 need to be run in the specified order.
|
||||
suite.addTest(new TestOperationSetBasicInstantMessaging(
|
||||
"firstTestReceiveMessage"));
|
||||
suite.addTest(new TestOperationSetBasicInstantMessaging(
|
||||
"thenTestSendMessage"));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the list to be sure that contacts exchanging messages
|
||||
* exists in each other lists
|
||||
* @throws Exception
|
||||
*/
|
||||
public void prepareContactList()
|
||||
throws Exception
|
||||
{
|
||||
fixture.clearProvidersLists();
|
||||
|
||||
Object o = new Object();
|
||||
synchronized(o)
|
||||
{
|
||||
o.wait(2000);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
opSetPresence1.subscribe(fixture.userID2);
|
||||
}
|
||||
catch (OperationFailedException ex)
|
||||
{
|
||||
// the contact already exist its OK
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
opSetPresence2.subscribe(fixture.userID1);
|
||||
}
|
||||
catch (OperationFailedException ex1)
|
||||
{
|
||||
// the contact already exist its OK
|
||||
}
|
||||
|
||||
synchronized(o)
|
||||
{
|
||||
o.wait(2000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an instant message from the tested operation set and assert
|
||||
* reception by the tester agent.
|
||||
*/
|
||||
public void firstTestReceiveMessage()
|
||||
{
|
||||
String body = "This is an IM coming from the tester agent"
|
||||
+ " on " + new Date().toString();
|
||||
|
||||
ImEventCollector evtCollector = new ImEventCollector();
|
||||
|
||||
//add a msg listener and register to the op set and send an instant
|
||||
//msg from the tester agent.
|
||||
opSetBasicIM1.addMessageListener(evtCollector);
|
||||
|
||||
Contact testerAgentContact
|
||||
= opSetPresence2.findContactByID(fixture.userID1);
|
||||
|
||||
logger.debug("Will send message " + body + " to: " + testerAgentContact);
|
||||
|
||||
opSetBasicIM2.sendInstantMessage(testerAgentContact,
|
||||
opSetBasicIM2.createMessage(body));
|
||||
|
||||
evtCollector.waitForEvent(10000);
|
||||
|
||||
opSetBasicIM1.removeMessageListener(evtCollector);
|
||||
|
||||
//assert reception of a message event
|
||||
assertTrue( "No events delivered upon a received message"
|
||||
, evtCollector.collectedEvents.size() > 0);
|
||||
|
||||
//assert event instance of Message Received Evt
|
||||
assertTrue( "Received evt was not an instance of "
|
||||
+ MessageReceivedEvent.class.getName()
|
||||
, evtCollector.collectedEvents.get(0)
|
||||
instanceof MessageReceivedEvent);
|
||||
|
||||
//assert source contact == testAgent.uin
|
||||
MessageReceivedEvent evt
|
||||
= (MessageReceivedEvent)evtCollector.collectedEvents.get(0);
|
||||
assertEquals("message sender "
|
||||
, evt.getSourceContact().getAddress()
|
||||
, fixture.userID2);
|
||||
|
||||
//assert messageBody == body
|
||||
assertEquals("message body", body, evt.getSourceMessage().getContent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an instant message from the tester agent and assert reception by
|
||||
* the tested implementation
|
||||
*/
|
||||
public void thenTestSendMessage()
|
||||
{
|
||||
String body = "This is an IM coming from the tested implementation"
|
||||
+ " on " + new Date().toString();
|
||||
|
||||
//create the message
|
||||
net.java.sip.communicator.service.protocol.Message msg
|
||||
= opSetBasicIM1.createMessage(body);
|
||||
|
||||
//register a listener in the op set
|
||||
ImEventCollector imEvtCollector1 = new ImEventCollector();
|
||||
opSetBasicIM1.addMessageListener(imEvtCollector1);
|
||||
|
||||
//register a listener in the tester agent
|
||||
ImEventCollector imEvtCollector2 = new ImEventCollector();
|
||||
opSetBasicIM2.addMessageListener(imEvtCollector2);
|
||||
|
||||
Contact testerAgentContact
|
||||
= opSetPresence1.findContactByID(fixture.userID2);
|
||||
|
||||
opSetBasicIM1.sendInstantMessage(testerAgentContact, msg);
|
||||
|
||||
imEvtCollector1.waitForEvent(10000);
|
||||
imEvtCollector2.waitForEvent(10000);
|
||||
|
||||
opSetBasicIM1.removeMessageListener(imEvtCollector1);
|
||||
opSetBasicIM2.removeMessageListener(imEvtCollector2);
|
||||
|
||||
//verify that the message delivered event was dispatched
|
||||
assertTrue( "No events delivered when sending a message"
|
||||
, imEvtCollector1.collectedEvents.size() > 0);
|
||||
|
||||
assertTrue( "Received evt was not an instance of "
|
||||
+ MessageDeliveredEvent.class.getName()
|
||||
, imEvtCollector1.collectedEvents.get(0)
|
||||
instanceof MessageDeliveredEvent);
|
||||
|
||||
MessageDeliveredEvent evt
|
||||
= (MessageDeliveredEvent)imEvtCollector1.collectedEvents.get(0);
|
||||
assertEquals("message destination "
|
||||
, evt.getDestinationContact().getAddress()
|
||||
, fixture.userID2);
|
||||
|
||||
assertSame("source message", msg, evt.getSourceMessage());
|
||||
|
||||
|
||||
//verify that the message has successfully arived at the destination
|
||||
assertTrue( "No messages received by the tester agent"
|
||||
, imEvtCollector2.collectedEvents.size() > 0);
|
||||
String receivedBody =
|
||||
((MessageReceivedEvent)imEvtCollector2.collectedEvents
|
||||
.get(0)).getSourceMessage().getContent();
|
||||
|
||||
assertEquals("received message body", msg.getContent(), receivedBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Message through the simple createMessage() method and inspects
|
||||
* its parameters.
|
||||
*/
|
||||
public void testCreateMessage1()
|
||||
{
|
||||
String body = "This is an IM coming from the tested implementation"
|
||||
+ " on " + new Date().toString();
|
||||
net.java.sip.communicator.service.protocol.Message msg
|
||||
= opSetBasicIM1.createMessage(body);
|
||||
|
||||
assertEquals("message body", body, msg.getContent());
|
||||
assertTrue("message body bytes"
|
||||
, Arrays.equals(body.getBytes(), msg.getRawData()));
|
||||
assertEquals("message length", body.length(), msg.getSize());
|
||||
assertEquals("message content type"
|
||||
, OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE
|
||||
, msg.getContentType());
|
||||
|
||||
assertEquals("message encoding"
|
||||
, OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING
|
||||
, msg.getEncoding());
|
||||
|
||||
assertNotNull("message uid", msg.getMessageUID());
|
||||
|
||||
//a further test on message uid.
|
||||
net.java.sip.communicator.service.protocol.Message msg2
|
||||
= opSetBasicIM1.createMessage(body);
|
||||
assertFalse("message uid", msg.getMessageUID().equals(
|
||||
msg2.getMessageUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Message through the advance createMessage() method and
|
||||
* inspects its parameters.
|
||||
*/
|
||||
public void testCreateMessage2()
|
||||
{
|
||||
String body = "This is an IM coming from the tested implementation"
|
||||
+ " on " + new Date().toString();
|
||||
String contentType = "text/html";
|
||||
String encoding = "UTF-16";
|
||||
String subject = "test message";
|
||||
net.java.sip.communicator.service.protocol.Message msg
|
||||
= opSetBasicIM1.createMessage(
|
||||
body.getBytes(), contentType, encoding, subject);
|
||||
|
||||
assertEquals("message body", body, msg.getContent());
|
||||
assertTrue("message body bytes"
|
||||
, Arrays.equals(body.getBytes(), msg.getRawData()));
|
||||
assertEquals("message length", body.length(), msg.getSize());
|
||||
assertEquals("message content type", contentType, msg.getContentType());
|
||||
assertEquals("message encoding", encoding, msg.getEncoding());
|
||||
assertNotNull("message uid", msg.getMessageUID());
|
||||
|
||||
//a further test on message uid.
|
||||
net.java.sip.communicator.service.protocol.Message msg2
|
||||
= opSetBasicIM1.createMessage(body);
|
||||
assertFalse("message uid", msg.getMessageUID().equals(
|
||||
msg2.getMessageUID()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects instant messaging events.
|
||||
*/
|
||||
private class ImEventCollector implements MessageListener
|
||||
{
|
||||
private List collectedEvents = new LinkedList();
|
||||
/**
|
||||
* Called when a new incoming <tt>Message</tt> has been received.
|
||||
* @param evt the <tt>MessageReceivedEvent</tt> containing the newly
|
||||
* received message, its sender and other details.
|
||||
*/
|
||||
public void messageReceived(MessageReceivedEvent evt)
|
||||
{
|
||||
logger.debug("Received a MessageReceivedEvent: " + evt);
|
||||
|
||||
synchronized(this)
|
||||
{
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to indicated that delivery of a message sent earlier has failed.
|
||||
* Reason code and phrase are contained by the <tt>MessageFailedEvent</tt>
|
||||
* @param evt the <tt>MessageFailedEvent</tt> containing the ID of the
|
||||
* message whose delivery has failed.
|
||||
*/
|
||||
public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
|
||||
{
|
||||
logger.debug("Received a MessageDeliveryFailedEvent: " + evt);
|
||||
|
||||
synchronized(this)
|
||||
{
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the underlying implementation has received an indication
|
||||
* that a message, sent earlier has been successfully received by the
|
||||
* destination.
|
||||
* @param evt the MessageDeliveredEvent containing the id of the message
|
||||
* that has caused the event.
|
||||
*/
|
||||
public void messageDelivered(MessageDeliveredEvent evt)
|
||||
{
|
||||
logger.debug("Received a MessageDeliveredEvent: " + evt);
|
||||
|
||||
synchronized(this)
|
||||
{
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whichever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
|
||||
if(collectedEvents.size() > 0)
|
||||
return;
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a message evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method that would simply send messages to a group of people so that
|
||||
* they would get notified that tests are being run.
|
||||
*/
|
||||
public void testSendFunMessages()
|
||||
{
|
||||
String hostname = "";
|
||||
|
||||
try{
|
||||
hostname = java.net.InetAddress.getLocalHost().getHostName() + ": ";
|
||||
}catch (UnknownHostException ex){}
|
||||
|
||||
String message = hostname
|
||||
+ "Hello this is the SIP Communicator build on: "
|
||||
+ new Date().toString()
|
||||
+ ". Have a very nice day!";
|
||||
|
||||
String list = System.getProperty("accounts.reporting.MSN_REPORT_LIST");
|
||||
|
||||
logger.debug("Will send message " + message + " to: " + list);
|
||||
|
||||
//if no property is specified - return
|
||||
if(list == null || list.trim().length() == 0)
|
||||
return;
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(list, " ");
|
||||
|
||||
while(tokenizer.hasMoreTokens())
|
||||
{
|
||||
String contactID = tokenizer.nextToken();
|
||||
Contact contact
|
||||
= opSetPresence2.findContactByID(contactID);
|
||||
|
||||
if(contact == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
opSetPresence2.subscribe(contactID);
|
||||
Object o = new Object();
|
||||
synchronized (o)
|
||||
{
|
||||
o.wait(2000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
contact
|
||||
= opSetPresence2.findContactByID(contactID);
|
||||
|
||||
opSetBasicIM2.sendInstantMessage(contact,
|
||||
opSetBasicIM2.createMessage(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,682 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class TestOperationSetPersistentPresence
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestOperationSetPersistentPresence.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
private OperationSetPersistentPresence opSetPersPresence1 = null;
|
||||
private OperationSetPersistentPresence opSetPersPresence2 = null;
|
||||
private static final String testGroupName = "NewGroup";
|
||||
private static final String testGroupName2 = "Renamed";
|
||||
|
||||
public TestOperationSetPersistentPresence(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test suite containing all tests of this class followed by
|
||||
* test methods that we want executed in a specified order.
|
||||
* @return the Test suite to run
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite =
|
||||
new TestSuite();
|
||||
|
||||
//the following 2 need to be run in the specified order.
|
||||
//(postTestRemoveGroup() needs the group created from
|
||||
//postTestCreateGroup() )
|
||||
suite.addTest(
|
||||
new TestOperationSetPersistentPresence("postTestCreateGroup"));
|
||||
|
||||
//rename
|
||||
// suite.addTest( new TestOperationSetPersistentPresence(
|
||||
// "postTestRenameGroup"));
|
||||
|
||||
suite.addTest(
|
||||
new TestOperationSetPersistentPresence("postTestRemoveGroup"));
|
||||
|
||||
// create the contact list
|
||||
suite.addTest(
|
||||
new TestOperationSetPersistentPresence("prepareContactList"));
|
||||
|
||||
suite.addTestSuite(TestOperationSetPersistentPresence.class);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
|
||||
Map supportedOperationSets1 =
|
||||
fixture.provider1.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets1 == null
|
||||
|| supportedOperationSets1.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this Msn implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetPersPresence1 =
|
||||
(OperationSetPersistentPresence)supportedOperationSets1.get(
|
||||
OperationSetPersistentPresence.class.getName());
|
||||
|
||||
//if still null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (opSetPersPresence1 == null)
|
||||
throw new NullPointerException(
|
||||
"An implementation of the Msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
|
||||
// lets do it once again for the second provider
|
||||
Map supportedOperationSets2 =
|
||||
fixture.provider2.getSupportedOperationSets();
|
||||
|
||||
if (supportedOperationSets2 == null
|
||||
|| supportedOperationSets2.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+ "this Msn implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetPersPresence2 =
|
||||
(OperationSetPersistentPresence) supportedOperationSets2.get(
|
||||
OperationSetPersistentPresence.class.getName());
|
||||
|
||||
//if still null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (opSetPersPresence2 == null)
|
||||
throw new NullPointerException(
|
||||
"An implementation of the msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
fixture.tearDown();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a server stored contact list and checks whether it contains
|
||||
* all contacts that have been added there during the initialization
|
||||
* phase by the testerAgent.
|
||||
*/
|
||||
public void testRetrievingServerStoredContactList()
|
||||
{
|
||||
ContactGroup rootGroup
|
||||
= opSetPersPresence1.getServerStoredContactListRoot();
|
||||
|
||||
logger.debug("=========== Server Stored Contact List =================");
|
||||
|
||||
logger.debug("rootGroup="+rootGroup.getGroupName()
|
||||
+" rootGroup.childContacts="+rootGroup.countContacts()
|
||||
+ "rootGroup.childGroups="+rootGroup.countSubgroups()
|
||||
+ "Printing rootGroupContents=\n"+rootGroup.toString());
|
||||
|
||||
Hashtable expectedContactList = fixture.preInstalledBuddyList;
|
||||
|
||||
logger.debug("============== Expected Contact List ===================");
|
||||
logger.debug(expectedContactList);
|
||||
|
||||
//Go through the contact list retrieved by the persistence presence set
|
||||
//and remove the name of every contact and group that we find there from
|
||||
//the expected contct list hashtable.
|
||||
Iterator groups = rootGroup.subgroups();
|
||||
while (groups.hasNext() )
|
||||
{
|
||||
ContactGroup group = (ContactGroup)groups.next();
|
||||
|
||||
List expectedContactsInGroup
|
||||
= (List)expectedContactList.get(group.getGroupName());
|
||||
|
||||
// When sending the offline message
|
||||
// the sever creates a group NotInContactList,
|
||||
// beacuse the buddy we are sending message to is not in
|
||||
// the contactlist. So this group must be ignored
|
||||
if(!group.getGroupName().equals("NotInContactList"))
|
||||
{
|
||||
assertNotNull("Group " + group.getGroupName() +
|
||||
" was returned by "
|
||||
+
|
||||
"the server but was not in the expected contact list."
|
||||
, expectedContactsInGroup);
|
||||
|
||||
Iterator contactsIter = group.contacts();
|
||||
while(contactsIter.hasNext())
|
||||
{
|
||||
String contactID = ((Contact)contactsIter.next()).
|
||||
getAddress();
|
||||
expectedContactsInGroup.remove(contactID);
|
||||
}
|
||||
|
||||
//If we've removed all the sub contacts, remove the group too.
|
||||
if(expectedContactsInGroup.size() == 0)
|
||||
expectedContactList.remove(group.getGroupName());
|
||||
}
|
||||
}
|
||||
|
||||
//whatever we now have in the expected contact list snapshot are groups,
|
||||
//that have been added by the testerAgent but that were not retrieved
|
||||
//by the persistent presence operation set.
|
||||
assertTrue("The following contacts were on the server sidec contact "
|
||||
+"list, but were not returned by the pers. pres. op. set"
|
||||
+ expectedContactList.toString()
|
||||
, expectedContactList.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a group in the server stored contact list, makes sure that the
|
||||
* corresponding event has been generated and verifies that the group is
|
||||
* in the list.
|
||||
*
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public void postTestCreateGroup()
|
||||
throws Exception
|
||||
{
|
||||
// first clear the list
|
||||
fixture.clearProvidersLists();
|
||||
|
||||
Object o = new Object();
|
||||
synchronized(o)
|
||||
{
|
||||
o.wait(3000);
|
||||
}
|
||||
|
||||
logger.trace("testing creation of server stored groups");
|
||||
//first add a listener
|
||||
GroupChangeCollector groupChangeCollector = new GroupChangeCollector();
|
||||
opSetPersPresence1
|
||||
.addServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
//create the group
|
||||
opSetPersPresence1.createServerStoredContactGroup(
|
||||
opSetPersPresence1.getServerStoredContactListRoot(), testGroupName);
|
||||
|
||||
groupChangeCollector.waitForEvent(10000);
|
||||
|
||||
opSetPersPresence1
|
||||
.removeServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
// check whether we got group created event
|
||||
assertEquals("Collected Group Change events: ",
|
||||
1, groupChangeCollector.collectedEvents.size());
|
||||
|
||||
assertEquals("Group name.", testGroupName,
|
||||
((ServerStoredGroupEvent)groupChangeCollector.collectedEvents
|
||||
.get(0)).getSourceGroup().getGroupName());
|
||||
|
||||
// check whether the group is retrievable
|
||||
ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName);
|
||||
|
||||
assertNotNull("A newly created group was not in the contact list.",
|
||||
group);
|
||||
|
||||
assertEquals("New group name", testGroupName, group.getGroupName());
|
||||
|
||||
// when opearting with groups . the group must have entries
|
||||
// so changes to take effect. Otherwise group will be lost after loggingout
|
||||
try
|
||||
{
|
||||
opSetPersPresence1.subscribe(group, fixture.userID2);
|
||||
|
||||
synchronized(o){o.wait(1500);}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
fail("error adding entry to group : " +
|
||||
group.getGroupName() + " " +
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the group created in the server stored contact list by the create
|
||||
* group test, makes sure that the corresponding event has been generated
|
||||
* and verifies that the group is not in the list any more.
|
||||
*/
|
||||
public void postTestRemoveGroup()
|
||||
{
|
||||
logger.trace("testing removal of server stored groups");
|
||||
|
||||
//first add a listener
|
||||
GroupChangeCollector groupChangeCollector = new GroupChangeCollector();
|
||||
opSetPersPresence1
|
||||
.addServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
//create the group
|
||||
opSetPersPresence1.removeServerStoredContactGroup(
|
||||
opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName2));
|
||||
|
||||
groupChangeCollector.waitForEvent(10000);
|
||||
|
||||
opSetPersPresence1
|
||||
.removeServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
// check whether we got group created event
|
||||
assertEquals("Collected Group Change event",
|
||||
1, groupChangeCollector.collectedEvents.size());
|
||||
|
||||
assertEquals("Group name.", testGroupName2,
|
||||
((ServerStoredGroupEvent)groupChangeCollector.collectedEvents
|
||||
.get(0)).getSourceGroup().getGroupName());
|
||||
|
||||
// check whether the group is still on the contact list
|
||||
ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName2);
|
||||
|
||||
assertNull("A freshly removed group was still on the contact list.",
|
||||
group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames our test group and checks whether corresponding events are
|
||||
* triggered. Verifies whether the group has really changed its name and
|
||||
* whether it is findable by its new name. Also makes sure that it does
|
||||
* not exist under its previous name any more.
|
||||
*/
|
||||
public void postTestRenameGroup()
|
||||
{
|
||||
logger.trace("Testing renaming groups.");
|
||||
|
||||
ContactGroup group = opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName);
|
||||
|
||||
//first add a listener
|
||||
GroupChangeCollector groupChangeCollector = new GroupChangeCollector();
|
||||
opSetPersPresence1
|
||||
.addServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
//change the name and wait for a confirmation event
|
||||
opSetPersPresence1.renameServerStoredContactGroup(group, testGroupName2);
|
||||
|
||||
groupChangeCollector.waitForEvent(10000);
|
||||
|
||||
opSetPersPresence1
|
||||
.removeServerStoredGroupChangeListener(groupChangeCollector);
|
||||
|
||||
//examine the event
|
||||
assertEquals("Collected Group Change event",
|
||||
1, groupChangeCollector.collectedEvents.size());
|
||||
|
||||
assertEquals("Group name.", testGroupName2,
|
||||
((ServerStoredGroupEvent)groupChangeCollector.collectedEvents
|
||||
.get(0)).getSourceGroup().getGroupName());
|
||||
|
||||
// check whether the group is still on the contact list
|
||||
ContactGroup oldGroup = opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName);
|
||||
|
||||
assertNull("A group was still findable by its old name after renaming.",
|
||||
oldGroup);
|
||||
|
||||
//make sure that we could find the group by its new name.
|
||||
ContactGroup newGroup = opSetPersPresence1.getServerStoredContactListRoot()
|
||||
.getGroup(testGroupName2);
|
||||
|
||||
assertNotNull("Could not find a renamed group by its new name.",
|
||||
newGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the contact list. Later will be test to be sure that creating is ok
|
||||
* @throws Exception
|
||||
*/
|
||||
public void prepareContactList()
|
||||
throws Exception
|
||||
{
|
||||
fixture.clearProvidersLists();
|
||||
|
||||
Object o = new Object();
|
||||
synchronized(o)
|
||||
{
|
||||
o.wait(3000);
|
||||
}
|
||||
|
||||
String contactList = System.getProperty(
|
||||
MsnProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME, null);
|
||||
|
||||
logger.debug("The "
|
||||
+ MsnProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME
|
||||
+ " property is set to=" + contactList);
|
||||
|
||||
if( contactList == null
|
||||
|| contactList.trim().length() < 6)//at least 4 for a UIN, 1 for the
|
||||
// dot and 1 for the grp name
|
||||
throw new IllegalArgumentException(
|
||||
"The " +
|
||||
MsnProtocolProviderServiceLick.CONTACT_LIST_PROPERTY_NAME +
|
||||
" property did not contain a contact list.");
|
||||
StringTokenizer tokenizer = new StringTokenizer(contactList, " \n\t");
|
||||
|
||||
logger.debug("tokens contained by the CL tokenized="
|
||||
+tokenizer.countTokens());
|
||||
|
||||
Hashtable contactListToCreate = new Hashtable();
|
||||
|
||||
//go over all group.uin tokens
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String groupUinToken = tokenizer.nextToken();
|
||||
int dotIndex = groupUinToken.indexOf(".");
|
||||
|
||||
if ( dotIndex == -1 )
|
||||
{
|
||||
throw new IllegalArgumentException(groupUinToken
|
||||
+ " is not a valid Group.UIN token");
|
||||
}
|
||||
|
||||
String groupName = groupUinToken.substring(0, dotIndex);
|
||||
String uin = groupUinToken.substring(dotIndex + 1);
|
||||
|
||||
if( groupName.trim().length() < 1
|
||||
|| uin.trim().length() < 4 )
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
groupName + " or " + uin +
|
||||
" are not a valid group name or msn UIN.");
|
||||
}
|
||||
|
||||
//check if we've already seen this group and if not - add it
|
||||
List uinInThisGroup = (List)contactListToCreate.get(groupName);
|
||||
if (uinInThisGroup == null)
|
||||
{
|
||||
uinInThisGroup = new ArrayList();
|
||||
contactListToCreate.put(groupName, uinInThisGroup);
|
||||
}
|
||||
|
||||
uinInThisGroup.add(uin);
|
||||
}
|
||||
|
||||
// now init the list
|
||||
Enumeration newGroupsEnum = contactListToCreate.keys();
|
||||
|
||||
//go over all groups in the contactsToAdd table
|
||||
while (newGroupsEnum.hasMoreElements())
|
||||
{
|
||||
String groupName = (String) newGroupsEnum.nextElement();
|
||||
logger.debug("Will add group " + groupName);
|
||||
|
||||
opSetPersPresence1.createServerStoredContactGroup(
|
||||
opSetPersPresence1.getServerStoredContactListRoot(), groupName);
|
||||
|
||||
ContactGroup newlyCreatedGroup =
|
||||
opSetPersPresence1.getServerStoredContactListRoot().getGroup(groupName);
|
||||
|
||||
Iterator contactsToAddToThisGroup
|
||||
= ( (List) contactListToCreate.get(groupName)).iterator();
|
||||
while (contactsToAddToThisGroup.hasNext())
|
||||
{
|
||||
String id = (String) contactsToAddToThisGroup.next();
|
||||
|
||||
logger.debug("Will add buddy " + id);
|
||||
opSetPersPresence1.subscribe(newlyCreatedGroup, id);
|
||||
}
|
||||
}
|
||||
|
||||
//store the created contact list for later reference
|
||||
MsnSlickFixture.preInstalledBuddyList = contactListToCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The class would listen for and store received events delivered to
|
||||
* <tt>ServerStoredGroupListener</tt>s.
|
||||
*/
|
||||
private class GroupChangeCollector implements ServerStoredGroupListener
|
||||
{
|
||||
public ArrayList collectedEvents = new ArrayList();
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedEvents.size() > 0)
|
||||
return;
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whnever an indication is received that a new server stored
|
||||
* group is created.
|
||||
* @param evt a ServerStoredGroupChangeEvent containing a reference to
|
||||
* the newly created group.
|
||||
*/
|
||||
public void groupCreated(ServerStoredGroupEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an indication is received that the name of a server stored
|
||||
* contact group has changed.
|
||||
* @param evt a ServerStoredGroupChangeEvent containing the details of the
|
||||
* name change.
|
||||
*/
|
||||
public void groupNameChanged(ServerStoredGroupEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whnever an indication is received that an existing server stored
|
||||
* group has been removed.
|
||||
* @param evt a ServerStoredGroupChangeEvent containing a reference to the
|
||||
* newly created group.
|
||||
*/
|
||||
public void groupRemoved(ServerStoredGroupEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whnever an indication is received that an existing server
|
||||
* stored group has been resolved.
|
||||
* @param evt a ServerStoredGroupChangeEvent containing a reference to
|
||||
* the resolved group.
|
||||
*/
|
||||
public void groupResolved(ServerStoredGroupEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class would listen for and store received subscription modification
|
||||
* events.
|
||||
*/
|
||||
private class SubscriptionEventCollector implements SubscriptionListener
|
||||
{
|
||||
public ArrayList collectedEvents = new ArrayList();
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
logger.trace("Waiting for a persistent subscription event");
|
||||
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedEvents.size() > 0)
|
||||
{
|
||||
logger.trace("SubEvt already received. " + collectedEvents);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
if(collectedEvents.size() > 0)
|
||||
logger.trace("Received a SubEvt in provider status.");
|
||||
else
|
||||
logger.trace("No SubEvt received for "+waitFor+"ms.");
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionCreated(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionRemoved(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionFailed(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionResolved(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionMoved(SubscriptionMovedEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void contactModified(ContactPropertyChangeEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,952 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.beans.*;
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.service.protocol.msnconstants.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Tests msn implementations of a Presence Operation Set. Tests in this class
|
||||
* verify functionality such as: Changing local (our own) status and
|
||||
* corresponding event dispatching; Querying status of contacts, Subscribing
|
||||
* for presence notifications upong status changes of specific contacts.
|
||||
* <p>
|
||||
* Using a custom suite() method, we make sure that apart from standard test
|
||||
* methods (those with a <tt>test</tt> prefix) we also execute those that
|
||||
* we want run in a specific order like for example - postTestSubscribe() and
|
||||
* postTestUnsubscribe().
|
||||
* <p>
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class TestOperationSetPresence
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestOperationSetPresence.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
private OperationSetPresence operationSetPresence1 = null;
|
||||
private OperationSetPresence operationSetPresence2 = null;
|
||||
private String statusMessageRoot = new String("Our status is now: ");
|
||||
|
||||
public TestOperationSetPresence(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
|
||||
Map supportedOperationSets1 =
|
||||
fixture.provider1.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets1 == null
|
||||
|| supportedOperationSets1.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
operationSetPresence1 =
|
||||
(OperationSetPresence)supportedOperationSets1.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (operationSetPresence1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
}
|
||||
|
||||
// do it once again for the second provider
|
||||
Map supportedOperationSets2 =
|
||||
fixture.provider2.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets2 == null
|
||||
|| supportedOperationSets2.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this msn implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
operationSetPresence2 =
|
||||
(OperationSetPresence)supportedOperationSets2.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null then the implementation doesn't offer a presence
|
||||
//operation set which is unacceptable for msn.
|
||||
if (operationSetPresence2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the msn service must provide an "
|
||||
+ "implementation of at least the one of the Presence "
|
||||
+ "Operation Sets");
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
|
||||
fixture.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test suite containing all tests of this class followed by
|
||||
* test methods that we want executed in a specified order.
|
||||
* @return Test
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
//return an (almost) empty suite if we're running in offline mode.
|
||||
if(MsnSlickFixture.onlineTestingDisabled)
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
//the only test around here that we could run without net
|
||||
//connectivity
|
||||
suite.addTest(
|
||||
new TestOperationSetPresence(
|
||||
"testSupportedStatusSetForCompleteness"));
|
||||
return suite;
|
||||
}
|
||||
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
// clear the lists before subscribing users
|
||||
suite.addTest(new TestOperationSetPresence("clearLists"));
|
||||
|
||||
// first postTestSubscribe. to be sure that contacts are in the
|
||||
// list so we can further continue and test presences each other
|
||||
suite.addTest(new TestOperationSetPresence("postTestSubscribe"));
|
||||
|
||||
// add other tests
|
||||
suite.addTestSuite(TestOperationSetPresence.class);
|
||||
|
||||
// now test unsubscribe
|
||||
suite.addTest(new TestOperationSetPresence("postTestUnsubscribe"));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that all necessary msn test states are supported by the
|
||||
* implementation.
|
||||
*/
|
||||
public void testSupportedStatusSetForCompleteness()
|
||||
{
|
||||
//first create a local list containing the presence status instances
|
||||
//supported by the underlying implementation.
|
||||
Iterator supportedStatusSetIter =
|
||||
operationSetPresence1.getSupportedStatusSet();
|
||||
|
||||
List supportedStatusSet = new LinkedList();
|
||||
while (supportedStatusSetIter.hasNext()){
|
||||
supportedStatusSet.add(supportedStatusSetIter.next());
|
||||
}
|
||||
|
||||
//create a copy of the MUST status set and remove any matching status
|
||||
//that is also present in the supported set.
|
||||
List requiredStatusSetCopy = (List)MsnStatusEnum.msnStatusSet.clone();
|
||||
|
||||
requiredStatusSetCopy.removeAll(supportedStatusSet);
|
||||
|
||||
//if we have anything left then the implementation is wrong.
|
||||
int unsupported = requiredStatusSetCopy.size();
|
||||
assertTrue( "There are " + unsupported + " statuses as follows:"
|
||||
+ requiredStatusSetCopy,
|
||||
unsupported == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to AWAY works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToAway() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.AWAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to NOT_AVAILABLE works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToNotAvailable() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.BE_RIGHT_BACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to DND works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToDnd() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.BUSY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to FREE_FOR_CHAT works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToIdle() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to ONLINE works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToOnline() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to OUT_TO_LUNCH works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToOutToLunch() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.OUT_TO_LUNCH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that changing state to ON_THE_PHONE works as supposed to and that it
|
||||
* generates the corresponding event.
|
||||
* @throws Exception in case a failure occurs while the operation set
|
||||
* is switching to the new state.
|
||||
*/
|
||||
public void testChangingStateToOnThePhone() throws Exception
|
||||
{
|
||||
subtestStateTransition(MsnStatusEnum.ON_THE_PHONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by methods testing state transiotions
|
||||
*
|
||||
* @param newStatus the MsnStatusEnum field corresponding to the status
|
||||
* that we'd like the opeation set to enter.
|
||||
*
|
||||
* @throws Exception in case changing the state causes an exception
|
||||
*/
|
||||
public void subtestStateTransition( MsnStatusEnum newStatus)
|
||||
throws Exception
|
||||
{
|
||||
logger.trace(" --=== beginning state transition test ===--");
|
||||
|
||||
PresenceStatus oldStatus = operationSetPresence1.getPresenceStatus();
|
||||
|
||||
logger.debug( "old status is=" + oldStatus.getStatusName()
|
||||
+ " new status=" + newStatus.getStatusName());
|
||||
|
||||
//First register a listener to make sure that all corresponding
|
||||
//events have been generated.
|
||||
PresenceStatusEventCollector statusEventCollector
|
||||
= new PresenceStatusEventCollector();
|
||||
operationSetPresence1.addProviderPresenceStatusListener(
|
||||
statusEventCollector);
|
||||
|
||||
//change the status
|
||||
operationSetPresence1.publishPresenceStatus(newStatus, null);
|
||||
pauseAfterStateChanges();
|
||||
|
||||
//test event notification.
|
||||
statusEventCollector.waitForPresEvent(10000);
|
||||
|
||||
operationSetPresence1.removeProviderPresenceStatusListener(
|
||||
statusEventCollector);
|
||||
|
||||
assertEquals("Events dispatched during an event transition.",
|
||||
1, statusEventCollector.collectedPresEvents.size());
|
||||
assertEquals("A status changed event contained wrong old status.",
|
||||
oldStatus,
|
||||
((ProviderPresenceStatusChangeEvent)
|
||||
statusEventCollector.collectedPresEvents.get(0))
|
||||
.getOldStatus());
|
||||
assertEquals("A status changed event contained wrong new status.",
|
||||
newStatus,
|
||||
((ProviderPresenceStatusChangeEvent)
|
||||
statusEventCollector.collectedPresEvents.get(0))
|
||||
.getNewStatus());
|
||||
|
||||
// verify that the operation set itself is aware of the status change
|
||||
assertEquals("opSet.getPresenceStatus() did not return properly.",
|
||||
newStatus,
|
||||
operationSetPresence1.getPresenceStatus());
|
||||
|
||||
MsnStatusEnum actualStatus = (MsnStatusEnum)
|
||||
operationSetPresence2.queryContactStatus(fixture.userID1);
|
||||
|
||||
assertEquals("The underlying implementation did not switch to the "
|
||||
+"requested presence status.",
|
||||
newStatus,
|
||||
actualStatus);
|
||||
|
||||
logger.trace(" --=== finished test ===--");
|
||||
}
|
||||
|
||||
/**
|
||||
* Give time changes to take effect
|
||||
*/
|
||||
private void pauseAfterStateChanges()
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.currentThread().sleep(1500);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug("Pausing between state changes was interrupted", ex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Verifies that querying status works fine. The tester agent would
|
||||
* change status and the operation set would have to return the right status
|
||||
* after every change.
|
||||
*
|
||||
* @throws java.lang.Exception if one of the transitions fails
|
||||
*/
|
||||
public void testQueryContactStatus()
|
||||
throws Exception
|
||||
{
|
||||
// --- AWAY ---
|
||||
logger.debug("Will Query an AWAY contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.AWAY,
|
||||
MsnStatusEnum.AWAY);
|
||||
|
||||
// --- NA ---
|
||||
logger.debug("Will Query an BRB contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.BE_RIGHT_BACK,
|
||||
MsnStatusEnum.BE_RIGHT_BACK);
|
||||
|
||||
// --- DND ---
|
||||
logger.debug("Will Query a Busy contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.BUSY,
|
||||
MsnStatusEnum.BUSY);
|
||||
|
||||
// --- FFC ---
|
||||
logger.debug("Will Query a Idle contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.IDLE,
|
||||
MsnStatusEnum.IDLE);
|
||||
|
||||
// --- INVISIBLE ---
|
||||
logger.debug("Will Query an Invisible contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.HIDE,
|
||||
MsnStatusEnum.OFFLINE);
|
||||
|
||||
// --- Online ---
|
||||
logger.debug("Will Query an Online contact.");
|
||||
subtestQueryContactStatus(MsnStatusEnum.ONLINE,
|
||||
MsnStatusEnum.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by functions testing the queryContactStatus method of the
|
||||
* presence operation set.
|
||||
* @param status the status as specified, that
|
||||
* the tester agent should switch to.
|
||||
* @param expectedReturn the PresenceStatus that the presence operation
|
||||
* set should see the tester agent in once it has switched to taStatusLong.
|
||||
*
|
||||
* @throws java.lang.Exception if querying the status causes some exception.
|
||||
*/
|
||||
public void subtestQueryContactStatus(PresenceStatus status,
|
||||
PresenceStatus expectedReturn)
|
||||
throws Exception
|
||||
{
|
||||
operationSetPresence2.publishPresenceStatus(status, "status message");
|
||||
|
||||
pauseAfterStateChanges();
|
||||
|
||||
PresenceStatus actualReturn
|
||||
= operationSetPresence1.queryContactStatus(fixture.userID2);
|
||||
assertEquals("Querying a "
|
||||
+ expectedReturn.getStatusName()
|
||||
+ " state did not return as expected"
|
||||
, expectedReturn, actualReturn);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method would add a subscription for a contact, wait for a
|
||||
* subscription event confirming the subscription, then change the status
|
||||
* of the newly added contact (which is actually the testerAgent) and
|
||||
* make sure that the corresponding notification events have been generated.
|
||||
*
|
||||
* @throws java.lang.Exception if an exception occurs during testing.
|
||||
*/
|
||||
public void postTestSubscribe()
|
||||
throws Exception
|
||||
{
|
||||
logger.debug("Testing Subscription and Subscription Event Dispatch.");
|
||||
|
||||
SubscriptionEventCollector subEvtCollector
|
||||
= new SubscriptionEventCollector();
|
||||
operationSetPresence1.addSubsciptionListener(subEvtCollector);
|
||||
|
||||
|
||||
synchronized (subEvtCollector){
|
||||
operationSetPresence1.subscribe(fixture.userID2);
|
||||
//we may already have the event, but it won't hurt to check.
|
||||
subEvtCollector.waitForEvent(10000);
|
||||
operationSetPresence1.removeSubscriptionListener(subEvtCollector);
|
||||
}
|
||||
|
||||
assertEquals("Subscription event dispatching failed."
|
||||
, 1, subEvtCollector.collectedEvents.size());
|
||||
SubscriptionEvent subEvt =
|
||||
(SubscriptionEvent)subEvtCollector.collectedEvents.get(0);
|
||||
|
||||
assertEquals("SubscriptionEvent Source:",
|
||||
fixture.userID2,
|
||||
((Contact)subEvt.getSource()).getAddress());
|
||||
assertEquals("SubscriptionEvent Source Contact:",
|
||||
fixture.userID2,
|
||||
subEvt.getSourceContact().getAddress());
|
||||
assertSame("SubscriptionEvent Source Provider:",
|
||||
fixture.provider1,
|
||||
subEvt.getSourceProvider());
|
||||
|
||||
subEvtCollector.collectedEvents.clear();
|
||||
|
||||
// make the user agent tester change its states and make sure we are
|
||||
// notified
|
||||
logger.debug("Testing presence notifications.");
|
||||
MsnStatusEnum oldStatus
|
||||
= (MsnStatusEnum)operationSetPresence2.getPresenceStatus();
|
||||
|
||||
|
||||
MsnStatusEnum newStatus = MsnStatusEnum.IDLE;
|
||||
|
||||
//in case we are by any chance already in a FREE_FOR_CHAT status, we'll
|
||||
//be changing to something else
|
||||
if(oldStatus.equals(newStatus)){
|
||||
newStatus = MsnStatusEnum.BUSY;
|
||||
}
|
||||
|
||||
//now do the actual status notification testing
|
||||
ContactPresenceEventCollector contactPresEvtCollector
|
||||
= new ContactPresenceEventCollector(
|
||||
fixture.userID2, newStatus);
|
||||
operationSetPresence1.addContactPresenceStatusListener(
|
||||
contactPresEvtCollector);
|
||||
|
||||
synchronized (contactPresEvtCollector){
|
||||
operationSetPresence2.publishPresenceStatus(newStatus, "new status");
|
||||
//we may already have the event, but it won't hurt to check.
|
||||
contactPresEvtCollector.waitForEvent(10000);
|
||||
operationSetPresence1
|
||||
.removeContactPresenceStatusListener(contactPresEvtCollector);
|
||||
}
|
||||
|
||||
assertEquals("Presence Notif. event dispatching failed."
|
||||
, 1, contactPresEvtCollector.collectedEvents.size());
|
||||
ContactPresenceStatusChangeEvent presEvt =
|
||||
(ContactPresenceStatusChangeEvent)
|
||||
contactPresEvtCollector.collectedEvents.get(0);
|
||||
|
||||
assertEquals("Presence Notif. event Source:",
|
||||
fixture.userID2,
|
||||
((Contact)presEvt.getSource()).getAddress());
|
||||
assertEquals("Presence Notif. event Source Contact:",
|
||||
fixture.userID2,
|
||||
presEvt.getSourceContact().getAddress());
|
||||
assertSame("Presence Notif. event Source Provider:",
|
||||
fixture.provider1,
|
||||
presEvt.getSourceProvider());
|
||||
|
||||
PresenceStatus reportedNewStatus = presEvt.getNewStatus();
|
||||
PresenceStatus reportedOldStatus = presEvt.getOldStatus();
|
||||
|
||||
assertEquals( "Reported new PresenceStatus: ",
|
||||
newStatus, reportedNewStatus );
|
||||
|
||||
//don't require equality between the reported old PresenceStatus and
|
||||
//the actual presence status of the tester agent because a first
|
||||
//notification is not supposed to have the old status as it really was.
|
||||
assertNotNull( "Reported old PresenceStatus: ", reportedOldStatus );
|
||||
|
||||
try
|
||||
{
|
||||
// add the the user to the reverse side needed for status tests
|
||||
subEvtCollector.collectedEvents.clear();
|
||||
operationSetPresence2.addSubsciptionListener(subEvtCollector);
|
||||
|
||||
synchronized (subEvtCollector)
|
||||
{
|
||||
operationSetPresence2.subscribe(fixture.userID1);
|
||||
//we may already have the event, but it won't hurt to check.
|
||||
subEvtCollector.waitForEvent(10000);
|
||||
operationSetPresence2.removeSubscriptionListener(
|
||||
subEvtCollector);
|
||||
}
|
||||
}
|
||||
catch (OperationFailedException ex)
|
||||
{
|
||||
// happens if the user is already subscribed
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We unsubscribe from presence notification deliveries concerning
|
||||
* testerAgent's presence status and verify that we receive the
|
||||
* subscription removed event. We then make the tester agent change status
|
||||
* and make sure that no notifications are delivered.
|
||||
*
|
||||
* @throws java.lang.Exception in case unsubscribing fails.
|
||||
*/
|
||||
public void postTestUnsubscribe()
|
||||
throws Exception
|
||||
{
|
||||
logger.debug("Testing Unsubscribe and unsubscription event dispatch.");
|
||||
|
||||
// First create a subscription and verify that it really gets created.
|
||||
SubscriptionEventCollector subEvtCollector
|
||||
= new SubscriptionEventCollector();
|
||||
operationSetPresence1.addSubsciptionListener(subEvtCollector);
|
||||
|
||||
Contact msnTesterAgentContact = operationSetPresence1
|
||||
.findContactByID(fixture.userID2);
|
||||
|
||||
assertNotNull(
|
||||
"Failed to find an existing subscription for the tester agent"
|
||||
, msnTesterAgentContact);
|
||||
|
||||
synchronized(subEvtCollector){
|
||||
operationSetPresence1.unsubscribe(msnTesterAgentContact);
|
||||
subEvtCollector.waitForEvent(10000);
|
||||
//don't want any more events
|
||||
operationSetPresence1.removeSubscriptionListener(subEvtCollector);
|
||||
}
|
||||
|
||||
assertEquals("Subscription event dispatching failed."
|
||||
, 1, subEvtCollector.collectedEvents.size());
|
||||
SubscriptionEvent subEvt =
|
||||
(SubscriptionEvent)subEvtCollector.collectedEvents.get(0);
|
||||
|
||||
assertEquals("SubscriptionEvent Source:",
|
||||
msnTesterAgentContact, subEvt.getSource());
|
||||
|
||||
assertEquals("SubscriptionEvent Source Contact:",
|
||||
msnTesterAgentContact, subEvt.getSourceContact());
|
||||
|
||||
assertSame("SubscriptionEvent Source Provider:",
|
||||
fixture.provider1,
|
||||
subEvt.getSourceProvider());
|
||||
|
||||
subEvtCollector.collectedEvents.clear();
|
||||
|
||||
// make the user agent tester change its states and make sure we don't
|
||||
// get notifications as we're now unsubscribed.
|
||||
logger.debug("Testing (lack of) presence notifications.");
|
||||
MsnStatusEnum oldStatus
|
||||
= (MsnStatusEnum)operationSetPresence2.getPresenceStatus();
|
||||
MsnStatusEnum newStatus = MsnStatusEnum.IDLE;
|
||||
|
||||
//in case we are by any chance already in a FREE_FOR_CHAT status, we'll
|
||||
//be changing to something else
|
||||
if(oldStatus.equals(newStatus)){
|
||||
newStatus = MsnStatusEnum.BUSY;
|
||||
}
|
||||
|
||||
//now do the actual status notification testing
|
||||
ContactPresenceEventCollector contactPresEvtCollector
|
||||
= new ContactPresenceEventCollector(fixture.userID2, null);
|
||||
operationSetPresence1.addContactPresenceStatusListener(
|
||||
contactPresEvtCollector);
|
||||
|
||||
synchronized (contactPresEvtCollector){
|
||||
operationSetPresence2.publishPresenceStatus(newStatus, "new status");
|
||||
|
||||
//we may already have the event, but it won't hurt to check.
|
||||
contactPresEvtCollector.waitForEvent(10000);
|
||||
operationSetPresence1
|
||||
.removeContactPresenceStatusListener(contactPresEvtCollector);
|
||||
}
|
||||
|
||||
assertEquals("Presence Notifications were received after unsubscibing."
|
||||
, 0, contactPresEvtCollector.collectedEvents.size());
|
||||
}
|
||||
|
||||
public void clearLists()
|
||||
throws Exception
|
||||
{
|
||||
logger.debug("Clear the two lists before tests");
|
||||
|
||||
Object o = new Object();
|
||||
synchronized (o)
|
||||
{
|
||||
o.wait(10000);
|
||||
}
|
||||
// wait for a moment
|
||||
// give time the impl to get the lists
|
||||
logger.debug("start clearing");
|
||||
fixture.clearProvidersLists();
|
||||
synchronized(o)
|
||||
{
|
||||
o.wait(3000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event collector that would collect all events generated by a
|
||||
* provider after a status change. The collector would also do a notidyAll
|
||||
* every time it receives an event.
|
||||
*/
|
||||
private class PresenceStatusEventCollector
|
||||
implements ProviderPresenceStatusListener
|
||||
{
|
||||
public ArrayList collectedPresEvents = new ArrayList();
|
||||
public ArrayList collectedStatMsgEvents = new ArrayList();
|
||||
|
||||
public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedPresEvents.size()+")= "+evt);
|
||||
collectedPresEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void providerStatusMessageChanged(PropertyChangeEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected stat.msg. evt("
|
||||
+collectedPresEvents.size()+")= "+evt);
|
||||
collectedStatMsgEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForPresEvent(long waitFor)
|
||||
{
|
||||
logger.trace("Waiting for a change in provider status.");
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedPresEvents.size() > 0){
|
||||
logger.trace("Change already received. " + collectedPresEvents);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
if(collectedPresEvents.size() > 0)
|
||||
logger.trace("Received a change in provider status.");
|
||||
else
|
||||
logger.trace("No change received for "+waitFor+"ms.");
|
||||
}
|
||||
catch (InterruptedException ex){
|
||||
logger.debug("Interrupted while waiting for a provider evt"
|
||||
, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until at least one staus message event is received or until
|
||||
* waitFor miliseconds pass (whichever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for a status message event before simply bailing out.
|
||||
*/
|
||||
public void waitForStatMsgEvent(long waitFor)
|
||||
{
|
||||
logger.trace("Waiting for a provider status message event.");
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedStatMsgEvents.size() > 0){
|
||||
logger.trace("Stat msg. evt already received. "
|
||||
+ collectedStatMsgEvents);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
if(collectedStatMsgEvents.size() > 0)
|
||||
logger.trace("Received a prov. stat. msg. evt.");
|
||||
else
|
||||
logger.trace("No prov. stat msg. received for "
|
||||
+waitFor+"ms.");
|
||||
}
|
||||
catch (InterruptedException ex){
|
||||
logger.debug("Interrupted while waiting for a status msg evt"
|
||||
, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class would listen for and store received subscription modification
|
||||
* events.
|
||||
*/
|
||||
private class SubscriptionEventCollector implements SubscriptionListener
|
||||
{
|
||||
public ArrayList collectedEvents = new ArrayList();
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedEvents.size() > 0)
|
||||
return;
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionCreated(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionRemoved(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void contactModified(ContactPropertyChangeEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionMoved(SubscriptionMovedEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionFailed(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received subsctiption and notifies all waiting on this
|
||||
* object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void subscriptionResolved(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The class would listen for and store received events caused by changes
|
||||
* in contact presence states.
|
||||
*/
|
||||
private class ContactPresenceEventCollector
|
||||
implements ContactPresenceStatusListener
|
||||
{
|
||||
public ArrayList collectedEvents = new ArrayList();
|
||||
private String trackedScreenName = null;
|
||||
private MsnStatusEnum status = null;
|
||||
|
||||
ContactPresenceEventCollector(String screenname,
|
||||
MsnStatusEnum wantedStatus)
|
||||
{
|
||||
this.trackedScreenName = screenname;
|
||||
this.status = wantedStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if(collectedEvents.size() > 0)
|
||||
return;
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the received status change event and notifies all waiting on
|
||||
* this object
|
||||
* @param evt the SubscriptionEvent containing the corresponding contact
|
||||
*/
|
||||
public void contactPresenceStatusChanged(
|
||||
ContactPresenceStatusChangeEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
//if the user has specified event details and the received
|
||||
//event does not match - then ignore it.
|
||||
if( this.trackedScreenName != null
|
||||
&& !evt.getSourceContact().getAddress()
|
||||
.equals(trackedScreenName))
|
||||
return;
|
||||
if( status != null
|
||||
&& status != evt.getNewStatus())
|
||||
return;
|
||||
|
||||
logger.debug("Collected evt("+collectedEvents.size()+")= "+evt);
|
||||
collectedEvents.add(evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wait till buddy is removed from our contact list.
|
||||
* Used in the authorization process tests
|
||||
*/
|
||||
private class UnsubscribeWait implements SubscriptionListener
|
||||
{
|
||||
public void waitForUnsubscribre(long waitFor)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void subscriptionRemoved(SubscriptionEvent evt)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
logger.debug("Got subscriptionRemoved " + evt);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void subscriptionCreated(SubscriptionEvent evt)
|
||||
{}
|
||||
public void subscriptionFailed(SubscriptionEvent evt)
|
||||
{}
|
||||
public void subscriptionMoved(SubscriptionMovedEvent evt)
|
||||
{}
|
||||
public void subscriptionResolved(SubscriptionEvent evt)
|
||||
{}
|
||||
public void contactModified(ContactPropertyChangeEvent evt)
|
||||
{}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Tests functionality of the typing notifications operation set.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class TestOperationSetTypingNotifications
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestOperationSetTypingNotifications.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
private OperationSetTypingNotifications opSetTypingNotifs1 = null;
|
||||
private OperationSetPresence opSetPresence1 = null;
|
||||
private OperationSetTypingNotifications opSetTypingNotifs2 = null;
|
||||
private OperationSetPresence opSetPresence2 = null;
|
||||
|
||||
private OperationSetBasicInstantMessaging opSetBasicIM1 = null;
|
||||
private OperationSetBasicInstantMessaging opSetBasicIM2 = null;
|
||||
|
||||
|
||||
public TestOperationSetTypingNotifications(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
|
||||
Map supportedOperationSets1 =
|
||||
fixture.provider1.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets1 == null
|
||||
|| supportedOperationSets1.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetTypingNotifs1 =
|
||||
(OperationSetTypingNotifications)supportedOperationSets1.get(
|
||||
OperationSetTypingNotifications.class.getName());
|
||||
|
||||
//if the op set is null then the implementation doesn't offer a typing.n
|
||||
//operation set which is unacceptable.
|
||||
if (opSetTypingNotifs1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for typing notifications was found");
|
||||
}
|
||||
|
||||
opSetBasicIM1 =
|
||||
(OperationSetBasicInstantMessaging)supportedOperationSets1.get(
|
||||
OperationSetBasicInstantMessaging.class.getName());
|
||||
|
||||
if (opSetBasicIM1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for basic IM was found");
|
||||
}
|
||||
|
||||
|
||||
//we also need the presence op set in order to retrieve contacts.
|
||||
opSetPresence1 =
|
||||
(OperationSetPresence)supportedOperationSets1.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null show that we're not happy.
|
||||
if (opSetPresence1 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the service must provide an "
|
||||
+ "implementation of at least one of the PresenceOperationSets");
|
||||
}
|
||||
|
||||
Map supportedOperationSets2 =
|
||||
fixture.provider2.getSupportedOperationSets();
|
||||
|
||||
if ( supportedOperationSets2 == null
|
||||
|| supportedOperationSets2.size() < 1)
|
||||
throw new NullPointerException(
|
||||
"No OperationSet implementations are supported by "
|
||||
+"this implementation. ");
|
||||
|
||||
//get the operation set presence here.
|
||||
opSetTypingNotifs2 =
|
||||
(OperationSetTypingNotifications)supportedOperationSets2.get(
|
||||
OperationSetTypingNotifications.class.getName());
|
||||
|
||||
//if the op set is null then the implementation doesn't offer a typing.n
|
||||
//operation set which is unacceptable for.
|
||||
if (opSetTypingNotifs2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for typing notifications was found");
|
||||
}
|
||||
|
||||
opSetBasicIM2 =
|
||||
(OperationSetBasicInstantMessaging)supportedOperationSets2.get(
|
||||
OperationSetBasicInstantMessaging.class.getName());
|
||||
|
||||
if (opSetBasicIM2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"No implementation for basic IM was found");
|
||||
}
|
||||
|
||||
|
||||
//we also need the presence op set in order to retrieve contacts.
|
||||
opSetPresence2 =
|
||||
(OperationSetPresence)supportedOperationSets2.get(
|
||||
OperationSetPresence.class.getName());
|
||||
|
||||
//if the op set is null show that we're not happy.
|
||||
if (opSetPresence2 == null)
|
||||
{
|
||||
throw new NullPointerException(
|
||||
"An implementation of the service must provide an "
|
||||
+ "implementation of at least one of the PresenceOperationSets");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the list to be sure that contacts exchanging messages
|
||||
* exists in each other lists
|
||||
* @throws Exception
|
||||
*/
|
||||
public void prepareContactList() throws Exception
|
||||
{
|
||||
// be sure that contacts are in their lists
|
||||
try{
|
||||
opSetPresence1.subscribe(fixture.userID2);
|
||||
}
|
||||
catch (OperationFailedException ex){
|
||||
// the contact already exist its OK
|
||||
}
|
||||
|
||||
try{
|
||||
opSetPresence2.subscribe(fixture.userID1);
|
||||
}
|
||||
catch (OperationFailedException ex1){
|
||||
// the contact already exist its OK
|
||||
}
|
||||
|
||||
Object o = new Object();
|
||||
synchronized (o)
|
||||
{
|
||||
o.wait(2000);
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
super.tearDown();
|
||||
|
||||
fixture.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test suite containing tests of this class in a specific order.
|
||||
* We'll first execute a test where we receive a typing notification, and
|
||||
* a volatile contact is created for the sender. we'll then be able to
|
||||
* retrieve this volatile contact and them a notification on our turn.
|
||||
* We need to do things this way as the contact corresponding to the tester
|
||||
* agent has been removed in the previous test and we no longer have it
|
||||
* in our contact list.
|
||||
*
|
||||
* @return Test a testsuite containing all tests to execute.
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
|
||||
suite.addTest(new TestOperationSetTypingNotifications(
|
||||
"prepareContactList"));
|
||||
|
||||
//the following 2 need to be run in the specified order.
|
||||
suite.addTest(new TestOperationSetTypingNotifications(
|
||||
"testTypingNotificationsEventDelivery"));
|
||||
return suite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a typing notification and verifies
|
||||
* whether it is properly received by the tested implementation
|
||||
*/
|
||||
public void testTypingNotificationsEventDelivery()
|
||||
{
|
||||
TypingEventCollector evtCollector = new TypingEventCollector();
|
||||
|
||||
// send message so request for receiving notifications also to be set
|
||||
Contact notifingContact =
|
||||
opSetPresence1.findContactByID(fixture.userID2);
|
||||
opSetBasicIM1.sendInstantMessage(notifingContact,
|
||||
opSetBasicIM1.createMessage("ping"));
|
||||
|
||||
opSetTypingNotifs1.addTypingNotificationsListener(evtCollector);
|
||||
|
||||
Contact contactToNotify =
|
||||
opSetPresence2.findContactByID(fixture.userID1);
|
||||
|
||||
opSetTypingNotifs2.sendTypingNotification(
|
||||
contactToNotify, OperationSetTypingNotifications.STATE_TYPING);
|
||||
|
||||
evtCollector.waitForEvent(10000);
|
||||
|
||||
opSetTypingNotifs1.removeTypingNotificationsListener(evtCollector);
|
||||
|
||||
//check event dispatching
|
||||
assertTrue("Number of typing events received was zero."
|
||||
, evtCollector.collectedEvents.size() > 0);
|
||||
|
||||
TypingNotificationEvent evt = (TypingNotificationEvent)evtCollector
|
||||
.collectedEvents.get(0);
|
||||
|
||||
assertEquals("Source of the typing notification event"
|
||||
, fixture.userID2
|
||||
, evt.getSourceContact().getAddress() );
|
||||
|
||||
assertEquals("Source of the typing notification event"
|
||||
, OperationSetTypingNotifications.STATE_TYPING
|
||||
, evt.getTypingState());
|
||||
|
||||
evtCollector.collectedEvents.clear();
|
||||
|
||||
opSetTypingNotifs1.addTypingNotificationsListener(evtCollector);
|
||||
|
||||
opSetTypingNotifs2.sendTypingNotification(
|
||||
contactToNotify, OperationSetTypingNotifications.STATE_STOPPED);
|
||||
|
||||
evtCollector.waitForEvent(10000);
|
||||
|
||||
opSetTypingNotifs1.removeTypingNotificationsListener(evtCollector);
|
||||
|
||||
//check event dispatching
|
||||
assertTrue("Number of typing events received was zero."
|
||||
, evtCollector.collectedEvents.size() > 0);
|
||||
|
||||
evt = (TypingNotificationEvent)evtCollector.collectedEvents.get(0);
|
||||
|
||||
assertEquals("Source of the typing notification event"
|
||||
, fixture.userID2
|
||||
, evt.getSourceContact().getAddress() );
|
||||
|
||||
assertEquals("Source of the typing notification event"
|
||||
, OperationSetTypingNotifications.STATE_STOPPED
|
||||
, evt.getTypingState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply collects allre received events and provides a mechanisim for
|
||||
* waiting for the next event.
|
||||
*/
|
||||
private class TypingEventCollector implements TypingNotificationsListener
|
||||
{
|
||||
private List collectedEvents = new LinkedList();
|
||||
/**
|
||||
* Called to indicate that a remote <tt>Contact</tt> has sent us a typing
|
||||
* notification. The method adds the <tt>event</tt> to the list of
|
||||
* captured events.
|
||||
* @param event a <tt>TypingNotificationEvent</tt> containing the sender
|
||||
* of the notification and its type.
|
||||
*/
|
||||
public void typingNotificationReceifed(TypingNotificationEvent event)
|
||||
{
|
||||
logger.debug("Received a typing notification: " + event);
|
||||
synchronized (this)
|
||||
{
|
||||
collectedEvents.add(event);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until at least one event is received or until waitFor
|
||||
* miliseconds pass (whicever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
synchronized(this){
|
||||
|
||||
if(collectedEvents.size() > 0)
|
||||
return;
|
||||
|
||||
try{
|
||||
wait(waitFor);
|
||||
}
|
||||
catch (InterruptedException ex){
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a subscription evt", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.protocol.msn;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Performs testing on protocol provider methods.
|
||||
* @todo add more detailed docs once the tests are written.
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class TestProtocolProviderServiceMsnImpl
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(TestProtocolProviderServiceMsnImpl.class);
|
||||
|
||||
private MsnSlickFixture fixture = new MsnSlickFixture();
|
||||
|
||||
/**
|
||||
* An event adapter that would collec registation state change events
|
||||
*/
|
||||
public RegistrationEventCollector regEvtCollector1
|
||||
= new RegistrationEventCollector();
|
||||
|
||||
/**
|
||||
* An event adapter that would collec registation state change events
|
||||
*/
|
||||
public RegistrationEventCollector regEvtCollector2
|
||||
= new RegistrationEventCollector();
|
||||
|
||||
/**
|
||||
* Creates a test encapsulator for the method with the specified name.
|
||||
* @param name the name of the method this test should run.
|
||||
*/
|
||||
public TestProtocolProviderServiceMsnImpl(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the fixture.
|
||||
* @throws Exception if super.setUp() throws one.
|
||||
*/
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
super.setUp();
|
||||
fixture.setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears the fixture down.
|
||||
* @throws Exception if fixture.tearDown() fails.
|
||||
*/
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
fixture.tearDown();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the instance of the Msn protocol provider that we're
|
||||
* going to use for testing is properly initialized and registered with
|
||||
* a Msn registrar. This MUST be called before any other online testing
|
||||
* of the Msn provider so that we won't have to reregister for every single
|
||||
* test.
|
||||
* <p>
|
||||
* The method also verifies that a registration event is fired upon
|
||||
* succesful registration and collected by our event collector.
|
||||
*
|
||||
* @throws OperationFailedException if provider.register() fails.
|
||||
*/
|
||||
public void testRegister()
|
||||
throws OperationFailedException
|
||||
{
|
||||
//add an event collector that will collect all events during the
|
||||
//registration and allow us to later inspect them and make sure
|
||||
//they were properly dispatched.
|
||||
fixture.provider1.addRegistrationStateChangeListener(regEvtCollector1);
|
||||
fixture.provider2.addRegistrationStateChangeListener(regEvtCollector2);
|
||||
|
||||
//register both our providers
|
||||
fixture.provider1.register(new SecurityAuthorityImpl(
|
||||
System.getProperty(MsnProtocolProviderServiceLick.ACCOUNT_1_PREFIX
|
||||
+ ProtocolProviderFactory.PASSWORD).toCharArray()));
|
||||
fixture.provider2.register(new SecurityAuthorityImpl(
|
||||
System.getProperty(MsnProtocolProviderServiceLick.ACCOUNT_2_PREFIX
|
||||
+ ProtocolProviderFactory.PASSWORD).toCharArray()));
|
||||
|
||||
//give it enough time to register. We won't really have to wait all this
|
||||
//time since the registration event collector would notify us the moment
|
||||
//we get signed on.
|
||||
logger.debug("Waiting for registration to complete ...");
|
||||
|
||||
regEvtCollector1.waitForEvent(15000);
|
||||
regEvtCollector2.waitForEvent(40000);
|
||||
|
||||
//make sure that the registration process trigerred the corresponding
|
||||
//events.
|
||||
assertTrue(
|
||||
"No events were dispatched during the registration process."
|
||||
,regEvtCollector1.collectedNewStates.size() > 0);
|
||||
|
||||
assertTrue(
|
||||
"No registration event notifying of registration was dispatched. "
|
||||
+"All events were: " + regEvtCollector1.collectedNewStates
|
||||
,regEvtCollector1.collectedNewStates
|
||||
.contains(RegistrationState.REGISTERED));
|
||||
|
||||
//now the same for provider 2
|
||||
assertTrue(
|
||||
"No events were dispatched during the registration process "
|
||||
+"of provider2."
|
||||
,regEvtCollector2.collectedNewStates.size() > 0);
|
||||
|
||||
assertTrue(
|
||||
"No registration event notifying of registration was dispatched. "
|
||||
+"All events were: " + regEvtCollector2.collectedNewStates
|
||||
,regEvtCollector2.collectedNewStates
|
||||
.contains(RegistrationState.REGISTERED));
|
||||
|
||||
|
||||
fixture.provider1
|
||||
.removeRegistrationStateChangeListener(regEvtCollector1);
|
||||
fixture.provider2
|
||||
.removeRegistrationStateChangeListener(regEvtCollector2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that all operation sets have the type they are declarded to
|
||||
* have.
|
||||
*
|
||||
* @throws java.lang.Exception if a class indicated in one of the keys
|
||||
* could not be forName()ed.
|
||||
*/
|
||||
public void testOperationSetTypes() throws Exception
|
||||
{
|
||||
Map supportedOperationSets
|
||||
= fixture.provider1.getSupportedOperationSets();
|
||||
|
||||
//make sure that keys (which are supposed to be class names) correspond
|
||||
//what the class of the values recorded against them.
|
||||
Iterator setNames = supportedOperationSets.keySet().iterator();
|
||||
while (setNames.hasNext())
|
||||
{
|
||||
String setName = (String) setNames.next();
|
||||
Object opSet = supportedOperationSets.get(setName);
|
||||
|
||||
assertTrue(opSet + " was not an instance of "
|
||||
+ setName + " as declared"
|
||||
, Class.forName(setName).isInstance(opSet));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that would plugin as a registration listener to a protocol
|
||||
* provider and simply record all events that it sees and notifyAll()
|
||||
* if it sees an event that notifies us of a completed
|
||||
* registration.
|
||||
*/
|
||||
public class RegistrationEventCollector
|
||||
implements RegistrationStateChangeListener
|
||||
{
|
||||
public List collectedNewStates = new LinkedList();
|
||||
|
||||
/**
|
||||
* The method would simply register all received events so that they
|
||||
* could be available for later inspection by the unit tests. In the
|
||||
* case where a registraiton event notifying us of a completed
|
||||
* registration is seen, the method would call notifyAll().
|
||||
*
|
||||
* @param evt ProviderStatusChangeEvent the event describing the status
|
||||
* change.
|
||||
*/
|
||||
public void registrationStateChanged(RegistrationStateChangeEvent evt)
|
||||
{
|
||||
logger.debug("Received a RegistrationStateChangeEvent: " + evt);
|
||||
|
||||
collectedNewStates.add(evt.getNewState());
|
||||
|
||||
if (evt.getNewState().equals(RegistrationState.REGISTERED))
|
||||
{
|
||||
logger.debug("We're registered and will notify those who wait");
|
||||
synchronized (this)
|
||||
{
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until an event notifying us of the awaited state change is
|
||||
* received or until waitFor miliseconds pass (whichever happens first).
|
||||
*
|
||||
* @param waitFor the number of miliseconds that we should be waiting
|
||||
* for an event before simply bailing out.
|
||||
*/
|
||||
public void waitForEvent(long waitFor)
|
||||
{
|
||||
logger.trace("Waiting for a RegistrationStateChangeEvent ");
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
if (collectedNewStates.contains(RegistrationState.REGISTERED))
|
||||
{
|
||||
logger.trace("Event already received. "
|
||||
+ collectedNewStates);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
wait(waitFor);
|
||||
|
||||
if (collectedNewStates.size() > 0)
|
||||
logger.trace(
|
||||
"Received a RegistrationStateChangeEvent.");
|
||||
else
|
||||
logger.trace(
|
||||
"No RegistrationStateChangeEvent received for "
|
||||
+ waitFor + "ms.");
|
||||
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
logger.debug(
|
||||
"Interrupted while waiting for a "
|
||||
+"RegistrationStateChangeEvent"
|
||||
, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A very simple straight forward implementation of a security authority
|
||||
* that would always return the same password (the one specified upon
|
||||
* construction) when asked for credentials.
|
||||
*/
|
||||
public class SecurityAuthorityImpl
|
||||
implements SecurityAuthority
|
||||
{
|
||||
/**
|
||||
* The password to return when asked for credentials
|
||||
*/
|
||||
private char[] passwd = null;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class that would always return "passwd"
|
||||
* when asked for credentials.
|
||||
*
|
||||
* @param passwd the password that this class should return when
|
||||
* asked for credentials.
|
||||
*/
|
||||
public SecurityAuthorityImpl(char[] passwd)
|
||||
{
|
||||
this.passwd = passwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Credentials object associated with the specified realm.
|
||||
* <p>
|
||||
* @param realm The realm that the credentials are needed for.
|
||||
* @param defaultValues the values to propose the user by default
|
||||
* @return The credentials associated with the specified realm or null
|
||||
* if none could be obtained.
|
||||
*/
|
||||
public UserCredentials obtainCredentials(String realm,
|
||||
UserCredentials defaultValues)
|
||||
{
|
||||
defaultValues.setPassword(passwd);
|
||||
return defaultValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
Bundle-Activator: net.java.sip.communicator.slick.protocol.msn.MsnProtocolProviderServiceLick
|
||||
Bundle-Name: Msn Protocol Provider Service Leveraging Implementation Compatibility Kit
|
||||
Bundle-Description: A Service Leveraging Implementation Compatibility Kit for the Msn implementation of the ProtocolProvider Service
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
junit.framework,
|
||||
org.osgi.framework,
|
||||
javax.net.ssl,
|
||||
javax.xml.parsers,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.msnconstants,
|
||||
net.java.sip.communicator.service.protocol.event
|
||||