aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java')
-rw-r--r--src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java2609
1 files changed, 1309 insertions, 1300 deletions
diff --git a/src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java b/src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java
index 7e8b9c8..561a092 100644
--- a/src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java
+++ b/src/net/java/sip/communicator/service/protocol/ProtocolProviderFactory.java
@@ -1,4 +1,4 @@
-/*
+/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
@@ -15,1302 +15,1311 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package net.java.sip.communicator.service.protocol;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.credentialsstorage.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.configuration.*;
-import org.osgi.framework.*;
-
-/**
- * The ProtocolProviderFactory is what actually creates instances of a
- * ProtocolProviderService implementation. A provider factory would register,
- * persistently store, and remove when necessary, ProtocolProviders. The way
- * things are in the SIP Communicator, a user account is represented (in a 1:1
- * relationship) by an AccountID and a ProtocolProvider. In other words - one
- * would have as many protocol providers installed in a given moment as they
- * would user account registered through the various services.
- *
- * @author Emil Ivov
- * @author Lubomir Marinov
- */
-public abstract class ProtocolProviderFactory
-{
- /**
- * The <tt>Logger</tt> used by the <tt>ProtocolProviderFactory</tt> class
- * and its instances for logging output.
- */
- private static final Logger logger
- = Logger.getLogger(ProtocolProviderFactory.class);
-
- /**
- * Then name of a property which represents a password.
- */
- public static final String PASSWORD = "PASSWORD";
-
- /**
- * The name of a property representing the name of the protocol for an
- * ProtocolProviderFactory.
- */
- public static final String PROTOCOL = "PROTOCOL_NAME";
-
- /**
- * The name of a property representing the path to protocol icons.
- */
- public static final String PROTOCOL_ICON_PATH = "PROTOCOL_ICON_PATH";
-
- /**
- * The name of a property representing the path to the account icon to
- * be used in the user interface, when the protocol provider service is not
- * available.
- */
- public static final String ACCOUNT_ICON_PATH = "ACCOUNT_ICON_PATH";
-
- /**
- * The name of a property which represents the AccountID of a
- * ProtocolProvider and that, together with a password is used to login
- * on the protocol network..
- */
- public static final String USER_ID = "USER_ID";
-
- /**
- * The name that should be displayed to others when we are calling or
- * writing them.
- */
- public static final String DISPLAY_NAME = "DISPLAY_NAME";
-
- /**
- * The name that should be displayed to the user on call via and chat via
- * lists.
- */
- public static final String ACCOUNT_DISPLAY_NAME = "ACCOUNT_DISPLAY_NAME";
-
- /**
- * The name of the property under which we store protocol AccountID-s.
- */
- public static final String ACCOUNT_UID = "ACCOUNT_UID";
-
- /**
- * The name of the property under which we store protocol the address of
- * a protocol centric entity (any protocol server).
- */
- public static final String SERVER_ADDRESS = "SERVER_ADDRESS";
-
- /**
- * The name of the property under which we store the number of the port
- * where the server stored against the SERVER_ADDRESS property is expecting
- * connections to be made via this protocol.
- */
- public static final String SERVER_PORT = "SERVER_PORT";
-
- /**
- * The name of the property under which we store the name of the transport
- * protocol that needs to be used to access the server.
- */
- public static final String SERVER_TRANSPORT = "SERVER_TRANSPORT";
-
- /**
- * The name of the property under which we store protocol the address of
- * a protocol proxy.
- */
- public static final String PROXY_ADDRESS = "PROXY_ADDRESS";
-
- /**
- * The name of the property under which we store the number of the port
- * where the proxy stored against the PROXY_ADDRESS property is expecting
- * connections to be made via this protocol.
- */
- public static final String PROXY_PORT = "PROXY_PORT";
-
- /**
- * The name of the property which defines whether proxy is auto configured
- * by the protocol by using known methods such as specific DNS queries.
- */
- public static final String PROXY_AUTO_CONFIG = "PROXY_AUTO_CONFIG";
-
- /**
- * The property indicating the preferred UDP and TCP
- * port to bind to for clear communications.
- */
- public static final String PREFERRED_CLEAR_PORT_PROPERTY_NAME
- = "net.java.sip.communicator.SIP_PREFERRED_CLEAR_PORT";
-
- /**
- * The property indicating the preferred TLS (TCP)
- * port to bind to for secure communications.
- */
- public static final String PREFERRED_SECURE_PORT_PROPERTY_NAME
- = "net.java.sip.communicator.SIP_PREFERRED_SECURE_PORT";
-
- /**
- * The name of the property under which we store the the type of the proxy
- * stored against the PROXY_ADDRESS property. Exact type values depend on
- * protocols and among them are socks4, socks5, http and possibly others.
- */
- public static final String PROXY_TYPE = "PROXY_TYPE";
-
- /**
- * The name of the property under which we store the the username for the
- * proxy stored against the PROXY_ADDRESS property.
- */
- public static final String PROXY_USERNAME = "PROXY_USERNAME";
-
- /**
- * The name of the property under which we store the the authorization name
- * for the proxy stored against the PROXY_ADDRESS property.
- */
- public static final String AUTHORIZATION_NAME = "AUTHORIZATION_NAME";
-
- /**
- * The name of the property under which we store the password for the proxy
- * stored against the PROXY_ADDRESS property.
- */
- public static final String PROXY_PASSWORD = "PROXY_PASSWORD";
-
- /**
- * The name of the property under which we store the name of the transport
- * protocol that needs to be used to access the proxy.
- */
- public static final String PROXY_TRANSPORT = "PROXY_TRANSPORT";
-
- /**
- * The name of the property that indicates whether loose routing should be
- * forced for all traffic in an account, rather than routing through an
- * outbound proxy which is the default for Jitsi.
- */
- public static final String FORCE_PROXY_BYPASS = "FORCE_PROXY_BYPASS";
-
- /**
- * The name of the property that indicates whether the client must
- * be registered with a registrar when making outgoing calls.
- */
- public static final String MUST_REGISTER_TO_CALL = "MUST_REGISTER_TO_CALL";
-
- /**
- * The name of the property under which we store the user preference for a
- * transport protocol to use (i.e. tcp or udp).
- */
- public static final String PREFERRED_TRANSPORT = "PREFERRED_TRANSPORT";
-
- /**
- * The name of the property under which we store whether we generate
- * resource values or we just use the stored one.
- */
- public static final String AUTO_GENERATE_RESOURCE = "AUTO_GENERATE_RESOURCE";
-
- /**
- * The name of the property under which we store resources such as the
- * jabber resource property.
- */
- public static final String RESOURCE = "RESOURCE";
-
- /**
- * The name of the property under which we store resource priority.
- */
- public static final String RESOURCE_PRIORITY = "RESOURCE_PRIORITY";
-
- /**
- * The name of the property which defines that the call is encrypted by
- * default
- */
- public static final String DEFAULT_ENCRYPTION = "DEFAULT_ENCRYPTION";
-
- /**
- * The name of the property that indicates the encryption protocols for this
- * account.
- */
- public static final String ENCRYPTION_PROTOCOL = "ENCRYPTION_PROTOCOL";
-
- /**
- * The name of the property that indicates the status (enabed or disabled)
- * encryption protocols for this account.
- */
- public static final String ENCRYPTION_PROTOCOL_STATUS
- = "ENCRYPTION_PROTOCOL_STATUS";
-
- /**
- * The name of the property which defines if to include the ZRTP attribute
- * to SIP/SDP
- */
- public static final String DEFAULT_SIPZRTP_ATTRIBUTE =
- "DEFAULT_SIPZRTP_ATTRIBUTE";
-
- /**
- * The name of the property which defines the ID of the client TLS
- * certificate configuration entry.
- */
- public static final String CLIENT_TLS_CERTIFICATE =
- "CLIENT_TLS_CERTIFICATE";
-
- /**
- * The name of the property under which we store the boolean value
- * indicating if the user name should be automatically changed if the
- * specified name already exists. This property is meant to be used by IRC
- * implementations.
- */
- public static final String AUTO_CHANGE_USER_NAME = "AUTO_CHANGE_USER_NAME";
-
- /**
- * The name of the property under which we store the boolean value
- * indicating if a password is required. Initially this property is meant to
- * be used by IRC implementations.
- */
- public static final String NO_PASSWORD_REQUIRED = "NO_PASSWORD_REQUIRED";
-
- /**
- * The name of the property under which we store if the presence is enabled.
- */
- public static final String IS_PRESENCE_ENABLED = "IS_PRESENCE_ENABLED";
-
- /**
- * The name of the property under which we store if the p2p mode for SIMPLE
- * should be forced.
- */
- public static final String FORCE_P2P_MODE = "FORCE_P2P_MODE";
-
- /**
- * The name of the property under which we store the offline contact polling
- * period for SIMPLE.
- */
- public static final String POLLING_PERIOD = "POLLING_PERIOD";
-
- /**
- * The name of the property under which we store the chosen default
- * subscription expiration value for SIMPLE.
- */
- public static final String SUBSCRIPTION_EXPIRATION
- = "SUBSCRIPTION_EXPIRATION";
-
- /**
- * Indicates if the server address has been validated.
- */
- public static final String SERVER_ADDRESS_VALIDATED
- = "SERVER_ADDRESS_VALIDATED";
-
- /**
- * Indicates if the server settings are over
- */
- public static final String IS_SERVER_OVERRIDDEN
- = "IS_SERVER_OVERRIDDEN";
- /**
- * Indicates if the proxy address has been validated.
- */
- public static final String PROXY_ADDRESS_VALIDATED
- = "PROXY_ADDRESS_VALIDATED";
-
- /**
- * Indicates the search strategy chosen for the DICT protocole.
- */
- public static final String STRATEGY = "STRATEGY";
-
- /**
- * Indicates a protocol that would not be shown in the user interface as an
- * account.
- */
- public static final String IS_PROTOCOL_HIDDEN = "IS_PROTOCOL_HIDDEN";
-
- /**
- * Indicates if the given account is the preferred account.
- */
- public static final String IS_PREFERRED_PROTOCOL = "IS_PREFERRED_PROTOCOL";
-
- /**
- * The name of the property that would indicate if a given account is
- * currently enabled or disabled.
- */
- public static final String IS_ACCOUNT_DISABLED = "IS_ACCOUNT_DISABLED";
-
- /**
- * The name of the property that would indicate if a given account
- * configuration form is currently hidden.
- */
- public static final String IS_ACCOUNT_CONFIG_HIDDEN = "IS_CONFIG_HIDDEN";
-
- /**
- * The name of the property that would indicate if a given account
- * status menu is currently hidden.
- */
- public static final String IS_ACCOUNT_STATUS_MENU_HIDDEN =
- "IS_STATUS_MENU_HIDDEN";
-
- /**
- * The name of the property that would indicate if a given account
- * configuration is read only.
- */
- public static final String IS_ACCOUNT_READ_ONLY = "IS_READ_ONLY";
-
- /**
- * The name of the property that would indicate if a given account
- * groups are readonly, values can be all or a comma separated
- * group names including root.
- */
- public static final String ACCOUNT_READ_ONLY_GROUPS = "READ_ONLY_GROUPS";
-
- /**
- * Indicates if ICE should be used.
- */
- public static final String IS_USE_ICE = "ICE_ENABLED";
-
- /**
- * Indicates if STUN server should be automatically discovered.
- */
- public static final String AUTO_DISCOVER_STUN = "AUTO_DISCOVER_STUN";
-
- /**
- * Indicates if default STUN server would be used if no other STUN/TURN
- * server are available.
- */
- public static final String USE_DEFAULT_STUN_SERVER
- = "USE_DEFAULT_STUN_SERVER";
-
- /**
- * The name of the boolean account property which indicates whether Jitsi
- * Videobridge is to be used, if available and supported, for conference
- * calls.
- */
- public static final String USE_JITSI_VIDEO_BRIDGE
- = "USE_JITSI_VIDEO_BRIDGE";
-
- /**
- * The property name prefix for all stun server properties. We generally use
- * this prefix in conjunction with an index which is how we store multiple
- * servers.
- */
- public static final String STUN_PREFIX = "STUN";
-
- /**
- * The base property name for address of additional STUN servers specified.
- */
- public static final String STUN_ADDRESS = "ADDRESS";
-
- /**
- * The base property name for port of additional STUN servers specified.
- */
- public static final String STUN_PORT = "PORT";
-
- /**
- * The base property name for username of additional STUN servers specified.
- */
- public static final String STUN_USERNAME = "USERNAME";
-
- /**
- * The base property name for password of additional STUN servers specified.
- */
- public static final String STUN_PASSWORD = "PASSWORD";
-
- /**
- * The base property name for the turn supported property of additional
- * STUN servers specified.
- */
- public static final String STUN_IS_TURN_SUPPORTED = "IS_TURN_SUPPORTED";
-
- /**
- * Indicates if JingleNodes should be used with ICE.
- */
- public static final String IS_USE_JINGLE_NODES = "JINGLE_NODES_ENABLED";
-
- /**
- * Indicates if JingleNodes should be used with ICE.
- */
- public static final String AUTO_DISCOVER_JINGLE_NODES
- = "AUTO_DISCOVER_JINGLE_NODES";
-
- /**
- * Indicates if JingleNodes should use buddies to search for nodes.
- */
- public static final String JINGLE_NODES_SEARCH_BUDDIES
- = "JINGLE_NODES_SEARCH_BUDDIES";
-
- /**
- * Indicates if UPnP should be used with ICE.
- */
- public static final String IS_USE_UPNP = "UPNP_ENABLED";
-
- /**
- * Indicates if we allow non-TLS connection.
- */
- public static final String IS_ALLOW_NON_SECURE = "ALLOW_NON_SECURE";
-
- /**
- * Enable notifications for new voicemail messages.
- */
- public static final String VOICEMAIL_ENABLED = "VOICEMAIL_ENABLED";
-
- /**
- * Address used to reach voicemail box, by services able to
- * subscribe for voicemail new messages notifications.
- */
- public static final String VOICEMAIL_URI = "VOICEMAIL_URI";
-
- /**
- * Address used to call to hear your messages stored on the server
- * for your voicemail.
- */
- public static final String VOICEMAIL_CHECK_URI = "VOICEMAIL_CHECK_URI";
-
- /**
- * Indicates if calling is disabled for a certain account.
- */
- public static final String IS_CALLING_DISABLED_FOR_ACCOUNT
- = "CALLING_DISABLED";
-
- /**
- * Indicates if desktop streaming/sharing is disabled for a certain account.
- */
- public static final String IS_DESKTOP_STREAMING_DISABLED
- = "DESKTOP_STREAMING_DISABLED";
-
- /**
- * Indicates if desktop remote control is disabled for a certain account.
- */
- public static final String IS_DESKTOP_REMOTE_CONTROL_DISABLED
- = "DESKTOP_REMOTE_CONTROL_DISABLED";
-
- /**
- * The sms default server address.
- */
- public static final String SMS_SERVER_ADDRESS = "SMS_SERVER_ADDRESS";
-
- /**
- * Keep-alive method used by the protocol.
- */
- public static final String KEEP_ALIVE_METHOD = "KEEP_ALIVE_METHOD";
-
- /**
- * The interval for keep-alives if any.
- */
- public static final String KEEP_ALIVE_INTERVAL = "KEEP_ALIVE_INTERVAL";
-
- /**
- * The name of the property holding DTMF method.
- */
- public static final String DTMF_METHOD = "DTMF_METHOD";
-
- /**
- * The minimal DTMF tone duration.
- */
- public static final String DTMF_MINIMAL_TONE_DURATION
- = "DTMF_MINIMAL_TONE_DURATION";
-
- /**
- * Paranoia mode when turned on requires all calls to be secure and
- * indicated as such.
- */
- public static final String MODE_PARANOIA = "MODE_PARANOIA";
-
- /**
- * The name of the "override encodings" property
- */
- public static final String OVERRIDE_ENCODINGS = "OVERRIDE_ENCODINGS";
-
- /**
- * The prefix used to store account encoding properties
- */
- public static final String ENCODING_PROP_PREFIX = "Encodings";
-
- /**
- * An account property to provide a connected account to check for
- * its status. Used when the current provider need to reject calls
- * but is missing presence operation set and need to check other
- * provider for status.
- */
- public static final String CUSAX_PROVIDER_ACCOUNT_PROP
- = "cusax.XMPP_ACCOUNT_ID";
-
- /**
- * The <code>BundleContext</code> containing (or to contain) the service
- * registration of this factory.
- */
- private final BundleContext bundleContext;
-
- /**
- * The name of the protocol this factory registers its
- * <code>ProtocolProviderService</code>s with and to be placed in the
- * properties of the accounts created by this factory.
- */
- private final String protocolName;
-
- /**
- * The table that we store our accounts in.
- * <p>
- * TODO Synchronize the access to the field which may in turn be better
- * achieved by also hiding it from protected into private access.
- * </p>
- */
- protected final Map<AccountID, ServiceRegistration<ProtocolProviderService>>
- registeredAccounts
- = new HashMap<AccountID, ServiceRegistration<ProtocolProviderService>>();
-
- /**
- * The name of the property that indicates the AVP type.
- * <ul>
- * <li>{@link #SAVP_OFF}</li>
- * <li>{@link #SAVP_MANDATORY}</li>
- * <li>{@link #SAVP_OPTIONAL}</li>
- * </ul>
- */
- public static final String SAVP_OPTION = "SAVP_OPTION";
-
- /**
- * Always use RTP/AVP
- */
- public static final int SAVP_OFF = 0;
-
- /**
- * Always use RTP/SAVP
- */
- public static final int SAVP_MANDATORY = 1;
-
- /**
- * Sends two media description, with RTP/SAVP being first.
- */
- public static final int SAVP_OPTIONAL = 2;
-
- /**
- * The name of the property that defines the enabled SDES cipher suites.
- * Enabled suites are listed as CSV by their RFC name.
- */
- public static final String SDES_CIPHER_SUITES = "SDES_CIPHER_SUITES";
-
- /**
- * The name of the property that defines the enabled/disabled state of
- * message carbons.
- */
- public static final String IS_CARBON_DISABLED = "CARBON_DISABLED";
-
- /**
- * Creates a new <tt>ProtocolProviderFactory</tt>.
- *
- * @param bundleContext the bundle context reference of the service
- * @param protocolName the name of the protocol
- */
- protected ProtocolProviderFactory(BundleContext bundleContext,
- String protocolName)
- {
- this.bundleContext = bundleContext;
- this.protocolName = protocolName;
- }
-
- /**
- * Gets the <code>BundleContext</code> containing (or to contain) the
- * service registration of this factory.
- *
- * @return the <code>BundleContext</code> containing (or to contain) the
- * service registration of this factory
- */
- public BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Initializes and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter. Note that account
- * registration is persistent and accounts that are registered during
- * a particular sip-communicator session would be automatically reloaded
- * during all following sessions until they are removed through the
- * removeAccount method.
- *
- * @param userID the user identifier uniquely representing the newly
- * created account within the protocol namespace.
- * @param accountProperties a set of protocol (or implementation) specific
- * properties defining the new account.
- * @return the AccountID of the newly created account.
- * @throws java.lang.IllegalArgumentException if userID does not correspond
- * to an identifier in the context of the underlying protocol or if
- * accountProperties does not contain a complete set of account installation
- * properties.
- * @throws java.lang.IllegalStateException if the account has already been
- * installed.
- * @throws java.lang.NullPointerException if any of the arguments is null.
- */
- public abstract AccountID installAccount(String userID,
- Map<String, String> accountProperties)
- throws IllegalArgumentException,
- IllegalStateException,
- NullPointerException;
-
-
- /**
- * Modifies the account corresponding to the specified accountID. This
- * method is meant to be used to change properties of already existing
- * accounts. Note that if the given accountID doesn't correspond to any
- * registered account this method would do nothing.
- *
- * @param protocolProvider the protocol provider service corresponding to
- * the modified account.
- * @param accountProperties a set of protocol (or implementation) specific
- * properties defining the new account.
- *
- * @throws java.lang.NullPointerException if any of the arguments is null.
- */
- public abstract void modifyAccount(
- ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException;
-
- /**
- * Returns a copy of the list containing the <tt>AccountID</tt>s of all
- * accounts currently registered in this protocol provider.
- * @return a copy of the list containing the <tt>AccountID</tt>s of all
- * accounts currently registered in this protocol provider.
- */
- public ArrayList<AccountID> getRegisteredAccounts()
- {
- synchronized (registeredAccounts)
- {
- return new ArrayList<AccountID>(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 unknown to the
- * provider factory.
- */
- public ServiceReference<ProtocolProviderService> getProviderForAccount(
- AccountID accountID)
- {
- ServiceRegistration<ProtocolProviderService> registration;
-
- synchronized (registeredAccounts)
- {
- registration = registeredAccounts.get(accountID);
- }
-
- try
- {
- if (registration != null)
- return registration.getReference();
- }
- catch (IllegalStateException ise)
- {
- synchronized (registeredAccounts)
- {
- registeredAccounts.remove(accountID);
- }
- }
-
- return null;
- }
-
- /**
- * 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)
- {
- // Unregister the protocol provider.
- ServiceReference<ProtocolProviderService> serRef
- = getProviderForAccount(accountID);
-
- boolean wasAccountExisting = false;
-
- // If the protocol provider service is registered, first unregister the
- // service.
- if (serRef != null)
- {
- BundleContext bundleContext = getBundleContext();
- ProtocolProviderService protocolProvider
- = bundleContext.getService(serRef);
-
- try
- {
- protocolProvider.unregister();
- }
- catch (OperationFailedException ex)
- {
- logger.error(
- "Failed to unregister protocol provider for account: "
- + accountID + " caused by: " + ex);
- }
- }
-
- ServiceRegistration<ProtocolProviderService> registration;
-
- synchronized (registeredAccounts)
- {
- registration = registeredAccounts.remove(accountID);
- }
-
- // first remove the stored account so when PP is unregistered we can
- // distinguish between deleted or just disabled account
- wasAccountExisting = removeStoredAccount(accountID);
-
- if (registration != null)
- {
- // Kill the service.
- registration.unregister();
- }
-
- return wasAccountExisting;
- }
-
- /**
- * The method stores the specified account in the configuration service
- * under the package name of the source factory. The restore and remove
- * account methods are to be used to obtain access to and control the stored
- * accounts.
- * <p>
- * In order to store all account properties, the method would create an
- * entry in the configuration service corresponding (beginning with) the
- * <tt>sourceFactory</tt>'s package name and add to it a unique identifier
- * (e.g. the current miliseconds.)
- * </p>
- *
- * @param accountID the AccountID corresponding to the account that we would
- * like to store.
- */
- protected void storeAccount(AccountID accountID)
- {
- this.storeAccount(accountID, true);
- }
-
- /**
- * The method stores the specified account in the configuration service
- * under the package name of the source factory. The restore and remove
- * account methods are to be used to obtain access to and control the stored
- * accounts.
- * <p>
- * In order to store all account properties, the method would create an
- * entry in the configuration service corresponding (beginning with) the
- * <tt>sourceFactory</tt>'s package name and add to it a unique identifier
- * (e.g. the current miliseconds.)
- * </p>
- *
- * @param accountID the AccountID corresponding to the account that we would
- * like to store.
- * @param isModification if <tt>false</tt> there must be no such already
- * loaded account, it <tt>true</tt> ist modification of an existing account.
- * Usually we use this method with <tt>false</tt> in method installAccount
- * and with <tt>true</tt> or the overridden method in method
- * modifyAccount.
- */
- protected void storeAccount(AccountID accountID, boolean isModification)
- {
- if(!isModification
- && getAccountManager().getStoredAccounts().contains(accountID))
- {
- throw new IllegalStateException(
- "An account for id " + accountID.getUserID()
- + " was already loaded!");
- }
-
- try
- {
- getAccountManager().storeAccount(this, accountID);
- }
- catch (OperationFailedException ofex)
- {
- throw new UndeclaredThrowableException(ofex);
- }
- }
-
- /**
- * Saves the password for the specified account after scrambling it a bit so
- * that it is not visible from first sight. (The method remains highly
- * insecure).
- *
- * @param accountID the AccountID for the account whose password we're
- * storing
- * @param password the password itself
- *
- * @throws IllegalArgumentException if no account corresponding to
- * <code>accountID</code> has been previously stored
- */
- public void storePassword(AccountID accountID, String password)
- throws IllegalArgumentException
- {
- try
- {
- storePassword(getBundleContext(), accountID, password);
- }
- catch (OperationFailedException ofex)
- {
- throw new UndeclaredThrowableException(ofex);
- }
- }
-
- /**
- * 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).
- * <p>
- * TODO Delegate the implementation to {@link AccountManager} because it
- * knows the format in which the password (among the other account
- * properties) is to be saved.
- * </p>
- *
- * @param bundleContext a currently valid bundle context.
- * @param accountID the <tt>AccountID</tt> of the account whose password is
- * to be stored
- * @param password the password to be stored
- *
- * @throws IllegalArgumentException if no account corresponding to
- * <tt>accountID</tt> has been previously stored.
- * @throws OperationFailedException if anything goes wrong while storing the
- * specified <tt>password</tt>
- */
- protected void storePassword(BundleContext bundleContext,
- AccountID accountID,
- String password)
- throws IllegalArgumentException,
- OperationFailedException
- {
- String accountPrefix
- = findAccountPrefix(
- bundleContext,
- accountID,
- getFactoryImplPackageName());
-
- if (accountPrefix == null)
- {
- throw
- new IllegalArgumentException(
- "No previous records found for account ID: "
- + accountID.getAccountUniqueID()
- + " in package"
- + getFactoryImplPackageName());
- }
-
- CredentialsStorageService credentialsStorage
- = ServiceUtils.getService(
- bundleContext,
- CredentialsStorageService.class);
-
- if (!credentialsStorage.storePassword(accountPrefix, password))
- {
- throw
- new OperationFailedException(
- "CredentialsStorageService failed to storePassword",
- OperationFailedException.GENERAL_ERROR);
- }
-
- // Update password property also in the AccountID
- // to prevent it from being removed during account reload
- // in some cases.
- accountID.setPassword(password);
-
- }
-
- /**
- * 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
- */
- public String loadPassword(AccountID accountID)
- {
- return loadPassword(getBundleContext(), accountID);
- }
-
- /**
- * Returns the password last saved for the specified account.
- * <p>
- * TODO Delegate the implementation to {@link AccountManager} because it
- * knows the format in which the password (among the other account
- * properties) was saved.
- * </p>
- *
- * @param bundleContext a currently valid bundle context.
- * @param accountID the AccountID for the account whose password we're
- * looking for..
- *
- * @return a String containing the password for the specified accountID.
- */
- protected String loadPassword(BundleContext bundleContext,
- AccountID accountID)
- {
- String accountPrefix = findAccountPrefix(
- bundleContext, accountID, getFactoryImplPackageName());
-
- if (accountPrefix == null)
- return null;
-
- CredentialsStorageService credentialsStorage
- = ServiceUtils.getService(
- bundleContext,
- CredentialsStorageService.class);
-
- return credentialsStorage.loadPassword(accountPrefix);
- }
-
- /**
- * 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 uninstallAccount method.
- *
- * @param accountProperties a set of protocol (or implementation) specific
- * properties defining the new account.
- * @return the AccountID of the newly loaded account
- */
- public AccountID loadAccount(Map<String, String> accountProperties)
- {
- AccountID accountID = createAccount(accountProperties);
-
- loadAccount(accountID);
-
- return accountID;
- }
-
- /**
- * Creates a protocol provider for the given <tt>accountID</tt> and
- * registers it in the bundle context. This method has a persistent
- * effect. Once created the resulting account will remain installed until
- * removed through the uninstallAccount method.
- *
- * @param accountID the account identifier
- * @return <tt>true</tt> if the account with the given <tt>accountID</tt> is
- * successfully loaded, otherwise returns <tt>false</tt>
- */
- public boolean loadAccount(AccountID accountID)
- {
- // Need to obtain the original user id property, instead of calling
- // accountID.getUserID(), because this method could return a modified
- // version of the user id property.
- String userID
- = accountID.getAccountPropertyString(
- ProtocolProviderFactory.USER_ID);
-
- ProtocolProviderService service = createService(userID, accountID);
-
- Dictionary<String, String> properties = new Hashtable<String, String>();
- properties.put(PROTOCOL, protocolName);
- properties.put(USER_ID, userID);
-
- ServiceRegistration<ProtocolProviderService> serviceRegistration
- = bundleContext.registerService(
- ProtocolProviderService.class,
- service,
- properties);
-
- if (serviceRegistration == null)
- {
- return false;
- }
- else
- {
- synchronized (registeredAccounts)
- {
- registeredAccounts.put(accountID, serviceRegistration);
- }
- return true;
- }
- }
-
- /**
- * Unloads the account corresponding to the given <tt>accountID</tt>.
- * Unregisters the corresponding protocol provider, but keeps the account in
- * contrast to the uninstallAccount method.
- *
- * @param accountID the account identifier
- * @return true if an account with the specified ID existed and was unloaded
- * and false otherwise.
- */
- public boolean unloadAccount(AccountID accountID)
- {
- // Unregister the protocol provider.
- ServiceReference<ProtocolProviderService> serRef
- = getProviderForAccount(accountID);
-
- if (serRef == null)
- {
- return false;
- }
-
- BundleContext bundleContext = getBundleContext();
- ProtocolProviderService protocolProvider
- = bundleContext.getService(serRef);
-
- try
- {
- protocolProvider.unregister();
- }
- catch (OperationFailedException ex)
- {
- logger.error(
- "Failed to unregister protocol provider for account: "
- + accountID + " caused by: " + ex);
- }
-
- ServiceRegistration<ProtocolProviderService> registration;
-
- synchronized (registeredAccounts)
- {
- registration = registeredAccounts.remove(accountID);
- }
- if (registration == null)
- {
- return false;
- }
-
- // Kill the service.
- registration.unregister();
-
- return true;
- }
-
- /**
- * Initializes and creates an account corresponding to the specified
- * accountProperties.
- *
- * @param accountProperties a set of protocol (or implementation) specific
- * properties defining the new account.
- * @return the AccountID of the newly created account
- */
- public AccountID createAccount(Map<String, String> accountProperties)
- {
- BundleContext bundleContext = getBundleContext();
- if (bundleContext == null)
- throw new NullPointerException(
- "The specified BundleContext was null");
-
- if (accountProperties == null)
- throw new NullPointerException(
- "The specified property map was null");
-
- String userID = accountProperties.get(USER_ID);
- if (userID == null)
- throw new NullPointerException(
- "The account properties contained no user id.");
-
- String protocolName = getProtocolName();
- if (!accountProperties.containsKey(PROTOCOL))
- accountProperties.put(PROTOCOL, protocolName);
-
- return createAccountID(userID, accountProperties);
- }
-
- /**
- * Creates a new <code>AccountID</code> instance with a specific user ID to
- * represent a given set of account properties.
- * <p>
- * The method is a pure factory allowing implementers to specify the runtime
- * type of the created <code>AccountID</code> and customize the instance.
- * The returned <code>AccountID</code> will later be associated with a
- * <code>ProtocolProviderService</code> by the caller (e.g. using
- * {@link #createService(String, AccountID)}).
- * </p>
- *
- * @param userID the user ID of the new instance
- * @param accountProperties the set of properties to be represented by the
- * new instance
- * @return a new <code>AccountID</code> instance with the specified user ID
- * representing the given set of account properties
- */
- protected abstract AccountID createAccountID(
- String userID, Map<String, String> accountProperties);
-
- /**
- * Gets the name of the protocol this factory registers its
- * <code>ProtocolProviderService</code>s with and to be placed in the
- * properties of the accounts created by this factory.
- *
- * @return the name of the protocol this factory registers its
- * <code>ProtocolProviderService</code>s with and to be placed in
- * the properties of the accounts created by this factory
- */
- public String getProtocolName()
- {
- return protocolName;
- }
-
- /**
- * Initializes a new <code>ProtocolProviderService</code> instance with a
- * specific user ID to represent a specific <code>AccountID</code>.
- * <p>
- * The method is a pure factory allowing implementers to specify the runtime
- * type of the created <code>ProtocolProviderService</code> and customize
- * the instance. The caller will later register the returned service with
- * the <code>BundleContext</code> of this factory.
- * </p>
- *
- * @param userID the user ID to initialize the new instance with
- * @param accountID the <code>AccountID</code> to be represented by the new
- * instance
- * @return a new <code>ProtocolProviderService</code> instance with the
- * specific user ID representing the specified
- * <code>AccountID</code>
- */
- protected abstract ProtocolProviderService createService(String userID,
- AccountID accountID);
-
- /**
- * Removes the account with <tt>accountID</tt> from the set of accounts
- * that are persistently stored inside the configuration service.
- *
- * @param accountID the AccountID of the account to remove.
- *
- * @return true if an account has been removed and false otherwise.
- */
- protected boolean removeStoredAccount(AccountID accountID)
- {
- return getAccountManager().removeStoredAccount(this, accountID);
- }
-
- /**
- * Returns the prefix for all persistently stored properties of the account
- * with the specified id.
- * @param bundleContext a currently valid bundle context.
- * @param accountID the AccountID of the account whose properties we're
- * looking for.
- * @param sourcePackageName a String containing the package name of the
- * concrete factory class that extends us.
- * @return a String indicating the ConfigurationService property name
- * prefix under which all account properties are stored or null if no
- * account corresponding to the specified id was found.
- */
- public static String findAccountPrefix(BundleContext bundleContext,
- AccountID accountID,
- String sourcePackageName)
- {
- ServiceReference<ConfigurationService> confReference
- = bundleContext.getServiceReference(ConfigurationService.class);
- ConfigurationService configurationService
- = bundleContext.getService(confReference);
-
- //first retrieve all accounts that we've registered
- List<String> storedAccounts =
- configurationService.getPropertyNamesByPrefix(sourcePackageName,
- true);
-
- //find an account with the corresponding id.
- for (String accountRootPropertyName : storedAccounts)
- {
- //unregister the account in the configuration service.
- //all the properties must have been registered in the following
- //hierarchy:
- //net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME
- String accountUID = configurationService.getString(
- accountRootPropertyName //node id
- + "." + ACCOUNT_UID); // propname
-
- if (accountID.getAccountUniqueID().equals(accountUID))
- {
- return accountRootPropertyName;
- }
- }
- return null;
- }
-
- /**
- * Returns the name of the package that we're currently running in (i.e.
- * the name of the package containing the proto factory that extends us).
- *
- * @return a String containing the package name of the concrete factory
- * class that extends us.
- */
- private String getFactoryImplPackageName()
- {
- String className = getClass().getName();
-
- return className.substring(0, className.lastIndexOf('.'));
- }
-
- /**
- * Prepares the factory for bundle shutdown.
- */
- public void stop()
- {
- if (logger.isTraceEnabled())
- logger.trace("Preparing to stop all protocol providers of" + this);
-
- synchronized (registeredAccounts)
- {
- for (ServiceRegistration<ProtocolProviderService> reg
- : registeredAccounts.values())
- {
- stop(reg);
- reg.unregister();
- }
-
- registeredAccounts.clear();
- }
- }
-
- /**
- * Shuts down the <code>ProtocolProviderService</code> representing an
- * account registered with this factory.
- *
- * @param registeredAccount the <code>ServiceRegistration</code> of the
- * <code>ProtocolProviderService</code> representing an account
- * registered with this factory
- */
- protected void stop(
- ServiceRegistration<ProtocolProviderService> registeredAccount)
- {
- ProtocolProviderService protocolProviderService
- = getBundleContext().getService(registeredAccount.getReference());
-
- protocolProviderService.shutdown();
- }
-
- /**
- * Get the <tt>AccountManager</tt> of the protocol.
- *
- * @return <tt>AccountManager</tt> of the protocol
- */
- private AccountManager getAccountManager()
- {
- BundleContext bundleContext = getBundleContext();
- ServiceReference<AccountManager> serviceReference
- = bundleContext.getServiceReference(AccountManager.class);
-
- return bundleContext.getService(serviceReference);
- }
-
-
- /**
- * Finds registered <tt>ProtocolProviderFactory</tt> for given
- * <tt>protocolName</tt>.
- * @param bundleContext the OSGI bundle context that will be used.
- * @param protocolName the protocol name.
- * @return Registered <tt>ProtocolProviderFactory</tt> for given protocol
- * name or <tt>null</tt> if no provider was found.
- */
- static public ProtocolProviderFactory getProtocolProviderFactory(
- BundleContext bundleContext,
- String protocolName)
- {
- Collection<ServiceReference<ProtocolProviderFactory>> serRefs;
- String osgiFilter
- = "(" + ProtocolProviderFactory.PROTOCOL + "=" + protocolName + ")";
-
- try
- {
- serRefs
- = bundleContext.getServiceReferences(
- ProtocolProviderFactory.class,
- osgiFilter);
- }
- catch (InvalidSyntaxException ex)
- {
- serRefs = null;
- logger.error(ex);
- }
- if ((serRefs == null) || serRefs.isEmpty())
- return null;
- else
- return bundleContext.getService(serRefs.iterator().next());
- }
-}
+package net.java.sip.communicator.service.protocol;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import net.java.sip.communicator.service.credentialsstorage.*;
+import net.java.sip.communicator.util.*;
+
+import org.jitsi.service.configuration.*;
+import org.osgi.framework.*;
+
+/**
+ * The ProtocolProviderFactory is what actually creates instances of a
+ * ProtocolProviderService implementation. A provider factory would register,
+ * persistently store, and remove when necessary, ProtocolProviders. The way
+ * things are in the SIP Communicator, a user account is represented (in a 1:1
+ * relationship) by an AccountID and a ProtocolProvider. In other words - one
+ * would have as many protocol providers installed in a given moment as they
+ * would user account registered through the various services.
+ *
+ * @author Emil Ivov
+ * @author Lubomir Marinov
+ */
+public abstract class ProtocolProviderFactory
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>ProtocolProviderFactory</tt> class
+ * and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(ProtocolProviderFactory.class);
+
+ /**
+ * Then name of a property which represents a password.
+ */
+ public static final String PASSWORD = "PASSWORD";
+
+ /**
+ * The name of a property representing the name of the protocol for an
+ * ProtocolProviderFactory.
+ */
+ public static final String PROTOCOL = "PROTOCOL_NAME";
+
+ /**
+ * The name of a property representing the path to protocol icons.
+ */
+ public static final String PROTOCOL_ICON_PATH = "PROTOCOL_ICON_PATH";
+
+ /**
+ * The name of a property representing the path to the account icon to
+ * be used in the user interface, when the protocol provider service is not
+ * available.
+ */
+ public static final String ACCOUNT_ICON_PATH = "ACCOUNT_ICON_PATH";
+
+ /**
+ * The name of a property which represents the AccountID of a
+ * ProtocolProvider and that, together with a password is used to login
+ * on the protocol network..
+ */
+ public static final String USER_ID = "USER_ID";
+
+ /**
+ * The name that should be displayed to others when we are calling or
+ * writing them.
+ */
+ public static final String DISPLAY_NAME = "DISPLAY_NAME";
+
+ /**
+ * The name that should be displayed to the user on call via and chat via
+ * lists.
+ */
+ public static final String ACCOUNT_DISPLAY_NAME = "ACCOUNT_DISPLAY_NAME";
+
+ /**
+ * The name of the property under which we store protocol AccountID-s.
+ */
+ public static final String ACCOUNT_UID = "ACCOUNT_UID";
+
+ /**
+ * The name of the property under which we store protocol the address of
+ * a protocol centric entity (any protocol server).
+ */
+ public static final String SERVER_ADDRESS = "SERVER_ADDRESS";
+
+ /**
+ * The name of the property under which we store the number of the port
+ * where the server stored against the SERVER_ADDRESS property is expecting
+ * connections to be made via this protocol.
+ */
+ public static final String SERVER_PORT = "SERVER_PORT";
+
+ /**
+ * The name of the property under which we store the name of the transport
+ * protocol that needs to be used to access the server.
+ */
+ public static final String SERVER_TRANSPORT = "SERVER_TRANSPORT";
+
+ /**
+ * The name of the property under which we store protocol the address of
+ * a protocol proxy.
+ */
+ public static final String PROXY_ADDRESS = "PROXY_ADDRESS";
+
+ /**
+ * The name of the property under which we store the number of the port
+ * where the proxy stored against the PROXY_ADDRESS property is expecting
+ * connections to be made via this protocol.
+ */
+ public static final String PROXY_PORT = "PROXY_PORT";
+
+ /**
+ * The name of the property which defines whether proxy is auto configured
+ * by the protocol by using known methods such as specific DNS queries.
+ */
+ public static final String PROXY_AUTO_CONFIG = "PROXY_AUTO_CONFIG";
+
+ /**
+ * The property indicating the preferred UDP and TCP
+ * port to bind to for clear communications.
+ */
+ public static final String PREFERRED_CLEAR_PORT_PROPERTY_NAME
+ = "net.java.sip.communicator.SIP_PREFERRED_CLEAR_PORT";
+
+ /**
+ * The property indicating the preferred TLS (TCP)
+ * port to bind to for secure communications.
+ */
+ public static final String PREFERRED_SECURE_PORT_PROPERTY_NAME
+ = "net.java.sip.communicator.SIP_PREFERRED_SECURE_PORT";
+
+ /**
+ * The name of the property under which we store the the type of the proxy
+ * stored against the PROXY_ADDRESS property. Exact type values depend on
+ * protocols and among them are socks4, socks5, http and possibly others.
+ */
+ public static final String PROXY_TYPE = "PROXY_TYPE";
+
+ /**
+ * The name of the property under which we store the the username for the
+ * proxy stored against the PROXY_ADDRESS property.
+ */
+ public static final String PROXY_USERNAME = "PROXY_USERNAME";
+
+ /**
+ * The name of the property under which we store the the authorization name
+ * for the proxy stored against the PROXY_ADDRESS property.
+ */
+ public static final String AUTHORIZATION_NAME = "AUTHORIZATION_NAME";
+
+ /**
+ * The name of the property under which we store the password for the proxy
+ * stored against the PROXY_ADDRESS property.
+ */
+ public static final String PROXY_PASSWORD = "PROXY_PASSWORD";
+
+ /**
+ * The name of the property under which we store the name of the transport
+ * protocol that needs to be used to access the proxy.
+ */
+ public static final String PROXY_TRANSPORT = "PROXY_TRANSPORT";
+
+ /**
+ * The name of the property that indicates whether loose routing should be
+ * forced for all traffic in an account, rather than routing through an
+ * outbound proxy which is the default for Jitsi.
+ */
+ public static final String FORCE_PROXY_BYPASS = "FORCE_PROXY_BYPASS";
+
+ /**
+ * The name of the property that indicates whether the client must
+ * be registered with a registrar when making outgoing calls.
+ */
+ public static final String MUST_REGISTER_TO_CALL = "MUST_REGISTER_TO_CALL";
+
+ /**
+ * The name of the property under which we store the user preference for a
+ * transport protocol to use (i.e. tcp or udp).
+ */
+ public static final String PREFERRED_TRANSPORT = "PREFERRED_TRANSPORT";
+
+ /**
+ * The name of the property under which we store whether we generate
+ * resource values or we just use the stored one.
+ */
+ public static final String AUTO_GENERATE_RESOURCE = "AUTO_GENERATE_RESOURCE";
+
+ /**
+ * The name of the property under which we store resources such as the
+ * jabber resource property.
+ */
+ public static final String RESOURCE = "RESOURCE";
+
+ /**
+ * The name of the property under which we store resource priority.
+ */
+ public static final String RESOURCE_PRIORITY = "RESOURCE_PRIORITY";
+
+ /**
+ * The name of the property which defines that the call is encrypted by
+ * default
+ */
+ public static final String DEFAULT_ENCRYPTION = "DEFAULT_ENCRYPTION";
+
+ /**
+ * The name of the property that indicates the encryption protocols for this
+ * account.
+ */
+ public static final String ENCRYPTION_PROTOCOL = "ENCRYPTION_PROTOCOL";
+
+ /**
+ * The name of the property that indicates the status (enabed or disabled)
+ * encryption protocols for this account.
+ */
+ public static final String ENCRYPTION_PROTOCOL_STATUS
+ = "ENCRYPTION_PROTOCOL_STATUS";
+
+ /**
+ * The name of the property which defines if to include the ZRTP attribute
+ * to SIP/SDP
+ */
+ public static final String DEFAULT_SIPZRTP_ATTRIBUTE =
+ "DEFAULT_SIPZRTP_ATTRIBUTE";
+
+ /**
+ * The name of the property which defines the ID of the client TLS
+ * certificate configuration entry.
+ */
+ public static final String CLIENT_TLS_CERTIFICATE =
+ "CLIENT_TLS_CERTIFICATE";
+
+ /**
+ * The name of the property under which we store the boolean value
+ * indicating if the user name should be automatically changed if the
+ * specified name already exists. This property is meant to be used by IRC
+ * implementations.
+ */
+ public static final String AUTO_CHANGE_USER_NAME = "AUTO_CHANGE_USER_NAME";
+
+ /**
+ * The name of the property under which we store the boolean value
+ * indicating if a password is required. Initially this property is meant to
+ * be used by IRC implementations.
+ */
+ public static final String NO_PASSWORD_REQUIRED = "NO_PASSWORD_REQUIRED";
+
+ /**
+ * The name of the property under which we store if the presence is enabled.
+ */
+ public static final String IS_PRESENCE_ENABLED = "IS_PRESENCE_ENABLED";
+
+ /**
+ * The name of the property under which we store if the p2p mode for SIMPLE
+ * should be forced.
+ */
+ public static final String FORCE_P2P_MODE = "FORCE_P2P_MODE";
+
+ /**
+ * The name of the property under which we store the offline contact polling
+ * period for SIMPLE.
+ */
+ public static final String POLLING_PERIOD = "POLLING_PERIOD";
+
+ /**
+ * The name of the property under which we store the chosen default
+ * subscription expiration value for SIMPLE.
+ */
+ public static final String SUBSCRIPTION_EXPIRATION
+ = "SUBSCRIPTION_EXPIRATION";
+
+ /**
+ * Indicates if the server address has been validated.
+ */
+ public static final String SERVER_ADDRESS_VALIDATED
+ = "SERVER_ADDRESS_VALIDATED";
+
+ /**
+ * Indicates if the server settings are over
+ */
+ public static final String IS_SERVER_OVERRIDDEN
+ = "IS_SERVER_OVERRIDDEN";
+ /**
+ * Indicates if the proxy address has been validated.
+ */
+ public static final String PROXY_ADDRESS_VALIDATED
+ = "PROXY_ADDRESS_VALIDATED";
+
+ /**
+ * Indicates the search strategy chosen for the DICT protocole.
+ */
+ public static final String STRATEGY = "STRATEGY";
+
+ /**
+ * Indicates a protocol that would not be shown in the user interface as an
+ * account.
+ */
+ public static final String IS_PROTOCOL_HIDDEN = "IS_PROTOCOL_HIDDEN";
+
+ /**
+ * Indicates if the given account is the preferred account.
+ */
+ public static final String IS_PREFERRED_PROTOCOL = "IS_PREFERRED_PROTOCOL";
+
+ /**
+ * The name of the property that would indicate if a given account is
+ * currently enabled or disabled.
+ */
+ public static final String IS_ACCOUNT_DISABLED = "IS_ACCOUNT_DISABLED";
+
+ /**
+ * The name of the property that would indicate if a given account
+ * configuration form is currently hidden.
+ */
+ public static final String IS_ACCOUNT_CONFIG_HIDDEN = "IS_CONFIG_HIDDEN";
+
+ /**
+ * The name of the property that would indicate if a given account
+ * status menu is currently hidden.
+ */
+ public static final String IS_ACCOUNT_STATUS_MENU_HIDDEN =
+ "IS_STATUS_MENU_HIDDEN";
+
+ /**
+ * The name of the property that would indicate if a given account
+ * configuration is read only.
+ */
+ public static final String IS_ACCOUNT_READ_ONLY = "IS_READ_ONLY";
+
+ /**
+ * The name of the property that would indicate if a given account
+ * groups are readonly, values can be all or a comma separated
+ * group names including root.
+ */
+ public static final String ACCOUNT_READ_ONLY_GROUPS = "READ_ONLY_GROUPS";
+
+ /**
+ * Indicates if ICE should be used.
+ */
+ public static final String IS_USE_ICE = "ICE_ENABLED";
+
+ /**
+ * Indicates if STUN server should be automatically discovered.
+ */
+ public static final String AUTO_DISCOVER_STUN = "AUTO_DISCOVER_STUN";
+
+ /**
+ * Indicates if default STUN server would be used if no other STUN/TURN
+ * server are available.
+ */
+ public static final String USE_DEFAULT_STUN_SERVER
+ = "USE_DEFAULT_STUN_SERVER";
+
+ /**
+ * The name of the boolean account property which indicates whether Jitsi
+ * Videobridge is to be used, if available and supported, for conference
+ * calls.
+ */
+ public static final String USE_JITSI_VIDEO_BRIDGE
+ = "USE_JITSI_VIDEO_BRIDGE";
+
+ /**
+ * The name of the boolean account property which indicates whether Jitsi
+ * will use translator for media, instead of mixing, for conference
+ * calls.
+ * By default if supported mixing is used (audio mixed, video relayed).
+ */
+ public static final String USE_TRANSLATOR_IN_CONFERENCE
+ = "USE_TRANSLATOR_IN_CONFERENCE";
+
+ /**
+ * The property name prefix for all stun server properties. We generally use
+ * this prefix in conjunction with an index which is how we store multiple
+ * servers.
+ */
+ public static final String STUN_PREFIX = "STUN";
+
+ /**
+ * The base property name for address of additional STUN servers specified.
+ */
+ public static final String STUN_ADDRESS = "ADDRESS";
+
+ /**
+ * The base property name for port of additional STUN servers specified.
+ */
+ public static final String STUN_PORT = "PORT";
+
+ /**
+ * The base property name for username of additional STUN servers specified.
+ */
+ public static final String STUN_USERNAME = "USERNAME";
+
+ /**
+ * The base property name for password of additional STUN servers specified.
+ */
+ public static final String STUN_PASSWORD = "PASSWORD";
+
+ /**
+ * The base property name for the turn supported property of additional
+ * STUN servers specified.
+ */
+ public static final String STUN_IS_TURN_SUPPORTED = "IS_TURN_SUPPORTED";
+
+ /**
+ * Indicates if JingleNodes should be used with ICE.
+ */
+ public static final String IS_USE_JINGLE_NODES = "JINGLE_NODES_ENABLED";
+
+ /**
+ * Indicates if JingleNodes should be used with ICE.
+ */
+ public static final String AUTO_DISCOVER_JINGLE_NODES
+ = "AUTO_DISCOVER_JINGLE_NODES";
+
+ /**
+ * Indicates if JingleNodes should use buddies to search for nodes.
+ */
+ public static final String JINGLE_NODES_SEARCH_BUDDIES
+ = "JINGLE_NODES_SEARCH_BUDDIES";
+
+ /**
+ * Indicates if UPnP should be used with ICE.
+ */
+ public static final String IS_USE_UPNP = "UPNP_ENABLED";
+
+ /**
+ * Indicates if we allow non-TLS connection.
+ */
+ public static final String IS_ALLOW_NON_SECURE = "ALLOW_NON_SECURE";
+
+ /**
+ * Enable notifications for new voicemail messages.
+ */
+ public static final String VOICEMAIL_ENABLED = "VOICEMAIL_ENABLED";
+
+ /**
+ * Address used to reach voicemail box, by services able to
+ * subscribe for voicemail new messages notifications.
+ */
+ public static final String VOICEMAIL_URI = "VOICEMAIL_URI";
+
+ /**
+ * Address used to call to hear your messages stored on the server
+ * for your voicemail.
+ */
+ public static final String VOICEMAIL_CHECK_URI = "VOICEMAIL_CHECK_URI";
+
+ /**
+ * Indicates if calling is disabled for a certain account.
+ */
+ public static final String IS_CALLING_DISABLED_FOR_ACCOUNT
+ = "CALLING_DISABLED";
+
+ /**
+ * Indicates if desktop streaming/sharing is disabled for a certain account.
+ */
+ public static final String IS_DESKTOP_STREAMING_DISABLED
+ = "DESKTOP_STREAMING_DISABLED";
+
+ /**
+ * Indicates if desktop remote control is disabled for a certain account.
+ */
+ public static final String IS_DESKTOP_REMOTE_CONTROL_DISABLED
+ = "DESKTOP_REMOTE_CONTROL_DISABLED";
+
+ /**
+ * The sms default server address.
+ */
+ public static final String SMS_SERVER_ADDRESS = "SMS_SERVER_ADDRESS";
+
+ /**
+ * Keep-alive method used by the protocol.
+ */
+ public static final String KEEP_ALIVE_METHOD = "KEEP_ALIVE_METHOD";
+
+ /**
+ * The interval for keep-alives if any.
+ */
+ public static final String KEEP_ALIVE_INTERVAL = "KEEP_ALIVE_INTERVAL";
+
+ /**
+ * The name of the property holding DTMF method.
+ */
+ public static final String DTMF_METHOD = "DTMF_METHOD";
+
+ /**
+ * The minimal DTMF tone duration.
+ */
+ public static final String DTMF_MINIMAL_TONE_DURATION
+ = "DTMF_MINIMAL_TONE_DURATION";
+
+ /**
+ * Paranoia mode when turned on requires all calls to be secure and
+ * indicated as such.
+ */
+ public static final String MODE_PARANOIA = "MODE_PARANOIA";
+
+ /**
+ * The name of the "override encodings" property
+ */
+ public static final String OVERRIDE_ENCODINGS = "OVERRIDE_ENCODINGS";
+
+ /**
+ * The prefix used to store account encoding properties
+ */
+ public static final String ENCODING_PROP_PREFIX = "Encodings";
+
+ /**
+ * An account property to provide a connected account to check for
+ * its status. Used when the current provider need to reject calls
+ * but is missing presence operation set and need to check other
+ * provider for status.
+ */
+ public static final String CUSAX_PROVIDER_ACCOUNT_PROP
+ = "cusax.XMPP_ACCOUNT_ID";
+
+ /**
+ * The <code>BundleContext</code> containing (or to contain) the service
+ * registration of this factory.
+ */
+ private final BundleContext bundleContext;
+
+ /**
+ * The name of the protocol this factory registers its
+ * <code>ProtocolProviderService</code>s with and to be placed in the
+ * properties of the accounts created by this factory.
+ */
+ private final String protocolName;
+
+ /**
+ * The table that we store our accounts in.
+ * <p>
+ * TODO Synchronize the access to the field which may in turn be better
+ * achieved by also hiding it from protected into private access.
+ * </p>
+ */
+ protected final Map<AccountID, ServiceRegistration<ProtocolProviderService>>
+ registeredAccounts
+ = new HashMap<AccountID, ServiceRegistration<ProtocolProviderService>>();
+
+ /**
+ * The name of the property that indicates the AVP type.
+ * <ul>
+ * <li>{@link #SAVP_OFF}</li>
+ * <li>{@link #SAVP_MANDATORY}</li>
+ * <li>{@link #SAVP_OPTIONAL}</li>
+ * </ul>
+ */
+ public static final String SAVP_OPTION = "SAVP_OPTION";
+
+ /**
+ * Always use RTP/AVP
+ */
+ public static final int SAVP_OFF = 0;
+
+ /**
+ * Always use RTP/SAVP
+ */
+ public static final int SAVP_MANDATORY = 1;
+
+ /**
+ * Sends two media description, with RTP/SAVP being first.
+ */
+ public static final int SAVP_OPTIONAL = 2;
+
+ /**
+ * The name of the property that defines the enabled SDES cipher suites.
+ * Enabled suites are listed as CSV by their RFC name.
+ */
+ public static final String SDES_CIPHER_SUITES = "SDES_CIPHER_SUITES";
+
+ /**
+ * The name of the property that defines the enabled/disabled state of
+ * message carbons.
+ */
+ public static final String IS_CARBON_DISABLED = "CARBON_DISABLED";
+
+ /**
+ * Creates a new <tt>ProtocolProviderFactory</tt>.
+ *
+ * @param bundleContext the bundle context reference of the service
+ * @param protocolName the name of the protocol
+ */
+ protected ProtocolProviderFactory(BundleContext bundleContext,
+ String protocolName)
+ {
+ this.bundleContext = bundleContext;
+ this.protocolName = protocolName;
+ }
+
+ /**
+ * Gets the <code>BundleContext</code> containing (or to contain) the
+ * service registration of this factory.
+ *
+ * @return the <code>BundleContext</code> containing (or to contain) the
+ * service registration of this factory
+ */
+ public BundleContext getBundleContext()
+ {
+ return bundleContext;
+ }
+
+ /**
+ * Initializes and creates an account corresponding to the specified
+ * accountProperties and registers the resulting ProtocolProvider in the
+ * <tt>context</tt> BundleContext parameter. Note that account
+ * registration is persistent and accounts that are registered during
+ * a particular sip-communicator session would be automatically reloaded
+ * during all following sessions until they are removed through the
+ * removeAccount method.
+ *
+ * @param userID the user identifier uniquely representing the newly
+ * created account within the protocol namespace.
+ * @param accountProperties a set of protocol (or implementation) specific
+ * properties defining the new account.
+ * @return the AccountID of the newly created account.
+ * @throws java.lang.IllegalArgumentException if userID does not correspond
+ * to an identifier in the context of the underlying protocol or if
+ * accountProperties does not contain a complete set of account installation
+ * properties.
+ * @throws java.lang.IllegalStateException if the account has already been
+ * installed.
+ * @throws java.lang.NullPointerException if any of the arguments is null.
+ */
+ public abstract AccountID installAccount(String userID,
+ Map<String, String> accountProperties)
+ throws IllegalArgumentException,
+ IllegalStateException,
+ NullPointerException;
+
+
+ /**
+ * Modifies the account corresponding to the specified accountID. This
+ * method is meant to be used to change properties of already existing
+ * accounts. Note that if the given accountID doesn't correspond to any
+ * registered account this method would do nothing.
+ *
+ * @param protocolProvider the protocol provider service corresponding to
+ * the modified account.
+ * @param accountProperties a set of protocol (or implementation) specific
+ * properties defining the new account.
+ *
+ * @throws java.lang.NullPointerException if any of the arguments is null.
+ */
+ public abstract void modifyAccount(
+ ProtocolProviderService protocolProvider,
+ Map<String, String> accountProperties)
+ throws NullPointerException;
+
+ /**
+ * Returns a copy of the list containing the <tt>AccountID</tt>s of all
+ * accounts currently registered in this protocol provider.
+ * @return a copy of the list containing the <tt>AccountID</tt>s of all
+ * accounts currently registered in this protocol provider.
+ */
+ public ArrayList<AccountID> getRegisteredAccounts()
+ {
+ synchronized (registeredAccounts)
+ {
+ return new ArrayList<AccountID>(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 unknown to the
+ * provider factory.
+ */
+ public ServiceReference<ProtocolProviderService> getProviderForAccount(
+ AccountID accountID)
+ {
+ ServiceRegistration<ProtocolProviderService> registration;
+
+ synchronized (registeredAccounts)
+ {
+ registration = registeredAccounts.get(accountID);
+ }
+
+ try
+ {
+ if (registration != null)
+ return registration.getReference();
+ }
+ catch (IllegalStateException ise)
+ {
+ synchronized (registeredAccounts)
+ {
+ registeredAccounts.remove(accountID);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)
+ {
+ // Unregister the protocol provider.
+ ServiceReference<ProtocolProviderService> serRef
+ = getProviderForAccount(accountID);
+
+ boolean wasAccountExisting = false;
+
+ // If the protocol provider service is registered, first unregister the
+ // service.
+ if (serRef != null)
+ {
+ BundleContext bundleContext = getBundleContext();
+ ProtocolProviderService protocolProvider
+ = bundleContext.getService(serRef);
+
+ try
+ {
+ protocolProvider.unregister();
+ }
+ catch (OperationFailedException ex)
+ {
+ logger.error(
+ "Failed to unregister protocol provider for account: "
+ + accountID + " caused by: " + ex);
+ }
+ }
+
+ ServiceRegistration<ProtocolProviderService> registration;
+
+ synchronized (registeredAccounts)
+ {
+ registration = registeredAccounts.remove(accountID);
+ }
+
+ // first remove the stored account so when PP is unregistered we can
+ // distinguish between deleted or just disabled account
+ wasAccountExisting = removeStoredAccount(accountID);
+
+ if (registration != null)
+ {
+ // Kill the service.
+ registration.unregister();
+ }
+
+ return wasAccountExisting;
+ }
+
+ /**
+ * The method stores the specified account in the configuration service
+ * under the package name of the source factory. The restore and remove
+ * account methods are to be used to obtain access to and control the stored
+ * accounts.
+ * <p>
+ * In order to store all account properties, the method would create an
+ * entry in the configuration service corresponding (beginning with) the
+ * <tt>sourceFactory</tt>'s package name and add to it a unique identifier
+ * (e.g. the current miliseconds.)
+ * </p>
+ *
+ * @param accountID the AccountID corresponding to the account that we would
+ * like to store.
+ */
+ protected void storeAccount(AccountID accountID)
+ {
+ this.storeAccount(accountID, true);
+ }
+
+ /**
+ * The method stores the specified account in the configuration service
+ * under the package name of the source factory. The restore and remove
+ * account methods are to be used to obtain access to and control the stored
+ * accounts.
+ * <p>
+ * In order to store all account properties, the method would create an
+ * entry in the configuration service corresponding (beginning with) the
+ * <tt>sourceFactory</tt>'s package name and add to it a unique identifier
+ * (e.g. the current miliseconds.)
+ * </p>
+ *
+ * @param accountID the AccountID corresponding to the account that we would
+ * like to store.
+ * @param isModification if <tt>false</tt> there must be no such already
+ * loaded account, it <tt>true</tt> ist modification of an existing account.
+ * Usually we use this method with <tt>false</tt> in method installAccount
+ * and with <tt>true</tt> or the overridden method in method
+ * modifyAccount.
+ */
+ protected void storeAccount(AccountID accountID, boolean isModification)
+ {
+ if(!isModification
+ && getAccountManager().getStoredAccounts().contains(accountID))
+ {
+ throw new IllegalStateException(
+ "An account for id " + accountID.getUserID()
+ + " was already loaded!");
+ }
+
+ try
+ {
+ getAccountManager().storeAccount(this, accountID);
+ }
+ catch (OperationFailedException ofex)
+ {
+ throw new UndeclaredThrowableException(ofex);
+ }
+ }
+
+ /**
+ * Saves the password for the specified account after scrambling it a bit so
+ * that it is not visible from first sight. (The method remains highly
+ * insecure).
+ *
+ * @param accountID the AccountID for the account whose password we're
+ * storing
+ * @param password the password itself
+ *
+ * @throws IllegalArgumentException if no account corresponding to
+ * <code>accountID</code> has been previously stored
+ */
+ public void storePassword(AccountID accountID, String password)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ storePassword(getBundleContext(), accountID, password);
+ }
+ catch (OperationFailedException ofex)
+ {
+ throw new UndeclaredThrowableException(ofex);
+ }
+ }
+
+ /**
+ * 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).
+ * <p>
+ * TODO Delegate the implementation to {@link AccountManager} because it
+ * knows the format in which the password (among the other account
+ * properties) is to be saved.
+ * </p>
+ *
+ * @param bundleContext a currently valid bundle context.
+ * @param accountID the <tt>AccountID</tt> of the account whose password is
+ * to be stored
+ * @param password the password to be stored
+ *
+ * @throws IllegalArgumentException if no account corresponding to
+ * <tt>accountID</tt> has been previously stored.
+ * @throws OperationFailedException if anything goes wrong while storing the
+ * specified <tt>password</tt>
+ */
+ protected void storePassword(BundleContext bundleContext,
+ AccountID accountID,
+ String password)
+ throws IllegalArgumentException,
+ OperationFailedException
+ {
+ String accountPrefix
+ = findAccountPrefix(
+ bundleContext,
+ accountID,
+ getFactoryImplPackageName());
+
+ if (accountPrefix == null)
+ {
+ throw
+ new IllegalArgumentException(
+ "No previous records found for account ID: "
+ + accountID.getAccountUniqueID()
+ + " in package"
+ + getFactoryImplPackageName());
+ }
+
+ CredentialsStorageService credentialsStorage
+ = ServiceUtils.getService(
+ bundleContext,
+ CredentialsStorageService.class);
+
+ if (!credentialsStorage.storePassword(accountPrefix, password))
+ {
+ throw
+ new OperationFailedException(
+ "CredentialsStorageService failed to storePassword",
+ OperationFailedException.GENERAL_ERROR);
+ }
+
+ // Update password property also in the AccountID
+ // to prevent it from being removed during account reload
+ // in some cases.
+ accountID.setPassword(password);
+
+ }
+
+ /**
+ * 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
+ */
+ public String loadPassword(AccountID accountID)
+ {
+ return loadPassword(getBundleContext(), accountID);
+ }
+
+ /**
+ * Returns the password last saved for the specified account.
+ * <p>
+ * TODO Delegate the implementation to {@link AccountManager} because it
+ * knows the format in which the password (among the other account
+ * properties) was saved.
+ * </p>
+ *
+ * @param bundleContext a currently valid bundle context.
+ * @param accountID the AccountID for the account whose password we're
+ * looking for..
+ *
+ * @return a String containing the password for the specified accountID.
+ */
+ protected String loadPassword(BundleContext bundleContext,
+ AccountID accountID)
+ {
+ String accountPrefix = findAccountPrefix(
+ bundleContext, accountID, getFactoryImplPackageName());
+
+ if (accountPrefix == null)
+ return null;
+
+ CredentialsStorageService credentialsStorage
+ = ServiceUtils.getService(
+ bundleContext,
+ CredentialsStorageService.class);
+
+ return credentialsStorage.loadPassword(accountPrefix);
+ }
+
+ /**
+ * 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 uninstallAccount method.
+ *
+ * @param accountProperties a set of protocol (or implementation) specific
+ * properties defining the new account.
+ * @return the AccountID of the newly loaded account
+ */
+ public AccountID loadAccount(Map<String, String> accountProperties)
+ {
+ AccountID accountID = createAccount(accountProperties);
+
+ loadAccount(accountID);
+
+ return accountID;
+ }
+
+ /**
+ * Creates a protocol provider for the given <tt>accountID</tt> and
+ * registers it in the bundle context. This method has a persistent
+ * effect. Once created the resulting account will remain installed until
+ * removed through the uninstallAccount method.
+ *
+ * @param accountID the account identifier
+ * @return <tt>true</tt> if the account with the given <tt>accountID</tt> is
+ * successfully loaded, otherwise returns <tt>false</tt>
+ */
+ public boolean loadAccount(AccountID accountID)
+ {
+ // Need to obtain the original user id property, instead of calling
+ // accountID.getUserID(), because this method could return a modified
+ // version of the user id property.
+ String userID
+ = accountID.getAccountPropertyString(
+ ProtocolProviderFactory.USER_ID);
+
+ ProtocolProviderService service = createService(userID, accountID);
+
+ Dictionary<String, String> properties = new Hashtable<String, String>();
+ properties.put(PROTOCOL, protocolName);
+ properties.put(USER_ID, userID);
+
+ ServiceRegistration<ProtocolProviderService> serviceRegistration
+ = bundleContext.registerService(
+ ProtocolProviderService.class,
+ service,
+ properties);
+
+ if (serviceRegistration == null)
+ {
+ return false;
+ }
+ else
+ {
+ synchronized (registeredAccounts)
+ {
+ registeredAccounts.put(accountID, serviceRegistration);
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Unloads the account corresponding to the given <tt>accountID</tt>.
+ * Unregisters the corresponding protocol provider, but keeps the account in
+ * contrast to the uninstallAccount method.
+ *
+ * @param accountID the account identifier
+ * @return true if an account with the specified ID existed and was unloaded
+ * and false otherwise.
+ */
+ public boolean unloadAccount(AccountID accountID)
+ {
+ // Unregister the protocol provider.
+ ServiceReference<ProtocolProviderService> serRef
+ = getProviderForAccount(accountID);
+
+ if (serRef == null)
+ {
+ return false;
+ }
+
+ BundleContext bundleContext = getBundleContext();
+ ProtocolProviderService protocolProvider
+ = bundleContext.getService(serRef);
+
+ try
+ {
+ protocolProvider.unregister();
+ }
+ catch (OperationFailedException ex)
+ {
+ logger.error(
+ "Failed to unregister protocol provider for account: "
+ + accountID + " caused by: " + ex);
+ }
+
+ ServiceRegistration<ProtocolProviderService> registration;
+
+ synchronized (registeredAccounts)
+ {
+ registration = registeredAccounts.remove(accountID);
+ }
+ if (registration == null)
+ {
+ return false;
+ }
+
+ // Kill the service.
+ registration.unregister();
+
+ return true;
+ }
+
+ /**
+ * Initializes and creates an account corresponding to the specified
+ * accountProperties.
+ *
+ * @param accountProperties a set of protocol (or implementation) specific
+ * properties defining the new account.
+ * @return the AccountID of the newly created account
+ */
+ public AccountID createAccount(Map<String, String> accountProperties)
+ {
+ BundleContext bundleContext = getBundleContext();
+ if (bundleContext == null)
+ throw new NullPointerException(
+ "The specified BundleContext was null");
+
+ if (accountProperties == null)
+ throw new NullPointerException(
+ "The specified property map was null");
+
+ String userID = accountProperties.get(USER_ID);
+ if (userID == null)
+ throw new NullPointerException(
+ "The account properties contained no user id.");
+
+ String protocolName = getProtocolName();
+ if (!accountProperties.containsKey(PROTOCOL))
+ accountProperties.put(PROTOCOL, protocolName);
+
+ return createAccountID(userID, accountProperties);
+ }
+
+ /**
+ * Creates a new <code>AccountID</code> instance with a specific user ID to
+ * represent a given set of account properties.
+ * <p>
+ * The method is a pure factory allowing implementers to specify the runtime
+ * type of the created <code>AccountID</code> and customize the instance.
+ * The returned <code>AccountID</code> will later be associated with a
+ * <code>ProtocolProviderService</code> by the caller (e.g. using
+ * {@link #createService(String, AccountID)}).
+ * </p>
+ *
+ * @param userID the user ID of the new instance
+ * @param accountProperties the set of properties to be represented by the
+ * new instance
+ * @return a new <code>AccountID</code> instance with the specified user ID
+ * representing the given set of account properties
+ */
+ protected abstract AccountID createAccountID(
+ String userID, Map<String, String> accountProperties);
+
+ /**
+ * Gets the name of the protocol this factory registers its
+ * <code>ProtocolProviderService</code>s with and to be placed in the
+ * properties of the accounts created by this factory.
+ *
+ * @return the name of the protocol this factory registers its
+ * <code>ProtocolProviderService</code>s with and to be placed in
+ * the properties of the accounts created by this factory
+ */
+ public String getProtocolName()
+ {
+ return protocolName;
+ }
+
+ /**
+ * Initializes a new <code>ProtocolProviderService</code> instance with a
+ * specific user ID to represent a specific <code>AccountID</code>.
+ * <p>
+ * The method is a pure factory allowing implementers to specify the runtime
+ * type of the created <code>ProtocolProviderService</code> and customize
+ * the instance. The caller will later register the returned service with
+ * the <code>BundleContext</code> of this factory.
+ * </p>
+ *
+ * @param userID the user ID to initialize the new instance with
+ * @param accountID the <code>AccountID</code> to be represented by the new
+ * instance
+ * @return a new <code>ProtocolProviderService</code> instance with the
+ * specific user ID representing the specified
+ * <code>AccountID</code>
+ */
+ protected abstract ProtocolProviderService createService(String userID,
+ AccountID accountID);
+
+ /**
+ * Removes the account with <tt>accountID</tt> from the set of accounts
+ * that are persistently stored inside the configuration service.
+ *
+ * @param accountID the AccountID of the account to remove.
+ *
+ * @return true if an account has been removed and false otherwise.
+ */
+ protected boolean removeStoredAccount(AccountID accountID)
+ {
+ return getAccountManager().removeStoredAccount(this, accountID);
+ }
+
+ /**
+ * Returns the prefix for all persistently stored properties of the account
+ * with the specified id.
+ * @param bundleContext a currently valid bundle context.
+ * @param accountID the AccountID of the account whose properties we're
+ * looking for.
+ * @param sourcePackageName a String containing the package name of the
+ * concrete factory class that extends us.
+ * @return a String indicating the ConfigurationService property name
+ * prefix under which all account properties are stored or null if no
+ * account corresponding to the specified id was found.
+ */
+ public static String findAccountPrefix(BundleContext bundleContext,
+ AccountID accountID,
+ String sourcePackageName)
+ {
+ ServiceReference<ConfigurationService> confReference
+ = bundleContext.getServiceReference(ConfigurationService.class);
+ ConfigurationService configurationService
+ = bundleContext.getService(confReference);
+
+ //first retrieve all accounts that we've registered
+ List<String> storedAccounts =
+ configurationService.getPropertyNamesByPrefix(sourcePackageName,
+ true);
+
+ //find an account with the corresponding id.
+ for (String accountRootPropertyName : storedAccounts)
+ {
+ //unregister the account in the configuration service.
+ //all the properties must have been registered in the following
+ //hierarchy:
+ //net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME
+ String accountUID = configurationService.getString(
+ accountRootPropertyName //node id
+ + "." + ACCOUNT_UID); // propname
+
+ if (accountID.getAccountUniqueID().equals(accountUID))
+ {
+ return accountRootPropertyName;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the name of the package that we're currently running in (i.e.
+ * the name of the package containing the proto factory that extends us).
+ *
+ * @return a String containing the package name of the concrete factory
+ * class that extends us.
+ */
+ private String getFactoryImplPackageName()
+ {
+ String className = getClass().getName();
+
+ return className.substring(0, className.lastIndexOf('.'));
+ }
+
+ /**
+ * Prepares the factory for bundle shutdown.
+ */
+ public void stop()
+ {
+ if (logger.isTraceEnabled())
+ logger.trace("Preparing to stop all protocol providers of" + this);
+
+ synchronized (registeredAccounts)
+ {
+ for (ServiceRegistration<ProtocolProviderService> reg
+ : registeredAccounts.values())
+ {
+ stop(reg);
+ reg.unregister();
+ }
+
+ registeredAccounts.clear();
+ }
+ }
+
+ /**
+ * Shuts down the <code>ProtocolProviderService</code> representing an
+ * account registered with this factory.
+ *
+ * @param registeredAccount the <code>ServiceRegistration</code> of the
+ * <code>ProtocolProviderService</code> representing an account
+ * registered with this factory
+ */
+ protected void stop(
+ ServiceRegistration<ProtocolProviderService> registeredAccount)
+ {
+ ProtocolProviderService protocolProviderService
+ = getBundleContext().getService(registeredAccount.getReference());
+
+ protocolProviderService.shutdown();
+ }
+
+ /**
+ * Get the <tt>AccountManager</tt> of the protocol.
+ *
+ * @return <tt>AccountManager</tt> of the protocol
+ */
+ private AccountManager getAccountManager()
+ {
+ BundleContext bundleContext = getBundleContext();
+ ServiceReference<AccountManager> serviceReference
+ = bundleContext.getServiceReference(AccountManager.class);
+
+ return bundleContext.getService(serviceReference);
+ }
+
+
+ /**
+ * Finds registered <tt>ProtocolProviderFactory</tt> for given
+ * <tt>protocolName</tt>.
+ * @param bundleContext the OSGI bundle context that will be used.
+ * @param protocolName the protocol name.
+ * @return Registered <tt>ProtocolProviderFactory</tt> for given protocol
+ * name or <tt>null</tt> if no provider was found.
+ */
+ static public ProtocolProviderFactory getProtocolProviderFactory(
+ BundleContext bundleContext,
+ String protocolName)
+ {
+ Collection<ServiceReference<ProtocolProviderFactory>> serRefs;
+ String osgiFilter
+ = "(" + ProtocolProviderFactory.PROTOCOL + "=" + protocolName + ")";
+
+ try
+ {
+ serRefs
+ = bundleContext.getServiceReferences(
+ ProtocolProviderFactory.class,
+ osgiFilter);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ serRefs = null;
+ logger.error(ex);
+ }
+ if ((serRefs == null) || serRefs.isEmpty())
+ return null;
+ else
+ return bundleContext.getService(serRefs.iterator().next());
+ }
+}