001/** 002 * 003 * Copyright 2003-2007 Jive Software, 2018-2022 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 */ 017 018package org.jivesoftware.smack; 019 020import java.net.MalformedURLException; 021import java.net.URL; 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.Collections; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Set; 028 029import javax.net.ssl.HostnameVerifier; 030 031import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionConfiguration; 032import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnectionModuleDescriptor; 033import org.jivesoftware.smack.compression.XMPPInputOutputStream; 034import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory; 035import org.jivesoftware.smack.debugger.SmackDebuggerFactory; 036import org.jivesoftware.smack.parsing.ExceptionThrowingCallback; 037import org.jivesoftware.smack.parsing.ExceptionThrowingCallbackWithHint; 038import org.jivesoftware.smack.parsing.ParsingExceptionCallback; 039import org.jivesoftware.smack.util.Objects; 040 041/** 042 * Represents the configuration of Smack. The configuration is used for: 043 * <ul> 044 * <li> Initializing classes by loading them at start-up. 045 * <li> Getting the current Smack version. 046 * <li> Getting and setting global library behavior, such as the period of time 047 * to wait for replies to packets from the server. Note: setting these values 048 * via the API will override settings in the configuration file. 049 * </ul> 050 * 051 * Configuration settings are stored in org.jivesoftware.smack/smack-config.xml. 052 * 053 * @author Gaston Dombiak 054 */ 055public final class SmackConfiguration { 056 057 public static final String SMACK_URL_STRING = "https://igniterealtime.org/projects/smack"; 058 059 public static final URL SMACK_URL; 060 061 static { 062 try { 063 SMACK_URL = new URL(SMACK_URL_STRING); 064 } catch (MalformedURLException e) { 065 throw new IllegalStateException(e); 066 } 067 } 068 069 private static int defaultPacketReplyTimeout = 5000; 070 private static int packetCollectorSize = 5000; 071 072 private static List<String> defaultMechs = new ArrayList<>(); 073 074 static Set<String> disabledSmackClasses = new HashSet<>(); 075 076 static final List<XMPPInputOutputStream> compressionHandlers = new ArrayList<>(2); 077 078 static boolean smackInitialized = false; 079 080 /** 081 * Value that indicates whether debugging is enabled. When enabled, a debug 082 * window will appear for each new connection that will contain the following 083 * information:<ul> 084 * <li> Client Traffic -- raw XML traffic generated by Smack and sent to the server. 085 * <li> Server Traffic -- raw XML traffic sent by the server to the client. 086 * <li> Interpreted Packets -- shows XML packets from the server as parsed by Smack. 087 * </ul> 088 * Debugging can be enabled by setting this field to true, or by setting the Java system 089 * property <code>smack.debugEnabled</code> to true. The system property can be set on the 090 * command line such as "java SomeApp -Dsmack.debugEnabled=true". 091 */ 092 public static boolean DEBUG = false; 093 094 private static SmackDebuggerFactory DEFAULT_DEBUGGER_FACTORY = ReflectionDebuggerFactory.INSTANCE; 095 096 /** 097 * The default parsing exception callback is {@link ExceptionThrowingCallback} which will 098 * throw an exception and therefore disconnect the active connection. 099 */ 100 private static ParsingExceptionCallback defaultCallback = new ExceptionThrowingCallbackWithHint(); 101 102 private static HostnameVerifier defaultHostnameVerififer; 103 104 /** 105 * Returns the Smack version information, eg "1.3.0". 106 * 107 * @return the Smack version information. 108 * @deprecated use {@link Smack#getVersion()} instead. 109 */ 110 @Deprecated 111 // TODO: Remove in Smack 4.6 112 public static String getVersion() { 113 return SmackInitialization.SMACK_VERSION; 114 } 115 116 /** 117 * Returns the number of milliseconds to wait for a response from 118 * the server. The default value is 5000 ms. 119 * 120 * @return the milliseconds to wait for a response from the server 121 */ 122 public static int getDefaultReplyTimeout() { 123 // The timeout value must be greater than 0 otherwise we will answer the default value 124 if (defaultPacketReplyTimeout <= 0) { 125 defaultPacketReplyTimeout = 5000; 126 } 127 return defaultPacketReplyTimeout; 128 } 129 130 /** 131 * Sets the number of milliseconds to wait for a response from 132 * the server. 133 * 134 * @param timeout the milliseconds to wait for a response from the server 135 */ 136 public static void setDefaultReplyTimeout(int timeout) { 137 if (timeout <= 0) { 138 throw new IllegalArgumentException(); 139 } 140 defaultPacketReplyTimeout = timeout; 141 } 142 143 public static void setDefaultSmackDebuggerFactory(SmackDebuggerFactory debuggerFactory) { 144 DEFAULT_DEBUGGER_FACTORY = Objects.requireNonNull(debuggerFactory, "Debugger factory must not be null"); 145 } 146 147 public static SmackDebuggerFactory getDefaultSmackDebuggerFactory() { 148 return DEFAULT_DEBUGGER_FACTORY; 149 } 150 151 /** 152 * Gets the default max size of a stanza collector before it will delete 153 * the older packets. 154 * 155 * @return The number of packets to queue before deleting older packets. 156 */ 157 public static int getStanzaCollectorSize() { 158 return packetCollectorSize; 159 } 160 161 /** 162 * Sets the default max size of a stanza collector before it will delete 163 * the older packets. 164 * 165 * @param collectorSize the number of packets to queue before deleting older packets. 166 */ 167 public static void setStanzaCollectorSize(int collectorSize) { 168 packetCollectorSize = collectorSize; 169 } 170 171 /** 172 * Add a SASL mechanism to the list to be used. 173 * 174 * @param mech the SASL mechanism to be added 175 */ 176 public static void addSaslMech(String mech) { 177 if (!defaultMechs.contains(mech)) { 178 defaultMechs.add(mech); 179 } 180 } 181 182 /** 183 * Add a Collection of SASL mechanisms to the list to be used. 184 * 185 * @param mechs the Collection of SASL mechanisms to be added 186 */ 187 public static void addSaslMechs(Collection<String> mechs) { 188 for (String mech : mechs) { 189 addSaslMech(mech); 190 } 191 } 192 193 /** 194 * Remove a SASL mechanism from the list to be used. 195 * 196 * @param mech the SASL mechanism to be removed 197 */ 198 public static void removeSaslMech(String mech) { 199 defaultMechs.remove(mech); 200 } 201 202 /** 203 * Remove a Collection of SASL mechanisms to the list to be used. 204 * 205 * @param mechs the Collection of SASL mechanisms to be removed 206 */ 207 public static void removeSaslMechs(Collection<String> mechs) { 208 defaultMechs.removeAll(mechs); 209 } 210 211 /** 212 * Returns the list of SASL mechanisms to be used. If a SASL mechanism is 213 * listed here it does not guarantee it will be used. The server may not 214 * support it, or it may not be implemented. 215 * 216 * @return the list of SASL mechanisms to be used. 217 */ 218 public static List<String> getSaslMechs() { 219 return Collections.unmodifiableList(defaultMechs); 220 } 221 222 /** 223 * Set the default parsing exception callback for all newly created connections. 224 * 225 * @param callback TODO javadoc me please 226 * @see ParsingExceptionCallback 227 */ 228 public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) { 229 defaultCallback = callback; 230 } 231 232 /** 233 * Returns the default parsing exception callback. 234 * 235 * @return the default parsing exception callback 236 * @see ParsingExceptionCallback 237 */ 238 public static ParsingExceptionCallback getDefaultParsingExceptionCallback() { 239 return defaultCallback; 240 } 241 242 public static void addCompressionHandler(XMPPInputOutputStream xmppInputOutputStream) { 243 compressionHandlers.add(xmppInputOutputStream); 244 } 245 246 /** 247 * Get compression handlers. 248 * 249 * @return a list of compression handlers. 250 */ 251 public static List<XMPPInputOutputStream> getCompressionHandlers() { 252 List<XMPPInputOutputStream> res = new ArrayList<>(compressionHandlers.size()); 253 for (XMPPInputOutputStream ios : compressionHandlers) { 254 if (ios.isSupported()) { 255 res.add(ios); 256 } 257 } 258 return res; 259 } 260 261 /** 262 * Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname 263 * of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a 264 * HostnameVerifier in their ConnectionConfiguration with 265 * {@link ConnectionConfiguration.Builder#setHostnameVerifier(HostnameVerifier)}. 266 * 267 * @param verifier HostnameVerifier 268 */ 269 public static void setDefaultHostnameVerifier(HostnameVerifier verifier) { 270 defaultHostnameVerififer = verifier; 271 } 272 273 /** 274 * Convenience method for {@link #addDisabledSmackClass(String)}. 275 * 276 * @param clz the Smack class to disable 277 */ 278 public static void addDisabledSmackClass(Class<?> clz) { 279 addDisabledSmackClass(clz.getName()); 280 } 281 282 /** 283 * Add a class to the disabled smack classes. 284 * <p> 285 * {@code className} can also be a package name, in this case, the entire 286 * package is disabled (but can be manually enabled). 287 * </p> 288 * 289 * @param className TODO javadoc me please 290 */ 291 public static void addDisabledSmackClass(String className) { 292 disabledSmackClasses.add(className); 293 } 294 295 /** 296 * Add the given class names to the list of disabled Smack classes. 297 * 298 * @param classNames the Smack classes to disable. 299 * @see #addDisabledSmackClass(String) 300 */ 301 public static void addDisabledSmackClasses(String... classNames) { 302 for (String className : classNames) { 303 addDisabledSmackClass(className); 304 } 305 } 306 307 public static boolean isDisabledSmackClass(String className) { 308 for (String disabledClassOrPackage : disabledSmackClasses) { 309 if (disabledClassOrPackage.equals(className)) { 310 return true; 311 } 312 int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); 313 // Security check to avoid NPEs if someone entered 'foo.bar.' 314 if (disabledClassOrPackage.length() > lastDotIndex 315 // disabledClassOrPackage is not an Class 316 && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) 317 // classToLoad startsWith the package disabledClassOrPackage disables 318 && className.startsWith(disabledClassOrPackage)) { 319 // Skip the class because the whole package was disabled 320 return true; 321 } 322 } 323 return false; 324 } 325 326 /** 327 * Check if Smack was successfully initialized. 328 * 329 * @return true if smack was initialized, false otherwise 330 */ 331 public static boolean isSmackInitialized() { 332 return smackInitialized; 333 } 334 335 /** 336 * Get the default HostnameVerifier 337 * 338 * @return the default HostnameVerifier or <code>null</code> if none was set 339 */ 340 static HostnameVerifier getDefaultHostnameVerifier() { 341 return defaultHostnameVerififer; 342 } 343 344 public enum UnknownIqRequestReplyMode { 345 doNotReply, 346 replyFeatureNotImplemented, 347 replyServiceUnavailable, 348 } 349 350 private static UnknownIqRequestReplyMode unknownIqRequestReplyMode = UnknownIqRequestReplyMode.replyFeatureNotImplemented; 351 352 public static UnknownIqRequestReplyMode getUnknownIqRequestReplyMode() { 353 return unknownIqRequestReplyMode; 354 } 355 356 public static void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) { 357 SmackConfiguration.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Must set mode"); 358 } 359 360 private static final int defaultConcurrencyLevelLimit; 361 362 static { 363 int availableProcessors = Runtime.getRuntime().availableProcessors(); 364 if (availableProcessors < 8) { 365 defaultConcurrencyLevelLimit = 8; 366 } else { 367 defaultConcurrencyLevelLimit = (int) (availableProcessors * 1.1); 368 } 369 } 370 371 public static int getDefaultConcurrencyLevelLimit() { 372 return defaultConcurrencyLevelLimit; 373 } 374 375 private static final Set<Class<? extends ModularXmppClientToServerConnectionModuleDescriptor>> KNOWN_MODULES = new HashSet<>(); 376 377 public static boolean addModule(Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor) { 378 synchronized (KNOWN_MODULES) { 379 return KNOWN_MODULES.add(moduleDescriptor); 380 } 381 } 382 383 public static void addAllKnownModulesTo(ModularXmppClientToServerConnectionConfiguration.Builder builder) { 384 synchronized (KNOWN_MODULES) { 385 for (Class<? extends ModularXmppClientToServerConnectionModuleDescriptor> moduleDescriptor : KNOWN_MODULES) { 386 builder.addModule(moduleDescriptor); 387 } 388 } 389 } 390 391 /** 392 * If enabled, causes {@link AbstractXMPPConnection} to create a thread for every asynchronous send operation. This 393 * is meant to work-around a shortcoming of Smack 4.4, where certain send operations are not asynchronous even if 394 * they should be. This is an expert setting, do not toggle if you do not understand the consequences or have been 395 * told to do so. Note that it is expected that this will not be needed in future Smack versions. 396 * 397 * @since 4.4.6 398 */ 399 public static boolean TRUELY_ASYNC_SENDS = false; 400}