2014-09-05 12:17:50 +02:00
|
|
|
/**
|
|
|
|
*
|
2016-11-20 19:32:26 +01:00
|
|
|
* Copyright 2003-2007 Jive Software, 2014-2016 Florian Schmaus
|
2014-09-05 12:17:50 +02:00
|
|
|
*
|
|
|
|
* 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.InputStream;
|
|
|
|
import java.io.InputStreamReader;
|
2019-05-08 11:34:40 +02:00
|
|
|
import java.nio.charset.StandardCharsets;
|
2014-09-05 12:17:50 +02:00
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
import org.jivesoftware.smack.compress.provider.CompressedProvider;
|
|
|
|
import org.jivesoftware.smack.compress.provider.FailureProvider;
|
2014-09-05 12:17:50 +02:00
|
|
|
import org.jivesoftware.smack.compression.Java7ZlibInputOutputStream;
|
2019-02-04 08:59:39 +01:00
|
|
|
import org.jivesoftware.smack.compression.XmppCompressionManager;
|
|
|
|
import org.jivesoftware.smack.compression.zlib.ZlibXmppCompressionFactory;
|
2014-09-05 12:17:50 +02:00
|
|
|
import org.jivesoftware.smack.initializer.SmackInitializer;
|
2014-10-30 12:56:10 +01:00
|
|
|
import org.jivesoftware.smack.packet.Bind;
|
2018-05-09 12:37:51 +02:00
|
|
|
import org.jivesoftware.smack.packet.Message.Body;
|
2014-10-30 12:56:10 +01:00
|
|
|
import org.jivesoftware.smack.provider.BindIQProvider;
|
2018-05-09 12:37:51 +02:00
|
|
|
import org.jivesoftware.smack.provider.BodyElementProvider;
|
2014-10-30 12:56:10 +01:00
|
|
|
import org.jivesoftware.smack.provider.ProviderManager;
|
2019-02-04 08:59:39 +01:00
|
|
|
import org.jivesoftware.smack.provider.TlsFailureProvider;
|
|
|
|
import org.jivesoftware.smack.provider.TlsProceedProvider;
|
2015-05-03 22:00:41 +02:00
|
|
|
import org.jivesoftware.smack.sasl.core.SASLAnonymous;
|
2014-11-20 18:50:33 +01:00
|
|
|
import org.jivesoftware.smack.sasl.core.SASLXOauth2Mechanism;
|
2014-10-21 11:59:11 +02:00
|
|
|
import org.jivesoftware.smack.sasl.core.SCRAMSHA1Mechanism;
|
2016-11-20 19:32:26 +01:00
|
|
|
import org.jivesoftware.smack.sasl.core.ScramSha1PlusMechanism;
|
2018-08-15 17:25:22 +02:00
|
|
|
import org.jivesoftware.smack.util.CloseableUtil;
|
2014-09-05 12:17:50 +02:00
|
|
|
import org.jivesoftware.smack.util.FileUtils;
|
2019-05-06 22:06:13 +02:00
|
|
|
import org.jivesoftware.smack.util.PacketParserUtils;
|
2017-06-14 17:12:43 +02:00
|
|
|
|
2019-05-06 22:06:13 +02:00
|
|
|
import org.jivesoftware.smack.xml.XmlPullParser;
|
2014-09-05 12:17:50 +02:00
|
|
|
|
|
|
|
|
|
|
|
public final class SmackInitialization {
|
|
|
|
static final String SMACK_VERSION;
|
|
|
|
|
2018-04-04 16:41:24 +02:00
|
|
|
private static final String DEFAULT_CONFIG_FILE = "org.jivesoftware.smack/smack-config.xml";
|
2014-09-05 12:17:50 +02:00
|
|
|
|
|
|
|
private static final Logger LOGGER = Logger.getLogger(SmackInitialization.class.getName());
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads the configuration from the smack-config.xml and system properties file.
|
|
|
|
* <p>
|
|
|
|
* 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
|
2015-01-18 21:33:03 +01:00
|
|
|
* 3) set DEBUG
|
2014-09-05 12:17:50 +02:00
|
|
|
*/
|
|
|
|
static {
|
|
|
|
String smackVersion;
|
2018-08-15 17:25:22 +02:00
|
|
|
BufferedReader reader = null;
|
2014-09-05 12:17:50 +02:00
|
|
|
try {
|
2019-05-08 11:34:40 +02:00
|
|
|
reader = new BufferedReader(new InputStreamReader(FileUtils.getStreamForClasspathFile("org.jivesoftware.smack/version", null), StandardCharsets.UTF_8));
|
2014-09-05 12:17:50 +02:00
|
|
|
smackVersion = reader.readLine();
|
2017-05-23 16:45:04 +02:00
|
|
|
} catch (Exception e) {
|
2014-09-05 12:17:50 +02:00
|
|
|
LOGGER.log(Level.SEVERE, "Could not determine Smack version", e);
|
2017-12-13 23:10:11 +01:00
|
|
|
smackVersion = "unknown";
|
2018-08-15 17:25:22 +02:00
|
|
|
} finally {
|
|
|
|
CloseableUtil.maybeClose(reader, LOGGER);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
SMACK_VERSION = smackVersion;
|
|
|
|
|
|
|
|
String disabledClasses = System.getProperty("smack.disabledClasses");
|
|
|
|
if (disabledClasses != null) {
|
|
|
|
String[] splitDisabledClasses = disabledClasses.split(",");
|
|
|
|
for (String s : splitDisabledClasses) SmackConfiguration.disabledSmackClasses.add(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
InputStream configFileStream;
|
|
|
|
try {
|
2018-04-04 16:41:24 +02:00
|
|
|
configFileStream = FileUtils.getStreamForClasspathFile(DEFAULT_CONFIG_FILE, null);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
catch (Exception e) {
|
2018-04-04 16:42:29 +02:00
|
|
|
throw new IllegalStateException("Could not load Smack configuration file", e);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
processConfigFile(configFileStream, null);
|
|
|
|
}
|
|
|
|
catch (Exception e) {
|
2018-04-04 16:42:29 +02:00
|
|
|
throw new IllegalStateException("Could not parse Smack configuration file", e);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add the Java7 compression handler first, since it's preferred
|
|
|
|
SmackConfiguration.compressionHandlers.add(new Java7ZlibInputOutputStream());
|
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
XmppCompressionManager.registerXmppCompressionFactory(ZlibXmppCompressionFactory.INSTANCE);
|
|
|
|
|
2014-09-05 12:17:50 +02:00
|
|
|
// Use try block since we may not have permission to get a system
|
|
|
|
// property (for example, when an applet).
|
|
|
|
try {
|
2015-01-18 21:33:03 +01:00
|
|
|
// Only overwrite DEBUG if it is set via the 'smack.debugEnabled' property. To prevent DEBUG_ENABLED
|
2014-10-19 21:48:17 +02:00
|
|
|
// = true, which could be set e.g. via a static block from user code, from being overwritten by the property not set
|
|
|
|
if (Boolean.getBoolean("smack.debugEnabled")) {
|
2015-01-18 21:33:03 +01:00
|
|
|
SmackConfiguration.DEBUG = true;
|
2014-10-19 21:48:17 +02:00
|
|
|
}
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
catch (Exception e) {
|
2018-04-04 16:42:09 +02:00
|
|
|
LOGGER.log(Level.FINE, "Could not handle debugEnable property on Smack initialization", e);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
|
2014-10-21 11:59:11 +02:00
|
|
|
SASLAuthentication.registerSASLMechanism(new SCRAMSHA1Mechanism());
|
2016-11-20 19:32:26 +01:00
|
|
|
SASLAuthentication.registerSASLMechanism(new ScramSha1PlusMechanism());
|
2014-11-20 18:50:33 +01:00
|
|
|
SASLAuthentication.registerSASLMechanism(new SASLXOauth2Mechanism());
|
2015-05-03 22:00:41 +02:00
|
|
|
SASLAuthentication.registerSASLMechanism(new SASLAnonymous());
|
2014-10-21 11:59:11 +02:00
|
|
|
|
2014-10-30 12:56:10 +01:00
|
|
|
ProviderManager.addIQProvider(Bind.ELEMENT, Bind.NAMESPACE, new BindIQProvider());
|
2018-05-09 12:37:51 +02:00
|
|
|
ProviderManager.addExtensionProvider(Body.ELEMENT, Body.NAMESPACE, new BodyElementProvider());
|
2014-10-30 12:56:10 +01:00
|
|
|
|
2019-02-04 08:59:39 +01:00
|
|
|
ProviderManager.addNonzaProvider(TlsProceedProvider.INSTANCE);
|
|
|
|
ProviderManager.addNonzaProvider(TlsFailureProvider.INSTANCE);
|
|
|
|
ProviderManager.addNonzaProvider(CompressedProvider.INSTANCE);
|
|
|
|
ProviderManager.addNonzaProvider(FailureProvider.INSTANCE);
|
|
|
|
|
2014-09-05 12:17:50 +02:00
|
|
|
SmackConfiguration.smackInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void processConfigFile(InputStream cfgFileStream,
|
|
|
|
Collection<Exception> exceptions) throws Exception {
|
|
|
|
processConfigFile(cfgFileStream, exceptions, SmackInitialization.class.getClassLoader());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void processConfigFile(InputStream cfgFileStream,
|
|
|
|
Collection<Exception> exceptions, ClassLoader classLoader) throws Exception {
|
2019-05-06 22:06:13 +02:00
|
|
|
XmlPullParser parser = PacketParserUtils.getParserFor(cfgFileStream);
|
|
|
|
XmlPullParser.Event eventType = parser.getEventType();
|
2014-09-05 12:17:50 +02:00
|
|
|
do {
|
2019-05-06 22:06:13 +02:00
|
|
|
if (eventType == XmlPullParser.Event.START_ELEMENT) {
|
2014-09-05 12:17:50 +02:00
|
|
|
if (parser.getName().equals("startupClasses")) {
|
|
|
|
parseClassesToLoad(parser, false, exceptions, classLoader);
|
|
|
|
}
|
|
|
|
else if (parser.getName().equals("optionalStartupClasses")) {
|
|
|
|
parseClassesToLoad(parser, true, exceptions, classLoader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eventType = parser.next();
|
|
|
|
}
|
2019-05-06 22:06:13 +02:00
|
|
|
while (eventType != XmlPullParser.Event.END_DOCUMENT);
|
2018-08-15 17:25:22 +02:00
|
|
|
CloseableUtil.maybeClose(cfgFileStream, LOGGER);
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void parseClassesToLoad(XmlPullParser parser, boolean optional,
|
|
|
|
Collection<Exception> exceptions, ClassLoader classLoader)
|
2017-12-13 23:10:11 +01:00
|
|
|
throws Exception {
|
2014-09-05 12:17:50 +02:00
|
|
|
final String startName = parser.getName();
|
2019-05-06 22:06:13 +02:00
|
|
|
XmlPullParser.Event eventType;
|
2014-09-25 09:42:55 +02:00
|
|
|
outerloop: do {
|
2014-09-05 12:17:50 +02:00
|
|
|
eventType = parser.next();
|
2019-05-06 22:06:13 +02:00
|
|
|
if (eventType == XmlPullParser.Event.START_ELEMENT && "className".equals(parser.getName())) {
|
2014-09-05 12:17:50 +02:00
|
|
|
String classToLoad = parser.nextText();
|
2014-11-21 18:21:54 +01:00
|
|
|
if (SmackConfiguration.isDisabledSmackClass(classToLoad)) {
|
|
|
|
continue outerloop;
|
2014-09-25 09:42:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-06 22:06:13 +02:00
|
|
|
while (!(eventType == XmlPullParser.Event.END_ELEMENT && startName.equals(parser.getName())));
|
2014-09-05 12:17:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2017-02-11 16:16:41 +01:00
|
|
|
SmackInitializer initializer = (SmackInitializer) initClass.getConstructor().newInstance();
|
2014-09-05 12:17:50 +02:00
|
|
|
List<Exception> 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|