blob: 2696d872a5c45075fa470603a64a87bd1e1b6bf8 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * Copyright 2003-2007 Jive Software.
7 *
8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package org.jivesoftware.smack;
22
23import java.io.InputStream;
24import java.net.URL;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Enumeration;
28import java.util.List;
29import java.util.Vector;
30
31import org.xmlpull.v1.XmlPullParserFactory;
32import org.xmlpull.v1.XmlPullParser;
33
34/**
35 * Represents the configuration of Smack. The configuration is used for:
36 * <ul>
37 * <li> Initializing classes by loading them at start-up.
38 * <li> Getting the current Smack version.
39 * <li> Getting and setting global library behavior, such as the period of time
40 * to wait for replies to packets from the server. Note: setting these values
41 * via the API will override settings in the configuration file.
42 * </ul>
43 *
44 * Configuration settings are stored in META-INF/smack-config.xml (typically inside the
45 * smack.jar file).
46 *
47 * @author Gaston Dombiak
48 */
49public final class SmackConfiguration {
50
51 private static final String SMACK_VERSION = "3.2.2";
52
53 private static int packetReplyTimeout = 5000;
54 private static Vector<String> defaultMechs = new Vector<String>();
55
56 private static boolean localSocks5ProxyEnabled = true;
57 private static int localSocks5ProxyPort = 7777;
58 private static int packetCollectorSize = 5000;
59
60 /**
61 * defaultPingInterval (in seconds)
62 */
63 private static int defaultPingInterval = 1800; // 30 min (30*60)
64
65 /**
66 * This automatically enables EntityCaps for new connections if it is set to true
67 */
68 private static boolean autoEnableEntityCaps = false;
69
70 private SmackConfiguration() {
71 }
72
73 /**
74 * Loads the configuration from the smack-config.xml file.<p>
75 *
76 * So far this means that:
77 * 1) a set of classes will be loaded in order to execute their static init block
78 * 2) retrieve and set the current Smack release
79 */
80 static {
81 try {
82 // Get an array of class loaders to try loading the providers files from.
83 ClassLoader[] classLoaders = getClassLoaders();
84 for (ClassLoader classLoader : classLoaders) {
85 Enumeration<URL> configEnum = classLoader.getResources("META-INF/smack-config.xml");
86 while (configEnum.hasMoreElements()) {
87 URL url = configEnum.nextElement();
88 InputStream systemStream = null;
89 try {
90 systemStream = url.openStream();
91 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
92 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
93 parser.setInput(systemStream, "UTF-8");
94 int eventType = parser.getEventType();
95 do {
96 if (eventType == XmlPullParser.START_TAG) {
97 if (parser.getName().equals("className")) {
98 // Attempt to load the class so that the class can get initialized
99 parseClassToLoad(parser);
100 }
101 else if (parser.getName().equals("packetReplyTimeout")) {
102 packetReplyTimeout = parseIntProperty(parser, packetReplyTimeout);
103 }
104 else if (parser.getName().equals("mechName")) {
105 defaultMechs.add(parser.nextText());
106 }
107 else if (parser.getName().equals("localSocks5ProxyEnabled")) {
108 localSocks5ProxyEnabled = Boolean.parseBoolean(parser.nextText());
109 }
110 else if (parser.getName().equals("localSocks5ProxyPort")) {
111 localSocks5ProxyPort = parseIntProperty(parser, localSocks5ProxyPort);
112 }
113 else if (parser.getName().equals("packetCollectorSize")) {
114 packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
115 }
116 else if (parser.getName().equals("defaultPingInterval")) {
117 defaultPingInterval = parseIntProperty(parser, defaultPingInterval);
118 }
119 else if (parser.getName().equals("autoEnableEntityCaps")) {
120 autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
121 }
122 }
123 eventType = parser.next();
124 }
125 while (eventType != XmlPullParser.END_DOCUMENT);
126 }
127 catch (Exception e) {
128 e.printStackTrace();
129 }
130 finally {
131 try {
132 systemStream.close();
133 }
134 catch (Exception e) {
135 // Ignore.
136 }
137 }
138 }
139 }
140 }
141 catch (Exception e) {
142 e.printStackTrace();
143 }
144 }
145
146 /**
147 * Returns the Smack version information, eg "1.3.0".
148 *
149 * @return the Smack version information.
150 */
151 public static String getVersion() {
152 return SMACK_VERSION;
153 }
154
155 /**
156 * Returns the number of milliseconds to wait for a response from
157 * the server. The default value is 5000 ms.
158 *
159 * @return the milliseconds to wait for a response from the server
160 */
161 public static int getPacketReplyTimeout() {
162 // The timeout value must be greater than 0 otherwise we will answer the default value
163 if (packetReplyTimeout <= 0) {
164 packetReplyTimeout = 5000;
165 }
166 return packetReplyTimeout;
167 }
168
169 /**
170 * Sets the number of milliseconds to wait for a response from
171 * the server.
172 *
173 * @param timeout the milliseconds to wait for a response from the server
174 */
175 public static void setPacketReplyTimeout(int timeout) {
176 if (timeout <= 0) {
177 throw new IllegalArgumentException();
178 }
179 packetReplyTimeout = timeout;
180 }
181
182 /**
183 * Gets the default max size of a packet collector before it will delete
184 * the older packets.
185 *
186 * @return The number of packets to queue before deleting older packets.
187 */
188 public static int getPacketCollectorSize() {
189 return packetCollectorSize;
190 }
191
192 /**
193 * Sets the default max size of a packet collector before it will delete
194 * the older packets.
195 *
196 * @param The number of packets to queue before deleting older packets.
197 */
198 public static void setPacketCollectorSize(int collectorSize) {
199 packetCollectorSize = collectorSize;
200 }
201
202 /**
203 * Add a SASL mechanism to the list to be used.
204 *
205 * @param mech the SASL mechanism to be added
206 */
207 public static void addSaslMech(String mech) {
208 if(! defaultMechs.contains(mech) ) {
209 defaultMechs.add(mech);
210 }
211 }
212
213 /**
214 * Add a Collection of SASL mechanisms to the list to be used.
215 *
216 * @param mechs the Collection of SASL mechanisms to be added
217 */
218 public static void addSaslMechs(Collection<String> mechs) {
219 for(String mech : mechs) {
220 addSaslMech(mech);
221 }
222 }
223
224 /**
225 * Remove a SASL mechanism from the list to be used.
226 *
227 * @param mech the SASL mechanism to be removed
228 */
229 public static void removeSaslMech(String mech) {
230 if( defaultMechs.contains(mech) ) {
231 defaultMechs.remove(mech);
232 }
233 }
234
235 /**
236 * Remove a Collection of SASL mechanisms to the list to be used.
237 *
238 * @param mechs the Collection of SASL mechanisms to be removed
239 */
240 public static void removeSaslMechs(Collection<String> mechs) {
241 for(String mech : mechs) {
242 removeSaslMech(mech);
243 }
244 }
245
246 /**
247 * Returns the list of SASL mechanisms to be used. If a SASL mechanism is
248 * listed here it does not guarantee it will be used. The server may not
249 * support it, or it may not be implemented.
250 *
251 * @return the list of SASL mechanisms to be used.
252 */
253 public static List<String> getSaslMechs() {
254 return defaultMechs;
255 }
256
257 /**
258 * Returns true if the local Socks5 proxy should be started. Default is true.
259 *
260 * @return if the local Socks5 proxy should be started
261 */
262 public static boolean isLocalSocks5ProxyEnabled() {
263 return localSocks5ProxyEnabled;
264 }
265
266 /**
267 * Sets if the local Socks5 proxy should be started. Default is true.
268 *
269 * @param localSocks5ProxyEnabled if the local Socks5 proxy should be started
270 */
271 public static void setLocalSocks5ProxyEnabled(boolean localSocks5ProxyEnabled) {
272 SmackConfiguration.localSocks5ProxyEnabled = localSocks5ProxyEnabled;
273 }
274
275 /**
276 * Return the port of the local Socks5 proxy. Default is 7777.
277 *
278 * @return the port of the local Socks5 proxy
279 */
280 public static int getLocalSocks5ProxyPort() {
281 return localSocks5ProxyPort;
282 }
283
284 /**
285 * Sets the port of the local Socks5 proxy. Default is 7777. If you set the port to a negative
286 * value Smack tries the absolute value and all following until it finds an open port.
287 *
288 * @param localSocks5ProxyPort the port of the local Socks5 proxy to set
289 */
290 public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) {
291 SmackConfiguration.localSocks5ProxyPort = localSocks5ProxyPort;
292 }
293
294 /**
295 * Returns the default ping interval (seconds)
296 *
297 * @return
298 */
299 public static int getDefaultPingInterval() {
300 return defaultPingInterval;
301 }
302
303 /**
304 * Sets the default ping interval (seconds). Set it to '-1' to disable the periodic ping
305 *
306 * @param defaultPingInterval
307 */
308 public static void setDefaultPingInterval(int defaultPingInterval) {
309 SmackConfiguration.defaultPingInterval = defaultPingInterval;
310 }
311
312 /**
313 * Check if Entity Caps are enabled as default for every new connection
314 * @return
315 */
316 public static boolean autoEnableEntityCaps() {
317 return autoEnableEntityCaps;
318 }
319
320 /**
321 * Set if Entity Caps are enabled or disabled for every new connection
322 *
323 * @param true if Entity Caps should be auto enabled, false if not
324 */
325 public static void setAutoEnableEntityCaps(boolean b) {
326 autoEnableEntityCaps = b;
327 }
328
329 private static void parseClassToLoad(XmlPullParser parser) throws Exception {
330 String className = parser.nextText();
331 // Attempt to load the class so that the class can get initialized
332 try {
333 Class.forName(className);
334 }
335 catch (ClassNotFoundException cnfe) {
336 System.err.println("Error! A startup class specified in smack-config.xml could " +
337 "not be loaded: " + className);
338 }
339 }
340
341 private static int parseIntProperty(XmlPullParser parser, int defaultValue)
342 throws Exception
343 {
344 try {
345 return Integer.parseInt(parser.nextText());
346 }
347 catch (NumberFormatException nfe) {
348 nfe.printStackTrace();
349 return defaultValue;
350 }
351 }
352
353 /**
354 * Returns an array of class loaders to load resources from.
355 *
356 * @return an array of ClassLoader instances.
357 */
358 private static ClassLoader[] getClassLoaders() {
359 ClassLoader[] classLoaders = new ClassLoader[2];
360 classLoaders[0] = SmackConfiguration.class.getClassLoader();
361 classLoaders[1] = Thread.currentThread().getContextClassLoader();
362 // Clean up possible null values. Note that #getClassLoader may return a null value.
363 List<ClassLoader> loaders = new ArrayList<ClassLoader>();
364 for (ClassLoader classLoader : classLoaders) {
365 if (classLoader != null) {
366 loaders.add(classLoader);
367 }
368 }
369 return loaders.toArray(new ClassLoader[loaders.size()]);
370 }
371}