Commit 820cd403 authored by Guus der Kinderen's avatar Guus der Kinderen

OF-1515: Migrate Private XML storage to PEP.

Openfire supports XEP-0049, Private XML Storage. However, Openfire can also be used for
XEP-0223: Persistent Storage of Private Data via PubSub. When a user previously used more
than one client, where each client would use a different XEP to store private data, the
private data that was stored by one client would not be shared with the other client. This
is undesirable, as such data typically includes data that benefits every client used by the
user.

In this commit, all data that is stored in the Private XML Storage database table will be
migrated to PEP. After a successful migration, the old database table is deleted.

Openfire continues to offer XEP-0049: Private XML Storage functionality. However, whenever
data is obtained or modified through methods defined in that XEP, the PEP data is modified.
parent d16c186d
......@@ -35,15 +35,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime ASC);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime ASC);
CREATE TABLE ofPrivate (
username VARCHAR(64) NOT NULL,
name VARCHAR(100) NOT NULL,
namespace VARCHAR(200) NOT NULL,
privateData VARCHAR(2000) NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username VARCHAR(64) NOT NULL,
messageID INTEGER NOT NULL,
......@@ -393,7 +384,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
-- Entry for admin user
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -35,15 +35,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime);
CREATE TABLE ofPrivate (
username VARCHAR(64) NOT NULL,
name VARCHAR(100) NOT NULL,
namespace VARCHAR(200) NOT NULL,
privateData LONGVARCHAR NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username VARCHAR(64) NOT NULL,
messageID BIGINT NOT NULL,
......@@ -379,7 +370,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
// Entry for admin user
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -32,14 +32,6 @@ CREATE TABLE ofUserFlag (
INDEX ofUserFlag_eTime_idx (endTime)
);
CREATE TABLE ofPrivate (
username VARCHAR(64) NOT NULL,
name VARCHAR(100) NOT NULL,
namespace VARCHAR(200) NOT NULL,
privateData TEXT NOT NULL,
PRIMARY KEY (username, name, namespace(100))
);
CREATE TABLE ofOffline (
username VARCHAR(64) NOT NULL,
messageID BIGINT NOT NULL,
......@@ -368,7 +360,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
# Entry for admin user
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -35,15 +35,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime ASC);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime ASC);
CREATE TABLE ofPrivate (
username VARCHAR2(64) NOT NULL,
name VARCHAR2(100) NOT NULL,
namespace VARCHAR2(200) NOT NULL,
privateData LONG NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username VARCHAR2(64) NOT NULL,
messageID INTEGER NOT NULL,
......@@ -377,7 +368,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
-- Entry for admin user
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -37,15 +37,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime);
CREATE TABLE ofPrivate (
username VARCHAR(64) NOT NULL,
name VARCHAR(100) NOT NULL,
namespace VARCHAR(200) NOT NULL,
privateData TEXT NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username VARCHAR(64) NOT NULL,
messageID INTEGER NOT NULL,
......@@ -385,7 +376,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
-- Entry for admin user
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -35,15 +35,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime ASC);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime ASC);
CREATE TABLE ofPrivate (
username NVARCHAR(64) NOT NULL,
name NVARCHAR(100) NOT NULL,
namespace NVARCHAR(200) NOT NULL,
privateData NTEXT NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username NVARCHAR(64) NOT NULL,
messageID INTEGER NOT NULL,
......@@ -382,7 +373,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
/* Entry for admin user */
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
......@@ -35,15 +35,6 @@ CREATE INDEX ofUserFlag_sTime_idx ON ofUserFlag (startTime ASC);
CREATE INDEX ofUserFlag_eTime_idx ON ofUserFlag (endTime ASC);
CREATE TABLE ofPrivate (
username NVARCHAR(64) NOT NULL,
name NVARCHAR(100) NOT NULL,
namespace NVARCHAR(200) NOT NULL,
privateData TEXT NOT NULL,
CONSTRAINT ofPrivate_pk PRIMARY KEY (username, name, namespace)
);
CREATE TABLE ofOffline (
username NVARCHAR(64) NOT NULL,
messageID INTEGER NOT NULL,
......@@ -383,7 +374,7 @@ INSERT INTO ofID (idType, id) VALUES (19, 1);
INSERT INTO ofID (idType, id) VALUES (23, 1);
INSERT INTO ofID (idType, id) VALUES (26, 2);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 26);
INSERT INTO ofVersion (name, version) VALUES ('openfire', 28);
/* Entry for admin user */
INSERT INTO ofUser (username, plainPassword, name, email, creationDate, modificationDate)
......
-- The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java
-- Update version
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
// The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java
// Update version
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
# The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java
# Update version
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
-- The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java
-- Update version
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
COMMIT;
-- The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java
-- Update version
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
/* The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java */
/* Update version */
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
/* The database update has been implemented in org.jivesoftware.database.bugfix.OF1515.java */
/* Update version */
UPDATE ofVersion SET version = 27 WHERE name = 'openfire';
-- Only when the update in 27 succeeded, drop the table that was used as its source.
DROP TABLE ofPrivate;
-- Update version
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
// Only when the update in 27 succeeded, drop the table that was used as its source.
DROP TABLE ofPrivate;
// Update version
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
# Only when the update in 27 succeeded, drop the table that was used as its source.
DROP TABLE ofPrivate;
# Update version
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
-- Only when the update in 27 succeeded, drop the table that was used as its source.
DROP TABLE ofPrivate;
-- Update version
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
COMMIT;
-- Only when the update in 27 succeeded, drop the table that was used as its source.
DROP TABLE ofPrivate;
-- Update version
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
/* Only when the update in 27 succeeded, drop the table that was used as its source. */
DROP TABLE ofPrivate;
/* Update version */
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
/* Only when the update in 27 succeeded, drop the table that was used as its source. */
DROP TABLE ofPrivate;
/* Update version */
UPDATE ofVersion SET version = 28 WHERE name = 'openfire';
......@@ -30,6 +30,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import org.jivesoftware.database.bugfix.OF1515;
import org.jivesoftware.database.bugfix.OF33;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
......@@ -66,7 +67,7 @@ public class SchemaManager {
/**
* Current Openfire database schema version.
*/
private static final int DATABASE_VERSION = 26;
private static final int DATABASE_VERSION = 28;
/**
* Checks the Openfire database schema to ensure that it's installed and up to date.
......@@ -270,6 +271,9 @@ public class SchemaManager {
if (i == 21 && schemaKey.equals("openfire")) {
OF33.executeFix(con);
}
if (i == 27 && schemaKey.equals("openfire")) {
OF1515.executeFix();
}
} catch (Exception e) {
Log.error(e.getMessage(), e);
return false;
......
This diff is collapsed.
......@@ -56,6 +56,18 @@ public class PEPServiceManager {
private PubSubEngine pubSubEngine = null;
/**
* Retrieves a PEP service -- attempting first from memory, then from the
* database.
*
* @param jid
* the JID of the user that owns the PEP service.
* @return the requested PEP service if found or null if not found.
*/
public PEPService getPEPService(JID jid) {
return getPEPService( jid.toBareJID() );
}
/**
* Retrieves a PEP service -- attempting first from memory, then from the
* database.
......
......@@ -336,7 +336,7 @@ public class PubSubEngine {
if (node == null) {
if (service instanceof PEPService && service.isServiceAdmin(owner) && canAutoCreate( publishOptions ) ) {
// If it is a PEP service & publisher is service owner - auto create nodes.
CreateNodeResponse response = createNodeHelper(service, iq, iq.getChildElement(), publishElement, publishOptions);
CreateNodeResponse response = createNodeHelper(service, iq.getFrom(), iq.getChildElement().element("configure"), publishElement.attributeValue("node"), publishOptions);
if (response.newNode == null) {
// New node creation failed. Since pep#auto-create is advertised
......@@ -1238,7 +1238,7 @@ public class PubSubEngine {
private void createNode(PubSubService service, IQ iq, Element childElement, Element createElement, DataForm publishOptions) {
// Call createNodeHelper and get the node creation status.
CreateNodeResponse response = createNodeHelper(service, iq, childElement, createElement, publishOptions);
CreateNodeResponse response = createNodeHelper(service, iq.getFrom(), childElement.element("configure"), createElement.attributeValue("node"), publishOptions);
if (response.newNode == null) {
// New node creation failed
sendErrorPacket(iq, response.creationStatus, response.pubsubError);
......@@ -1258,7 +1258,7 @@ public class PubSubEngine {
/**
* Response Object returned by createNodeHelper method
*/
private class CreateNodeResponse {
public static class CreateNodeResponse {
public final PacketError.Condition creationStatus;
public final Node newNode;
public final Element pubsubError;
......@@ -1281,19 +1281,21 @@ public class PubSubEngine {
* <br/>NOTE 2: This method calls UserManager::isRegisteredUser(JID) which can block waiting for a response - so
* do not call this method in the same thread in which a response might arrive
*
* @param service The service instance that's responsible for processing (cannot be null)
* @param requester The (full) JID of the entity that performs the action (cannot be null)
* @param configuration Optional Configuration dataform, if user requested to configure the node (can be null)
* @param nodeID The ID of the node to be created, or null when an instant node is to be created.
* @param publishOptions Optional Publishing Options, which are either preconditions or configuration overrides (can be null)
* @return {@link CreateNodeResponse}
*/
private CreateNodeResponse createNodeHelper(PubSubService service, IQ iq, Element childElement, Element createElement, DataForm publishOptions) {
// Get sender of the IQ packet
JID from = iq.getFrom();
public static CreateNodeResponse createNodeHelper(PubSubService service, JID requester, Element configuration, String nodeID, DataForm publishOptions) {
// Verify that sender has permissions to create nodes
if (!service.canCreateNode(from) || (!isComponent(from) && !UserManager.getInstance().isRegisteredUser(from))) {
if (!service.canCreateNode(requester) || (!isComponent(requester) && !UserManager.getInstance().isRegisteredUser(requester))) {
// The user is not allowed to create nodes so return an error
return new CreateNodeResponse(PacketError.Condition.forbidden, null, null);
}
DataForm completedForm = null;
CollectionNode parentNode = null;
String nodeID = createElement.attributeValue("node");
String newNodeID = nodeID;
if (nodeID == null) {
// User requested an instant node
......@@ -1312,11 +1314,11 @@ public class PubSubEngine {
while (service.getNode(newNodeID) != null);
}
boolean collectionType = false;
// Check if user requested to configure the node (using a data form)
Element configureElement = childElement.element("configure");
if (configureElement != null) {
if (configuration!= null) {
// Get the data form that contains the parent nodeID
completedForm = getSentConfigurationForm( configureElement );
completedForm = getSentConfigurationForm( configuration );
}
if (publishOptions != null) {
......@@ -1384,7 +1386,7 @@ public class PubSubEngine {
if (parentNode != null && !collectionType) {
// Check if requester is allowed to add a new leaf child node to the parent node
if (!parentNode.isAssociationAllowed(from)) {
if (!parentNode.isAssociationAllowed(requester)) {
// User is not allowed to add child leaf node to parent node. Return an error.
return new CreateNodeResponse(PacketError.Condition.forbidden, null, null);
}
......@@ -1402,15 +1404,15 @@ public class PubSubEngine {
Node newNode = null;
try {
// TODO Assumed that the owner of the subscription is the bare JID of the subscription JID. Waiting StPeter answer for explicit field.
JID owner = from.asBareJID();
JID owner = requester.asBareJID();
synchronized (newNodeID.intern()) {
if (service.getNode(newNodeID) == null) {
// Create the node
if (collectionType) {
newNode = new CollectionNode(service, parentNode, newNodeID, from);
newNode = new CollectionNode(service, parentNode, newNodeID, requester);
}
else {
newNode = new LeafNode(service, parentNode, newNodeID, from);
newNode = new LeafNode(service, parentNode, newNodeID, requester);
}
// Add the creator as the node owner
newNode.addOwner(owner);
......@@ -1863,7 +1865,7 @@ public class PubSubEngine {
* @return the data form included in the configure element sent by the node owner or
* <tt>null</tt> if none was included or access model was defined.
*/
private DataForm getSentConfigurationForm(Element configureElement) {
private static DataForm getSentConfigurationForm(Element configureElement) {
DataForm completedForm = null;
FormField formField;
Element formElement = configureElement.element(QName.get("x", "jabber:x:data"));
......@@ -2048,7 +2050,7 @@ public class PubSubEngine {
* @param jid
* @return <tt>true</tt> if the JID is a component, <tt>false<.tt> if not.
*/
private boolean isComponent(JID jid) {
private static boolean isComponent(JID jid) {
final RoutingTable routingTable = XMPPServer.getInstance().getRoutingTable();
if (routingTable != null) {
return routingTable.hasComponentRoute(jid);
......@@ -2061,7 +2063,7 @@ public class PubSubEngine {
* @param jid the JID representing the remote server
* @return true if the supplied JID is a connected server session
*/
private boolean isRemoteServer(final JID jid) {
private static boolean isRemoteServer(final JID jid) {
final String jidString = jid.toString();
final SessionManager sessionManager = SessionManager.getInstance();
for (final String incomingServer : sessionManager.getIncomingServers()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment