1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2025-09-10 18:59:41 +02:00

Reworked Smack initialization

Move extension relevant configuration options from SmackConfiguration to
the extension. Introduced disabledSmackClasses that can be configured
via a system property or configuration file.
This commit is contained in:
Florian Schmaus 2014-02-23 17:48:07 +01:00
parent 4121ec2c0e
commit 3093333533
11 changed files with 193 additions and 338 deletions

View file

@ -22,7 +22,9 @@ import java.io.InputStream;
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;
@ -54,17 +56,13 @@ public final class SmackConfiguration {
private static final String DEFAULT_CONFIG_FILE = "classpath:org.jivesoftware.smack/smack-config.xml";
private static final Logger log = Logger.getLogger(SmackConfiguration.class.getName());
private static InputStream configFileStream;
private static int defaultPacketReplyTimeout = 5000;
private static int packetCollectorSize = 5000;
private static List<String> defaultMechs = new ArrayList<String>();
private static boolean localSocks5ProxyEnabled = true;
private static int localSocks5ProxyPort = 7777;
private static int packetCollectorSize = 5000;
private static boolean initialized = false;
private static Set<String> disabledSmackClasses = new HashSet<String>();
static {
String smackVersion;
@ -78,6 +76,34 @@ public final class SmackConfiguration {
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);
}
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);
}
}
/**
@ -86,11 +112,6 @@ public final class SmackConfiguration {
*/
private static ParsingExceptionCallback defaultCallback = new ExceptionThrowingCallback();
/**
* This automatically enables EntityCaps for new connections if it is set to true
*/
private static boolean autoEnableEntityCaps = true;
private SmackConfiguration() {
}
@ -101,39 +122,7 @@ public final class SmackConfiguration {
* 1) a set of classes will be loaded in order to execute their static init block
* 2) retrieve and set the current Smack release
*/
/**
* Sets the location of the config file on the classpath. Only required if changing from the default location of <i>classpath:org.jivesoftware.smack/smack-config.xml</i>.
*
* <p>
* This method must be called before accessing any other class in Smack.
*
* @param configFileUrl The location of the config file.
* @param loader The classloader to use if the URL has a protocol of <b>classpath</> and the file is not located on the default classpath.
* This can be set to null to use defaults and is ignored for all other protocols.
* @throws IllegalArgumentException If the config URL is invalid in that it cannot open an {@link InputStream}
*/
public static void setConfigFileUrl(String configFileUrl, ClassLoader loader) {
try {
configFileStream = FileUtils.getStreamForUrl(configFileUrl, loader);
}
catch (Exception e) {
throw new IllegalArgumentException("Failed to create input stream from specified file URL ["+ configFileUrl + "]", e);
}
initialize();
}
/**
* Sets the {@link InputStream} representing the smack configuration file. This can be used to override the default with something that is not on the classpath.
* <p>
* This method must be called before accessing any other class in Smack.
* @param configFile
*/
public static void setConfigFileStream(InputStream configFile) {
configFileStream = configFile;
initialize();
}
/**
* Returns the Smack version information, eg "1.3.0".
*
@ -150,8 +139,6 @@ public final class SmackConfiguration {
* @return the milliseconds to wait for a response from the server
*/
public static int getDefaultPacketReplyTimeout() {
initialize();
// The timeout value must be greater than 0 otherwise we will answer the default value
if (defaultPacketReplyTimeout <= 0) {
defaultPacketReplyTimeout = 5000;
@ -166,8 +153,6 @@ public final class SmackConfiguration {
* @param timeout the milliseconds to wait for a response from the server
*/
public static void setDefaultPacketReplyTimeout(int timeout) {
initialize();
if (timeout <= 0) {
throw new IllegalArgumentException();
}
@ -181,8 +166,7 @@ public final class SmackConfiguration {
* @return The number of packets to queue before deleting older packets.
*/
public static int getPacketCollectorSize() {
initialize();
return packetCollectorSize;
return packetCollectorSize;
}
/**
@ -192,8 +176,7 @@ public final class SmackConfiguration {
* @param The number of packets to queue before deleting older packets.
*/
public static void setPacketCollectorSize(int collectorSize) {
initialize();
packetCollectorSize = collectorSize;
packetCollectorSize = collectorSize;
}
/**
@ -202,8 +185,6 @@ public final class SmackConfiguration {
* @param mech the SASL mechanism to be added
*/
public static void addSaslMech(String mech) {
initialize();
if(! defaultMechs.contains(mech) ) {
defaultMechs.add(mech);
}
@ -215,8 +196,6 @@ public final class SmackConfiguration {
* @param mechs the Collection of SASL mechanisms to be added
*/
public static void addSaslMechs(Collection<String> mechs) {
initialize();
for(String mech : mechs) {
addSaslMech(mech);
}
@ -228,7 +207,6 @@ public final class SmackConfiguration {
* @param mech the SASL mechanism to be removed
*/
public static void removeSaslMech(String mech) {
initialize();
defaultMechs.remove(mech);
}
@ -238,7 +216,6 @@ public final class SmackConfiguration {
* @param mechs the Collection of SASL mechanisms to be removed
*/
public static void removeSaslMechs(Collection<String> mechs) {
initialize();
defaultMechs.removeAll(mechs);
}
@ -253,66 +230,6 @@ public final class SmackConfiguration {
return Collections.unmodifiableList(defaultMechs);
}
/**
* Returns true if the local Socks5 proxy should be started. Default is true.
*
* @return if the local Socks5 proxy should be started
*/
public static boolean isLocalSocks5ProxyEnabled() {
initialize();
return localSocks5ProxyEnabled;
}
/**
* Sets if the local Socks5 proxy should be started. Default is true.
*
* @param localSocks5ProxyEnabled if the local Socks5 proxy should be started
*/
public static void setLocalSocks5ProxyEnabled(boolean localSocks5ProxyEnabled) {
initialize();
SmackConfiguration.localSocks5ProxyEnabled = localSocks5ProxyEnabled;
}
/**
* Return the port of the local Socks5 proxy. Default is 7777.
*
* @return the port of the local Socks5 proxy
*/
public static int getLocalSocks5ProxyPort() {
initialize();
return localSocks5ProxyPort;
}
/**
* Sets the port of the local Socks5 proxy. Default is 7777. If you set the port to a negative
* value Smack tries the absolute value and all following until it finds an open port.
*
* @param localSocks5ProxyPort the port of the local Socks5 proxy to set
*/
public static void setLocalSocks5ProxyPort(int localSocks5ProxyPort) {
initialize();
SmackConfiguration.localSocks5ProxyPort = localSocks5ProxyPort;
}
/**
* Check if Entity Caps are enabled as default for every new connection
* @return
*/
public static boolean autoEnableEntityCaps() {
initialize();
return autoEnableEntityCaps;
}
/**
* Set if Entity Caps are enabled or disabled for every new connection
*
* @param true if Entity Caps should be auto enabled, false if not
*/
public static void setAutoEnableEntityCaps(boolean b) {
initialize();
autoEnableEntityCaps = b;
}
/**
* Set the default parsing exception callback for all newly created connections
*
@ -320,7 +237,6 @@ public final class SmackConfiguration {
* @see ParsingExceptionCallback
*/
public static void setDefaultParsingExceptionCallback(ParsingExceptionCallback callback) {
initialize();
defaultCallback = callback;
}
@ -331,11 +247,35 @@ public final class SmackConfiguration {
* @see ParsingExceptionCallback
*/
public static ParsingExceptionCallback getDefaultParsingExceptionCallback() {
initialize();
return defaultCallback;
}
public static void parseClassesToLoad(XmlPullParser parser, boolean optional) throws XmlPullParserException, IOException, Exception {
public static void processConfigFile(InputStream cfgFileStream, Collection<Exception> exceptions) 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);
}
else if (parser.getName().equals("optionalStartupClasses")) {
parseClassesToLoad(parser, true, exceptions);
}
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
try {
cfgFileStream.close();
}
catch (IOException e) {
log.log(Level.SEVERE, "Error while closing config file input stream", e);
}
}
private static void parseClassesToLoad(XmlPullParser parser, boolean optional, Collection<Exception> exceptions) throws XmlPullParserException, IOException, Exception {
final String startName = parser.getName();
int eventType;
String name;
@ -343,13 +283,22 @@ public final class SmackConfiguration {
eventType = parser.next();
name = parser.getName();
if (eventType == XmlPullParser.START_TAG && "className".equals(name)) {
String classToLoad = parser.nextText();
loadSmackClass(classToLoad, optional);
if (disabledSmackClasses.contains(name)) {
log.info("Not loading disabled Smack class " + name);
}
else {
String classToLoad = parser.nextText();
try {
loadSmackClass(classToLoad, optional);
} catch (Exception e) {
exceptions.add(e);
}
}
}
} while (! (eventType == XmlPullParser.END_TAG && startName.equals(name)));
}
public static void loadSmackClass(String className, boolean optional) throws Exception {
private static void loadSmackClass(String className, boolean optional) throws Exception {
// Attempt to load the class so that the class can get initialized
try {
Class<?> initClass = Class.forName(className);
@ -373,101 +322,4 @@ public final class SmackConfiguration {
throw cnfe;
}
}
private static int parseIntProperty(XmlPullParser parser, int defaultValue)
throws Exception
{
try {
return Integer.parseInt(parser.nextText());
}
catch (NumberFormatException nfe) {
log.log(Level.SEVERE, "Could not parse integer", nfe);
return defaultValue;
}
}
/*
* Order of precedence for config file is VM arg, setConfigXXX methods and embedded default file location.
*/
private static void initialize() {
if (initialized) {
return;
}
initialized = true;
String configFileLocation = System.getProperty("smack.config.file");
if (configFileLocation != null) {
try {
configFileStream = FileUtils.getStreamForUrl(configFileLocation, null);
}
catch (Exception e) {
log.log(Level.SEVERE, "Error creating input stream for config file [" + configFileLocation + "] from VM argument", e);
}
}
if (configFileStream == null) {
try {
configFileStream = FileUtils.getStreamForUrl(DEFAULT_CONFIG_FILE, null);
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
if (configFileStream != null) {
try {
readFile(configFileStream);
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
else {
log.log(Level.INFO, "No configuration file found");
}
}
private static void readFile(InputStream cfgFileStream) 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);
}
else if (parser.getName().equals("optionalStartupClasses")) {
parseClassesToLoad(parser, true);
}
else if (parser.getName().equals("defaultPacketReplyTimeout")) {
defaultPacketReplyTimeout = parseIntProperty(parser, defaultPacketReplyTimeout);
}
else if (parser.getName().equals("mechName")) {
defaultMechs.add(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyEnabled")) {
localSocks5ProxyEnabled = Boolean.parseBoolean(parser.nextText());
}
else if (parser.getName().equals("localSocks5ProxyPort")) {
localSocks5ProxyPort = parseIntProperty(parser, localSocks5ProxyPort);
}
else if (parser.getName().equals("packetCollectorSize")) {
packetCollectorSize = parseIntProperty(parser, packetCollectorSize);
}
else if (parser.getName().equals("autoEnableEntityCaps")) {
autoEnableEntityCaps = Boolean.parseBoolean(parser.nextText());
}
}
eventType = parser.next();
}
while (eventType != XmlPullParser.END_DOCUMENT);
try {
cfgFileStream.close();
}
catch (IOException e) {
log.log(Level.SEVERE, "Error while closing config file input stream", e);
}
}
}

View file

@ -16,31 +16,31 @@
*/
package org.jivesoftware.smack.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public final class FileUtils {
private FileUtils() {
}
public static InputStream getStreamForUrl(String url, ClassLoader loader) throws MalformedURLException, IOException {
URI fileUri = URI.create(url);
if (fileUri.getScheme() == null) {
throw new MalformedURLException("No protocol found in file URL: " + url);
}
if (fileUri.getScheme().equals("classpath")) {
// Get an array of class loaders to try loading the providers files from.
ClassLoader[] classLoaders = getClassLoaders();
for (ClassLoader classLoader : classLoaders) {
InputStream is = classLoader.getResourceAsStream(fileUri.getSchemeSpecificPart());
if (is != null) {
return is;
}
@ -51,7 +51,7 @@ public final class FileUtils {
}
return null;
}
/**
* Returns default classloaders.
*
@ -72,4 +72,14 @@ public final class FileUtils {
return loaders.toArray(new ClassLoader[loaders.size()]);
}
public static boolean addLines(String url, Set<String> set) throws MalformedURLException, IOException {
InputStream is = getStreamForUrl(url, null);
if (is == null) return false;
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
set.add(line);
}
return true;
}
}

View file

@ -1,22 +1,6 @@
<?xml version="1.0"?>
<!-- Smack configuration file. -->
<smack>
<!-- Default Packet reply timeout in milliseconds -->
<defaultPacketReplyTimeout>5000</defaultPacketReplyTimeout>
<!-- Enable/Disable local Socks5 proxy -->
<localSocks5ProxyEnabled>true</localSocks5ProxyEnabled>
<!-- Port of the local Socks5 proxy -->
<localSocks5ProxyPort>7777</localSocks5ProxyPort>
<!-- Port of the local Socks5 proxy -->
<packetCollectorSize>10000</packetCollectorSize>
<!-- Automatic enable Entity Caps (XEP-0115) for new connections -->
<autoEnableEntityCaps>false</autoEnableEntityCaps>
<!-- Classes that will be loaded when Smack starts -->
<startupClasses>
<className>org.jivesoftware.smack.initializer.VmArgInitializer</className>