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}