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<String>(); 059 060 static Set<String> disabledSmackClasses = new HashSet<String>(); 061 062 final static List<XMPPInputOutputStream> compressionHandlers = new ArrayList<XMPPInputOutputStream>(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 apear 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 * <p/> 077 * Debugging can be enabled by setting this field to true, or by setting the Java system 078 * property <tt>smack.debugEnabled</tt> to true. The system property can be set on the 079 * command line such as "java SomeApp -Dsmack.debugEnabled=true". 080 */ 081 public static boolean DEBUG = false; 082 083 /** 084 * The default parsing exception callback is {@link ExceptionThrowingCallback} which will 085 * throw an exception and therefore disconnect the active connection. 086 */ 087 private static ParsingExceptionCallback defaultCallback = new ExceptionThrowingCallback(); 088 089 private static HostnameVerifier defaultHostnameVerififer; 090 091 /** 092 * Returns the Smack version information, eg "1.3.0". 093 * 094 * @return the Smack version information. 095 */ 096 public static String getVersion() { 097 return SmackInitialization.SMACK_VERSION; 098 } 099 100 /** 101 * Returns the number of milliseconds to wait for a response from 102 * the server. The default value is 5000 ms. 103 * 104 * @return the milliseconds to wait for a response from the server 105 * @deprecated use {@link #getDefaultReplyTimeout()} instead. 106 */ 107 @Deprecated 108 public static int getDefaultPacketReplyTimeout() { 109 return getDefaultReplyTimeout(); 110 } 111 112 /** 113 * Sets the number of milliseconds to wait for a response from 114 * the server. 115 * 116 * @param timeout the milliseconds to wait for a response from the server 117 * @deprecated use {@link #setDefaultReplyTimeout(int)} instead. 118 */ 119 @Deprecated 120 public static void setDefaultPacketReplyTimeout(int timeout) { 121 setDefaultReplyTimeout(timeout); 122 } 123 124 /** 125 * Returns the number of milliseconds to wait for a response from 126 * the server. The default value is 5000 ms. 127 * 128 * @return the milliseconds to wait for a response from the server 129 */ 130 public static int getDefaultReplyTimeout() { 131 // The timeout value must be greater than 0 otherwise we will answer the default value 132 if (defaultPacketReplyTimeout <= 0) { 133 defaultPacketReplyTimeout = 5000; 134 } 135 return defaultPacketReplyTimeout; 136 } 137 138 /** 139 * Sets the number of milliseconds to wait for a response from 140 * the server. 141 * 142 * @param timeout the milliseconds to wait for a response from the server 143 */ 144 public static void setDefaultReplyTimeout(int timeout) { 145 if (timeout <= 0) { 146 throw new IllegalArgumentException(); 147 } 148 defaultPacketReplyTimeout = timeout; 149 } 150 151 /** 152 * Gets the default max size of a stanza(/packet) 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(/packet) 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 * Sets Smack debugger factory. 195 * 196 * @param debuggerFactory new debugger factory implementation to be used by Smack 197 */ 198 public static void setDebuggerFactory(SmackDebuggerFactory debuggerFactory) { 199 SmackConfiguration.debuggerFactory = debuggerFactory; 200 } 201 202 /** 203 * Get the debugger factory. 204 * 205 * @return a debugger factory or <code>null</code> 206 */ 207 public static SmackDebuggerFactory getDebuggerFactory() { 208 return debuggerFactory; 209 } 210 211 /** 212 * Creates new debugger instance with given arguments as parameters. May 213 * return <code>null</code> if no DebuggerFactory is set or if the factory 214 * did not produce a debugger. 215 * 216 * @param connection 217 * @param writer 218 * @param reader 219 * @return a new debugger or <code>null</code> 220 */ 221 public static SmackDebugger createDebugger(XMPPConnection connection, Writer writer, Reader reader) { 222 SmackDebuggerFactory factory = getDebuggerFactory(); 223 if (factory == null) { 224 return null; 225 } else { 226 return factory.create(connection, writer, reader); 227 } 228 } 229 230 /** 231 * Remove a SASL mechanism from the list to be used. 232 * 233 * @param mech the SASL mechanism to be removed 234 */ 235 public static void removeSaslMech(String mech) { 236 defaultMechs.remove(mech); 237 } 238 239 /** 240 * Remove a Collection of SASL mechanisms to the list to be used. 241 * 242 * @param mechs the Collection of SASL mechanisms to be removed 243 */ 244 public static void removeSaslMechs(Collection<String> mechs) { 245 defaultMechs.removeAll(mechs); 246 } 247 248 /** 249 * Returns the list of SASL mechanisms to be used. If a SASL mechanism is 250 * listed here it does not guarantee it will be used. The server may not 251 * support it, or it may not be implemented. 252 * 253 * @return the list of SASL mechanisms to be used. 254 */ 255 public static List<String> getSaslMechs() { 256 return Collections.unmodifiableList(defaultMechs); 257 } 258 259 /** 260 * Set the default parsing exception callback for all newly created connections. 261 * 262 * @param callback 263 * @see ParsingExceptionCallback 264 */ 265 public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) { 266 defaultCallback = callback; 267 } 268 269 /** 270 * Returns the default parsing exception callback. 271 * 272 * @return the default parsing exception callback 273 * @see ParsingExceptionCallback 274 */ 275 public static ParsingExceptionCallback getDefaultParsingExceptionCallback() { 276 return defaultCallback; 277 } 278 279 public static void addCompressionHandler(XMPPInputOutputStream xmppInputOutputStream) { 280 compressionHandlers.add(xmppInputOutputStream); 281 } 282 283 public static List<XMPPInputOutputStream> getCompresionHandlers() { 284 List<XMPPInputOutputStream> res = new ArrayList<XMPPInputOutputStream>(compressionHandlers.size()); 285 for (XMPPInputOutputStream ios : compressionHandlers) { 286 if (ios.isSupported()) { 287 res.add(ios); 288 } 289 } 290 return res; 291 } 292 293 /** 294 * Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname 295 * of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a 296 * HostnameVerifier in their ConnecitonConfiguration with 297 * {@link ConnectionConfiguration.Builder#setHostnameVerifier(HostnameVerifier)}. 298 */ 299 public static void setDefaultHostnameVerifier(HostnameVerifier verifier) { 300 defaultHostnameVerififer = verifier; 301 } 302 303 /** 304 * Convenience method for {@link #addDisabledSmackClass(String)}. 305 * 306 * @param clz the Smack class to disable 307 */ 308 public static void addDisabledSmackClass(Class<?> clz) { 309 addDisabledSmackClass(clz.getName()); 310 } 311 312 /** 313 * Add a class to the disabled smack classes. 314 * <p> 315 * {@code className} can also be a package name, in this case, the entire 316 * package is disabled (but can be manually enabled). 317 * </p> 318 * 319 * @param className 320 */ 321 public static void addDisabledSmackClass(String className) { 322 disabledSmackClasses.add(className); 323 } 324 325 /** 326 * Add the given class names to the list of disabled Smack classes. 327 * 328 * @param classNames the Smack classes to disable. 329 * @see #addDisabledSmackClass(String) 330 */ 331 public static void addDisabledSmackClasses(String... classNames) { 332 for (String className : classNames) { 333 addDisabledSmackClass(className); 334 } 335 } 336 337 public static boolean isDisabledSmackClass(String className) { 338 for (String disabledClassOrPackage : disabledSmackClasses) { 339 if (disabledClassOrPackage.equals(className)) { 340 return true; 341 } 342 int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); 343 // Security check to avoid NPEs if someone entered 'foo.bar.' 344 if (disabledClassOrPackage.length() > lastDotIndex 345 // disabledClassOrPackage is not an Class 346 && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) 347 // classToLoad startsWith the package disabledClassOrPackage disables 348 && className.startsWith(disabledClassOrPackage)) { 349 // Skip the class because the whole package was disabled 350 return true; 351 } 352 } 353 return false; 354 } 355 356 /** 357 * Check if Smack was successfully initialized. 358 * 359 * @return true if smack was initialized, false otherwise 360 */ 361 public static boolean isSmackInitialized() { 362 return smackInitialized; 363 } 364 365 /** 366 * Get the default HostnameVerifier 367 * 368 * @return the default HostnameVerifier or <code>null</code> if none was set 369 */ 370 static HostnameVerifier getDefaultHostnameVerifier() { 371 return defaultHostnameVerififer; 372 } 373 374 enum UnknownIqRequestReplyMode { 375 doNotReply, 376 replyFeatureNotImplemented, 377 replyServiceUnavailable, 378 } 379 380 // TODO Change to replyFeatureNotImplemented in Smack 4.3 381 private static UnknownIqRequestReplyMode unknownIqRequestReplyMode = UnknownIqRequestReplyMode.replyServiceUnavailable; 382 383 public static UnknownIqRequestReplyMode getUnknownIqRequestReplyMode() { 384 return unknownIqRequestReplyMode; 385 } 386 387 public static void setUnknownIqRequestReplyMode(UnknownIqRequestReplyMode unknownIqRequestReplyMode) { 388 SmackConfiguration.unknownIqRequestReplyMode = Objects.requireNonNull(unknownIqRequestReplyMode, "Must set mode"); 389 } 390}