From af9b9a876905a15db13f1be5e2a4134b2474b826 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 5 Sep 2014 12:17:50 +0200 Subject: [PATCH] Split SmackConfiguration into Configuration and Initalization also add SmackConfiguration.addDisabledSmackClass() --- .../smack/SmackConfiguration.java | 236 +++--------------- .../smack/SmackInitialization.java | 233 +++++++++++++++++ .../smack/initializer/UrlInitializer.java | 4 +- .../smack/SmackConfigurationTest.java | 27 ++ 4 files changed, 294 insertions(+), 206 deletions(-) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java index 9664603c5..87c4377d3 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -17,36 +17,23 @@ package org.jivesoftware.smack; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; import java.io.Writer; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.net.ssl.HostnameVerifier; -import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream; import org.jivesoftware.smack.compression.XMPPInputOutputStream; import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory; import org.jivesoftware.smack.debugger.SmackDebugger; import org.jivesoftware.smack.debugger.SmackDebuggerFactory; -import org.jivesoftware.smack.initializer.SmackInitializer; import org.jivesoftware.smack.parsing.ExceptionThrowingCallback; import org.jivesoftware.smack.parsing.ParsingExceptionCallback; -import org.jivesoftware.smack.util.FileUtils; -import org.xmlpull.v1.XmlPullParserFactory; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; /** * Represents the configuration of Smack. The configuration is used for: @@ -63,19 +50,17 @@ import org.xmlpull.v1.XmlPullParserException; * @author Gaston Dombiak */ public final class SmackConfiguration { - private static final String SMACK_VERSION; - private static final String DEFAULT_CONFIG_FILE = "classpath:org.jivesoftware.smack/smack-config.xml"; - - private static final Logger LOGGER = Logger.getLogger(SmackConfiguration.class.getName()); private static int defaultPacketReplyTimeout = 5000; private static int packetCollectorSize = 5000; private static List defaultMechs = new ArrayList(); - private static Set disabledSmackClasses = new HashSet(); + static Set disabledSmackClasses = new HashSet(); - private final static List compressionHandlers = new ArrayList(2); + final static List compressionHandlers = new ArrayList(2); + + static boolean smackInitialized = false; private static SmackDebuggerFactory debuggerFactory = new ReflectionDebuggerFactory(); @@ -94,89 +79,6 @@ public final class SmackConfiguration { */ public static boolean DEBUG_ENABLED = false; - /** - * Loads the configuration from the smack-config.xml and system properties file. - *

- * So far this means that: - * 1) a set of classes will be loaded in order to execute their static init block - * 2) retrieve and set the current Smack release - * 3) set DEBUG_ENABLED - */ - static { - String smackVersion; - try { - BufferedReader reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForUrl("classpath:org.jivesoftware.smack/version", null))); - smackVersion = reader.readLine(); - try { - reader.close(); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "IOException closing stream", e); - } - } catch(Exception e) { - LOGGER.log(Level.SEVERE, "Could not determine Smack version", e); - smackVersion = "unkown"; - } - SMACK_VERSION = smackVersion; - - String disabledClasses = System.getProperty("smack.disabledClasses"); - if (disabledClasses != null) { - String[] splitDisabledClasses = disabledClasses.split(","); - for (String s : splitDisabledClasses) disabledSmackClasses.add(s); - } - try { - FileUtils.addLines("classpath:org.jivesoftware.smack/disabledClasses", disabledSmackClasses); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - - try { - Class c = Class.forName("org.jivesoftware.smack.CustomSmackConfiguration"); - Field f = c.getField("DISABLED_SMACK_CLASSES"); - String[] sa = (String[]) f.get(null); - if (sa != null) - for (String s : sa) - disabledSmackClasses.add(s); - } - catch (ClassNotFoundException e1) { - } - catch (NoSuchFieldException e) { - } - catch (SecurityException e) { - } - catch (IllegalArgumentException e) { - } - catch (IllegalAccessException e) { - } - - InputStream configFileStream; - try { - configFileStream = FileUtils.getStreamForUrl(DEFAULT_CONFIG_FILE, null); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - - try { - processConfigFile(configFileStream, null); - } - catch (Exception e) { - throw new IllegalStateException(e); - } - - // Add the Java7 compression handler first, since it's preferred - compressionHandlers.add(new Java7ZlibInputOutputStream()); - - // Use try block since we may not have permission to get a system - // property (for example, when an applet). - try { - DEBUG_ENABLED = Boolean.getBoolean("smack.debugEnabled"); - } - catch (Exception e) { - // Ignore. - } - } - /** * The default parsing exception callback is {@link ExceptionThrowingCallback} which will * throw an exception and therefore disconnect the active connection. @@ -191,7 +93,7 @@ public final class SmackConfiguration { * @return the Smack version information. */ public static String getVersion() { - return SMACK_VERSION; + return SmackInitialization.SMACK_VERSION; } /** @@ -371,6 +273,33 @@ public final class SmackConfiguration { defaultHostnameVerififer = verifier; } + /** + * Convenience method for {@link #addDisabledSmackClass(String)}. + * + * @param clz the Smack class to disable + */ + public static void addDisabledSmackClass(Class clz) { + addDisabledSmackClass(clz.getName()); + } + + /** + * Add a class to the disabled smack classes + * + * @param className + */ + public static void addDisabledSmackClass(String className) { + disabledSmackClasses.add(className); + } + + /** + * Check if Smack was successfully initialized. + * + * @return true if smack was initialized, false otherwise + */ + public static boolean isSmackInitialized() { + return smackInitialized; + } + /** * Get the default HostnameVerifier * @@ -380,105 +309,4 @@ public final class SmackConfiguration { return defaultHostnameVerififer; } - public static void processConfigFile(InputStream cfgFileStream, - Collection exceptions) throws Exception { - processConfigFile(cfgFileStream, exceptions, SmackConfiguration.class.getClassLoader()); - } - - public static void processConfigFile(InputStream cfgFileStream, - Collection exceptions, ClassLoader classLoader) throws Exception { - XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); - parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); - parser.setInput(cfgFileStream, "UTF-8"); - int eventType = parser.getEventType(); - do { - if (eventType == XmlPullParser.START_TAG) { - if (parser.getName().equals("startupClasses")) { - parseClassesToLoad(parser, false, exceptions, classLoader); - } - else if (parser.getName().equals("optionalStartupClasses")) { - parseClassesToLoad(parser, true, exceptions, classLoader); - } - } - eventType = parser.next(); - } - while (eventType != XmlPullParser.END_DOCUMENT); - try { - cfgFileStream.close(); - } - catch (IOException e) { - LOGGER.log(Level.SEVERE, "Error while closing config file input stream", e); - } - } - - private static void parseClassesToLoad(XmlPullParser parser, boolean optional, - Collection exceptions, ClassLoader classLoader) - throws XmlPullParserException, IOException, Exception { - final String startName = parser.getName(); - int eventType; - String name; - do { - eventType = parser.next(); - name = parser.getName(); - if (eventType == XmlPullParser.START_TAG && "className".equals(name)) { - String classToLoad = parser.nextText(); - if (disabledSmackClasses.contains(classToLoad)) { - LOGGER.info("Not loading disabled Smack class " + classToLoad); - } - else { - try { - loadSmackClass(classToLoad, optional, classLoader); - } - catch (Exception e) { - // Don't throw the exception if an exceptions collection is given, instead - // record it there. This is used for unit testing purposes. - if (exceptions != null) { - exceptions.add(e); - } - else { - throw e; - } - } - } - } - } - while (!(eventType == XmlPullParser.END_TAG && startName.equals(name))); - } - - private static void loadSmackClass(String className, boolean optional, ClassLoader classLoader) throws Exception { - Class initClass; - try { - // Attempt to load and initialize the class so that all static initializer blocks of - // class are executed - initClass = Class.forName(className, true, classLoader); - } - catch (ClassNotFoundException cnfe) { - Level logLevel; - if (optional) { - logLevel = Level.FINE; - } - else { - logLevel = Level.WARNING; - } - LOGGER.log(logLevel, "A startup class '" + className + "' could not be loaded."); - if (!optional) { - throw cnfe; - } else { - return; - } - } - if (SmackInitializer.class.isAssignableFrom(initClass)) { - SmackInitializer initializer = (SmackInitializer) initClass.newInstance(); - List exceptions = initializer.initialize(); - if (exceptions == null || exceptions.size() == 0) { - LOGGER.log(Level.FINE, "Loaded SmackInitializer " + className); - } else { - for (Exception e : exceptions) { - LOGGER.log(Level.SEVERE, "Exception in loadSmackClass", e); - } - } - } else { - LOGGER.log(Level.FINE, "Loaded " + className); - } - } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java new file mode 100644 index 000000000..e443092dc --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java @@ -0,0 +1,233 @@ +/** + * + * Copyright 2003-2007 Jive Software, 2014 Florian Schmaus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jivesoftware.smack; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream; +import org.jivesoftware.smack.initializer.SmackInitializer; +import org.jivesoftware.smack.util.FileUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + + +public final class SmackInitialization { + static final String SMACK_VERSION; + + private static final String DEFAULT_CONFIG_FILE = "classpath:org.jivesoftware.smack/smack-config.xml"; + + private static final Logger LOGGER = Logger.getLogger(SmackInitialization.class.getName()); + + /** + * Loads the configuration from the smack-config.xml and system properties file. + *

+ * So far this means that: + * 1) a set of classes will be loaded in order to execute their static init block + * 2) retrieve and set the current Smack release + * 3) set DEBUG_ENABLED + */ + static { + String smackVersion; + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForUrl("classpath:org.jivesoftware.smack/version", null))); + smackVersion = reader.readLine(); + try { + reader.close(); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "IOException closing stream", e); + } + } catch(Exception e) { + LOGGER.log(Level.SEVERE, "Could not determine Smack version", e); + smackVersion = "unkown"; + } + SMACK_VERSION = smackVersion; + + String disabledClasses = System.getProperty("smack.disabledClasses"); + if (disabledClasses != null) { + String[] splitDisabledClasses = disabledClasses.split(","); + for (String s : splitDisabledClasses) SmackConfiguration.disabledSmackClasses.add(s); + } + try { + FileUtils.addLines("classpath:org.jivesoftware.smack/disabledClasses", SmackConfiguration.disabledSmackClasses); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + + try { + Class c = Class.forName("org.jivesoftware.smack.CustomSmackConfiguration"); + Field f = c.getField("DISABLED_SMACK_CLASSES"); + String[] sa = (String[]) f.get(null); + if (sa != null) { + LOGGER.warning("Using CustomSmackConfig is deprecated and will be removed in a future release"); + for (String s : sa) + SmackConfiguration.disabledSmackClasses.add(s); + } + } + catch (ClassNotFoundException e1) { + } + catch (NoSuchFieldException e) { + } + catch (SecurityException e) { + } + catch (IllegalArgumentException e) { + } + catch (IllegalAccessException e) { + } + + InputStream configFileStream; + try { + configFileStream = FileUtils.getStreamForUrl(DEFAULT_CONFIG_FILE, null); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + + try { + processConfigFile(configFileStream, null); + } + catch (Exception e) { + throw new IllegalStateException(e); + } + + // Add the Java7 compression handler first, since it's preferred + SmackConfiguration.compressionHandlers.add(new Java7ZlibInputOutputStream()); + + // Use try block since we may not have permission to get a system + // property (for example, when an applet). + try { + SmackConfiguration.DEBUG_ENABLED = Boolean.getBoolean("smack.debugEnabled"); + } + catch (Exception e) { + // Ignore. + } + + SmackConfiguration.smackInitialized = true; + } + + public static void processConfigFile(InputStream cfgFileStream, + Collection exceptions) throws Exception { + processConfigFile(cfgFileStream, exceptions, SmackInitialization.class.getClassLoader()); + } + + public static void processConfigFile(InputStream cfgFileStream, + Collection exceptions, ClassLoader classLoader) throws Exception { + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(cfgFileStream, "UTF-8"); + int eventType = parser.getEventType(); + do { + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals("startupClasses")) { + parseClassesToLoad(parser, false, exceptions, classLoader); + } + else if (parser.getName().equals("optionalStartupClasses")) { + parseClassesToLoad(parser, true, exceptions, classLoader); + } + } + eventType = parser.next(); + } + while (eventType != XmlPullParser.END_DOCUMENT); + try { + cfgFileStream.close(); + } + catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error while closing config file input stream", e); + } + } + + private static void parseClassesToLoad(XmlPullParser parser, boolean optional, + Collection exceptions, ClassLoader classLoader) + throws XmlPullParserException, IOException, Exception { + final String startName = parser.getName(); + int eventType; + String name; + do { + eventType = parser.next(); + name = parser.getName(); + if (eventType == XmlPullParser.START_TAG && "className".equals(name)) { + String classToLoad = parser.nextText(); + if (SmackConfiguration.disabledSmackClasses.contains(classToLoad)) { + LOGGER.info("Not loading disabled Smack class " + classToLoad); + } + else { + try { + loadSmackClass(classToLoad, optional, classLoader); + } + catch (Exception e) { + // Don't throw the exception if an exceptions collection is given, instead + // record it there. This is used for unit testing purposes. + if (exceptions != null) { + exceptions.add(e); + } + else { + throw e; + } + } + } + } + } + while (!(eventType == XmlPullParser.END_TAG && startName.equals(name))); + } + + private static void loadSmackClass(String className, boolean optional, ClassLoader classLoader) throws Exception { + Class initClass; + try { + // Attempt to load and initialize the class so that all static initializer blocks of + // class are executed + initClass = Class.forName(className, true, classLoader); + } + catch (ClassNotFoundException cnfe) { + Level logLevel; + if (optional) { + logLevel = Level.FINE; + } + else { + logLevel = Level.WARNING; + } + LOGGER.log(logLevel, "A startup class '" + className + "' could not be loaded."); + if (!optional) { + throw cnfe; + } else { + return; + } + } + if (SmackInitializer.class.isAssignableFrom(initClass)) { + SmackInitializer initializer = (SmackInitializer) initClass.newInstance(); + List exceptions = initializer.initialize(); + if (exceptions == null || exceptions.size() == 0) { + LOGGER.log(Level.FINE, "Loaded SmackInitializer " + className); + } else { + for (Exception e : exceptions) { + LOGGER.log(Level.SEVERE, "Exception in loadSmackClass", e); + } + } + } else { + LOGGER.log(Level.FINE, "Loaded " + className); + } + } +} diff --git a/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java b/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java index e2f13b474..c3c876cd2 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/initializer/UrlInitializer.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import org.jivesoftware.smack.SmackConfiguration; +import org.jivesoftware.smack.SmackInitialization; import org.jivesoftware.smack.provider.ProviderFileLoader; import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smack.util.FileUtils; @@ -72,7 +72,7 @@ public abstract class UrlInitializer extends SmackAndOsgiInitializer { if (configUrl != null) { try { is = FileUtils.getStreamForUrl(configUrl, classLoader); - SmackConfiguration.processConfigFile(is, exceptions, classLoader); + SmackInitialization.processConfigFile(is, exceptions, classLoader); } catch (Exception e) { exceptions.add(e); diff --git a/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java b/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java index d8cbd688d..d93a7c5ce 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/SmackConfigurationTest.java @@ -16,8 +16,11 @@ */ package org.jivesoftware.smack; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.junit.Ignore; import org.junit.Test; public class SmackConfigurationTest { @@ -30,4 +33,28 @@ public class SmackConfigurationTest { fail("SmackConfiguration threw Throwable"); } } + + // As there is currently no annotation/way to run a testclass/single test in a separate VM, + // which is required for reliable results of this test, and we don't want to fork a VM for + // *every* test, those tests are currently disabled. Hopefully this will change in the future. + @Ignore + @Test + public void smackConfigurationShouldNotCauseInitializationTest() { + SmackConfiguration.getDefaultPacketReplyTimeout(); + + // Only a call to SmackConfiguration.getVersion() should cause Smack to become initialized. + assertFalse(SmackConfiguration.isSmackInitialized()); + } + + // As there is currently no annotation/way to run a testclass/single test in a separate VM, + // which is required for reliable results of this test, and we don't want to fork a VM for + // *every* test, those tests are currently disabled. Hopefully this will change in the future. + @Ignore + @Test + public void smackconfigurationVersionShouldInitialzieSmacktTest() { + SmackConfiguration.getVersion(); + + // Only a call to SmackConfiguration.getVersion() should cause Smack to become initialized. + assertTrue(SmackConfiguration.isSmackInitialized()); + } }