Skip to content

OF-2710: Replace two group-member queries with one in DefaultGroupPro…#3382

Open
MilanTyagi2004 wants to merge 1 commit into
igniterealtime:mainfrom
MilanTyagi2004:OF-2710
Open

OF-2710: Replace two group-member queries with one in DefaultGroupPro…#3382
MilanTyagi2004 wants to merge 1 commit into
igniterealtime:mainfrom
MilanTyagi2004:OF-2710

Conversation

@MilanTyagi2004

Copy link
Copy Markdown
Collaborator

Description

DefaultGroupProvider currently performs two database queries when loading a group's users:

  • One query to retrieve regular members.
  • One query to retrieve administrators.

As both user types are stored in the same table (ofGroupUser) and differ only by the value of the administrator column, the data can be retrieved using a single query and categorized in memory.

This PR optimizes group loading by replacing the two queries with a single query that retrieves both members and administrators.

Changes

  • Added a new query constant, LOAD_MEMBERS_AND_ADMINS, that retrieves both username and administrator values from ofGroupUser.
  • Removed the separate LOAD_MEMBERS and LOAD_ADMINS query constants.
  • Replaced the getMembers(String, boolean) helper method with loadMembersAndAdmins(String, Collection<JID>, Collection<JID>).
  • Updated group-loading logic to populate member and administrator collections from a single result set.
  • Updated createGroup and getGroup to use the new helper method.

Benefits

  • Reduces the number of database queries required to load group membership data from two to one.
  • Lowers database workload and query overhead.
  • Preserves existing behavior and APIs.
  • Requires no schema or architectural changes.

Testing

Compilation

mvn compile

…vider

Optimize DefaultGroupProvider by replacing two separate SQL lookups (one for standard members and one for administrators) with a single combined query.
- Remove LOAD_ADMINS and LOAD_MEMBERS SQL constants.
- Add LOAD_MEMBERS_AND_ADMINS SQL constant.
- Replace getMembers helper method with loadMembersAndAdmins to retrieve all users for a group and categorize them in memory by administrator status.
- Update createGroup and getGroup call sites to use the new loadMembersAndAdmins helper.
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR refactors group member and administrator loading in DefaultGroupProvider. A new SQL constant LOAD_MEMBERS_AND_ADMINS replaces two separate queries and returns both the persisted username and an administrator flag per row. A new helper method loadMembersAndAdmins executes this combined query, constructs JID objects from persisted usernames, normalizes JIDs to bare form when resources are detected, logs warnings for malformed entries, and partitions results into either the administrators or members collection based on the database flag. The createGroup and getGroup methods are updated to use this helper instead of invoking separate member and administrator queries.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description clearly relates to the changeset, explaining the optimization of group member/admin loading from two queries to one query.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java (1)

521-527: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix component check to use the persisted username, not an uninitialized JID.

On Line 523, server.matchesComponent(userJID) is evaluated before userJID is assigned. This makes the component branch ineffective and can misclassify component entries (without @) as local users.

Suggested fix
                 JID userJID = null;
                 if (user.indexOf('@') == -1) {
-                    // Create JID of local user if JID does not match a component's JID
-                    if (!server.matchesComponent(userJID)) {
+                    // Create JID of local user if value does not match a component JID
+                    if (!server.matchesComponent(user)) {
                         userJID = server.createJID(user, null);
                     } else {
-                        // FIXME else... what? OF-2709 Note that the 'if' condition is _always_ true (should it use 'user' instead of 'userJID'?)
+                        userJID = new JID(user);
                     }
                 }
                 else {
                     userJID = new JID(user);
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`
around lines 521 - 527, In DefaultGroupProvider, the component check uses
userJID before it is assigned causing incorrect classification; change the
matchesComponent call to use the persisted username variable (user) instead of
userJID and only create/assign userJID via server.createJID(user, null) when
matchesComponent(user) returns false (i.e., keep the branch logic but evaluate
server.matchesComponent(user) and then set userJID accordingly), ensuring the
else branch handles the component case correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`:
- Around line 521-527: In DefaultGroupProvider, the component check uses userJID
before it is assigned causing incorrect classification; change the
matchesComponent call to use the persisted username variable (user) instead of
userJID and only create/assign userJID via server.createJID(user, null) when
matchesComponent(user) returns false (i.e., keep the branch logic but evaluate
server.matchesComponent(user) and then set userJID accordingly), ensuring the
else branch handles the component case correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f2b3c391-3f22-4e51-89b6-ab8ed9074495

📥 Commits

Reviewing files that changed from the base of the PR and between 75c25b0 and ba0ceb7.

📒 Files selected for processing (1)
  • xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java (1)

84-94: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail the create path when INSERT_GROUP fails.

Line 84 logs the SQLException, but Lines 90-94 still build and return a Group. That makes createGroup report success for a group that was never written to ofGroup; xmppserver/src/main/java/org/jivesoftware/openfire/commands/admin/group/AddGroup.java:104-166 immediately mutates the returned Group, so the caller keeps operating on non-existent state. Propagate the failure here instead of falling through.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`
around lines 84 - 94, The create path currently swallows SQLException and
continues to call loadMembersAndAdmins and return a new Group; update
DefaultGroupProvider.createGroup so that failures to run the INSERT_GROUP do not
fall through: check the result of the PreparedStatement.executeUpdate (or set a
boolean/flag) and if it doesn't indicate a successful insert, or if an
SQLException is caught, rethrow an exception (e.g., SQLException or
IllegalStateException with the original exception as the cause) instead of
continuing; ensure this change is applied around the INSERT_GROUP execution and
catch block so loadMembersAndAdmins and the Group(...) return only happen on a
successful insert.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`:
- Around line 484-490: The call to server.matchesComponent currently passes the
String user; change it to pass a JID by constructing a JID from the user String
for the component check inside DefaultGroupProvider.loadMembersAndAdmins:
parse/construct a JID (new JID(user) or equivalent) and use that JID when
calling XMPPServer.matchesComponent(jid), while keeping server.createJID(user,
null) for the normal local-username path and assigning userJID appropriately
(userJID = server.createJID(user, null) for local usernames, otherwise new
JID(user) for full JIDs/components).

---

Outside diff comments:
In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`:
- Around line 84-94: The create path currently swallows SQLException and
continues to call loadMembersAndAdmins and return a new Group; update
DefaultGroupProvider.createGroup so that failures to run the INSERT_GROUP do not
fall through: check the result of the PreparedStatement.executeUpdate (or set a
boolean/flag) and if it doesn't indicate a successful insert, or if an
SQLException is caught, rethrow an exception (e.g., SQLException or
IllegalStateException with the original exception as the cause) instead of
continuing; ensure this change is applied around the INSERT_GROUP execution and
catch block so loadMembersAndAdmins and the Group(...) return only happen on a
successful insert.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 33dd30de-d40f-46ee-b2d9-a54c16588455

📥 Commits

Reviewing files that changed from the base of the PR and between ba0ceb7 and 403779f.

📒 Files selected for processing (1)
  • xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java

Comment on lines 484 to 490
if (user.indexOf('@') == -1) {
// Create JID of local user if JID does not match a component's JID
if (!server.matchesComponent(userJID)) {
if (!server.matchesComponent(user)) {
userJID = server.createJID(user, null);
} else {
// FIXME else... what? OF-2709 Note that the 'if' condition is _always_ true (should it use 'user' instead of 'userJID'?)
userJID = new JID(user);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspecting XMPPServer.matchesComponent signature(s):"
fd -p 'XMPPServer.java' | xargs -r rg -n -C2 'matchesComponent\s*\('

echo
echo "Inspecting the failing call site:"
sed -n '482,490p' xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java

Repository: igniterealtime/Openfire

Length of output: 621


Fix matchesComponent argument type in DefaultGroupProvider
XMPPServer.matchesComponent takes a JID, but DefaultGroupProvider.loadMembersAndAdmins(...) passes user (String) to server.matchesComponent(...), producing String cannot be converted to JID. Derive/parse a JID for the component check, and keep server.createJID(user, null) for the ordinary local-username path.

🧰 Tools
🪛 GitHub Actions: CodeQL / 0_Analyze (java).txt

[error] 486-486: Maven compilation failed (maven-compiler-plugin:3.15.0:compile). incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID

🪛 GitHub Actions: CodeQL / Analyze (java)

[error] 486-486: Maven compiler plugin (maven-compiler-plugin) compilation error: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID.

🪛 GitHub Actions: Openfire CI / 28_Build Openfire from source (ubuntu-latest, 25, zulu).txt

[error] 486-486: COMPILATION ERROR: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID (maven-compiler-plugin compile on project xmppserver).

🪛 GitHub Actions: Openfire CI / 31_Build Openfire from source (ubuntu-latest, 21, zulu).txt

[error] 486-486: Maven Compiler (maven-compiler-plugin) compilation failed: incompatible types. java.lang.String cannot be converted to org.xmpp.packet.JID at DefaultGroupProvider.java:[486,50].

🪛 GitHub Actions: Openfire CI / 32_Build Openfire from source (ubuntu-latest, 17, zulu).txt

[error] 486-486: Maven compiler failed: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID. Error occurred in maven-compiler-plugin:3.15.0:compile (default-compile) for project xmppserver.

🪛 GitHub Actions: Openfire CI / 33_Build Openfire from source (macos-latest, 17, zulu).txt

[error] 486-486: Maven compiler plugin failed: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID.

🪛 GitHub Actions: Openfire CI / 34_Build Openfire from source (macos-latest, 21, zulu).txt

[error] 486-486: Maven compiler error: incompatible types at DefaultGroupProvider.java:[486,50]. java.lang.String cannot be converted to org.xmpp.packet.JID.

🪛 GitHub Actions: Openfire CI / Build Openfire from source (macos-latest, 17, zulu)

[error] 486-486: Maven Compiler Plugin failed: incompatible types at line 486, column 50. Error: java.lang.String cannot be converted to org.xmpp.packet.JID.

🪛 GitHub Actions: Openfire CI / Build Openfire from source (macos-latest, 21, zulu)

[error] 486-486: maven-compiler-plugin compilation error: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID

🪛 GitHub Actions: Openfire CI / Build Openfire from source (ubuntu-latest, 17, zulu)

[error] 486-486: maven-compiler-plugin compilation failed: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID

🪛 GitHub Actions: Openfire CI / Build Openfire from source (ubuntu-latest, 21, zulu)

[error] 486-486: Maven compiler failed (maven-compiler-plugin:3.15.0:compile). Compilation error: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID.

🪛 GitHub Actions: Openfire CI / Build Openfire from source (ubuntu-latest, 25, zulu)

[error] 486-486: Maven compiler failed in org.apache.maven.plugins:maven-compiler-plugin:3.15.0:compile (default-compile) with error: incompatible types: java.lang.String cannot be converted to org.xmpp.packet.JID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xmppserver/src/main/java/org/jivesoftware/openfire/group/DefaultGroupProvider.java`
around lines 484 - 490, The call to server.matchesComponent currently passes the
String user; change it to pass a JID by constructing a JID from the user String
for the component check inside DefaultGroupProvider.loadMembersAndAdmins:
parse/construct a JID (new JID(user) or equivalent) and use that JID when
calling XMPPServer.matchesComponent(jid), while keeping server.createJID(user,
null) for the normal local-username path and assigning userJID appropriately
(userJID = server.createJID(user, null) for local usernames, otherwise new
JID(user) for full JIDs/components).

Comment on lines +106 to 110
List<JID> members = new ArrayList<>();
List<JID> administrators = new ArrayList<>();
loadMembersAndAdmins(name, members, administrators);

return new Group(name, "", members, administrators);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under what circumstances would a group already have members?

Comment on lines +538 to +544
if (userJID != null) {
if (isAdmin) {
administrators.add(userJID);
} else {
members.add(userJID);
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these populate temporary lists until the db iteration is complete and error free, then mutate the original?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g.

List<JID> tmpMembers = new ArrayList<>();
List<JID> tmpAdmins = new ArrayList<>();
// fill tmp lists from ResultSet...
// on success:
members.addAll(tmpMembers);
administrators.addAll(tmpAdmins);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. the main idea was to populate the list until db iteration is complete then mutate the original.

@MilanTyagi2004

Copy link
Copy Markdown
Collaborator Author

@Fishbowler
Apology for the delayed response.

This PR is under resolving state i am working on it.

@MilanTyagi2004

Copy link
Copy Markdown
Collaborator Author

you can review my other PRs
Thanks and DOAP file is also under resolving state.

thanks for the point issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants