org.igniterealtime.jbosh.ServiceLib Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of smack-ece Show documentation
Show all versions of smack-ece Show documentation
Library to connect to Cisco Enterprise Chat and Email (ECE) chat interface which is a modified version of XMPP over BOSH standard.
The newest version!
/*
* Copyright 2009 Mike Cumings
*
* 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.igniterealtime.jbosh;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Utility library for use in loading services using the Jar Service Provider Interface (Jar SPI). This can be replaced once the
* minimum java rev moves beyond Java 5.
*/
final class ServiceLib {
/**
* Logger.
*/
private static final Logger LOG =
Logger.getLogger(ServiceLib.class.getName());
///////////////////////////////////////////////////////////////////////////
// Package-private methods:
/**
* Prevent construction.
*/
private ServiceLib() {
// Empty
}
///////////////////////////////////////////////////////////////////////////
// Package-private methods:
/**
* Probe for and select an implementation of the specified service type by using the a modified Jar SPI mechanism. Modified in
* that the system properties will be checked to see if there is a value set for the naem of the class to be loaded. If so,
* that value is treated as the class name of the first implementation class to be attempted to be loaded. This provides a
* (unsupported) mechanism to insert other implementations. Note that the supported mechanism is by properly ordering the
* classpath.
*
* @return service instance
* @throws IllegalStateException is no service implementations could be instantiated
*/
static T loadService(Class ofType) {
List implClasses = loadServicesImplementations(ofType);
for (String implClass : implClasses) {
T result = attemptLoad(ofType, implClass);
if (result != null) {
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Selected " + ofType.getSimpleName()
+ " implementation: "
+ result.getClass().getName());
}
return result;
}
}
throw (new IllegalStateException(
"Could not load " + ofType.getName() + " implementation"));
}
///////////////////////////////////////////////////////////////////////////
// Private methods:
/**
* Generates a list of implementation class names by using the Jar SPI technique. The order in which the class names occur in
* the service manifest is significant.
*
* @return list of all declared implementation class names
*/
private static List loadServicesImplementations(
final Class> ofClass) {
List result = new ArrayList();
// Allow a sysprop to specify the first candidate
String override = System.getProperty(ofClass.getName());
if (override != null) {
result.add(override);
}
ClassLoader loader = ServiceLib.class.getClassLoader();
URL url = loader.getResource("org.igniterealtime.jbosh/" + ofClass.getName());
if (url == null) {
// Early-out
return result;
}
InputStream inStream = null;
InputStreamReader reader = null;
BufferedReader bReader = null;
try {
inStream = url.openStream();
reader = new InputStreamReader(inStream);
bReader = new BufferedReader(reader);
String line;
while ((line = bReader.readLine()) != null) {
if (!line.matches("\\s*(#.*)?")) {
// not a comment or blank line
result.add(line.trim());
}
}
} catch (IOException iox) {
LOG.log(Level.WARNING,
"Could not load services descriptor: " + url.toString(),
iox);
} finally {
finalClose(bReader);
finalClose(reader);
finalClose(inStream);
}
return result;
}
/**
* Attempts to load the specified implementation class. Attempts will fail if - for example - the implementation depends on a
* class not found on the classpath.
*
* @param className implementation class to attempt to load
* @return service instance, or {@code null} if the instance could not be loaded
*/
private static T attemptLoad(
final Class ofClass,
final String className) {
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Attempting service load: " + className);
}
Level level;
Throwable thrown;
try {
Class> clazz = Class.forName(className);
if (!ofClass.isAssignableFrom(clazz)) {
if (LOG.isLoggable(Level.WARNING)) {
LOG.warning(clazz.getName() + " is not assignable to "
+ ofClass.getName());
}
return null;
}
return ofClass.cast(clazz.newInstance());
} catch (LinkageError ex) {
level = Level.FINEST;
thrown = ex;
} catch (ClassNotFoundException ex) {
level = Level.FINEST;
thrown = ex;
} catch (InstantiationException ex) {
level = Level.WARNING;
thrown = ex;
} catch (IllegalAccessException ex) {
level = Level.WARNING;
thrown = ex;
}
LOG.log(level,
"Could not load " + ofClass.getSimpleName()
+ " instance: " + className,
thrown);
return null;
}
/**
* Check and close a closeable object, trapping and ignoring any exception that might result.
*
* @param closeMe the thing to close
*/
private static void finalClose(final Closeable closeMe) {
if (closeMe != null) {
try {
closeMe.close();
} catch (IOException iox) {
LOG.log(Level.FINEST, "Could not close: " + closeMe, iox);
}
}
}
}