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 */ 105 public static int getDefaultPacketReplyTimeout() { 106 // The timeout value must be greater than 0 otherwise we will answer the default value 107 if (defaultPacketReplyTimeout <= 0) { 108 defaultPacketReplyTimeout = 5000; 109 } 110 return defaultPacketReplyTimeout; 111 } 112 113 /** 114 * Sets the number of milliseconds to wait for a response from 115 * the server. 116 * 117 * @param timeout the milliseconds to wait for a response from the server 118 */ 119 public static void setDefaultPacketReplyTimeout(int timeout) { 120 if (timeout <= 0) { 121 throw new IllegalArgumentException(); 122 } 123 defaultPacketReplyTimeout = timeout; 124 } 125 126 /** 127 * Gets the default max size of a stanza(/packet) collector before it will delete 128 * the older packets. 129 * 130 * @return The number of packets to queue before deleting older packets. 131 */ 132 public static int getPacketCollectorSize() { 133 return packetCollectorSize; 134 } 135 136 /** 137 * Sets the default max size of a stanza(/packet) collector before it will delete 138 * the older packets. 139 * 140 * @param collectorSize the number of packets to queue before deleting older packets. 141 */ 142 public static void setPacketCollectorSize(int collectorSize) { 143 packetCollectorSize = collectorSize; 144 } 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 /** 158 * Add a Collection of SASL mechanisms to the list to be used. 159 * 160 * @param mechs the Collection of SASL mechanisms to be added 161 */ 162 public static void addSaslMechs(Collection<String> mechs) { 163 for(String mech : mechs) { 164 addSaslMech(mech); 165 } 166 } 167 168 /** 169 * Sets Smack debugger factory. 170 * 171 * @param debuggerFactory new debugger factory implementation to be used by Smack 172 */ 173 public static void setDebuggerFactory(SmackDebuggerFactory debuggerFactory) { 174 SmackConfiguration.debuggerFactory = debuggerFactory; 175 } 176 177 /** 178 * @return a debugger factory or <code>null</code> 179 */ 180 public static SmackDebuggerFactory getDebuggerFactory() { 181 return debuggerFactory; 182 } 183 184 /** 185 * Creates new debugger instance with given arguments as parameters. May 186 * return <code>null</code> if no DebuggerFactory is set or if the factory 187 * did not produce a debugger. 188 * 189 * @param connection 190 * @param writer 191 * @param reader 192 * @return a new debugger or <code>null</code> 193 */ 194 public static SmackDebugger createDebugger(XMPPConnection connection, Writer writer, Reader reader) { 195 SmackDebuggerFactory factory = getDebuggerFactory(); 196 if (factory == null) { 197 return null; 198 } else { 199 return factory.create(connection, writer, reader); 200 } 201 } 202 203 /** 204 * Remove a SASL mechanism from the list to be used. 205 * 206 * @param mech the SASL mechanism to be removed 207 */ 208 public static void removeSaslMech(String mech) { 209 defaultMechs.remove(mech); 210 } 211 212 /** 213 * Remove a Collection of SASL mechanisms to the list to be used. 214 * 215 * @param mechs the Collection of SASL mechanisms to be removed 216 */ 217 public static void removeSaslMechs(Collection<String> mechs) { 218 defaultMechs.removeAll(mechs); 219 } 220 221 /** 222 * Returns the list of SASL mechanisms to be used. If a SASL mechanism is 223 * listed here it does not guarantee it will be used. The server may not 224 * support it, or it may not be implemented. 225 * 226 * @return the list of SASL mechanisms to be used. 227 */ 228 public static List<String> getSaslMechs() { 229 return Collections.unmodifiableList(defaultMechs); 230 } 231 232 /** 233 * Set the default parsing exception callback for all newly created connections 234 * 235 * @param callback 236 * @see ParsingExceptionCallback 237 */ 238 public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) { 239 defaultCallback = callback; 240 } 241 242 /** 243 * Returns the default parsing exception callback 244 * 245 * @return the default parsing exception callback 246 * @see ParsingExceptionCallback 247 */ 248 public static ParsingExceptionCallback getDefaultParsingExceptionCallback() { 249 return defaultCallback; 250 } 251 252 public static void addCompressionHandler(XMPPInputOutputStream xmppInputOutputStream) { 253 compressionHandlers.add(xmppInputOutputStream); 254 } 255 256 public static List<XMPPInputOutputStream> getCompresionHandlers() { 257 List<XMPPInputOutputStream> res = new ArrayList<XMPPInputOutputStream>(compressionHandlers.size()); 258 for (XMPPInputOutputStream ios : compressionHandlers) { 259 if (ios.isSupported()) { 260 res.add(ios); 261 } 262 } 263 return res; 264 } 265 266 /** 267 * Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname 268 * of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a 269 * HostnameVerifier in their ConnecitonConfiguration with 270 * {@link ConnectionConfiguration.Builder#setHostnameVerifier(HostnameVerifier)}. 271 */ 272 public static void setDefaultHostnameVerifier(HostnameVerifier verifier) { 273 defaultHostnameVerififer = verifier; 274 } 275 276 /** 277 * Convenience method for {@link #addDisabledSmackClass(String)}. 278 * 279 * @param clz the Smack class to disable 280 */ 281 public static void addDisabledSmackClass(Class<?> clz) { 282 addDisabledSmackClass(clz.getName()); 283 } 284 285 /** 286 * Add a class to the disabled smack classes. 287 * <p> 288 * {@code className} can also be a package name, in this case, the entire 289 * package is disabled (but can be manually enabled). 290 * </p> 291 * 292 * @param className 293 */ 294 public static void addDisabledSmackClass(String className) { 295 disabledSmackClasses.add(className); 296 } 297 298 public static boolean isDisabledSmackClass(String className) { 299 for (String disabledClassOrPackage : disabledSmackClasses) { 300 if (disabledClassOrPackage.equals(className)) { 301 return true; 302 } 303 int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); 304 // Security check to avoid NPEs if someone entered 'foo.bar.' 305 if (disabledClassOrPackage.length() > lastDotIndex 306 // disabledClassOrPackage is not an Class 307 && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) 308 // classToLoad startsWith the package disabledClassOrPackage disables 309 && className.startsWith(disabledClassOrPackage)) { 310 // Skip the class because the whole package was disabled 311 return true; 312 } 313 } 314 return false; 315 } 316 317 /** 318 * Check if Smack was successfully initialized. 319 * 320 * @return true if smack was initialized, false otherwise 321 */ 322 public static boolean isSmackInitialized() { 323 return smackInitialized; 324 } 325 326 /** 327 * Get the default HostnameVerifier 328 * 329 * @return the default HostnameVerifier or <code>null</code> if none was set 330 */ 331 static HostnameVerifier getDefaultHostnameVerifier() { 332 return defaultHostnameVerififer; 333 } 334 335}