001/**
002 *
003 * Copyright 2017 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingle;
018
019import java.util.Map;
020import java.util.WeakHashMap;
021import java.util.concurrent.ConcurrentHashMap;
022import java.util.concurrent.ExecutorService;
023import java.util.concurrent.Executors;
024import java.util.logging.Level;
025import java.util.logging.Logger;
026
027import org.jivesoftware.smack.Manager;
028import org.jivesoftware.smack.XMPPConnection;
029import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
030import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
031import org.jivesoftware.smack.packet.IQ;
032import org.jivesoftware.smack.packet.IQ.Type;
033import org.jivesoftware.smack.util.StringUtils;
034
035import org.jivesoftware.smackx.jingle.element.Jingle;
036import org.jivesoftware.smackx.jingle.element.JingleAction;
037import org.jivesoftware.smackx.jingle.element.JingleContent;
038import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
039import org.jivesoftware.smackx.jingle.transports.jingle_ibb.JingleIBBTransportManager;
040import org.jivesoftware.smackx.jingle.transports.jingle_s5b.JingleS5BTransportManager;
041
042import org.jxmpp.jid.FullJid;
043
044public final class JingleManager extends Manager {
045
046    private static final Logger LOGGER = Logger.getLogger(JingleManager.class.getName());
047
048    private static final Map<XMPPConnection, JingleManager> INSTANCES = new WeakHashMap<>();
049
050    private static final ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
051
052    public static ExecutorService getThreadPool() {
053        return threadPool;
054    }
055
056    public static synchronized JingleManager getInstanceFor(XMPPConnection connection) {
057        JingleManager jingleManager = INSTANCES.get(connection);
058        if (jingleManager == null) {
059            jingleManager = new JingleManager(connection);
060            INSTANCES.put(connection, jingleManager);
061        }
062        return jingleManager;
063    }
064
065    private final Map<String, JingleHandler> descriptionHandlers = new ConcurrentHashMap<>();
066
067    private final Map<FullJidAndSessionId, JingleSessionHandler> jingleSessionHandlers = new ConcurrentHashMap<>();
068
069    private final JingleUtil jutil;
070
071    private JingleManager(XMPPConnection connection) {
072        super(connection);
073
074        jutil = new JingleUtil(connection);
075
076        connection.registerIQRequestHandler(
077                new AbstractIqRequestHandler(Jingle.ELEMENT, Jingle.NAMESPACE, Type.set, Mode.async) {
078                    @Override
079                    public IQ handleIQRequest(IQ iqRequest) {
080                        final Jingle jingle = (Jingle) iqRequest;
081
082                        FullJid fullFrom = jingle.getFrom().asFullJidOrThrow();
083                        String sid = jingle.getSid();
084                        FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, sid);
085
086                        JingleSessionHandler sessionHandler = jingleSessionHandlers.get(fullJidAndSessionId);
087                        if (sessionHandler != null) {
088                            // Handle existing session
089                            return sessionHandler.handleJingleSessionRequest(jingle);
090                        }
091
092                        if (jingle.getAction() == JingleAction.session_initiate) {
093
094                            JingleContent content = jingle.getContents().get(0);
095                            JingleContentDescription description = content.getDescription();
096                            JingleHandler jingleDescriptionHandler = descriptionHandlers.get(
097                                    description.getNamespace());
098
099                            if (jingleDescriptionHandler == null) {
100                                // Unsupported Application
101                                LOGGER.log(Level.WARNING, "Unsupported Jingle application.");
102                                return jutil.createSessionTerminateUnsupportedApplications(fullFrom, sid);
103                            }
104                            return jingleDescriptionHandler.handleJingleRequest(jingle);
105                        }
106
107                        // Unknown session
108                        LOGGER.log(Level.WARNING, "Unknown session.");
109                        return jutil.createErrorUnknownSession(jingle);
110                    }
111                });
112        // Register transports.
113        JingleTransportMethodManager transportMethodManager = JingleTransportMethodManager.getInstanceFor(connection);
114        transportMethodManager.registerTransportManager(JingleIBBTransportManager.getInstanceFor(connection));
115        transportMethodManager.registerTransportManager(JingleS5BTransportManager.getInstanceFor(connection));
116    }
117
118    public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) {
119        return descriptionHandlers.put(namespace, handler);
120    }
121
122    public JingleSessionHandler registerJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) {
123        FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId);
124        return jingleSessionHandlers.put(fullJidAndSessionId, sessionHandler);
125    }
126
127    public JingleSessionHandler unregisterJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) {
128        FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId);
129        return jingleSessionHandlers.remove(fullJidAndSessionId);
130    }
131
132    public static String randomId() {
133        return StringUtils.randomString(24);
134    }
135}