001/** 002 * 003 * Copyright 2014 Georg Lukas. 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 */ 017 018package org.jivesoftware.smackx.iqversion; 019 020import java.util.Map; 021import java.util.WeakHashMap; 022 023import org.jivesoftware.smack.SmackConfiguration; 024import org.jivesoftware.smack.SmackException.NoResponseException; 025import org.jivesoftware.smack.SmackException.NotConnectedException; 026import org.jivesoftware.smack.ConnectionCreationListener; 027import org.jivesoftware.smack.XMPPConnection; 028import org.jivesoftware.smack.Manager; 029import org.jivesoftware.smack.XMPPConnectionRegistry; 030import org.jivesoftware.smack.XMPPException.XMPPErrorException; 031import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; 032import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; 033import org.jivesoftware.smack.packet.IQ; 034import org.jivesoftware.smack.packet.XMPPError; 035import org.jivesoftware.smack.packet.XMPPError.Condition; 036import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 037import org.jivesoftware.smackx.iqversion.packet.Version; 038 039/** 040 * A Version Manager that automatically responds to version IQs with a predetermined reply. 041 * 042 * <p> 043 * The VersionManager takes care of handling incoming version request IQs, according to 044 * XEP-0092 (Software Version). You can configure the version reply for a given connection 045 * by running the following code: 046 * </p> 047 * 048 * <pre> 049 * Version MY_VERSION = new Version("My Little XMPP Application", "v1.23", "OS/2 32-bit"); 050 * VersionManager.getInstanceFor(mConnection).setVersion(MY_VERSION); 051 * </pre> 052 * 053 * @author Georg Lukas 054 */ 055public class VersionManager extends Manager { 056 private static final Map<XMPPConnection, VersionManager> INSTANCES = new WeakHashMap<XMPPConnection, VersionManager>(); 057 058 private static Version defaultVersion; 059 060 private Version ourVersion = defaultVersion; 061 062 public static void setDefaultVersion(String name, String version) { 063 setDefaultVersion(name, version, null); 064 } 065 066 public static void setDefaultVersion(String name, String version, String os) { 067 defaultVersion = generateVersionFrom(name, version, os); 068 } 069 070 private static boolean autoAppendSmackVersion = true; 071 072 static { 073 XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { 074 public void connectionCreated(XMPPConnection connection) { 075 VersionManager.getInstanceFor(connection); 076 } 077 }); 078 } 079 080 private VersionManager(final XMPPConnection connection) { 081 super(connection); 082 083 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection); 084 sdm.addFeature(Version.NAMESPACE); 085 086 connection.registerIQRequestHandler(new AbstractIqRequestHandler(Version.ELEMENT, Version.NAMESPACE, IQ.Type.get, 087 Mode.async) { 088 @Override 089 public IQ handleIQRequest(IQ iqRequest) { 090 if (ourVersion == null) { 091 return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.not_acceptable)); 092 } 093 094 return Version.createResultFor(iqRequest, ourVersion); 095 } 096 }); 097 } 098 099 public static synchronized VersionManager getInstanceFor(XMPPConnection connection) { 100 VersionManager versionManager = INSTANCES.get(connection); 101 102 if (versionManager == null) { 103 versionManager = new VersionManager(connection); 104 INSTANCES.put(connection, versionManager); 105 } 106 107 return versionManager; 108 } 109 110 public static void setAutoAppendSmackVersion(boolean autoAppendSmackVersion) { 111 VersionManager.autoAppendSmackVersion = autoAppendSmackVersion; 112 } 113 114 public void setVersion(String name, String version) { 115 setVersion(name, version, null); 116 } 117 118 public void setVersion(String name, String version, String os) { 119 ourVersion = generateVersionFrom(name, version, os); 120 } 121 122 public void unsetVersion() { 123 ourVersion = null; 124 } 125 126 public boolean isSupported(String jid) throws NoResponseException, XMPPErrorException, 127 NotConnectedException { 128 return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, 129 Version.NAMESPACE); 130 } 131 132 /** 133 * Request version information from a given JID. 134 * 135 * @param jid 136 * @return the version information or {@code null} if not supported by JID 137 * @throws NoResponseException 138 * @throws XMPPErrorException 139 * @throws NotConnectedException 140 */ 141 public Version getVersion(String jid) throws NoResponseException, XMPPErrorException, 142 NotConnectedException { 143 if (!isSupported(jid)) { 144 return null; 145 } 146 return connection().createPacketCollectorAndSend(new Version(jid)).nextResultOrThrow(); 147 } 148 149 private static Version generateVersionFrom(String name, String version, String os) { 150 if (autoAppendSmackVersion) { 151 name += " (Smack " + SmackConfiguration.getVersion() + ')'; 152 } 153 return new Version(name, version, os); 154 } 155}