001: /**
002: * $RCSfile$
003: * $Revision: $
004: * $Date: $
005: *
006: * Copyright (C) 2006 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.openfire.privacy;
011:
012: import org.dom4j.Element;
013: import org.dom4j.io.SAXReader;
014: import org.jivesoftware.database.DbConnectionManager;
015: import org.jivesoftware.util.Log;
016:
017: import java.io.StringReader;
018: import java.sql.Connection;
019: import java.sql.PreparedStatement;
020: import java.sql.ResultSet;
021: import java.util.Collections;
022: import java.util.HashMap;
023: import java.util.Map;
024: import java.util.concurrent.BlockingQueue;
025: import java.util.concurrent.LinkedBlockingQueue;
026: import java.util.concurrent.atomic.AtomicInteger;
027:
028: /**
029: * Provider for the privacy lists system. Privacy lists are read and written
030: * from the <tt>jivePrivacyList</tt> database table.
031: *
032: * @author Gaston Dombiak
033: */
034: public class PrivacyListProvider {
035:
036: private static final String PRIVACY_LIST_COUNT = "SELECT count(*) from jivePrivacyList";
037: private static final String LOAD_LIST_NAMES = "SELECT name, isDefault FROM jivePrivacyList WHERE username=?";
038: private static final String LOAD_PRIVACY_LIST = "SELECT isDefault, list FROM jivePrivacyList WHERE username=? AND name=?";
039: private static final String LOAD_DEFAULT_PRIVACY_LIST = "SELECT name, list FROM jivePrivacyList WHERE username=? AND isDefault=1";
040: private static final String DELETE_PRIVACY_LIST = "DELETE FROM jivePrivacyList WHERE username=? AND name=?";
041: private static final String DELETE_PRIVACY_LISTS = "DELETE FROM jivePrivacyList WHERE username=?";
042: private static final String UPDATE_PRIVACY_LIST = "UPDATE jivePrivacyList SET isDefault=?, list=? WHERE username=? AND name=?";
043: private static final String INSERT_PRIVACY_LIST = "INSERT INTO jivePrivacyList (username, name, isDefault, list) VALUES (?, ?, ?, ?)";
044:
045: /**
046: * Pool of SAX Readers. SAXReader is not thread safe so we need to have a pool of readers.
047: */
048: private BlockingQueue<SAXReader> xmlReaders = new LinkedBlockingQueue<SAXReader>();
049:
050: /**
051: * Stores the total number of privacy lists.
052: */
053: private AtomicInteger privacyListCount;
054:
055: public PrivacyListProvider() {
056: super ();
057: // Initialize the pool of sax readers
058: for (int i = 0; i < 50; i++) {
059: SAXReader xmlReader = new SAXReader();
060: xmlReader.setEncoding("UTF-8");
061: xmlReaders.add(xmlReader);
062: }
063:
064: // Load the total number of privacy lists in the database. We're looking
065: // for the (very common) special case that there are no privacy lists stored.
066: // In that case, we can optimize away many database calls. In the future, a
067: // better general-case solution may be to cache all privacy lists defined
068: // if there are less than, say, 500.
069: privacyListCount = new AtomicInteger(0);
070: loadPrivacyListCount();
071: }
072:
073: /**
074: * Returns the names of the existing privacy lists indicating which one is the
075: * default privacy list associated to a user.
076: *
077: * @param username the username of the user to get his privacy lists names.
078: * @return the names of the existing privacy lists with a default flag.
079: */
080: public Map<String, Boolean> getPrivacyLists(String username) {
081: // If there are no privacy lists stored, this method is a no-op.
082: if (privacyListCount.get() == 0) {
083: return Collections.emptyMap();
084: }
085:
086: Map<String, Boolean> names = new HashMap<String, Boolean>();
087: Connection con = null;
088: PreparedStatement pstmt = null;
089: ResultSet rs = null;
090: try {
091: con = DbConnectionManager.getConnection();
092: pstmt = con.prepareStatement(LOAD_LIST_NAMES);
093: pstmt.setString(1, username);
094: rs = pstmt.executeQuery();
095: while (rs.next()) {
096: names.put(rs.getString(1), rs.getInt(2) == 1);
097: }
098: } catch (Exception e) {
099: Log.error(
100: "Error loading names of privacy lists for username: "
101: + username, e);
102: } finally {
103: DbConnectionManager.closeConnection(rs, pstmt, con);
104: }
105: return names;
106: }
107:
108: /**
109: * Loads the requested privacy list from the database. Returns <tt>null</tt> if a list
110: * with the specified name does not exist.
111: *
112: * @param username the username of the user to get his privacy list.
113: * @param listName name of the list to load.
114: * @return the privacy list with the specified name or <tt>null</tt> if a list
115: * with the specified name does not exist.
116: */
117: public PrivacyList loadPrivacyList(String username, String listName) {
118: // If there are no privacy lists stored, this method is a no-op.
119: if (privacyListCount.get() == 0) {
120: return null;
121: }
122:
123: boolean isDefault = false;
124: String listValue = null;
125:
126: Connection con = null;
127: PreparedStatement pstmt = null;
128: ResultSet rs = null;
129:
130: try {
131: con = DbConnectionManager.getConnection();
132: pstmt = con.prepareStatement(LOAD_PRIVACY_LIST);
133: pstmt.setString(1, username);
134: pstmt.setString(2, listName);
135: rs = pstmt.executeQuery();
136: if (rs.next()) {
137: isDefault = rs.getInt(1) == 1;
138: listValue = rs.getString(2);
139: } else {
140: return null;
141: }
142: } catch (Exception e) {
143: Log.error("Error loading privacy list: " + listName
144: + " of username: " + username, e);
145: return null;
146: } finally {
147: DbConnectionManager.closeConnection(rs, pstmt, con);
148: }
149:
150: PrivacyList privacyList = null;
151: SAXReader xmlReader = null;
152: try {
153: // Get a sax reader from the pool
154: xmlReader = xmlReaders.take();
155: Element listElement = xmlReader.read(
156: new StringReader(listValue)).getRootElement();
157: privacyList = new PrivacyList(username, listName,
158: isDefault, listElement);
159: } catch (Exception e) {
160: Log.error(e);
161: } finally {
162: // Return the sax reader to the pool
163: if (xmlReader != null) {
164: xmlReaders.add(xmlReader);
165: }
166: }
167:
168: return privacyList;
169: }
170:
171: /**
172: * Loads the default privacy list of a given user from the database. Returns <tt>null</tt>
173: * if no list was found.
174: *
175: * @param username the username of the user to get his default privacy list.
176: * @return the default privacy list or <tt>null</tt> if no list was found.
177: */
178: public PrivacyList loadDefaultPrivacyList(String username) {
179: // If there are no privacy lists stored, this method is a no-op.
180: if (privacyListCount.get() == 0) {
181: return null;
182: }
183:
184: String listName = null;
185: String listValue = null;
186:
187: Connection con = null;
188: PreparedStatement pstmt = null;
189: ResultSet rs = null;
190: try {
191: con = DbConnectionManager.getConnection();
192: pstmt = con.prepareStatement(LOAD_DEFAULT_PRIVACY_LIST);
193: pstmt.setString(1, username);
194: rs = pstmt.executeQuery();
195: if (rs.next()) {
196: listName = rs.getString(1);
197: listValue = rs.getString(2);
198: } else {
199: return null;
200: }
201: } catch (Exception e) {
202: Log.error(
203: "Error loading default privacy list of username: "
204: + username, e);
205: return null;
206: } finally {
207: DbConnectionManager.closeConnection(rs, pstmt, con);
208: }
209:
210: PrivacyList privacyList = null;
211: SAXReader xmlReader = null;
212: try {
213: // Get a sax reader from the pool
214: xmlReader = xmlReaders.take();
215: Element listElement = xmlReader.read(
216: new StringReader(listValue)).getRootElement();
217: privacyList = new PrivacyList(username, listName, true,
218: listElement);
219: } catch (Exception e) {
220: Log.error(e);
221: } finally {
222: // Return the sax reader to the pool
223: if (xmlReader != null) {
224: xmlReaders.add(xmlReader);
225: }
226: }
227:
228: return privacyList;
229: }
230:
231: /**
232: * Creates and saves the new privacy list to the database.
233: *
234: * @param username the username of the user that created a new privacy list.
235: * @param list the PrivacyList to save.
236: */
237: public void createPrivacyList(String username, PrivacyList list) {
238: Connection con = null;
239: PreparedStatement pstmt = null;
240: try {
241: con = DbConnectionManager.getConnection();
242: pstmt = con.prepareStatement(INSERT_PRIVACY_LIST);
243: pstmt.setString(1, username);
244: pstmt.setString(2, list.getName());
245: pstmt.setInt(3, (list.isDefault() ? 1 : 0));
246: pstmt.setString(4, list.asElement().asXML());
247: pstmt.executeUpdate();
248: } catch (Exception e) {
249: Log.error("Error adding privacy list: " + list.getName()
250: + " of username: " + username, e);
251: } finally {
252: DbConnectionManager.closeConnection(pstmt, con);
253: }
254: // Set the privacy list count to -1. We don't know how many privacy lists there
255: // are, but it's not "0", which is the case we care about.
256: privacyListCount.set(-1);
257: }
258:
259: /**
260: * Updated the existing privacy list in the database.
261: *
262: * @param username the username of the user that updated a privacy list.
263: * @param list the PrivacyList to update in the database.
264: */
265: public void updatePrivacyList(String username, PrivacyList list) {
266: Connection con = null;
267: PreparedStatement pstmt = null;
268: try {
269: con = DbConnectionManager.getConnection();
270: pstmt = con.prepareStatement(UPDATE_PRIVACY_LIST);
271: pstmt.setInt(1, (list.isDefault() ? 1 : 0));
272: pstmt.setString(2, list.asElement().asXML());
273: pstmt.setString(3, username);
274: pstmt.setString(4, list.getName());
275: pstmt.executeUpdate();
276: } catch (Exception e) {
277: Log.error("Error updating privacy list: " + list.getName()
278: + " of username: " + username, e);
279: } finally {
280: DbConnectionManager.closeConnection(pstmt, con);
281: }
282: }
283:
284: /**
285: * Deletes an existing privacy list from the database.
286: *
287: * @param username the username of the user that deleted a privacy list.
288: * @param listName the name of the PrivacyList to delete.
289: */
290: public void deletePrivacyList(String username, String listName) {
291: // If there are no privacy lists stored, this method is a no-op.
292: if (privacyListCount.get() == 0) {
293: return;
294: }
295: Connection con = null;
296: PreparedStatement pstmt = null;
297: try {
298: con = DbConnectionManager.getConnection();
299: pstmt = con.prepareStatement(DELETE_PRIVACY_LIST);
300: pstmt.setString(1, username);
301: pstmt.setString(2, listName);
302: pstmt.executeUpdate();
303: } catch (Exception e) {
304: Log.error("Error deleting privacy list: " + listName
305: + " of username: " + username, e);
306: } finally {
307: DbConnectionManager.closeConnection(pstmt, con);
308: }
309: // Set the privacy list count to -1. We don't know how many privacy lists there
310: // are, but it's probably not "0", which is the case we care about.
311: privacyListCount.set(-1);
312: }
313:
314: /**
315: * Deletes all existing privacy list from the database for the given user.
316: *
317: * @param username the username of the user whose privacy lists are going to be deleted.
318: */
319: public void deletePrivacyLists(String username) {
320: // If there are no privacy lists stored, this method is a no-op.
321: if (privacyListCount.get() == 0) {
322: return;
323: }
324: Connection con = null;
325: PreparedStatement pstmt = null;
326: try {
327: con = DbConnectionManager.getConnection();
328: pstmt = con.prepareStatement(DELETE_PRIVACY_LISTS);
329: pstmt.setString(1, username);
330: pstmt.executeUpdate();
331: } catch (Exception e) {
332: Log.error("Error deleting privacy lists of username: "
333: + username, e);
334: } finally {
335: DbConnectionManager.closeConnection(pstmt, con);
336: }
337: // Set the privacy list count to -1. We don't know how many privacy lists there
338: // are, but it's probably not "0", which is the case we care about.
339: privacyListCount.set(-1);
340: }
341:
342: /**
343: * Loads the total number of privacy lists stored in the database.
344: */
345: private void loadPrivacyListCount() {
346: Connection con = null;
347: PreparedStatement pstmt = null;
348: ResultSet rs = null;
349: try {
350: con = DbConnectionManager.getConnection();
351: pstmt = con.prepareStatement(PRIVACY_LIST_COUNT);
352: rs = pstmt.executeQuery();
353: rs.next();
354: privacyListCount.set(rs.getInt(1));
355: } catch (Exception e) {
356: Log.error(e);
357: } finally {
358: DbConnectionManager.closeConnection(rs, pstmt, con);
359: }
360: }
361: }
|