PrivateStorage.java 5.98 KB
Newer Older
Matt Tucker's avatar
Matt Tucker committed
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision$
 * $Date$
 *
Matt Tucker's avatar
Matt Tucker committed
6
 * Copyright (C) 2004 Jive Software. All rights reserved.
Matt Tucker's avatar
Matt Tucker committed
7
 *
Matt Tucker's avatar
Matt Tucker committed
8 9
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
Matt Tucker's avatar
Matt Tucker committed
10
 */
Matt Tucker's avatar
Matt Tucker committed
11

12
package org.jivesoftware.messenger;
Matt Tucker's avatar
Matt Tucker committed
13 14

import org.jivesoftware.messenger.container.BasicModule;
15
import org.jivesoftware.database.DbConnectionManager;
Matt Tucker's avatar
Matt Tucker committed
16
import org.jivesoftware.util.Log;
17 18 19
import org.jivesoftware.util.LocaleUtils;
import org.dom4j.Element;
import org.dom4j.Document;
Matt Tucker's avatar
Matt Tucker committed
20
import org.dom4j.io.SAXReader;
Matt Tucker's avatar
Matt Tucker committed
21

22
import java.sql.*;
Matt Tucker's avatar
Matt Tucker committed
23
import java.sql.Connection;
24
import java.io.StringWriter;
25
import java.io.StringReader;
Matt Tucker's avatar
Matt Tucker committed
26 27

/**
28 29
 * Private storage for user accounts (JEP-0049). It is used by some XMPP systems
 * for saving client settings on the server.
Matt Tucker's avatar
Matt Tucker committed
30 31 32
 *
 * @author Iain Shigeoka
 */
33
public class PrivateStorage extends BasicModule {
Matt Tucker's avatar
Matt Tucker committed
34

35
    private static final String LOAD_PRIVATE =
36
        "SELECT value FROM jivePrivate WHERE username=? AND namespace=?";
37
    private static final String INSERT_PRIVATE =
38
        "INSERT INTO jivePrivate (value,name,username,namespace) VALUES (?,?,?,?)";
39
    private static final String UPDATE_PRIVATE =
40
        "UPDATE jivePrivate SET value=?, name=? WHERE username=? AND namespace=?";
Matt Tucker's avatar
Matt Tucker committed
41

42 43 44 45
    // Currently no delete supported, we can detect an add of an empty element and
    // use that to signal a delete but that optimization doesn't seem necessary.
    // private static final String DELETE_PRIVATE =
    //     "DELETE FROM jivePrivate WHERE userID=? AND name=? AND namespace=?";
Matt Tucker's avatar
Matt Tucker committed
46

47
    private boolean enabled = JiveGlobals.getBooleanProperty("xmpp.privateStorageEnabled", true);
Matt Tucker's avatar
Matt Tucker committed
48

Matt Tucker's avatar
Matt Tucker committed
49 50
    SAXReader xmlReader = new SAXReader();

51 52 53 54
    /**
     * Constructs a new PrivateStore instance.
     */
    public PrivateStorage() {
Matt Tucker's avatar
Matt Tucker committed
55 56 57
        super("Private user data storage");
    }

58 59 60 61 62
    /**
     * Returns true if private storage is enabled.
     *
     * @return true if private storage is enabled.
     */
Matt Tucker's avatar
Matt Tucker committed
63 64 65 66
    public boolean isEnabled() {
        return enabled;
    }

67 68 69 70 71
    /**
     * Sets whether private storage is enabled.
     *
     * @param enabled true if this private store is enabled.
     */
Matt Tucker's avatar
Matt Tucker committed
72
    public void setEnabled(boolean enabled) {
73 74
        this.enabled = enabled;
        JiveGlobals.setProperty("xmpp.privateStorageEnabled", Boolean.toString(enabled));
Matt Tucker's avatar
Matt Tucker committed
75 76
    }

77 78 79 80 81 82 83 84
    /**
     * Stores private data. If the name and namespace of the element matches another
     * stored private data XML document, then replace it with the new one.
     *
     * @param data the data to store (XML element)
     * @param username the username of the account where private data is being stored
     */
    public void add(String username, Element data) {
Matt Tucker's avatar
Matt Tucker committed
85
        if (enabled) {
86
            java.sql.Connection con = null;
Matt Tucker's avatar
Matt Tucker committed
87 88 89 90 91 92
            PreparedStatement pstmt = null;
            try {
                StringWriter writer = new StringWriter();
                data.write(writer);
                con = DbConnectionManager.getConnection();
                pstmt = con.prepareStatement(LOAD_PRIVATE);
93
                pstmt.setString(1, username);
Matt Tucker's avatar
Matt Tucker committed
94 95
                pstmt.setString(2, data.getNamespaceURI());
                ResultSet rs = pstmt.executeQuery();
96
                boolean update = false;
Matt Tucker's avatar
Matt Tucker committed
97
                if (rs.next()) {
98 99 100 101
                    update = true;
                }
                rs.close();
                pstmt.close();
102

103
                if (update) {
Matt Tucker's avatar
Matt Tucker committed
104 105 106 107 108 109 110
                    pstmt = con.prepareStatement(UPDATE_PRIVATE);
                }
                else {
                    pstmt = con.prepareStatement(INSERT_PRIVATE);
                }
                pstmt.setString(1, writer.toString());
                pstmt.setString(2, data.getName());
111
                pstmt.setString(3, username);
Matt Tucker's avatar
Matt Tucker committed
112
                pstmt.setString(4, data.getNamespaceURI());
Derek DeMoro's avatar
Derek DeMoro committed
113
                pstmt.executeUpdate();
Matt Tucker's avatar
Matt Tucker committed
114 115 116 117 118
            }
            catch (Exception e) {
                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
            }
            finally {
119 120 121 122
                try { if (pstmt != null) { pstmt.close(); } }
                catch (Exception e) { Log.error(e); }
                try { if (con != null) { con.close(); } }
                catch (Exception e) { Log.error(e); }
Matt Tucker's avatar
Matt Tucker committed
123 124 125 126
            }
        }
    }

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    /**
     * Returns the data stored under a key corresponding to the name and namespace
     * of the given element. The Element must be in the form:<p>
     *
     * <code>&lt;name xmlns='namespace'/&gt;</code><p>
     *
     * If no data is currently stored under the given key, an empty element will be
     * returned.
     *
     * @param data an XML document who's element name and namespace is used to
     *      match previously stored private data.
     * @param username the username of the account where private data is being stored.
     * @return the data stored under the given key or the data element.
     */
    public Element get(String username, Element data) {
Matt Tucker's avatar
Matt Tucker committed
142 143 144 145 146 147
        if (enabled) {
            Connection con = null;
            PreparedStatement pstmt = null;
            try {
                con = DbConnectionManager.getConnection();
                pstmt = con.prepareStatement(LOAD_PRIVATE);
148
                pstmt.setString(1, username);
Matt Tucker's avatar
Matt Tucker committed
149 150 151
                pstmt.setString(2, data.getNamespaceURI());
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
Gaston Dombiak's avatar
Gaston Dombiak committed
152
                    data.clearContent();
Matt Tucker's avatar
Matt Tucker committed
153
                    String result = rs.getString(1).trim();
154
                    Document doc = xmlReader.read(new StringReader(result));
155
                    data = doc.getRootElement();
Matt Tucker's avatar
Matt Tucker committed
156
                }
157
                rs.close();
Matt Tucker's avatar
Matt Tucker committed
158 159 160 161 162
            }
            catch (Exception e) {
                Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
            }
            finally {
163 164 165 166
                try { if (pstmt != null) { pstmt.close(); } }
                catch (Exception e) { Log.error(e); }
                try { if (con != null) { con.close(); } }
                catch (Exception e) { Log.error(e); }
Matt Tucker's avatar
Matt Tucker committed
167 168 169 170
            }
        }
        return data;
    }
171
}