Localized state strings.

cusax-fix
Yana Stamcheva 15 years ago
parent 5efd96c9b6
commit 77797561f4

@ -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

@ -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;
}
}

@ -8,82 +8,692 @@
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 @@ boolean removeStoredAccount(ProtocolProviderFactory factory,
* #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 @@ boolean removeStoredAccount(ProtocolProviderFactory factory,
* 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 void loadAccount(AccountID accountID)
* 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 void unloadAccount(AccountID accountID)
* @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;
}
}

@ -34,6 +34,7 @@
*
* @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
@ -296,18 +330,26 @@ public static final boolean isOnHold(CallPeerState state)
*/
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
@ -318,6 +360,16 @@ public String getStateString()
return callStateStr;
}
/**
* 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:

@ -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.*;
/**
@ -50,6 +50,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
@ -79,6 +84,27 @@ static ConfigurationService getConfigurationService()
return configurationService;
}
/**
* 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.
@ -130,7 +156,7 @@ public void start(BundleContext bundleContext)
accountManagerServiceRegistration =
bundleContext.registerService(AccountManager.class.getName(),
new AccountManagerImpl(bundleContext), null);
new AccountManager(bundleContext), null);
singleCallInProgressPolicy =
new SingleCallInProgressPolicy(bundleContext);

@ -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.*;

@ -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,

Loading…
Cancel
Save