Home | History | Annotate | Download | only in smack
      1 /**
      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 
     21 package org.jivesoftware.smack;
     22 
     23 import java.io.InputStream;
     24 import java.net.URL;
     25 import java.util.ArrayList;
     26 import java.util.Collection;
     27 import java.util.Enumeration;
     28 import java.util.List;
     29 import java.util.Vector;
     30 
     31 import org.xmlpull.v1.XmlPullParserFactory;
     32 import 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  */
     49 public 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 }
    372