Search in sources :

Example 1 with RefreshNodeTask

use of org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask in project Openfire by igniterealtime.

the class PubSubEngine method createNodeHelper.

/**
 * Checks if the following conditions are satisfied and creates a node
 * - Requester can create nodes
 * - Instant node creation is enabled
 * - Node does not already exist
 * - New node configuration is valid
 *
 * <br>NOTE 1: This method should not reply to the client
 * <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}
 */
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(requester) || (!isComponent(requester) && !UserManager.getInstance().isRegisteredUser(requester, true))) {
        // 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 newNodeID = nodeID;
    if (nodeID == null) {
        // User requested an instant node
        if (!service.isInstantNodeSupported()) {
            // Instant nodes creation is not allowed so return an error
            Element pubsubError = DocumentHelper.createElement(QName.get("nodeid-required", "http://jabber.org/protocol/pubsub#errors"));
            return new CreateNodeResponse(PacketError.Condition.not_acceptable, pubsubError, null);
        }
        do {
            // Create a new nodeID and make sure that the random generated string does not
            // match an existing node. Probability to match an existing node are very very low
            // but they exist :)
            newNodeID = StringUtils.randomString(15);
        } while (service.getNode(newNodeID) != null);
    }
    boolean collectionType = false;
    // Check if user requested to configure the node (using a data form)
    if (configuration != null) {
        // Get the data form that contains the parent nodeID
        completedForm = getSentConfigurationForm(configuration);
    }
    if (publishOptions != null) {
        // Apply publish options to override provided config.
        if (completedForm == null) {
            completedForm = publishOptions;
        } else {
            for (final FormField publishOption : publishOptions.getFields()) {
                completedForm.removeField(publishOption.getVariable());
                final FormField formField = completedForm.addField(publishOption.getVariable(), publishOption.getLabel(), publishOption.getType());
                for (final String value : publishOption.getValues()) {
                    formField.addValue(value);
                }
            }
        }
    }
    if (completedForm != null) {
        // Calculate newNodeID when new node is affiliated with a Collection
        FormField field = completedForm.getField("pubsub#collection");
        if (field != null) {
            List<String> values = field.getValues();
            if (!values.isEmpty()) {
                String parentNodeID = values.get(0);
                Node tempNode = service.getNode(parentNodeID);
                if (tempNode == null) {
                    // Requested parent node was not found so return an error
                    return new CreateNodeResponse(PacketError.Condition.item_not_found, null, null);
                } else if (!tempNode.isCollectionNode()) {
                    // Requested parent node is not a collection node so return an error
                    return new CreateNodeResponse(PacketError.Condition.not_acceptable, null, null);
                }
                parentNode = (CollectionNode) tempNode;
            }
        }
        field = completedForm.getField("pubsub#node_type");
        if (field != null) {
            // Check if user requested to create a new collection node
            List<String> values = field.getValues();
            if (!values.isEmpty()) {
                collectionType = "collection".equals(values.get(0));
            }
        }
    }
    // If no parent was defined then use the root collection node
    if (parentNode == null && service.isCollectionNodesSupported()) {
        parentNode = service.getRootCollectionNode();
    }
    // Check that the requested nodeID does not exist
    Node existingNode = service.getNode(newNodeID);
    if (existingNode != null) {
        // There is a conflict since a node with the same ID already exists
        return new CreateNodeResponse(PacketError.Condition.conflict, null, null);
    }
    if (collectionType && !service.isCollectionNodesSupported()) {
        // Cannot create a collection node since the service doesn't support it
        Element pubsubError = DocumentHelper.createElement(QName.get("unsupported", "http://jabber.org/protocol/pubsub#errors"));
        pubsubError.addAttribute("feature", "collections");
        return new CreateNodeResponse(PacketError.Condition.feature_not_implemented, pubsubError, null);
    }
    if (parentNode != null && !collectionType) {
        // Check if requester is allowed to add a new leaf child node to the parent node
        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);
        }
        // Check if number of child leaf nodes has not been exceeded
        if (parentNode.isMaxLeafNodeReached()) {
            // Max number of child leaf nodes has been reached. Return an error.
            Element pubsubError = DocumentHelper.createElement(QName.get("max-nodes-exceeded", "http://jabber.org/protocol/pubsub#errors"));
            return new CreateNodeResponse(PacketError.Condition.conflict, pubsubError, null);
        }
    }
    // Create and configure the node
    boolean conflict = false;
    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 = requester.asBareJID();
        final DefaultNodeConfiguration defaultConfiguration = service.getDefaultNodeConfiguration(!collectionType);
        synchronized ((newNodeID + MUTEX_SUFFIX_NODE).intern()) {
            if (service.getNode(newNodeID) == null) {
                // Create the node
                if (collectionType) {
                    newNode = new CollectionNode(service.getUniqueIdentifier(), parentNode, newNodeID, requester, defaultConfiguration);
                } else {
                    newNode = new LeafNode(service.getUniqueIdentifier(), parentNode, newNodeID, requester, defaultConfiguration);
                }
                // Add the creator as the node owner
                newNode.addOwner(owner);
                // Configure and save the node to the backend store
                if (completedForm != null) {
                    newNode.configure(completedForm);
                } else {
                    newNode.saveToDB();
                }
                // TODO Replace with a cluster task that does not interact with the database (OF-2141).
                CacheFactory.doClusterTask(new RefreshNodeTask(newNode));
            } else {
                conflict = true;
            }
        }
        if (conflict) {
            // There is a conflict since a node with the same ID already exists
            return new CreateNodeResponse(PacketError.Condition.conflict, null, null);
        } else {
            // Return success to the node owner
            return new CreateNodeResponse(null, null, newNode);
        }
    } catch (NotAcceptableException e) {
        // Node should have at least one owner. Return not-acceptable error.
        return new CreateNodeResponse(PacketError.Condition.not_acceptable, null, null);
    }
}
Also used : Element(org.dom4j.Element) RefreshNodeTask(org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask) DataForm(org.xmpp.forms.DataForm) FormField(org.xmpp.forms.FormField)

Example 2 with RefreshNodeTask

use of org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask in project Openfire by igniterealtime.

the class PubSubEngine method createNodeHelper.

/**
     * Checks if the following conditions are satisfied and creates a node
     * - Requester can create nodes
     * - Instant node creation is enabled
     * - Node does not already exist
     * - New node configuration is valid
     *
     * NOTE: This method should not reply to the client
     *
     * @param service
     * @param iq
     * @param childElement
     * @param createElement
     * @return {@link CreateNodeResponse}
     */
private CreateNodeResponse createNodeHelper(PubSubService service, IQ iq, Element childElement, Element createElement) {
    // Get sender of the IQ packet
    JID from = iq.getFrom();
    // Verify that sender has permissions to create nodes
    if (!service.canCreateNode(from) || (!UserManager.getInstance().isRegisteredUser(from) && !isComponent(from))) {
        // 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
        if (!service.isInstantNodeSupported()) {
            // Instant nodes creation is not allowed so return an error
            Element pubsubError = DocumentHelper.createElement(QName.get("nodeid-required", "http://jabber.org/protocol/pubsub#errors"));
            return new CreateNodeResponse(PacketError.Condition.not_acceptable, pubsubError, null);
        }
        do {
            // Create a new nodeID and make sure that the random generated string does not
            // match an existing node. Probability to match an existing node are very very low
            // but they exist :)
            newNodeID = StringUtils.randomString(15);
        } 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) {
        // Get the data form that contains the parent nodeID
        completedForm = getSentConfigurationForm(configureElement);
        if (completedForm != null) {
            // Calculate newNodeID when new node is affiliated with a Collection
            FormField field = completedForm.getField("pubsub#collection");
            if (field != null) {
                List<String> values = field.getValues();
                if (!values.isEmpty()) {
                    String parentNodeID = values.get(0);
                    Node tempNode = service.getNode(parentNodeID);
                    if (tempNode == null) {
                        // Requested parent node was not found so return an error
                        return new CreateNodeResponse(PacketError.Condition.item_not_found, null, null);
                    } else if (!tempNode.isCollectionNode()) {
                        // Requested parent node is not a collection node so return an error
                        return new CreateNodeResponse(PacketError.Condition.not_acceptable, null, null);
                    }
                    parentNode = (CollectionNode) tempNode;
                }
            }
            field = completedForm.getField("pubsub#node_type");
            if (field != null) {
                // Check if user requested to create a new collection node
                List<String> values = field.getValues();
                if (!values.isEmpty()) {
                    collectionType = "collection".equals(values.get(0));
                }
            }
        }
    }
    // If no parent was defined then use the root collection node
    if (parentNode == null && service.isCollectionNodesSupported()) {
        parentNode = service.getRootCollectionNode();
    }
    // Check that the requested nodeID does not exist
    Node existingNode = service.getNode(newNodeID);
    if (existingNode != null) {
        // There is a conflict since a node with the same ID already exists
        return new CreateNodeResponse(PacketError.Condition.conflict, null, null);
    }
    if (collectionType && !service.isCollectionNodesSupported()) {
        // Cannot create a collection node since the service doesn't support it
        Element pubsubError = DocumentHelper.createElement(QName.get("unsupported", "http://jabber.org/protocol/pubsub#errors"));
        pubsubError.addAttribute("feature", "collections");
        return new CreateNodeResponse(PacketError.Condition.feature_not_implemented, pubsubError, null);
    }
    if (parentNode != null && !collectionType) {
        // Check if requester is allowed to add a new leaf child node to the parent node
        if (!parentNode.isAssociationAllowed(from)) {
            // User is not allowed to add child leaf node to parent node. Return an error.
            return new CreateNodeResponse(PacketError.Condition.forbidden, null, null);
        }
        // Check if number of child leaf nodes has not been exceeded
        if (parentNode.isMaxLeafNodeReached()) {
            // Max number of child leaf nodes has been reached. Return an error.
            Element pubsubError = DocumentHelper.createElement(QName.get("max-nodes-exceeded", "http://jabber.org/protocol/pubsub#errors"));
            return new CreateNodeResponse(PacketError.Condition.conflict, pubsubError, null);
        }
    }
    // Create and configure the node
    boolean conflict = false;
    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();
        synchronized (newNodeID.intern()) {
            if (service.getNode(newNodeID) == null) {
                // Create the node
                if (collectionType) {
                    newNode = new CollectionNode(service, parentNode, newNodeID, from);
                } else {
                    newNode = new LeafNode(service, parentNode, newNodeID, from);
                }
                // Add the creator as the node owner
                newNode.addOwner(owner);
                // Configure and save the node to the backend store
                if (completedForm != null) {
                    newNode.configure(completedForm);
                } else {
                    newNode.saveToDB();
                }
                CacheFactory.doClusterTask(new RefreshNodeTask(newNode));
            } else {
                conflict = true;
            }
        }
        if (conflict) {
            // There is a conflict since a node with the same ID already exists
            return new CreateNodeResponse(PacketError.Condition.conflict, null, null);
        } else {
            // Return success to the node owner
            return new CreateNodeResponse(null, null, newNode);
        }
    } catch (NotAcceptableException e) {
        // Node should have at least one owner. Return not-acceptable error.
        return new CreateNodeResponse(PacketError.Condition.not_acceptable, null, null);
    }
}
Also used : JID(org.xmpp.packet.JID) Element(org.dom4j.Element) RefreshNodeTask(org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask) DataForm(org.xmpp.forms.DataForm) FormField(org.xmpp.forms.FormField)

Example 3 with RefreshNodeTask

use of org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask in project Openfire by igniterealtime.

the class PubSubEngine method configureNode.

private void configureNode(PubSubService service, IQ iq, Element configureElement, String nodeID) {
    Node node = service.getNode(nodeID);
    if (node == null) {
        // Node does not exist. Return item-not-found error
        sendErrorPacket(iq, PacketError.Condition.item_not_found, null);
        return;
    }
    if (!node.isAdmin(iq.getFrom())) {
        // Requesting entity is not allowed to get node configuration. Return forbidden error
        sendErrorPacket(iq, PacketError.Condition.forbidden, null);
        return;
    }
    // Get the data form that contains the parent nodeID
    DataForm completedForm = getSentConfigurationForm(configureElement);
    if (completedForm != null) {
        try {
            // Update node configuration with the provided data form
            // (and update the backend store)
            node.configure(completedForm);
            // TODO Replace with a cluster task that does not interact with the database (OF-2141).
            CacheFactory.doClusterTask(new RefreshNodeTask(node));
            // Return that node configuration was successful
            router.route(IQ.createResultIQ(iq));
        } catch (NotAcceptableException e) {
            // Node should have at least one owner. Return not-acceptable error.
            sendErrorPacket(iq, PacketError.Condition.not_acceptable, null);
        }
    } else {
        // No data form was included so return bad-request error
        sendErrorPacket(iq, PacketError.Condition.bad_request, null);
    }
}
Also used : DataForm(org.xmpp.forms.DataForm) RefreshNodeTask(org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask)

Aggregations

RefreshNodeTask (org.jivesoftware.openfire.pubsub.cluster.RefreshNodeTask)3 DataForm (org.xmpp.forms.DataForm)3 Element (org.dom4j.Element)2 FormField (org.xmpp.forms.FormField)2 JID (org.xmpp.packet.JID)1