public static LocalConnectionMultiplexerSession createSession(String serverName, XmlPullParser xpp, Connection connection)
            throws XmlPullParserException {
        String domain = xpp.getAttributeValue("", "to");

        // Retrieve list of namespaces declared in current element (OF-2556)
        connection.setAdditionalNamespaces(XMPPPacketReader.getPrefixedNamespacesOnCurrentElement(xpp));

        Log.debug("LocalConnectionMultiplexerSession: [ConMng] Starting registration of new connection manager for domain: " + domain);

        final Element stream = DocumentHelper.createElement(QName.get("stream", "stream", "http://etherx.jabber.org/streams"));
        final Document document = DocumentHelper.createDocument(stream);
        document.setXMLEncoding(StandardCharsets.UTF_8.toString());
        stream.add(Namespace.get("jabber:connectionmanager"));
        stream.addAttribute("version", "1.0");

        // Check that a domain was provided in the stream header
        if (domain == null) {
            Log.debug("LocalConnectionMultiplexerSession: [ConMng] Domain not specified in stanza: {}", xpp.getText());
            // Include the bad-format in the response and close the underlying connection.
            connection.deliverRawText(StringUtils.asUnclosedStream(document));
            connection.close(new StreamError(StreamError.Condition.bad_format, "Missing 'to' attribute value."));
            return null;
        }
        stream.addAttribute("from", domain);

        // Get the requested domain
        JID address = new JID(domain);
        // Check that a secret key was configured in the server
        String secretKey = ConnectionMultiplexerManager.getDefaultSecret();
        if (secretKey == null) {
            Log.debug("LocalConnectionMultiplexerSession: [ConMng] A shared secret for connection manager was not found.");
            // Include the internal-server-error in the response and close the underlying connection
            connection.deliverRawText(StringUtils.asUnclosedStream(document));
            connection.close(new StreamError(StreamError.Condition.internal_server_error));
            return null;
        }
        // Check that the requested subdomain is not already in use
        if (SessionManager.getInstance().getConnectionMultiplexerSession(address) != null) {
            Log.debug("LocalConnectionMultiplexerSession: [ConMng] Another connection manager is already using domain: {}", domain);
            // Domain already occupied so return a conflict error and close the connection.
            connection.deliverRawText(StringUtils.asUnclosedStream(document));
            connection.close(new StreamError(StreamError.Condition.conflict, "The requested address is already being used by another connection manager."));
            return null;
        }

        // Set the connection manager domain to use delivering a packet fails
        final MultiplexerPacketDeliverer packetDeliverer = (MultiplexerPacketDeliverer) connection.getPacketDeliverer();
        if (packetDeliverer != null) {
            packetDeliverer.setConnectionManagerDomain(address.getDomain());
        }

        // Create a ConnectionMultiplexerSession for the new session originated
        // from the connection manager
        LocalConnectionMultiplexerSession session = SessionManager.getInstance().createMultiplexerSession(connection, address);
        // Set the address of the new session
        session.setAddress(address);
        connection.init(session);

        try {
            Log.debug("LocalConnectionMultiplexerSession: [ConMng] Send stream header with ID: {} for connection manager with domain: {}", session.getStreamID(), domain);
            // Build the start packet response
            stream.addAttribute("id", session.getStreamID().toString());

            // Announce stream features.
            final Element features = DocumentHelper.createElement(QName.get("features", "stream", "http://etherx.jabber.org/streams"));
            document.getRootElement().add(features);
            if (connection.getConfiguration().getTlsPolicy() != Connection.TLSPolicy.disabled && !connection.getConfiguration().getIdentityStore().getAllCertificates().isEmpty()) {
                final Element starttls = DocumentHelper.createElement(QName.get("starttls", "urn:ietf:params:xml:ns:xmpp-tls"));
                if (connection.getConfiguration().getTlsPolicy() == Connection.TLSPolicy.required) {
                    starttls.addElement("required");
                }
                features.add(starttls);
            }

            // Include Stream features
            final List<Element> specificFeatures = session.getAvailableStreamFeatures();
            if (specificFeatures != null) {
                for (final Element feature : specificFeatures) {
                    features.add(feature);
                }
            }

            connection.deliverRawText(StringUtils.asUnclosedStream(document));

            return session;
        }
        catch (Exception e) {
            Log.error("An error occurred while creating a Connection Manager Session", e);
            // Close the underlying connection
            connection.deliverRawText(StringUtils.asUnclosedStream(document));
            connection.close(new StreamError(StreamError.Condition.internal_server_error));
            return null;
        }
    }
Represents a session between the server and a connection manager.<p>

Each Connection Manager has its own domain. Each connection from the same connection manager
uses a different resource. Unlike any other session, connection manager sessions are not
present in the routing table. This means that connection managers are not reachable entities.
In other words, entities cannot send packets to connection managers but clients being hosted
by them. The main reason behind this design decision is that connection managers are private
components of the server so they can only be contacted by the server. Connection Manager
sessions are present in {@link SessionManager} but not in {@link org.jivesoftware.openfire.RoutingTable}. Use
{@link SessionManager#getConnectionMultiplexerSessions(String)} to get all sessions or
{@link org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager#getMultiplexerSession(String)}
to get a random session to a given connection manager.

@author Gaston Dombiak
xmppserver/src/main/java/org/jivesoftware/openfire/session/LocalConnectionMultiplexerSession.java