Package rocks.xmpp.extensions.jingle

Source Code of rocks.xmpp.extensions.jingle.JingleSession

/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Christian Schudt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package rocks.xmpp.extensions.jingle;

import rocks.xmpp.core.Jid;
import rocks.xmpp.core.XmppException;
import rocks.xmpp.core.session.XmppSession;
import rocks.xmpp.core.stanza.model.client.IQ;
import rocks.xmpp.extensions.jingle.model.Jingle;
import rocks.xmpp.extensions.jingle.transports.model.TransportMethod;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* @author Christian Schudt
*/
public final class JingleSession {

    private static final Logger logger = Logger.getLogger(JingleManager.class.getName());

    private final Set<JingleListener> jingleListeners = new CopyOnWriteArraySet<>();

    private final String sessionId;

    private final XmppSession xmppSession;

    private final Jid peer;

    private final JingleManager jingleManager;

    private final boolean createdLocally;

    // See 7.2.2 content-add:
    // Therefore it is the responsibility of the recipient to maintain a local copy of the current content definition(s).
    private final List<Jingle.Content> contents;

    private State state = State.INITIAL;

    JingleSession(String sessionId, Jid peer, boolean createdLocally, XmppSession xmppSession, JingleManager jingleManager, Jingle.Content... contents) {
        this(sessionId, peer, createdLocally, xmppSession, jingleManager, Arrays.asList(contents));
    }

    JingleSession(String sessionId, Jid peer, boolean createdLocally, XmppSession xmppSession, JingleManager jingleManager, List<Jingle.Content> contents) {
        this.sessionId = sessionId;
        this.xmppSession = xmppSession;
        this.peer = peer;
        this.jingleManager = jingleManager;
        this.createdLocally = createdLocally;
        this.contents = new ArrayList<>(contents);
    }

    /**
     * Gets the session id.
     *
     * @return The session id.
     */
    public String getSessionId() {
        return sessionId;
    }

    /**
     * Initiates the session.
     *
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the entity returned a stanza error.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#protocol-initiate">6.2 Initiation</a>
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#def-action-session-initiate">7.2.10 session-initiate</a>
     */
    public void initiate() throws XmppException {
        if (state != State.INITIAL) {
            throw new IllegalStateException("Session has already been initiated.");
        }
        if (!createdLocally) {
            throw new UnsupportedOperationException("You are not the initiator.");
        }
        xmppSession.query(new IQ(peer, IQ.Type.SET, Jingle.initiator(xmppSession.getConnectedResource(), sessionId, Jingle.Action.SESSION_INITIATE, contents)));
        state = State.PENDING;
    }

    /**
     * Accepts the session. You must at least provide one content element.
     *
     * @param contents The contents.
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the entity returned a stanza error.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#session-acceptance">6.5 Acceptance</a>
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#def-action-session-accept">7.2.8 session-accept</a>
     */
    public void accept(Jingle.Content... contents) throws XmppException {
        if (state != State.PENDING) {
            throw new IllegalStateException("The session is not in pending state.");
        }
        if (createdLocally) {
            throw new UnsupportedOperationException("You are the initiator and cannot accept the session.");
        }
        // In the session-accept stanza, the <jingle/> element MUST contain one or more <content/> elements, each of which MUST contain one <description/> element and one <transport/> element.
        if (contents.length == 0) {
            throw new IllegalArgumentException("No content element provided.");
        }
        for (Jingle.Content content : contents) {
            if (content.getApplicationFormat() == null) {
                throw new IllegalArgumentException("No application format provided in content.");
            }
            if (content.getTransportMethod() == null) {
                throw new IllegalArgumentException("No transport method provided in content.");
            }
        }

        xmppSession.query(new IQ(peer, IQ.Type.SET, Jingle.responder(xmppSession.getConnectedResource(), sessionId, Jingle.Action.SESSION_ACCEPT, Arrays.asList(contents))));
        // The session is now in the ACTIVE state.
        state = State.ACTIVE;
    }

    /**
     * Terminates the Jingle session.
     *
     * @param reason The reason for termination.
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the entity returned a stanza error.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#session-terminate">6.7 Termination</a>
     */
    public void terminate(Jingle.Reason reason) throws XmppException {
        if (state == State.INITIAL) {
            throw new IllegalStateException("The session has not yet been initialized.");
        }
        // As soon as an entity sends a session-terminate action, it MUST consider the session to be in the ENDED state
        // (even before receiving acknowledgement from the other party).
        state = State.ENDED;
        try {
            xmppSession.query(new IQ(peer, IQ.Type.SET, new Jingle(sessionId, Jingle.Action.SESSION_TERMINATE, reason)));
        } finally {
            jingleManager.removeSession(sessionId);
        }
    }

    /**
     * @param contentName     The content name.
     * @param transportMethod The replaced transport method.
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the entity returned a stanza error.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#def-action-transport-replace">7.2.15 transport-replace</a>
     */
    public void replaceTransport(String contentName, TransportMethod transportMethod) throws XmppException {
        Jingle.Content content = new Jingle.Content(contentName, Jingle.Content.Creator.INITIATOR, null, transportMethod);
        xmppSession.query(new IQ(peer, IQ.Type.SET, Jingle.initiator(xmppSession.getConnectedResource(), sessionId, Jingle.Action.TRANSPORT_REPLACE, Arrays.asList(content))));
    }

    public void acceptTransport(String contentName, TransportMethod transportMethod) throws XmppException {
        Jingle.Content content = new Jingle.Content(contentName, Jingle.Content.Creator.INITIATOR, null, transportMethod);
        xmppSession.query(new IQ(peer, IQ.Type.SET, Jingle.initiator(xmppSession.getConnectedResource(), sessionId, Jingle.Action.TRANSPORT_ACCEPT, Arrays.asList(content))));
    }

    public void rejectTransport(String contentName, TransportMethod transportMethod) throws XmppException {
        Jingle.Content content = new Jingle.Content(contentName, Jingle.Content.Creator.INITIATOR, null, transportMethod);
        xmppSession.query(new IQ(peer, IQ.Type.SET, Jingle.initiator(xmppSession.getConnectedResource(), sessionId, Jingle.Action.TRANSPORT_REJECT, Arrays.asList(content))));
    }

    /**
     * Sends a session info.
     *
     * @param object The session info payload.
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the entity returned a stanza error.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#def-action-session-info">7.2.9 session-info</a>
     */
    public void sendSessionInfo(Object object) throws XmppException {
        if (state == State.INITIAL) {
            throw new IllegalStateException("The session has not yet been initialized.");
        }
        xmppSession.query(new IQ(peer, IQ.Type.SET, new Jingle(sessionId, Jingle.Action.SESSION_INFO, object)));
    }

    /**
     * Adds a Jingle listener, which allows to listen for Jingle events.
     *
     * @param jingleListener The listener.
     * @see #removeJingleListener(JingleListener)
     */
    public final void addJingleListener(JingleListener jingleListener) {
        jingleListeners.add(jingleListener);
    }

    /**
     * Removes a previously added Jingle listener.
     *
     * @param jingleListener The listener.
     * @see #addJingleListener(JingleListener)
     */
    public final void removeJingleListener(JingleListener jingleListener) {
        jingleListeners.remove(jingleListener);
    }

    /**
     * Notifies the Jingle listeners.
     *
     * @param jingleEvent The Jingle event.
     */
    void notifyJingleListeners(JingleEvent jingleEvent) {
        for (JingleListener jingleListener : jingleListeners) {
            try {
                jingleListener.jingleReceived(jingleEvent);
            } catch (Exception exc) {
                logger.log(Level.WARNING, exc.getMessage(), exc);
            }
        }
    }


    /**
     * Represents the state of a Jingle session.
     *
     * @see <a href="http://xmpp.org/extensions/xep-0166.html#concepts-session">5.1 Overall Session Management</a>
     */
    public enum State {
        /**
         * The session has not yet been initiated.
         */
        INITIAL,
        /**
         * The session has been initiated, but not yet accepted.
         */
        PENDING,
        /**
         * The session has been accepted.
         */
        ACTIVE,
        /**
         * The session has been ended.
         */
        ENDED
    }
}
TOP

Related Classes of rocks.xmpp.extensions.jingle.JingleSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.