Commit cd126149 authored by Holger Bergunde's avatar Holger Bergunde Committed by holger.bergunde

add remoteroster basic functionalty

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@12895 b35dd754-fafc-0310-a699-88a17e54d16e
parent 334d2538
package org.jivesoftware.openfire.plugin;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.packageProcessor.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.ReceiveComponentUpdatesProcessor;
import org.jivesoftware.openfire.plugin.packageProcessor.SendRosterProcessor;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class RemotePackageInterceptor implements PacketInterceptor {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
private String _mySubdomain;
private Map<String, AbstractRemoteRosterProcessor> _packetProcessor = new HashMap<String, AbstractRemoteRosterProcessor>();
private Set<String> _registeredJids = new HashSet<String>();
public RemotePackageInterceptor(String initialSubdomain) {
_mySubdomain = initialSubdomain;
XMPPServer server = XMPPServer.getInstance();
RosterManager rosterMananger = server.getRosterManager();
AbstractRemoteRosterProcessor sendroster = new SendRosterProcessor(rosterMananger, _mySubdomain);
AbstractRemoteRosterProcessor receiveChanges = new ReceiveComponentUpdatesProcessor(rosterMananger);
_packetProcessor.put("sendRoster", sendroster);
_packetProcessor.put("receiveChanges", receiveChanges);
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException
{
if (!processed && incoming) {
if (packet instanceof IQ) {
IQ myPacket = (IQ) packet;
if (myPacket.getFrom() == null || myPacket.getTo() == null) {
return;
}
String to = myPacket.getTo().toString();
String from = myPacket.getFrom().toString();
if (myPacket.getType().equals(IQ.Type.get) && from.equals(_mySubdomain)) {
if (findNodesInDocument(myPacket.getElement().getDocument(), "//roster:*").size() == 1) {
// This Package is a roster request by remote component
_packetProcessor.get("sendRoster").process(packet);
}
} else if (myPacket.getType().equals(IQ.Type.set) && from.equals(_mySubdomain)) {
if (findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item").size() >= 1) {
// Component sends roster update
_packetProcessor.get("receiveChanges").process(packet);
}
} else if (myPacket.getType().equals(IQ.Type.set) && myPacket.getTo().toString().equals(_mySubdomain)) {
// user provided register informations to gateway
if (packet.toXML().contains("jabber:iq:gateway:register")) {
_registeredJids.add(from);
} else if (findNodesInDocument(myPacket.getChildElement().getDocument(), "//register:remove")
.size() == 1) {
// TODO: works until the server restarts...:(
_registeredJids.remove(from);
}
} else if (myPacket.getType().equals(IQ.Type.result)
&& myPacket.getFrom().toString().equals(_mySubdomain)) {
// Adds iq:registered to features to indicate, that user is
// registered with gateway
if (_registeredJids.contains(to)) {
Element feature = new DefaultElement("feature");
feature.add(new DefaultAttribute("var", "jabber:iq:registered"));
myPacket.getChildElement().add(feature);
}
}
}
}
}
/**
* Search the specified document for Nodes corresponding to the xpath Keep
* in mind that you have to use xmpp namespace for searching e.g.
* '//roster:features'
*
* @param doc
* document
* @param xpath
* with roster namespace for searching in query nodes
* @return list of nodes
*/
protected List<Node> findNodesInDocument(Document doc, String xpath)
{
Map<String, String> namespaceUris = new HashMap<String, String>();
namespaceUris.put("roster", "jabber:iq:roster");
namespaceUris.put("register", "jabber:iq:register");
XPath xPath = DocumentHelper.createXPath(xpath);
xPath.setNamespaceURIs(namespaceUris);
return xPath.selectNodes(doc);
}
protected String getServerNameFromComponentName(String componentName)
{
int intServer = componentName.lastIndexOf(".");
return componentName.substring(0, intServer);
}
}
package org.jivesoftware.openfire.plugin;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.component.ComponentEventListener;
import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.session.ComponentSession;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
public class RemoteRosterPlugin implements Plugin {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
// private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
final SessionManager _sessionManager = SessionManager.getInstance();
private Map<String, RemotePackageInterceptor> _interceptors = new HashMap<String, RemotePackageInterceptor>();
private static PluginManager pluginManager;
private Set<String> _waitingForIQResponse = new HashSet<String>();
private InterceptorManager _interceptorManager;
private PropertyEventListener _settingsObserver;
public RemoteRosterPlugin() {
}
public void initializePlugin(PluginManager manager, File pluginDirectory)
{
pluginManager = manager;
manageExternalComponents();
listenToSettings();
_interceptorManager = InterceptorManager.getInstance();
}
private void manageExternalComponents()
{
InternalComponentManager compManager = InternalComponentManager.getInstance();
compManager.addListener(new ComponentEventListener() {
/**
* Check if the unregistered component contains to one of our
* package interceptors
*/
@Override
public void componentUnregistered(JID componentJID)
{
ComponentSession session = _sessionManager.getComponentSession(componentJID.getDomain());
if (session != null && _interceptors.containsKey(session.getExternalComponent().getInitialSubdomain())) {
String initialSubdomain = session.getExternalComponent().getInitialSubdomain();
// Remove it from Map & ComponentManager
updateInterceptors(initialSubdomain);
}
}
/**
* If there is a new external Component, check if it is a gateway
* and add create a package interceptor if it is enabled
*/
@Override
public void componentRegistered(JID componentJID)
{
_waitingForIQResponse.add(componentJID.getDomain());
}
@Override
public void componentInfoReceived(IQ iq)
{
String from = iq.getFrom().getDomain();
//Waiting for this external component sending an IQ response to us?
if (_waitingForIQResponse.contains(from)) {
Element packet = iq.getChildElement();
Document doc = packet.getDocument();
List<Node> nodes = findNodesInDocument(doc, "//xmpp:identity[@category='gateway']");
//Is this external component a gateway and there is no package interceptor for it?
if (nodes.size() > 0 && !_interceptors.containsKey(from))
{
updateInterceptors(from);
}
// We got the IQ, we can now remove it from the set, because
// we are not waiting any more
_waitingForIQResponse.remove(from);
}
}
});
}
private void listenToSettings()
{
_settingsObserver = new RemoteRosterPropertyListener() {
@Override
protected void changedProperty(String prop)
{
updateInterceptors(prop);
}
};
PropertyEventDispatcher.addListener(_settingsObserver);
}
private static PluginManager pluginManager;
public void destroyPlugin()
{
for (String interceptor : _interceptors.keySet())
{
removeInterceptor(interceptor);
}
PropertyEventDispatcher.removeListener(_settingsObserver);
pluginManager = null;
_interceptorManager = null;
}
public RemoteRosterPlugin() {
}
private void updateInterceptors(String componentJID)
{
boolean allowed = JiveGlobals.getBooleanProperty("plugin.remoteroster.jids."+componentJID, false);
if (allowed)
{
if(!_interceptors.containsKey(componentJID))
{
createNewPackageIntercetor(componentJID);
}
} else
{
if(_interceptors.containsKey(componentJID))
{
removeInterceptor(componentJID);
}
}
}
public String getName()
{
return "remoteRoster";
public void initializePlugin(PluginManager manager, File pluginDirectory) {
pluginManager = manager;
}
}
/**
* Search the specified document for Nodes corresponding to the xpath
* Keep in mind that you have to use xmpp namespace for searching e.g. '//xmpp:features'
* @param doc document
* @param xpath with xmpp namespace for searching in query nodes
* @return list of nodes
*/
private List<Node> findNodesInDocument(Document doc, String xpath)
{
Map<String, String> namespaceUris = new HashMap<String, String>();
namespaceUris.put("xmpp", "http://jabber.org/protocol/disco#info");
XPath xPath = DocumentHelper.createXPath(xpath);
xPath.setNamespaceURIs(namespaceUris);
return xPath.selectNodes(doc);
}
public static PluginManager getPluginManager()
{
return pluginManager;
}
public void destroyPlugin() {
}
private void removeInterceptor(String initialSubdomain)
{
RemotePackageInterceptor interceptor = _interceptors.get(initialSubdomain);
if (interceptor != null) {
_interceptorManager.removeInterceptor(interceptor);
_interceptors.remove(initialSubdomain);
}
}
private void createNewPackageIntercetor(String initialSubdomain)
{
RemotePackageInterceptor interceptor = new RemotePackageInterceptor(initialSubdomain);
_interceptors.put(initialSubdomain, interceptor);
_interceptorManager.addInterceptor(interceptor);
}
public String getName() {
return "remoteRoster";
}
public static PluginManager getPluginManager() {
return pluginManager;
}
}
package org.jivesoftware.openfire.plugin;
import java.util.Map;
import org.jivesoftware.util.PropertyEventListener;
public abstract class RemoteRosterPropertyListener implements PropertyEventListener {
@Override
public void xmlPropertySet(String property, Map<String, Object> params)
{
}
@Override
public void xmlPropertyDeleted(String property, Map<String, Object> params)
{
}
@Override
public void propertySet(String property, Map<String, Object> params)
{
if (property.contains("plugin.remoteroster.jids."))
{
changedProperty(property.replace("plugin.remoteroster.jids.", ""));
}
}
@Override
public void propertyDeleted(String property, Map<String, Object> params)
{
changedProperty(property);
}
protected abstract void changedProperty(String prop);
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.xmpp.packet.Packet;
abstract public class AbstractRemoteRosterProcessor {
XMPPServer _server;
PacketRouter _router;
public AbstractRemoteRosterProcessor() {
_server = XMPPServer.getInstance();
}
abstract public void process(Packet packet) throws PacketRejectedException;
protected void dispatchPacket(Packet packet)
{
PacketRouter router = _server.getPacketRouter();
router.route(packet);
}
/**
* Search the specified document for Nodes corresponding to the xpath Keep
* in mind that you have to use xmpp namespace for searching e.g.
* '//roster:features'
*
* @param doc
* document
* @param xpath
* with roster namespace for searching in query nodes
* @return list of nodes
*/
protected List<Node> findNodesInDocument(Document doc, String xpath)
{
Map<String, String> namespaceUris = new HashMap<String, String>();
namespaceUris.put("roster", "jabber:iq:roster");
XPath xPath = DocumentHelper.createXPath(xpath);
xPath.setNamespaceURIs(namespaceUris);
return xPath.selectNodes(doc);
}
protected String getUsernameFromJid(String jid)
{
int firstAtPos = jid.indexOf("@");
return firstAtPos != -1 ? jid.substring(0, firstAtPos) : jid;
}
protected String getServerNameFromComponentName(String componentName)
{
int intServer = componentName.lastIndexOf(".");
return componentName.substring(0, intServer);
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
public class ReceiveComponentUpdatesProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
public ReceiveComponentUpdatesProcessor(RosterManager rosterManager) {
_rosterManager = rosterManager;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
IQ myPacket = (IQ) packet;
String to = myPacket.getTo().toString();
String username = getUsernameFromJid(to);
List<Node> nodes = findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item");
for (Node n : nodes) {
Roster roster;
try {
roster = _rosterManager.getRoster(username);
String jid = n.valueOf("@jid");
String name = n.valueOf("@name");
List<String> grouplist = new ArrayList<String>();
List<Node> groupnodes = findNodesInDocument(n.getDocument(), "//roster:group");
for (Node ne : groupnodes) {
String groupName = ne.getText();
grouplist.add(groupName);
}
boolean rosterPersisten = JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false);
roster.createRosterItem(new JID(jid), name, grouplist, true, rosterPersisten);
RosterItem getThat = roster.getRosterItem(new JID(jid));
getThat.setSubStatus(RosterItem.SUB_BOTH);
roster.updateRosterItem(getThat);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package org.jivesoftware.openfire.plugin.packageProcessor;
import java.util.Collection;
import org.dom4j.Element;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
public class SendRosterProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
private String _componentName;
public SendRosterProcessor(RosterManager rosterMananger, String componentName) {
_rosterManager = rosterMananger;
_componentName = componentName;
}
@Override
public void process(Packet packet) throws PacketRejectedException
{
IQ myPacket = (IQ) packet;
String from = myPacket.getFrom().toString();
String to = myPacket.getFrom().toString();
String username = getUsernameFromJid(to);
Roster roster;
try {
roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
sendRosterToComponent(packet, items);
} catch (UserNotFoundException e) {
e.printStackTrace();
}
}
private void sendRosterToComponent(Packet requestPacket, Collection<RosterItem> items)
{
IQ iq = (IQ) requestPacket;
IQ response = IQ.createResultIQ(iq);
response.setTo(_componentName);
Element query = new DefaultElement("query");
for (RosterItem i : items) {
CharSequence serverName = getServerNameFromComponentName(_componentName);
if (i.getJid().toString().contains(serverName)) {
Element item = new DefaultElement("item");
item.add(new DefaultAttribute("jid", i.getJid().toString()));
item.add(new DefaultAttribute("name", i.getNickname()));
item.add(new DefaultAttribute("subscription", "both"));
for (String s : i.getGroups()) {
Element group = new DefaultElement("group");
group.setText(s);
item.add(group);
}
query.add(item);
}
}
query.addNamespace("", "jabber:iq:roster");
response.setChildElement(query);
dispatchPacket(response);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment