aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2011-07-04 15:39:10 +0000
committerDamian Minkov <damencho@jitsi.org>2011-07-04 15:39:10 +0000
commit2e78f26000b30f35d464e5c21f842c67e1f54691 (patch)
tree25c3d6c76d197fcc963e021c310dec916f734b1b /src/net/java/sip
parentc8b23f022b1e482133a8a5549c452d3440dca0bc (diff)
downloadjitsi-2e78f26000b30f35d464e5c21f842c67e1f54691.zip
jitsi-2e78f26000b30f35d464e5c21f842c67e1f54691.tar.gz
jitsi-2e78f26000b30f35d464e5c21f842c67e1f54691.tar.bz2
Adds listener for notifying for server stored account details.
SIP protocol gets its account display name from the OK responses to its register requests.
Diffstat (limited to 'src/net/java/sip')
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java39
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java31
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java19
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java17
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java143
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java30
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java9
-rw-r--r--src/net/java/sip/communicator/service/protocol/AbstractOperationSetServerStoredAccountInfo.java103
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java21
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeEvent.java106
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeListener.java18
11 files changed, 526 insertions, 10 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
index 311c217..546de43 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/presence/AccountStatusPanel.java
@@ -34,6 +34,7 @@ import net.java.sip.communicator.util.swing.*;
public class AccountStatusPanel
extends TransparentPanel
implements RegistrationStateChangeListener,
+ ServerStoredDetailsChangeListener,
PluginComponentListener,
AvatarListener,
Skinnable
@@ -401,6 +402,13 @@ public class AccountStatusPanel
= protocolProvider.getOperationSet(OperationSetAvatar.class);
if (avatarOpSet != null)
avatarOpSet.addAvatarListener(this);
+
+ OperationSetServerStoredAccountInfo serverStoredAccountInfo
+ = protocolProvider.getOperationSet(
+ OperationSetServerStoredAccountInfo.class);
+ if (serverStoredAccountInfo != null)
+ serverStoredAccountInfo.addServerStoredDetailsChangeListener(
+ this);
}
else if (evt.getNewState().equals(RegistrationState.UNREGISTERING)
|| evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
@@ -409,6 +417,13 @@ public class AccountStatusPanel
= protocolProvider.getOperationSet(OperationSetAvatar.class);
if (avatarOpSet != null)
avatarOpSet.removeAvatarListener(this);
+
+ OperationSetServerStoredAccountInfo serverStoredAccountInfo
+ = protocolProvider.getOperationSet(
+ OperationSetServerStoredAccountInfo.class);
+ if (serverStoredAccountInfo != null)
+ serverStoredAccountInfo.removeServerStoredDetailsChangeListener(
+ this);
}
else if (evt.getNewState().equals(RegistrationState.REGISTERING))
{
@@ -540,4 +555,28 @@ public class AccountStatusPanel
accountImageLabel.setImageIcon(ImageLoader
.getImage(ImageLoader.DEFAULT_USER_PHOTO));
}
+
+ /**
+ * Registers a ServerStoredDetailsChangeListener with the operation sets
+ * of the providers, if a provider change its name we use it in the UI.
+ *
+ * @param evt the <tt>ServerStoredDetailsChangeEvent</tt>
+ * the event for name change.
+ */
+ public void serverStoredDetailsChanged(ServerStoredDetailsChangeEvent evt)
+ {
+ if(evt.getNewValue() instanceof
+ ServerStoredDetails.DisplayNameDetail
+ && (evt.getEventID() == ServerStoredDetailsChangeEvent.DETAIL_ADDED
+ || evt.getEventID()
+ == ServerStoredDetailsChangeEvent.DETAIL_REPLACED))
+ {
+ String accountName =
+ ((ServerStoredDetails.DisplayNameDetail)evt.getNewValue())
+ .getName();
+
+ if (accountName != null && accountName.length() > 0)
+ accountNameLabel.setText(accountName);
+ }
+ }
} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
index b30e130..45b11f1 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredAccountInfoIcqImpl.java
@@ -11,6 +11,7 @@ import java.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
+import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joscar.*;
import net.kano.joscar.snac.*;
@@ -23,7 +24,7 @@ import net.kano.joustsim.oscar.oscar.service.icon.*;
* @author Damian Minkov
*/
public class OperationSetServerStoredAccountInfoIcqImpl
- implements OperationSetServerStoredAccountInfo
+ extends AbstractOperationSetServerStoredAccountInfo
{
private static final Logger logger =
Logger.getLogger(OperationSetServerStoredAccountInfoIcqImpl.class);
@@ -290,6 +291,11 @@ public class OperationSetServerStoredAccountInfoIcqImpl
ByteBlock.wrap(((ServerStoredDetails.ImageDetail) detail).getBytes()));
infoRetreiver.detailsChanged(uin);
+ fireServerStoredDetailsChangeEvent(icqProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
+
return;
}
@@ -399,6 +405,11 @@ public class OperationSetServerStoredAccountInfoIcqImpl
OperationFailedException.GENERAL_ERROR);
infoRetreiver.detailsChanged(uin);
+
+ fireServerStoredDetailsChangeEvent(icqProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
}
private void setInterests(MetaFullInfoSetCmd cmd, List<InterestDetail> interests)
@@ -524,6 +535,12 @@ public class OperationSetServerStoredAccountInfoIcqImpl
if (responseListener.success)
{
infoRetreiver.detailsChanged(uin);
+
+ fireServerStoredDetailsChangeEvent(icqProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_REMOVED,
+ detail,
+ null);
+
return true;
}
else
@@ -597,6 +614,12 @@ public class OperationSetServerStoredAccountInfoIcqImpl
.getBytes()));
infoRetreiver.detailsChanged(uin);
+
+ fireServerStoredDetailsChangeEvent(icqProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
+ currentDetailValue,
+ newDetailValue);
+
return true;
}
@@ -749,6 +772,12 @@ public class OperationSetServerStoredAccountInfoIcqImpl
if(responseListener.success)
{
infoRetreiver.detailsChanged(uin);
+
+ fireServerStoredDetailsChangeEvent(icqProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
+ currentDetailValue,
+ newDetailValue);
+
return true;
}
else
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
index 2d94b56..0948a59 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredAccountInfoJabberImpl.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.protocol.jabber;
import java.util.*;
+import net.java.sip.communicator.service.protocol.event.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smackx.packet.*;
@@ -15,11 +16,14 @@ import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
/**
+ * The Account Info Operation set is a means of accessing and modifying detailed
+ * information on the user/account that is currently logged in through this
+ * provider.
*
* @author Damian Minkov
*/
public class OperationSetServerStoredAccountInfoJabberImpl
- implements OperationSetServerStoredAccountInfo
+ extends AbstractOperationSetServerStoredAccountInfo
{
private InfoRetreiver infoRetreiver = null;
@@ -222,8 +226,16 @@ public class OperationSetServerStoredAccountInfoJabberImpl
} catch (XMPPException xmppe)
{
xmppe.printStackTrace();
+
+ // return to skip events when there is error
+ return;
}
}
+
+ fireServerStoredDetailsChangeEvent(jabberProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
}
/**
@@ -307,6 +319,11 @@ public class OperationSetServerStoredAccountInfoJabberImpl
v1.setAvatar(((ImageDetail) newDetailValue).getBytes());
v1.save(jabberProvider.getConnection());
+ fireServerStoredDetailsChangeEvent(jabberProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
+ currentDetailValue,
+ newDetailValue);
+
return true;
} catch (XMPPException xmppe)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
index 317424b..6fbf012 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
@@ -24,8 +24,8 @@ import javax.imageio.*;
* @author Damian Minkov
*/
public class OperationSetServerStoredAccountInfoMsnImpl
- implements OperationSetServerStoredAccountInfo,
- RegistrationStateChangeListener
+ extends AbstractOperationSetServerStoredAccountInfo
+ implements RegistrationStateChangeListener
{
/**
* Logger for this class.
@@ -367,8 +367,16 @@ public class OperationSetServerStoredAccountInfoMsnImpl
} catch(Exception e)
{
logger.error("Error setting own avatar.", e);
+
+ // on error return to skip details change
+ return;
}
}
+
+ fireServerStoredDetailsChangeEvent(msnProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
}
/**
@@ -488,6 +496,11 @@ public class OperationSetServerStoredAccountInfoMsnImpl
owner.getEmail().getEmailAddress(),
b));
+ fireServerStoredDetailsChangeEvent(msnProvider,
+ ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
+ currentDetailValue,
+ newDetailValue);
+
return true;
} catch(Exception e)
{
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
index 4f5f2e2..d6b14b1 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/OperationSetServerStoredAccountInfoSipImpl.java
@@ -22,8 +22,8 @@ import java.util.*;
* @author Grigorii Balutsel
*/
public class OperationSetServerStoredAccountInfoSipImpl
- implements OperationSetServerStoredAccountInfo,
- RegistrationStateChangeListener
+ extends AbstractOperationSetServerStoredAccountInfo
+ implements RegistrationStateChangeListener
{
/**
* Logger class.
@@ -42,6 +42,11 @@ public class OperationSetServerStoredAccountInfoSipImpl
private ImageDetail accountImage;
/**
+ * Current display name if set.
+ */
+ private DisplayNameDetail displayNameDetail;
+
+ /**
* Flag whether account image is loaded.
*/
private boolean isAccountImageLoaded = false;
@@ -79,6 +84,12 @@ public class OperationSetServerStoredAccountInfoSipImpl
result.add(getAccountImage());
}
}
+ else if(DisplayNameDetail.class.isAssignableFrom(detailClass)
+ && displayNameDetail != null)
+ {
+ result.add(displayNameDetail);
+ }
+
return result.iterator();
}
@@ -104,6 +115,12 @@ public class OperationSetServerStoredAccountInfoSipImpl
result.add(getAccountImage());
}
}
+ else if(DisplayNameDetail.class.isAssignableFrom(detailClass)
+ && displayNameDetail != null)
+ {
+ result.add(displayNameDetail);
+ }
+
return result.iterator();
}
@@ -123,6 +140,12 @@ public class OperationSetServerStoredAccountInfoSipImpl
details.add(getAccountImage());
}
}
+
+ if(displayNameDetail != null)
+ {
+ details.add(displayNameDetail);
+ }
+
return details.iterator();
}
@@ -141,6 +164,9 @@ public class OperationSetServerStoredAccountInfoSipImpl
{
result.add(ImageDetail.class);
}
+
+ result.add(DisplayNameDetail.class);
+
return result.iterator();
}
@@ -156,8 +182,9 @@ public class OperationSetServerStoredAccountInfoSipImpl
public boolean isDetailClassSupported(
Class<? extends GenericDetail> detailClass)
{
- return ImageDetail.class.isAssignableFrom(detailClass) &&
- isImageDetailSupported();
+ return (ImageDetail.class.isAssignableFrom(detailClass)
+ && isImageDetailSupported())
+ || DisplayNameDetail.class.isAssignableFrom(detailClass);
}
/**
@@ -174,6 +201,11 @@ public class OperationSetServerStoredAccountInfoSipImpl
{
return 1;
}
+ else if(DisplayNameDetail.class.isAssignableFrom(detailClass))
+ {
+ return 1;
+ }
+
return 0;
}
@@ -198,6 +230,35 @@ public class OperationSetServerStoredAccountInfoSipImpl
* instances.
*/
public void addDetail(GenericDetail detail)
+ throws IllegalArgumentException,
+ OperationFailedException,
+ ArrayIndexOutOfBoundsException
+ {
+ addDetail(detail, true);
+ }
+
+ /**
+ * Adds the specified detail to the list of details registered on-line
+ * for this account.
+ *
+ * @param detail the detail that we'd like registered on the server.
+ * @param fireChangeEvents whether to fire change events.
+ * @throws IllegalArgumentException if such a detail already exists
+ * and its max instances number has
+ * been atteined or if the underlying
+ * implementation does not support
+ * setting details of the
+ * corresponding class.
+ * @throws OperationFailedException with code Network Failure if
+ * putting the new value online has
+ * failed.
+ * @throws ArrayIndexOutOfBoundsException if the number of instances
+ * currently registered by the
+ * application is already equal to
+ * the maximum number of supported
+ * instances.
+ */
+ public void addDetail(GenericDetail detail, boolean fireChangeEvents)
throws IllegalArgumentException, OperationFailedException,
ArrayIndexOutOfBoundsException
{
@@ -227,6 +288,16 @@ public class OperationSetServerStoredAccountInfoSipImpl
accountImage = imageDetail;
isAccountImageLoaded = true;
}
+ else if(DisplayNameDetail.class.isAssignableFrom(detail.getClass()))
+ {
+ displayNameDetail = (DisplayNameDetail)detail;
+ }
+
+ if(fireChangeEvents)
+ fireServerStoredDetailsChangeEvent(provider,
+ ServerStoredDetailsChangeEvent.DETAIL_ADDED,
+ null,
+ detail);
}
/**
@@ -242,6 +313,23 @@ public class OperationSetServerStoredAccountInfoSipImpl
public boolean removeDetail(GenericDetail detail)
throws OperationFailedException
{
+ return removeDetail(detail, true);
+ }
+
+ /**
+ * Removes the specified detail from the list of details stored online for
+ * this account.
+ *
+ * @param detail the detail to remove
+ * @param fireChangeEvents whether to fire change events.
+ * @return true if the specified detail existed and was successfully removed
+ * and false otherwise.
+ * @throws OperationFailedException with code Network Failure if removing
+ * the detail from the server has failed
+ */
+ private boolean removeDetail(GenericDetail detail, boolean fireChangeEvents)
+ throws OperationFailedException
+ {
boolean isFound = false;
Iterator<?> iter = getAllAvailableDetails();
while (iter.hasNext())
@@ -263,6 +351,13 @@ public class OperationSetServerStoredAccountInfoSipImpl
deleteImageDetail();
accountImage = null;
}
+
+ if(fireChangeEvents)
+ fireServerStoredDetailsChangeEvent(provider,
+ ServerStoredDetailsChangeEvent.DETAIL_REMOVED,
+ detail,
+ null);
+
return true;
}
@@ -298,8 +393,14 @@ public class OperationSetServerStoredAccountInfoSipImpl
{
return true;
}
- removeDetail(currentDetailValue);
- addDetail(newDetailValue);
+ removeDetail(currentDetailValue, false);
+ addDetail(newDetailValue, false);
+
+ fireServerStoredDetailsChangeEvent(provider,
+ ServerStoredDetailsChangeEvent.DETAIL_REPLACED,
+ currentDetailValue,
+ newDetailValue);
+
return true;
}
@@ -450,4 +551,34 @@ public class OperationSetServerStoredAccountInfoSipImpl
accountImage = null;
}
}
+
+ /**
+ * Changes the display name string.
+ */
+ void setOurDisplayName(String newDisplayName)
+ {
+ DisplayNameDetail oldDisplayName = displayNameDetail;
+ DisplayNameDetail newDisplayNameDetail
+ = new DisplayNameDetail(newDisplayName);
+
+ List<GenericDetail> alreadySetDetails = new Vector<GenericDetail>();
+ Iterator<GenericDetail> iter
+ = getDetails(newDisplayNameDetail.getClass());
+ while (iter.hasNext())
+ {
+ alreadySetDetails.add(iter.next());
+ }
+
+ try
+ {
+ if(alreadySetDetails.size() > 0)
+ replaceDetail(oldDisplayName, newDisplayNameDetail);
+ else
+ addDetail(newDisplayNameDetail);
+ }
+ catch(OperationFailedException e)
+ {
+ logger.error("Filed to set display name", e);
+ }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
index 91833ec..668e3b2 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java
@@ -2386,6 +2386,36 @@ public class ProtocolProviderServiceSipImpl
}
/**
+ * Changes the display name string.
+ *
+ * @return whether we have successfully changed the display name.
+ */
+ boolean setOurDisplayName(String newDisplayName)
+ {
+ // if we really want to change the display name
+ // and it is existing, change it.
+ if(newDisplayName != null && !ourDisplayName.equals(newDisplayName))
+ {
+ getAccountID().putAccountProperty(
+ ProtocolProviderFactory.DISPLAY_NAME,
+ newDisplayName);
+
+ ourDisplayName = newDisplayName;
+
+ OperationSetServerStoredAccountInfoSipImpl accountInfoOpSet
+ = (OperationSetServerStoredAccountInfoSipImpl)getOperationSet(
+ OperationSetServerStoredAccountInfo.class);
+
+ if(accountInfoOpSet != null)
+ accountInfoOpSet.setOurDisplayName(newDisplayName);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Returns a User Agent header that could be used for signing our requests.
*
* @return a <tt>UserAgentHeader</tt> that could be used for signing our
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
index 4ccf544..c038fae 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/SipRegistrarConnection.java
@@ -417,6 +417,15 @@ public class SipRegistrarConnection
requestedExpiration = expiresHeader.getExpires();
}
+ FromHeader fromHeader = (FromHeader) register
+ .getHeader(FromHeader.NAME);
+
+ if(fromHeader != null && fromHeader.getAddress() != null)
+ {
+ if(sipProvider.setOurDisplayName(
+ fromHeader.getAddress().getDisplayName()))
+ this.ourSipAddressOfRecord = null;
+ }
//now check if the registrar has touched our expiration timeout in its
//response. Again, check contact headers first.
diff --git a/src/net/java/sip/communicator/service/protocol/AbstractOperationSetServerStoredAccountInfo.java b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetServerStoredAccountInfo.java
new file mode 100644
index 0000000..d457a43
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/AbstractOperationSetServerStoredAccountInfo.java
@@ -0,0 +1,103 @@
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import java.util.*;
+
+/**
+ * Represents a default implementation of
+ * {@link OperationSetServerStoredAccountInfo} in order to make it easier for
+ * implementers to provide complete solutions while focusing on
+ * implementation-specific details.
+ *
+ * @author Damian Minkov
+ */
+public abstract class AbstractOperationSetServerStoredAccountInfo
+ implements OperationSetServerStoredAccountInfo
+{
+ /**
+ * The <tt>Logger</tt> used by the
+ * <tt>AbstractOperationSetPersistentPresence</tt> class and its instances
+ * for logging output.
+ */
+ private static final Logger logger =
+ Logger.getLogger(AbstractOperationSetServerStoredAccountInfo.class);
+
+ /**
+ * A list of listeners registered for
+ * <tt>ServerStoredDetailsChangeListener</tt>s.
+ */
+ private final List<ServerStoredDetailsChangeListener>
+ serverStoredDetailsListeners
+ = new ArrayList<ServerStoredDetailsChangeListener>();
+
+ /**
+ * Registers a ServerStoredDetailsChangeListener with this operation set so
+ * that it gets notifications of details change.
+ *
+ * @param listener the <tt>ServerStoredDetailsChangeListener</tt>
+ * to register.
+ */
+ public void addServerStoredDetailsChangeListener(
+ ServerStoredDetailsChangeListener listener)
+ {
+ synchronized (serverStoredDetailsListeners)
+ {
+ if (!serverStoredDetailsListeners.contains(listener))
+ serverStoredDetailsListeners.add(listener);
+ }
+ }
+
+ /**
+ * Unregisters <tt>listener</tt> so that it won't receive any further
+ * notifications upon details change.
+ *
+ * @param listener the <tt>ServerStoredDetailsChangeListener</tt>
+ * to unregister.
+ */
+ public void removeServerStoredDetailsChangeListener(
+ ServerStoredDetailsChangeListener listener)
+ {
+ synchronized (serverStoredDetailsListeners)
+ {
+ serverStoredDetailsListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Notify all listeners of the corresponding account detail
+ * change event.
+ *
+ * @param eventID the int ID of the event to dispatch
+ * @param oldValue the value that the changed property had before the change
+ * occurred.
+ * @param newValue the value that the changed property currently has (after
+ * the change has occurred).
+ */
+ public void fireServerStoredDetailsChangeEvent(
+ ProtocolProviderService source,
+ int eventID, Object oldValue, Object newValue)
+ {
+ ServerStoredDetailsChangeEvent evt
+ = new ServerStoredDetailsChangeEvent(
+ source,
+ eventID,
+ oldValue,
+ newValue);
+
+ Collection<ServerStoredDetailsChangeListener> listeners;
+ synchronized (serverStoredDetailsListeners)
+ {
+ listeners = new ArrayList<ServerStoredDetailsChangeListener>(
+ serverStoredDetailsListeners);
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Dispatching a Contact Property Change Event to"
+ + listeners.size() + " listeners. Evt=" + evt);
+
+ for (ServerStoredDetailsChangeListener listener : listeners)
+ listener.serverStoredDetailsChanged(evt);
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
index 140e812..206aa88 100644
--- a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredAccountInfo.java
@@ -9,6 +9,7 @@ package net.java.sip.communicator.service.protocol;
import java.util.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
+import net.java.sip.communicator.service.protocol.event.*;
/**
* The Account Info Operation set is a means of accessing and modifying detailed
@@ -184,4 +185,24 @@ public interface OperationSetServerStoredAccountInfo
ServerStoredDetails.GenericDetail currentDetailValue,
ServerStoredDetails.GenericDetail newDetailValue)
throws ClassCastException, OperationFailedException;
+
+ /**
+ * Registers a ServerStoredDetailsChangeListener with this operation set so
+ * that it gets notifications of details change.
+ *
+ * @param listener the <tt>ServerStoredDetailsChangeListener</tt>
+ * to register.
+ */
+ public void addServerStoredDetailsChangeListener(
+ ServerStoredDetailsChangeListener listener);
+
+ /**
+ * Unregisters <tt>listener</tt> so that it won't receive any further
+ * notifications upon details change.
+ *
+ * @param listener the <tt>ServerStoredDetailsChangeListener</tt>
+ * to unregister.
+ */
+ public void removeServerStoredDetailsChangeListener(
+ ServerStoredDetailsChangeListener listener);
}
diff --git a/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeEvent.java
new file mode 100644
index 0000000..51a24f5
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeEvent.java
@@ -0,0 +1,106 @@
+package net.java.sip.communicator.service.protocol.event;
+
+import net.java.sip.communicator.service.protocol.*;
+
+import java.util.*;
+
+/**
+ * Instances of this class represent a change in the server stored details
+ * change that triggered them.
+ *
+ * @author Damian Minkov
+ */
+public class ServerStoredDetailsChangeEvent
+ extends EventObject
+{
+ /**
+ * Indicates that the ServerStoredDetailsChangeEvent instance was triggered
+ * by adding a new detail.
+ */
+ public static final int DETAIL_ADDED = 1;
+
+ /**
+ * Indicates that the ServerStoredDetailsChangeEvent instance was triggered
+ * by the removal of an existing detail.
+ */
+ public static final int DETAIL_REMOVED = 2;
+
+ /**
+ * Indicates that the ServerStoredDetailsChangeEvent instance was triggered
+ * by the fact a detail was replaced with new value.
+ */
+ public static final int DETAIL_REPLACED = 3;
+
+ /**
+ * The event type id.
+ */
+ private final int eventID;
+
+ /**
+ * New value for property. May be null if not known.
+ * @serial
+ */
+ private Object newValue;
+
+ /**
+ * Previous value for property. May be null if not known.
+ * @serial
+ */
+ private Object oldValue;
+
+ /**
+ * Constructs a ServerStoredDetailsChangeEvent.
+ *
+ * @param source The object on which the Event initially occurred.
+ * @throws IllegalArgumentException if source is null.
+ */
+ public ServerStoredDetailsChangeEvent(
+ ProtocolProviderService source,
+ int eventID,
+ Object oldValue,
+ Object newValue)
+ {
+ super(source);
+
+ this.eventID = eventID;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ /**
+ * Returns the provider that has generated this event
+ * @return the provider that generated the event.
+ */
+ public ProtocolProviderService getProvider()
+ {
+ return (ProtocolProviderService)getSource();
+ }
+
+ /**
+ * Gets the new value for the event, expressed as an Object.
+ *
+ * @return The new value for the event, expressed as an Object.
+ */
+ public Object getNewValue()
+ {
+ return newValue;
+ }
+
+ /**
+ * Gets the old value for the event, expressed as an Object.
+ *
+ * @return The old value for the event, expressed as an Object.
+ */
+ public Object getOldValue()
+ {
+ return oldValue;
+ }
+
+ /**
+ * The event type id.
+ */
+ public int getEventID()
+ {
+ return eventID;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeListener.java b/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeListener.java
new file mode 100644
index 0000000..5d763fd
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/ServerStoredDetailsChangeListener.java
@@ -0,0 +1,18 @@
+package net.java.sip.communicator.service.protocol.event;
+
+/**
+ * Listener that is informed when a change has been made to some server
+ * stored detail.
+ *
+ * @author Damian Minkov
+ */
+public interface ServerStoredDetailsChangeListener
+{
+ /**
+ * The method is called by a ProtocolProvider implementation whenever
+ * a change in the server stored detail occurred.
+ * @param evt ServerStoredDetailsChangeEvent the event describing the detail
+ * change.
+ */
+ public void serverStoredDetailsChanged(ServerStoredDetailsChangeEvent evt);
+}