package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.set;
import java.io.StringReader;
import java.util.Collection;
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.db.ClosableIteratorImpl;
import org.buddycloud.channelserver.db.exception.NodeStoreException;
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.JabberPubsub;
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.PubSubElementProcessorAbstract;
import org.buddycloud.channelserver.pubsub.model.GlobalItemID;
import org.buddycloud.channelserver.pubsub.model.NodeItem;
import org.buddycloud.channelserver.pubsub.model.NodeSubscription;
import org.buddycloud.channelserver.pubsub.model.impl.GlobalItemIDImpl;
import org.buddycloud.channelserver.pubsub.subscription.Subscriptions;
import org.buddycloud.channelserver.utils.XMLConstants;
import org.buddycloud.channelserver.utils.node.item.payload.Buddycloud;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.dom.DOMElement;
import org.dom4j.io.SAXReader;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.resultsetmanagement.ResultSet;
public class ItemDelete extends PubSubElementProcessorAbstract {
private static final Logger LOGGER = Logger.getLogger(ItemDelete.class);
private GlobalItemID itemId;
private NodeItem nodeItem;
private Element parsedPayload;
public ItemDelete(BlockingQueue<Packet> outQueue, ChannelManager channelManager) {
this.setOutQueue(outQueue);
this.setChannelManager(channelManager);
acceptedElementName = "retract";
}
@Override
public void process(Element elm, JID actor, IQ reqIQ, Element rsm) throws InterruptedException, NodeStoreException {
element = elm;
request = reqIQ;
response = IQ.createResultIQ(request);
node = element.attributeValue(XMLConstants.NODE_ATTR);
this.actor = actor;
if (null == this.actor) {
this.actor = request.getFrom();
}
if (!nodePresent()) {
outQueue.put(response);
return;
}
if (!Configuration.getInstance().isLocalNode(node)) {
makeRemoteRequest();
return;
}
try {
if (!checkNodeExists() || !itemIdProvided() || !itemExists() || !validPayload() || !canDelete()) {
outQueue.put(response);
return;
}
deleteItem();
outQueue.put(response);
deleteReplies();
sendNotifications(node, itemId);
return;
} catch (NodeStoreException e) {
LOGGER.error(e);
setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
} catch (NullPointerException e) {
LOGGER.error(e);
setErrorCondition(PacketError.Type.modify, PacketError.Condition.bad_request);
} catch (IllegalArgumentException e) {
LOGGER.error(e);
createExtendedErrorReply(
PacketError.Type.modify, PacketError.Condition.bad_request,
"global-id-error", Buddycloud.NS_ERROR, e.getMessage()
);
}
outQueue.put(response);
}
private void deleteReplies() throws NodeStoreException {
if (null != nodeItem.getInReplyTo()) {
return;
}
ClosableIteratorImpl<NodeItem> replies = channelManager.getNodeItemReplies(node, itemId.getItemID(), null, true, -1);
NodeItem reply = null;
while (replies.hasNext()) {
reply = replies.next();
channelManager.deleteNodeItemById(reply.getNodeId(), reply.getId());
sendNotifications(node, new GlobalItemIDImpl(new JID(
Configuration.getInstance().getServerDomain()), reply.getNodeId(), reply.getId()));
}
}
private void sendNotifications(String node, GlobalItemID itemId) throws NodeStoreException {
try {
String notify =
request.getElement().element(XMLConstants.PUBSUB_ELEM).element(XMLConstants.RETRACT_ELEM).attributeValue(XMLConstants.NOTIFY_ATTR);
if ((notify != null) && (Boolean.FALSE.toString().equals(notify) || notify.equals("0"))) {
return;
}
ResultSet<NodeSubscription> subscriptions = channelManager.getNodeSubscriptionListeners(node);
Message notification = getNotificationMessage(node, itemId);
for (NodeSubscription subscription : subscriptions) {
LOGGER.debug("Subscription [node: " + subscription.getNodeId() + ", listener: " + subscription.getListener() + ", subscription: "
+ subscription.getSubscription() + "]");
if (subscription.getSubscription().equals(Subscriptions.subscribed)) {
notification.setTo(subscription.getListener());
outQueue.put(notification.createCopy());
}
}
Collection<JID> admins = getAdminUsers();
for (JID admin : admins) {
notification.setTo(admin);
outQueue.put(notification.createCopy());
}
} catch (NullPointerException e) {
LOGGER.error(e);
return;
} catch (InterruptedException e) {
LOGGER.error(e);
return;
}
}
private Message getNotificationMessage(String node, GlobalItemID itemId) {
Message notification = new Message();
notification.setType(Message.Type.headline);
notification.getElement().addAttribute("remote-server-discover", "false");
Element event = notification.addChildElement("event", JabberPubsub.NS_PUBSUB_EVENT);
Element items = event.addElement("items");
items.addAttribute("node", node);
Element retract = items.addElement("retract");
retract.addAttribute("id", itemId.getItemID());
return notification;
}
private void deleteItem() throws NodeStoreException {
channelManager.deleteNodeItemById(node, itemId.getItemID());
}
private boolean canDelete() throws NodeStoreException {
if (!userOwnsItem() && !userManagesNode()) {
setErrorCondition(PacketError.Type.auth, PacketError.Condition.forbidden);
return false;
}
return true;
}
private boolean userOwnsItem() {
try {
return parsedPayload.element("author").elementText("name").equals(actor.toBareJID());
} catch (NullPointerException e) {
return false;
}
}
private boolean userManagesNode() throws NodeStoreException {
return channelManager.getNodeMembership(node, actor).getAffiliation().canAuthorize();
}
private boolean validPayload() {
try {
SAXReader xmlReader = new SAXReader();
xmlReader.setMergeAdjacentText(true);
xmlReader.setStringInternEnabled(true);
xmlReader.setStripWhitespaceText(true);
parsedPayload = xmlReader.read(new StringReader(nodeItem.getPayload())).getRootElement();
return true;
} catch (Exception e) {
LOGGER.error(e);
setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
return false;
}
}
private boolean itemExists() throws NodeStoreException {
nodeItem = channelManager.getNodeItem(node, itemId.getItemID());
if (nodeItem != null) {
return true;
}
setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
return false;
}
private boolean itemIdProvided() {
String id =
request.getElement().element(XMLConstants.PUBSUB_ELEM).element(XMLConstants.RETRACT_ELEM).element(XMLConstants.ITEM_ELEM)
.attributeValue(XMLConstants.ID_ATTR);
if ((id != null) && !id.isEmpty()) {
if (GlobalItemIDImpl.isGlobalId(id)) {
itemId = GlobalItemIDImpl.fromBuddycloudString(id);
} else {
itemId = new GlobalItemIDImpl(new JID(
Configuration.getInstance().getServerDomain()), node, id);
}
return true;
}
response.setType(IQ.Type.error);
Element nodeIdRequired = new DOMElement("item-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("error");
error.addAttribute("type", PacketError.Type.modify.toXMPP());
error.add(badRequest);
error.add(nodeIdRequired);
response.setChildElement(error);
return false;
}
}