public void configure(DataForm completedForm) throws NotAcceptableException {
        getLogger().trace("Apply configuration from provided data form...");

        boolean wasPresenceBased = isPresenceBasedDelivery();

        if (DataForm.Type.cancel.equals(completedForm.getType())) {
            getLogger().trace("... Data form type cancel: Existing node configuration is applied (i.e. nothing is changed).");
        }
        else if (DataForm.Type.submit.equals(completedForm.getType())) {
            List<String> values;

            // Get the new list of owners
            FormField ownerField = completedForm.getField("pubsub#owner");
            boolean ownersSent = ownerField != null;
            List<JID> owners = new ArrayList<>();
            if (ownersSent) {
                for (String value : ownerField.getValues()) {
                    try {
                        owners.add(new JID(value));
                    }
                    catch (Exception e) {
                        // Do nothing
                    }
                }
            }

            if (ownersSent && owners.isEmpty()) {
                getLogger().trace("... data form type submit not acceptable: all the current owners would be removed.");
                throw new NotAcceptableException("This would remove all current owners.");
            }


            getLogger().trace("... data form type submit. Applying fields from form ...");
            for (FormField field : completedForm.getFields()) {
                getLogger().trace("... processing field '{}' ...", field.getVariable());
                if ("FORM_TYPE".equals(field.getVariable())) {
                    // Do nothing
                }
                else if ("pubsub#deliver_payloads".equals(field.getVariable())) {
                    deliverPayloads = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#notify_config".equals(field.getVariable())) {
                    notifyConfigChanges = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#notify_delete".equals(field.getVariable())) {
                    notifyDelete = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#notify_retract".equals(field.getVariable())) {
                    notifyRetract = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#presence_based_delivery".equals(field.getVariable())) {
                    presenceBasedDelivery = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#subscribe".equals(field.getVariable())) {
                    subscriptionEnabled = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#subscription_required".equals(field.getVariable())) {
                    // TODO Replace this variable for the one defined in the JEP (once one is defined)
                    subscriptionConfigurationRequired = parseFirstValueAsBoolean( field, true ) ;
                }
                else if ("pubsub#type".equals(field.getVariable())) {
                    values = field.getValues();
                    payloadType = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#body_xslt".equals(field.getVariable())) {
                    values = field.getValues();
                    bodyXSLT = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#dataform_xslt".equals(field.getVariable())) {
                    values = field.getValues();
                    dataformXSLT = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#access_model".equals(field.getVariable())) {
                    values = field.getValues();
                    if (!values.isEmpty())  {
                        accessModel = AccessModel.valueOf(values.get(0));
                    }
                }
                else if ("pubsub#publish_model".equals(field.getVariable())) {
                    values = field.getValues();
                    if (!values.isEmpty())  {
                        publisherModel = PublisherModel.valueOf(values.get(0));
                    }
                }
                else if ("pubsub#roster_groups_allowed".equals(field.getVariable())) {
                    // Get the new list of roster group(s) allowed to subscribe and retrieve items
                    rosterGroupsAllowed = new ArrayList<>();
                    for (String value : field.getValues()) {
                        addAllowedRosterGroup(value);
                    }
                }
                else if ("pubsub#contact".equals(field.getVariable())) {
                    // Get the new list of users that may be contacted with questions
                    contacts = new ArrayList<>();
                    for (String value : field.getValues()) {
                        try {
                            addContact(new JID(value));
                        }
                        catch (Exception e) {
                            // Do nothing
                        }
                    }
                }
                else if ("pubsub#description".equals(field.getVariable())) {
                    values = field.getValues();
                    description = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#language".equals(field.getVariable())) {
                    values = field.getValues();
                    language = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#title".equals(field.getVariable())) {
                    values = field.getValues();
                    name = !values.isEmpty() ? values.get(0) : " ";
                }
                else if ("pubsub#itemreply".equals(field.getVariable())) {
                    values = field.getValues();
                    if (!values.isEmpty())  {
                        replyPolicy = ItemReplyPolicy.valueOf(values.get(0));
                    }
                }
                else if ("pubsub#replyroom".equals(field.getVariable())) {
                    // Get the new list of multi-user chat rooms to specify for replyroom
                    replyRooms = new ArrayList<>();
                    for (String value : field.getValues()) {
                        try {
                            addReplyRoom(new JID(value));
                        }
                        catch (Exception e) {
                            // Do nothing
                        }
                    }
                }
                else if ("pubsub#replyto".equals(field.getVariable())) {
                    // Get the new list of JID(s) to specify for replyto
                    replyTo = new ArrayList<>();
                    for (String value : field.getValues()) {
                        try {
                            addReplyTo(new JID(value));
                        }
                        catch (Exception e) {
                            // Do nothing
                        }
                    }
                }
                else if ("pubsub#collection".equals(field.getVariable())) {
                    // Set the parent collection node
                    values = field.getValues();
                    String newParent = !values.isEmpty() ? values.get(0) : " ";
                    Node newParentNode = getService().getNode(newParent);

                    if (!(newParentNode instanceof CollectionNode))
                    {
                        throw new NotAcceptableException("Specified node in field pubsub#collection [" + newParent + "] " + ((newParentNode == null) ? "does not exist" : "is not a collection node"));
                    }
                    changeParent((CollectionNode)newParentNode);
                }
                else {
                    // Let subclasses be configured by specified fields
                    configure(field);
                }
            }
            getLogger().trace("... applied all fields from form.");

            // Set new list of owners of the node
            if (ownersSent) {
                getLogger().trace("... set new list of owners of the node");

                // Calculate owners to remove and remove them from the DB
                Collection<JID> oldOwners = getOwners();
                oldOwners.removeAll(owners);
                for (JID jid : oldOwners) {
                    removeOwner(jid);
                }

                // Calculate new owners and add them to the DB
                owners.removeAll(getOwners());
                for (JID jid : owners) {
                    addOwner(jid);
                }
            }
            // TODO Before removing owner or admin check if user was changed from admin to owner or vice versa. This way his subscriptions are not going to be deleted.
            FormField publisherField = completedForm.getField("pubsub#publisher");
            if (publisherField != null) {
                getLogger().trace("... set new list of owners of the node");

                // New list of publishers was sent to update publishers of the node
                List<JID> publishers = new ArrayList<>();
                for (String value : publisherField.getValues()) {
                    try {
                        publishers.add(new JID(value));
                    }
                    catch (Exception e) {
                        // Do nothing
                    }
                }
                // Calculate publishers to remove and remove them from the DB
                Collection<JID> oldPublishers = getPublishers();
                oldPublishers.removeAll(publishers);
                for (JID jid : oldPublishers) {
                    removePublisher(jid);
                }

                // Calculate new publishers and add them to the DB
                publishers.removeAll(getPublishers());
                for (JID jid : publishers) {
                    addPublisher(jid);
                }
            }

            getLogger().trace("... Let subclasses have a chance to finish node configuration based on the completed form");
            postConfigure(completedForm);

            // Update the modification date to reflect the last time when the node's configuration was modified
            modificationDate = new Date();

            // Notify subscribers that the node configuration has changed
            nodeConfigurationChanged();
        }
        // Store the new or updated node in the backend store
        saveToDB();

        // Check if we need to subscribe or unsubscribe from affiliate presences
        if (wasPresenceBased != isPresenceBasedDelivery()) {
            if (isPresenceBasedDelivery()) {
                addPresenceSubscriptions();
            }
            else {
                cancelPresenceSubscriptions();
            }
        }
    }
Changes the node configuration based on the completed data form. Only owners or
sysadmins are allowed to change the node configuration. The completed data form
cannot remove all node owners. An exception is going to be thrown if the new form
tries to leave the node without owners.

@param completedForm the completed data form.
@throws NotAcceptableException if completed data form tries to leave the node without owners.
xmppserver/src/main/java/org/jivesoftware/openfire/pubsub/Node.java