|
| 1 | +package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.get; |
| 2 | + |
| 3 | +import java.io.StringReader; |
| 4 | +import java.util.Map; |
| 5 | +import java.util.concurrent.BlockingQueue; |
| 6 | + |
| 7 | +import org.buddycloud.channelserver.channel.ChannelManager; |
| 8 | +import org.buddycloud.channelserver.channel.Conf; |
| 9 | +import org.buddycloud.channelserver.channel.node.configuration.field.AccessModel; |
| 10 | +import org.buddycloud.channelserver.db.exception.NodeStoreException; |
| 11 | +import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.JabberPubsub; |
| 12 | +import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.PubSubElementProcessorAbstract; |
| 13 | +import org.buddycloud.channelserver.pubsub.accessmodel.AccessModels; |
| 14 | +import org.buddycloud.channelserver.pubsub.affiliation.Affiliations; |
| 15 | +import org.buddycloud.channelserver.pubsub.model.NodeAffiliation; |
| 16 | +import org.buddycloud.channelserver.pubsub.model.NodeItem; |
| 17 | +import org.buddycloud.channelserver.pubsub.model.NodeSubscription; |
| 18 | +import org.buddycloud.channelserver.pubsub.model.NodeThread; |
| 19 | +import org.buddycloud.channelserver.pubsub.subscription.Subscriptions; |
| 20 | +import org.buddycloud.channelserver.utils.node.NodeAclRefuseReason; |
| 21 | +import org.buddycloud.channelserver.utils.node.NodeViewAcl; |
| 22 | +import org.dom4j.DocumentException; |
| 23 | +import org.dom4j.Element; |
| 24 | +import org.dom4j.io.SAXReader; |
| 25 | +import org.xmpp.packet.IQ; |
| 26 | +import org.xmpp.packet.JID; |
| 27 | +import org.xmpp.packet.Packet; |
| 28 | +import org.xmpp.packet.PacketError; |
| 29 | +import org.xmpp.resultsetmanagement.ResultSet; |
| 30 | + |
| 31 | +public class NodeThreadsGet extends PubSubElementProcessorAbstract { |
| 32 | + |
| 33 | + private static final int MAX_THREADS_TO_RETURN = 15; |
| 34 | + private int max; |
| 35 | + private String afterId; |
| 36 | + |
| 37 | + public NodeThreadsGet(BlockingQueue<Packet> outQueue, |
| 38 | + ChannelManager channelManager) { |
| 39 | + setChannelManager(channelManager); |
| 40 | + setOutQueue(outQueue); |
| 41 | + } |
| 42 | + |
| 43 | + @Override |
| 44 | + public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) |
| 45 | + throws Exception { |
| 46 | + this.request = reqIQ; |
| 47 | + this.node = elm.attributeValue("node"); |
| 48 | + this.actor = actorJID; |
| 49 | + this.resultSetManagement = rsm; |
| 50 | + this.max = MAX_THREADS_TO_RETURN; |
| 51 | + |
| 52 | + if (actor == null) { |
| 53 | + actor = request.getFrom(); |
| 54 | + } |
| 55 | + if (!isValidStanza()) { |
| 56 | + outQueue.put(response); |
| 57 | + return; |
| 58 | + } |
| 59 | + if (!userCanViewNode()) { |
| 60 | + outQueue.put(response); |
| 61 | + return; |
| 62 | + } |
| 63 | + if (!parseRsmElement()) { |
| 64 | + outQueue.put(response); |
| 65 | + } |
| 66 | + getNodeThreads(); |
| 67 | + addRsmElement(); |
| 68 | + outQueue.put(response); |
| 69 | + } |
| 70 | + |
| 71 | + private void addRsmElement() throws NodeStoreException { |
| 72 | + if (firstItem == null) { |
| 73 | + return; |
| 74 | + } |
| 75 | + Element pubsubEl = response.getElement().addElement("pubsub", |
| 76 | + JabberPubsub.NAMESPACE_URI); |
| 77 | + Element rsm = pubsubEl.addElement("set", NS_RSM); |
| 78 | + rsm.addElement("first", NS_RSM).setText(firstItem); |
| 79 | + rsm.addElement("last", NS_RSM).setText(lastItem); |
| 80 | + |
| 81 | + Integer nodeThreadCount = channelManager.countNodeThreads(node); |
| 82 | + rsm.addElement("count", NS_RSM).setText(nodeThreadCount.toString()); |
| 83 | + } |
| 84 | + |
| 85 | + private void getNodeThreads() throws NodeStoreException, DocumentException { |
| 86 | + ResultSet<NodeThread> nodeThreads = channelManager.getNodeThreads(node, afterId, max); |
| 87 | + this.response = IQ.createResultIQ(request); |
| 88 | + Element pubsubEl = response.getElement().addElement("pubsub", |
| 89 | + JabberPubsub.NAMESPACE_URI); |
| 90 | + SAXReader xmlReader = new SAXReader(); |
| 91 | + for (NodeThread nodeThread : nodeThreads) { |
| 92 | + Element threadEl = pubsubEl.addElement("thread"); |
| 93 | + threadEl.addAttribute("node", node); |
| 94 | + threadEl.addAttribute("id", nodeThread.getId()); |
| 95 | + threadEl.addAttribute("updated", Conf.formatDate( |
| 96 | + nodeThread.getUpdated())); |
| 97 | + ResultSet<NodeItem> items = nodeThread.getItems(); |
| 98 | + for (NodeItem item : items) { |
| 99 | + Element entry = xmlReader.read( |
| 100 | + new StringReader(item.getPayload())).getRootElement(); |
| 101 | + Element itemElement = threadEl.addElement("item"); |
| 102 | + itemElement.addAttribute("id", item.getId()); |
| 103 | + itemElement.add(entry); |
| 104 | + } |
| 105 | + } |
| 106 | + if (!nodeThreads.isEmpty()) { |
| 107 | + this.firstItem = nodeThreads.getFirst(1).iterator().next().getId(); |
| 108 | + this.lastItem = nodeThreads.getLast(1).iterator().next().getId(); |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + private boolean isValidStanza() throws NodeStoreException { |
| 113 | + if (node == null) { |
| 114 | + createExtendedErrorReply(PacketError.Type.modify, |
| 115 | + PacketError.Condition.bad_request, "nodeid-required"); |
| 116 | + return false; |
| 117 | + } |
| 118 | + if (!channelManager.nodeExists(node)) { |
| 119 | + setErrorCondition(PacketError.Type.cancel, |
| 120 | + PacketError.Condition.item_not_found); |
| 121 | + return false; |
| 122 | + } |
| 123 | + return true; |
| 124 | + } |
| 125 | + |
| 126 | + private AccessModels getNodeAccessModel(Map<String, String> nodeConfiguration) { |
| 127 | + if (!nodeConfiguration.containsKey(AccessModel.FIELD_NAME)) { |
| 128 | + return AccessModels.authorize; |
| 129 | + } |
| 130 | + return AccessModels.createFromString(nodeConfiguration |
| 131 | + .get(AccessModel.FIELD_NAME)); |
| 132 | + } |
| 133 | + |
| 134 | + private boolean userCanViewNode() throws NodeStoreException { |
| 135 | + NodeSubscription nodeSubscription = channelManager.getUserSubscription( |
| 136 | + node, actor); |
| 137 | + NodeAffiliation nodeAffiliation = channelManager.getUserAffiliation( |
| 138 | + node, actor); |
| 139 | + |
| 140 | + Affiliations affiliation = Affiliations.none; |
| 141 | + Subscriptions subscription = Subscriptions.none; |
| 142 | + if (nodeSubscription != null) { |
| 143 | + affiliation = nodeAffiliation.getAffiliation(); |
| 144 | + subscription = nodeSubscription.getSubscription(); |
| 145 | + } |
| 146 | + NodeViewAcl nodeViewAcl = new NodeViewAcl(); |
| 147 | + Map<String, String> nodeConfiguration = channelManager.getNodeConf(node); |
| 148 | + |
| 149 | + if (nodeViewAcl.canViewNode(node, affiliation, subscription, |
| 150 | + getNodeAccessModel(nodeConfiguration))) { |
| 151 | + return true; |
| 152 | + } |
| 153 | + |
| 154 | + NodeAclRefuseReason reason = nodeViewAcl.getReason(); |
| 155 | + createExtendedErrorReply(reason.getType(), reason.getCondition(), |
| 156 | + reason.getAdditionalErrorElement()); |
| 157 | + return false; |
| 158 | + } |
| 159 | + |
| 160 | + private boolean parseRsmElement() throws NodeStoreException { |
| 161 | + if (null == resultSetManagement) { |
| 162 | + return true; |
| 163 | + } |
| 164 | + Element maxEl = resultSetManagement.element("max"); |
| 165 | + if (maxEl != null) { |
| 166 | + this.max = Integer.parseInt(maxEl.getTextTrim()); |
| 167 | + } |
| 168 | + Element afterEl = resultSetManagement.element("after"); |
| 169 | + if (afterEl != null) { |
| 170 | + this.afterId = afterEl.getTextTrim(); |
| 171 | + if (channelManager.getNodeItem(node, afterId) == null) { |
| 172 | + setErrorCondition(PacketError.Type.cancel, |
| 173 | + PacketError.Condition.item_not_found); |
| 174 | + return false; |
| 175 | + } |
| 176 | + } |
| 177 | + return true; |
| 178 | + } |
| 179 | + |
| 180 | + @Override |
| 181 | + public boolean accept(Element elm) { |
| 182 | + return elm.getName().equals("threads"); |
| 183 | + } |
| 184 | +} |
0 commit comments