package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub;
import java.util.Collection;
import java.util.Map;
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.Helper;
import org.buddycloud.channelserver.channel.node.configuration.field.AccessModel;
import org.buddycloud.channelserver.db.exception.NodeStoreException;
import org.buddycloud.channelserver.pubsub.accessmodel.AccessModels;
import org.buddycloud.channelserver.utils.XMLConstants;
import org.buddycloud.channelserver.utils.node.NodeAclRefuseReason;
import org.buddycloud.channelserver.utils.node.NodeViewAcl;
import org.buddycloud.channelserver.utils.node.item.payload.Buddycloud;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.dom.DOMElement;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.PacketError.Condition;
import org.xmpp.packet.PacketError.Type;
public abstract class PubSubElementProcessorAbstract implements PubSubElementProcessor {
private static final Logger LOGGER = Logger.getLogger(PubSubElementProcessorAbstract.class);
public static final String NS_RSM = "http://jabber.org/protocol/rsm";
protected BlockingQueue<Packet> outQueue;
protected ChannelManager channelManager;
protected Element element;
protected IQ response;
protected IQ request;
protected JID actor;
protected String node = null;
protected Helper configurationHelper;
protected Map<String, String> nodeConfiguration;
protected String parentId;
protected Element pubsub;
// RSM details
protected int maxResults = -1;
protected String afterItemId = null;
protected String beforeItemId;
protected Element resultSetManagement;
protected String firstItem;
protected String lastItem;
protected int totalEntriesCount;
protected NodeViewAcl nodeViewAcl;
private Collection<JID> adminUsers;
protected String acceptedElementName;
public void setOutQueue(BlockingQueue<Packet> outQueue) {
this.outQueue = outQueue;
}
public void setChannelManager(ChannelManager channelManager) {
this.channelManager = channelManager;
}
protected Collection<JID> getAdminUsers() {
if (null == adminUsers) {
adminUsers = Configuration.getInstance().getAdminUsers();
}
return adminUsers;
}
public void setNode(String node) {
this.node = node;
}
public void setConfigurationHelper(Helper helper) {
configurationHelper = helper;
}
protected Helper getNodeConfigurationHelper() {
if (null == configurationHelper) {
configurationHelper = new Helper(channelManager);
}
return configurationHelper;
}
protected void setErrorCondition(Type type, Condition condition) {
if (null == response) {
response = IQ.createResultIQ(request);
}
response.setType(IQ.Type.error);
PacketError error = new PacketError(condition, type);
response.setError(error);
}
protected void createExtendedErrorReply(Type type, Condition condition, String additionalElement) {
if ((null != additionalElement) && (additionalElement.indexOf(" ") > -1)) {
// Its probably an error message!
createExtendedErrorReply(type, condition, null, null, additionalElement);
return;
}
createExtendedErrorReply(type, condition, additionalElement, JabberPubsub.NS_PUBSUB_ERROR);
}
protected void createExtendedErrorReply(Type type, Condition condition, String additionalElement, String additionalNamespace) {
createExtendedErrorReply(type, condition, additionalElement, additionalNamespace, null);
}
protected void createExtendedErrorReply(Type type, Condition condition, String additionalElement, String additionalNamespace, String text) {
if (null == response) {
response = IQ.createResultIQ(request);
}
response.setType(IQ.Type.error);
Element standardError = new DOMElement(condition.toXMPP(), new org.dom4j.Namespace("", JabberPubsub.NS_XMPP_STANZAS));
Element extraError = new DOMElement(additionalElement, new org.dom4j.Namespace("", additionalNamespace));
Element error = new DOMElement(XMLConstants.ERROR_ELEM);
error.addAttribute(XMLConstants.TYPE_ATTR, type.toXMPP());
error.add(standardError);
error.add(extraError);
if (null != text) {
Element description = new DOMElement(XMLConstants.TEXT_ELEM, new org.dom4j.Namespace("", "urn:ietf:params:xml:ns:xmpp-stanzas"));
description.setText(text);
error.add(description);
}
response.setChildElement(error);
}
protected Document getDocumentHelper() {
return DocumentHelper.createDocument();
}
public boolean accept(Element elm) {
return acceptedElementName.equals(elm.getName());
}
protected boolean checkNodeExists() throws NodeStoreException {
if ((!Configuration.getInstance().isLocalNode(node)) || !channelManager.nodeExists(node)) {
setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
return false;
}
return true;
}
protected boolean userCanViewNode() throws NodeStoreException {
if (getNodeViewAcl().canViewNode(node, channelManager.getNodeMembership(node, actor), getNodeAccessModel(),
Configuration.getInstance().isLocalJID(actor))) {
return true;
}
NodeAclRefuseReason reason = getNodeViewAcl().getReason();
createExtendedErrorReply(reason.getType(), reason.getCondition(), reason.getAdditionalErrorElement());
return false;
}
public void setNodeViewAcl(NodeViewAcl acl) {
nodeViewAcl = acl;
}
protected NodeViewAcl getNodeViewAcl() {
if (null == nodeViewAcl) {
nodeViewAcl = new NodeViewAcl();
}
return nodeViewAcl;
}
private AccessModels getNodeAccessModel() {
if (!nodeConfiguration.containsKey(AccessModel.FIELD_NAME)) {
return AccessModels.authorize;
}
return AccessModels.createFromString(nodeConfiguration.get(AccessModel.FIELD_NAME));
}
protected boolean actorIsRegistered() {
if (Configuration.getInstance().isLocalJID(actor)) {
return true;
} else {
setErrorCondition(PacketError.Type.auth, PacketError.Condition.forbidden);
return false;
}
}
protected void makeRemoteRequest() throws InterruptedException {
request.setTo(new JID(node.split("/")[2]).getDomain());
Element actor = request.getElement().element(XMLConstants.PUBSUB_ELEM).addElement(XMLConstants.ACTOR_ELEM, Buddycloud.NS);
actor.addText(request.getFrom().toBareJID());
outQueue.put(request);
}
protected boolean isValidStanza() {
Element replies = request.getChildElement().element(acceptedElementName);
try {
node = replies.attributeValue(XMLConstants.NODE_ATTR);
if (null == node) {
createExtendedErrorReply(PacketError.Type.modify, PacketError.Condition.bad_request, XMLConstants.NODE_ID_REQUIRED);
return false;
}
parentId = replies.attributeValue(XMLConstants.ITEM_ID);
if (null == parentId) {
createExtendedErrorReply(PacketError.Type.modify, PacketError.Condition.bad_request, XMLConstants.ITEM_ID_REQUIRED);
return false;
}
if (!channelManager.nodeExists(node)) {
setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
return false;
}
nodeConfiguration = channelManager.getNodeConf(node);
} catch (NullPointerException e) {
LOGGER.error(e);
setErrorCondition(PacketError.Type.modify, PacketError.Condition.bad_request);
return false;
} catch (NodeStoreException e) {
LOGGER.error(e);
setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
return false;
}
return true;
}
@Override
public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) throws Exception {
response = IQ.createResultIQ(reqIQ);
request = reqIQ;
actor = actorJID;
node = elm.attributeValue(XMLConstants.NODE_ATTR);
resultSetManagement = rsm;
if (null == actor) {
actor = request.getFrom();
}
if (!isValidStanza()) {
outQueue.put(response);
return;
}
if (!Configuration.getInstance().isLocalJID(request.getFrom())) {
response.getElement().addAttribute(XMLConstants.REMOTE_SERVER_DISCOVER_ATTR, Boolean.FALSE.toString());
}
pubsub = response.getElement().addElement(XMLConstants.PUBSUB_ELEM, JabberPubsub.NAMESPACE_URI);
try {
if (parseRsmElement()) {
addRecentItems();
addRsmElement();
}
} catch (NodeStoreException e) {
LOGGER.error(e);
response.getElement().remove(pubsub);
setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
}
outQueue.put(response);
}
protected boolean parseRsmElement() throws NodeStoreException {
Element rsmElement = request.getChildElement().element(XMLConstants.SET_ELEM);
if (null == rsmElement) {
return true;
}
Element max;
if (null != (max = rsmElement.element("max"))) {
maxResults = Integer.parseInt(max.getTextTrim());
}
Element after;
Element before;
if (null != (after = rsmElement.element("after"))) {
afterItemId = after.getTextTrim();
}
if (null != (before = rsmElement.element("before"))) {
beforeItemId = before.getTextTrim();
}
return true;
};
protected void addRecentItems() throws NodeStoreException {
// Empty implementation
return;
}
protected void addRsmElement() throws NodeStoreException {
// Empty implementation
return;
}
protected boolean nodePresent() {
if (node != null && !"".equals(node)) {
return true;
}
response.setType(IQ.Type.error);
Element nodeIdRequired = new DOMElement(XMLConstants.NODE_ID_REQUIRED, new Namespace("", JabberPubsub.NS_PUBSUB_ERROR));
Element badRequest = new DOMElement(PacketError.Condition.bad_request.toXMPP(), new Namespace("", JabberPubsub.NS_XMPP_STANZAS));
Element error = new DOMElement(XMLConstants.ERROR_ELEM);
error.addAttribute(XMLConstants.TYPE_ATTR, "modify");
error.add(badRequest);
error.add(nodeIdRequired);
response.setChildElement(error);
return false;
}
}