Skip to content

Commit b7bf8f1

Browse files
author
Simon Tennant
committed
Merge pull request #303 from lloydwatkin/parent-only-node
Parent only item retrieval for nodes
2 parents 1efae9a + 6f93bc8 commit b7bf8f1

File tree

10 files changed

+340
-105
lines changed

10 files changed

+340
-105
lines changed

src/main/java/org/buddycloud/channelserver/channel/ChannelManagerImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ public ResultSet<NodeSubscription> getSubscriptionChanges(JID user, Date startDa
113113
}
114114

115115
@Override
116-
public CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count)
116+
public CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count, boolean parentOnly)
117117
throws NodeStoreException {
118-
return nodeStore.getNodeItems(nodeId, afterItemId, count);
118+
return nodeStore.getNodeItems(nodeId, afterItemId, count, parentOnly);
119119
}
120120

121121
@Override
@@ -152,8 +152,8 @@ public CloseableIterator<NodeItem> getNewNodeItemsForUser(JID user, Date startDa
152152
}
153153

154154
@Override
155-
public int countNodeItems(String nodeId) throws NodeStoreException {
156-
return nodeStore.countNodeItems(nodeId);
155+
public int countNodeItems(String nodeId, boolean parentOnly) throws NodeStoreException {
156+
return nodeStore.countNodeItems(nodeId, parentOnly);
157157
}
158158

159159
public boolean isCachedNode(String nodeId) throws NodeStoreException {

src/main/java/org/buddycloud/channelserver/db/NodeStore.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,11 @@ ResultSet<NodeMembershipWithConfiguration> getUserMembershipsWithConfiguration(J
234234
* @param afterNodeId the itemId after which to retrieve items (exclusive, based on modified
235235
* date).
236236
* @param count the maximum number of records to return.
237+
* @param boolean whether to only retrieve parent items (i.e. no comments/replies)
237238
* @return an {@link Iterator} of the node entries.
238239
* @throws NodeStoreException
239240
*/
240-
CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count) throws NodeStoreException;
241+
CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count, boolean parentOnly) throws NodeStoreException;
241242

242243
/**
243244
* Get node items between two dates
@@ -339,10 +340,11 @@ CloseableIterator<NodeItem> getRecentItems(JID user, Date since, int maxPerNode,
339340
* Retrieves the number of items within a node.
340341
*
341342
* @param nodeId the node id from which to retrieve the item count.
343+
* @param parentOnly whether to include post item replies/comments in count
342344
* @return the entries count.
343345
* @throws NodeStoreException
344346
*/
345-
int countNodeItems(String nodeId) throws NodeStoreException;
347+
int countNodeItems(String nodeId, boolean parentOnly) throws NodeStoreException;
346348

347349
/**
348350
* Retrieves a single node item by the node item id.

src/main/java/org/buddycloud/channelserver/db/jdbc/JDBCNodeStore.java

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ public ResultSet<NodeSubscription> getNodeSubscriptionListeners() throws NodeSto
859859
}
860860

861861
@Override
862-
public CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count) throws NodeStoreException {
862+
public CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemId, int count, boolean parentOnly) throws NodeStoreException {
863863
NodeItem afterItem = null;
864864

865865
PreparedStatement stmt = null;
@@ -869,16 +869,23 @@ public CloseableIterator<NodeItem> getNodeItems(String nodeId, String afterItemI
869869
}
870870

871871
String countSQL = "";
872-
873872
if (count > -1) {
874873
countSQL = " OFFSET 0 LIMIT " + count;
875874
} else if (count < -1) {
876875
throw new IllegalArgumentException("Invalid value for parameter count: " + count);
877876
}
878-
877+
878+
String parentOnlySubstitution = "";
879+
if (parentOnly) {
880+
parentOnlySubstitution = " AND \"in_reply_to\" IS NULL ";
881+
}
882+
883+
String query = null;
879884
try {
880885
if (afterItem == null) {
881-
stmt = conn.prepareStatement(dialect.selectItemsForNode() + countSQL);
886+
query = dialect.selectItemsForNode()
887+
.replace("%parentOnly%", parentOnlySubstitution) + countSQL;
888+
stmt = conn.prepareStatement(query);
882889
stmt.setString(1, nodeId);
883890

884891
java.sql.ResultSet rs = stmt.executeQuery();
@@ -893,7 +900,9 @@ public NodeItem convertRow(java.sql.ResultSet rs) throws SQLException {
893900
}
894901
});
895902
} else {
896-
stmt = conn.prepareStatement(dialect.selectItemsForNodeBeforeDate() + countSQL);
903+
query = dialect.selectItemsForNodeBeforeDate()
904+
.replace("%parentOnly%", parentOnlySubstitution) + countSQL;
905+
stmt = conn.prepareStatement(query);
897906
stmt.setString(1, nodeId);
898907
stmt.setTimestamp(2, new java.sql.Timestamp(afterItem.getUpdated().getTime()));
899908
stmt.setTimestamp(3, new java.sql.Timestamp(afterItem.getUpdated().getTime()));
@@ -1154,7 +1163,7 @@ public CloseableIterator<NodeItem> getRecentItems(JID user, Date since, int maxP
11541163

11551164
@Override
11561165
public CloseableIterator<NodeItem> getNodeItems(String nodeId) throws NodeStoreException {
1157-
return getNodeItems(nodeId, null, -1);
1166+
return getNodeItems(nodeId, null, -1, false);
11581167
}
11591168

11601169
@Override
@@ -1312,11 +1321,18 @@ public CloseableIterator<NodeItem> getNewNodeItemsForUser(JID user, Date startDa
13121321
}
13131322

13141323
@Override
1315-
public int countNodeItems(String nodeId) throws NodeStoreException {
1324+
public int countNodeItems(String nodeId, boolean parentOnly) throws NodeStoreException {
13161325
PreparedStatement selectStatement = null;
13171326

13181327
try {
1319-
selectStatement = conn.prepareStatement(dialect.countItemsForNode());
1328+
String query = dialect.countItemsForNode();
1329+
String parentOnlySubstitution = "";
1330+
if (parentOnly) {
1331+
parentOnlySubstitution = "AND \"in_reply_to\" IS NULL";
1332+
}
1333+
selectStatement = conn.prepareStatement(
1334+
query.replace("%parentOnly%", parentOnlySubstitution)
1335+
);
13201336
selectStatement.setString(1, nodeId);
13211337

13221338
java.sql.ResultSet rs = selectStatement.executeQuery();
@@ -1537,7 +1553,7 @@ public ArrayList<String> getNodeList() throws NodeStoreException {
15371553

15381554
@Override
15391555
public boolean isCachedNode(String nodeId) throws NodeStoreException {
1540-
return ((this.countNodeItems(nodeId) > 0) && (true == this.isCachedNodeConfig(nodeId)));
1556+
return ((this.countNodeItems(nodeId, false) > 0) && (true == this.isCachedNodeConfig(nodeId)));
15411557
}
15421558

15431559
@Override

src/main/java/org/buddycloud/channelserver/db/jdbc/dialect/Sql92NodeStoreDialect.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,14 @@ public class Sql92NodeStoreDialect implements NodeStoreSQLDialect {
107107
+ " FROM \"items\" WHERE \"node\" = ? AND \"id\" = ?";
108108

109109
private static final String SELECT_ITEMS_FOR_NODE = "SELECT \"node\", \"id\", \"updated\", \"xml\", \"in_reply_to\", \"created\""
110-
+ " FROM \"items\" WHERE \"node\" = ? ORDER BY \"updated\" DESC, \"id\" ASC";
110+
+ " FROM \"items\" WHERE \"node\" = ? %parentOnly% ORDER BY \"updated\" DESC, \"id\" ASC";
111111

112112
private static final String SELECT_ITEMS_FOR_NODE_AFTER_DATE = "SELECT \"node\", \"id\", \"updated\", \"xml\", \"in_reply_to\", \"created\""
113113
+ " FROM \"items\" WHERE \"node\" = ? AND ( \"updated\" > ? OR ( \"updated\" = ? AND \"id\" > ? ) )"
114114
+ " ORDER BY \"updated\" ASC, \"id\" DESC";
115115

116116
private static final String SELECT_ITEMS_FOR_NODE_BEFORE_DATE = "SELECT \"node\", \"id\", \"updated\", \"xml\", \"in_reply_to\", \"created\""
117-
+ " FROM \"items\" WHERE \"node\" = ? AND ( \"updated\" < ? OR ( \"updated\" = ? AND \"id\" < ? ) )"
117+
+ " FROM \"items\" WHERE \"node\" = ? AND ( \"updated\" < ? OR ( \"updated\" = ? AND \"id\" < ? ) ) %parentOnly%"
118118
+ " ORDER BY \"updated\" DESC, \"id\" ASC";
119119

120120
private static final String SELECT_ITEMS_FOR_USER_BETWEEN_DATES = "" + "SELECT \"node\", \"id\", \"updated\", \"xml\", \"in_reply_to\", \"created\""
@@ -130,7 +130,7 @@ public class Sql92NodeStoreDialect implements NodeStoreSQLDialect {
130130
private static final String SELECT_COUNT_RECENT_ITEM_PARTS = "" + "(SELECT COUNT(\"id\") " + "FROM \"items\" " + "WHERE \"node\" = ? "
131131
+ "AND \"updated\" > ? " + "%parentOnly% " + "LIMIT ?)";
132132

133-
private static final String COUNT_ITEMS_FOR_NODE = "SELECT COUNT(*)" + " FROM \"items\" WHERE \"node\" = ?";
133+
private static final String COUNT_ITEMS_FOR_NODE = "SELECT COUNT(*)" + " FROM \"items\" WHERE \"node\" = ? %parentOnly%;";
134134

135135
private static final String SELECT_ITEM_REPLIES = "" + "SELECT \"id\", \"node\", \"xml\", \"updated\", \"in_reply_to\", \"created\" "
136136
+ "FROM \"items\" WHERE \"node\" = ? AND \"in_reply_to\" LIKE ? " + "AND \"updated\" > ? ORDER BY \"updated\" DESC";

src/main/java/org/buddycloud/channelserver/packetprocessor/iq/namespace/pubsub/get/items/NodeItemsGet.java

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,19 @@ public class NodeItemsGet extends PubSubElementProcessorAbstract {
4242
private String lastItem;
4343
private SAXReader xmlReader;
4444
private Element entry;
45-
private IQ requestIq;
4645
private IQ reply;
4746
private Element resultSetManagement;
4847
private Element element;
48+
private boolean parentOnly = false;
4949

5050
private Map<String, String> nodeDetails;
5151

5252
private int rsmEntriesCount;
5353

5454
private JID actor;
5555

56+
private Element items;
57+
5658
public NodeItemsGet(BlockingQueue<Packet> outQueue, ChannelManager channelManager) {
5759
setOutQueue(outQueue);
5860
setChannelManager(channelManager);
@@ -66,31 +68,37 @@ public void setChannelManager(ChannelManager ds) {
6668

6769
@Override
6870
public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) throws Exception {
69-
node = elm.attributeValue(XMLConstants.NODE_ATTR);
70-
requestIq = reqIQ;
71+
request = reqIQ;
72+
7173
reply = IQ.createResultIQ(reqIQ);
7274
element = elm;
7375
resultSetManagement = rsm;
7476

75-
if (!Configuration.getInstance().isLocalJID(requestIq.getFrom())) {
77+
if (!Configuration.getInstance().isLocalJID(request.getFrom())) {
7678
reply.getElement().addAttribute(XMLConstants.REMOTE_SERVER_DISCOVER_ATTR, Boolean.FALSE.toString());
7779
}
7880

79-
boolean isCached = channelManager.isCachedNode(node);
80-
81-
this.actor = actorJID;
82-
if (null == this.actor) {
83-
this.actor = requestIq.getFrom();
84-
}
85-
86-
if (!Configuration.getInstance().isLocalNode(node) && !isCached) {
87-
LOGGER.debug("Node " + node + " is remote and not cached, off to get some data");
88-
89-
makeRemoteRequest();
90-
return;
91-
}
92-
9381
try {
82+
83+
if (!isValidStanza()) {
84+
outQueue.put(reply);
85+
return;
86+
}
87+
88+
boolean isCached = channelManager.isCachedNode(node);
89+
90+
this.actor = actorJID;
91+
if (null == this.actor) {
92+
this.actor = request.getFrom();
93+
}
94+
95+
if (!Configuration.getInstance().isLocalNode(node) && !isCached) {
96+
LOGGER.debug("Node " + node + " is remote and not cached, off to get some data");
97+
98+
makeRemoteRequest();
99+
return;
100+
}
101+
94102
if (!checkNodeExists()) {
95103
setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
96104
outQueue.put(reply);
@@ -102,7 +110,7 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) throws Exc
102110
return;
103111
}
104112
xmlReader = new SAXReader();
105-
if (element.element(XMLConstants.ITEM_ELEM) == null) {
113+
if (null == items.element(XMLConstants.ITEM_ELEM)) {
106114
getItems();
107115
} else {
108116
if (!getItem()) {
@@ -112,13 +120,22 @@ public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) throws Exc
112120
} catch (NodeStoreException e) {
113121
LOGGER.error(e);
114122
setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
123+
} catch (NullPointerException e) {
124+
LOGGER.error(e);
125+
setErrorCondition(PacketError.Type.modify, PacketError.Condition.bad_request);
115126
}
116127
outQueue.put(reply);
117128
}
129+
130+
protected boolean isValidStanza() {
131+
Element pubsub = request.getElement().element(XMLConstants.PUBSUB_ELEM);
132+
items = pubsub.element(XMLConstants.ITEMS_ELEM);
133+
node = items.attributeValue(XMLConstants.NODE_ATTR);
134+
return true;
135+
}
118136

119137
private boolean getItem() throws Exception {
120-
NodeItem nodeItem = channelManager.getNodeItem(node, element.element(XMLConstants.ITEM_ELEM).attributeValue(XMLConstants.ID_ATTR));
121-
138+
NodeItem nodeItem = channelManager.getNodeItem(node, items.element(XMLConstants.ITEM_ELEM).attributeValue(XMLConstants.ID_ATTR));
122139
if (nodeItem == null) {
123140
if (!Configuration.getInstance().isLocalNode(node)) {
124141
makeRemoteRequest();
@@ -137,12 +154,12 @@ private boolean getItem() throws Exception {
137154

138155
@Override
139156
protected void makeRemoteRequest() throws InterruptedException {
140-
requestIq.setTo(new JID(node.split("/")[2]).getDomain());
141-
if (null == requestIq.getElement().element(XMLConstants.PUBSUB_ELEM).element(XMLConstants.ACTOR_ELEM)) {
142-
Element actor = requestIq.getElement().element(XMLConstants.PUBSUB_ELEM).addElement(XMLConstants.ACTOR_ELEM, Buddycloud.NS);
143-
actor.addText(requestIq.getFrom().toBareJID());
157+
request.setTo(new JID(node.split("/")[2]).getDomain());
158+
if (null == request.getElement().element(XMLConstants.PUBSUB_ELEM).element(XMLConstants.ACTOR_ELEM)) {
159+
Element actor = request.getElement().element(XMLConstants.PUBSUB_ELEM).addElement(XMLConstants.ACTOR_ELEM, Buddycloud.NS);
160+
actor.addText(request.getFrom().toBareJID());
144161
}
145-
outQueue.put(requestIq);
162+
outQueue.put(request);
146163
}
147164

148165
@Override
@@ -169,7 +186,12 @@ private void getItems() throws Exception {
169186
int maxItemsToReturn = MAX_ITEMS_TO_RETURN;
170187
String afterItemId = null;
171188

172-
String maxItems = element.attributeValue(XMLConstants.MAX_ITEMS_ATTR);
189+
String parentOnlyAttribute = request.getChildElement().element(XMLConstants.ITEMS_ELEM).attributeValue(XMLConstants.PARENT_ONLY_ATTR);
190+
if ((null != parentOnlyAttribute) && ((Boolean.TRUE.toString().equals(parentOnlyAttribute)) || ("1".equals(parentOnlyAttribute)))) {
191+
parentOnly = true;
192+
}
193+
194+
String maxItems = items.attributeValue(XMLConstants.MAX_ITEMS_ATTR);
173195

174196
if (maxItems != null) {
175197
maxItemsToReturn = Integer.parseInt(maxItems);
@@ -205,7 +227,7 @@ private void getItems() throws Exception {
205227
items.addAttribute(XMLConstants.NODE_ATTR, node);
206228

207229
entry = null;
208-
int totalEntriesCount = getNodeItems(items, maxItemsToReturn, afterItemId);
230+
int totalEntriesCount = getNodeItems(items, maxItemsToReturn, afterItemId, parentOnly);
209231

210232
if ((false == Configuration.getInstance().isLocalNode(node)) && (0 == rsmEntriesCount)) {
211233
LOGGER.debug("No results in cache for remote node, so " + "we're going federated to get more");
@@ -254,9 +276,9 @@ private AccessModels getNodeAccessModel() {
254276
/**
255277
* Get items nodes
256278
*/
257-
private int getNodeItems(Element items, int maxItemsToReturn, String afterItemId) throws NodeStoreException {
279+
private int getNodeItems(Element items, int maxItemsToReturn, String afterItemId, boolean parentOnly) throws NodeStoreException {
258280

259-
CloseableIterator<NodeItem> itemIt = channelManager.getNodeItems(node, afterItemId, maxItemsToReturn);
281+
CloseableIterator<NodeItem> itemIt = channelManager.getNodeItems(node, afterItemId, maxItemsToReturn, parentOnly);
260282
rsmEntriesCount = 0;
261283
if (itemIt == null) {
262284
return 0;
@@ -273,7 +295,7 @@ private int getNodeItems(Element items, int maxItemsToReturn, String afterItemId
273295
lastItem = nodeItem.getId();
274296
}
275297
LOGGER.debug("Including RSM there are " + rsmEntriesCount + " items for node " + node);
276-
return channelManager.countNodeItems(node);
298+
return channelManager.countNodeItems(node, parentOnly);
277299
} finally {
278300
itemIt.close();
279301
}

0 commit comments

Comments
 (0)