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; 037 038/** 039 * Represents the configuration of Smack. The configuration is used for: 040 * <ul> 041 * <li> Initializing classes by loading them at start-up. 042 * <li> Getting the current Smack version. 043 * <li> Getting and setting global library behavior, such as the period of time 044 * to wait for replies to packets from the server. Note: setting these values 045 * via the API will override settings in the configuration file. 046 * </ul> 047 * 048 * Configuration settings are stored in org.jivesoftware.smack/smack-config.xml. 049 * 050 * @author Gaston Dombiak 051 */ 052public final class SmackConfiguration { 053 054 private static int defaultPacketReplyTimeout = 5000; 055 private static int packetCollectorSize = 5000; 056 057 private static List<String> defaultMechs = new ArrayList<String>(); 058 059 static Set<String> disabledSmackClasses = new HashSet<String>(); 060 061 final static List<XMPPInputOutputStream> compressionHandlers = new ArrayList<XMPPInputOutputStream>(2); 062 063 static boolean smackInitialized = false; 064 065 private static SmackDebuggerFactory debuggerFactory = new ReflectionDebuggerFactory(); 066 067 /** 068 * Value that indicates whether debugging is enabled. When enabled, a debug 069 * window will apear for each new connection that will contain the following 070 * information:<ul> 071 * <li> Client Traffic -- raw XML traffic generated by Smack and sent to the server. 072 * <li> Server Traffic -- raw XML traffic sent by the server to the client. 073 * <li> Interpreted Packets -- shows XML packets from the server as parsed by Smack. 074 * </ul> 075 * <p/> 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 public static List<XMPPInputOutputStream> getCompresionHandlers() { 283 List<XMPPInputOutputStream> res = new ArrayList<XMPPInputOutputStream>(compressionHandlers.size()); 284 for (XMPPInputOutputStream ios : compressionHandlers) { 285 if (ios.isSupported()) { 286 res.add(ios); 287 } 288 } 289 return res; 290 } 291 292 /** 293 * Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname 294 * of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a 295 * HostnameVerifier in their ConnecitonConfiguration with 296 * {@link ConnectionConfiguration.Builder#setHostnameVerifier(HostnameVerifier)}. 297 */ 298 public static void setDefaultHostnameVerifier(HostnameVerifier verifier) { 299 defaultHostnameVerififer = verifier; 300 } 301 302 /** 303 * Convenience method for {@link #addDisabledSmackClass(String)}. 304 * 305 * @param clz the Smack class to disable 306 */ 307 public static void addDisabledSmackClass(Class<?> clz) { 308 addDisabledSmackClass(clz.getName()); 309 } 310 311 /** 312 * Add a class to the disabled smack classes. 313 * <p> 314 * {@code className} can also be a package name, in this case, the entire 315 * package is disabled (but can be manually enabled). 316 * </p> 317 * 318 * @param className 319 */ 320 public static void addDisabledSmackClass(String className) { 321 disabledSmackClasses.add(className); 322 } 323 324 /** 325 * Add the given class names to the list of disabled Smack classes. 326 * 327 * @param classNames the Smack classes to disable. 328 * @see #addDisabledSmackClass(String) 329 */ 330 public static void addDisabledSmackClasses(String... classNames) { 331 for (String className : classNames) { 332 addDisabledSmackClass(className); 333 } 334 } 335 336 public static boolean isDisabledSmackClass(String className) { 337 for (String disabledClassOrPackage : disabledSmackClasses) { 338 if (disabledClassOrPackage.equals(className)) { 339 return true; 340 } 341 int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); 342 // Security check to avoid NPEs if someone entered 'foo.bar.' 343 if (disabledClassOrPackage.length() > lastDotIndex 344 // disabledClassOrPackage is not an Class 345 && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) 346 // classToLoad startsWith the package disabledClassOrPackage disables 347 && className.startsWith(disabledClassOrPackage)) { 348 // Skip the class because the whole package was disabled 349 return true; 350 } 351 } 352 return false; 353 } 354 355 /** 356 * Check if Smack was successfully initialized. 357 * 358 * @return true if smack was initialized, false otherwise 359 */ 360 public static boolean isSmackInitialized() { 361 return smackInitialized; 362 } 363 364 /** 365 * Get the default HostnameVerifier 366 * 367 * @return the default HostnameVerifier or <code>null</code> if none was set 368 */ 369 static HostnameVerifier getDefaultHostnameVerifier() { 370 return defaultHostnameVerififer; 371 } 372 373}