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