diff --git a/src/net/java/sip/communicator/impl/protocol/gibberish/ProtocolProviderServiceGibberishImpl.java b/src/net/java/sip/communicator/impl/protocol/gibberish/ProtocolProviderServiceGibberishImpl.java new file mode 100644 index 000000000..d183964ca --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/gibberish/ProtocolProviderServiceGibberishImpl.java @@ -0,0 +1,402 @@ +/* + * 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.gibberish; + +import java.util.*; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +/** + * A Gibberish implementation of the ProtocolProviderService. + * + * @author Emil Ivov + */ +public class ProtocolProviderServiceGibberishImpl + implements ProtocolProviderService +{ + private static final Logger logger + = Logger.getLogger(ProtocolProviderServiceGibberishImpl.class); + + /** + * The name of this protocol. + */ + public static final String GIBBERISH_PROTOCOL_NAME = "Gibberish"; + + /** + * The id of the account that this protocol provider represents. + */ + private AccountID accountID = null; + + /** + * We use this to lock access to initialization. + */ + private Object initializationLock = new Object(); + + /** + * The hashtable with the operation sets that we support locally. + */ + private Hashtable supportedOperationSets = new Hashtable(); + + /** + * A list of listeners interested in changes in our registration state. + */ + private Vector registrationStateListeners = new Vector(); + + /** + * Indicates whether or not the provider is initialized and ready for use. + */ + private boolean isInitialized = false; + + /** + * The registration state that we are currently in. Note that in a real + * world protocol implementation this field won't exist and the registration + * state would be retrieved from the protocol stack. + */ + private RegistrationState currentRegistrationState + = RegistrationState.UNREGISTERED; + + + /** + * The default constructor for the Gibberish protocol provider. + */ + public ProtocolProviderServiceGibberishImpl() + { + logger.trace("Creating a gibberish provider."); + } + + /** + * Initializes the service implementation, and puts it in a sate where it + * could interoperate with other services. It is strongly recomended that + * properties in this Map be mapped to property names as specified by + * AccountProperties. + * + * @param userID the user id of the gibberish account we're currently + * initializing + * @param accountID the identifier of the account that this protocol + * provider represents. + * + * @see net.java.sip.communicator.service.protocol.AccountID + */ + protected void initialize(String userID, + AccountID accountID) + { + synchronized(initializationLock) + { + this.accountID = accountID; + + //initialize the presence operationset + OperationSetPersistentPresence persistentPresence = + new OperationSetPersistentPresenceGibberishImpl(this); + + supportedOperationSets.put( + OperationSetPersistentPresence.class.getName(), + persistentPresence); + + + //register it once again for those that simply need presence and + //won't be smart enough to check for a persistent presence + //alternative + supportedOperationSets.put( OperationSetPresence.class.getName(), + persistentPresence); + + //initialize the IM operation set + OperationSetBasicInstantMessagingGibberishImpl basicInstantMessaging + = new OperationSetBasicInstantMessagingGibberishImpl( + this + , (OperationSetPersistentPresenceGibberishImpl) + persistentPresence); + + supportedOperationSets.put( + OperationSetBasicInstantMessaging.class.getName(), + basicInstantMessaging); + + //initialize the typing notifications operation set + OperationSetTypingNotifications typingNotifications = + new OperationSetTypingNotificationsGibberishImpl(this); + + supportedOperationSets.put( + OperationSetTypingNotifications.class.getName(), + typingNotifications); + + isInitialized = true; + } + } + + /** + * Registers the specified listener with this provider so that it would + * receive notifications on changes of its state or other properties such + * as its local address and display name. + * + * @param listener the listener to register. + */ + public void addRegistrationStateChangeListener( + RegistrationStateChangeListener listener) + { + synchronized(registrationStateListeners) + { + if (!registrationStateListeners.contains(listener)) + registrationStateListeners.add(listener); + } + + } + + /** + * Removes the specified registration listener so that it won't receive + * further notifications when our registration state changes. + * + * @param listener the listener to remove. + */ + public void removeRegistrationStateChangeListener( + RegistrationStateChangeListener listener) + { + synchronized(registrationStateListeners) + { + registrationStateListeners.remove(listener); + } + } + + /** + * Creates a RegistrationStateChangeEvent corresponding to the + * specified old and new states and notifies all currently registered + * listeners. + * + * @param oldState the state that the provider had before the change + * occurred + * @param newState the state that the provider is currently in. + * @param reasonCode a value corresponding to one of the REASON_XXX fields + * of the RegistrationStateChangeEvent class, indicating the reason for + * this state transition. + * @param reason a String further explaining the reason code or null if + * no such explanation is necessary. + */ + private void fireRegistrationStateChanged( RegistrationState oldState, + RegistrationState newState, + int reasonCode, + String reason) + { + RegistrationStateChangeEvent event = + new RegistrationStateChangeEvent( + this, oldState, newState, reasonCode, reason); + + logger.debug("Dispatching " + event + " to " + + registrationStateListeners.size()+ " listeners."); + + Iterator listeners = null; + synchronized (registrationStateListeners) + { + listeners = new ArrayList(registrationStateListeners).iterator(); + } + + while (listeners.hasNext()) + { + RegistrationStateChangeListener listener + = (RegistrationStateChangeListener) listeners.next(); + + listener.registrationStateChanged(event); + } + + logger.trace("Done."); + } + + + /** + * Returns the AccountID that uniquely identifies the account represented + * by this instance of the ProtocolProviderService. + * + * @return the id of the account represented by this provider. + */ + public AccountID getAccountID() + { + return accountID; + } + + /** + * Returns the operation set corresponding to the specified class or null + * if this operation set is not supported by the provider implementation. + * + * @param opsetClass the Class of the operation set that we're + * looking for. + * @return returns an OperationSet of the specified Class if + * the undelying implementation supports it or null otherwise. + */ + public OperationSet getOperationSet(Class opsetClass) + { + return (OperationSet) getSupportedOperationSets() + .get(opsetClass.getName()); + } + + /** + * Returns the short name of the protocol that the implementation of this + * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for + * example). + * + * @return a String containing the short name of the protocol this + * service is implementing (most often that would be a name in + * ProtocolNames). + */ + public String getProtocolName() + { + return GIBBERISH_PROTOCOL_NAME; + } + + /** + * Returns the state of the registration of this protocol provider with + * the corresponding registration service. + * + * @return ProviderRegistrationState + */ + public RegistrationState getRegistrationState() + { + return currentRegistrationState; + } + + /** + * Returns an array containing all operation sets supported by the + * current implementation. + * + * @return a java.util.Map containing instance of all supported + * operation sets mapped against their class names (e.g. + * OperationSetPresence.class.getName()) . + */ + public Map getSupportedOperationSets() + { + //Copy the map so that the caller is not able to modify it. + return (Map)supportedOperationSets.clone(); + } + + /** + * Indicates whether or not this provider is registered + * + * @return true if the provider is currently registered and false + * otherwise. + */ + public boolean isRegistered() + { + return currentRegistrationState.equals(RegistrationState.REGISTERED); + } + + /** + * Starts the registration process. + * + * @param authority the security authority that will be used for + * resolving any security challenges that may be returned during the + * registration or at any moment while wer're registered. + * @throws OperationFailedException with the corresponding code it the + * registration fails for some reason (e.g. a networking error or an + * implementation problem). + */ + public void register(SecurityAuthority authority) + throws OperationFailedException + { + //we don't really need a password here since there's no server in + //Gibberish but nevertheless we'll behave as if we did. + + //verify whether a password has already been stored for this account + String password = GibberishActivator. + getProtocolProviderFactory().loadPassword(getAccountID()); + + //if we don't - retrieve it from the user through the security authority + if (password == null) + { + //create a default credentials object + UserCredentials credentials = new UserCredentials(); + credentials.setUserName(getAccountID().getUserID()); + + //request a password from the user + credentials = authority.obtainCredentials("Gibberish" + , credentials); + + //extract the password the user passed us. + char[] pass = credentials.getPassword(); + + // the user didn't provide us a password (canceled the operation) + if (pass == null) + { + fireRegistrationStateChanged( + getRegistrationState(), + RegistrationState.UNREGISTERED, + RegistrationStateChangeEvent.REASON_USER_REQUEST, ""); + return; + } + password = new String(pass); + + //if the user indicated that the password should be saved, we'll ask + //the proto provider factory to store it for us. + if (credentials.isPasswordPersistent()) + { + GibberishActivator.getProtocolProviderFactory() + .storePassword(getAccountID(), password); + } + } + + + RegistrationState oldState = currentRegistrationState; + currentRegistrationState = RegistrationState.REGISTERED; + + fireRegistrationStateChanged( + oldState + , currentRegistrationState + , RegistrationStateChangeEvent.REASON_USER_REQUEST + , null); + } + + /** + * Makes the service implementation close all open sockets and release + * any resources that it might have taken and prepare for + * shutdown/garbage collection. + */ + public void shutdown() + { + if(!isInitialized) + { + return; + } + logger.trace("Killing the Gibberish Protocol Provider."); + + if(isRegistered()) + { + try + { + //do the unregistration + unregister(); + } + catch (OperationFailedException ex) + { + //we're shutting down so we need to silence the exception here + logger.error( + "Failed to properly unregister before shutting down. " + + getAccountID() + , ex); + } + } + + isInitialized = false; + } + + /** + * Ends the registration of this protocol provider with the current + * registration service. + * + * @throws OperationFailedException with the corresponding code it the + * registration fails for some reason (e.g. a networking error or an + * implementation problem). + */ + public void unregister() + throws OperationFailedException + { + RegistrationState oldState = currentRegistrationState; + currentRegistrationState = RegistrationState.UNREGISTERED; + + fireRegistrationStateChanged( + oldState + , currentRegistrationState + , RegistrationStateChangeEvent.REASON_USER_REQUEST + , null); + } +}