Fixes a socket-related exception in the MSN protocol implementation which used to happen every time my MSN account was to go offline (either by manually setting it or by quitting the application).

cusax-fix
Lyubomir Marinov 17 years ago
parent d3e5f492ce
commit 0f148ad9c1

@ -31,7 +31,7 @@ public class OperationSetBasicInstantMessagingMsnImpl
/**
* The provider that created us.
*/
private ProtocolProviderServiceMsnImpl msnProvider = null;
private final ProtocolProviderServiceMsnImpl msnProvider;
/**
* A reference to the persistent presence operation set that we use
@ -39,7 +39,8 @@ public class OperationSetBasicInstantMessagingMsnImpl
*/
private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
private OperationSetAdHocMultiUserChatMsnImpl opSetMuc = null;
private final OperationSetAdHocMultiUserChatMsnImpl opSetMuc;
/**
* Creates an instance of this operation set.
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
@ -50,8 +51,10 @@ public class OperationSetBasicInstantMessagingMsnImpl
ProtocolProviderServiceMsnImpl provider)
{
this.msnProvider = provider;
opSetMuc = (OperationSetAdHocMultiUserChatMsnImpl) msnProvider
.getOperationSet(OperationSetAdHocMultiUserChat.class);
opSetMuc
= (OperationSetAdHocMultiUserChatMsnImpl)
msnProvider
.getOperationSet(OperationSetAdHocMultiUserChat.class);
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
}
@ -83,10 +86,7 @@ public boolean isOfflineMessagingSupported()
*/
public boolean isContentTypeSupported(String contentType)
{
if(contentType.equals(DEFAULT_MIME_TYPE))
return true;
else
return false;
return DEFAULT_MIME_TYPE.equals(contentType);
}
public Message createMessage(String content, String contentType,
@ -117,10 +117,10 @@ public void sendInstantMessage(Contact to, Message message)
+ to);
MessageDeliveredEvent msgDeliveryPendingEvt
= new MessageDeliveredEvent(
message, to, System.currentTimeMillis());
= new MessageDeliveredEvent(message, to);
msgDeliveryPendingEvt = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
msgDeliveryPendingEvt
= messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
return;
@ -128,11 +128,10 @@ public void sendInstantMessage(Contact to, Message message)
msnProvider.getMessenger().
sendText(
((ContactMsnImpl)to).getSourceContact().getEmail(),
msgDeliveryPendingEvt.getSourceMessage().getContent()
);
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(message, to, System.currentTimeMillis());
msgDeliveryPendingEvt.getSourceMessage().getContent());
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(message, to);
// msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
@ -183,10 +182,14 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt)
(OperationSetPersistentPresenceMsnImpl) msnProvider
.getOperationSet(OperationSetPersistentPresence.class);
msnProvider.getMessenger().
addMessageListener(new MsnMessageListener());
msnProvider.getMessenger().
addEmailListener(new MsnMessageListener());
MsnMessenger msnMessenger = msnProvider.getMessenger();
/*
* FIXME What's the point of having to MsnMessageListener
* instances?
*/
msnMessenger.addMessageListener(new MsnMessageListener());
msnMessenger.addEmailListener(new MsnMessageListener());
}
}
}
@ -202,7 +205,7 @@ public void instantMessageReceived(MsnSwitchboard switchboard,
// FILTER OUT THE GROUP MESSAGES
if (opSetMuc.isGroupChatMessage(switchboard))
return;
Message newMessage = createMessage(message.getContent());
Contact sourceContact = opSetPersPresence.
findContactByID(contact.getEmail().getEmailAddress());
@ -232,8 +235,7 @@ public void instantMessageReceived(MsnSwitchboard switchboard,
* @param body of message
* @param contentType of message
* @param encoding of message
* @param displayName
* @param from the user who sent this message
* @param contact the user who sent this message
*/
public void offlineMessageReceived(String body,
String contentType,

@ -21,24 +21,20 @@
* An implementation of the protocol provider service over the Msn protocol
*
* @author Damian Minkov
* @author Lubomir Marinov
*/
public class ProtocolProviderServiceMsnImpl
extends AbstractProtocolProviderService
{
private static final Logger logger =
Logger.getLogger(ProtocolProviderServiceMsnImpl.class);
private static final Logger logger
= Logger.getLogger(ProtocolProviderServiceMsnImpl.class);
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();
private final Object initializationLock = new Object();
/**
* The identifier of the account that this provider represents.
@ -57,8 +53,15 @@ public class ProtocolProviderServiceMsnImpl
/**
* The icon corresponding to the msn protocol.
*/
private ProtocolIconMsnImpl msnIcon
= new ProtocolIconMsnImpl();
private final ProtocolIconMsnImpl msnIcon = new ProtocolIconMsnImpl();
/**
* The indicator which determines whether
* {@link MsnMessengerListener#logout(MsnMessenger)} has been received for
* {@link #messenger} and it is thus an error to call
* {@link MsnMessenger#logout()} on it.
*/
private boolean logoutReceived = false;
/**
* Returns the state of the registration of this protocol provider
@ -114,7 +117,8 @@ void reconnect(int reasonCode)
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
null);
}
}
@ -130,21 +134,25 @@ private void connectAndLogin(SecurityAuthority authority, int reasonCode)
synchronized(initializationLock)
{
//verify whether a password has already been stored for this account
String password = MsnActivator.
getProtocolProviderFactory().loadPassword(getAccountID());
ProtocolProviderFactory protocolProviderFactory
= MsnActivator.getProtocolProviderFactory();
AccountID accountID = getAccountID();
String password = protocolProviderFactory.loadPassword(accountID);
//decode
if (password == null)
{
//create a default credentials object
UserCredentials credentials = new UserCredentials();
credentials.setUserName(getAccountID().getUserID());
credentials.setUserName(accountID.getUserID());
//request a password from the user
credentials = authority.obtainCredentials(
ProtocolNames.MSN,
credentials,
reasonCode);
credentials
= authority
.obtainCredentials(
ProtocolNames.MSN,
credentials,
reasonCode);
// in case user has canceled the login window
if(credentials == null)
@ -152,7 +160,8 @@ private void connectAndLogin(SecurityAuthority authority, int reasonCode)
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
RegistrationStateChangeEvent.REASON_USER_REQUEST,
"");
return;
}
@ -165,22 +174,25 @@ private void connectAndLogin(SecurityAuthority authority, int reasonCode)
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
RegistrationStateChangeEvent.REASON_USER_REQUEST,
"");
return;
}
password = new String(pass);
if (credentials.isPasswordPersistent())
{
MsnActivator.getProtocolProviderFactory()
.storePassword(getAccountID(), password);
}
protocolProviderFactory.storePassword(accountID, password);
}
messenger = MsnMessengerFactory.createMsnMessenger(
getAccountID().getUserID(),
password);
messenger
= MsnMessengerFactory
.createMsnMessenger(accountID.getUserID(), password);
/*
* We've just created the messenger so we're sure we haven't
* received a logout for it.
*/
logoutReceived = false;
messenger.addMessengerListener(new MsnConnectionListener());
persistentPresence.setMessenger(messenger);
@ -195,7 +207,8 @@ private void connectAndLogin(SecurityAuthority authority, int reasonCode)
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND, null);
RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND,
null);
}
}
}
@ -216,16 +229,19 @@ void unregister(boolean fireEvent)
{
RegistrationState currRegState = getRegistrationState();
if(messenger != null)
messenger.logout();
// The synchronization is for logoutReceived at least.
synchronized (initializationLock)
{
if((messenger != null) && !logoutReceived)
messenger.logout();
}
if(fireEvent)
{
fireRegistrationStateChanged(
currRegState,
RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_USER_REQUEST, null);
}
RegistrationStateChangeEvent.REASON_USER_REQUEST,
null);
}
/**
@ -254,56 +270,45 @@ public String getProtocolName()
*
* @see net.java.sip.communicator.service.protocol.AccountID
*/
protected void initialize(String screenname,
AccountID accountID)
protected void initialize(String screenname, AccountID accountID)
{
synchronized(initializationLock)
{
this.accountID = accountID;
supportedOperationSets.put(
OperationSetInstantMessageTransform.class.getName(),
addSupportedOperationSet(
OperationSetInstantMessageTransform.class,
new OperationSetInstantMessageTransformImpl());
//initialize the presence operationset
persistentPresence = new OperationSetPersistentPresenceMsnImpl(this);
supportedOperationSets.put(
OperationSetPersistentPresence.class.getName(),
addSupportedOperationSet(
OperationSetPersistentPresence.class,
persistentPresence);
//register it once again for those that simply need presence
supportedOperationSets.put( OperationSetPresence.class.getName(),
persistentPresence);
OperationSetAdHocMultiUserChat adHocMultiUserChat =
new OperationSetAdHocMultiUserChatMsnImpl(this);
supportedOperationSets.put(OperationSetAdHocMultiUserChat.class
.getName(), adHocMultiUserChat);
addSupportedOperationSet(
OperationSetPresence.class,
persistentPresence);
// initialize the IM operation set
OperationSetBasicInstantMessagingMsnImpl basicInstantMessaging
= new OperationSetBasicInstantMessagingMsnImpl(this);
addSupportedOperationSet(
OperationSetAdHocMultiUserChat.class,
new OperationSetAdHocMultiUserChatMsnImpl(this));
supportedOperationSets.put(OperationSetBasicInstantMessaging.class
.getName(), basicInstantMessaging);
// initialize the IM operation set
addSupportedOperationSet(
OperationSetBasicInstantMessaging.class,
new OperationSetBasicInstantMessagingMsnImpl(this));
//initialize the typing notifications operation set
typingNotifications =
new OperationSetTypingNotificationsMsnImpl(this);
supportedOperationSets.put(
OperationSetTypingNotifications.class.getName(),
typingNotifications
= new OperationSetTypingNotificationsMsnImpl(this);
addSupportedOperationSet(
OperationSetTypingNotifications.class,
typingNotifications);
OperationSetFileTransferMsnImpl fileTransferOpSet =
new OperationSetFileTransferMsnImpl(this);
supportedOperationSets.put(
OperationSetFileTransfer.class.getName(),
fileTransferOpSet);
isInitialized = true;
addSupportedOperationSet(
OperationSetFileTransfer.class,
new OperationSetFileTransferMsnImpl(this));
}
}
@ -314,28 +319,13 @@ protected void initialize(String screenname,
*/
public void shutdown()
{
synchronized(initializationLock){
if (messenger != null)
{
messenger.logout();
messenger = null;
}
isInitialized = false;
synchronized(initializationLock)
{
unregister(false);
messenger = null;
}
}
/**
* 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;
}
/**
* Returns the AccountID that uniquely identifies the account represented
* by this instance of the ProtocolProviderService.
@ -369,21 +359,21 @@ MsnMessenger getMessenger()
* @param reason a String further explaining the reason code or null if
* no such explanation is necessary.
*/
public void fireRegistrationStateChanged( RegistrationState oldState,
RegistrationState newState,
int reasonCode,
String reason)
public void fireRegistrationStateChanged(RegistrationState oldState,
RegistrationState newState,
int reasonCode,
String reason)
{
if(newState.equals(RegistrationState.UNREGISTERED) ||
newState.equals(RegistrationState.CONNECTION_FAILED))
if (newState.equals(RegistrationState.UNREGISTERED)
|| newState.equals(RegistrationState.CONNECTION_FAILED))
messenger = null;
super.fireRegistrationStateChanged(oldState, newState, reasonCode, reason);
}
/**
* Listens when we are logged in or out from the server
* or incoming exception in the lib impl.
* Listens when we are logged in or out from the server or incoming
* exception in the lib impl.
*/
private class MsnConnectionListener
implements MsnMessengerListener
@ -394,18 +384,20 @@ public void loginCompleted(MsnMessenger msnMessenger)
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.REGISTERED,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
null);
}
public void logout(MsnMessenger msnMessenger)
{
logger.trace("logout");
unregister(true);
// if(isRegistered())
// fireRegistrationStateChanged(
// getRegistrationState(),
// RegistrationState.UNREGISTERED,
// RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null);
// The synchronization is for logoutReceived at least.
synchronized (initializationLock)
{
logoutReceived = true;
unregister(true);
}
}
public void exceptionCaught(MsnMessenger msnMessenger,
@ -446,52 +438,50 @@ else if(throwable instanceof UnknownHostException)
RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND,
"A network error occured. Could not connect to server.");
}
else
else if(throwable instanceof MsnProtocolException)
{
if(throwable instanceof MsnProtocolException)
{
MsnProtocolException exception =
(MsnProtocolException)throwable;
MsnProtocolException exception =
(MsnProtocolException)throwable;
logger.error("Error in Msn lib ", exception);
logger.error("Error in Msn lib ", exception);
switch(exception.getErrorCode())
switch(exception.getErrorCode())
{
case 500:
case 540:
case 601:
if(isRegistered())
{
case 500:
case 540:
case 601:
if(isRegistered())
{
unregister(false);
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.
REASON_INTERNAL_ERROR, null);
}
break;
case 911:
if(isRegistered())
{
unregister(false);
MsnActivator.getProtocolProviderFactory().
storePassword(getAccountID(), null);
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.AUTHENTICATION_FAILED,
RegistrationStateChangeEvent.
REASON_AUTHENTICATION_FAILED, null);
// We try to reconnect and ask user to retype
// password.
reconnect(SecurityAuthority.WRONG_PASSWORD);
}
break;
unregister(false);
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_INTERNAL_ERROR,
null);
}
return;
break;
case 911:
if(isRegistered())
{
unregister(false);
MsnActivator.getProtocolProviderFactory().
storePassword(getAccountID(), null);
fireRegistrationStateChanged(
getRegistrationState(),
RegistrationState.AUTHENTICATION_FAILED,
RegistrationStateChangeEvent
.REASON_AUTHENTICATION_FAILED,
null);
// We try to reconnect and ask user to retype
// password.
reconnect(SecurityAuthority.WRONG_PASSWORD);
}
break;
}
}
else
{
logger.error("Error in Msn lib ", throwable);
// We don't want to disconnect on any error, that's why we're

@ -12,9 +12,11 @@
import net.java.sip.communicator.util.*;
/**
* Implements "standard" functionality of <tt>ProtocolProviderService</tt> in
* Implements standard functionality of <tt>ProtocolProviderService</tt> in
* order to make it easier for implementers to provide complete solutions while
* focusing on protocol-specific details.
*
* @author Lubomir Marinov
*/
public abstract class AbstractProtocolProviderService
implements ProtocolProviderService
@ -55,6 +57,26 @@ public void addRegistrationStateChangeListener(
}
}
/**
* Adds a specific <tt>OperationSet</tt> implementation to the set of
* supported <tt>OperationSet</tt>s of this instance. Serves as a type-safe
* wrapper around {@link #supportedOperationSets} and its
* {@link Hashtable#put(String, OperationSet)} and also shortens the code
* which performs such additions.
*
* @param <T> the exact type of the <tt>OperationSet</tt> implementation to
* be added
* @param opsetClass the <tt>Class</tt> of <tt>OperationSet</tt> under the
* name of which the specified implementation is to be added
* @param opset the <tt>OperationSet</tt> implementation to be added
*/
protected <T extends OperationSet> void addSupportedOperationSet(
Class<T> opsetClass,
T opset)
{
supportedOperationSets.put(opsetClass.getName(), opset);
}
/**
* Creates a RegistrationStateChange event corresponding to the specified
* old and new states and notifies all currently registered listeners.
@ -133,7 +155,7 @@ public void fireRegistrationStateChanged( RegistrationState oldState,
@SuppressWarnings("unchecked")
public <T extends OperationSet> T getOperationSet(Class<T> opsetClass)
{
return (T) doGetSupportedOperationSets().get(opsetClass.getName());
return (T) supportedOperationSets.get(opsetClass.getName());
}
/**
@ -165,17 +187,9 @@ public String getProtocolDisplayName()
*/
public Map<String, OperationSet> getSupportedOperationSets()
{
Map<String, OperationSet> supportedOperationSets =
doGetSupportedOperationSets();
return new Hashtable<String, OperationSet>(supportedOperationSets);
}
protected Map<String, OperationSet> doGetSupportedOperationSets()
{
return supportedOperationSets;
}
/**
* Indicates whether or not this provider is registered
*

Loading…
Cancel
Save