public void createSubscription(IQ originalIQ, JID owner, JID subscriber,
            boolean authorizationRequired, DataForm options) {
        getLogger().trace("Create subscription for '{}' ('{}'). Authorization required: {}", owner, subscriber, authorizationRequired);

        // Create a new affiliation if required
        if (getAffiliate(owner) == null) {
            addNoneAffiliation(owner);
        }
        // Figure out subscription status
        NodeSubscription.State subState = NodeSubscription.State.subscribed;
        if (isSubscriptionConfigurationRequired()) {
            // User has to configure the subscription to make it active
            subState = NodeSubscription.State.unconfigured;
        }
        else if (authorizationRequired && !isAdmin(owner)) {
            // Node owner needs to authorize subscription request so status is pending
            subState = NodeSubscription.State.pending;
        }
        // Generate a subscription ID (override even if one was sent by the client)
        String id = StringUtils.randomString(40);
        // Create new subscription
        NodeSubscription subscription = new NodeSubscription(this, owner, subscriber, subState, id);
        // Configure the subscription with the specified configuration (if any)
        if (options != null) {
            subscription.configure(options);
        }

        if ( subscription.isAuthorizationPending() ) {
            final Set<NodeSubscription> existing = new HashSet<>();
            existing.add( subscriptionsByJID.get( subscription.getJID().toString() ) ); // potentially null
            existing.addAll( subscriptionsByID.values().stream().filter( s -> s.getJID().equals( subscription.getJID() ) ).collect( Collectors.toSet()) );
            if (existing.stream().anyMatch( s -> s != null && s.isAuthorizationPending() ) ) {
                getLogger().debug("This node already has a pending subscription for this JID ('{}'). The XEP forbids this.", subscription.getJID());

                if (originalIQ != null ) {
                    final IQ response = IQ.createResultIQ( originalIQ );
                    response.setError( PacketError.Condition.not_authorized );
                    response.getError().getElement().addElement( "pending-subscription", "http://jabber.org/protocol/pubsub#errors" );
                    getService().send( response );
                }
                // Silently ignore if this was an internal API call.
                return;
            }
        }

        addSubscription(subscription);

        if (savedToDB) {
            getLogger().trace("Add the new subscription to the database");
            XMPPServer.getInstance().getPubSubModule().getPersistenceProvider().createSubscription(this, subscription);
        }

        if (originalIQ != null) {
            // Reply with subscription and affiliation status indicating if subscription
            // must be configured (only when subscription was made through an IQ packet)
            getLogger().trace("Reply with subscription and affiliation status");
            subscription.sendSubscriptionState(originalIQ);
        }

        if (subscription.isAuthorizationPending()) {
            getLogger().trace("Send notification to node owners asking to approve new subscription.");
            subscription.sendAuthorizationRequest();
        }

        getLogger().trace("Update the other members with the new subscription.");
        CacheFactory.doClusterTask(new NewSubscriptionTask(subscription));

        getLogger().trace("Send last published item (if node is leaf node and subscription status is ok).");
        if (isSendItemSubscribe() && subscription.isActive()) {
            PublishedItem lastItem = getLastPublishedItem();
            if (lastItem != null) {
                subscription.sendLastPublishedItem(lastItem);
            }
        }

        getLogger().trace("Check if we need to subscribe to the presence of the owner.");
        if (isPresenceBasedDelivery() && getSubscriptions(subscription.getOwner()).size() == 1) {
            if (subscription.getPresenceStates().isEmpty()) {
                // Subscribe to the owner's presence since the node is only sending events to
                // online subscribers and this is the first subscription of the user and the
                // subscription is not filtering notifications based on presence show values.
                getService().presenceSubscriptionRequired(this, owner);
            }
        }
    }
Creates a new subscription and possibly a new affiliate if the owner of the subscription
does not have any existing affiliation with the node. The new subscription might require
to be authorized by a node owner to be active. If new subscriptions are required to be
configured before being active then the subscription state would be "unconfigured".<p>

The originalIQ parameter may be {@code null} when using this API internally. When no
IQ packet was sent then no IQ result will be sent to the sender. The rest of the
functionality is the same.

@param originalIQ the IQ packet sent by the entity to subscribe to the node or
       null when using this API internally.
@param owner the JID of the affiliate.
@param subscriber the JID where event notifications are going to be sent.
@param authorizationRequired true if the new subscriptions needs to be authorized by
       a node owner.
@param options the data form with the subscription configuration or null if subscriber
       didn't provide a configuration.
xmppserver/src/main/java/org/jivesoftware/openfire/pubsub/Node.java