org.jivesoftware.openfire.group.DefaultGroupProvider Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.group;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.openfire.XMPPServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.JID;
/**
* Database implementation of the GroupManager interface.
*
* @author Matt Tucker
*/
public class DefaultGroupProvider extends AbstractGroupProvider {
private static final Logger Log = LoggerFactory.getLogger(DefaultGroupProvider.class);
private static final String INSERT_GROUP =
"INSERT INTO ofGroup (groupName, description) VALUES (?, ?)";
private static final String SAVE_GROUP =
"UPDATE ofGroup SET description=? WHERE groupName=?";
private static final String SET_GROUP_NAME_1 =
"UPDATE ofGroup SET groupName=? WHERE groupName=?";
private static final String SET_GROUP_NAME_2 =
"UPDATE ofGroupProp SET groupName=? WHERE groupName=?";
private static final String SET_GROUP_NAME_3 =
"UPDATE ofGroupUser SET groupName=? WHERE groupName=?";
private static final String DELETE_GROUP_USERS =
"DELETE FROM ofGroupUser WHERE groupName=?";
private static final String DELETE_PROPERTIES =
"DELETE FROM ofGroupProp WHERE groupName=?";
private static final String DELETE_GROUP =
"DELETE FROM ofGroup WHERE groupName=?";
private static final String GROUP_COUNT = "SELECT count(*) FROM ofGroup";
private static final String LOAD_ADMINS =
"SELECT username FROM ofGroupUser WHERE administrator=1 AND groupName=? ORDER BY username";
private static final String LOAD_MEMBERS =
"SELECT username FROM ofGroupUser WHERE administrator=0 AND groupName=? ORDER BY username";
private static final String LOAD_GROUP =
"SELECT description FROM ofGroup WHERE groupName=?";
private static final String REMOVE_USER =
"DELETE FROM ofGroupUser WHERE groupName=? AND username=?";
private static final String ADD_USER =
"INSERT INTO ofGroupUser (groupName, username, administrator) VALUES (?, ?, ?)";
private static final String UPDATE_USER =
"UPDATE ofGroupUser SET administrator=? WHERE groupName=? AND username=?";
private static final String USER_GROUPS =
"SELECT groupName FROM ofGroupUser WHERE username=?";
private static final String ALL_GROUPS = "SELECT groupName FROM ofGroup ORDER BY groupName";
private static final String SEARCH_GROUP_NAME = "SELECT groupName FROM ofGroup WHERE groupName LIKE ? ORDER BY groupName";
private XMPPServer server = XMPPServer.getInstance();
@Override
public Group createGroup(String name) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(INSERT_GROUP);
pstmt.setString(1, name);
pstmt.setString(2, "");
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
Collection members = getMembers(name, false);
Collection administrators = getMembers(name, true);
return new Group(name, "", members, administrators);
}
@Override
public Group getGroup(String name) throws GroupNotFoundException {
String description = null;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_GROUP);
pstmt.setString(1, name);
rs = pstmt.executeQuery();
if (!rs.next()) {
throw new GroupNotFoundException("Group with name "
+ name + " not found.");
}
description = rs.getString(1);
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
Collection members = getMembers(name, false);
Collection administrators = getMembers(name, true);
return new Group(name, description, members, administrators);
}
@Override
public void setDescription(String name, String description) throws GroupNotFoundException {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(SAVE_GROUP);
pstmt.setString(1, description);
pstmt.setString(2, name);
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
throw new GroupNotFoundException();
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
@Override
public void setName(String oldName, String newName) throws GroupAlreadyExistsException
{
Connection con = null;
PreparedStatement pstmt = null;
boolean abortTransaction = false;
try {
con = DbConnectionManager.getTransactionConnection();
pstmt = con.prepareStatement(SET_GROUP_NAME_1);
pstmt.setString(1, newName);
pstmt.setString(2, oldName);
pstmt.executeUpdate();
DbConnectionManager.fastcloseStmt(pstmt);
pstmt = con.prepareStatement(SET_GROUP_NAME_2);
pstmt.setString(1, newName);
pstmt.setString(2, oldName);
pstmt.executeUpdate();
DbConnectionManager.fastcloseStmt(pstmt);
pstmt = con.prepareStatement(SET_GROUP_NAME_3);
pstmt.setString(1, newName);
pstmt.setString(2, oldName);
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
abortTransaction = true;
}
finally {
DbConnectionManager.closeStatement(pstmt);
DbConnectionManager.closeTransactionConnection(con, abortTransaction);
}
}
@Override
public void deleteGroup(String groupName) {
Connection con = null;
PreparedStatement pstmt = null;
boolean abortTransaction = false;
try {
con = DbConnectionManager.getTransactionConnection();
// Remove all users in the group.
pstmt = con.prepareStatement(DELETE_GROUP_USERS);
pstmt.setString(1, groupName);
pstmt.executeUpdate();
DbConnectionManager.fastcloseStmt(pstmt);
// Remove all properties of the group.
pstmt = con.prepareStatement(DELETE_PROPERTIES);
pstmt.setString(1, groupName);
pstmt.executeUpdate();
DbConnectionManager.fastcloseStmt(pstmt);
// Remove the group entry.
pstmt = con.prepareStatement(DELETE_GROUP);
pstmt.setString(1, groupName);
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
abortTransaction = true;
}
finally {
DbConnectionManager.closeStatement(pstmt);
DbConnectionManager.closeTransactionConnection(con, abortTransaction);
}
}
@Override
public int getGroupCount() {
int count = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(GROUP_COUNT);
rs = pstmt.executeQuery();
if (rs.next()) {
count = rs.getInt(1);
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return count;
}
@Override
public Collection getGroupNames() {
List groupNames = new ArrayList<>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ALL_GROUPS);
rs = pstmt.executeQuery();
while (rs.next()) {
groupNames.add(rs.getString(1));
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con); }
return groupNames;
}
@Override
public Collection getGroupNames(int startIndex, int numResults) {
List groupNames = new ArrayList<>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = DbConnectionManager.createScrollablePreparedStatement(con, ALL_GROUPS);
rs = pstmt.executeQuery();
DbConnectionManager.scrollResultSet(rs, startIndex);
int count = 0;
while (rs.next() && count < numResults) {
groupNames.add(rs.getString(1));
count++;
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return groupNames;
}
@Override
public Collection getGroupNames(JID user) {
List groupNames = new ArrayList<>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(USER_GROUPS);
pstmt.setString(1, server.isLocal(user) ? user.getNode() : user.toString());
rs = pstmt.executeQuery();
while (rs.next()) {
groupNames.add(rs.getString(1));
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return groupNames;
}
@Override
public void addMember(String groupName, JID user, boolean administrator) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(ADD_USER);
pstmt.setString(1, groupName);
pstmt.setString(2, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.setInt(3, administrator ? 1 : 0);
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
@Override
public void updateMember(String groupName, JID user, boolean administrator) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(UPDATE_USER);
pstmt.setInt(1, administrator ? 1 : 0);
pstmt.setString(2, groupName);
pstmt.setString(3, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
@Override
public void deleteMember(String groupName, JID user) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(REMOVE_USER);
pstmt.setString(1, groupName);
pstmt.setString(2, server.isLocal(user) ? user.getNode() : user.toString());
pstmt.executeUpdate();
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(pstmt, con);
}
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public Collection search(String query) {
return search(query, 0, Integer.MAX_VALUE);
}
@Override
public Collection search(String query, int startIndex, int numResults) {
if (query == null || "".equals(query)) {
return Collections.emptyList();
}
// SQL LIKE queries don't map directly into a keyword/wildcard search like we want.
// Therefore, we do a best approximiation by replacing '*' with '%' and then
// surrounding the whole query with two '%'. This will return more data than desired,
// but is better than returning less data than desired.
query = "%" + query.replace('*', '%') + "%";
if (query.endsWith("%%")) {
query = query.substring(0, query.length()-1);
}
List groupNames = new ArrayList<>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
if ((startIndex==0) && (numResults==Integer.MAX_VALUE))
{
pstmt = con.prepareStatement(SEARCH_GROUP_NAME);
pstmt.setString(1, query);
rs = pstmt.executeQuery();
while (rs.next()) {
groupNames.add(rs.getString(1));
}
} else {
pstmt = DbConnectionManager.createScrollablePreparedStatement(con, SEARCH_GROUP_NAME);
DbConnectionManager.limitRowsAndFetchSize(pstmt, startIndex, numResults);
pstmt.setString(1, query);
rs = pstmt.executeQuery();
// Scroll to the start index.
DbConnectionManager.scrollResultSet(rs, startIndex);
int count = 0;
while (rs.next() && count < numResults) {
groupNames.add(rs.getString(1));
count++;
}
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return groupNames;
}
@Override
public boolean isSearchSupported() {
return true;
}
@Override
public boolean isSharingSupported() {
return true;
}
private Collection getMembers(String groupName, boolean adminsOnly) {
List members = new ArrayList<>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = DbConnectionManager.getConnection();
if (adminsOnly) {
pstmt = con.prepareStatement(LOAD_ADMINS);
}
else {
pstmt = con.prepareStatement(LOAD_MEMBERS);
}
pstmt.setString(1, groupName);
rs = pstmt.executeQuery();
while (rs.next()) {
String user = rs.getString(1);
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)) {
userJID = server.createJID(user, null);
}
}
else {
userJID = new JID(user);
}
members.add(userJID);
}
}
catch (SQLException e) {
Log.error(e.getMessage(), e);
}
finally {
DbConnectionManager.closeConnection(rs, pstmt, con);
}
return members;
}
}