/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.*;
import org.osgi.framework.*;
/**
* A Gibberish implementation of a persistent presence operation set. In order
* to simulate server persistence, this operation set would simply accept all
* unresolved contacts and resolve them immediately. A real world protocol
* implementation would save it on a server using methods provided by the
* protocol stack.
*
* @author Emil Ivov
*/
public class OperationSetPersistentPresenceGibberishImpl
extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceGibberishImpl>
{
private static final Logger logger =
Logger.getLogger(OperationSetPersistentPresenceGibberishImpl.class);
/**
* The root of the gibberish contact list.
*/
private ContactGroupGibberishImpl contactListRoot = null;
/**
* The currently active status message.
*/
private String statusMessage = "Default Status Message";
/**
* Our presence status.
*/
private PresenceStatus presenceStatus = GibberishStatusEnum.OFFLINE;
/**
* The <tt>AuthorizationHandler</tt> instance that we'd have to transmit
* authorization requests to for approval.
*/
private AuthorizationHandler authorizationHandler = null;
/**
* Creates an instance of this operation set keeping a reference to the
* specified parent <tt>provider</tt>.
* @param provider the ProtocolProviderServiceGibberishImpl instance that
* created us.
*/
public OperationSetPersistentPresenceGibberishImpl(
ProtocolProviderServiceGibberishImpl provider)
{
super(provider);
contactListRoot = new ContactGroupGibberishImpl("RootGroup", provider);
//add our unregistration listener
parentProvider.addRegistrationStateChangeListener(
new UnregistrationListener());
}
/**
* Creates a group with the specified name and parent in the server
* stored contact list.
*
* @param parent the group where the new group should be created
* @param groupName the name of the new group to create.
*/
public void createServerStoredContactGroup(ContactGroup parent,
String groupName)
{
ContactGroupGibberishImpl newGroup
= new ContactGroupGibberishImpl(groupName, parentProvider);
((ContactGroupGibberishImpl)parent).addSubgroup(newGroup);
this.fireServerStoredGroupEvent(
newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
}
/**
* A Gibberish Provider method to use for fast filling of a contact list.
*
* @param contactGroup the group to add
*/
public void addGibberishGroup(ContactGroupGibberishImpl contactGroup)
{
contactListRoot.addSubgroup(contactGroup);
}
/**
* A Gibberish Provider method to use for fast filling of a contact list.
* This method would add both the group and fire an event.
*
* @param parent the group where <tt>contactGroup</tt> should be added.
* @param contactGroup the group to add
*/
public void addGibberishGroupAndFireEvent(
ContactGroupGibberishImpl parent
, ContactGroupGibberishImpl contactGroup)
{
parent.addSubgroup(contactGroup);
this.fireServerStoredGroupEvent(
contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
}
/**
* Returns a reference to the contact with the specified ID in case we
* have a subscription for it and null otherwise/
*
* @param contactID a String identifier of the contact which we're
* seeking a reference of.
* @return a reference to the Contact with the specified
* <tt>contactID</tt> or null if we don't have a subscription for the
* that identifier.
*/
public Contact findContactByID(String contactID)
{
return contactListRoot.findContactByID(contactID);
}
/**
* Sets the specified status message.
* @param statusMessage a String containing the new status message.
*/
public void setStatusMessage(String statusMessage)
{
this.statusMessage = statusMessage;
}
/**
* Returns the status message that was last set through
* setCurrentStatusMessage.
*
* @return the last status message that we have requested and the aim
* server has confirmed.
*/
public String getCurrentStatusMessage()
{
return statusMessage;
}
/**
* Returns the protocol specific contact instance representing the local
* user.
*
* @return the Contact (address, phone number, or uin) that the Provider
* implementation is communicating on behalf of.
*/
public Contact getLocalContact()
{
return null;
}
/**
* Returns a PresenceStatus instance representing the state this provider
* is currently in.
*
* @return the PresenceStatus last published by this provider.
*/
public PresenceStatus getPresenceStatus()
{
return presenceStatus;
}
/**
* Returns the root group of the server stored contact list.
*
* @return the root ContactGroup for the ContactList stored by this
* service.
*/
public ContactGroup getServerStoredContactListRoot()
{
return contactListRoot;
}
/**
* Returns the set of PresenceStatus objects that a user of this service
* may request the provider to enter.
*
* @return Iterator a PresenceStatus array containing "enterable" status
* instances.
*/
public Iterator<PresenceStatus> getSupportedStatusSet()
{
return GibberishStatusEnum.supportedStatusSet();
}
/**
* Removes the specified contact from its current parent and places it
* under <tt>newParent</tt>.
*
* @param contactToMove the <tt>Contact</tt> to move
* @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
* would be placed.
*/
public void moveContactToGroup(Contact contactToMove,
ContactGroup newParent)
{
ContactGibberishImpl gibberishContact
= (ContactGibberishImpl)contactToMove;
ContactGroupGibberishImpl parentGibberishGroup
= findContactParent(gibberishContact);
parentGibberishGroup.removeContact(gibberishContact);
//if this is a volatile contact then we haven't really subscribed to
//them so we'd need to do so here
if(!gibberishContact.isPersistent())
{
//first tell everyone that the volatile contact was removed
fireSubscriptionEvent(gibberishContact
, parentGibberishGroup
, SubscriptionEvent.SUBSCRIPTION_REMOVED);
try
{
//now subscribe
this.subscribe(newParent, contactToMove.getAddress());
//now tell everyone that we've added the contact
fireSubscriptionEvent(gibberishContact
, newParent
, SubscriptionEvent.SUBSCRIPTION_CREATED);
}
catch (Exception ex)
{
logger.error("Failed to move contact "
+ gibberishContact.getAddress()
, ex);
}
}
else
{
( (ContactGroupGibberishImpl) newParent)
.addContact(gibberishContact);
fireSubscriptionMovedEvent(contactToMove
, parentGibberishGroup
, newParent);
}
}
/**
* Requests the provider to enter into a status corresponding to the
* specified paramters.
*
* @param status the PresenceStatus as returned by
* getRequestableStatusSet
* @param statusMessage the message that should be set as the reason to
* enter that status
* @throws IllegalArgumentException if the status requested is not a
* valid PresenceStatus supported by this provider.
* @throws IllegalStateException if the provider is not currently
* registered.
* @throws OperationFailedException with code NETWORK_FAILURE if
* publishing the status fails due to a network error.
*/
public void publishPresenceStatus(PresenceStatus status,
String statusMessage) throws
IllegalArgumentException, IllegalStateException,
OperationFailedException
{
PresenceStatus oldPresenceStatus = this.presenceStatus;
this.presenceStatus = status;
this.statusMessage = statusMessage;
this.fireProviderStatusChangeEvent(oldPresenceStatus);
//since we are not a real protocol, we set the contact presence status
//ourselves and make them have the same status as ours.
changePresenceStatusForAllContacts( getServerStoredContactListRoot()
, getPresenceStatus());
//now check whether we are in someone else's contact list and modify
//our status there
List<Contact> contacts = findContactsPointingToUs();
Iterator<Contact> contactsIter = contacts.iterator();
while (contactsIter.hasNext())
{
ContactGibberishImpl contact = (ContactGibberishImpl)contactsIter.next();
PresenceStatus oldStatus = contact.getPresenceStatus();
contact.setPresenceStatus(status);
contact.getParentPresenceOperationSet()
.fireContactPresenceStatusChangeEvent(
contact
, contact.getParentContactGroup()
, oldStatus);
}
}
/**
* Get the PresenceStatus for a particular contact.
*
* @param contactIdentifier the identifier of the contact whose status
* we're interested in.
* @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
* <tt>contact</tt>
* @throws IllegalArgumentException if <tt>contact</tt> is not a contact
* known to the underlying protocol provider
* @throws IllegalStateException if the underlying protocol provider is
* not registered/signed on a public service.
* @throws OperationFailedException with code NETWORK_FAILURE if
* retrieving the status fails due to errors experienced during
* network communication
*/
public PresenceStatus queryContactStatus(String contactIdentifier) throws
IllegalArgumentException, IllegalStateException,
OperationFailedException
{
return findContactByID(contactIdentifier).getPresenceStatus();
}
/**
* Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
*
* @param contact the <tt>ContactGibberishImpl</tt> whose status we'd like
* to set.
* @param newStatus the new status we'd like to set to <tt>contact</tt>.
*/
private void changePresenceStatusForContact(
ContactGibberishImpl contact
, PresenceStatus newStatus)
{
PresenceStatus oldStatus = contact.getPresenceStatus();
contact.setPresenceStatus(newStatus);
fireContactPresenceStatusChangeEvent(
contact, findContactParent(contact), oldStatus);
}
/**
* Sets the presence status of all <tt>contact</tt>s in our contact list
* (except those that correspond to another provider registered with SC)
* to <tt>newStatus</tt>.
*
* @param newStatus the new status we'd like to set to <tt>contact</tt>.
* @param parent the group in which we'd have to update the status of all
* direct and indirect child contacts.
*/
private void changePresenceStatusForAllContacts(ContactGroup parent,
PresenceStatus newStatus)
{
//first set the status for contacts in this group
Iterator<Contact> childContacts = parent.contacts();
while(childContacts.hasNext())
{
ContactGibberishImpl contact
= (ContactGibberishImpl)childContacts.next();
if(findProviderForGibberishUserID(contact.getAddress()) != null)
{
//this is a contact corresponding to another SIP Communicator
//provider so we won't change it's status here.
continue;
}
PresenceStatus oldStatus = contact.getPresenceStatus();
contact.setPresenceStatus(newStatus);
fireContactPresenceStatusChangeEvent(
contact, parent, oldStatus);
}
//now call this method recursively for all subgroups
Iterator<ContactGroup> subgroups = parent.subgroups();
while(subgroups.hasNext())
{
ContactGroup subgroup = subgroups.next();
changePresenceStatusForAllContacts(subgroup, newStatus);
}
}
/**
* Returns the group that is parent of the specified gibberishGroup or null
* if no parent was found.
* @param gibberishGroup the group whose parent we're looking for.
* @return the ContactGroupGibberishImpl instance that gibberishGroup
* belongs to or null if no parent was found.
*/
public ContactGroupGibberishImpl findGroupParent(
ContactGroupGibberishImpl gibberishGroup)
{
return contactListRoot.findGroupParent(gibberishGroup);
}
/**
* Returns the group that is parent of the specified gibberishContact or
* null if no parent was found.
* @param gibberishContact the contact whose parent we're looking for.
* @return the ContactGroupGibberishImpl instance that gibberishContact
* belongs to or null if no parent was found.
*/
public ContactGroupGibberishImpl findContactParent(
ContactGibberishImpl gibberishContact)
{
return (ContactGroupGibberishImpl)gibberishContact
.getParentContactGroup();
}
/**
* Removes the specified group from the server stored contact list.
*
* @param group the group to remove.
*
* @throws IllegalArgumentException if <tt>group</tt> was not found in this
* protocol's contact list.
*/
public void removeServerStoredContactGroup(ContactGroup group)
throws IllegalArgumentException
{
ContactGroupGibberishImpl gibberishGroup
= (ContactGroupGibberishImpl)group;
ContactGroupGibberishImpl parent = findGroupParent(gibberishGroup);
if(parent == null){
throw new IllegalArgumentException(
"group " + group
+ " does not seem to belong to this protocol's contact list.");
}
parent.removeSubGroup(gibberishGroup);
this.fireServerStoredGroupEvent(
gibberishGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
}
/**
* Renames the specified group from the server stored contact list.
*
* @param group the group to rename.
* @param newName the new name of the group.
*/
public void renameServerStoredContactGroup(ContactGroup group,
String newName)
{
((ContactGroupGibberishImpl)group).setGroupName(newName);
this.fireServerStoredGroupEvent(
group,
ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
}
/**
* Handler for incoming authorization requests.
*
* @param handler an instance of an AuthorizationHandler for
* authorization requests coming from other users requesting
* permission add us to their contact list.
*/
public void setAuthorizationHandler(AuthorizationHandler handler)
{
this.authorizationHandler = handler;
}
/**
* Persistently adds a subscription for the presence status of the
* contact corresponding to the specified contactIdentifier and indicates
* that it should be added to the specified group of the server stored
* contact list.
*
* @param parent the parent group of the server stored contact list
* where the contact should be added. <p>
* @param contactIdentifier the contact whose status updates we are
* subscribing for.
* @throws IllegalArgumentException if <tt>contact</tt> or
* <tt>parent</tt> are not a contact known to the underlying protocol
* provider.
* @throws IllegalStateException if the underlying protocol provider is
* not registered/signed on a public service.
* @throws OperationFailedException with code NETWORK_FAILURE if
* subscribing fails due to errors experienced during network
* communication
*/
public void subscribe(ContactGroup parent, String contactIdentifier) throws
IllegalArgumentException, IllegalStateException,
OperationFailedException
{
ContactGibberishImpl contact = new ContactGibberishImpl(
contactIdentifier
, parentProvider);
if(authorizationHandler != null)
{
//we require authorizations in gibberish
AuthorizationRequest request
= authorizationHandler.createAuthorizationRequest(contact);
//and finally pretend that the remote contact has granted us
//authorization
AuthorizationResponse response
= deliverAuthorizationRequest(request, contact);
authorizationHandler.processAuthorizationResponse(
response, contact);
//if the request was not accepted - return the contact.
if(response.getResponseCode() == AuthorizationResponse.REJECT)
return;
}
((ContactGroupGibberishImpl)parent).addContact(contact);
fireSubscriptionEvent(contact,
parent,
SubscriptionEvent.SUBSCRIPTION_CREATED);
//if the newly added contact corresponds to another provider - set their
//status accordingly
ProtocolProviderServiceGibberishImpl gibProvider
= findProviderForGibberishUserID(contactIdentifier);
if(gibProvider != null)
{
OperationSetPersistentPresence opSetPresence
= gibProvider
.getOperationSet(OperationSetPersistentPresence.class);
changePresenceStatusForContact(
contact,
opSetPresence.getPresenceStatus());
}
else
{
//otherwise - since we are not a real protocol, we set the contact
//presence status ourselves
changePresenceStatusForContact(contact, getPresenceStatus());
}
//notify presence listeners for the status change.
fireContactPresenceStatusChangeEvent(contact
, parent
, GibberishStatusEnum.OFFLINE);
}
/**
* Depending on whether <tt>contact</tt> corresponds to another protocol
* provider installed in sip-communicator, this method would either deliver
* it to that provider or simulate a corresponding request from the
* destination contact and make return a response after it has received
* one If the destination contact matches us, then we'll ask the user to
* act upon the request, and return the response.
*
* @param request the authorization request that we'd like to deliver to the
* desination <tt>contact</tt>.
* @param contact the <tt>Contact</tt> to notify
*
* @return the <tt>AuthorizationResponse</tt> that has been given or
* generated in response to <tt>request</tt>.
*/
private AuthorizationResponse deliverAuthorizationRequest(
AuthorizationRequest request,
Contact contact)
{
String userID = contact.getAddress();
//if the user id is our own id, then this request is being routed to us
//from another instance of the gibberish provider.
if (userID.equals(this.parentProvider.getAccountID().getUserID()))
{
//check who is the provider sending the message
String sourceUserID = contact.getProtocolProvider()
.getAccountID().getUserID();
//check whether they are in our contact list
Contact from = findContactByID(sourceUserID);
//and if not - add them there as volatile.
if (from == null)
{
from = createVolatileContact(sourceUserID);
}
//and now handle the request.
return authorizationHandler.processAuthorisationRequest(
request, from);
}
else
{
//if userID is not our own, try a check whether another provider
//has that id and if yes - deliver the request to them.
ProtocolProviderServiceGibberishImpl gibberishProvider
= this.findProviderForGibberishUserID(userID);
if (gibberishProvider != null)
{
OperationSetPersistentPresenceGibberishImpl opSetPersPresence
= (OperationSetPersistentPresenceGibberishImpl)
gibberishProvider.getOperationSet(
OperationSetPersistentPresence.class);
return opSetPersPresence
.deliverAuthorizationRequest(request, contact);
}
else
{
//if we got here then "to" is simply someone in our contact
//list so let's just simulate a reciproce request and generate
//a response accordingly.
//pretend that the remote contact is asking for authorization
authorizationHandler.processAuthorisationRequest(
request, contact);
//and now pretend that the remote contact has granted us
//authorization
return new AuthorizationResponse(AuthorizationResponse.ACCEPT
, "You are welcome!");
}
}
}
/**
* Adds a subscription for the presence status of the contact
* corresponding to the specified contactIdentifier.
*
* @param contactIdentifier the identifier of the contact whose status
* updates we are subscribing for. <p>
* @throws IllegalArgumentException if <tt>contact</tt> is not a contact
* known to the underlying protocol provider
* @throws IllegalStateException if the underlying protocol provider is
* not registered/signed on a public service.
* @throws OperationFailedException with code NETWORK_FAILURE if
* subscribing fails due to errors experienced during network
* communication
*/
public void subscribe(String contactIdentifier) throws
IllegalArgumentException, IllegalStateException,
OperationFailedException
{
subscribe(contactListRoot, contactIdentifier);
}
/**
* Removes a subscription for the presence status of the specified
* contact.
*
* @param contact the contact whose status updates we are unsubscribing
* from.
* @throws IllegalArgumentException if <tt>contact</tt> is not a contact
* known to the underlying protocol provider
* @throws IllegalStateException if the underlying protocol provider is
* not registered/signed on a public service.
* @throws OperationFailedException with code NETWORK_FAILURE if
* unsubscribing fails due to errors experienced during network
* communication
*/
public void unsubscribe(Contact contact) throws IllegalArgumentException,
IllegalStateException, OperationFailedException
{
ContactGroupGibberishImpl parentGroup
= (ContactGroupGibberishImpl)((ContactGibberishImpl)contact)
.getParentContactGroup();
parentGroup.removeContact((ContactGibberishImpl)contact);
fireSubscriptionEvent(
contact,
contact.getParentContactGroup(),
SubscriptionEvent.SUBSCRIPTION_REMOVED);
}
/**
* Creates and returns a unresolved contact from the specified
* <tt>address</tt> and <tt>persistentData</tt>. The method will not try
* to establish a network connection and resolve the newly created Contact
* against the server. The protocol provider may will later try and resolve
* the contact. When this happens the corresponding event would notify
* interested subscription listeners.
*
* @param address an identifier of the contact that we'll be creating.
* @param persistentData a String returned Contact's getPersistentData()
* method during a previous run and that has been persistently stored
* locally.
* @return the unresolved <tt>Contact</tt> created from the specified
* <tt>address</tt> and <tt>persistentData</tt>
*/
public Contact createUnresolvedContact(String address,
String persistentData)
{
return createUnresolvedContact(address
, persistentData
, getServerStoredContactListRoot());
}
/**
* Creates and returns a unresolved contact from the specified
* <tt>address</tt> and <tt>persistentData</tt>. The method will not try
* to establish a network connection and resolve the newly created Contact
* against the server. The protocol provider may will later try and resolve
* the contact. When this happens the corresponding event would notify
* interested subscription listeners.
*
* @param address an identifier of the contact that we'll be creating.
* @param persistentData a String returned Contact's getPersistentData()
* method during a previous run and that has been persistently stored
* locally.
* @param parent the group where the unresolved contact is
* supposed to belong to.
*
* @return the unresolved <tt>Contact</tt> created from the specified
* <tt>address</tt> and <tt>persistentData</tt>
*/
public Contact createUnresolvedContact(String address,
String persistentData,
ContactGroup parent)
{
ContactGibberishImpl contact = new ContactGibberishImpl(
address
, parentProvider);
contact.setResolved(false);
( (ContactGroupGibberishImpl) parent).addContact(contact);
fireSubscriptionEvent(contact,
parent,
SubscriptionEvent.SUBSCRIPTION_CREATED);
//since we don't have any server, we'll simply resolve the contact
//ourselves as if we've just received an event from the server telling
//us that it has been resolved.
fireSubscriptionEvent(
contact, parent, SubscriptionEvent.SUBSCRIPTION_RESOLVED);
//since we are not a real protocol, we set the contact presence status
//ourselves
changePresenceStatusForContact( contact, getPresenceStatus());
return contact;
}
/**
* Looks for a gibberish protocol provider registered for a user id matching
* <tt>gibberishUserID</tt>.
*
* @param gibberishUserID the ID of the Gibberish user whose corresponding
* protocol provider we'd like to find.
* @return ProtocolProviderServiceGibberishImpl a gibberish protocol
* provider registered for a user with id <tt>gibberishUserID</tt> or null
* if there is no such protocol provider.
*/
public ProtocolProviderServiceGibberishImpl
findProviderForGibberishUserID(String gibberishUserID)
{
BundleContext bc = GibberishActivator.getBundleContext();
String osgiQuery = "(&"
+ "(" + ProtocolProviderFactory.PROTOCOL
+ "=Gibberish)"
+ "(" + ProtocolProviderFactory.USER_ID
+ "=" + gibberishUserID + ")"
+ ")";
ServiceReference[] refs = null;
try
{
refs = bc.getServiceReferences(
ProtocolProviderService.class.getName()
,osgiQuery);
}
catch (InvalidSyntaxException ex)
{
logger.error("Failed to execute the following osgi query: "
+ osgiQuery
, ex);
}
if(refs != null && refs.length > 0)
{
return (ProtocolProviderServiceGibberishImpl)bc.getService(refs[0]);
}
return null;
}
/**
* Looks for gibberish protocol providers that have added us to their
* contact list and returns list of all contacts representing us in these
* providers.
*
* @return a list of all contacts in other providers' contact lists that
* point to us.
*/
public List<Contact> findContactsPointingToUs()
{
List<Contact> contacts = new LinkedList<Contact>();
BundleContext bc = GibberishActivator.getBundleContext();
String osgiQuery =
"(" + ProtocolProviderFactory.PROTOCOL
+ "=Gibberish)";
ServiceReference[] refs = null;
try
{
refs = bc.getServiceReferences(
ProtocolProviderService.class.getName()
,osgiQuery);
}
catch (InvalidSyntaxException ex)
{
logger.error("Failed to execute the following osgi query: "
+ osgiQuery
, ex);
}
for (int i =0; refs != null && i < refs.length; i++)
{
ProtocolProviderServiceGibberishImpl gibProvider
= (ProtocolProviderServiceGibberishImpl)bc.getService(refs[i]);
OperationSetPersistentPresenceGibberishImpl opSetPersPresence
= (OperationSetPersistentPresenceGibberishImpl)gibProvider
.getOperationSet(OperationSetPersistentPresence.class);
Contact contact = opSetPersPresence.findContactByID(
parentProvider.getAccountID().getUserID());
if (contact != null)
contacts.add(contact);
}
return contacts;
}
/**
* Creates and returns a unresolved contact group from the specified
* <tt>address</tt> and <tt>persistentData</tt>. The method will not try
* to establish a network connection and resolve the newly created
* <tt>ContactGroup</tt> against the server or the contact itself. The
* protocol provider will later resolve the contact group. When this happens
* the corresponding event would notify interested subscription listeners.
*
* @param groupUID an identifier, returned by ContactGroup's getGroupUID,
* that the protocol provider may use in order to create the group.
* @param persistentData a String returned ContactGroups's
* getPersistentData() method during a previous run and that has been
* persistently stored locally.
* @param parentGroup the group under which the new group is to be created
* or null if this is group directly underneath the root.
* @return the unresolved <tt>ContactGroup</tt> created from the specified
* <tt>uid</tt> and <tt>persistentData</tt>
*/
public ContactGroup createUnresolvedContactGroup(String groupUID,
String persistentData, ContactGroup parentGroup)
{
ContactGroupGibberishImpl newGroup
= new ContactGroupGibberishImpl(
ContactGroupGibberishImpl.createNameFromUID(groupUID)
, parentProvider);
newGroup.setResolved(false);
//if parent is null then we're adding under root.
if(parentGroup == null)
parentGroup = getServerStoredContactListRoot();
((ContactGroupGibberishImpl)parentGroup).addSubgroup(newGroup);
this.fireServerStoredGroupEvent(
newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
return newGroup;
}
private class UnregistrationListener
implements RegistrationStateChangeListener
{
/**
* The method is called by a ProtocolProvider implementation whenver
* a change in the registration state of the corresponding provider had
* occurred. The method is particularly interested in events stating
* that the gibberish provider has unregistered so that it would fire
* status change events for all contacts in our buddy list.
*
* @param evt ProviderStatusChangeEvent the event describing the status
* change.
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
if (! evt.getNewState().equals(RegistrationState.UNREGISTERED)
&& !evt.getNewState().equals(RegistrationState.AUTHENTICATION_FAILED)
&& !evt.getNewState().equals(RegistrationState.CONNECTION_FAILED))
{
return;
}
//send event notifications saying that all our buddies are
//offline. The icq protocol does not implement top level buddies
//nor subgroups for top level groups so a simple nested loop
//would be enough.
Iterator<ContactGroup> groupsIter
= getServerStoredContactListRoot().subgroups();
while (groupsIter.hasNext())
{
ContactGroup group = groupsIter.next();
Iterator<Contact> contactsIter = group.contacts();
while (contactsIter.hasNext())
{
ContactGibberishImpl contact
= (ContactGibberishImpl) contactsIter.next();
PresenceStatus oldContactStatus
= contact.getPresenceStatus();
if (!oldContactStatus.isOnline())
continue;
contact.setPresenceStatus(GibberishStatusEnum.OFFLINE);
fireContactPresenceStatusChangeEvent(
contact
, contact.getParentContactGroup()
, oldContactStatus);
}
}
}
}
/**
* Returns the volatile group or null if this group has not yet been
* created.
*
* @return a volatile group existing in our contact list or <tt>null</tt>
* if such a group has not yet been created.
*/
private ContactGroupGibberishImpl getNonPersistentGroup()
{
for (int i = 0
; i < getServerStoredContactListRoot().countSubgroups()
; i++)
{
ContactGroupGibberishImpl gr =
(ContactGroupGibberishImpl)getServerStoredContactListRoot()
.getGroup(i);
if(!gr.isPersistent())
return gr;
}
return null;
}
/**
* Creates a non persistent contact for the specified address. This would
* also create (if necessary) a group for volatile contacts that would not
* be added to the server stored contact list. This method would have no
* effect on the server stored contact list.
*
* @param contactAddress the address of the volatile contact we'd like to
* create.
* @return the newly created volatile contact.
*/
public ContactGibberishImpl createVolatileContact(String contactAddress)
{
//First create the new volatile contact;
ContactGibberishImpl newVolatileContact
= new ContactGibberishImpl(contactAddress
, this.parentProvider);
newVolatileContact.setPersistent(false);
//Check whether a volatile group already exists and if not create
//one
ContactGroupGibberishImpl theVolatileGroup = getNonPersistentGroup();
//if the parent volatile group is null then we create it
if (theVolatileGroup == null)
{
theVolatileGroup = new ContactGroupGibberishImpl(
GibberishActivator.getResources().getI18NString(
"service.gui.NOT_IN_CONTACT_LIST_GROUP_NAME")
, parentProvider);
theVolatileGroup.setResolved(false);
theVolatileGroup.setPersistent(false);
this.contactListRoot.addSubgroup(theVolatileGroup);
fireServerStoredGroupEvent(theVolatileGroup
, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
}
//now add the volatile contact instide it
theVolatileGroup.addContact(newVolatileContact);
fireSubscriptionEvent(newVolatileContact
, theVolatileGroup
, SubscriptionEvent.SUBSCRIPTION_CREATED);
return newVolatileContact;
}
}