aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2012-01-18 12:14:04 +0000
committerDamian Minkov <damencho@jitsi.org>2012-01-18 12:14:04 +0000
commit22cb35dd3d39404ab31a24744b35237963307602 (patch)
treeefed1c404121feb7781c7d2d2db31d16c79bbea7
parentbfe6da5fbd7a47c0b04e710005f2041458e15b18 (diff)
downloadjitsi-22cb35dd3d39404ab31a24744b35237963307602.zip
jitsi-22cb35dd3d39404ab31a24744b35237963307602.tar.gz
jitsi-22cb35dd3d39404ab31a24744b35237963307602.tar.bz2
Fixes ui blocking displaying contact in contactlist or in the tooltip, when checking for contact server stored details like phones etc.
-rw-r--r--resources/languages/resources.properties1
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java94
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java122
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java110
-rw-r--r--src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java8
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/InfoRetreiver.java65
-rw-r--r--src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredContactInfoIcqImpl.java103
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java260
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredContactInfoJabberImpl.java90
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetServerStoredContactInfo.java24
10 files changed, 666 insertions, 211 deletions
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties
index 2a3b186..cbeaeda 100644
--- a/resources/languages/resources.properties
+++ b/resources/languages/resources.properties
@@ -274,6 +274,7 @@ service.gui.LAST=Last
service.gui.LEAVE=&Leave
service.gui.LIMIT_REACHED_FOR_IP=You have too many existing registrations from the local IP address and the {0} server doesn''t allow to open any more of them.
service.gui.LOADING_ROOMS=Loading rooms...
+service.gui.LOADING=Loading...
service.gui.LOCALLY_ON_HOLD_STATUS=Locally on hold
service.gui.LOGIN_NETWORK_ERROR=Unable to log in with account: User name: {0}, Server name: {1}, due to a network failure. Please check your network connection.
service.gui.LOGIN_GENERAL_ERROR=An error occurred while logging in with account: User name: {0}, Server name: {1}:{2}.
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
index 6947f11..d909b1b 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
@@ -314,8 +314,13 @@ public class MainToolBar
chatPanel.findFileTransferChatTransport() != null);
boolean hasPhone = false;
+ boolean hasTelephony =
+ !getOperationSetForCapabilities(
+ chatPanel.chatSession.getTransportsForOperationSet(
+ OperationSetBasicTelephony.class),
+ OperationSetBasicTelephony.class).isEmpty();
- if(contact != null)
+ if(!hasTelephony && contact != null)
{
Iterator<Contact> contacts = contact.getContacts();
while(contacts.hasNext())
@@ -324,25 +329,30 @@ public class MainToolBar
OperationSetServerStoredContactInfo infoOpSet =
c.getProtocolProvider().getOperationSet(
OperationSetServerStoredContactInfo.class);
- Iterator<GenericDetail> details = null;
+ Iterator<GenericDetail> details;
if(infoOpSet != null)
{
- details = infoOpSet.getAllDetailsForContact(c);
+ details = infoOpSet.requestAllDetailsForContact(c,
+ new DetailsListener(
+ chatPanel.chatSession, callButton));
- while(details.hasNext())
+ if(details != null)
{
- GenericDetail d = details.next();
- if(d instanceof PhoneNumberDetail &&
- !(d instanceof PagerDetail) &&
- !(d instanceof FaxDetail))
+ while(details.hasNext())
{
- PhoneNumberDetail pnd = (PhoneNumberDetail)d;
- if(pnd.getNumber() != null &&
- pnd.getNumber().length() > 0)
+ GenericDetail d = details.next();
+ if(d instanceof PhoneNumberDetail &&
+ !(d instanceof PagerDetail) &&
+ !(d instanceof FaxDetail))
{
- hasPhone = true;
- break;
+ PhoneNumberDetail pnd = (PhoneNumberDetail)d;
+ if(pnd.getNumber() != null &&
+ pnd.getNumber().length() > 0)
+ {
+ hasPhone = true;
+ break;
+ }
}
}
}
@@ -350,10 +360,7 @@ public class MainToolBar
}
}
- callButton.setEnabled(hasPhone || !getOperationSetForCapabilities(
- chatPanel.chatSession.getTransportsForOperationSet(
- OperationSetBasicTelephony.class),
- OperationSetBasicTelephony.class).isEmpty());
+ callButton.setEnabled(hasTelephony || hasPhone);
desktopSharingButton.setEnabled(!getOperationSetForCapabilities(
chatPanel.chatSession.getTransportsForOperationSet(
OperationSetDesktopSharingServer.class),
@@ -854,4 +861,57 @@ public class MainToolBar
optionsButton.setIconImage(ImageLoader.getImage(
ImageLoader.CHAT_CONFIGURE_ICON));
}
+
+ /**
+ * Listens for responses if later received deliver them.
+ * If meanwhile chat session has been changed ignore any events.
+ */
+ private class DetailsListener
+ implements OperationSetServerStoredContactInfo.DetailsResponseListener
+ {
+ private ChatSession source;
+ private JButton callButton;
+
+ /**
+ * Creates listener.
+ * @param chatSession the source chat session.
+ * @param callButton the call button.
+ */
+ DetailsListener(ChatSession chatSession, JButton callButton)
+ {
+ this.source = chatSession;
+ this.callButton = callButton;
+ }
+
+ /**
+ * Details has been retrieved.
+ * @param details the details retrieved if any.
+ */
+ public void detailsRetrieved(Iterator<GenericDetail> details)
+ {
+ if(!source.equals(chatSession))
+ return;
+
+ if(callButton.isEnabled())
+ return;
+
+ while(details.hasNext())
+ {
+ GenericDetail d = details.next();
+ if(d instanceof PhoneNumberDetail &&
+ !(d instanceof PagerDetail) &&
+ !(d instanceof FaxDetail))
+ {
+ PhoneNumberDetail pnd = (PhoneNumberDetail)d;
+ if(pnd.getNumber() != null &&
+ pnd.getNumber().length() > 0)
+ {
+ callButton.setEnabled(true);
+ return;
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
index 1b9745b..e6ab7fd 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java
@@ -193,7 +193,7 @@ public class ContactListTreeCellRenderer
/**
* The parent tree.
*/
- private JTree tree;
+ private TreeContactList tree;
/**
* Initializes the panel containing the node.
@@ -339,7 +339,7 @@ public class ContactListTreeCellRenderer
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus)
{
- this.tree = tree;
+ this.tree = (TreeContactList)tree;
this.row = row;
this.isSelected = selected;
this.treeNode = (TreeNode) value;
@@ -740,8 +740,10 @@ public class ContactListTreeCellRenderer
// call button
boolean hasPhone = false;
+ // check for phone stored in contact info only
+ // if telephony contact is missing
if(uiContact.getContactNode().getContactDescriptor().getDescriptor()
- instanceof MetaContact)
+ instanceof MetaContact && telephonyContact == null)
{
MetaContact metaContact =
(MetaContact)uiContact.getContactNode().getContactDescriptor().
@@ -754,27 +756,32 @@ public class ContactListTreeCellRenderer
OperationSetServerStoredContactInfo infoOpSet =
contact.getProtocolProvider().getOperationSet(
OperationSetServerStoredContactInfo.class);
- Iterator<GenericDetail> details = null;
+ Iterator<GenericDetail> details;
if(infoOpSet != null)
{
- details = infoOpSet.getAllDetailsForContact(contact);
+ details = infoOpSet.requestAllDetailsForContact(
+ contact,
+ new DetailsListener(treeNode, callButton, uiContact));
- while(details.hasNext())
+ if(details != null)
{
- GenericDetail d = details.next();
- if(d instanceof PhoneNumberDetail &&
- !(d instanceof PagerDetail) &&
- !(d instanceof FaxDetail))
+ while(details.hasNext())
{
- PhoneNumberDetail pnd = (PhoneNumberDetail)d;
- if(pnd.getNumber() != null &&
- pnd.getNumber().length() > 0)
+ GenericDetail d = details.next();
+ if(d instanceof PhoneNumberDetail &&
+ !(d instanceof PagerDetail) &&
+ !(d instanceof FaxDetail))
{
- hasPhone = true;
- break;
- }
- }
+ PhoneNumberDetail pnd = (PhoneNumberDetail)d;
+ if(pnd.getNumber() != null &&
+ pnd.getNumber().length() > 0)
+ {
+ hasPhone = true;
+ break;
+ }
+ }
+ }
}
}
}
@@ -1488,4 +1495,85 @@ public class ContactListTreeCellRenderer
desktopSharingButton.setPressedImage(ImageLoader.getImage(
ImageLoader.DESKTOP_BUTTON_SMALL_PRESSED));
}
+
+ /**
+ * Listens for contact details if not cached, we will receive when they
+ * are retrieved to update current call button state, if meanwhile
+ * user hasn't changed the current contact.
+ */
+ private class DetailsListener
+ implements OperationSetServerStoredContactInfo.DetailsResponseListener
+ {
+ /**
+ * The source this listener is created for, if current tree node
+ * changes ignore any event.
+ */
+ private Object source;
+
+ /**
+ * The button to change.
+ */
+ private JButton callButton;
+
+ /**
+ * The ui contact to update after changes.
+ */
+ private UIContact uiContact;
+
+ /**
+ * Create listener.
+ * @param source the contact this listener is for, if different
+ * than current ignore.
+ * @param callButton
+ * @param uiContact the contact to refresh
+ */
+ DetailsListener(Object source, JButton callButton, UIContact uiContact)
+ {
+ this.source = source;
+ this.callButton = callButton;
+ this.uiContact = uiContact;
+ }
+
+ /**
+ * Details have been retrieved.
+ * @param details the details retrieved if any.
+ */
+ public void detailsRetrieved(Iterator<GenericDetail> details)
+ {
+ // if treenode has changed ignore
+ if(!source.equals(treeNode))
+ return;
+
+ // if call button is enabled nothing to check
+ if(callButton.isEnabled())
+ return;
+
+ while(details.hasNext())
+ {
+ GenericDetail d = details.next();
+
+ if(d instanceof PhoneNumberDetail &&
+ !(d instanceof PagerDetail) &&
+ !(d instanceof FaxDetail))
+ {
+ PhoneNumberDetail pnd = (PhoneNumberDetail)d;
+ if(pnd.getNumber() != null &&
+ pnd.getNumber().length() > 0)
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ callButton.setEnabled(false);
+
+ tree.refreshContact(uiContact);
+ }
+ });
+
+ return;
+ }
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java
index 3aa1062..600f2d7 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/contactsource/MetaUIContact.java
@@ -379,7 +379,7 @@ public class MetaUIContact
*/
public ExtendedTooltip getToolTip()
{
- ExtendedTooltip tip = new ExtendedTooltip(
+ final ExtendedTooltip tip = new ExtendedTooltip(
GuiActivator.getUIService().getMainFrame(), true);
byte[] avatarImage = metaContact.getAvatar();
@@ -414,47 +414,24 @@ public class MetaUIContact
if(infoOpSet != null)
{
Iterator<GenericDetail> details =
- infoOpSet.getAllDetailsForContact(protocolContact);
-
- while(details.hasNext())
- {
- GenericDetail d = details.next();
- if(d instanceof PhoneNumberDetail &&
- !(d instanceof FaxDetail) &&
- !(d instanceof PagerDetail))
- {
- PhoneNumberDetail pnd = (PhoneNumberDetail)d;
- if(pnd.getNumber() != null &&
- pnd.getNumber().length() > 0)
+ infoOpSet.requestAllDetailsForContact(protocolContact,
+ new OperationSetServerStoredContactInfo
+ .DetailsResponseListener()
{
- String localizedType = null;
-
- if(d instanceof WorkPhoneDetail)
- {
- localizedType =
- GuiActivator.getResources().
- getI18NString(
- "service.gui.WORK_PHONE");
- }
- else if(d instanceof MobilePhoneDetail)
- {
- localizedType =
- GuiActivator.getResources().
- getI18NString(
- "service.gui.MOBILE_PHONE");
- }
- else
+ public void detailsRetrieved(
+ Iterator<GenericDetail> details)
{
- localizedType =
- GuiActivator.getResources().
- getI18NString(
- "service.gui.PHONE");
+ fillTooltipLines(tip, details);
}
-
- tip.addLine(null, pnd.getNumber() +
- " (" + localizedType + ")");
- }
- }
+ });
+
+ if(details != null)
+ fillTooltipLines(tip, details);
+ else
+ {
+ tip.addLine(null,
+ GuiActivator.getResources().
+ getI18NString("service.gui.LOADING"));
}
}
@@ -472,6 +449,61 @@ public class MetaUIContact
}
/**
+ * Fills the tooltip with details.
+ * @param tip the tooltip to fill
+ * @param details the available details.
+ */
+ private void fillTooltipLines(ExtendedTooltip tip,
+ Iterator<GenericDetail> details)
+ {
+ tip.removeAllLines();
+
+ while(details.hasNext())
+ {
+ GenericDetail d = details.next();
+ if(d instanceof PhoneNumberDetail &&
+ !(d instanceof FaxDetail) &&
+ !(d instanceof PagerDetail))
+ {
+ PhoneNumberDetail pnd = (PhoneNumberDetail)d;
+ if(pnd.getNumber() != null &&
+ pnd.getNumber().length() > 0)
+ {
+ String localizedType = null;
+
+ if(d instanceof WorkPhoneDetail)
+ {
+ localizedType =
+ GuiActivator.getResources().
+ getI18NString(
+ "service.gui.WORK_PHONE");
+ }
+ else if(d instanceof MobilePhoneDetail)
+ {
+ localizedType =
+ GuiActivator.getResources().
+ getI18NString(
+ "service.gui.MOBILE_PHONE");
+ }
+ else
+ {
+ localizedType =
+ GuiActivator.getResources().
+ getI18NString(
+ "service.gui.PHONE");
+ }
+
+ tip.addLine(null, (pnd.getNumber() +
+ " (" + localizedType + ")"));
+ }
+ }
+ }
+
+ tip.validate();
+ tip.repaint();
+ }
+
+ /**
* Returns the corresponding <tt>ContactNode</tt> in the contact list
* component data model.
* @return the corresponding <tt>ContactNode</tt>
diff --git a/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java b/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java
index 5bb62b7..7beac81 100644
--- a/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/ExtendedTooltip.java
@@ -197,6 +197,14 @@ public class ExtendedTooltip
}
/**
+ * Clear all lines.
+ */
+ public void removeAllLines()
+ {
+ linesPanel.removeAll();
+ }
+
+ /**
* Sets the text that would appear on the bottom of the tooltip.
* @param text the text to set
*/
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/InfoRetreiver.java b/src/net/java/sip/communicator/impl/protocol/icq/InfoRetreiver.java
index c9c1d7a..16b9986 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/InfoRetreiver.java
+++ b/src/net/java/sip/communicator/impl/protocol/icq/InfoRetreiver.java
@@ -113,37 +113,62 @@ public class InfoRetreiver
*/
protected List<GenericDetail> getContactDetails(String uin)
{
- List<GenericDetail> result = retreivedDetails.get(uin);
+ List<GenericDetail> result = getCachedContactDetails(uin);
if(result == null)
{
- int reqID = requestID++;
+ return retrieveDetails(uin);
+ }
+
+ return result;
+ }
- //retrieve the details
- long toICQUin = Long.parseLong(uin);
- MetaFullInfoRequest infoRequest =
- new MetaFullInfoRequest(
- Long.parseLong(ownerUin),
- reqID,
- toICQUin);
+ /**
+ * Retrieve details and return them or if missing return an empty list.
+ * @param uin the uin to search for.
+ * @return the details or empty list.
+ */
+ protected List<GenericDetail> retrieveDetails(String uin)
+ {
+ int reqID = requestID++;
- UserInfoResponseRetriever responseRetriever =
- new UserInfoResponseRetriever(reqID);
+ //retrieve the details
+ long toICQUin = Long.parseLong(uin);
+ MetaFullInfoRequest infoRequest =
+ new MetaFullInfoRequest(
+ Long.parseLong(ownerUin),
+ reqID,
+ toICQUin);
- icqProvider.getAimConnection().getInfoService().getOscarConnection()
- .sendSnacRequest(infoRequest, responseRetriever);
+ UserInfoResponseRetriever responseRetriever =
+ new UserInfoResponseRetriever(reqID);
- responseRetriever.waitForLastInfo(60000);
+ icqProvider.getAimConnection().getInfoService().getOscarConnection()
+ .sendSnacRequest(infoRequest, responseRetriever);
- result = responseRetriever.result;
+ responseRetriever.waitForLastInfo(60000);
- if (result == null)
- result = new LinkedList<GenericDetail>();
+ List<GenericDetail> result = responseRetriever.result;
- retreivedDetails.put(uin, result);
- }
+ if (result == null)
+ result = new LinkedList<GenericDetail>();
- return new LinkedList<GenericDetail>(result);
+ // put even empty result to bypass further retrieve
+ retreivedDetails.put(uin, responseRetriever.result);
+
+ return responseRetriever.result;
+ }
+
+ /**
+ * Request the full info for the given uin if available in cache,
+ * if missing return null.
+ *
+ * @param uin to search for in cache.
+ * @return list of details.
+ */
+ protected List<GenericDetail> getCachedContactDetails(String uin)
+ {
+ return retreivedDetails.get(uin);
}
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredContactInfoIcqImpl.java b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredContactInfoIcqImpl.java
index 9811d85..664061e 100644
--- a/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredContactInfoIcqImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/icq/OperationSetServerStoredContactInfoIcqImpl.java
@@ -10,6 +10,7 @@ import java.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
+import net.java.sip.communicator.util.*;
/**
* @author Damian Minkov
@@ -17,7 +18,21 @@ import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
public class OperationSetServerStoredContactInfoIcqImpl
implements OperationSetServerStoredContactInfo
{
+ /**
+ * The logger.
+ */
+ private static final Logger logger =
+ Logger.getLogger(OperationSetServerStoredContactInfoIcqImpl.class);
+
private InfoRetreiver infoRetreiver;
+
+ /**
+ * If we got several listeners for the same contact lets retrieve once
+ * but deliver result to all.
+ */
+ private Hashtable<String, List<DetailsResponseListener>>
+ listenersForDetails =
+ new Hashtable<String, List<DetailsResponseListener>>();
/**
* The icq provider that created us.
@@ -126,4 +141,92 @@ public class OperationSetServerStoredContactInfoIcqImpl
"The icq provider must be signed on the ICQ service before "
+"being able to communicate.");
}
+
+ /**
+ * Requests all details existing for the specified contact.
+ * @param contact the specified contact
+ * @return a java.util.Iterator over all details existing for the specified
+ * contact.
+ */
+ public Iterator<GenericDetail> requestAllDetailsForContact(
+ final Contact contact, final DetailsResponseListener listener)
+ {
+ assertConnected();
+
+ List<GenericDetail> res =
+ infoRetreiver.getCachedContactDetails(contact.getAddress());
+
+ if(res != null)
+ {
+ if(contact.getImage() != null)
+ {
+ res.add(new ServerStoredDetails.ImageDetail(
+ "Image", contact.getImage()));
+ }
+ return res.iterator();
+ }
+
+ synchronized(listenersForDetails)
+ {
+ List<DetailsResponseListener> ls =
+ listenersForDetails.get(contact.getAddress());
+
+ boolean isFirst = false;
+ if(ls == null)
+ {
+ ls = new ArrayList<DetailsResponseListener>();
+ isFirst = true;
+ listenersForDetails.put(contact.getAddress(), ls);
+ }
+
+ if(!ls.contains(listener))
+ ls.add(listener);
+
+ // there is already scheduled retrieve, will deliver at listener.
+ if(!isFirst)
+ return null;
+ }
+
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ List<GenericDetail> result =
+ infoRetreiver.retrieveDetails(contact.getAddress());
+
+ if(contact.getImage() != null)
+ {
+ result.add(new ServerStoredDetails.ImageDetail(
+ "Image", contact.getImage()));
+ }
+
+ List<DetailsResponseListener> listeners;
+
+ synchronized(listenersForDetails)
+ {
+ listeners =
+ listenersForDetails.remove(contact.getAddress());
+ }
+
+ if(listeners == null)
+ return;
+
+ for(DetailsResponseListener l : listeners)
+ {
+ try
+ {
+ l.detailsRetrieved(result.iterator());
+ }
+ catch(Throwable t)
+ {
+ logger.error(
+ "Error delivering for retrieved details", t);
+ }
+ }
+ }
+ }, getClass().getName() + ".RetrieveDetails").start();
+
+ // return null as there is no cache and we will try to retrieve
+ return null;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
index 695b488..808a124 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/InfoRetreiver.java
@@ -102,162 +102,186 @@ public class InfoRetreiver
*/
List<GenericDetail> getContactDetails(String contactAddress)
{
- List<GenericDetail> result = retreivedDetails.get(contactAddress);
+ List<GenericDetail> result = getCachedContactDetails(contactAddress);
if(result == null)
{
- result = new LinkedList<GenericDetail>();
- try
- {
- XMPPConnection connection = jabberProvider.getConnection();
+ return retrieveDetails(contactAddress);
+ }
- if(connection == null || !connection.isAuthenticated())
- return null;
+ return result;
+ }
- VCard card = new VCard();
- card.load(connection, contactAddress);
+ /**
+ * Retrieve details and return them or if missing return an empty list.
+ * @param contactAddress the address to search for.
+ * @return the details or empty list.
+ */
+ protected List<GenericDetail> retrieveDetails(String contactAddress)
+ {
+ List<GenericDetail> result = new LinkedList<GenericDetail>();
+ try
+ {
+ XMPPConnection connection = jabberProvider.getConnection();
- String tmp = null;
+ if(connection == null || !connection.isAuthenticated())
+ return null;
- tmp = checkForFullName(card);
- if(tmp != null)
- result.add(new ServerStoredDetails.DisplayNameDetail(tmp));
+ VCard card = new VCard();
+ card.load(connection, contactAddress);
- tmp = card.getFirstName();
- if(tmp != null)
- result.add(new ServerStoredDetails.FirstNameDetail(tmp));
+ String tmp;
- tmp = card.getMiddleName();
- if(tmp != null)
- result.add(new ServerStoredDetails.MiddleNameDetail(tmp));
+ tmp = checkForFullName(card);
+ if(tmp != null)
+ result.add(new ServerStoredDetails.DisplayNameDetail(tmp));
- tmp = card.getLastName();
- if(tmp != null)
- result.add(new ServerStoredDetails.LastNameDetail(tmp));
+ tmp = card.getFirstName();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.FirstNameDetail(tmp));
- tmp = card.getNickName();
- if(tmp != null)
- result.add(new ServerStoredDetails.NicknameDetail(tmp));
+ tmp = card.getMiddleName();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.MiddleNameDetail(tmp));
- // Home Details
- // addrField one of
- // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
- // LOCALITY, REGION, PCODE, CTRY
- tmp = card.getAddressFieldHome("STREET");
- if(tmp != null)
- result.add(new ServerStoredDetails.AddressDetail(tmp));
+ tmp = card.getLastName();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.LastNameDetail(tmp));
- tmp = card.getAddressFieldHome("LOCALITY");
- if(tmp != null)
- result.add(new ServerStoredDetails.CityDetail(tmp));
+ tmp = card.getNickName();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.NicknameDetail(tmp));
- tmp = card.getAddressFieldHome("REGION");
- if(tmp != null)
- result.add(new ServerStoredDetails.ProvinceDetail(tmp));
+ // Home Details
+ // addrField one of
+ // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
+ // LOCALITY, REGION, PCODE, CTRY
+ tmp = card.getAddressFieldHome("STREET");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.AddressDetail(tmp));
- tmp = card.getAddressFieldHome("PCODE");
- if(tmp != null)
- result.add(new ServerStoredDetails.PostalCodeDetail(tmp));
+ tmp = card.getAddressFieldHome("LOCALITY");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.CityDetail(tmp));
+
+ tmp = card.getAddressFieldHome("REGION");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.ProvinceDetail(tmp));
+
+ tmp = card.getAddressFieldHome("PCODE");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.PostalCodeDetail(tmp));
// tmp = card.getAddressFieldHome("CTRY");
// if(tmp != null)
// result.add(new ServerStoredDetails.CountryDetail(tmp);
- // phoneType one of
- //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
+ // phoneType one of
+ //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
- tmp = card.getPhoneHome("VOICE");
- if(tmp != null)
- result.add(new ServerStoredDetails.PhoneNumberDetail(tmp));
+ tmp = card.getPhoneHome("VOICE");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.PhoneNumberDetail(tmp));
- tmp = card.getPhoneHome("FAX");
- if(tmp != null)
- result.add(new ServerStoredDetails.FaxDetail(tmp));
+ tmp = card.getPhoneHome("FAX");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.FaxDetail(tmp));
- tmp = card.getPhoneHome("PAGER");
- if(tmp != null)
- result.add(new ServerStoredDetails.PagerDetail(tmp));
+ tmp = card.getPhoneHome("PAGER");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.PagerDetail(tmp));
- tmp = card.getPhoneHome("CELL");
- if(tmp != null)
- result.add(new ServerStoredDetails.MobilePhoneDetail(tmp));
+ tmp = card.getPhoneHome("CELL");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.MobilePhoneDetail(tmp));
- tmp = card.getEmailHome();
- if(tmp != null)
- result.add(new ServerStoredDetails.EmailAddressDetail(tmp));
+ tmp = card.getEmailHome();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.EmailAddressDetail(tmp));
- // Work Details
- // addrField one of
- // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
- // LOCALITY, REGION, PCODE, CTRY
- tmp = card.getAddressFieldWork("STREET");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkAddressDetail(tmp));
+ // Work Details
+ // addrField one of
+ // POSTAL, PARCEL, (DOM | INTL), PREF, POBOX, EXTADR, STREET,
+ // LOCALITY, REGION, PCODE, CTRY
+ tmp = card.getAddressFieldWork("STREET");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkAddressDetail(tmp));
- tmp = card.getAddressFieldWork("LOCALITY");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkCityDetail(tmp));
+ tmp = card.getAddressFieldWork("LOCALITY");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkCityDetail(tmp));
- tmp = card.getAddressFieldWork("REGION");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkProvinceDetail(tmp));
+ tmp = card.getAddressFieldWork("REGION");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkProvinceDetail(tmp));
- tmp = card.getAddressFieldWork("PCODE");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkPostalCodeDetail(tmp));
+ tmp = card.getAddressFieldWork("PCODE");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkPostalCodeDetail(tmp));
// tmp = card.getAddressFieldWork("CTRY");
// if(tmp != null)
// result.add(new ServerStoredDetails.WorkCountryDetail(tmp);
- // phoneType one of
- //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
-
- tmp = card.getPhoneWork("VOICE");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkPhoneDetail(tmp));
-
- tmp = card.getPhoneWork("FAX");
- if(tmp != null)
- result.add(new WorkFaxDetail(tmp));
-
- tmp = card.getPhoneWork("PAGER");
- if(tmp != null)
- result.add(new WorkPagerDetail(tmp));
-
- tmp = card.getPhoneWork("CELL");
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkMobilePhoneDetail(tmp));
-
-
- tmp = card.getEmailWork();
- if(tmp != null)
- result.add(new ServerStoredDetails.EmailAddressDetail(tmp));
-
- tmp = card.getOrganization();
- if(tmp != null)
- result.add(new ServerStoredDetails.WorkOrganizationNameDetail(tmp));
-
- tmp = card.getOrganizationUnit();
- if(tmp != null)
- result.add(new WorkDepartmentNameDetail(tmp));
-
- byte[] imageBytes = card.getAvatar();
- if(imageBytes != null && imageBytes.length > 0)
- result.add(new ServerStoredDetails.ImageDetail(
- "Image", imageBytes));
- }
- catch (Exception exc)
- {
- logger.error("Cannot load details for contact "
- + this + " : " + exc.getMessage()
- , exc);
- }
+ // phoneType one of
+ //VOICE, FAX, PAGER, MSG, CELL, VIDEO, BBS, MODEM, ISDN, PCS, PREF
+
+ tmp = card.getPhoneWork("VOICE");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkPhoneDetail(tmp));
+
+ tmp = card.getPhoneWork("FAX");
+ if(tmp != null)
+ result.add(new WorkFaxDetail(tmp));
+
+ tmp = card.getPhoneWork("PAGER");
+ if(tmp != null)
+ result.add(new WorkPagerDetail(tmp));
+
+ tmp = card.getPhoneWork("CELL");
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkMobilePhoneDetail(tmp));
+
+
+ tmp = card.getEmailWork();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.EmailAddressDetail(tmp));
+
+ tmp = card.getOrganization();
+ if(tmp != null)
+ result.add(new ServerStoredDetails.WorkOrganizationNameDetail(tmp));
+
+ tmp = card.getOrganizationUnit();
+ if(tmp != null)
+ result.add(new WorkDepartmentNameDetail(tmp));
+
+ byte[] imageBytes = card.getAvatar();
+ if(imageBytes != null && imageBytes.length > 0)
+ result.add(new ServerStoredDetails.ImageDetail(
+ "Image", imageBytes));
+ }
+ catch (Throwable exc)
+ {
+ logger.error("Cannot load details for contact "
+ + this + " : " + exc.getMessage()
+ , exc);
}
retreivedDetails.put(contactAddress, result);
- return new LinkedList<GenericDetail>(result);
+ return result;
+ }
+
+ /**
+ * request the full info for the given contactAddress if available
+ * in cache.
+ *
+ * @param contactAddress to search for
+ * @return list of the details if any.
+ */
+ List<GenericDetail> getCachedContactDetails(String contactAddress)
+ {
+ return retreivedDetails.get(contactAddress);
}
private String checkForFullName(VCard card)
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredContactInfoJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredContactInfoJabberImpl.java
index 11d770c..e900d6e 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredContactInfoJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetServerStoredContactInfoJabberImpl.java
@@ -10,6 +10,7 @@ import java.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
+import net.java.sip.communicator.util.*;
/**
* @author Damian Minkov
@@ -17,8 +18,22 @@ import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
public class OperationSetServerStoredContactInfoJabberImpl
implements OperationSetServerStoredContactInfo
{
+ /**
+ * The logger.
+ */
+ private static final Logger logger =
+ Logger.getLogger(OperationSetServerStoredContactInfoJabberImpl.class);
+
private InfoRetreiver infoRetreiver = null;
+ /**
+ * If we got several listeners for the same contact lets retrieve once
+ * but deliver result to all.
+ */
+ private Hashtable<String, List<DetailsResponseListener>>
+ listenersForDetails =
+ new Hashtable<String, List<DetailsResponseListener>>();
+
protected OperationSetServerStoredContactInfoJabberImpl(
InfoRetreiver infoRetreiver)
{
@@ -96,4 +111,79 @@ public class OperationSetServerStoredContactInfoJabberImpl
else
return new LinkedList<GenericDetail>(details).iterator();
}
+
+ /**
+ * Requests all details existing for the specified contact.
+ * @param contact the specified contact
+ * @return a java.util.Iterator over all details existing for the specified
+ * contact.
+ */
+ public Iterator<GenericDetail> requestAllDetailsForContact(
+ final Contact contact, DetailsResponseListener listener)
+ {
+ List<GenericDetail> res =
+ infoRetreiver.getCachedContactDetails(contact.getAddress());
+
+ if(res != null)
+ {
+ return res.iterator();
+ }
+
+ synchronized(listenersForDetails)
+ {
+ List<DetailsResponseListener> ls =
+ listenersForDetails.get(contact.getAddress());
+
+ boolean isFirst = false;
+ if(ls == null)
+ {
+ ls = new ArrayList<DetailsResponseListener>();
+ isFirst = true;
+ listenersForDetails.put(contact.getAddress(), ls);
+ }
+
+ if(!ls.contains(listener))
+ ls.add(listener);
+
+ // there is already scheduled retrieve, will deliver at listener.
+ if(!isFirst)
+ return null;
+ }
+
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ List<GenericDetail> result =
+ infoRetreiver.retrieveDetails(contact.getAddress());
+
+ List<DetailsResponseListener> listeners;
+
+ synchronized(listenersForDetails)
+ {
+ listeners =
+ listenersForDetails.remove(contact.getAddress());
+ }
+
+ if(listeners == null)
+ return;
+
+ for(DetailsResponseListener l : listeners)
+ {
+ try
+ {
+ l.detailsRetrieved(result.iterator());
+ }
+ catch(Throwable t)
+ {
+ logger.error(
+ "Error delivering for retrieved details", t);
+ }
+ }
+ }
+ }, getClass().getName() + ".RetrieveDetails").start();
+
+ // return null as there is no cache and we will try to retrieve
+ return null;
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredContactInfo.java b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredContactInfo.java
index 48056cc..d81d33c 100644
--- a/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredContactInfo.java
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetServerStoredContactInfo.java
@@ -80,4 +80,28 @@ public interface OperationSetServerStoredContactInfo
* contact.
*/
public Iterator<GenericDetail> getAllDetailsForContact(Contact contact);
+
+ /**
+ * Requests all details existing for the specified contact.
+ * @param contact the specified contact
+ * @return a java.util.Iterator over all details existing for the specified
+ * contact. If there are missing in the local cache null value will
+ * be returned and they will be scheduled for retrieve.
+ * The <tt>listener</tt> will be used to inform that retrieve has finished.
+ */
+ public Iterator<GenericDetail> requestAllDetailsForContact(
+ Contact contact, DetailsResponseListener listener);
+
+ /**
+ * Retrieving details can take some time, this listener will inform
+ * when retrieving has ended and will return the details if any.
+ */
+ public interface DetailsResponseListener
+ {
+ /**
+ * Informs for details retrieved.
+ * @param detailIterator the details retrieved if any.
+ */
+ public void detailsRetrieved(Iterator<GenericDetail> detailIterator);
+ }
}