All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.igniterealtime.jbosh.ServiceLib Maven / Gradle / Ivy

Go to download

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);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy