VersionManager.java

  1. /**
  2.  *
  3.  * Copyright 2014 Georg Lukas.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smackx.iqversion;

  18. import java.util.Map;
  19. import java.util.WeakHashMap;

  20. import org.jivesoftware.smack.SmackConfiguration;
  21. import org.jivesoftware.smack.SmackException.NoResponseException;
  22. import org.jivesoftware.smack.SmackException.NotConnectedException;
  23. import org.jivesoftware.smack.ConnectionCreationListener;
  24. import org.jivesoftware.smack.XMPPConnection;
  25. import org.jivesoftware.smack.Manager;
  26. import org.jivesoftware.smack.XMPPConnectionRegistry;
  27. import org.jivesoftware.smack.XMPPException.XMPPErrorException;
  28. import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
  29. import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
  30. import org.jivesoftware.smack.packet.IQ;
  31. import org.jivesoftware.smack.packet.XMPPError;
  32. import org.jivesoftware.smack.packet.XMPPError.Condition;
  33. import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
  34. import org.jivesoftware.smackx.iqversion.packet.Version;
  35. import org.jxmpp.jid.Jid;

  36. /**
  37.  * A Version Manager that automatically responds to version IQs with a predetermined reply.
  38.  *
  39.  * <p>
  40.  * The VersionManager takes care of handling incoming version request IQs, according to
  41.  * XEP-0092 (Software Version). You can configure the version reply for a given connection
  42.  * by running the following code:
  43.  * </p>
  44.  *
  45.  * <pre>
  46.  * Version MY_VERSION = new Version("My Little XMPP Application", "v1.23", "OS/2 32-bit");
  47.  * VersionManager.getInstanceFor(mConnection).setVersion(MY_VERSION);
  48.  * </pre>
  49.  *
  50.  * @author Georg Lukas
  51.  */
  52. public class VersionManager extends Manager {
  53.     private static final Map<XMPPConnection, VersionManager> INSTANCES = new WeakHashMap<XMPPConnection, VersionManager>();

  54.     private static Version defaultVersion;

  55.     private Version ourVersion = defaultVersion;

  56.     public static void setDefaultVersion(String name, String version) {
  57.         setDefaultVersion(name, version, null);
  58.     }

  59.     public static void setDefaultVersion(String name, String version, String os) {
  60.         defaultVersion = generateVersionFrom(name, version, os);
  61.     }

  62.     private static boolean autoAppendSmackVersion = true;

  63.     static {
  64.         XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
  65.             public void connectionCreated(XMPPConnection connection) {
  66.                 VersionManager.getInstanceFor(connection);
  67.             }
  68.         });
  69.     }

  70.     private VersionManager(final XMPPConnection connection) {
  71.         super(connection);

  72.         ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
  73.         sdm.addFeature(Version.NAMESPACE);

  74.         connection.registerIQRequestHandler(new AbstractIqRequestHandler(Version.ELEMENT, Version.NAMESPACE, IQ.Type.get,
  75.                         Mode.async) {
  76.             @Override
  77.             public IQ handleIQRequest(IQ iqRequest) {
  78.                 if (ourVersion == null) {
  79.                     return IQ.createErrorResponse(iqRequest, new XMPPError(Condition.not_acceptable));
  80.                 }

  81.                 return Version.createResultFor(iqRequest, ourVersion);
  82.             }
  83.         });
  84.     }

  85.     public static synchronized VersionManager getInstanceFor(XMPPConnection connection) {
  86.         VersionManager versionManager = INSTANCES.get(connection);

  87.         if (versionManager == null) {
  88.             versionManager = new VersionManager(connection);
  89.             INSTANCES.put(connection, versionManager);
  90.         }

  91.         return versionManager;
  92.     }

  93.     public static void setAutoAppendSmackVersion(boolean autoAppendSmackVersion) {
  94.         VersionManager.autoAppendSmackVersion = autoAppendSmackVersion;
  95.     }

  96.     public void setVersion(String name, String version) {
  97.         setVersion(name, version, null);
  98.     }

  99.     public void setVersion(String name, String version, String os) {
  100.         ourVersion = generateVersionFrom(name, version, os);
  101.     }

  102.     public void unsetVersion() {
  103.         ourVersion = null;
  104.     }

  105.     public boolean isSupported(Jid jid) throws NoResponseException, XMPPErrorException,
  106.                     NotConnectedException, InterruptedException {
  107.         return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid,
  108.                         Version.NAMESPACE);
  109.     }

  110.     /**
  111.      * Request version information from a given JID.
  112.      *
  113.      * @param jid
  114.      * @return the version information or {@code null} if not supported by JID
  115.      * @throws NoResponseException
  116.      * @throws XMPPErrorException
  117.      * @throws NotConnectedException
  118.      * @throws InterruptedException
  119.      */
  120.     public Version getVersion(Jid jid) throws NoResponseException, XMPPErrorException,
  121.                     NotConnectedException, InterruptedException {
  122.         if (!isSupported(jid)) {
  123.             return null;
  124.         }
  125.         return connection().createPacketCollectorAndSend(new Version(jid)).nextResultOrThrow();
  126.     }

  127.     private static Version generateVersionFrom(String name, String version, String os) {
  128.         if (autoAppendSmackVersion) {
  129.             name += " (Smack " + SmackConfiguration.getVersion() + ')';
  130.         }
  131.         return new Version(name, version, os);
  132.     }
  133. }