mirror of https://github.com/sipwise/jitsi.git
parent
2dfda98983
commit
03262f0dd4
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 413 B |
|
After Width: | Height: | Size: 662 B |
|
After Width: | Height: | Size: 2.9 KiB |
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* A simple, straightforward implementation of a rss ContactGroup. Since
|
||||
* the Rss protocol is not a real one, we simply store all group details
|
||||
* in class fields. You should know that when implementing a real protocol,
|
||||
* the contact group implementation would rather encapsulate group objects from
|
||||
* the protocol stack and group property values should be returned by consulting
|
||||
* the encapsulated object.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ContactGroupRssImpl
|
||||
implements ContactGroup
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ContactGroupRssImpl.class);
|
||||
|
||||
/**
|
||||
* The name of this Rss contact group.
|
||||
*/
|
||||
private String groupName = null;
|
||||
|
||||
/**
|
||||
* The list of this group's members.
|
||||
*/
|
||||
private Vector contacts = new Vector();
|
||||
|
||||
/**
|
||||
* The list of sub groups belonging to this group.
|
||||
*/
|
||||
private Vector subGroups = new Vector();
|
||||
|
||||
/**
|
||||
* The group that this group belongs to (or null if this is the root group).
|
||||
*/
|
||||
private ContactGroupRssImpl parentGroup = null;
|
||||
|
||||
/**
|
||||
* Determines whether this group is really in the contact list or whether
|
||||
* it is here only temporarily and will be gone next time we restart.
|
||||
*/
|
||||
private boolean isPersistent = true;
|
||||
|
||||
/**
|
||||
* The protocol provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceRssImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* Determines whether this group has been resolved on the server.
|
||||
* Unresolved groups are groups that were available on previous runs and
|
||||
* that the meta contact list has stored. During all next runs, when
|
||||
* bootstrapping, the meta contact list would create these groups as
|
||||
* unresolved. Once a protocol provider implementation confirms that the
|
||||
* groups are still on the server, it would issue an event indicating that
|
||||
* the groups are now resolved.
|
||||
*/
|
||||
private boolean isResolved = true;
|
||||
|
||||
/**
|
||||
* An id uniquely identifying the group. For many protocols this could be
|
||||
* the group name itself.
|
||||
*/
|
||||
private String uid = null;
|
||||
private static final String UID_SUFFIX = ".uid";
|
||||
|
||||
/**
|
||||
* Creates a ContactGroupRssImpl with the specified name.
|
||||
*
|
||||
* @param groupName the name of the group.
|
||||
* @param parentProvider the protocol provider that created this group.
|
||||
*/
|
||||
public ContactGroupRssImpl(
|
||||
String groupName,
|
||||
ProtocolProviderServiceRssImpl parentProvider)
|
||||
{
|
||||
this.groupName = groupName;
|
||||
this.uid = groupName + UID_SUFFIX;
|
||||
this.parentProvider = parentProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the group may contain subgroups or not.
|
||||
*
|
||||
* @return always true in this implementation.
|
||||
*/
|
||||
public boolean canContainSubgroups()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol provider that this group belongs to.
|
||||
* @return a regerence to the ProtocolProviderService instance that this
|
||||
* ContactGroup belongs to.
|
||||
*/
|
||||
public ProtocolProviderService getProtocolProvider()
|
||||
{
|
||||
return parentProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator over all contacts, member of this
|
||||
* <tt>ContactGroup</tt>.
|
||||
*
|
||||
* @return a java.util.Iterator over all contacts inside this
|
||||
* <tt>ContactGroup</tt>
|
||||
*/
|
||||
public Iterator contacts()
|
||||
{
|
||||
return contacts.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact to this group.
|
||||
* @param contactToAdd the ContactRssImpl to add to this group.
|
||||
*/
|
||||
public void addContact(ContactRssImpl contactToAdd)
|
||||
{
|
||||
this.contacts.add(contactToAdd);
|
||||
contactToAdd.setParentGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of <tt>Contact</tt> members of this
|
||||
* <tt>ContactGroup</tt>
|
||||
*
|
||||
* @return an int indicating the number of <tt>Contact</tt>s, members of
|
||||
* this <tt>ContactGroup</tt>.
|
||||
*/
|
||||
public int countContacts()
|
||||
{
|
||||
return contacts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of subgroups contained by this
|
||||
* <tt>ContactGroup</tt>.
|
||||
*
|
||||
* @return the number of subGroups currently added to this group.
|
||||
*/
|
||||
public int countSubgroups()
|
||||
{
|
||||
return subGroups.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified contact group to the contained by this group.
|
||||
* @param subgroup the ContactGroupRssImpl to add as a subgroup to this group.
|
||||
*/
|
||||
public void addSubgroup(ContactGroupRssImpl subgroup)
|
||||
{
|
||||
this.subGroups.add(subgroup);
|
||||
subgroup.setParentGroup(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the group that is the new parent of this group
|
||||
* @param parent ContactGroupRssImpl
|
||||
*/
|
||||
void setParentGroup(ContactGroupRssImpl parent)
|
||||
{
|
||||
this.parentGroup = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact group that currently contains this group or null if
|
||||
* this is the root contact group.
|
||||
* @return the contact group that currently contains this group or null if
|
||||
* this is the root contact group.
|
||||
*/
|
||||
public ContactGroup getParentContactGroup()
|
||||
{
|
||||
return this.parentGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified contact group from the this group's subgroups.
|
||||
* @param subgroup the ContactGroupRssImpl subgroup to remove.
|
||||
*/
|
||||
public void removeSubGroup(ContactGroupRssImpl subgroup)
|
||||
{
|
||||
this.subGroups.remove(subgroup);
|
||||
subgroup.setParentGroup(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the <tt>Contact</tt> with the specified index.
|
||||
*
|
||||
* @param index the index of the <tt>Contact</tt> to return.
|
||||
* @return the <tt>Contact</tt> with the specified index.
|
||||
*/
|
||||
public Contact getContact(int index)
|
||||
{
|
||||
return (ContactRssImpl)contacts.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that is parent of the specified rssGroup or null
|
||||
* if no parent was found.
|
||||
* @param rssGroup the group whose parent we're looking for.
|
||||
* @return the ContactGroupRssImpl instance that rssGroup
|
||||
* belongs to or null if no parent was found.
|
||||
*/
|
||||
public ContactGroupRssImpl findGroupParent(
|
||||
ContactGroupRssImpl rssGroup)
|
||||
{
|
||||
if ( subGroups.contains(rssGroup) )
|
||||
return this;
|
||||
|
||||
Iterator subGroupsIter = subgroups();
|
||||
while (subGroupsIter.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl subgroup
|
||||
= (ContactGroupRssImpl) subGroupsIter.next();
|
||||
|
||||
ContactGroupRssImpl parent
|
||||
= subgroup.findGroupParent(rssGroup);
|
||||
|
||||
if(parent != null)
|
||||
return parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that is parent of the specified rssContact or
|
||||
* null if no parent was found.
|
||||
*
|
||||
* @param rssContact the contact whose parent we're looking for.
|
||||
* @return the ContactGroupRssImpl instance that rssContact
|
||||
* belongs to or <tt>null</tt> if no parent was found.
|
||||
*/
|
||||
public ContactGroupRssImpl findContactParent(
|
||||
ContactRssImpl rssContact)
|
||||
{
|
||||
if ( contacts.contains(rssContact) )
|
||||
return this;
|
||||
|
||||
Iterator subGroupsIter = subgroups();
|
||||
while (subGroupsIter.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl subgroup
|
||||
= (ContactGroupRssImpl) subGroupsIter.next();
|
||||
|
||||
ContactGroupRssImpl parent
|
||||
= subgroup.findContactParent(rssContact);
|
||||
|
||||
if(parent != null)
|
||||
return parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the <tt>Contact</tt> with the specified address or identifier.
|
||||
*
|
||||
* @param id the addres or identifier of the <tt>Contact</tt> we are
|
||||
* looking for.
|
||||
* @return the <tt>Contact</tt> with the specified id or address.
|
||||
*/
|
||||
public Contact getContact(String id)
|
||||
{
|
||||
Iterator contactsIter = contacts();
|
||||
while (contactsIter.hasNext())
|
||||
{
|
||||
ContactRssImpl contact = (ContactRssImpl) contactsIter.next();
|
||||
if (contact.getAddress().equals(id))
|
||||
return contact;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified index.
|
||||
*
|
||||
* @param index the index of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return the <tt>ContactGroup</tt> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(int index)
|
||||
{
|
||||
return (ContactGroup)subGroups.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subgroup with the specified name.
|
||||
*
|
||||
* @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
|
||||
* @return the <tt>ContactGroup</tt> with the specified index.
|
||||
*/
|
||||
public ContactGroup getGroup(String groupName)
|
||||
{
|
||||
Iterator groupsIter = subgroups();
|
||||
while (groupsIter.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl contactGroup
|
||||
= (ContactGroupRssImpl) groupsIter.next();
|
||||
if (contactGroup.getGroupName().equals(groupName))
|
||||
return contactGroup;
|
||||
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this group.
|
||||
*
|
||||
* @return a String containing the name of this group.
|
||||
*/
|
||||
public String getGroupName()
|
||||
{
|
||||
return this.groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this group a new name.
|
||||
* @param newGrpName a String containing the new name of this group.
|
||||
*/
|
||||
public void setGroupName(String newGrpName)
|
||||
{
|
||||
this.groupName = newGrpName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the sub groups that this
|
||||
* <tt>ContactGroup</tt> contains.
|
||||
*
|
||||
* @return a java.util.Iterator over the <tt>ContactGroup</tt> children
|
||||
* of this group (i.e. subgroups).
|
||||
*/
|
||||
public Iterator subgroups()
|
||||
{
|
||||
return subGroups.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified contact from this group.
|
||||
* @param contact the ContactRssImpl to remove from this group
|
||||
*/
|
||||
public void removeContact(ContactRssImpl contact)
|
||||
{
|
||||
this.contacts.remove(contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contact with the specified id or null if no such contact
|
||||
* exists.
|
||||
* @param id the id of the contact we're looking for.
|
||||
* @return ContactRssImpl
|
||||
*/
|
||||
public ContactRssImpl findContactByID(String id)
|
||||
{
|
||||
//first go through the contacts that are direct children.
|
||||
Iterator contactsIter = contacts();
|
||||
|
||||
while(contactsIter.hasNext())
|
||||
{
|
||||
ContactRssImpl mContact = (ContactRssImpl)contactsIter.next();
|
||||
|
||||
if( mContact.getAddress().equals(id) )
|
||||
return mContact;
|
||||
}
|
||||
|
||||
//if we didn't find it here, let's try in the subougroups
|
||||
Iterator groupsIter = subgroups();
|
||||
|
||||
while( groupsIter.hasNext() )
|
||||
{
|
||||
ContactGroupRssImpl mGroup = (ContactGroupRssImpl)groupsIter.next();
|
||||
|
||||
ContactRssImpl mContact = mGroup.findContactByID(id);
|
||||
|
||||
if (mContact != null)
|
||||
return mContact;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a String representation of this group and the contacts it
|
||||
* contains (may turn out to be a relatively long string).
|
||||
* @return a String representing this group and its child contacts.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
|
||||
StringBuffer buff = new StringBuffer(getGroupName());
|
||||
buff.append(".subGroups=" + countSubgroups() + ":\n");
|
||||
|
||||
Iterator subGroups = subgroups();
|
||||
while (subGroups.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl group = (ContactGroupRssImpl)subGroups.next();
|
||||
buff.append(group.toString());
|
||||
if (subGroups.hasNext())
|
||||
buff.append("\n");
|
||||
}
|
||||
|
||||
buff.append("\nChildContacts="+countContacts()+":[");
|
||||
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactRssImpl contact = (ContactRssImpl) contacts.next();
|
||||
buff.append(contact.toString());
|
||||
if(contacts.hasNext())
|
||||
buff.append(", ");
|
||||
}
|
||||
return buff.append("]").toString();
|
||||
}
|
||||
|
||||
public Vector getRssURLList(Vector rssURLList){
|
||||
//private Vector rssURLList;
|
||||
//StringBuffer buff = new StringBuffer(getGroupName());
|
||||
//buff.append(".subGroups=" + countSubgroups() + ":\n");
|
||||
|
||||
Iterator subGroups = subgroups();
|
||||
while (subGroups.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl group = (ContactGroupRssImpl)subGroups.next();
|
||||
//buff.append(
|
||||
group.getRssURLList(rssURLList);
|
||||
// if (subGroups.hasNext())
|
||||
// buff.append("\n");
|
||||
}
|
||||
|
||||
//buff.append("\nChildContacts="+countContacts()+":[");
|
||||
|
||||
Iterator contacts = contacts();
|
||||
while (contacts.hasNext())
|
||||
{
|
||||
ContactRssImpl contact = (ContactRssImpl) contacts.next();
|
||||
//buff.append(contact.getDisplayName());
|
||||
rssURLList.addElement(contact);
|
||||
//if(contacts.hasNext())
|
||||
// buff.append(", ");
|
||||
}
|
||||
//return buff.append("]").toString();
|
||||
return rssURLList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether or not this contact group is being stored by the server.
|
||||
* Non persistent contact groups are common in the case of simple,
|
||||
* non-persistent presence operation sets. They could however also be seen
|
||||
* in persistent presence operation sets when for example we have received
|
||||
* an event from someone not on our contact list and the contact that we
|
||||
* associated with that user is placed in a non persistent group. Non
|
||||
* persistent contact groups are volatile even when coming from a persistent
|
||||
* presence op. set. They would only exist until the application is closed
|
||||
* and will not be there next time it is loaded.
|
||||
*
|
||||
* @param isPersistent true if the contact group is to be persistent and
|
||||
* false otherwise.
|
||||
*/
|
||||
public void setPersistent(boolean isPersistent)
|
||||
{
|
||||
this.isPersistent = isPersistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact group is being stored by the
|
||||
* server. Non persistent contact groups exist for the sole purpose of
|
||||
* containing non persistent contacts.
|
||||
* @return true if the contact group is persistent and false otherwise.
|
||||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return isPersistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as no persistent data is required and the contact address is
|
||||
* sufficient for restoring the contact.
|
||||
* <p>
|
||||
* @return null as no such data is needed.
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact has been resolved against the
|
||||
* server. Unresolved contacts are used when initially loading a contact
|
||||
* list that has been stored in a local file until the presence operation
|
||||
* set has managed to retrieve all the contact list from the server and has
|
||||
* properly mapped contacts to their on-line buddies.
|
||||
* @return true if the contact has been resolved (mapped against a buddy)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isResolved()
|
||||
{
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the group resolved or unresolved.
|
||||
*
|
||||
* @param resolved true to make the group resolved; false to
|
||||
* make it unresolved
|
||||
*/
|
||||
public void setResolved(boolean resolved)
|
||||
{
|
||||
this.isResolved = resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>String</tt> that uniquely represnets the group inside
|
||||
* the current protocol. The string MUST be persistent (it must not change
|
||||
* across connections or runs of the application). In many cases (Jabber,
|
||||
* ICQ) the string may match the name of the group as these protocols
|
||||
* only allow a single level of contact groups and there is no danger of
|
||||
* having the same name twice in the same contact list. Other protocols
|
||||
* (no examples come to mind but that doesn't bother me ;) ) may be
|
||||
* supporting mutilple levels of grooups so it might be possible for group
|
||||
* A and group B to both contain groups named C. In such cases the
|
||||
* implementation must find a way to return a unique identifier in this
|
||||
* method and this UID should never change for a given group.
|
||||
*
|
||||
* @return a String representing this group in a unique and persistent
|
||||
* way.
|
||||
*/
|
||||
public String getUID()
|
||||
{
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ugly but tricky conversion method.
|
||||
* @param uid the uid we'd like to get a name from
|
||||
* @return the name of the group with the specified <tt>uid</tt>.
|
||||
*/
|
||||
static String createNameFromUID(String uid)
|
||||
{
|
||||
return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one which in terms
|
||||
* of contact groups translates to having the equal names and matching
|
||||
* subgroups and child contacts. The resolved status of contactgroups and
|
||||
* contacts is deliberately ignored so that groups and/or contacts would
|
||||
* be assumed equal even if it differs.
|
||||
* <p>
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <code>true</code> if this contact group has the equal child
|
||||
* contacts and subgroups to those of the <code>obj</code> argument.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj == null
|
||||
|| !(obj instanceof ContactGroupRssImpl))
|
||||
return false;
|
||||
|
||||
ContactGroupRssImpl rssGroup
|
||||
= (ContactGroupRssImpl)obj;
|
||||
|
||||
if( ! rssGroup.getGroupName().equals(getGroupName())
|
||||
|| ! rssGroup.getUID().equals(getUID())
|
||||
|| rssGroup.countContacts() != countContacts()
|
||||
|| rssGroup.countSubgroups() != countSubgroups())
|
||||
return false;
|
||||
|
||||
//traverse child contacts
|
||||
Iterator theirContacts = rssGroup.contacts();
|
||||
|
||||
while(theirContacts.hasNext())
|
||||
{
|
||||
ContactRssImpl theirContact
|
||||
= (ContactRssImpl)theirContacts.next();
|
||||
|
||||
ContactRssImpl ourContact
|
||||
= (ContactRssImpl)getContact(theirContact.getAddress());
|
||||
|
||||
if(ourContact == null
|
||||
|| !ourContact.equals(theirContact))
|
||||
return false;
|
||||
}
|
||||
|
||||
//traverse subgroups
|
||||
Iterator theirSubgroups = rssGroup.subgroups();
|
||||
|
||||
while(theirSubgroups.hasNext())
|
||||
{
|
||||
ContactGroupRssImpl theirSubgroup
|
||||
= (ContactGroupRssImpl)theirSubgroups.next();
|
||||
|
||||
ContactGroupRssImpl ourSubgroup
|
||||
= (ContactGroupRssImpl)getGroup(
|
||||
theirSubgroup.getGroupName());
|
||||
|
||||
if(ourSubgroup == null
|
||||
|| !ourSubgroup.equals(theirSubgroup))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of a rss Contact.
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
public class ContactRssImpl
|
||||
implements Contact
|
||||
{
|
||||
private String lastDate = null;
|
||||
private Date date = null;
|
||||
private String nickName = null;
|
||||
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ContactRssImpl.class);
|
||||
|
||||
private static SimpleDateFormat DATE_FORMATTER =
|
||||
new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss");
|
||||
|
||||
/**
|
||||
* The id of the contact.
|
||||
*/
|
||||
private String contactID = null;
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceRssImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* The group that belong to.
|
||||
*/
|
||||
private ContactGroupRssImpl parentGroup = null;
|
||||
|
||||
/**
|
||||
* The presence status of the contact.
|
||||
*/
|
||||
private PresenceStatus presenceStatus = RssStatusEnum.ONLINE;
|
||||
|
||||
/**
|
||||
* Determines whether this contact is persistent, i.e. member of the contact
|
||||
* list or whether it is here only temporarily.
|
||||
*/
|
||||
private boolean isPersistent = true;
|
||||
|
||||
/**
|
||||
* Determines whether the contact has been resolved (i.e. we have a
|
||||
* confirmation that it is still on the server contact list).
|
||||
*/
|
||||
private boolean isResolved = false;
|
||||
|
||||
/**
|
||||
* Creates an instance of a meta contact with the specified string used
|
||||
* as a name and identifier.
|
||||
*
|
||||
* @param id the identifier of this contact (also used as a name).
|
||||
* @param parentProvider the provider that created us.
|
||||
*/
|
||||
public ContactRssImpl(
|
||||
String id,
|
||||
ProtocolProviderServiceRssImpl parentProvider)
|
||||
{
|
||||
this.contactID = id;
|
||||
this.parentProvider = parentProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only called when the contact is added to a new
|
||||
* <tt>ContactGroupRssImpl</tt> by the
|
||||
* <tt>ContactGroupRssImpl</tt> itself.
|
||||
*
|
||||
* @param newParentGroup the <tt>ContactGroupRssImpl</tt> that is now
|
||||
* parent of this <tt>ContactRssImpl</tt>
|
||||
*/
|
||||
void setParentGroup(ContactGroupRssImpl newParentGroup)
|
||||
{
|
||||
this.parentGroup = newParentGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String that can be used for identifying the contact.
|
||||
*
|
||||
* @return a String id representing and uniquely identifying the contact.
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
return contactID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String that could be used by any user interacting modules
|
||||
* for referring to this contact.
|
||||
*
|
||||
* @return a String that can be used for referring to this contact when
|
||||
* interacting with the user.
|
||||
*/
|
||||
public String getDisplayName()
|
||||
{
|
||||
if(nickName == null) return contactID;
|
||||
else return nickName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String nickName){
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Date corresponding to the date of the last query
|
||||
* on this rss contact.
|
||||
*
|
||||
* @return a Date in order to compare with a new one obtained via
|
||||
* a query on the feed.
|
||||
*/
|
||||
public Date getDate()
|
||||
{
|
||||
return this.date;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is only called when a new date is found after a query
|
||||
* on the feed corresponding to this contact
|
||||
*
|
||||
* @param date the <tt>Date</tt> that is now
|
||||
* the last update date of the <tt>ContactRssImpl</tt>
|
||||
*/
|
||||
public void setDate(Date date)
|
||||
{
|
||||
this.date = date;
|
||||
this.lastDate = convertDateToString(this.date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updating the lastDate in String format of the contact
|
||||
*
|
||||
* @param lastDate the <tt>String</tt> that is now
|
||||
* the last update date of the <tt>ContactRssImpl</tt>
|
||||
*/
|
||||
public void setLastDate(String lastDate)
|
||||
{
|
||||
this.lastDate = lastDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String corresponding to the date of the last query
|
||||
* on this rss contact.
|
||||
*
|
||||
* @return a String representing a Date in order to compare with
|
||||
* a new one obtained via a query on the feed.
|
||||
*/
|
||||
public String getLastDate()
|
||||
{
|
||||
return this.lastDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String corresponding to a date after a conversion
|
||||
* from a Date
|
||||
*
|
||||
* @param date the date
|
||||
* @return a String which is placed in the lastDate variable of the
|
||||
* present contact
|
||||
*/
|
||||
private String convertDateToString(Date date)
|
||||
{
|
||||
return DATE_FORMATTER.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when a the contact is restored and a
|
||||
* previous saved lastDate is found as persistent-data: this
|
||||
* data is in a String format, and this method convert it into
|
||||
* a Date usable by the protocol.
|
||||
* @param lastDate date as String
|
||||
*/
|
||||
private void convertStringToDate(String lastDate)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.date = DATE_FORMATTER.parse(lastDate);
|
||||
}
|
||||
catch(ParseException ex)
|
||||
{
|
||||
logger.error("Cannot parse Date", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of String corresponding to a date bursted in multiple
|
||||
* fields as this:
|
||||
* ddd mmm DD HH:mm:ss ZZZZ YYYY
|
||||
*
|
||||
* @return an Array of String
|
||||
*/
|
||||
private String[] getToken(String param1, String param2)
|
||||
{
|
||||
int i = 0;
|
||||
String data[] = new String[8];
|
||||
StringTokenizer tmp = new StringTokenizer(param1, param2);
|
||||
|
||||
while(tmp.hasMoreTokens())
|
||||
{
|
||||
data[i] = tmp.nextToken();
|
||||
i++;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing an image (most often a photo or an
|
||||
* avatar) that the contact uses as a representation.
|
||||
*
|
||||
* @return byte[] an image representing the contact.
|
||||
*/
|
||||
public byte[] getImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the contact.
|
||||
*
|
||||
* @return RssStatusEnum.STATUS.
|
||||
*/
|
||||
public PresenceStatus getPresenceStatus()
|
||||
{
|
||||
return this.presenceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets <tt>rssPresenceStatus</tt> as the PresenceStatus that this
|
||||
* contact is currently in.
|
||||
* @param rssPresenceStatus the <tt>RssPresenceStatus</tt>
|
||||
* currently valid for this contact.
|
||||
*/
|
||||
public void setPresenceStatus(PresenceStatus rssPresenceStatus)
|
||||
{
|
||||
this.presenceStatus = rssPresenceStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the protocol provider that created the contact.
|
||||
*
|
||||
* @return a refererence to an instance of the ProtocolProviderService
|
||||
*/
|
||||
public ProtocolProviderService getProtocolProvider()
|
||||
{
|
||||
return parentProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact represents our own identity.
|
||||
*
|
||||
* @return true in case this is a contact that represents ourselves and
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean isLocal()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that contains this contact.
|
||||
* @return a reference to the <tt>ContactGroupRssImpl</tt> that
|
||||
* contains this contact.
|
||||
*/
|
||||
public ContactGroup getParentContactGroup()
|
||||
{
|
||||
return this.parentGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this contact, containing most of its
|
||||
* representative details.
|
||||
*
|
||||
* @return a string representation of this contact.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer buff
|
||||
= new StringBuffer("ContactRssImpl[ DisplayName=")
|
||||
.append(getDisplayName()).append("]");
|
||||
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact is being stored by the server.
|
||||
* Non persistent contacts are common in the case of simple, non-persistent
|
||||
* presence operation sets. They could however also be seen in persistent
|
||||
* presence operation sets when for example we have received an event
|
||||
* from someone not on our contact list. Non persistent contacts are
|
||||
* volatile even when coming from a persistent presence op. set. They would
|
||||
* only exist until the application is closed and will not be there next
|
||||
* time it is loaded.
|
||||
*
|
||||
* @return true if the contact is persistent and false otherwise.
|
||||
*/
|
||||
public boolean isPersistent()
|
||||
{
|
||||
return isPersistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies whether or not this contact is being stored by the server.
|
||||
* Non persistent contacts are common in the case of simple, non-persistent
|
||||
* presence operation sets. They could however also be seen in persistent
|
||||
* presence operation sets when for example we have received an event
|
||||
* from someone not on our contact list. Non persistent contacts are
|
||||
* volatile even when coming from a persistent presence op. set. They would
|
||||
* only exist until the application is closed and will not be there next
|
||||
* time it is loaded.
|
||||
*
|
||||
* @param isPersistent true if the contact is persistent and false
|
||||
* otherwise.
|
||||
*/
|
||||
public void setPersistent(boolean isPersistent)
|
||||
{
|
||||
this.isPersistent = isPersistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null as no persistent data is required and the contact address is
|
||||
* sufficient for restoring the contact.
|
||||
* <p>
|
||||
* @return null as no such data is needed.
|
||||
*/
|
||||
public String getPersistentData()
|
||||
{
|
||||
// to store data only when lastDate is set
|
||||
if(lastDate != null)
|
||||
return "lastDate=" + lastDate + ";";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setPersistentData(String persistentData)
|
||||
{
|
||||
if(persistentData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
StringTokenizer dataToks = new StringTokenizer(persistentData, ";");
|
||||
while(dataToks.hasMoreTokens())
|
||||
{
|
||||
String data[] = dataToks.nextToken().split("=");
|
||||
if(data[0].equals("lastDate") && data.length > 1)
|
||||
{
|
||||
this.lastDate = data[1];
|
||||
convertStringToDate(this.lastDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this contact has been resolved against the
|
||||
* server. Unresolved contacts are used when initially loading a contact
|
||||
* list that has been stored in a local file until the presence operation
|
||||
* set has managed to retrieve all the contact list from the server and has
|
||||
* properly mapped contacts to their on-line buddies.
|
||||
*
|
||||
* @return true if the contact has been resolved (mapped against a buddy)
|
||||
* and false otherwise.
|
||||
*/
|
||||
public boolean isResolved()
|
||||
{
|
||||
return isResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the contact resolved or unresolved.
|
||||
*
|
||||
* @param resolved true to make the contact resolved; false to
|
||||
* make it unresolved
|
||||
*/
|
||||
public void setResolved(boolean resolved)
|
||||
{
|
||||
this.isResolved = resolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one which in terms
|
||||
* of contacts translates to having equal ids. The resolved status of the
|
||||
* contacts deliberately ignored so that contacts would be declared equal
|
||||
* even if it differs.
|
||||
* <p>
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return <code>true</code> if this contact has the same id as that of the
|
||||
* <code>obj</code> argument.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj == null
|
||||
|| ! (obj instanceof ContactRssImpl))
|
||||
return false;
|
||||
|
||||
ContactRssImpl rssContact = (ContactRssImpl) obj;
|
||||
|
||||
return this.getAddress().equals(rssContact.getAddress());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the persistent presence operation set that this contact belongs
|
||||
* to.
|
||||
*
|
||||
* @return the <tt>OperationSetPersistentPresenceRssImpl</tt> that
|
||||
* this contact belongs to.
|
||||
*/
|
||||
public OperationSetPersistentPresenceRssImpl
|
||||
getParentPresenceOperationSet()
|
||||
{
|
||||
return (OperationSetPersistentPresenceRssImpl)parentProvider
|
||||
.getOperationSet(OperationSetPersistentPresence.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Very simple message implementation for the Rss protocol.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class MessageRssImpl
|
||||
implements Message
|
||||
{
|
||||
/**
|
||||
* The actual message content.
|
||||
*/
|
||||
private String textContent = null;
|
||||
|
||||
/**
|
||||
* The content type of the message. (text/plain if null)
|
||||
*/
|
||||
private String contentType = null;
|
||||
|
||||
/**
|
||||
* The message encoding. (UTF8 if null).
|
||||
*/
|
||||
private String contentEncoding = null;
|
||||
|
||||
/**
|
||||
* A String uniquely identifying the message
|
||||
*/
|
||||
private String messageUID = null;
|
||||
|
||||
/**
|
||||
* The subject of the message. (most often is null)
|
||||
*/
|
||||
private String subject = null;
|
||||
|
||||
/**
|
||||
* Creates a message instance according to the specified parameters.
|
||||
*
|
||||
* @param content the message body
|
||||
* @param contentType message content type or null for text/plain
|
||||
* @param contentEncoding message encoding or null for UTF8
|
||||
* @param subject the subject of the message or null for no subject.
|
||||
*/
|
||||
public MessageRssImpl(String content,
|
||||
String contentType,
|
||||
String contentEncoding,
|
||||
String subject)
|
||||
{
|
||||
this.textContent = content;
|
||||
this.contentType = contentType;
|
||||
this.contentEncoding = contentEncoding;
|
||||
this.subject = subject;
|
||||
|
||||
//generate the uid
|
||||
this.messageUID = String.valueOf(System.currentTimeMillis())
|
||||
+ String.valueOf(hashCode());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message body.
|
||||
*
|
||||
* @return the message content.
|
||||
*/
|
||||
public String getContent()
|
||||
{
|
||||
return textContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the content of this message.
|
||||
*
|
||||
* @return the type of the content of this message.
|
||||
*/
|
||||
public String getContentType()
|
||||
{
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoding used for the message content.
|
||||
*
|
||||
* @return the encoding of the message body.
|
||||
*/
|
||||
public String getEncoding()
|
||||
{
|
||||
return contentEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string uniquely identifying the message.
|
||||
*
|
||||
* @return a <tt>String</tt> uniquely identifying the message.
|
||||
*/
|
||||
public String getMessageUID()
|
||||
{
|
||||
return messageUID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message body in a binary form.
|
||||
*
|
||||
* @return a <tt>byte[]</tt> representation of the message body.
|
||||
*/
|
||||
public byte[] getRawData()
|
||||
{
|
||||
return getContent().getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the length of this message.
|
||||
*
|
||||
* @return the length of this message.
|
||||
*/
|
||||
public int getSize()
|
||||
{
|
||||
return getContent().length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message subject.
|
||||
*
|
||||
* @return the message subject.
|
||||
*/
|
||||
public String getSubject()
|
||||
{
|
||||
return subject;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,436 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
/**
|
||||
* Instant messaging functionalites for the Rss protocol.
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
public class OperationSetBasicInstantMessagingRssImpl
|
||||
implements OperationSetBasicInstantMessaging
|
||||
{
|
||||
/**
|
||||
* Currently registered message listeners.
|
||||
*/
|
||||
private Vector messageListeners = new Vector();
|
||||
|
||||
/**
|
||||
* The currently valid persistent presence operation set..
|
||||
*/
|
||||
private OperationSetPersistentPresenceRssImpl opSetPersPresence = null;
|
||||
|
||||
/**
|
||||
* The protocol provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceRssImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* The timer used in order to refresh one or more rss feeds
|
||||
*/
|
||||
private Timer timer = null;
|
||||
|
||||
/**
|
||||
* The value corresponding to the time in ms
|
||||
* of the rss refreshing period (here 10min)
|
||||
*/
|
||||
final int PERIOD_REFRESH_RSS = 600000;
|
||||
|
||||
/**
|
||||
* Creates an instance of this operation set keeping a reference to the
|
||||
* parent protocol provider and presence operation set.
|
||||
*
|
||||
* @param provider The provider instance that creates us.
|
||||
* @param opSetPersPresence the currently valid
|
||||
* <tt>OperationSetPersistentPresenceRssImpl</tt> instance.
|
||||
*/
|
||||
public OperationSetBasicInstantMessagingRssImpl(
|
||||
ProtocolProviderServiceRssImpl provider,
|
||||
OperationSetPersistentPresenceRssImpl opSetPersPresence)
|
||||
{
|
||||
this.opSetPersPresence = opSetPersPresence;
|
||||
this.parentProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a MessageListener with this operation set so that it gets
|
||||
* notifications of successful message delivery, failure or reception of
|
||||
* incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to register.
|
||||
*/
|
||||
public void addMessageListener(MessageListener listener)
|
||||
{
|
||||
if(!messageListeners.contains(listener))
|
||||
messageListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending arbitrary MIME-encoding content.
|
||||
*
|
||||
* @param content content value
|
||||
* @param contentType the MIME-type for <tt>content</tt>
|
||||
* @param contentEncoding encoding used for <tt>content</tt>
|
||||
* @param subject a <tt>String</tt> subject or <tt>null</tt> for now
|
||||
* subject.
|
||||
* @return the newly created message.
|
||||
*/
|
||||
public Message createMessage(byte[] content, String contentType,
|
||||
String contentEncoding, String subject)
|
||||
{
|
||||
return new MessageRssImpl(new String(content), contentType
|
||||
, contentEncoding, subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Message instance for sending a simple text messages with
|
||||
* default (text/plain) content type and encoding.
|
||||
*
|
||||
* @param messageText the string content of the message.
|
||||
* @return Message the newly created message
|
||||
*/
|
||||
public Message createMessage(String messageText)
|
||||
{
|
||||
|
||||
return new MessageRssImpl(messageText, DEFAULT_MIME_TYPE
|
||||
, DEFAULT_MIME_ENCODING, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisteres <tt>listener</tt> so that it won't receive any further
|
||||
* notifications upon successful message delivery, failure or reception
|
||||
* of incoming messages..
|
||||
*
|
||||
* @param listener the <tt>MessageListener</tt> to unregister.
|
||||
*/
|
||||
public void removeMessageListener(MessageListener listener)
|
||||
{
|
||||
messageListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a RSS feed specified as contact
|
||||
*
|
||||
* @param rssContact the <tt>contact</tt> to send query
|
||||
* @param newContact the <tt>boolean</tt> to now if it's a new feed/contact
|
||||
* @param aloneUpdate the <tt>boolean</tt> to know if it's
|
||||
* a query just for one feed/contact
|
||||
*/
|
||||
private void submitRssQuery(ContactRssImpl rssContact,
|
||||
boolean newContact,
|
||||
boolean aloneUpdate)
|
||||
{
|
||||
Message msg;
|
||||
boolean newName = false;
|
||||
boolean newDate = false;
|
||||
boolean update = false;
|
||||
Date lastQueryDate = null;
|
||||
String newDisplayName = new String();
|
||||
String oldDisplayName = new String();
|
||||
|
||||
//we instantiate a new RssFeedReader which will contain the feed retrieved
|
||||
RssFeedReader rssFeed = new RssFeedReader(rssContact.getAddress());
|
||||
|
||||
//we parse the feed/contact
|
||||
rssFeed.recupFlux();
|
||||
|
||||
if(rssFeed.getFeed() == null)
|
||||
{
|
||||
msg = createMessage("No RSS feed available at URL "+ rssContact.getAddress());
|
||||
}else
|
||||
{
|
||||
//we recover the feed's old name
|
||||
if(newContact)
|
||||
oldDisplayName = rssContact.getDisplayName();
|
||||
else
|
||||
oldDisplayName = rssFeed.getTitle();
|
||||
|
||||
//we change the contact's displayName according to the feed's title
|
||||
newDisplayName = rssFeed.getTitle();
|
||||
if(!(newDisplayName.equals(oldDisplayName)))
|
||||
{
|
||||
newName = true;
|
||||
}
|
||||
rssContact.setDisplayName(newDisplayName);
|
||||
|
||||
//Looking for a date representing the last item retrieved on this feed
|
||||
//we look after a date saving in the contact's parameters (i.e. in the
|
||||
// file contactlist.xml)
|
||||
if(rssContact.getDate() != null)
|
||||
lastQueryDate = rssContact.getDate();
|
||||
|
||||
//we create the message containing the new items retrieved
|
||||
msg = createMessage(rssFeed.getPrintedFeed(lastQueryDate));
|
||||
|
||||
//if a newer date is avalaible for the current feed/contact looking the
|
||||
// date of each item of the feed retrieved, we update this date
|
||||
if(rssFeed.getUltimateItemDate() != null)
|
||||
{
|
||||
if(lastQueryDate != null)
|
||||
{
|
||||
if(rssFeed.getUltimateItemDate().compareTo(lastQueryDate)>0)
|
||||
{
|
||||
rssContact.setDate(rssFeed.getUltimateItemDate());
|
||||
newDate = true;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rssContact.setDate(rssFeed.getUltimateItemDate());
|
||||
newDate = true;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
update = true;
|
||||
|
||||
//if we have a new date or a new name on this feed/contact, we fire that
|
||||
// the contact has his properties modified in order to save it
|
||||
if(newName || newDate)
|
||||
this.opSetPersPresence.fireContactPropertyChangeEvent(
|
||||
ContactPropertyChangeEvent.
|
||||
PROPERTY_DISPLAY_NAME, rssContact,
|
||||
oldDisplayName, newDisplayName);
|
||||
}
|
||||
|
||||
//if the feed has been updated or if the user made a request on a specific
|
||||
//feed/contact, we fire a new message containing the new items to the user
|
||||
if(update || aloneUpdate)
|
||||
fireMessageReceived(msg, rssContact);
|
||||
}
|
||||
|
||||
/**
|
||||
* To refresh all rss feeds registered as contacts
|
||||
*/
|
||||
public void refreshRssFeed()
|
||||
{
|
||||
Vector rssContactList = new Vector();
|
||||
rssContactList = opSetPersPresence.getContactListRoot().
|
||||
getRssURLList(rssContactList);
|
||||
Iterator rssContact = rssContactList.iterator();
|
||||
while(rssContact.hasNext())
|
||||
{
|
||||
submitRssQuery((ContactRssImpl)rssContact.next(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To refresh a specific rss feed specified as param
|
||||
*
|
||||
* @param rssURL the <tt>contact</tt> to be refreshed
|
||||
* @param newContact
|
||||
* @param aloneUpdate
|
||||
*/
|
||||
public void refreshRssFeed( ContactRssImpl rssURL,
|
||||
boolean newContact,
|
||||
boolean aloneUpdate)
|
||||
{
|
||||
submitRssQuery(rssURL, newContact, aloneUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creating the timer permitting the refresh of rss feeds
|
||||
*/
|
||||
public void createTimer()
|
||||
{
|
||||
RssTimerRefreshFeed refresh = new RssTimerRefreshFeed(this);
|
||||
this.timer = new Timer();
|
||||
this.timer.scheduleAtFixedRate(refresh, 0, PERIOD_REFRESH_RSS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the timer if the user switch to the OFFLINE status
|
||||
*/
|
||||
public void stopTimer(){
|
||||
this.timer.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the feeds for a new Rss Feed just added as persistent contact
|
||||
*
|
||||
* @param contact the <tt>Contact</tt> added
|
||||
*/
|
||||
public void newContact(ContactRssImpl contact)
|
||||
{
|
||||
RssThread rssThr = new RssThread(this,contact, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the <tt>message</tt> to the destination indicated by the
|
||||
* <tt>to</tt> contact.
|
||||
*
|
||||
* @param to the <tt>Contact</tt> to send <tt>message</tt> to
|
||||
* @param message the <tt>Message</tt> to send.
|
||||
* @throws IllegalStateException if the underlying ICQ stack is not
|
||||
* registered and initialized.
|
||||
* @throws IllegalArgumentException if <tt>to</tt> is not an instance
|
||||
* belonging to the underlying implementation.
|
||||
*/
|
||||
public void sendInstantMessage(Contact to, Message message)
|
||||
throws IllegalStateException,
|
||||
IllegalArgumentException
|
||||
{
|
||||
if( !(to instanceof ContactRssImpl) )
|
||||
throw new IllegalArgumentException(
|
||||
"The specified contact is not a Rss contact."
|
||||
+ to);
|
||||
|
||||
MessageDeliveredEvent msgDeliveredEvt
|
||||
= new MessageDeliveredEvent(message, to, new Date());
|
||||
|
||||
//refresh the present rssFeed "to"
|
||||
fireMessageDelivered(message,to);
|
||||
RssThread rssThr = new RssThread(this, (ContactRssImpl)to, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* In case the to the <tt>to</tt> Contact corresponds to another rss
|
||||
* protocol provider registered with SIP Communicator, we deliver
|
||||
* the message to them, in case the <tt>to</tt> Contact represents us, we
|
||||
* fire a <tt>MessageReceivedEvent</tt>, and if <tt>to</tt> is simply
|
||||
* a contact in our contact list, then we simply echo the message.
|
||||
*
|
||||
* @param message the <tt>Message</tt> the message to deliver.
|
||||
* @param to the <tt>Contact</tt> that we should deliver the message to.
|
||||
*/
|
||||
private void deliverMessage(Message message, ContactRssImpl to)
|
||||
{
|
||||
String userID = to.getAddress();
|
||||
|
||||
//if the user id is owr own id, then this message is being routed to us
|
||||
//from another instance of the rss provider.
|
||||
if (userID.equals(this.parentProvider.getAccountID().getUserID()))
|
||||
{
|
||||
//check who is the provider sending the message
|
||||
String sourceUserID
|
||||
= to.getProtocolProvider().getAccountID().getUserID();
|
||||
|
||||
//check whether they are in our contact list
|
||||
Contact from = opSetPersPresence.findContactByID(sourceUserID);
|
||||
|
||||
|
||||
//and if not - add them there as volatile.
|
||||
if(from == null)
|
||||
{
|
||||
from = opSetPersPresence.createVolatileContact(sourceUserID);
|
||||
}
|
||||
|
||||
//and now fire the message received event.
|
||||
fireMessageReceived(message, from);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if userID is not our own, try an check whether another provider
|
||||
//has that id and if yes - deliver the message to them.
|
||||
ProtocolProviderServiceRssImpl rssProvider
|
||||
= this.opSetPersPresence.findProviderForRssUserID(userID);
|
||||
if(rssProvider != null)
|
||||
{
|
||||
OperationSetBasicInstantMessagingRssImpl opSetIM
|
||||
= (OperationSetBasicInstantMessagingRssImpl)
|
||||
rssProvider.getOperationSet(
|
||||
OperationSetBasicInstantMessaging.class);
|
||||
opSetIM.deliverMessage(message, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we got here then "to" is simply someone in our contact
|
||||
//list so let's just echo the message.
|
||||
fireMessageReceived(message, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered message listeners that a message has been
|
||||
* delivered successfully to its addressee..
|
||||
*
|
||||
* @param message the <tt>Message</tt> that has been delivered.
|
||||
* @param to the <tt>Contact</tt> that <tt>message</tt> was delivered to.
|
||||
*/
|
||||
private void fireMessageDelivered(Message message, Contact to)
|
||||
{
|
||||
MessageDeliveredEvent evt
|
||||
= new MessageDeliveredEvent(message, to, new Date());
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
listener.messageDelivered(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered message listeners that a message has been
|
||||
* received.
|
||||
*
|
||||
* @param message the <tt>Message</tt> that has been received.
|
||||
* @param from the <tt>Contact</tt> that <tt>message</tt> was received from.
|
||||
*/
|
||||
private void fireMessageReceived(Message message, Contact from)
|
||||
{
|
||||
MessageReceivedEvent evt
|
||||
= new MessageReceivedEvent(message, from, new Date());
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (messageListeners)
|
||||
{
|
||||
listeners = new ArrayList(messageListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
MessageListener listener
|
||||
= (MessageListener) listeners.next();
|
||||
|
||||
listener.messageReceived(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines wheter the protocol provider (or the protocol itself) support
|
||||
* sending and receiving offline messages. Most often this method would
|
||||
* return true for protocols that support offline messages and false for
|
||||
* those that don't. It is however possible for a protocol to support these
|
||||
* messages and yet have a particular account that does not (i.e. feature
|
||||
* not enabled on the protocol server). In cases like this it is possible
|
||||
* for this method to return true even when offline messaging is not
|
||||
* supported, and then have the sendMessage method throw an
|
||||
* OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
|
||||
*
|
||||
* @return <tt>true</tt> if the protocol supports offline messages and
|
||||
* <tt>false</tt> otherwise.
|
||||
*/
|
||||
public boolean isOfflineMessagingSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public ProtocolProviderServiceRssImpl getParentProvider(){
|
||||
return this.parentProvider;
|
||||
}
|
||||
|
||||
public OperationSetPersistentPresenceRssImpl getOpSetPersPresence(){
|
||||
return this.opSetPersPresence;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Implements typing notifications for the Rss protocol. The operation
|
||||
* set would simply mirror all outgoing typing notifications and make them
|
||||
* appear as incoming events generated by the contact that we are currently
|
||||
* writing a message to.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class OperationSetTypingNotificationsRssImpl
|
||||
implements OperationSetTypingNotifications
|
||||
{
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(OperationSetTypingNotificationsRssImpl.class);
|
||||
|
||||
/**
|
||||
* All currently registered TN listeners.
|
||||
*/
|
||||
private List typingNotificationsListeners = new ArrayList();
|
||||
|
||||
/**
|
||||
* The provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceRssImpl parentProvider = null;
|
||||
|
||||
/**
|
||||
* The currently valid persistent presence operation set..
|
||||
*/
|
||||
private OperationSetPersistentPresenceRssImpl opSetPersPresence = null;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of this operation set and keeps the parent
|
||||
* provider as a reference.
|
||||
*
|
||||
* @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
|
||||
* that created us and that we'll use for retrieving the underlying aim
|
||||
* connection.
|
||||
* @param opSetPersPresence the currently valid
|
||||
* <tt>OperationSetPersistentPresenceRssImpl</tt> instance.
|
||||
*/
|
||||
OperationSetTypingNotificationsRssImpl(
|
||||
ProtocolProviderServiceRssImpl provider,
|
||||
OperationSetPersistentPresenceRssImpl opSetPersPresence)
|
||||
{
|
||||
this.parentProvider = provider;
|
||||
this.opSetPersPresence = opSetPersPresence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>listener</tt> to the list of listeners registered for receiving
|
||||
* <tt>TypingNotificationEvent</tt>s
|
||||
*
|
||||
* @param listener the <tt>TypingNotificationsListener</tt> listener that
|
||||
* we'd like to add to the list of listeneres registered for receiving
|
||||
* typing notificaions.
|
||||
*/
|
||||
public void addTypingNotificationsListener(
|
||||
TypingNotificationsListener listener)
|
||||
{
|
||||
synchronized(typingNotificationsListeners)
|
||||
{
|
||||
typingNotificationsListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes <tt>listener</tt> from the list of listeners registered for
|
||||
* receiving <tt>TypingNotificationEvent</tt>s
|
||||
*
|
||||
* @param listener the <tt>TypingNotificationsListener</tt> listener that
|
||||
* we'd like to remove
|
||||
*/
|
||||
public void removeTypingNotificationsListener(
|
||||
TypingNotificationsListener listener)
|
||||
{
|
||||
synchronized(typingNotificationsListeners)
|
||||
{
|
||||
typingNotificationsListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers a <tt>TypingNotificationEvent</tt> to all registered listeners.
|
||||
* @param sourceContact the contact who has sent the notification.
|
||||
* @param evtCode the code of the event to deliver.
|
||||
*/
|
||||
private void fireTypingNotificationsEvent(Contact sourceContact
|
||||
,int evtCode)
|
||||
{
|
||||
logger.debug("Dispatching a TypingNotif. event to "
|
||||
+ typingNotificationsListeners.size()+" listeners. Contact "
|
||||
+ sourceContact.getAddress() + " has now a typing status of "
|
||||
+ evtCode);
|
||||
|
||||
TypingNotificationEvent evt = new TypingNotificationEvent(
|
||||
sourceContact, evtCode);
|
||||
|
||||
Iterator listeners = null;
|
||||
synchronized (typingNotificationsListeners)
|
||||
{
|
||||
listeners = new ArrayList(typingNotificationsListeners).iterator();
|
||||
}
|
||||
|
||||
while (listeners.hasNext())
|
||||
{
|
||||
TypingNotificationsListener listener
|
||||
= (TypingNotificationsListener) listeners.next();
|
||||
|
||||
listener.typingNotificationReceifed(evt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a notification to <tt>notifiedContatct</tt> that we have entered
|
||||
* <tt>typingState</tt>.
|
||||
*
|
||||
* @param notifiedContact the <tt>Contact</tt> to notify
|
||||
* @param typingState the typing state that we have entered.
|
||||
*
|
||||
* @throws java.lang.IllegalStateException if the underlying stack is
|
||||
* not registered and initialized.
|
||||
* @throws java.lang.IllegalArgumentException if <tt>notifiedContact</tt> is
|
||||
* not an instance belonging to the underlying implementation.
|
||||
*/
|
||||
public void sendTypingNotification(Contact notifiedContact, int typingState)
|
||||
throws IllegalStateException, IllegalArgumentException
|
||||
{
|
||||
if( !(notifiedContact instanceof ContactRssImpl) )
|
||||
throw new IllegalArgumentException(
|
||||
"The specified contact is not a Rss contact."
|
||||
+ notifiedContact);
|
||||
|
||||
|
||||
String userID = notifiedContact.getAddress();
|
||||
|
||||
//if the user id is owr own id, then this message is being routed to us
|
||||
//from another instance of the rss provider.
|
||||
if (userID.equals(this.parentProvider.getAccountID().getUserID()))
|
||||
{
|
||||
//check who is the provider sending the message
|
||||
String sourceUserID = notifiedContact.getProtocolProvider()
|
||||
.getAccountID().getUserID();
|
||||
|
||||
//check whether they are in our contact list
|
||||
Contact from = opSetPersPresence.findContactByID(sourceUserID);
|
||||
|
||||
//and if not - add them there as volatile.
|
||||
if (from == null)
|
||||
{
|
||||
from = opSetPersPresence.createVolatileContact(sourceUserID);
|
||||
}
|
||||
|
||||
//and now fire the message received event.
|
||||
fireTypingNotificationsEvent(from, typingState);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if userID is not our own, try a check whether another provider
|
||||
//has that id and if yes - deliver the message to them.
|
||||
ProtocolProviderServiceRssImpl rssProvider
|
||||
= this.opSetPersPresence.findProviderForRssUserID(userID);
|
||||
if (rssProvider != null)
|
||||
{
|
||||
OperationSetTypingNotificationsRssImpl opSetTN
|
||||
= (OperationSetTypingNotificationsRssImpl)
|
||||
rssProvider.getOperationSet(
|
||||
OperationSetTypingNotifications.class);
|
||||
opSetTN.sendTypingNotification(notifiedContact, typingState);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we got here then "to" is simply someone in our contact
|
||||
//list so let's just echo the message.
|
||||
fireTypingNotificationsEvent(notifiedContact, typingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.stream.*;
|
||||
|
||||
import net.java.sip.communicator.impl.gui.utils.*;
|
||||
import net.java.sip.communicator.impl.gui.utils.ImageLoader.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Reperesents the Rss protocol icon. Implements the <tt>ProtocolIcon</tt>
|
||||
* interface in order to provide a rss logo image in two different sizes.
|
||||
*
|
||||
* @author Yana Stamcheva
|
||||
*/
|
||||
public class ProtocolIconRssImpl
|
||||
implements ProtocolIcon
|
||||
{
|
||||
private static Logger logger
|
||||
= Logger.getLogger(ProtocolIconRssImpl.class);
|
||||
|
||||
/**
|
||||
* A hash table containing the protocol icon in different sizes.
|
||||
*/
|
||||
private static Hashtable iconsTable = new Hashtable();
|
||||
static
|
||||
{
|
||||
iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
|
||||
loadIcon("resources/images/rss/rss-online.png"));
|
||||
|
||||
iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
|
||||
loadIcon("resources/images/rss/rss64x64.png"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
|
||||
* an iterator to a set containing the supported icon sizes.
|
||||
* @return an iterator to a set containing the supported icon sizes
|
||||
*/
|
||||
public Iterator getSupportedSizes()
|
||||
{
|
||||
return iconsTable.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returne TRUE if a icon with the given size is supported, FALSE-otherwise.
|
||||
*/
|
||||
public boolean isSizeSupported(String iconSize)
|
||||
{
|
||||
return iconsTable.containsKey(iconSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon image in the given size.
|
||||
* @param iconSize the icon size; one of ICON_SIZE_XXX constants
|
||||
*/
|
||||
public byte[] getIcon(String iconSize)
|
||||
{
|
||||
return (byte[])iconsTable.get(iconSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon image used to represent the protocol connecting state.
|
||||
* @return the icon image used to represent the protocol connecting state
|
||||
*/
|
||||
public byte[] getConnectingIcon()
|
||||
{
|
||||
return loadIcon("resources/images/rss/rss-online.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image from a given image path.
|
||||
* @param imagePath The identifier of the image.
|
||||
* @return The image for the given identifier.
|
||||
*/
|
||||
public static byte[] loadIcon(String imagePath)
|
||||
{
|
||||
InputStream is = ProtocolIconRssImpl.class
|
||||
.getClassLoader().getResourceAsStream(imagePath);
|
||||
|
||||
byte[] icon = null;
|
||||
try {
|
||||
icon = new byte[is.available()];
|
||||
is.read(icon);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to load icon: " + imagePath, e);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* The Rss protocol provider factory creates instances of the Rss
|
||||
* protocol provider service. One Service instance corresponds to one account.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class ProtocolProviderFactoryRssImpl
|
||||
extends ProtocolProviderFactory
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ProtocolProviderFactoryRssImpl.class);
|
||||
|
||||
/**
|
||||
* The table that we store our accounts in.
|
||||
*/
|
||||
private Hashtable registeredAccounts = new Hashtable();
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance of the ProtocolProviderFactoryRssImpl.
|
||||
*/
|
||||
public ProtocolProviderFactoryRssImpl()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ServiceReference for the protocol provider corresponding
|
||||
* to the specified accountID or null if the accountID is unknown.
|
||||
*
|
||||
* @param accountID the accountID of the protocol provider we'd like to
|
||||
* get
|
||||
* @return a ServiceReference object to the protocol provider with the
|
||||
* specified account id and null if the account id is unknwon to the
|
||||
* provider factory.
|
||||
*/
|
||||
public ServiceReference getProviderForAccount(AccountID accountID)
|
||||
{
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.get(accountID);
|
||||
|
||||
return (registration == null )
|
||||
? null
|
||||
: registration.getReference();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the list containing the <tt>AccoudID</tt>s of all
|
||||
* accounts currently registered in this protocol provider.
|
||||
*
|
||||
* @return a copy of the list containing the <tt>AccoudID</tt>s of all
|
||||
* accounts currently registered in this protocol provider.
|
||||
*/
|
||||
public ArrayList getRegisteredAccounts()
|
||||
{
|
||||
return new ArrayList(registeredAccounts.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads (and hence installs) all accounts previously stored in the
|
||||
* configuration service.
|
||||
*/
|
||||
public void loadStoredAccounts()
|
||||
{
|
||||
super.loadStoredAccounts( RssActivator.getBundleContext());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializaed and creates an account corresponding to the specified
|
||||
* accountProperties and registers the resulting ProtocolProvider in the
|
||||
* <tt>context</tt> BundleContext parameter.
|
||||
*
|
||||
* @param userIDStr tha/a user identifier uniquely representing the newly
|
||||
* created account within the protocol namespace.
|
||||
* @param accountProperties a set of protocol (or implementation)
|
||||
* specific properties defining the new account.
|
||||
* @return the AccountID of the newly created account.
|
||||
*/
|
||||
public AccountID installAccount( String userIDStr,
|
||||
Map accountProperties)
|
||||
{
|
||||
BundleContext context
|
||||
= RssActivator.getBundleContext();
|
||||
if (context == null)
|
||||
throw new NullPointerException("The specified BundleContext was null");
|
||||
|
||||
if (userIDStr == null)
|
||||
throw new NullPointerException("The specified AccountID was null");
|
||||
|
||||
if (accountProperties == null)
|
||||
throw new NullPointerException("The specified property map was null");
|
||||
|
||||
accountProperties.put(USER_ID, userIDStr);
|
||||
|
||||
AccountID accountID = new RssAccountID(userIDStr, accountProperties);
|
||||
|
||||
//make sure we haven't seen this account id before.
|
||||
if (registeredAccounts.containsKey(accountID))
|
||||
throw new IllegalStateException(
|
||||
"An account for id " + userIDStr + " was already installed!");
|
||||
|
||||
//first store the account and only then load it as the load generates
|
||||
//an osgi event, the osgi event triggers (through the UI) a call to the
|
||||
//ProtocolProviderService.register() method and it needs to acces
|
||||
//the configuration service and check for a stored password.
|
||||
this.storeAccount(
|
||||
RssActivator.getBundleContext()
|
||||
, accountID);
|
||||
|
||||
accountID = loadAccount(accountProperties);
|
||||
|
||||
return accountID;
|
||||
}
|
||||
/**
|
||||
* Initializes and creates an account corresponding to the specified
|
||||
* accountProperties and registers the resulting ProtocolProvider in the
|
||||
* <tt>context</tt> BundleContext parameter.
|
||||
*
|
||||
* @param accountProperties a set of protocol (or implementation)
|
||||
* specific properties defining the new account.
|
||||
* @return the AccountID of the newly loaded account
|
||||
*/
|
||||
public AccountID loadAccount( Map accountProperties)
|
||||
{
|
||||
BundleContext context
|
||||
= RssActivator.getBundleContext();
|
||||
if(context == null)
|
||||
throw new NullPointerException("The specified BundleContext was null");
|
||||
|
||||
String userIDStr = (String)accountProperties.get(USER_ID);
|
||||
|
||||
AccountID accountID = new RssAccountID(userIDStr, accountProperties);
|
||||
|
||||
//get a reference to the configuration service and register whatever
|
||||
//properties we have in it.
|
||||
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put(PROTOCOL, "Rss");
|
||||
properties.put(USER_ID, userIDStr);
|
||||
|
||||
ProtocolProviderServiceRssImpl rssProtocolProvider
|
||||
= new ProtocolProviderServiceRssImpl();
|
||||
|
||||
rssProtocolProvider.initialize(userIDStr, accountID);
|
||||
|
||||
ServiceRegistration registration
|
||||
= context.registerService( ProtocolProviderService.class.getName(),
|
||||
rssProtocolProvider,
|
||||
properties);
|
||||
|
||||
registeredAccounts.put(accountID, registration);
|
||||
return accountID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified account from the list of accounts that this
|
||||
* provider factory is handling.
|
||||
*
|
||||
* @param accountID the ID of the account to remove.
|
||||
* @return true if an account with the specified ID existed and was
|
||||
* removed and false otherwise.
|
||||
*/
|
||||
public boolean uninstallAccount(AccountID accountID)
|
||||
{
|
||||
//unregister the protocol provider
|
||||
ServiceReference serRef = getProviderForAccount(accountID);
|
||||
|
||||
ProtocolProviderService protocolProvider
|
||||
= (ProtocolProviderService) RssActivator.getBundleContext()
|
||||
.getService(serRef);
|
||||
|
||||
try
|
||||
{
|
||||
protocolProvider.unregister();
|
||||
}
|
||||
catch (OperationFailedException exc)
|
||||
{
|
||||
logger.error("Failed to unregister protocol provider for account : "
|
||||
+ accountID + " caused by : " + exc);
|
||||
}
|
||||
|
||||
ServiceRegistration registration
|
||||
= (ServiceRegistration)registeredAccounts.remove(accountID);
|
||||
|
||||
if(registration == null)
|
||||
return false;
|
||||
|
||||
//kill the service
|
||||
registration.unregister();
|
||||
|
||||
registeredAccounts.remove(accountID);
|
||||
|
||||
return removeStoredAccount(RssActivator.getBundleContext(), accountID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the password for the specified account after scrambling it a bit
|
||||
* so that it is not visible from first sight (Method remains highly
|
||||
* insecure).
|
||||
*
|
||||
* @param accountID the AccountID for the account whose password we're
|
||||
* storing.
|
||||
* @param passwd the password itself.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if no account corresponding
|
||||
* to <tt>accountID</tt> has been previously stored.
|
||||
*/
|
||||
public void storePassword(AccountID accountID, String passwd)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super.storePassword(RssActivator.getBundleContext(),
|
||||
accountID,
|
||||
passwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password last saved for the specified account.
|
||||
*
|
||||
* @param accountID the AccountID for the account whose password we're
|
||||
* looking for..
|
||||
*
|
||||
* @return a String containing the password for the specified accountID.
|
||||
*
|
||||
* @throws java.lang.IllegalArgumentException if no account corresponding
|
||||
* to <tt>accountID</tt> has been previously stored.
|
||||
*/
|
||||
public String loadPassword(AccountID accountID)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
return super.loadPassword(RssActivator.getBundleContext(), accountID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the factory for bundle shutdown.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
Enumeration registrations = this.registeredAccounts.elements();
|
||||
|
||||
while(registrations.hasMoreElements())
|
||||
{
|
||||
ServiceRegistration reg
|
||||
= ((ServiceRegistration)registrations.nextElement());
|
||||
|
||||
reg.unregister();
|
||||
}
|
||||
|
||||
Enumeration idEnum = registeredAccounts.keys();
|
||||
|
||||
while(idEnum.hasMoreElements())
|
||||
{
|
||||
registeredAccounts.remove(idEnum.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
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 Rss implementation of the ProtocolProviderService.
|
||||
*
|
||||
* @author Emil Ivov/Jean-Albert Vescovo
|
||||
*/
|
||||
public class ProtocolProviderServiceRssImpl
|
||||
implements ProtocolProviderService
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ProtocolProviderServiceRssImpl.class);
|
||||
|
||||
/**
|
||||
* The name of this protocol.
|
||||
*/
|
||||
public static final String RSS_PROTOCOL_NAME = "Rss";
|
||||
|
||||
/**
|
||||
* 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 logo corresponding to the rss protocol.
|
||||
*/
|
||||
private ProtocolIconRssImpl rssIcon
|
||||
= new ProtocolIconRssImpl();
|
||||
|
||||
/**
|
||||
* A reference to the IM operation set
|
||||
*/
|
||||
private OperationSetBasicInstantMessagingRssImpl basicInstantMessaging;
|
||||
|
||||
private boolean start = 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 Rss protocol provider.
|
||||
*/
|
||||
public ProtocolProviderServiceRssImpl()
|
||||
{
|
||||
logger.trace("Creating a rss provider.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the service implementation, and puts it in a state where it
|
||||
* could interoperate with other services. It is strongly recomended that
|
||||
* properties in this Map be mapped to property names as specified by
|
||||
* <tt>AccountProperties</tt>.
|
||||
*
|
||||
* @param userID the user id of the rss 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
|
||||
OperationSetPersistentPresenceRssImpl persistentPresence =
|
||||
new OperationSetPersistentPresenceRssImpl(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
|
||||
//OperationSetBasicInstantMessagingRssImpl
|
||||
basicInstantMessaging
|
||||
= new OperationSetBasicInstantMessagingRssImpl(
|
||||
this
|
||||
, (OperationSetPersistentPresenceRssImpl)
|
||||
persistentPresence);
|
||||
|
||||
supportedOperationSets.put(
|
||||
OperationSetBasicInstantMessaging.class.getName(),
|
||||
basicInstantMessaging);
|
||||
|
||||
//initialize the typing notifications operation set
|
||||
OperationSetTypingNotifications typingNotifications =
|
||||
new OperationSetTypingNotificationsRssImpl(
|
||||
this, persistentPresence);
|
||||
|
||||
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 <tt>RegistrationStateChangeEvent</tt> 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);
|
||||
}
|
||||
|
||||
/* If Timer isn't started, we launch a new timer for sending periodic
|
||||
* rss feeds' refresh taks.
|
||||
* If yes, we stop it.
|
||||
*/
|
||||
if(!start){
|
||||
this.basicInstantMessaging.createTimer();
|
||||
start = true;
|
||||
}
|
||||
else{
|
||||
this.basicInstantMessaging.stopTimer();
|
||||
start = false;
|
||||
}
|
||||
|
||||
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 <tt>Class</tt> of the operation set that we're
|
||||
* looking for.
|
||||
* @return returns an OperationSet of the specified <tt>Class</tt> 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 RSS_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
|
||||
//Rss but nevertheless we'll behave as if we did.
|
||||
|
||||
//verify whether a password has already been stored for this account
|
||||
String password = RssActivator.
|
||||
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("Rss"
|
||||
, 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())
|
||||
{
|
||||
RssActivator.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 Rss 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rss protocol icon.
|
||||
* @return the rss protocol icon
|
||||
*/
|
||||
public ProtocolIcon getProtocolIcon()
|
||||
{
|
||||
return rssIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IM set
|
||||
* @return the IM set
|
||||
*/
|
||||
public OperationSetBasicInstantMessagingRssImpl getBasicInstantMessaging()
|
||||
{
|
||||
return this.basicInstantMessaging;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Rss implementation of a sip-communicator account id.
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class RssAccountID
|
||||
extends AccountID
|
||||
{
|
||||
/**
|
||||
* Creates an account id from the specified id and account properties.
|
||||
*
|
||||
* @param userID the user identifier correspnding to the account
|
||||
* @param accountProperties any other properties necessary for the account.
|
||||
*/
|
||||
RssAccountID(String userID, Map accountProperties)
|
||||
{
|
||||
super( userID,
|
||||
accountProperties,
|
||||
"Rss",
|
||||
"rss.org");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
import net.java.sip.communicator.impl.gui.*;
|
||||
/**
|
||||
* Loads the Rss provider factory and registers its services in the OSGI
|
||||
* bundle context.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class RssActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(RssActivator.class);
|
||||
|
||||
/**
|
||||
* A reference to the registration of our Rss protocol provider
|
||||
* factory.
|
||||
*/
|
||||
private ServiceRegistration rssPpFactoryServReg = null;
|
||||
|
||||
/**
|
||||
* A reference to the Rss protocol provider factory.
|
||||
*/
|
||||
private static ProtocolProviderFactoryRssImpl
|
||||
rssProviderFactory = null;
|
||||
|
||||
/**
|
||||
* The currently valid bundle context.
|
||||
*/
|
||||
private static BundleContext bundleContext = null;
|
||||
|
||||
|
||||
/**
|
||||
* Called when this bundle is started. In here we'll export the
|
||||
* rss ProtocolProviderFactory implementation so that it could be
|
||||
* possible to register accounts with it in SIP Communicator.
|
||||
*
|
||||
* @param context The execution context of the bundle being started.
|
||||
* @throws Exception If this method throws an exception, this bundle is
|
||||
* marked as stopped and the Framework will remove this bundle's
|
||||
* listeners, unregister all services registered by this bundle, and
|
||||
* release all services used by this bundle.
|
||||
*/
|
||||
public void start(BundleContext context)
|
||||
throws Exception
|
||||
{
|
||||
this.bundleContext = context;
|
||||
|
||||
Hashtable hashtable = new Hashtable();
|
||||
hashtable.put(ProtocolProviderFactory.PROTOCOL, "Rss");
|
||||
|
||||
rssProviderFactory = new ProtocolProviderFactoryRssImpl();
|
||||
|
||||
//load all stored Rss accounts.
|
||||
rssProviderFactory.loadStoredAccounts();
|
||||
|
||||
//reg the rss provider factory.
|
||||
rssPpFactoryServReg = context.registerService(
|
||||
ProtocolProviderFactory.class.getName(),
|
||||
rssProviderFactory,
|
||||
hashtable);
|
||||
|
||||
logger.info("Rss protocol implementation [STARTED].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the bundle context that we were started with.
|
||||
* @return a reference to the BundleContext instance that we were started
|
||||
* witn.
|
||||
*/
|
||||
public static BundleContext getBundleContext()
|
||||
{
|
||||
return bundleContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrurns a reference to the protocol provider factory that we have
|
||||
* registered.
|
||||
* @return a reference to the <tt>ProtocolProviderFactoryJabberImpl</tt>
|
||||
* instance that we have registered from this package.
|
||||
*/
|
||||
public static ProtocolProviderFactoryRssImpl getProtocolProviderFactory()
|
||||
{
|
||||
return rssProviderFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being stopped.
|
||||
* @throws Exception If this method throws an exception, the bundle is
|
||||
* still marked as stopped, and the Framework will remove the bundle's
|
||||
* listeners, unregister all services registered by the bundle, and
|
||||
* release all services used by the bundle.
|
||||
*/
|
||||
public void stop(BundleContext context)
|
||||
throws Exception
|
||||
{
|
||||
this.rssProviderFactory.stop();
|
||||
rssPpFactoryServReg.unregister();
|
||||
logger.info("Rss protocol implementation [STOPPED].");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.syndication.feed.synd.*;
|
||||
import com.sun.syndication.io.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
|
||||
/**
|
||||
* The class used for using the Informa Library into the RSS protocol
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
public class RssFeedReader
|
||||
{
|
||||
|
||||
/**
|
||||
* The id of the contact/feed, used to make a tcp query toward
|
||||
* the .xml file containing the items of the feed.
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* The title of the feed, which will be used as the displayname
|
||||
* of the contact/feed.
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* The object charged to retrieve the feed incoming from the relavant server.
|
||||
*/
|
||||
private SyndFeed feed;
|
||||
|
||||
/**
|
||||
* The last update date of this feed.
|
||||
*/
|
||||
private Date ultimateItemDate = null;
|
||||
|
||||
/**
|
||||
* An array of SyndEntry which will contain all the items retrieved from the feed.
|
||||
*/
|
||||
private SyndEntry[] items;
|
||||
|
||||
/**
|
||||
* Creates an instance of a rss feed with the specified string used
|
||||
* as an url to contact the relevant server.
|
||||
*
|
||||
* @param address the url of this feed.
|
||||
*/
|
||||
public RssFeedReader(String address)
|
||||
{
|
||||
this.address = address;
|
||||
this.feed = null;
|
||||
this.title = "No feed avalaible !";
|
||||
}
|
||||
|
||||
/**
|
||||
* To refresh this rss contact/feed registered as contact
|
||||
* Moreover, we sort the items by reverse chronological order after
|
||||
* insert them into an Array
|
||||
*/
|
||||
public void recupFlux()
|
||||
{
|
||||
try
|
||||
{
|
||||
URL rssURL = new URL(this.address);
|
||||
|
||||
//the most important thing in this protocol: we parse the rss feed
|
||||
//using the Rome library
|
||||
SyndFeedInput input = new SyndFeedInput();
|
||||
this.feed = input.build(new XmlReader(rssURL));
|
||||
this.title = this.feed.getTitle();
|
||||
|
||||
//we retrieve the items and sort them by reverse chronological order
|
||||
items = (SyndEntry[])(this.feed.getEntries().toArray(new SyndEntry[0]));
|
||||
sortItems();
|
||||
|
||||
//we retrieve the date of the most recent item
|
||||
this.ultimateItemDate = findUltimateItemDate();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
System.out.println("ERROR: "+ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String containing the message to send to the user after
|
||||
* a successful query on a rss server:
|
||||
*
|
||||
* - if we have no items, we return "No items found on this feed !"
|
||||
* - if we can't read a date in these items, we return the last 10 items of the feed
|
||||
* - if we can read a date, we just return the items which have a date earlier than
|
||||
* the lastQueryDate, and "No new articles in your feed since last update." if it isn't
|
||||
* new item since lastQueryDate.
|
||||
*
|
||||
* We signal to the user ("Send anything to refresh this feed...") that he can send anything
|
||||
* to refresh the present contact/feed.
|
||||
*
|
||||
* @param lastQueryDate the date to compare with that of the items retrieved.
|
||||
* @return String string
|
||||
*/
|
||||
public String getPrintedFeed(Date lastQueryDate)
|
||||
{
|
||||
boolean more = true;
|
||||
int i=0,nbNewItem = 0;
|
||||
String printedFeed = new String();
|
||||
|
||||
if(items.length > 0)
|
||||
{
|
||||
while((i<items.length)&&more)
|
||||
{
|
||||
if((items[i].getPublishedDate() != null) && (lastQueryDate != null))
|
||||
{
|
||||
if(items[i].getPublishedDate().compareTo(lastQueryDate)>0)
|
||||
{
|
||||
printedFeed += "\nAt " + items[i].getPublishedDate()+" - " +
|
||||
items[i].getTitle() +
|
||||
"\nLink: " + items[i].getLink() + "\n\n";
|
||||
nbNewItem++;
|
||||
}
|
||||
else{
|
||||
more = false;
|
||||
if(nbNewItem == 0) printedFeed +=
|
||||
"\n\nNo new articles in your feed since last update.";
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(items[i].getPublishedDate() != null)
|
||||
printedFeed += "\nAt " + items[i].getPublishedDate();
|
||||
|
||||
printedFeed += "\n" + items[i].getTitle() +
|
||||
"\nLink: "+items[i].getLink()+"\n\n";
|
||||
|
||||
if(i == 10) more = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
printedFeed += ("\n\nSend anything to refresh this feed...");
|
||||
}
|
||||
else
|
||||
{
|
||||
printedFeed += "No items found on this feed !";
|
||||
}
|
||||
return printedFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* To sort the items retrieved from the rss contact/feed registered as contact
|
||||
* We use for that a bubble sort algorithm
|
||||
*/
|
||||
public void sortItems()
|
||||
{
|
||||
int i;
|
||||
int size = items.length;
|
||||
SyndEntry temp;
|
||||
boolean inversion;
|
||||
do
|
||||
{
|
||||
inversion=false;
|
||||
for(i = 0; i < size - 1; i++)
|
||||
{
|
||||
if((items[i].getPublishedDate() != null) && (items[i+1].getPublishedDate()!=null))
|
||||
if(items[i].getPublishedDate().compareTo(items[i+1].getPublishedDate())<0)
|
||||
{
|
||||
temp = items[i];
|
||||
items[i] = items[i+1];
|
||||
items[i+1] = temp;
|
||||
inversion=true;
|
||||
}
|
||||
}
|
||||
size--;
|
||||
}while(inversion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Date that can be used to know the most recent item in a retrieved feed.
|
||||
*
|
||||
* @return the feed's Date representing the nearest item's date never retrieved on this feed.
|
||||
*/
|
||||
public Date getUltimateItemDate()
|
||||
{
|
||||
return this.ultimateItemDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Date that can be used to know the most recent item in a retrieved feed.
|
||||
*
|
||||
* This method just gives the date of the first element of the array of ItemIF previously
|
||||
* sorted.
|
||||
*
|
||||
* @return a Date representing the nearest item's date.
|
||||
*/
|
||||
private Date findUltimateItemDate()
|
||||
{
|
||||
if(items[0].getPublishedDate() != null)
|
||||
this.ultimateItemDate = items[0].getPublishedDate();
|
||||
return this.ultimateItemDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ChannelIF that can be used to know if a feed exists indeed.
|
||||
*
|
||||
* @return a ChannelIF containing the result of a query on a rss server.
|
||||
*/
|
||||
public SyndFeed getFeed()
|
||||
{
|
||||
return this.feed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Date giving the publication date of the feed on the relevant server.
|
||||
*
|
||||
* In most case, this date doesn't exist on the server. Not used at this time in this
|
||||
* implementation.
|
||||
*
|
||||
* @return a Date representing the publication date of the feed.
|
||||
*/
|
||||
public Date getPubDate()
|
||||
{
|
||||
return this.feed.getPublishedDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String used as a displayname.
|
||||
*
|
||||
* @return a String title representing the feed/contact.
|
||||
*/
|
||||
public String getTitle()
|
||||
{
|
||||
return this.title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String that can be used for identifying the contact.
|
||||
*
|
||||
* We'll prefer to use the title of the feed as displayname.
|
||||
*
|
||||
* @return a String id representing and uniquely identifying the contact.
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
return this.address;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An implementation of <tt>PresenceStatus</tt> that enumerates all states that
|
||||
* a Rss contact can fall into.
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
public class RssStatusEnum
|
||||
extends PresenceStatus
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(RssStatusEnum.class);
|
||||
|
||||
/**
|
||||
* Indicates an Offline status or status with 0 connectivity.
|
||||
*/
|
||||
public static final RssStatusEnum OFFLINE
|
||||
= new RssStatusEnum(
|
||||
0
|
||||
, "Offline"
|
||||
, loadIcon("resources/images/rss/rss-offline.png"));
|
||||
|
||||
/**
|
||||
* The Online status. Indicate that the user is able and willing to
|
||||
* communicate.
|
||||
*/
|
||||
public static final RssStatusEnum ONLINE
|
||||
= new RssStatusEnum(
|
||||
65
|
||||
, "Online"
|
||||
, loadIcon("resources/images/rss/rss-online.png"));
|
||||
|
||||
/**
|
||||
* Initialize the list of supported status states.
|
||||
*/
|
||||
private static List supportedStatusSet = new LinkedList();
|
||||
static
|
||||
{
|
||||
supportedStatusSet.add(OFFLINE);
|
||||
supportedStatusSet.add(ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>RssPresneceStatus</tt> with the
|
||||
* specified parameters.
|
||||
* @param status the connectivity level of the new presence status instance
|
||||
* @param statusName the name of the presence status.
|
||||
* @param statusIcon the icon associated with this status
|
||||
*/
|
||||
private RssStatusEnum(int status,
|
||||
String statusName,
|
||||
byte[] statusIcon)
|
||||
{
|
||||
super(status, statusName, statusIcon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all status instances supproted by the rss
|
||||
* provider.
|
||||
* @return an <tt>Iterator</tt> over all status instances supported by the
|
||||
* rss provider.
|
||||
*/
|
||||
static Iterator supportedStatusSet()
|
||||
{
|
||||
return supportedStatusSet.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image from a given image path.
|
||||
* @param imagePath The path to the image resource.
|
||||
* @return The image extracted from the resource at the specified path.
|
||||
*/
|
||||
public static byte[] loadIcon(String imagePath)
|
||||
{
|
||||
InputStream is = RssStatusEnum.class.getClassLoader()
|
||||
.getResourceAsStream(imagePath);
|
||||
|
||||
byte[] icon = null;
|
||||
try
|
||||
{
|
||||
icon = new byte[is.available()];
|
||||
is.read(icon);
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
logger.error("Failed to load icon: " + imagePath, exc);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
|
||||
/**
|
||||
* Instant messaging functionalites for the Rss protocol.
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
public class RssThread
|
||||
extends Thread
|
||||
{
|
||||
private OperationSetBasicInstantMessagingRssImpl opSet;
|
||||
private ContactRssImpl rssFeed = null;
|
||||
private boolean newContact = false;
|
||||
private boolean aloneUpdate = false;
|
||||
|
||||
/** Creates a new instance of RssThread
|
||||
* @param opSet the OperationSetBasicInstantMessagingRssImpl instance that
|
||||
* is managing the rss protocol.
|
||||
*/
|
||||
public RssThread(OperationSetBasicInstantMessagingRssImpl opSet)
|
||||
{
|
||||
this.opSet = opSet;
|
||||
this.start();
|
||||
}
|
||||
|
||||
/** Creates a new instance of RssThread
|
||||
* @param opSet the OperationSetBasicInstantMessagingRssImpl instance that
|
||||
* is managing the rss protocol.
|
||||
* @param rssFeed the contact that the thread is going to do a query
|
||||
* @param newContact newContact
|
||||
* @param aloneUpdate aloneUpdate
|
||||
*/
|
||||
public RssThread(OperationSetBasicInstantMessagingRssImpl opSet,
|
||||
ContactRssImpl rssFeed,
|
||||
boolean newContact,
|
||||
boolean aloneUpdate)
|
||||
{
|
||||
this.opSet = opSet;
|
||||
this.rssFeed = rssFeed;
|
||||
this.newContact = newContact;
|
||||
this.aloneUpdate = aloneUpdate;
|
||||
this.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* The task executed by the thread
|
||||
* If no rss contact given as parameter, the query is launched for all contacts
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(this.rssFeed == null)
|
||||
this.opSet.refreshRssFeed();
|
||||
else
|
||||
this.opSet.refreshRssFeed(this.rssFeed,this.newContact,this.aloneUpdate);
|
||||
}
|
||||
catch(Exception exc)
|
||||
{
|
||||
exc.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.rss;
|
||||
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* Instant messaging functionalites for the Rss protocol.
|
||||
*
|
||||
* @author Jean-Albert Vescovo
|
||||
*/
|
||||
|
||||
public class RssTimerRefreshFeed
|
||||
extends TimerTask
|
||||
{
|
||||
private OperationSetBasicInstantMessagingRssImpl opSet;
|
||||
|
||||
/**
|
||||
* Creates an instance of timer used to seeking periodically the rss feeds registered
|
||||
* as contacts.
|
||||
* @param opSet the OperationSetBasicInstantMessagingRssImpl instance that
|
||||
* is managing the rss protocol.
|
||||
*/
|
||||
public RssTimerRefreshFeed(OperationSetBasicInstantMessagingRssImpl opSet)
|
||||
{
|
||||
this.opSet = opSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* What the timer is supposed to do each time the PERIOD_REFRESH_RSS expire.
|
||||
* In facts, it launch a new thread responsible for starting one or more rss queries
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
RssThread rssThr = new RssThread(this.opSet);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
Bundle-Activator: net.java.sip.communicator.impl.protocol.rss.RssActivator
|
||||
Bundle-Name: Rss Protocol Provider
|
||||
Bundle-Description: A bundle providing support for the Rss protocol.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
org.xml.sax,
|
||||
org.xml.sax.helpers,
|
||||
org.jdom,
|
||||
org.jdom.input,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.event
|
||||
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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.plugin.rssaccregwizz;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The <tt>FirstWizardPage</tt> is the page, where user could enter the user ID
|
||||
* and the password of the account.
|
||||
*
|
||||
* @author Emil Ivov/Jean-Albert Vescovo
|
||||
*/
|
||||
public class FirstWizardPage
|
||||
extends JPanel implements WizardPage, DocumentListener
|
||||
{
|
||||
|
||||
public static final String FIRST_PAGE_IDENTIFIER = "FirstPageIdentifier";
|
||||
|
||||
private JPanel userPassPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
private JPanel labelsPanel = new JPanel();
|
||||
|
||||
private JLabel existingAccountLabel =
|
||||
new JLabel("RSS account already exists !");
|
||||
|
||||
private JLabel creatingAccountLabel =
|
||||
new JLabel("Press next to creat your RSS account...");
|
||||
|
||||
private JTextField userIDField = new JTextField();
|
||||
|
||||
private JPanel mainPanel = new JPanel();
|
||||
|
||||
private Object nextPageIdentifier = WizardPage.SUMMARY_PAGE_IDENTIFIER;
|
||||
|
||||
private RssAccountRegistration registration = null;
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>FirstWizardPage</tt>.
|
||||
* @param registration the <tt>RssAccountRegistration</tt>, where
|
||||
* all data through the wizard are stored
|
||||
* @param wizardContainer the wizardContainer, where this page will
|
||||
* be added
|
||||
*/
|
||||
public FirstWizardPage(RssAccountRegistration registration,
|
||||
WizardContainer wizardContainer)
|
||||
{
|
||||
|
||||
super(new BorderLayout());
|
||||
|
||||
this.wizardContainer = wizardContainer;
|
||||
|
||||
this.registration = registration;
|
||||
|
||||
this.setPreferredSize(new Dimension(300, 150));
|
||||
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
this.init();
|
||||
|
||||
this.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
this.labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.Y_AXIS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all panels, buttons, etc.
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
this.userIDField.getDocument().addDocumentListener(this);
|
||||
|
||||
this.existingAccountLabel.setForeground(Color.RED);
|
||||
|
||||
this.creatingAccountLabel.setForeground(Color.BLUE);
|
||||
|
||||
labelsPanel.add(creatingAccountLabel);
|
||||
|
||||
if(!isExistingAccount("rss")){
|
||||
labelsPanel.remove(existingAccountLabel);
|
||||
labelsPanel.add(creatingAccountLabel);
|
||||
setNextButtonAccordingToUserID(true);
|
||||
}
|
||||
else{
|
||||
labelsPanel.remove(creatingAccountLabel);
|
||||
labelsPanel.add(existingAccountLabel);
|
||||
setNextButtonAccordingToUserID(false);
|
||||
}
|
||||
|
||||
userPassPanel.add(labelsPanel, BorderLayout.CENTER);
|
||||
|
||||
userPassPanel.setBorder(BorderFactory
|
||||
.createTitledBorder("RSS account creation..."));
|
||||
|
||||
this.add(userPassPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getIdentifier</code> to return
|
||||
* this page identifier.
|
||||
*
|
||||
* @return the Identifier of the first page in this wizard.
|
||||
*/
|
||||
public Object getIdentifier()
|
||||
{
|
||||
return FIRST_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getNextPageIdentifier</code> to return
|
||||
* the next page identifier - the summary page.
|
||||
*
|
||||
* @return the identifier of the page following this one.
|
||||
*/
|
||||
public Object getNextPageIdentifier()
|
||||
{
|
||||
return nextPageIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getBackPageIdentifier</code> to return
|
||||
* the next back identifier - the default page.
|
||||
*
|
||||
* @return the identifier of the default wizard page.
|
||||
*/
|
||||
public Object getBackPageIdentifier()
|
||||
{
|
||||
return WizardPage.DEFAULT_PAGE_IDENTIFIER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>WizardPage.getWizardForm</code> to return
|
||||
* this panel.
|
||||
*
|
||||
* @return the component to be displayed in this wizard page.
|
||||
*/
|
||||
public Object getWizardForm()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Before this page is displayed enables or disables the "Next" wizard
|
||||
* button according to whether the UserID field is empty.
|
||||
*/
|
||||
public void pageShowing()
|
||||
{
|
||||
if(isExistingAccount("Rss")) setNextButtonAccordingToUserID(false);
|
||||
else setNextButtonAccordingToUserID(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the user input when the "Next" wizard buttons is clicked.
|
||||
*/
|
||||
public void pageNext()
|
||||
{
|
||||
nextPageIdentifier = SUMMARY_PAGE_IDENTIFIER;
|
||||
userPassPanel.remove(existingAccountLabel);
|
||||
registration.setUserID("Rss");
|
||||
registration.setPassword("rss");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the "Next" wizard button according to whether the
|
||||
* User ID field is empty.
|
||||
*/
|
||||
private void setNextButtonAccordingToUserID(boolean newOne)
|
||||
{
|
||||
if(!newOne)
|
||||
{
|
||||
wizardContainer.setNextFinishButtonEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
wizardContainer.setNextFinishButtonEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user types in the
|
||||
* User ID field. Enables or disables the "Next" wizard button according to
|
||||
* whether the User ID field is empty.
|
||||
*
|
||||
* @param event the event containing the update.
|
||||
*/
|
||||
public void insertUpdate(DocumentEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the <tt>DocumentEvent</tt> triggered when user deletes letters
|
||||
* from the UserID field. Enables or disables the "Next" wizard button
|
||||
* according to whether the UserID field is empty.
|
||||
*
|
||||
* @param event the event containing the update.
|
||||
*/
|
||||
public void removeUpdate(DocumentEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
public void pageHiding()
|
||||
{
|
||||
}
|
||||
|
||||
public void pageShown()
|
||||
{
|
||||
}
|
||||
|
||||
public void pageBack()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the UserID and Password fields in this panel with the data comming
|
||||
* from the given protocolProvider.
|
||||
* @param protocolProvider The <tt>ProtocolProviderService</tt> to load the
|
||||
* data from.
|
||||
*/
|
||||
public void loadAccount(ProtocolProviderService protocolProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies whether there is already an account installed with the same
|
||||
* details as the one that the user has just entered.
|
||||
*
|
||||
* @param userID the name of the user that the account is registered for
|
||||
* @return true if there is already an account for this userID and false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean isExistingAccount(String userID)
|
||||
{
|
||||
ProtocolProviderFactory factory
|
||||
= RssAccRegWizzActivator.getRssProtocolProviderFactory();
|
||||
|
||||
ArrayList registeredAccounts = factory.getRegisteredAccounts();
|
||||
|
||||
for (int i = 0; i < registeredAccounts.size(); i++)
|
||||
{
|
||||
AccountID accountID = (AccountID) registeredAccounts.get(i);
|
||||
|
||||
if (userID.equalsIgnoreCase(accountID.getUserID()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.plugin.rssaccregwizz;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* The Messages class manages the access to the internationalization
|
||||
* properties files.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class Resources
|
||||
{
|
||||
|
||||
private static Logger log = Logger.getLogger(Resources.class);
|
||||
|
||||
private static final String BUNDLE_NAME
|
||||
= "net.java.sip.communicator.plugin.rssaccregwizz.resources";
|
||||
|
||||
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
|
||||
.getBundle(BUNDLE_NAME);
|
||||
|
||||
public static ImageID GIBBERISH_LOGO = new ImageID("protocolIcon");
|
||||
|
||||
public static ImageID PAGE_IMAGE = new ImageID("pageImage");
|
||||
|
||||
/**
|
||||
* Returns an internationalized string corresponding to the given key.
|
||||
* @param key The key of the string.
|
||||
* @return An internationalized string corresponding to the given key.
|
||||
*/
|
||||
public static String getString(String key)
|
||||
{
|
||||
try
|
||||
{
|
||||
return RESOURCE_BUNDLE.getString(key);
|
||||
|
||||
}
|
||||
catch (MissingResourceException exc)
|
||||
{
|
||||
return '!' + key + '!';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an image from a given image identifier.
|
||||
* @param imageID The identifier of the image.
|
||||
* @return The image for the given identifier.
|
||||
*/
|
||||
public static byte[] getImage(ImageID imageID)
|
||||
{
|
||||
byte[] image = new byte[100000];
|
||||
|
||||
String path = Resources.getString(imageID.getId());
|
||||
try
|
||||
{
|
||||
Resources.class.getClassLoader()
|
||||
.getResourceAsStream(path).read(image);
|
||||
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
log.error("Failed to load image:" + path, exc);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the Image Identifier.
|
||||
*/
|
||||
public static class ImageID
|
||||
{
|
||||
private String id;
|
||||
|
||||
private ImageID(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.plugin.rssaccregwizz;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.configuration.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Registers the <tt>RssAccountRegistrationWizard</tt> in the UI Service.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class RssAccRegWizzActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(
|
||||
RssAccRegWizzActivator.class.getName());
|
||||
|
||||
/**
|
||||
* A currently valid bundle context.
|
||||
*/
|
||||
public static BundleContext bundleContext;
|
||||
|
||||
/**
|
||||
* A currently valid reference to the configuration service.
|
||||
*/
|
||||
private static ConfigurationService configService;
|
||||
|
||||
/**
|
||||
* Starts this bundle.
|
||||
* @param bc the currently valid <tt>BundleContext</tt>.
|
||||
*/
|
||||
public void start(BundleContext bc)
|
||||
{
|
||||
logger.info("Loading rss account wizard.");
|
||||
|
||||
bundleContext = bc;
|
||||
|
||||
ServiceReference uiServiceRef = bundleContext
|
||||
.getServiceReference(UIService.class.getName());
|
||||
|
||||
UIService uiService
|
||||
= (UIService) bundleContext.getService(uiServiceRef);
|
||||
|
||||
AccountRegistrationWizardContainer wizardContainer
|
||||
= uiService.getAccountRegWizardContainer();
|
||||
|
||||
RssAccountRegistrationWizard rssWizard
|
||||
= new RssAccountRegistrationWizard(wizardContainer);
|
||||
|
||||
wizardContainer.addAccountRegistrationWizard(rssWizard);
|
||||
|
||||
logger.info("Rss account registration wizard [STARTED].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle.
|
||||
*
|
||||
* @param context The execution context of the bundle being stopped.
|
||||
*/
|
||||
public void stop(BundleContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <tt>ProtocolProviderFactory</tt> for the Rss protocol.
|
||||
* @return the <tt>ProtocolProviderFactory</tt> for the Rss protocol
|
||||
*/
|
||||
public static ProtocolProviderFactory getRssProtocolProviderFactory()
|
||||
{
|
||||
|
||||
ServiceReference[] serRefs = null;
|
||||
|
||||
String osgiFilter = "("
|
||||
+ ProtocolProviderFactory.PROTOCOL
|
||||
+ "=" + "Rss" + ")";
|
||||
|
||||
try
|
||||
{
|
||||
serRefs = bundleContext.getServiceReferences(
|
||||
ProtocolProviderFactory.class.getName(), osgiFilter);
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
logger.error(ex);
|
||||
}
|
||||
|
||||
return (ProtocolProviderFactory) bundleContext.getService(serRefs[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundleContext that we received when we were started.
|
||||
*
|
||||
* @return a currently valid instance of a bundleContext.
|
||||
*/
|
||||
public BundleContext getBundleContext()
|
||||
{
|
||||
return bundleContext;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
/**
|
||||
* The <tt>RssAccountRegistration</tt> is used to store all user input data
|
||||
* through the <tt>RssAccountRegistrationWizard</tt>.
|
||||
*
|
||||
* @author Emil Ivov/Jean-Albert Vescovo
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.rssaccregwizz;
|
||||
|
||||
public class RssAccountRegistration
|
||||
{
|
||||
private String userID;
|
||||
private String password;
|
||||
private boolean rememberPassword;
|
||||
|
||||
/**
|
||||
* Returns the User ID of the rss registration account.
|
||||
* @return the User ID of the rss registration account.
|
||||
*/
|
||||
public String getUserID()
|
||||
{
|
||||
return userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user ID of the rss registration account.
|
||||
* @param userID the userID of the rss registration account.
|
||||
*/
|
||||
public void setUserID(String userID)
|
||||
{
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password of the Rss registration account.
|
||||
*
|
||||
* @return the password of the Rss registration account.
|
||||
*/
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password of the Rss registration account.
|
||||
*
|
||||
* @param password the password of the Rss registration account.
|
||||
*/
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if password has to remembered, <tt>false</tt>
|
||||
* otherwise.
|
||||
*
|
||||
* @return <tt>true</tt> if password has to remembered, <tt>false</tt>
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isRememberPassword()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rememberPassword value of this Rss account registration.
|
||||
*
|
||||
* @param rememberPassword <tt>true</tt> if password has to remembered,
|
||||
* <tt>false</tt> otherwise.
|
||||
*/
|
||||
public void setRememberPassword(boolean rememberPassword)
|
||||
{
|
||||
this.rememberPassword = true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.plugin.rssaccregwizz;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.impl.gui.customcontrols.*;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* The <tt>RssAccountRegistrationWizard</tt> is an implementation of the
|
||||
* <tt>AccountRegistrationWizard</tt> for the Rss protocol. It allows
|
||||
* the user to create and configure a new Rss account.
|
||||
*
|
||||
* @author Emil Ivov
|
||||
*/
|
||||
public class RssAccountRegistrationWizard
|
||||
implements AccountRegistrationWizard
|
||||
{
|
||||
|
||||
/**
|
||||
* The first page of the rss account registration wizard.
|
||||
*/
|
||||
private FirstWizardPage firstWizardPage;
|
||||
|
||||
/**
|
||||
* The object that we use to store details on an account that we will be
|
||||
* creating.
|
||||
*/
|
||||
private RssAccountRegistration registration
|
||||
= new RssAccountRegistration();
|
||||
|
||||
private WizardContainer wizardContainer;
|
||||
|
||||
private ProtocolProviderService protocolProvider;
|
||||
|
||||
private String propertiesPackage
|
||||
= "net.java.sip.communicator.plugin.rssaccregwizz";
|
||||
|
||||
private boolean isModification;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>RssAccountRegistrationWizard</tt>.
|
||||
* @param wizardContainer the wizard container, where this wizard
|
||||
* is added
|
||||
*/
|
||||
public RssAccountRegistrationWizard(WizardContainer wizardContainer)
|
||||
{
|
||||
this.wizardContainer = wizardContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getIcon</code> method.
|
||||
* Returns the icon to be used for this wizard.
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getIcon()
|
||||
{
|
||||
return Resources.getImage(Resources.GIBBERISH_LOGO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getPageImage</code> method.
|
||||
* Returns the image used to decorate the wizard page
|
||||
*
|
||||
* @return byte[] the image used to decorate the wizard page
|
||||
*/
|
||||
public byte[] getPageImage()
|
||||
{
|
||||
return Resources.getImage(Resources.PAGE_IMAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getProtocolName</code>
|
||||
* method. Returns the protocol name for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolName()
|
||||
{
|
||||
return Resources.getString("protocolName");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the <code>AccountRegistrationWizard.getProtocolDescription
|
||||
* </code> method. Returns the description of the protocol for this wizard.
|
||||
* @return String
|
||||
*/
|
||||
public String getProtocolDescription()
|
||||
{
|
||||
return Resources.getString("protocolDescription");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of pages contained in this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getPages()
|
||||
{
|
||||
ArrayList pages = new ArrayList();
|
||||
firstWizardPage = new FirstWizardPage(registration, wizardContainer);
|
||||
|
||||
pages.add(firstWizardPage);
|
||||
|
||||
return pages.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of data that user has entered through this wizard.
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getSummary()
|
||||
{
|
||||
Hashtable summaryTable = new Hashtable();
|
||||
|
||||
summaryTable.put("User ID", registration.getUserID());
|
||||
|
||||
return summaryTable.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs the account created through this wizard.
|
||||
* @return ProtocolProviderService
|
||||
*/
|
||||
public ProtocolProviderService finish()
|
||||
{
|
||||
firstWizardPage = null;
|
||||
ProtocolProviderFactory factory
|
||||
= RssAccRegWizzActivator.getRssProtocolProviderFactory();
|
||||
|
||||
return this.installAccount(factory,
|
||||
registration.getUserID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an account for the given user and password.
|
||||
* @param providerFactory the ProtocolProviderFactory which will create
|
||||
* the account
|
||||
* @param user the user identifier
|
||||
* @return the <tt>ProtocolProviderService</tt> for the new account.
|
||||
*/
|
||||
public ProtocolProviderService installAccount(
|
||||
ProtocolProviderFactory providerFactory,
|
||||
String user)
|
||||
{
|
||||
|
||||
Hashtable accountProperties = new Hashtable();
|
||||
|
||||
if (registration.isRememberPassword())
|
||||
{
|
||||
accountProperties.put(ProtocolProviderFactory.PASSWORD
|
||||
, registration.getPassword());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
AccountID accountID = providerFactory.installAccount(
|
||||
user, accountProperties);
|
||||
|
||||
ServiceReference serRef = providerFactory
|
||||
.getProviderForAccount(accountID);
|
||||
|
||||
protocolProvider = (ProtocolProviderService)
|
||||
RssAccRegWizzActivator.bundleContext
|
||||
.getService(serRef);
|
||||
}
|
||||
catch (IllegalArgumentException exc)
|
||||
{
|
||||
new ErrorDialog(null, exc.getMessage(), exc).showDialog();
|
||||
}
|
||||
catch (IllegalStateException exc)
|
||||
{
|
||||
new ErrorDialog(null, exc.getMessage(), exc).showDialog();
|
||||
}
|
||||
|
||||
return protocolProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the UserID and Password fields in this panel with the data comming
|
||||
* from the given protocolProvider.
|
||||
* @param protocolProvider The <tt>ProtocolProviderService</tt> to load the
|
||||
* data from.
|
||||
*/
|
||||
|
||||
public void loadAccount(ProtocolProviderService protocolProvider)
|
||||
{
|
||||
|
||||
this.protocolProvider = protocolProvider;
|
||||
|
||||
isModification = true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
protocolName=Rss
|
||||
protocolDescription=Add your preferred RSS feeds into SIP Communicator !
|
||||
userID=User ID:
|
||||
password=Password:
|
||||
rememberPassword=Remember password
|
||||
userAndPassword=Identification
|
||||
existingAccount=* The account you entered is already installed.
|
||||
|
||||
protocolIcon=resources/images/rss/rss-online.png
|
||||
pageImage=resources/images/rss/rss64x64.png
|
||||
@ -0,0 +1,30 @@
|
||||
Bundle-Activator: net.java.sip.communicator.plugin.rssaccregwizz.RssAccRegWizzActivator
|
||||
Bundle-Name: Rss account registration wizard
|
||||
Bundle-Description: Rss account registration wizard.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.osgi.framework,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.configuration,
|
||||
net.java.sip.communicator.service.configuration.event,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.event,
|
||||
net.java.sip.communicator.service.contactlist,
|
||||
net.java.sip.communicator.service.contactlist.event,
|
||||
net.java.sip.communicator.service.gui,
|
||||
net.java.sip.communicator.service.gui.event,
|
||||
net.java.sip.communicator.service.browserlauncher,
|
||||
javax.swing,
|
||||
javax.swing.event,
|
||||
javax.swing.table,
|
||||
javax.swing.text,
|
||||
javax.swing.text.html,
|
||||
javax.accessibility,
|
||||
javax.swing.plaf,
|
||||
javax.swing.plaf.metal,
|
||||
javax.swing.plaf.basic,
|
||||
javax.imageio,
|
||||
javax.swing.filechooser,
|
||||
javax.swing.tree,
|
||||
javax.swing.undo,
|
||||
javax.swing.border
|
||||
Loading…
Reference in new issue