001/** 002 * 003 * Copyright 2017-2021 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.util.StringUtils; 033 034import org.jivesoftware.smackx.jingle.element.Jingle; 035import org.jivesoftware.smackx.jingle.element.JingleAction; 036import org.jivesoftware.smackx.jingle.element.JingleContent; 037import org.jivesoftware.smackx.jingle.element.JingleContentDescription; 038import org.jivesoftware.smackx.jingle.transports.jingle_ibb.JingleIBBTransportManager; 039import org.jivesoftware.smackx.jingle.transports.jingle_s5b.JingleS5BTransportManager; 040 041import org.jxmpp.jid.FullJid; 042 043public final class JingleManager extends Manager { 044 045 private static final Logger LOGGER = Logger.getLogger(JingleManager.class.getName()); 046 047 private static final Map<XMPPConnection, JingleManager> INSTANCES = new WeakHashMap<>(); 048 049 private static final ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 050 051 public static ExecutorService getThreadPool() { 052 return threadPool; 053 } 054 055 public static synchronized JingleManager getInstanceFor(XMPPConnection connection) { 056 JingleManager jingleManager = INSTANCES.get(connection); 057 if (jingleManager == null) { 058 jingleManager = new JingleManager(connection); 059 INSTANCES.put(connection, jingleManager); 060 } 061 return jingleManager; 062 } 063 064 private final Map<String, JingleHandler> descriptionHandlers = new ConcurrentHashMap<>(); 065 066 private final Map<FullJidAndSessionId, JingleSessionHandler> jingleSessionHandlers = new ConcurrentHashMap<>(); 067 068 private final JingleUtil jutil; 069 070 private JingleManager(XMPPConnection connection) { 071 super(connection); 072 073 jutil = new JingleUtil(connection); 074 075 connection.registerIQRequestHandler( 076 new AbstractIqRequestHandler(Jingle.ELEMENT, Jingle.NAMESPACE, IQ.Type.set, Mode.async) { 077 @Override 078 public IQ handleIQRequest(IQ iqRequest) { 079 final Jingle jingle = (Jingle) iqRequest; 080 081 FullJid fullFrom = jingle.getFrom().asFullJidOrThrow(); 082 String sid = jingle.getSid(); 083 FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, sid); 084 085 JingleSessionHandler sessionHandler = jingleSessionHandlers.get(fullJidAndSessionId); 086 if (sessionHandler != null) { 087 // Handle existing session 088 return sessionHandler.handleJingleSessionRequest(jingle); 089 } 090 091 if (jingle.getAction() == JingleAction.session_initiate) { 092 093 JingleContent content = jingle.getContents().get(0); 094 JingleContentDescription description = content.getDescription(); 095 JingleHandler jingleDescriptionHandler = descriptionHandlers.get( 096 description.getNamespace()); 097 098 if (jingleDescriptionHandler == null) { 099 // Unsupported Application 100 LOGGER.log(Level.WARNING, "Unsupported Jingle application."); 101 return jutil.createSessionTerminateUnsupportedApplications(fullFrom, sid); 102 } 103 return jingleDescriptionHandler.handleJingleRequest(jingle); 104 } 105 106 // Unknown session 107 LOGGER.log(Level.WARNING, "Unknown session."); 108 return jutil.createErrorUnknownSession(jingle); 109 } 110 }); 111 // Register transports. 112 JingleTransportMethodManager transportMethodManager = JingleTransportMethodManager.getInstanceFor(connection); 113 transportMethodManager.registerTransportManager(JingleIBBTransportManager.getInstanceFor(connection)); 114 transportMethodManager.registerTransportManager(JingleS5BTransportManager.getInstanceFor(connection)); 115 } 116 117 public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) { 118 return descriptionHandlers.put(namespace, handler); 119 } 120 121 public JingleSessionHandler registerJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { 122 FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); 123 return jingleSessionHandlers.put(fullJidAndSessionId, sessionHandler); 124 } 125 126 public JingleSessionHandler unregisterJingleSessionHandler(FullJid otherJid, String sessionId, JingleSessionHandler sessionHandler) { 127 FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(otherJid, sessionId); 128 return jingleSessionHandlers.remove(fullJidAndSessionId); 129 } 130 131 public static String randomId() { 132 return StringUtils.randomString(24); 133 } 134}