package org.buddycloud.channelserver.packetprocessor.iq.namespace.discoinfo;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.BlockingQueue;
import org.apache.log4j.Logger;
import org.buddycloud.channelserver.Configuration;
import org.buddycloud.channelserver.channel.ChannelManager;
import org.buddycloud.channelserver.channel.node.configuration.field.AccessModel;
import org.buddycloud.channelserver.db.exception.NodeStoreException;
import org.buddycloud.channelserver.packetprocessor.PacketProcessor;
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.JabberPubsub;
import org.buddycloud.channelserver.utils.XMLConstants;
import org.dom4j.Element;
import org.xmpp.forms.DataForm;
import org.xmpp.forms.FormField;
import org.xmpp.packet.IQ;
import org.xmpp.packet.IQ.Type;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketError.Condition;
public class DiscoInfoGet implements PacketProcessor<IQ> {
public static final String ELEMENT_NAME = "query";
private static final Logger logger = Logger.getLogger(DiscoInfoGet.class);
private final BlockingQueue<Packet> outQueue;
private final ChannelManager channelManager;
private String node;
private IQ result;
private IQ requestIq;
private Element query;
private Map<String, String> conf;
public DiscoInfoGet(BlockingQueue<Packet> outQueue, ChannelManager channelManager) {
this.outQueue = outQueue;
this.channelManager = channelManager;
}
@Override
public void process(IQ reqIQ) throws Exception {
requestIq = reqIQ;
result = IQ.createResultIQ(reqIQ);
Element elm = reqIQ.getChildElement();
node = elm.attributeValue(XMLConstants.NODE_ATTR);
query = result.setChildElement(ELEMENT_NAME, JabberDiscoInfo.NAMESPACE_URI);
if (false == Configuration.getInstance().isLocalJID(requestIq.getFrom())) {
result.getElement().addAttribute(XMLConstants.REMOTE_SERVER_DISCOVER_ATTR, Boolean.FALSE.toString());
}
if ((node == null) || ("".equals(node))) {
sendServerDiscoInfo();
return;
}
if (false == Configuration.getInstance().isLocalNode(node) && (false == channelManager.isCachedNode(node))) {
logger.info("Node " + node + " is remote and not cached so " + "we're going off to get disco#info");
makeRemoteRequest();
return;
}
conf = channelManager.getNodeConf(node);
if (conf.isEmpty()) {
nodeDoesntExistResponse();
return;
}
try {
sendNodeConfigurationInformation();
} catch (NodeStoreException e) {
logger.error(e);
setErrorResponse(PacketError.Type.wait, PacketError.Condition.internal_server_error);
}
}
private void sendNodeConfigurationInformation() throws Exception {
TreeMap<String, String> configuration = new TreeMap<String, String>();
DataForm x = new DataForm(DataForm.Type.result);
FormField formType = x.addField();
formType.setType(FormField.Type.hidden);
formType.setVariable("FORM_TYPE");
formType.addValue("http://jabber.org/protocol/pubsub#meta-data");
String value;
configuration.putAll(conf);
for (String key : configuration.keySet()) {
value = configuration.get(key);
if ((true == key.equals(AccessModel.FIELD_NAME)) && (value.equals(AccessModel.local.toString()))
&& (false == Configuration.getInstance().isLocalJID(requestIq.getFrom()))) {
value = AccessModel.authorize.toString();
}
x.addField(key, null, null).addValue(value);
}
query.addAttribute(XMLConstants.NODE_ATTR, node);
query.addElement("identity").addAttribute("category", "pubsub").addAttribute("type", "leaf");
query.addElement("feature").addAttribute("var", "http://jabber.org/protocol/pubsub");
query.add(x.getElement());
query.addElement("feature").addAttribute("var", JabberPubsub.NAMESPACE_URI);
Element identity = query.addElement("identity");
identity.addAttribute("category", "pubsub");
identity.addAttribute("type", "leaf");
logger.trace("Returning DISCO info for node: " + node);
outQueue.put(result);
}
private void nodeDoesntExistResponse() throws InterruptedException {
/*
* Not found. Let's return something like this: <iq type='error'
* from='plays.shakespeare.lit' to='romeo@montague.net/orchard' id='info1'> <query
* xmlns='http://jabber.org/protocol/disco#info' node='/user/pretty@lady.com/posts'/> <error
* type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error>
* </iq>
*/
setErrorResponse(PacketError.Type.cancel, PacketError.Condition.item_not_found);
}
private void setErrorResponse(PacketError.Type type, Condition condition) throws InterruptedException {
result.setChildElement(result.getChildElement().createCopy());
result.setType(Type.error);
PacketError pe = new PacketError(condition, type);
result.setError(pe);
outQueue.put(result);
}
private void sendServerDiscoInfo() throws InterruptedException {
query.addElement("identity").addAttribute("category", "pubsub").addAttribute("type", "channels");
query.addElement("identity").addAttribute("category", "pubsub").addAttribute("type", "inbox");
query.addElement("feature").addAttribute("var", "jabber:iq:register");
query.addElement("feature").addAttribute("var", "http://jabber.org/protocol/disco#info");
query.addElement("feature").addAttribute("var", "http://jabber.org/protocol/disco#items");
query.addElement("feature").addAttribute("var", "jabber:iq:search");
outQueue.put(result);
}
private void makeRemoteRequest() throws InterruptedException {
requestIq.setTo(new JID(node.split("/")[2]).getDomain());
outQueue.put(requestIq);
}
}