/* * 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; import java.util.*; import net.java.sip.communicator.util.*; /** * The AccountID is an account identifier that, uniquely represents a specific * user account over a specific protocol. The class needs to be extended by * every protocol implementation because of its protected * constructor. The reason why this constructor is protected is mostly avoiding * confusion and letting people (using the protocol provider service) believe * that they are the ones who are supposed to instantiate the accountid class. * <p> * Every instance of the <tt>ProtocolProviderService</tt>, created through the * ProtocolProviderFactory is assigned an AccountID instance, that uniquely * represents it and whose string representation (obtained through the * getAccountUID() method) can be used for identification of persistently stored * account details. * <p> * Account id's are guaranteed to be different for different accounts and in the * same time are bound to be equal for multiple installations of the same * account. * * @author Emil Ivov * @author Lubomir Marinov */ public abstract class AccountID { private static final Logger logger = Logger.getLogger(AccountID.class); /** * Allows a specific set of account properties to override a given default * protocol name (e.g. account registration wizards which want to present a * well-known protocol name associated with the account that is different * from the name of the effective protocol). * <p> * Note: The logic of the SIP protocol implementation at the time of this * writing modifies <tt>accountProperties</tt> to contain the default * protocol name if an override hasn't been defined. Since the desire is to * enable all account registration wizards to override the protocol name, * the current implementation places the specified * <tt>defaultProtocolName</tt> in a similar fashion. * </p> * * @param accountProperties a Map containing any other protocol and * implementation specific account initialization properties * @param defaultProtocolName the protocol name to be used in case * <tt>accountProperties</tt> doesn't provide an overriding value * @return */ private static final String getOverriddenProtocolName( Map accountProperties, String defaultProtocolName) { String key = ProtocolProviderFactory.PROTOCOL; String protocolName = (String) accountProperties.get(key); if ((protocolName == null) && (defaultProtocolName != null)) { protocolName = defaultProtocolName; accountProperties.put(key, protocolName); } return protocolName; } /** * Contains all implementation specific properties that define the account. * The exact names of the keys are protocol (and sometimes implementation) * specific. * Currently, only String property keys and values will get properly stored. * If you need something else, please consider converting it through custom * accessors (get/set) in your implementation. */ protected Map accountProperties = null; /** * A String uniquely identifying the user for this particular account. */ protected String userID = null; /** * A String uniquely identifying this account, that can also be used for * storing and unambiguously retrieving details concerning it. */ protected String accountUID = null; /** * The name of the service that defines the context for this account. */ protected String serviceName = null; /** * Creates an account id for the specified provider userid and * accountProperties. * @param userID a String that uniquely identifies the user. * @param accountProperties a Map containing any other protocol and * implementation specific account initialization properties * @param protocolName the name of the protocol implemented by the provider * that this id is meant for. * @param serviceName the name of the service (e.g. iptel.org, jabber.org, * icq.com) that this account is registered with. */ protected AccountID( String userID, Map accountProperties, String protocolName, String serviceName) { /* * Allow account registration wizards to override the default protocol * name through accountProperties for the purposes of presenting a * well-known protocol name associated with the account that is * different from the name of the effective protocol. */ protocolName = getOverriddenProtocolName(accountProperties, protocolName); this.userID = userID; this.accountProperties = new Hashtable(accountProperties); this.serviceName = serviceName; //create a unique identifier string this.accountUID = protocolName + ":" + userID + "@" + ((serviceName == null)? "":serviceName); } /** * Returns the user id associated with this account. * * @return A String identifying the user inside this particular service. */ public String getUserID() { return userID; } /** * Returns a name that can be displayed to the user when referring to this * account. * * @return A String identifying the user inside this particular service. */ public String getDisplayName() { String returnValue = getUserID(); String protocolName = getAccountPropertyString(ProtocolProviderFactory.PROTOCOL); if (protocolName != null && protocolName.trim().length() > 0) returnValue += " (" + protocolName + ")"; return returnValue; } /** * Returns a String uniquely identifying this account, guaranteed to remain * the same across multiple installations of the same account and to always * be unique for differing accounts. * @return String */ public String getAccountUniqueID() { return accountUID; } /** * Returns a Map containing protocol and implementation account * initialization properties. * @return a Map containing protocol and implementation account * initialization properties. */ public Map getAccountProperties() { return new Hashtable(accountProperties); } public Object getAccountProperty(Object key) { return accountProperties.get(key); } public boolean getAccountPropertyBoolean(Object key, boolean defaultValue) { String value = getAccountPropertyString(key); return (value == null) ? defaultValue : Boolean.parseBoolean(value); } public int getAccountPropertyInt(Object key, int defaultValue) { String stringValue = getAccountPropertyString(key); int intValue = defaultValue; if (stringValue != null) { try { intValue = Integer.parseInt(stringValue); } catch (NumberFormatException ex) { logger.error("Failed to parse account property " + key + " value " + stringValue + " as an integer", ex); } } return intValue; } public String getAccountPropertyString(Object key) { Object value = getAccountProperty(key); return (value == null) ? null : value.toString(); } /** * Adds a property to the map of properties for this account identifier. * * @param key the key of the property * @param value the property value */ public void putAccountProperty(Object key, Object value) { accountProperties.put(key, value); } /** * Returns a hash code value for the object. This method is * supported for the benefit of hashtables such as those provided by * <tt>java.util.Hashtable</tt>. * <p> * @return a hash code value for this object. * @see java.lang.Object#equals(java.lang.Object) * @see java.util.Hashtable */ public int hashCode() { return (accountUID == null)? 0 : accountUID.hashCode(); } /** * Indicates whether some other object is "equal to" this account id. * <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. * @see #hashCode() * @see java.util.Hashtable */ @Override public boolean equals(Object obj) { if (this == obj) return true; if( obj == null || ! (getClass().isInstance(obj)) || ! (userID.equals(((AccountID)obj).userID))) return false; return true; } /** * Returns a string representation of this account id (same as calling * getAccountUniqueID()). * * @return a string representation of this account id. */ public String toString() { return getAccountUniqueID(); } /** * Returns the name of the service that defines the context for this * account. Often this name would be an sqdn or even an ipaddress but this * would not always be the case (e.g. p2p providers may return a name that * does not directly correspond to an IP address or host name). * <p> * @return the name of the service that defines the context for this * account. */ public String getService() { return this.serviceName; } /** * Returns a string that could be directly used (or easily converted to) an * address that other users of the protocol can use to communicate with us. * By default this string is set to userid@servicename. Protocol * implementors should override it if they'd need it to respect a different * syntax. * * @return a String in the form of userid@service that other protocol users * should be able to parse into a meaningful address and use it to * communicate with us. */ public String getAccountAddress() { String userID = getUserID(); return (userID.indexOf('@') > 0) ? userID : (userID + "@" + getService()); } /** * Set the account properties. * * @param accountProperties the properties of the account */ public void setAccountProperties(Map accountProperties) { this.accountProperties = accountProperties; } }