SmackConfiguration.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software, 2018-2022 Florian Schmaus.
  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.smack;

  18. import java.net.MalformedURLException;
  19. import java.net.URL;
  20. import java.util.ArrayList;
  21. import java.util.Collection;
  22. import java.util.Collections;
  23. import java.util.HashSet;
  24. import java.util.List;
  25. import java.util.Set;

  26. import javax.net.ssl.HostnameVerifier;

  27. import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration;
  28. import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor;
  29. import org.jivesoftware.smack.compression.XMPPInputOutputStream;
  30. import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
  31. import org.jivesoftware.smack.debugger.SmackDebuggerFactory;
  32. import org.jivesoftware.smack.parsing.ExceptionThrowingCallback;
  33. import org.jivesoftware.smack.parsing.ExceptionThrowingCallbackWithHint;
  34. import org.jivesoftware.smack.parsing.ParsingExceptionCallback;
  35. import org.jivesoftware.smack.util.Objects;

  36. /**
  37.  * Represents the configuration of Smack. The configuration is used for:
  38.  * <ul>
  39.  *      <li> Initializing classes by loading them at start-up.
  40.  *      <li> Getting the current Smack version.
  41.  *      <li> Getting and setting global library behavior, such as the period of time
  42.  *          to wait for replies to packets from the server. Note: setting these values
  43.  *          via the API will override settings in the configuration file.
  44.  * </ul>
  45.  *
  46.  * Configuration settings are stored in org.jivesoftware.smack/smack-config.xml.
  47.  *
  48.  * @author Gaston Dombiak
  49.  */
  50. public final class SmackConfiguration {

  51.     public static final String SMACK_URL_STRING = "https://igniterealtime.org/projects/smack";

  52.     public static final URL SMACK_URL;

  53.     static {
  54.         try {
  55.             SMACK_URL = new URL(SMACK_URL_STRING);
  56.         } catch (MalformedURLException e) {
  57.             throw new IllegalStateException(e);
  58.         }
  59.     }

  60.     private static int defaultPacketReplyTimeout = 5000;
  61.     private static int packetCollectorSize = 5000;

  62.     private static List<String> defaultMechs = new ArrayList<>();

  63.     static Set<String> disabledSmackClasses = new HashSet<>();

  64.     static final List<XMPPInputOutputStream> compressionHandlers = new ArrayList<>(2);

  65.     static boolean smackInitialized = false;

  66.     /**
  67.      * Value that indicates whether debugging is enabled. When enabled, a debug
  68.      * window will appear for each new connection that will contain the following
  69.      * information:<ul>
  70.      * <li> Client Traffic -- raw XML traffic generated by Smack and sent to the server.
  71.      * <li> Server Traffic -- raw XML traffic sent by the server to the client.
  72.      * <li> Interpreted Packets -- shows XML packets from the server as parsed by Smack.
  73.      * </ul>
  74.      * Debugging can be enabled by setting this field to true, or by setting the Java system
  75.      * property <code>smack.debugEnabled</code> to true. The system property can be set on the
  76.      * command line such as "java SomeApp -Dsmack.debugEnabled=true".
  77.      */
  78.     public static boolean DEBUG = false;

  79.     private static SmackDebuggerFactory DEFAULT_DEBUGGER_FACTORY = ReflectionDebuggerFactory.INSTANCE;

  80.     /**
  81.      * The default parsing exception callback is {@link ExceptionThrowingCallback} which will
  82.      * throw an exception and therefore disconnect the active connection.
  83.      */
  84.     private static ParsingExceptionCallback defaultCallback = new ExceptionThrowingCallbackWithHint();

  85.     private static HostnameVerifier defaultHostnameVerififer;

  86.     /**
  87.      * Returns the Smack version information, eg "1.3.0".
  88.      *
  89.      * @return the Smack version information.
  90.      * @deprecated use {@link Smack#getVersion()} instead.
  91.      */
  92.     @Deprecated
  93.     // TODO: Remove in Smack 4.6
  94.     public static String getVersion() {
  95.         return SmackInitialization.SMACK_VERSION;
  96.     }

  97.     /**
  98.      * Returns the number of milliseconds to wait for a response from
  99.      * the server. The default value is 5000 ms.
  100.      *
  101.      * @return the milliseconds to wait for a response from the server
  102.      */
  103.     public static int getDefaultReplyTimeout() {
  104.         // The timeout value must be greater than 0 otherwise we will answer the default value
  105.         if (defaultPacketReplyTimeout <= 0) {
  106.             defaultPacketReplyTimeout = 5000;
  107.         }
  108.         return defaultPacketReplyTimeout;
  109.     }

  110.     /**
  111.      * Sets the number of milliseconds to wait for a response from
  112.      * the server.
  113.      *
  114.      * @param timeout the milliseconds to wait for a response from the server
  115.      */
  116.     public static void setDefaultReplyTimeout(int timeout) {
  117.         if (timeout <= 0) {
  118.             throw new IllegalArgumentException();
  119.         }
  120.         defaultPacketReplyTimeout = timeout;
  121.     }

  122.     public static void setDefaultSmackDebuggerFactory(SmackDebuggerFactory debuggerFactory) {
  123.         DEFAULT_DEBUGGER_FACTORY = Objects.requireNonNull(debuggerFactory, "Debugger factory must not be null");
  124.     }

  125.     public static SmackDebuggerFactory getDefaultSmackDebuggerFactory() {
  126.         return DEFAULT_DEBUGGER_FACTORY;
  127.     }

  128.     /**
  129.      * Gets the default max size of a stanza collector before it will delete
  130.      * the older packets.
  131.      *
  132.      * @return The number of packets to queue before deleting older packets.
  133.      */
  134.     public static int getStanzaCollectorSize() {
  135.         return packetCollectorSize;
  136.     }

  137.     /**
  138.      * Sets the default max size of a stanza collector before it will delete
  139.      * the older packets.
  140.      *
  141.      * @param collectorSize the number of packets to queue before deleting older packets.
  142.      */
  143.     public static void setStanzaCollectorSize(int collectorSize) {
  144.         packetCollectorSize = collectorSize;
  145.     }

  146.     /**
  147.      * Add a SASL mechanism to the list to be used.
  148.      *
  149.      * @param mech the SASL mechanism to be added
  150.      */
  151.     public static void addSaslMech(String mech) {
  152.         if (!defaultMechs.contains(mech)) {
  153.             defaultMechs.add(mech);
  154.         }
  155.     }

  156.     /**
  157.      * Add a Collection of SASL mechanisms to the list to be used.
  158.      *
  159.      * @param mechs the Collection of SASL mechanisms to be added
  160.      */
  161.     public static void addSaslMechs(Collection<String> mechs) {
  162.         for (String mech : mechs) {
  163.             addSaslMech(mech);
  164.         }
  165.     }

  166.     /**
  167.      * Remove a SASL mechanism from the list to be used.
  168.      *
  169.      * @param mech the SASL mechanism to be removed
  170.      */
  171.     public static void removeSaslMech(String mech) {
  172.         defaultMechs.remove(mech);
  173.     }

  174.     /**
  175.      * Remove a Collection of SASL mechanisms to the list to be used.
  176.      *
  177.      * @param mechs the Collection of SASL mechanisms to be removed
  178.      */
  179.     public static void removeSaslMechs(Collection<String> mechs) {
  180.         defaultMechs.removeAll(mechs);
  181.     }

  182.     /**
  183.      * Returns the list of SASL mechanisms to be used. If a SASL mechanism is
  184.      * listed here it does not guarantee it will be used. The server may not
  185.      * support it, or it may not be implemented.
  186.      *
  187.      * @return the list of SASL mechanisms to be used.
  188.      */
  189.     public static List<String> getSaslMechs() {
  190.         return Collections.unmodifiableList(defaultMechs);
  191.     }

  192.     /**
  193.      * Set the default parsing exception callback for all newly created connections.
  194.      *
  195.      * @param callback TODO javadoc me please
  196.      * @see ParsingExceptionCallback
  197.      */
  198.     public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) {
  199.         defaultCallback = callback;
  200.     }

  201.     /**
  202.      * Returns the default parsing exception callback.
  203.      *
  204.      * @return the default parsing exception callback
  205.      * @see ParsingExceptionCallback
  206.      */
  207.     public static ParsingExceptionCallback getDefaultParsingExceptionCallback() {
  208.         return defaultCallback;
  209.     }

  210.     public static void addCompressionHandler(XMPPInputOutputStream xmppInputOutputStream) {
  211.         compressionHandlers.add(xmppInputOutputStream);
  212.     }

  213.     /**
  214.      * Get compression handlers.
  215.      *
  216.      * @return a list of compression handlers.
  217.      */
  218.     public static List<XMPPInputOutputStream> getCompressionHandlers() {
  219.         List<XMPPInputOutputStream> res = new ArrayList<>(compressionHandlers.size());
  220.         for (XMPPInputOutputStream ios : compressionHandlers) {
  221.             if (ios.isSupported()) {
  222.                 res.add(ios);
  223.             }
  224.         }
  225.         return res;
  226.     }

  227.     /**
  228.      * Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname
  229.      * of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a
  230.      * HostnameVerifier in their ConnectionConfiguration with
  231.      * {@link ConnectionConfiguration.Builder#setHostnameVerifier(HostnameVerifier)}.
  232.      *
  233.      * @param verifier HostnameVerifier
  234.      */
  235.     public static void setDefaultHostnameVerifier(HostnameVerifier verifier) {
  236.         defaultHostnameVerififer = verifier;
  237.     }

  238.     /**
  239.      * Convenience method for {@link #addDisabledSmackClass(String)}.
  240.      *
  241.      * @param clz the Smack class to disable
  242.      */
  243.     public static void addDisabledSmackClass(Class<?> clz) {
  244.         addDisabledSmackClass(clz.getName());
  245.     }

  246.     /**
  247.      * Add a class to the disabled smack classes.
  248.      * <p>
  249.      * {@code className} can also be a package name, in this case, the entire
  250.      * package is disabled (but can be manually enabled).
  251.      * </p>
  252.      *
  253.      * @param className TODO javadoc me please
  254.      */
  255.     public static void addDisabledSmackClass(String className) {
  256.         disabledSmackClasses.add(className);
  257.     }

  258.     /**
  259.      * Add the given class names to the list of disabled Smack classes.
  260.      *
  261.      * @param classNames the Smack classes to disable.
  262.      * @see #addDisabledSmackClass(String)
  263.      */
  264.     public static void addDisabledSmackClasses(String... classNames) {
  265.         for (String className : classNames) {
  266.             addDisabledSmackClass(className);
  267.         }
  268.     }

  269.     public static boolean isDisabledSmackClass(String className) {
  270.         for (String disabledClassOrPackage : disabledSmackClasses) {
  271.             if (disabledClassOrPackage.equals(className)) {
  272.                 return true;
  273.             }
  274.             int lastDotIndex = disabledClassOrPackage.lastIndexOf('.');
  275.             // Security check to avoid NPEs if someone entered 'foo.bar.'
  276.             if (disabledClassOrPackage.length() > lastDotIndex
  277.                             // disabledClassOrPackage is not an Class
  278.                             && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1))
  279.                             // classToLoad startsWith the package disabledClassOrPackage disables
  280.                             && className.startsWith(disabledClassOrPackage)) {
  281.                 // Skip the class because the whole package was disabled
  282.                 return true;
  283.             }
  284.         }
  285.         return false;
  286.     }

  287.     /**
  288.      * Check if Smack was successfully initialized.
  289.      *
  290.      * @return true if smack was initialized, false otherwise
  291.      */
  292.     public static boolean isSmackInitialized() {
  293.         return smackInitialized;
  294.     }

  295.     /**
  296.      * Get the default HostnameVerifier
  297.      *
  298.      * @return the default HostnameVerifier or <code>null</code> if none was set
  299.      */
  300.     static HostnameVerifier getDefaultHostnameVerifier() {
  301.         return defaultHostnameVerififer;
  302.     }

  303.     public enum UnknownIqRequestReplyMode {
  304.         doNotReply,
  305.         replyFeatureNotImplemented,
  306.         replyServiceUnavailable,
  307.     }

  308.     private static UnknownIqRequestReplyMode unknownIqRequestReplyMode = UnknownIqRequestReplyMode.replyFeatureNotImplemented;

  309.     public static UnknownIqRequestReplyMode getUnknownIqRequestReplyMode() {
  310.         return unknownIqRequestReplyMode;
  311.     }

  312.     public static void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) {
  313.         SmackConfiguration.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Must set mode");
  314.     }

  315.     private static final int defaultConcurrencyLevelLimit;

  316.     static {
  317.         int availableProcessors = Runtime.getRuntime().availableProcessors();
  318.         if (availableProcessors < 8) {
  319.             defaultConcurrencyLevelLimit = 8;
  320.         } else {
  321.             defaultConcurrencyLevelLimit = (int) (availableProcessors * 1.1);
  322.         }
  323.     }

  324.     public static int getDefaultConcurrencyLevelLimit() {
  325.         return defaultConcurrencyLevelLimit;
  326.     }

  327.     private static final Set<Class<? extends ModularXmppClientToServerConnectionModuleDescriptor>> KNOWN_MODULES = new HashSet<>();

  328.     public static boolean addModule(Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor) {
  329.         synchronized (KNOWN_MODULES) {
  330.             return KNOWN_MODULES.add(moduleDescriptor);
  331.         }
  332.     }

  333.     public static void addAllKnownModulesTo(ModularXmppClientToServerConnectionConfiguration.Builder builder) {
  334.         synchronized (KNOWN_MODULES) {
  335.             for (Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor : KNOWN_MODULES) {
  336.                 builder.addModule(moduleDescriptor);
  337.             }
  338.         }
  339.     }

  340.     /**
  341.      * If enabled, causes {@link AbstractXMPPConnection} to create a thread for every asynchronous send operation. This
  342.      * is meant to work-around a shortcoming of Smack 4.4, where certain send operations are not asynchronous even if
  343.      * they should be. This is an expert setting, do not toggle if you do not understand the consequences or have been
  344.      * told to do so. Note that it is expected that this will not be needed in future Smack versions.
  345.      *
  346.      * @since 4.4.6
  347.      */
  348.     public static boolean TRUELY_ASYNC_SENDS = false;
  349. }