diff options
-rw-r--r-- | resources/languages/resources.properties | 14 | ||||
-rw-r--r-- | src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java | 838 | ||||
-rw-r--r-- | src/net/java/sip/communicator/service/protocol/AccountManager.java | 784 | ||||
-rw-r--r-- | src/net/java/sip/communicator/service/protocol/CallPeerState.java | 104 | ||||
-rw-r--r-- | src/net/java/sip/communicator/service/protocol/ProtocolProviderActivator.java (renamed from src/net/java/sip/communicator/impl/protocol/ProtocolProviderActivator.java) | 32 | ||||
-rw-r--r-- | src/net/java/sip/communicator/service/protocol/SingleCallInProgressPolicy.java (renamed from src/net/java/sip/communicator/impl/protocol/SingleCallInProgressPolicy.java) | 3 | ||||
-rw-r--r-- | src/net/java/sip/communicator/service/protocol/protocol.provider.manifest.mf | 5 |
7 files changed, 864 insertions, 916 deletions
diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index ac0e409..dbdc417 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -74,6 +74,7 @@ service.gui.BAN_FAILED_NOT_ENOUGH_PERMISSIONS=Failed to ban {0}. You don''t have service.gui.BRB_MESSAGE=I'm gone right now, but I'll be back.
service.gui.BROWSE=Browse
service.gui.BUSY_MESSAGE=Sorry, I'm busy right now.
+service.gui.BUSY_STATUS=Busy
service.gui.CALL=Call
service.gui.CALL_CONTACT=Call contact
service.gui.CALL_FAILED=Call failed
@@ -114,7 +115,10 @@ service.gui.CLOSE_CHAT_ACTIVE_FILE_TRANSFER=You have active file transfers. Are service.gui.COMPARE_WITH_PARTNER=Compare with partner and click the padlock to confirm.
# keep the following string short
service.gui.COMPARE_WITH_PARTNER_SHORT=Compare with partner: {0}
+service.gui.CONNECTED_STATUS=Connected
service.gui.CONNECTING=Connecting...
+service.gui.CONNECTING_STATUS=Connecting
+service.gui.CONNECTING_EARLY_MEDIA_STATUS=Connecting*
service.gui.CONNECTION=Connection
service.gui.CONNECTION_FAILED_MSG=Connection failed for the following account: User name: {0}, Server name: {1}. Please check your network connection or contact your network administrator for more information.
service.gui.CONNECTION_EXPIRED_MSG=You are currently disconnected from the {0} server.
@@ -143,6 +147,7 @@ service.gui.DATE=Date service.gui.DELETE=Delete
service.gui.DESKTOP_SHARING_WARNING=<b>Are you sure you want to start screen sharing?</b> <br> Clicking OK will let people on this call see your screen.
service.gui.DIALPAD=Dialpad
+service.gui.DISCONNECTED_STATUS=Disconnected
service.gui.DND_STATUS=Do not disturb
service.gui.DO_NOT_ASK_AGAIN=Don't ask again
service.gui.DO_NOT_SHOW_AGAIN=Don't show this message again
@@ -162,6 +167,7 @@ service.gui.EXTENDED_CRITERIA=Extended criteria service.gui.GENERAL=General
service.gui.GENERAL_ERROR=General error
service.gui.GROUP_NAME=Group name
+service.gui.FAILED_STATUS=Call failed
service.gui.FAILED_TO_JOIN_CHAT_ROOM=Failed to join chat room with name: {0}.
service.gui.FFC_STATUS=Free for chat
service.gui.FILE=&File
@@ -218,6 +224,8 @@ service.gui.IDENTIFIER=Identifier service.gui.IGNORE=&Ignore
service.gui.INSERT_SMILEY=Insert smiley
service.gui.INCOMING_CALL=Incoming call received from: {0}
+service.gui.INCOMING_CALL_STATUS=Incoming call
+service.gui.INITIATING_CALL_STATUS=Initiating call
service.gui.INVITATION=Invitation text
service.gui.INVITATION_RECEIVED=Invitation received
service.gui.INVITATION_RECEIVED_MSG={0} has invited you to join {1} chat room. You could accept, reject or ignore this invitation.
@@ -244,6 +252,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.LOCALLY_ON_HOLD_STATUS=Locally on hold
service.gui.LOGIN=&Login
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}.
@@ -278,6 +287,7 @@ service.gui.MULTIPLE_LOGINS=You have logged in more than once with the same acco service.gui.MY_CHAT_ROOMS=Go to chat room...
service.gui.MY_CHAT_ROOMS_TITLE=Go to chat room
service.gui.MUTE=Mute
+service.gui.MUTUALLY_ON_HOLD_STATUS=Mutually On Hold
service.gui.NETWORK=Network
service.gui.NETWORK_FAILURE=Network failure
service.gui.NEXT=&Next
@@ -325,6 +335,7 @@ service.gui.READY=Ready service.gui.REASON=Reason
service.gui.RECEIVED=received
service.gui.RECONNECTION_LIMIT_EXCEEDED=You have have been disconnecting and reconnecting to the server too fast. The following account: User name: {0}, Server name: {1} is temporarily banned and would have to wait a bit before trying to login again.
+service.gui.REFERRED_STATUS=Referred
service.gui.REJECT=&Reject
service.gui.REMEMBER_PASSWORD=Remember password
service.gui.REMOVE=&Remove
@@ -333,11 +344,13 @@ service.gui.REMOVE_ACCOUNT_MESSAGE=Are you sure you want to remove this account? service.gui.REMOVE_CONTACT=&Remove contact
service.gui.REMOVE_CONTACT_TEXT=<DIV>Are you sure you want to remove <B> {0} </B><BR>from your contact list?</DIV>
service.gui.REMOVE_GROUP=&Remove group
+service.gui.REMOTELY_ON_HOLD_STATUS=Remotely on hold
service.gui.RENAME=&Rename
service.gui.RENAME_CONTACT=Re&name contact
service.gui.RENAME_CONTACT_WIZARD=In the field below you can specify the name you would like to use for the given contact.
service.gui.RENAME_GROUP=Re&name group
service.gui.RENAME_GROUP_INFO=In the field below you can specify the name you would like to use for the given group.
+service.gui.RINGING_STATUS=Ringing
service.gui.REQUEST=&Request
service.gui.REQUEST_AUTHORIZATION=&Request authorization
service.gui.REQUEST_AUTHORIZATION_MSG=Can''t add {0} to your Contact List. {0} must authorize your request to add him/her. Please enter your request below.
@@ -407,6 +420,7 @@ service.gui.USER_EXISTS_ERROR=This user already exists on the selected network. service.gui.USERNAME_NULL=Please fill the name of your account.
service.gui.ACCOUNT_CREATION_FAILED=We failed to create your account due to the following error: {0}
service.gui.UNKNOWN=Unknown user
+service.gui.UNKNOWN_STATUS=Unknown state
service.gui.UNREGISTERED_MESSAGE=Unable to connect the following account: User name: {0}, Server name: {1}. You are currently offline.
service.gui.VIDEO_CALL=&Video call
service.gui.VIEW=&View
diff --git a/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java b/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java deleted file mode 100644 index 5bbbf93..0000000 --- a/src/net/java/sip/communicator/impl/protocol/AccountManagerImpl.java +++ /dev/null @@ -1,838 +0,0 @@ -/*
- * 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.impl.protocol;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.configuration.*;
-import net.java.sip.communicator.service.credentialsstorage.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * Represents an implementation of <tt>AccountManager</tt> which loads the
- * accounts in a separate thread.
- *
- * @author Lubomir Marinov
- * @author Yana Stamcheva
- */
-public class AccountManagerImpl
- implements AccountManager
-{
-
- /**
- * The delay in milliseconds the background <tt>Thread</tt> loading the
- * stored accounts should wait before dying so that it doesn't get recreated
- * for each <tt>ProtocolProviderFactory</tt> registration.
- */
- private static final long LOAD_STORED_ACCOUNTS_TIMEOUT = 30000;
-
- /**
- * The <tt>BundleContext</tt> this service is registered in.
- */
- private final BundleContext bundleContext;
-
- /**
- * The <tt>AccountManagerListener</tt>s currently interested in the
- * events fired by this manager.
- */
- private final List<AccountManagerListener> listeners =
- new LinkedList<AccountManagerListener>();
-
- /**
- * The queue of <tt>ProtocolProviderFactory</tt> services awaiting their
- * stored accounts to be loaded.
- */
- private final Queue<ProtocolProviderFactory> loadStoredAccountsQueue =
- new LinkedList<ProtocolProviderFactory>();
-
- /**
- * The <tt>Thread</tt> loading the stored accounts of the
- * <tt>ProtocolProviderFactory</tt> services waiting in
- * {@link #loadStoredAccountsQueue}.
- */
- private Thread loadStoredAccountsThread;
-
- /**
- * The <tt>Logger</tt> used by this <tt>AccountManagerImpl</tt> instance for
- * logging output.
- */
- private final Logger logger = Logger.getLogger(AccountManagerImpl.class);
-
- /**
- * The list of <tt>AccountID</tt>s, corresponding to all stored accounts.
- */
- private Vector<AccountID> storedAccounts = new Vector<AccountID>();
-
- /**
- * Initializes a new <tt>AccountManagerImpl</tt> instance loaded in a
- * specific <tt>BundleContext</tt> (in which the caller will usually
- * later register it).
- *
- * @param bundleContext the <tt>BundleContext</tt> in which the new
- * instance is loaded (and in which the caller will usually later
- * register it as a service)
- */
- public AccountManagerImpl(BundleContext bundleContext)
- {
- this.bundleContext = bundleContext;
-
- this.bundleContext.addServiceListener(new ServiceListener()
- {
- public void serviceChanged(ServiceEvent serviceEvent)
- {
- AccountManagerImpl.this.serviceChanged(serviceEvent);
- }
- });
- }
-
- /**
- * Implements AccountManager#addListener(AccountManagerListener).
- * @param listener the <tt>AccountManagerListener</tt> to add
- */
- public void addListener(AccountManagerListener listener)
- {
- synchronized (listeners)
- {
- if (!listeners.contains(listener))
- listeners.add(listener);
- }
- }
-
- /**
- * Loads the accounts stored for a specific
- * <tt>ProtocolProviderFactory</tt>.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> to load the
- * stored accounts of
- */
- private void doLoadStoredAccounts(ProtocolProviderFactory factory)
- {
- ConfigurationService configService
- = ProtocolProviderActivator.getConfigurationService();
- String factoryPackage = getFactoryImplPackageName(factory);
- List<String> accounts
- = configService.getPropertyNamesByPrefix(factoryPackage, true);
-
- if (logger.isDebugEnabled())
- logger.debug("Discovered " + accounts.size() + " stored "
- + factoryPackage + " accounts");
-
- for (Iterator<String> storedAccountIter = accounts.iterator();
- storedAccountIter.hasNext();)
- {
- String storedAccount = storedAccountIter.next();
-
- if (logger.isDebugEnabled())
- logger.debug("Loading account " + storedAccount);
-
- List<String> storedAccountProperties =
- configService.getPropertyNamesByPrefix(storedAccount, true);
- Map<String, String> accountProperties =
- new Hashtable<String, String>();
- boolean disabled = false;
- CredentialsStorageService credentialsStorage
- = ServiceUtils.getService(
- bundleContext,
- CredentialsStorageService.class);
-
- for (Iterator<String> storedAccountPropertyIter
- = storedAccountProperties.iterator();
- storedAccountPropertyIter.hasNext();)
- {
- String property = storedAccountPropertyIter.next();
- String value = configService.getString(property);
-
- property = stripPackagePrefix(property);
-
- if (ProtocolProviderFactory.IS_ACCOUNT_DISABLED.equals(property))
- disabled = Boolean.parseBoolean(value);
- // Decode passwords.
- else if (ProtocolProviderFactory.PASSWORD.equals(property)
- && !credentialsStorage.isStoredEncrypted(storedAccount))
- {
- if ((value != null) && value.length() != 0)
- {
-
- /*
- * TODO Converting byte[] to String using the platform's
- * default charset may result in an invalid password.
- */
- value = new String(Base64.decode(value));
- }
- }
-
- if (value != null)
- accountProperties.put(property, value);
- }
-
- try
- {
- AccountID accountID = factory.createAccount(accountProperties);
-
- // If for some reason the account id is not created we move to
- // the next account.
- if (accountID == null)
- continue;
-
- synchronized (storedAccounts)
- {
- storedAccounts.add(accountID);
- }
- if (!disabled)
- factory.loadAccount(accountID);
- }
- catch (Exception ex)
- {
-
- /*
- * Swallow the exception in order to prevent a single account
- * from halting the loading of subsequent accounts.
- */
- logger.error("Failed to load account " + accountProperties, ex);
- }
- }
- }
-
- /**
- * Notifies the registered {@link #listeners} that the stored accounts of a
- * specific <tt>ProtocolProviderFactory</tt> have just been loaded.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> which had its
- * stored accounts just loaded
- */
- private void fireStoredAccountsLoaded(ProtocolProviderFactory factory)
- {
- AccountManagerListener[] listeners;
- synchronized (this.listeners)
- {
- listeners =
- this.listeners
- .toArray(new AccountManagerListener[this.listeners.size()]);
- }
-
- int listenerCount = listeners.length;
- if (listenerCount > 0)
- {
- AccountManagerEvent event =
- new AccountManagerEvent(this,
- AccountManagerEvent.STORED_ACCOUNTS_LOADED, factory);
-
- for (int listenerIndex = 0;
- listenerIndex < listenerCount; listenerIndex++)
- {
- listeners[listenerIndex].handleAccountManagerEvent(event);
- }
- }
- }
-
- private String getFactoryImplPackageName(ProtocolProviderFactory factory)
- {
- String className = factory.getClass().getName();
-
- return className.substring(0, className.lastIndexOf('.'));
- }
-
- public boolean hasStoredAccounts(String protocolName, boolean includeHidden)
- {
- ServiceReference[] factoryRefs = null;
- boolean hasStoredAccounts = false;
-
- try
- {
- factoryRefs
- = bundleContext.getServiceReferences(
- ProtocolProviderFactory.class.getName(), null);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error(
- "Failed to retrieve the registered ProtocolProviderFactories",
- ex);
- }
-
- if ((factoryRefs != null) && (factoryRefs.length > 0))
- {
- ConfigurationService configService
- = ProtocolProviderActivator.getConfigurationService();
-
- for (ServiceReference factoryRef : factoryRefs)
- {
- ProtocolProviderFactory factory
- = (ProtocolProviderFactory)
- bundleContext.getService(factoryRef);
-
- if ((protocolName != null)
- && !protocolName.equals(factory.getProtocolName()))
- {
- continue;
- }
-
- String factoryPackage = getFactoryImplPackageName(factory);
- List<String> storedAccounts
- = configService
- .getPropertyNamesByPrefix(factoryPackage, true);
-
- /* Ignore the hidden accounts. */
- for (Iterator<String> storedAccountIter =
- storedAccounts.iterator(); storedAccountIter.hasNext();)
- {
- String storedAccount = storedAccountIter.next();
- List<String> storedAccountProperties =
- configService.getPropertyNamesByPrefix(storedAccount,
- true);
- boolean hidden = false;
-
- if (!includeHidden)
- {
- for (Iterator<String> storedAccountPropertyIter =
- storedAccountProperties.iterator();
- storedAccountPropertyIter.hasNext();)
- {
- String property = storedAccountPropertyIter.next();
- String value = configService.getString(property);
-
- property = stripPackagePrefix(property);
-
- if (ProtocolProviderFactory.IS_PROTOCOL_HIDDEN
- .equals(property))
- {
- hidden = (value != null);
- break;
- }
- }
- }
-
- if (!hidden)
- {
- hasStoredAccounts = true;
- break;
- }
- }
-
- if (hasStoredAccounts || (protocolName != null))
- {
- break;
- }
- }
- }
- return hasStoredAccounts;
- }
-
- /**
- * Loads the accounts stored for a specific
- * <tt>ProtocolProviderFactory</tt> and notifies the registered
- * {@link #listeners} that the stored accounts of the specified
- * <tt>factory</tt> have just been loaded
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> to load the
- * stored accounts of
- */
- private void loadStoredAccounts(ProtocolProviderFactory factory)
- {
- doLoadStoredAccounts(factory);
-
- fireStoredAccountsLoaded(factory);
- }
-
- /**
- * Notifies this manager that a specific
- * <tt>ProtocolProviderFactory</tt> has been registered as a service.
- * The current implementation queues the specified <tt>factory</tt> to
- * have its stored accounts as soon as possible.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> which has been
- * registered as a service.
- */
- private void protocolProviderFactoryRegistered(
- ProtocolProviderFactory factory)
- {
- queueLoadStoredAccounts(factory);
- }
-
- /**
- * Queues a specific <tt>ProtocolProviderFactory</tt> to have its stored
- * accounts loaded as soon as possible.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> to be queued for
- * loading its stored accounts as soon as possible
- */
- private void queueLoadStoredAccounts(ProtocolProviderFactory factory)
- {
- synchronized (loadStoredAccountsQueue)
- {
- loadStoredAccountsQueue.add(factory);
- loadStoredAccountsQueue.notify();
-
- if (loadStoredAccountsThread == null)
- {
- loadStoredAccountsThread = new Thread()
- {
- public void run()
- {
- runInLoadStoredAccountsThread();
- }
- };
- loadStoredAccountsThread.setDaemon(true);
- loadStoredAccountsThread
- .setName("AccountManager.loadStoredAccounts");
- loadStoredAccountsThread.start();
- }
- }
- }
-
- /**
- * Implements AccountManager#removeListener(AccountManagerListener).
- * @param listener the <tt>AccountManagerListener</tt> to remove
- */
- public void removeListener(AccountManagerListener listener)
- {
- synchronized (listeners)
- {
- listeners.remove(listener);
- }
- }
-
- /**
- * Running in {@link #loadStoredAccountsThread}, loads the stored accounts
- * of the <tt>ProtocolProviderFactory</tt> services waiting in
- * {@link #loadStoredAccountsQueue}
- */
- private void runInLoadStoredAccountsThread()
- {
- boolean interrupted = false;
- while (!interrupted)
- {
- try
- {
- ProtocolProviderFactory factory;
-
- synchronized (loadStoredAccountsQueue)
- {
- factory = loadStoredAccountsQueue.poll();
- if (factory == null)
- {
- /*
- * Technically, we should be handing spurious wakeups.
- * However, we cannot check the condition in a queue.
- * Anyway, we just want to keep this Thread alive long
- * enough to allow it to not be re-created multiple
- * times and not handing a spurious wakeup will just
- * cause such an inconvenience.
- */
- try
- {
- loadStoredAccountsQueue
- .wait(LOAD_STORED_ACCOUNTS_TIMEOUT);
- }
- catch (InterruptedException ex)
- {
- logger
- .warn(
- "The loading of the stored accounts has"
- + " been interrupted",
- ex);
- interrupted = true;
- break;
- }
- factory = loadStoredAccountsQueue.poll();
- }
- }
-
- if (factory != null)
- {
- try
- {
- loadStoredAccounts(factory);
- }
- catch (Exception ex)
- {
-
- /*
- * Swallow the exception in order to prevent a single
- * factory from halting the loading of subsequent
- * factories.
- */
- logger.error("Failed to load accounts for " + factory,
- ex);
- }
- }
- }
- finally
- {
- synchronized (loadStoredAccountsQueue)
- {
- if (!interrupted && (loadStoredAccountsQueue.size() <= 0))
- {
- if (loadStoredAccountsThread == Thread.currentThread())
- {
- loadStoredAccountsThread = null;
- }
- break;
- }
- }
- }
- }
- }
-
- /**
- * Notifies this manager that an OSGi service has changed. The current
- * implementation tracks the registrations of
- * <tt>ProtocolProviderFactory</tt> services in order to queue them for
- * loading their stored accounts.
- *
- * @param serviceEvent the <tt>ServiceEvent</tt> containing the event
- * data
- */
- private void serviceChanged(ServiceEvent serviceEvent)
- {
- switch (serviceEvent.getType())
- {
- case ServiceEvent.REGISTERED:
- Object service
- = bundleContext.getService(serviceEvent.getServiceReference());
-
- if (service instanceof ProtocolProviderFactory)
- {
- protocolProviderFactoryRegistered(
- (ProtocolProviderFactory) service);
- }
- break;
- default:
- break;
- }
- }
-
- /**
- * Stores an account represented in the form of an <tt>AccountID</tt>
- * created by a specific <tt>ProtocolProviderFactory</tt>.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> which created the
- * account to be stored
- * @param accountID the account in the form of <tt>AccountID</tt> to be
- * stored
- * @throws OperationFailedException if anything goes wrong while storing the
- * account
- */
- public void storeAccount(
- ProtocolProviderFactory factory,
- AccountID accountID)
- throws OperationFailedException
- {
- synchronized (storedAccounts)
- {
- if (!storedAccounts.contains(accountID))
- storedAccounts.add(accountID);
- }
-
- ConfigurationService configurationService
- = ProtocolProviderActivator.getConfigurationService();
- String factoryPackage = getFactoryImplPackageName(factory);
-
- // First check if such accountID already exists in the configuration.
- List<String> storedAccounts =
- configurationService.getPropertyNamesByPrefix(factoryPackage, true);
- String accountUID = accountID.getAccountUniqueID();
- String accountNodeName = null;
-
- for (Iterator<String> storedAccountIter = storedAccounts.iterator();
- storedAccountIter.hasNext();)
- {
- String storedAccount = storedAccountIter.next();
- String storedAccountUID =
- configurationService.getString(storedAccount + "."
- + ProtocolProviderFactory.ACCOUNT_UID);
-
- if (storedAccountUID.equals(accountUID))
- accountNodeName = configurationService.getString(storedAccount);
- }
-
- Map<String, Object> configurationProperties
- = new HashMap<String, Object>();
-
- // Create a unique node name of the properties node that will contain
- // this account's properties.
- if (accountNodeName == null)
- {
- accountNodeName = "acc" + Long.toString(System.currentTimeMillis());
-
- // set a value for the persistent node so that we could later
- // retrieve it as a property
- configurationProperties.put(
- factoryPackage /* prefix */ + "." + accountNodeName,
- accountNodeName);
-
- // register the account in the configuration service.
- // we register all the properties in the following hierarchy
- //net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME
- configurationProperties.put(factoryPackage// prefix
- + "." + accountNodeName // node name for the account id
- + "." + ProtocolProviderFactory.ACCOUNT_UID, // propname
- accountID.getAccountUniqueID()); // value
- }
-
- // store the rest of the properties
- Map<String, String> accountProperties = accountID.getAccountProperties();
-
- for (Map.Entry<String, String> entry : accountProperties.entrySet())
- {
- String property = entry.getKey();
- String value = entry.getValue();
-
- // If the property is a password, store it securely.
- if (property.equals(ProtocolProviderFactory.PASSWORD))
- {
- CredentialsStorageService credentialsStorage
- = ServiceUtils.getService(
- bundleContext,
- CredentialsStorageService.class);
- String accountPrefix = factoryPackage + "." + accountNodeName;
-
- // encrypt and store
- if ((value != null)
- && (value.length() != 0)
- && !credentialsStorage.storePassword(
- accountPrefix,
- value))
- {
- throw
- new OperationFailedException(
- "CredentialsStorageService failed to"
- + " storePassword",
- OperationFailedException.GENERAL_ERROR);
- }
- }
- else
- {
- configurationProperties.put(
- factoryPackage // prefix
- + "." + accountNodeName // a unique node name for the account id
- + "." + property, // propname
- value); // value
- }
- }
-
- if (configurationProperties.size() > 0)
- configurationService.setProperties(configurationProperties);
-
- if (logger.isDebugEnabled())
- logger.debug("Stored account for id " + accountID.getAccountUniqueID()
- + " for package " + factoryPackage);
- }
-
- /**
- * Removes the account with <tt>accountID</tt> from the set of accounts
- * that are persistently stored inside the configuration service.
- *
- * @param factory the <tt>ProtocolProviderFactory</tt> which created the
- * account to be stored
- * @param accountID the AccountID of the account to remove.
- * @return true if an account has been removed and false otherwise.
- */
- public boolean removeStoredAccount(ProtocolProviderFactory factory,
- AccountID accountID)
- {
- synchronized (storedAccounts)
- {
- if (storedAccounts.contains(accountID))
- storedAccounts.remove(accountID);
- }
-
- String factoryPackage = getFactoryImplPackageName(factory);
-
- // remove the stored password explicitly using credentials service
- CredentialsStorageService credentialsStorage
- = ServiceUtils.getService(
- bundleContext,
- CredentialsStorageService.class);
- String accountPrefix =
- ProtocolProviderFactory.findAccountPrefix(bundleContext, accountID,
- factoryPackage);
-
- credentialsStorage.removePassword(accountPrefix);
-
- ConfigurationService configurationService
- = ServiceUtils.getService(
- bundleContext,
- ConfigurationService.class);
- //first retrieve all accounts that we've registered
- List<String> storedAccounts
- = configurationService.getPropertyNamesByPrefix(
- factoryPackage, 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
- + "." + ProtocolProviderFactory.ACCOUNT_UID); // propname
-
- if (accountUID.equals(accountID.getAccountUniqueID()))
- {
- //retrieve the names of all properties registered for the
- //current account.
- List<String> accountPropertyNames
- = configurationService.getPropertyNamesByPrefix(
- accountRootPropertyName, false);
-
- //set all account properties to null in order to remove them.
- for (String propName : accountPropertyNames)
- configurationService.setProperty(propName, null);
-
- //and now remove the parent too.
- configurationService.setProperty(accountRootPropertyName, null);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns an <tt>Iterator</tt> over a list of all stored
- * <tt>AccountID</tt>s. The list of stored accounts include all registered
- * accounts and all disabled accounts. In other words in this list we could
- * find accounts that aren't loaded.
- * <p>
- * In order to check if an account is already loaded please use the
- * #isAccountLoaded(AccountID accountID) method. To load an account use the
- * #loadAccount(AccountID accountID) method.
- *
- * @return an <tt>Iterator</tt> over a list of all stored
- * <tt>AccountID</tt>s
- */
- public Collection<AccountID> getStoredAccounts()
- {
- synchronized (storedAccounts)
- {
- return new Vector<AccountID>(storedAccounts);
- }
- }
-
- /**
- * Loads the account corresponding to the given <tt>AccountID</tt>. An
- * account is loaded when its <tt>ProtocolProviderService</tt> is registered
- * in the bundle context. This method is meant to load the account through
- * the corresponding <tt>ProtocolProviderFactory</tt>.
- *
- * @param accountID the identifier of the account to load
- * @throws OperationFailedException if anything goes wrong while loading the
- * account corresponding to the specified <tt>accountID</tt>
- */
- public void loadAccount(AccountID accountID)
- throws OperationFailedException
- {
- // If the account with the given id is already loaded we have nothing
- // to do here.
- if (isAccountLoaded(accountID))
- return;
-
- ProtocolProviderFactory providerFactory
- = ProtocolProviderActivator.getProtocolProviderFactory(
- accountID.getProtocolName());
-
- if(providerFactory.loadAccount(accountID))
- {
- accountID.putAccountProperty(
- ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
- String.valueOf(false));
- // Finally store the modified properties.
- storeAccount(providerFactory, accountID);
- }
- }
-
- /**
- * Unloads the account corresponding to the given <tt>AccountID</tt>. An
- * account is unloaded when its <tt>ProtocolProviderService</tt> is
- * unregistered in the bundle context. This method is meant to unload the
- * account through the corresponding <tt>ProtocolProviderFactory</tt>.
- *
- * @param accountID the identifier of the account to load
- * @throws OperationFailedException if anything goes wrong while unloading
- * the account corresponding to the specified <tt>accountID</tt>
- */
- public void unloadAccount(AccountID accountID)
- throws OperationFailedException
- {
- // If the account with the given id is already unloaded we have nothing
- // to do here.
- if (!isAccountLoaded(accountID))
- return;
-
- ProtocolProviderFactory providerFactory
- = ProtocolProviderActivator.getProtocolProviderFactory(
- accountID.getProtocolName());
-
- // Obtain the protocol provider.
- ServiceReference serRef
- = providerFactory.getProviderForAccount(accountID);
-
- // If there's no such provider we have nothing to do here.
- if (serRef == null)
- return;
-
- ProtocolProviderService protocolProvider =
- (ProtocolProviderService) bundleContext.getService(serRef);
-
- // Set the account icon path for unloaded accounts.
- String iconPathProperty = accountID.getAccountPropertyString(
- ProtocolProviderFactory.ACCOUNT_ICON_PATH);
-
- if (iconPathProperty == null)
- {
- accountID.putAccountProperty(
- ProtocolProviderFactory.ACCOUNT_ICON_PATH,
- protocolProvider.getProtocolIcon()
- .getIconPath(ProtocolIcon.ICON_SIZE_32x32));
- }
-
- accountID.putAccountProperty(
- ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
- String.valueOf(true));
-
- if (!providerFactory.unloadAccount(accountID))
- {
- accountID.putAccountProperty(
- ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
- String.valueOf(false));
- }
- // Finally store the modified properties.
- storeAccount(providerFactory, accountID);
- }
-
- /**
- * Checks if the account corresponding to the given <tt>accountID</tt> is
- * loaded. An account is loaded if its <tt>ProtocolProviderService</tt> is
- * registered in the bundle context. By default all accounts are loaded.
- * However the user could manually unload an account, which would be
- * unregistered from the bundle context, but would remain in the
- * configuration file.
- *
- * @param accountID the identifier of the account to load
- * @return <tt>true</tt> to indicate that the account with the given
- * <tt>accountID</tt> is loaded, <tt>false</tt> - otherwise
- */
- public boolean isAccountLoaded(AccountID accountID)
- {
- return storedAccounts.contains(accountID) && accountID.isEnabled();
- }
-
- private String stripPackagePrefix(String property)
- {
- int packageEndIndex = property.lastIndexOf('.');
-
- if (packageEndIndex != -1)
- property = property.substring(packageEndIndex + 1);
- return property;
- }
-}
diff --git a/src/net/java/sip/communicator/service/protocol/AccountManager.java b/src/net/java/sip/communicator/service/protocol/AccountManager.java index 043941b..7a17c05 100644 --- a/src/net/java/sip/communicator/service/protocol/AccountManager.java +++ b/src/net/java/sip/communicator/service/protocol/AccountManager.java @@ -8,82 +8,692 @@ package net.java.sip.communicator.service.protocol; import java.util.*;
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.credentialsstorage.*;
import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import org.osgi.framework.*;
/**
- * Represents a manager of accounts which contains the details about the format
- * in which the accounts in question are stored (i.e. knows how to store and
- * load them) and takes care of loading them on start-up.
+ * Represents an implementation of <tt>AccountManager</tt> which loads the
+ * accounts in a separate thread.
*
* @author Lubomir Marinov
* @author Yana Stamcheva
*/
-public interface AccountManager
+public class AccountManager
{
/**
- * Registers a specific listener to be notified about events fired by this
- * <tt>AccountManager</tt>. If the <tt>listener</tt> is already
- * registered, it will not be registered again.
- *
- * @param listener
- * the listener to be registered for notification events fired by
- * this <tt>AccountManager</tt>
+ * The delay in milliseconds the background <tt>Thread</tt> loading the
+ * stored accounts should wait before dying so that it doesn't get recreated
+ * for each <tt>ProtocolProviderFactory</tt> registration.
*/
- void addListener(AccountManagerListener listener);
+ private static final long LOAD_STORED_ACCOUNTS_TIMEOUT = 30000;
/**
- * Determines whether the account store represented by this manager contains
- * stored accounts.
- *
- * @param protocolName
- * the name of the protocol for which the stored accounts are to
- * be checked or <tt>null</tt> for all protocols
- * @param includeHidden
- * <tt>true</tt> to take into account both non-hidden and hidden
- * stored accounts; <tt>false</tt> for non-hidden only
- * @return <tt>true</tt> if the account store represented by this manager
- * contains stored accounts; <tt>false</tt>, otherwise
+ * The <tt>BundleContext</tt> this service is registered in.
+ */
+ private final BundleContext bundleContext;
+
+ /**
+ * The <tt>AccountManagerListener</tt>s currently interested in the
+ * events fired by this manager.
+ */
+ private final List<AccountManagerListener> listeners =
+ new LinkedList<AccountManagerListener>();
+
+ /**
+ * The queue of <tt>ProtocolProviderFactory</tt> services awaiting their
+ * stored accounts to be loaded.
+ */
+ private final Queue<ProtocolProviderFactory> loadStoredAccountsQueue =
+ new LinkedList<ProtocolProviderFactory>();
+
+ /**
+ * The <tt>Thread</tt> loading the stored accounts of the
+ * <tt>ProtocolProviderFactory</tt> services waiting in
+ * {@link #loadStoredAccountsQueue}.
+ */
+ private Thread loadStoredAccountsThread;
+
+ /**
+ * The <tt>Logger</tt> used by this <tt>AccountManagerImpl</tt> instance for
+ * logging output.
+ */
+ private final Logger logger = Logger.getLogger(AccountManager.class);
+
+ /**
+ * The list of <tt>AccountID</tt>s, corresponding to all stored accounts.
+ */
+ private Vector<AccountID> storedAccounts = new Vector<AccountID>();
+
+ /**
+ * Initializes a new <tt>AccountManagerImpl</tt> instance loaded in a
+ * specific <tt>BundleContext</tt> (in which the caller will usually
+ * later register it).
+ *
+ * @param bundleContext the <tt>BundleContext</tt> in which the new
+ * instance is loaded (and in which the caller will usually later
+ * register it as a service)
+ */
+ public AccountManager(BundleContext bundleContext)
+ {
+ this.bundleContext = bundleContext;
+
+ this.bundleContext.addServiceListener(new ServiceListener()
+ {
+ public void serviceChanged(ServiceEvent serviceEvent)
+ {
+ AccountManager.this.serviceChanged(serviceEvent);
+ }
+ });
+ }
+
+ /**
+ * Implements AccountManager#addListener(AccountManagerListener).
+ * @param listener the <tt>AccountManagerListener</tt> to add
+ */
+ public void addListener(AccountManagerListener listener)
+ {
+ synchronized (listeners)
+ {
+ if (!listeners.contains(listener))
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Loads the accounts stored for a specific
+ * <tt>ProtocolProviderFactory</tt>.
+ *
+ * @param factory the <tt>ProtocolProviderFactory</tt> to load the
+ * stored accounts of
+ */
+ private void doLoadStoredAccounts(ProtocolProviderFactory factory)
+ {
+ ConfigurationService configService
+ = ProtocolProviderActivator.getConfigurationService();
+ String factoryPackage = getFactoryImplPackageName(factory);
+ List<String> accounts
+ = configService.getPropertyNamesByPrefix(factoryPackage, true);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Discovered " + accounts.size() + " stored "
+ + factoryPackage + " accounts");
+
+ for (Iterator<String> storedAccountIter = accounts.iterator();
+ storedAccountIter.hasNext();)
+ {
+ String storedAccount = storedAccountIter.next();
+
+ if (logger.isDebugEnabled())
+ logger.debug("Loading account " + storedAccount);
+
+ List<String> storedAccountProperties =
+ configService.getPropertyNamesByPrefix(storedAccount, true);
+ Map<String, String> accountProperties =
+ new Hashtable<String, String>();
+ boolean disabled = false;
+ CredentialsStorageService credentialsStorage
+ = ServiceUtils.getService(
+ bundleContext,
+ CredentialsStorageService.class);
+
+ for (Iterator<String> storedAccountPropertyIter
+ = storedAccountProperties.iterator();
+ storedAccountPropertyIter.hasNext();)
+ {
+ String property = storedAccountPropertyIter.next();
+ String value = configService.getString(property);
+
+ property = stripPackagePrefix(property);
+
+ if (ProtocolProviderFactory.IS_ACCOUNT_DISABLED.equals(property))
+ disabled = Boolean.parseBoolean(value);
+ // Decode passwords.
+ else if (ProtocolProviderFactory.PASSWORD.equals(property)
+ && !credentialsStorage.isStoredEncrypted(storedAccount))
+ {
+ if ((value != null) && value.length() != 0)
+ {
+
+ /*
+ * TODO Converting byte[] to String using the platform's
+ * default charset may result in an invalid password.
+ */
+ value = new String(Base64.decode(value));
+ }
+ }
+
+ if (value != null)
+ accountProperties.put(property, value);
+ }
+
+ try
+ {
+ AccountID accountID = factory.createAccount(accountProperties);
+
+ // If for some reason the account id is not created we move to
+ // the next account.
+ if (accountID == null)
+ continue;
+
+ synchronized (storedAccounts)
+ {
+ storedAccounts.add(accountID);
+ }
+ if (!disabled)
+ factory.loadAccount(accountID);
+ }
+ catch (Exception ex)
+ {
+
+ /*
+ * Swallow the exception in order to prevent a single account
+ * from halting the loading of subsequent accounts.
+ */
+ logger.error("Failed to load account " + accountProperties, ex);
+ }
+ }
+ }
+
+ /**
+ * Notifies the registered {@link #listeners} that the stored accounts of a
+ * specific <tt>ProtocolProviderFactory</tt> have just been loaded.
+ *
+ * @param factory the <tt>ProtocolProviderFactory</tt> which had its
+ * stored accounts just loaded
+ */
+ private void fireStoredAccountsLoaded(ProtocolProviderFactory factory)
+ {
+ AccountManagerListener[] listeners;
+ synchronized (this.listeners)
+ {
+ listeners =
+ this.listeners
+ .toArray(new AccountManagerListener[this.listeners.size()]);
+ }
+
+ int listenerCount = listeners.length;
+ if (listenerCount > 0)
+ {
+ AccountManagerEvent event =
+ new AccountManagerEvent(this,
+ AccountManagerEvent.STORED_ACCOUNTS_LOADED, factory);
+
+ for (int listenerIndex = 0;
+ listenerIndex < listenerCount; listenerIndex++)
+ {
+ listeners[listenerIndex].handleAccountManagerEvent(event);
+ }
+ }
+ }
+
+ private String getFactoryImplPackageName(ProtocolProviderFactory factory)
+ {
+ String className = factory.getClass().getName();
+
+ return className.substring(0, className.lastIndexOf('.'));
+ }
+
+ public boolean hasStoredAccounts(String protocolName, boolean includeHidden)
+ {
+ ServiceReference[] factoryRefs = null;
+ boolean hasStoredAccounts = false;
+
+ try
+ {
+ factoryRefs
+ = bundleContext.getServiceReferences(
+ ProtocolProviderFactory.class.getName(), null);
+ }
+ catch (InvalidSyntaxException ex)
+ {
+ logger.error(
+ "Failed to retrieve the registered ProtocolProviderFactories",
+ ex);
+ }
+
+ if ((factoryRefs != null) && (factoryRefs.length > 0))
+ {
+ ConfigurationService configService
+ = ProtocolProviderActivator.getConfigurationService();
+
+ for (ServiceReference factoryRef : factoryRefs)
+ {
+ ProtocolProviderFactory factory
+ = (ProtocolProviderFactory)
+ bundleContext.getService(factoryRef);
+
+ if ((protocolName != null)
+ && !protocolName.equals(factory.getProtocolName()))
+ {
+ continue;
+ }
+
+ String factoryPackage = getFactoryImplPackageName(factory);
+ List<String> storedAccounts
+ = configService
+ .getPropertyNamesByPrefix(factoryPackage, true);
+
+ /* Ignore the hidden accounts. */
+ for (Iterator<String> storedAccountIter =
+ storedAccounts.iterator(); storedAccountIter.hasNext();)
+ {
+ String storedAccount = storedAccountIter.next();
+ List<String> storedAccountProperties =
+ configService.getPropertyNamesByPrefix(storedAccount,
+ true);
+ boolean hidden = false;
+
+ if (!includeHidden)
+ {
+ for (Iterator<String> storedAccountPropertyIter =
+ storedAccountProperties.iterator();
+ storedAccountPropertyIter.hasNext();)
+ {
+ String property = storedAccountPropertyIter.next();
+ String value = configService.getString(property);
+
+ property = stripPackagePrefix(property);
+
+ if (ProtocolProviderFactory.IS_PROTOCOL_HIDDEN
+ .equals(property))
+ {
+ hidden = (value != null);
+ break;
+ }
+ }
+ }
+
+ if (!hidden)
+ {
+ hasStoredAccounts = true;
+ break;
+ }
+ }
+
+ if (hasStoredAccounts || (protocolName != null))
+ {
+ break;
+ }
+ }
+ }
+ return hasStoredAccounts;
+ }
+
+ /**
+ * Loads the accounts stored for a specific
+ * <tt>ProtocolProviderFactory</tt> and notifies the registered
+ * {@link #listeners} that the stored accounts of the specified
+ * <tt>factory</tt> have just been loaded
+ *
+ * @param factory the <tt>ProtocolProviderFactory</tt> to load the
+ * stored accounts of
+ */
+ private void loadStoredAccounts(ProtocolProviderFactory factory)
+ {
+ doLoadStoredAccounts(factory);
+
+ fireStoredAccountsLoaded(factory);
+ }
+
+ /**
+ * Notifies this manager that a specific
+ * <tt>ProtocolProviderFactory</tt> has been registered as a service.
+ * The current implementation queues the specified <tt>factory</tt> to
+ * have its stored accounts as soon as possible.
+ *
+ * @param factory the <tt>ProtocolProviderFactory</tt> which has been
+ * registered as a service.
+ */
+ private void protocolProviderFactoryRegistered(
+ ProtocolProviderFactory factory)
+ {
+ queueLoadStoredAccounts(factory);
+ }
+
+ /**
+ * Queues a specific <tt>ProtocolProviderFactory</tt> to have its stored
+ * accounts loaded as soon as possible.
+ *
+ * @param factory the <tt>ProtocolProviderFactory</tt> to be queued for
+ * loading its stored accounts as soon as possible
+ */
+ private void queueLoadStoredAccounts(ProtocolProviderFactory factory)
+ {
+ synchronized (loadStoredAccountsQueue)
+ {
+ loadStoredAccountsQueue.add(factory);
+ loadStoredAccountsQueue.notify();
+
+ if (loadStoredAccountsThread == null)
+ {
+ loadStoredAccountsThread = new Thread()
+ {
+ public void run()
+ {
+ runInLoadStoredAccountsThread();
+ }
+ };
+ loadStoredAccountsThread.setDaemon(true);
+ loadStoredAccountsThread
+ .setName("AccountManager.loadStoredAccounts");
+ loadStoredAccountsThread.start();
+ }
+ }
+ }
+
+ /**
+ * Implements AccountManager#removeListener(AccountManagerListener).
+ * @param listener the <tt>AccountManagerListener</tt> to remove
+ */
+ public void removeListener(AccountManagerListener listener)
+ {
+ synchronized (listeners)
+ {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Running in {@link #loadStoredAccountsThread}, loads the stored accounts
+ * of the <tt>ProtocolProviderFactory</tt> services waiting in
+ * {@link #loadStoredAccountsQueue}
*/
- boolean hasStoredAccounts(String protocolName, boolean includeHidden);
+ private void runInLoadStoredAccountsThread()
+ {
+ boolean interrupted = false;
+ while (!interrupted)
+ {
+ try
+ {
+ ProtocolProviderFactory factory;
+
+ synchronized (loadStoredAccountsQueue)
+ {
+ factory = loadStoredAccountsQueue.poll();
+ if (factory == null)
+ {
+ /*
+ * Technically, we should be handing spurious wakeups.
+ * However, we cannot check the condition in a queue.
+ * Anyway, we just want to keep this Thread alive long
+ * enough to allow it to not be re-created multiple
+ * times and not handing a spurious wakeup will just
+ * cause such an inconvenience.
+ */
+ try
+ {
+ loadStoredAccountsQueue
+ .wait(LOAD_STORED_ACCOUNTS_TIMEOUT);
+ }
+ catch (InterruptedException ex)
+ {
+ logger
+ .warn(
+ "The loading of the stored accounts has"
+ + " been interrupted",
+ ex);
+ interrupted = true;
+ break;
+ }
+ factory = loadStoredAccountsQueue.poll();
+ }
+ }
+
+ if (factory != null)
+ {
+ try
+ {
+ loadStoredAccounts(factory);
+ }
+ catch (Exception ex)
+ {
+
+ /*
+ * Swallow the exception in order to prevent a single
+ * factory from halting the loading of subsequent
+ * factories.
+ */
+ logger.error("Failed to load accounts for " + factory,
+ ex);
+ }
+ }
+ }
+ finally
+ {
+ synchronized (loadStoredAccountsQueue)
+ {
+ if (!interrupted && (loadStoredAccountsQueue.size() <= 0))
+ {
+ if (loadStoredAccountsThread == Thread.currentThread())
+ {
+ loadStoredAccountsThread = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
/**
- * Unregisters a specific listener from this <tt>AccountManager</tt> so
- * that it no longer received notifications about events fired by this
- * manager.
+ * Notifies this manager that an OSGi service has changed. The current
+ * implementation tracks the registrations of
+ * <tt>ProtocolProviderFactory</tt> services in order to queue them for
+ * loading their stored accounts.
*
- * @param listener
- * the listener to be unregistered from this
- * <tt>AccountManager</tt> so that it no longer receives
- * notifications about events fired by this manager
+ * @param serviceEvent the <tt>ServiceEvent</tt> containing the event
+ * data
*/
- void removeListener(AccountManagerListener listener);
+ private void serviceChanged(ServiceEvent serviceEvent)
+ {
+ switch (serviceEvent.getType())
+ {
+ case ServiceEvent.REGISTERED:
+ Object service
+ = bundleContext.getService(serviceEvent.getServiceReference());
+
+ if (service instanceof ProtocolProviderFactory)
+ {
+ protocolProviderFactoryRegistered(
+ (ProtocolProviderFactory) service);
+ }
+ break;
+ default:
+ break;
+ }
+ }
/**
* Stores an account represented in the form of an <tt>AccountID</tt>
* created by a specific <tt>ProtocolProviderFactory</tt>.
- *
+ *
* @param factory the <tt>ProtocolProviderFactory</tt> which created the
* account to be stored
* @param accountID the account in the form of <tt>AccountID</tt> to be
* stored
* @throws OperationFailedException if anything goes wrong while storing the
- * specified account
+ * account
*/
- void storeAccount(ProtocolProviderFactory factory, AccountID accountID)
- throws OperationFailedException;
+ public void storeAccount(
+ ProtocolProviderFactory factory,
+ AccountID accountID)
+ throws OperationFailedException
+ {
+ synchronized (storedAccounts)
+ {
+ if (!storedAccounts.contains(accountID))
+ storedAccounts.add(accountID);
+ }
+
+ ConfigurationService configurationService
+ = ProtocolProviderActivator.getConfigurationService();
+ String factoryPackage = getFactoryImplPackageName(factory);
+
+ // First check if such accountID already exists in the configuration.
+ List<String> storedAccounts =
+ configurationService.getPropertyNamesByPrefix(factoryPackage, true);
+ String accountUID = accountID.getAccountUniqueID();
+ String accountNodeName = null;
+
+ for (Iterator<String> storedAccountIter = storedAccounts.iterator();
+ storedAccountIter.hasNext();)
+ {
+ String storedAccount = storedAccountIter.next();
+ String storedAccountUID =
+ configurationService.getString(storedAccount + "."
+ + ProtocolProviderFactory.ACCOUNT_UID);
+
+ if (storedAccountUID.equals(accountUID))
+ accountNodeName = configurationService.getString(storedAccount);
+ }
+
+ Map<String, Object> configurationProperties
+ = new HashMap<String, Object>();
+
+ // Create a unique node name of the properties node that will contain
+ // this account's properties.
+ if (accountNodeName == null)
+ {
+ accountNodeName = "acc" + Long.toString(System.currentTimeMillis());
+
+ // set a value for the persistent node so that we could later
+ // retrieve it as a property
+ configurationProperties.put(
+ factoryPackage /* prefix */ + "." + accountNodeName,
+ accountNodeName);
+
+ // register the account in the configuration service.
+ // we register all the properties in the following hierarchy
+ //net.java.sip.communicator.impl.protocol.PROTO_NAME.ACC_ID.PROP_NAME
+ configurationProperties.put(factoryPackage// prefix
+ + "." + accountNodeName // node name for the account id
+ + "." + ProtocolProviderFactory.ACCOUNT_UID, // propname
+ accountID.getAccountUniqueID()); // value
+ }
+
+ // store the rest of the properties
+ Map<String, String> accountProperties = accountID.getAccountProperties();
+
+ for (Map.Entry<String, String> entry : accountProperties.entrySet())
+ {
+ String property = entry.getKey();
+ String value = entry.getValue();
+
+ // If the property is a password, store it securely.
+ if (property.equals(ProtocolProviderFactory.PASSWORD))
+ {
+ CredentialsStorageService credentialsStorage
+ = ServiceUtils.getService(
+ bundleContext,
+ CredentialsStorageService.class);
+ String accountPrefix = factoryPackage + "." + accountNodeName;
+
+ // encrypt and store
+ if ((value != null)
+ && (value.length() != 0)
+ && !credentialsStorage.storePassword(
+ accountPrefix,
+ value))
+ {
+ throw
+ new OperationFailedException(
+ "CredentialsStorageService failed to"
+ + " storePassword",
+ OperationFailedException.GENERAL_ERROR);
+ }
+ }
+ else
+ {
+ configurationProperties.put(
+ factoryPackage // prefix
+ + "." + accountNodeName // a unique node name for the account id
+ + "." + property, // propname
+ value); // value
+ }
+ }
+
+ if (configurationProperties.size() > 0)
+ configurationService.setProperties(configurationProperties);
+
+ if (logger.isDebugEnabled())
+ logger.debug("Stored account for id " + accountID.getAccountUniqueID()
+ + " for package " + factoryPackage);
+ }
/**
* Removes the account with <tt>accountID</tt> from the set of accounts
* that are persistently stored inside the configuration service.
- * <p>
+ *
* @param factory the <tt>ProtocolProviderFactory</tt> which created the
* account to be stored
* @param accountID the AccountID of the account to remove.
- * <p>
* @return true if an account has been removed and false otherwise.
*/
- boolean removeStoredAccount(ProtocolProviderFactory factory,
- AccountID accountID);
+ public boolean removeStoredAccount(ProtocolProviderFactory factory,
+ AccountID accountID)
+ {
+ synchronized (storedAccounts)
+ {
+ if (storedAccounts.contains(accountID))
+ storedAccounts.remove(accountID);
+ }
+
+ String factoryPackage = getFactoryImplPackageName(factory);
+
+ // remove the stored password explicitly using credentials service
+ CredentialsStorageService credentialsStorage
+ = ServiceUtils.getService(
+ bundleContext,
+ CredentialsStorageService.class);
+ String accountPrefix =
+ ProtocolProviderFactory.findAccountPrefix(bundleContext, accountID,
+ factoryPackage);
+
+ credentialsStorage.removePassword(accountPrefix);
+
+ ConfigurationService configurationService
+ = ServiceUtils.getService(
+ bundleContext,
+ ConfigurationService.class);
+ //first retrieve all accounts that we've registered
+ List<String> storedAccounts
+ = configurationService.getPropertyNamesByPrefix(
+ factoryPackage, 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
+ + "." + ProtocolProviderFactory.ACCOUNT_UID); // propname
+
+ if (accountUID.equals(accountID.getAccountUniqueID()))
+ {
+ //retrieve the names of all properties registered for the
+ //current account.
+ List<String> accountPropertyNames
+ = configurationService.getPropertyNamesByPrefix(
+ accountRootPropertyName, false);
+
+ //set all account properties to null in order to remove them.
+ for (String propName : accountPropertyNames)
+ configurationService.setProperty(propName, null);
+
+ //and now remove the parent too.
+ configurationService.setProperty(accountRootPropertyName, null);
+ return true;
+ }
+ }
+ return false;
+ }
/**
* Returns an <tt>Iterator</tt> over a list of all stored
@@ -95,9 +705,16 @@ public interface AccountManager * #isAccountLoaded(AccountID accountID) method. To load an account use the
* #loadAccount(AccountID accountID) method.
*
- * @return a <tt>Collection</tt> of all stored <tt>AccountID</tt>s
+ * @return an <tt>Iterator</tt> over a list of all stored
+ * <tt>AccountID</tt>s
*/
- public Collection<AccountID> getStoredAccounts();
+ public Collection<AccountID> getStoredAccounts()
+ {
+ synchronized (storedAccounts)
+ {
+ return new Vector<AccountID>(storedAccounts);
+ }
+ }
/**
* Loads the account corresponding to the given <tt>AccountID</tt>. An
@@ -110,7 +727,26 @@ public interface AccountManager * account corresponding to the specified <tt>accountID</tt>
*/
public void loadAccount(AccountID accountID)
- throws OperationFailedException;
+ throws OperationFailedException
+ {
+ // If the account with the given id is already loaded we have nothing
+ // to do here.
+ if (isAccountLoaded(accountID))
+ return;
+
+ ProtocolProviderFactory providerFactory
+ = ProtocolProviderActivator.getProtocolProviderFactory(
+ accountID.getProtocolName());
+
+ if(providerFactory.loadAccount(accountID))
+ {
+ accountID.putAccountProperty(
+ ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
+ String.valueOf(false));
+ // Finally store the modified properties.
+ storeAccount(providerFactory, accountID);
+ }
+ }
/**
* Unloads the account corresponding to the given <tt>AccountID</tt>. An
@@ -123,7 +759,53 @@ public interface AccountManager * the account corresponding to the specified <tt>accountID</tt>
*/
public void unloadAccount(AccountID accountID)
- throws OperationFailedException;
+ throws OperationFailedException
+ {
+ // If the account with the given id is already unloaded we have nothing
+ // to do here.
+ if (!isAccountLoaded(accountID))
+ return;
+
+ ProtocolProviderFactory providerFactory
+ = ProtocolProviderActivator.getProtocolProviderFactory(
+ accountID.getProtocolName());
+
+ // Obtain the protocol provider.
+ ServiceReference serRef
+ = providerFactory.getProviderForAccount(accountID);
+
+ // If there's no such provider we have nothing to do here.
+ if (serRef == null)
+ return;
+
+ ProtocolProviderService protocolProvider =
+ (ProtocolProviderService) bundleContext.getService(serRef);
+
+ // Set the account icon path for unloaded accounts.
+ String iconPathProperty = accountID.getAccountPropertyString(
+ ProtocolProviderFactory.ACCOUNT_ICON_PATH);
+
+ if (iconPathProperty == null)
+ {
+ accountID.putAccountProperty(
+ ProtocolProviderFactory.ACCOUNT_ICON_PATH,
+ protocolProvider.getProtocolIcon()
+ .getIconPath(ProtocolIcon.ICON_SIZE_32x32));
+ }
+
+ accountID.putAccountProperty(
+ ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
+ String.valueOf(true));
+
+ if (!providerFactory.unloadAccount(accountID))
+ {
+ accountID.putAccountProperty(
+ ProtocolProviderFactory.IS_ACCOUNT_DISABLED,
+ String.valueOf(false));
+ }
+ // Finally store the modified properties.
+ storeAccount(providerFactory, accountID);
+ }
/**
* Checks if the account corresponding to the given <tt>accountID</tt> is
@@ -137,5 +819,17 @@ public interface AccountManager * @return <tt>true</tt> to indicate that the account with the given
* <tt>accountID</tt> is loaded, <tt>false</tt> - otherwise
*/
- public boolean isAccountLoaded(AccountID accountID);
+ public boolean isAccountLoaded(AccountID accountID)
+ {
+ return storedAccounts.contains(accountID) && accountID.isEnabled();
+ }
+
+ private String stripPackagePrefix(String property)
+ {
+ int packageEndIndex = property.lastIndexOf('.');
+
+ if (packageEndIndex != -1)
+ property = property.substring(packageEndIndex + 1);
+ return property;
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/CallPeerState.java b/src/net/java/sip/communicator/service/protocol/CallPeerState.java index 79d83d1..5775e3d 100644 --- a/src/net/java/sip/communicator/service/protocol/CallPeerState.java +++ b/src/net/java/sip/communicator/service/protocol/CallPeerState.java @@ -34,6 +34,7 @@ package net.java.sip.communicator.service.protocol; * * @author Emil Ivov * @author Lubomir Marinov + * @author Yana Stamcheva */ public class CallPeerState { @@ -51,8 +52,10 @@ public class CallPeerState * newly created call peer that don't yet have an attributed call * state. */ - public static final CallPeerState UNKNOWN = - new CallPeerState(_UNKNOWN); + public static final CallPeerState UNKNOWN + = new CallPeerState(_UNKNOWN, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.UNKNOWN_STATUS")); /** * This constant value indicates a String representation of the @@ -68,8 +71,10 @@ public class CallPeerState * this state the moment we receive a "100 Trying" request from a proxy or * the remote side. */ - public static final CallPeerState INITIATING_CALL = - new CallPeerState(_INITIATING_CALL); + public static final CallPeerState INITIATING_CALL + = new CallPeerState(_INITIATING_CALL, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.INITIATING_CALL_STATUS")); /** * This constant value indicates a String representation of the CONNECTING @@ -83,8 +88,10 @@ public class CallPeerState * CONNECTING - which means that a network connection to that peer * is currently being established. */ - public static final CallPeerState CONNECTING = - new CallPeerState(_CONNECTING); + public static final CallPeerState CONNECTING + = new CallPeerState(_CONNECTING, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.CONNECTING_STATUS")); /** * This constant value indicates a String representation of the CONNECTING @@ -98,16 +105,20 @@ public class CallPeerState * CONNECTING - which means that a network connection to that peer * is currently being established. */ - public static final CallPeerState CONNECTING_WITH_EARLY_MEDIA = - new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA ); + public static final CallPeerState CONNECTING_WITH_EARLY_MEDIA + = new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.CONNECTING_EARLY_MEDIA_STATUS")); /** * This constant value indicates that the state of the incoming call peer * is CONNECTING - which means that a network connection to that peer * is currently being established. */ - public static final CallPeerState CONNECTING_INCOMING_CALL = - new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA ); + public static final CallPeerState CONNECTING_INCOMING_CALL + = new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.CONNECTING_STATUS")); /** * This constant value indicates that the state of the incoming call peer @@ -116,8 +127,10 @@ public class CallPeerState * the other peer we can still can hear media coming from the * server for example. */ - public static final CallPeerState CONNECTING_INCOMING_CALL_WITH_MEDIA = - new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA ); + public static final CallPeerState CONNECTING_INCOMING_CALL_WITH_MEDIA + = new CallPeerState( _CONNECTING_WITH_EARLY_MEDIA, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.CONNECTING_EARLY_MEDIA_STATUS")); /** * This constant value indicates a String representation of the @@ -133,8 +146,10 @@ public class CallPeerState * peer has been established and peer's phone is currently alerting the * remote user of the current call. */ - public static final CallPeerState ALERTING_REMOTE_SIDE = - new CallPeerState(_ALERTING_REMOTE_SIDE); + public static final CallPeerState ALERTING_REMOTE_SIDE + = new CallPeerState(_ALERTING_REMOTE_SIDE, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.RINGING_STATUS")); /** * This constant value indicates a String representation of the @@ -150,7 +165,9 @@ public class CallPeerState * graphical alert (the phone is ringing). */ public static final CallPeerState INCOMING_CALL - = new CallPeerState(_INCOMING_CALL); + = new CallPeerState(_INCOMING_CALL, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.INCOMING_CALL_STATUS")); /** * This constant value indicates a String representation of the CONNECTED @@ -165,7 +182,9 @@ public class CallPeerState * peer. */ public static final CallPeerState CONNECTED - = new CallPeerState(_CONNECTED); + = new CallPeerState(_CONNECTED, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.CONNECTED_STATUS")); /** * This constant value indicates a String representation of the DISCONNECTED @@ -179,8 +198,10 @@ public class CallPeerState * is DISCONNECTED - which means that this peer is not participating :) * in the call any more. */ - public static final CallPeerState DISCONNECTED = - new CallPeerState(_DISCONNECTED); + public static final CallPeerState DISCONNECTED + = new CallPeerState(_DISCONNECTED, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.DISCONNECTED_STATUS")); /** * This constant value indicates a String representation of the REFERRED @@ -194,7 +215,10 @@ public class CallPeerState * is REFERRED - which means that this peer has transfered us to another * peer. */ - public static final CallPeerState REFERRED = new CallPeerState(_REFERRED); + public static final CallPeerState REFERRED + = new CallPeerState(_REFERRED, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.REFERRED_STATUS")); /** * This constant value indicates a String representation of the BUSY @@ -210,7 +234,9 @@ public class CallPeerState * because they were already in a call). */ public static final CallPeerState BUSY - = new CallPeerState(_BUSY); + = new CallPeerState(_BUSY, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.BUSY_STATUS")); /** * This constant value indicates a String representation of the FAILED @@ -224,7 +250,9 @@ public class CallPeerState * peer has failed for an unexpected reason. */ public static final CallPeerState FAILED - = new CallPeerState(_FAILED); + = new CallPeerState(_FAILED, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.FAILED_STATUS")); /** * The constant value being a String representation of the ON_HOLD_LOCALLY @@ -239,7 +267,9 @@ public class CallPeerState * locally put on hold. */ public static final CallPeerState ON_HOLD_LOCALLY - = new CallPeerState(_ON_HOLD_LOCALLY); + = new CallPeerState(_ON_HOLD_LOCALLY, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.LOCALLY_ON_HOLD_STATUS")); /** * The constant value being a String representation of the ON_HOLD_MUTUALLY @@ -254,7 +284,9 @@ public class CallPeerState * mutually - locally and remotely - put on hold. */ public static final CallPeerState ON_HOLD_MUTUALLY - = new CallPeerState(_ON_HOLD_MUTUALLY); + = new CallPeerState(_ON_HOLD_MUTUALLY, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.MUTUALLY_ON_HOLD_STATUS")); /** * The constant value being a String representation of the ON_HOLD_REMOTELY @@ -270,7 +302,9 @@ public class CallPeerState * remotely put on hold. */ public static final CallPeerState ON_HOLD_REMOTELY - = new CallPeerState(_ON_HOLD_REMOTELY); + = new CallPeerState(_ON_HOLD_REMOTELY, + ProtocolProviderActivator.getResourceService().getI18NString( + "service.gui.REMOTELY_ON_HOLD_STATUS")); /** * Determines whether a specific <tt>CallPeerState</tt> value @@ -297,17 +331,25 @@ public class CallPeerState private String callStateStr; /** + * A localized string representation of this peer's Call State. + */ + private String callStateLocalizedStr; + + /** * Create a peer call state object with a value corresponding to the * specified string. * @param callPeerState a string representation of the state. + * @param callStateLocalizedStr the localized string representing this state */ - private CallPeerState(String callPeerState) + private CallPeerState( String callPeerState, + String callStateLocalizedStr) { this.callStateStr = callPeerState; + this.callStateLocalizedStr = callStateLocalizedStr; } /** - * Returns a String representation of tha CallPeerState. + * Returns a String representation of the CallPeerState. * * @return A string value (one of the _BUSY, _CALLING, _CONNECTED, * _CONNECTING, _DISCONNECTED, _FAILED, _RINGING constants) representing @@ -319,6 +361,16 @@ public class CallPeerState } /** + * Returns a localized String representation of the CallPeerState. + * + * @return a localized String representation of the CallPeerState + */ + public String getLocalizedStateString() + { + return callStateLocalizedStr; + } + + /** * Returns a string representation of this call state. Strings returned * by this method have the following format: * CallPeerState:<STATE_STRING> diff --git a/src/net/java/sip/communicator/impl/protocol/ProtocolProviderActivator.java b/src/net/java/sip/communicator/service/protocol/ProtocolProviderActivator.java index 00ceb2f..1cd9d25 100644 --- a/src/net/java/sip/communicator/impl/protocol/ProtocolProviderActivator.java +++ b/src/net/java/sip/communicator/service/protocol/ProtocolProviderActivator.java @@ -4,12 +4,12 @@ * Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.protocol;
+package net.java.sip.communicator.service.protocol;
import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;
-import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
/**
@@ -51,6 +51,11 @@ public class ProtocolProviderActivator private static ConfigurationService configurationService;
/**
+ * The resource service through which we obtain localized strings.
+ */
+ private static ResourceManagementService resourceService;
+
+ /**
* The <code>SingleCallInProgressPolicy</code> making sure that the
* <code>Call</code>s accessible in the <code>BundleContext</code> of this
* activator will obey to the rule that a new <code>Call</code> should put
@@ -80,6 +85,27 @@ public class ProtocolProviderActivator }
/**
+ * Gets the <code>ResourceManagementService</code> to be used by the classes
+ * in the bundle represented by <code>ProtocolProviderActivator</code>.
+ *
+ * @return the <code>ResourceManagementService</code> to be used by the
+ * classes in the bundle represented by
+ * <code>ProtocolProviderActivator</code>
+ */
+ public static ResourceManagementService getResourceService()
+ {
+ if (resourceService == null)
+ {
+ resourceService
+ = (ResourceManagementService)
+ bundleContext.getService(
+ bundleContext.getServiceReference(
+ ResourceManagementService.class.getName()));
+ }
+ return resourceService;
+ }
+
+ /**
* Returns a <tt>ProtocolProviderFactory</tt> for a given protocol
* provider.
* @param protocolName the name of the protocol, which factory we're
@@ -130,7 +156,7 @@ public class ProtocolProviderActivator accountManagerServiceRegistration =
bundleContext.registerService(AccountManager.class.getName(),
- new AccountManagerImpl(bundleContext), null);
+ new AccountManager(bundleContext), null);
singleCallInProgressPolicy =
new SingleCallInProgressPolicy(bundleContext);
diff --git a/src/net/java/sip/communicator/impl/protocol/SingleCallInProgressPolicy.java b/src/net/java/sip/communicator/service/protocol/SingleCallInProgressPolicy.java index fbed031..adb31d8 100644 --- a/src/net/java/sip/communicator/impl/protocol/SingleCallInProgressPolicy.java +++ b/src/net/java/sip/communicator/service/protocol/SingleCallInProgressPolicy.java @@ -4,13 +4,12 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.protocol; +package net.java.sip.communicator.service.protocol; import java.util.*; import org.osgi.framework.*; -import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; diff --git a/src/net/java/sip/communicator/service/protocol/protocol.provider.manifest.mf b/src/net/java/sip/communicator/service/protocol/protocol.provider.manifest.mf index 4f5abb7..06867f8 100644 --- a/src/net/java/sip/communicator/service/protocol/protocol.provider.manifest.mf +++ b/src/net/java/sip/communicator/service/protocol/protocol.provider.manifest.mf @@ -1,4 +1,4 @@ -Bundle-Activator: net.java.sip.communicator.impl.protocol.ProtocolProviderActivator +Bundle-Activator: net.java.sip.communicator.service.protocol.ProtocolProviderActivator Bundle-Name: Protocol Provider Service Bundle-Description: Protocol Provider Service. Bundle-Vendor: sip-communicator.org @@ -7,7 +7,8 @@ System-Bundle: yes Import-Package: org.osgi.framework, net.java.sip.communicator.service.configuration, net.java.sip.communicator.service.credentialsstorage, - net.java.sip.communicator.util + net.java.sip.communicator.util, + net.java.sip.communicator.service.resources Export-Package: net.java.sip.communicator.service.protocol, net.java.sip.communicator.service.protocol.aimconstants, net.java.sip.communicator.service.protocol.event, |