Package org.restlet.engine

Source Code of org.restlet.engine.Engine

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.engine;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.engine.io.IoUtils;
import org.restlet.engine.log.LoggerFacade;

/**
* Engine supporting the Restlet API. The engine acts as a registry of various
* {@link Helper} types: {@link org.restlet.engine.security.AuthenticatorHelper}
* , {@link ClientHelper}, {@link org.restlet.engine.converter.ConverterHelper}
* and {@link ServerHelper} classes.<br>
* <br>
* Note that by default the JULI logging mechanism is used but it is possible to
* replace it by providing an alternate {@link LoggerFacade} implementation. For
* this, just pass a system property named
* "org.restlet.engine.loggerFacadeClass" with the qualified class name as a
* value.
*
* @author Jerome Louvel
*/
public class Engine {

    public static final String DESCRIPTOR = "META-INF/services";

    public static final String DESCRIPTOR_AUTHENTICATOR = "org.restlet.engine.security.AuthenticatorHelper";

    public static final String DESCRIPTOR_AUTHENTICATOR_PATH = DESCRIPTOR + "/"
            + DESCRIPTOR_AUTHENTICATOR;

    public static final String DESCRIPTOR_CLIENT = "org.restlet.engine.ClientHelper";

    public static final String DESCRIPTOR_CLIENT_PATH = DESCRIPTOR + "/"
            + DESCRIPTOR_CLIENT;

    public static final String DESCRIPTOR_CONVERTER = "org.restlet.engine.converter.ConverterHelper";

    public static final String DESCRIPTOR_CONVERTER_PATH = DESCRIPTOR + "/"
            + DESCRIPTOR_CONVERTER;

    public static final String DESCRIPTOR_PROTOCOL = "org.restlet.engine.ProtocolHelper";

    public static final String DESCRIPTOR_PROTOCOL_PATH = DESCRIPTOR + "/"
            + DESCRIPTOR_PROTOCOL;

    public static final String DESCRIPTOR_SERVER = "org.restlet.engine.ServerHelper";

    public static final String DESCRIPTOR_SERVER_PATH = DESCRIPTOR + "/"
            + DESCRIPTOR_SERVER;

    /** The registered engine. */
    private static volatile Engine instance = null;

    /** The org.restlet log level . */
    private static volatile boolean logConfigured = false;

    /** The general log formatter. */
    private static volatile Class<? extends Formatter> logFormatter = org.restlet.engine.log.SimplestFormatter.class;

    /** The general log level . */
    private static volatile Level logLevel = Level.INFO;

    /** Major version number. */
    public static final String MAJOR_NUMBER = "2";

    /** Minor version number. */
    public static final String MINOR_NUMBER = "1";

    /** Release number. */
    public static final String RELEASE_NUMBER = "m5";

    /** The org.restlet log level . */
    private static volatile Level restletLogLevel;

    /** Complete version. */
    public static final String VERSION = MAJOR_NUMBER + '.' + MINOR_NUMBER
            + RELEASE_NUMBER;

    /** Complete version header. */
    public static final String VERSION_HEADER = "Restlet-Framework/" + VERSION;

    /**
     * Clears the current Restlet Engine altogether.
     */
    public static synchronized void clear() {
        setInstance(null);
    }

    /**
     * Clears the thread local variables set by the Restlet API and engine.
     */
    public static void clearThreadLocalVariables() {
        Response.setCurrent(null);
        Context.setCurrent(null);
        org.restlet.routing.VirtualHost.setCurrent(null);
        org.restlet.Application.setCurrent(null);
    }

    /**
     * Updates the global log configuration of the JVM programmatically.
     */
    public static void configureLog() {
        if ((System.getProperty("java.util.logging.config.file") == null)
                && (System.getProperty("java.util.logging.config.class") == null)) {
            StringBuilder sb = new StringBuilder();
            sb.append("handlers=");
            sb.append(java.util.logging.ConsoleHandler.class.getCanonicalName())
                    .append('\n');

            if (getLogLevel() != null) {
                sb.append(".level=" + getLogLevel().getName()).append('\n');
            }

            if (getRestletLogLevel() != null) {
                sb.append("org.restlet.level=" + getRestletLogLevel().getName())
                        .append('\n');
            }

            if (getLogFormatter() != null) {
                String handler = java.util.logging.ConsoleHandler.class
                        .getCanonicalName();
                sb.append(handler + ".formatter="
                        + getLogFormatter().getCanonicalName() + "\n");

                if (getLogLevel() != null) {
                    sb.append(handler + ".level=" + getLogLevel().getName()
                            + "\n");
                }
            }

            try {
                LogManager.getLogManager().readConfiguration(
                        new ByteArrayInputStream(sb.toString().getBytes()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        logConfigured = true;
    }

    /**
     * Returns an anonymous logger. By default it calls
     * {@link #getLogger(String)} with a "" name.
     *
     * @return The logger.
     */
    public static Logger getAnonymousLogger() {
        return getInstance().getLoggerFacade().getAnonymousLogger();
    }

    /**
     * Returns the registered Restlet engine.
     *
     * @return The registered Restlet engine.
     */
    public static synchronized Engine getInstance() {
        Engine result = instance;

        if (result == null) {
            result = register();
        }

        return result;
    }

    /**
     * Returns the general log formatter.
     *
     * @return The general log formatter.
     */
    public static Class<? extends Formatter> getLogFormatter() {
        return Engine.logFormatter;
    }

    /**
     * Returns a logger based on the class name of the given object.
     *
     * @param clazz
     *            The parent class.
     * @return The logger.
     */
    public static Logger getLogger(Class<?> clazz) {
        return getInstance().getLoggerFacade().getLogger(clazz);
    }

    /**
     * Returns a logger based on the class name of the given object.
     *
     * @param clazz
     *            The parent class.
     * @param defaultLoggerName
     *            The default logger name to use if no one can be inferred from
     *            the class.
     * @return The logger.
     */
    public static Logger getLogger(Class<?> clazz, String defaultLoggerName) {
        return getInstance().getLoggerFacade().getLogger(clazz,
                defaultLoggerName);
    }

    /**
     * Returns a logger based on the class name of the given object.
     *
     * @param object
     *            The parent object.
     * @param defaultLoggerName
     *            The default logger name to use if no one can be inferred from
     *            the object class.
     * @return The logger.
     */
    public static Logger getLogger(Object object, String defaultLoggerName) {
        return getInstance().getLoggerFacade().getLogger(object,
                defaultLoggerName);
    }

    /**
     * Returns a logger based on the given logger name.
     *
     * @param loggerName
     *            The logger name.
     * @return The logger.
     */
    public static Logger getLogger(String loggerName) {
        return getInstance().getLoggerFacade().getLogger(loggerName);
    }

    /**
     * Returns the general log level.
     *
     * @return The general log level.
     */
    public static Level getLogLevel() {
        return Engine.logLevel;
    }

    /**
     * Returns the classloader resource for a given name/path.
     *
     * @param name
     *            The name/path to lookup.
     * @return The resource URL.
     */
    public static java.net.URL getResource(String name) {
        return getInstance().getClassLoader().getResource(name);
    }

    /**
     * Returns the Restlet log level. For loggers with a name starting with
     * "org.restlet".
     *
     * @return The Restlet log level.
     */
    public static Level getRestletLogLevel() {
        return Engine.restletLogLevel;
    }

    /**
     * Returns the class object for the given name using the engine classloader.
     *
     * @param className
     *            The class name to lookup.
     * @return The class object or null if the class was not found.
     * @see #getClassLoader()
     */
    public static Class<?> loadClass(String className)
            throws ClassNotFoundException {
        return getInstance().getClassLoader().loadClass(className);
    }

    /**
     * Registers a new Restlet Engine.
     *
     * @return The registered engine.
     */
    public static synchronized Engine register() {
        return register(true);
    }

    /**
     * Registers a new Restlet Engine.
     *
     * @param discoverPlugins
     *            True if plug-ins should be automatically discovered.
     * @return The registered engine.
     */
    public static synchronized Engine register(boolean discoverPlugins) {
        if (!logConfigured) {
            configureLog();
        }
        Engine result = new Engine(discoverPlugins);
        org.restlet.engine.Engine.setInstance(result);
        return result;
    }

    /**
     * Sets the registered Restlet engine.
     *
     * @param engine
     *            The registered Restlet engine.
     * @deprecated Use the {@link #register()} and {@link #register(boolean)}
     *             methods instead.
     */
    @Deprecated
    public static synchronized void setInstance(Engine engine) {
        instance = engine;
    }

    /**
     * Sets the general log formatter.
     *
     * @param logFormatter
     *            The general log formatter.
     */
    public static void setLogFormatter(Class<? extends Formatter> logFormatter) {
        Engine.logFormatter = logFormatter;
        configureLog();
    }

    /**
     * Sets the general log level. Modifies the global JVM's {@link LogManager}.
     *
     * @param logLevel
     *            The general log level.
     */
    public static void setLogLevel(Level logLevel) {
        Engine.logLevel = logLevel;
        configureLog();
    }

    /**
     * Sets the Restlet log level. For loggers with a name starting with
     * "org.restlet".
     *
     * @param restletLogLevel
     *            The Restlet log level.
     */
    public static void setRestletLogLevel(Level restletLogLevel) {
        Engine.restletLogLevel = restletLogLevel;
        configureLog();
    }

    /** Class loader to use for dynamic class loading. */
    private volatile ClassLoader classLoader;

    /** The logger facade to use. */
    private LoggerFacade loggerFacade;

    /** List of available authenticator helpers. */
    private final List<org.restlet.engine.security.AuthenticatorHelper> registeredAuthenticators;

    /** List of available client connectors. */
    private final List<ConnectorHelper<Client>> registeredClients;

    /** List of available converter helpers. */
    private final List<org.restlet.engine.converter.ConverterHelper> registeredConverters;

    /** List of available protocol helpers. */
    private final List<org.restlet.engine.ProtocolHelper> registeredProtocols;

    /** List of available server connectors. */
    private final List<ConnectorHelper<org.restlet.Server>> registeredServers;

    /** User class loader to use for dynamic class loading. */
    private volatile ClassLoader userClassLoader;

    /**
     * Constructor that will automatically attempt to discover connectors.
     */
    public Engine() {
        this(true);
    }

    /**
     * Constructor.
     *
     * @param discoverHelpers
     *            True if helpers should be automatically discovered.
     */
    public Engine(boolean discoverHelpers) {
        // Prevent engine initialization code from recreating other engines
        setInstance(this);

        // Instantiate the logger facade
        if (Edition.CURRENT == Edition.GWT) {
            this.loggerFacade = new LoggerFacade();
        } else {
            this.classLoader = createClassLoader();
            this.userClassLoader = null;

            String loggerFacadeClass = System.getProperty(
                    "org.restlet.engine.loggerFacadeClass",
                    "org.restlet.engine.log.LoggerFacade");
            try {
                this.loggerFacade = (LoggerFacade) getClassLoader().loadClass(
                        loggerFacadeClass).newInstance();
            } catch (Exception e) {
                this.loggerFacade = new LoggerFacade();
                this.loggerFacade.getLogger("org.restlet").log(Level.WARNING,
                        "Unable to register the logger facade", e);
            }
        }

        this.registeredClients = new CopyOnWriteArrayList<ConnectorHelper<Client>>();
        this.registeredProtocols = new CopyOnWriteArrayList<ProtocolHelper>();

        this.registeredServers = new CopyOnWriteArrayList<ConnectorHelper<org.restlet.Server>>();
        this.registeredAuthenticators = new CopyOnWriteArrayList<org.restlet.engine.security.AuthenticatorHelper>();
        this.registeredConverters = new CopyOnWriteArrayList<org.restlet.engine.converter.ConverterHelper>();

        if (discoverHelpers) {
            try {
                discoverConnectors();
                discoverProtocols();

                discoverAuthenticators();
                discoverConverters();
            } catch (IOException e) {
                Context.getCurrentLogger()
                        .log(Level.WARNING,
                                "An error occured while discovering the engine helpers.",
                                e);
            }
        }
    }

    /**
     * Creates a new class loader. By default, it returns an instance of
     * {@link org.restlet.engine.util.EngineClassLoader}.
     *
     * @return A new class loader.
     */
    protected ClassLoader createClassLoader() {
        return new org.restlet.engine.util.EngineClassLoader(this);
    }

    /**
     * Creates a new helper for a given client connector.
     *
     * @param client
     *            The client to help.
     * @param helperClass
     *            Optional helper class name.
     * @return The new helper.
     */
    @SuppressWarnings("unchecked")
    public ConnectorHelper<Client> createHelper(Client client,
            String helperClass) {
        ConnectorHelper<Client> result = null;

        if (client.getProtocols().size() > 0) {
            ConnectorHelper<Client> connector = null;
            for (final Iterator<ConnectorHelper<Client>> iter = getRegisteredClients()
                    .iterator(); (result == null) && iter.hasNext();) {
                connector = iter.next();

                if (connector.getProtocols().containsAll(client.getProtocols())) {
                    if ((helperClass == null)
                            || connector.getClass().getCanonicalName()
                                    .equals(helperClass)) {
                        try {
                            result = connector.getClass()
                                    .getConstructor(Client.class)
                                    .newInstance(client);
                        } catch (Exception e) {
                            Context.getCurrentLogger()
                                    .log(Level.SEVERE,
                                            "Exception during the instantiation of the client connector.",
                                            e);
                        }
                    }
                }
            }

            if (result == null) {
                // Couldn't find a matching connector
                StringBuilder sb = new StringBuilder();
                sb.append("No available client connector supports the required protocols: ");

                for (Protocol p : client.getProtocols()) {
                    sb.append("'").append(p.getName()).append("' ");
                }

                sb.append(". Please add the JAR of a matching connector to your classpath.");

                if (Edition.CURRENT == Edition.ANDROID) {
                    sb.append(" Then, register this connector helper manually.");
                }

                Context.getCurrentLogger().log(Level.WARNING, sb.toString());
            }
        }

        return result;
    }

    /**
     * Creates a new helper for a given server connector.
     *
     * @param server
     *            The server to help.
     * @param helperClass
     *            Optional helper class name.
     * @return The new helper.
     */
    @SuppressWarnings("unchecked")
    public ConnectorHelper<org.restlet.Server> createHelper(
            org.restlet.Server server, String helperClass) {
        ConnectorHelper<org.restlet.Server> result = null;

        if (server.getProtocols().size() > 0) {
            ConnectorHelper<org.restlet.Server> connector = null;
            for (final Iterator<ConnectorHelper<org.restlet.Server>> iter = getRegisteredServers()
                    .iterator(); (result == null) && iter.hasNext();) {
                connector = iter.next();

                if ((helperClass == null)
                        || connector.getClass().getCanonicalName()
                                .equals(helperClass)) {
                    if (connector.getProtocols().containsAll(
                            server.getProtocols())) {
                        try {
                            result = connector.getClass()
                                    .getConstructor(org.restlet.Server.class)
                                    .newInstance(server);
                        } catch (Exception e) {
                            Context.getCurrentLogger()
                                    .log(Level.SEVERE,
                                            "Exception while instantiation the server connector.",
                                            e);
                        }
                    }
                }
            }

            if (result == null) {
                // Couldn't find a matching connector
                final StringBuilder sb = new StringBuilder();
                sb.append("No available server connector supports the required protocols: ");

                for (final Protocol p : server.getProtocols()) {
                    sb.append("'").append(p.getName()).append("' ");
                }

                sb.append(". Please add the JAR of a matching connector to your classpath.");

                if (Edition.CURRENT == Edition.ANDROID) {
                    sb.append(" Then, register this connector helper manually.");
                }

                Context.getCurrentLogger().log(Level.WARNING, sb.toString());
            }
        }

        return result;
    }

    /**
     * Discovers the authenticator helpers and register the default helpers.
     *
     * @throws IOException
     */
    private void discoverAuthenticators() throws IOException {
        registerHelpers(DESCRIPTOR_AUTHENTICATOR_PATH,
                getRegisteredAuthenticators(), null);
        registerDefaultAuthentications();
    }

    /**
     * Discovers the server and client connectors and register the default
     * connectors.
     *
     * @throws IOException
     */
    private void discoverConnectors() throws IOException {
        registerHelpers(DESCRIPTOR_CLIENT_PATH, getRegisteredClients(),
                Client.class);
        registerHelpers(DESCRIPTOR_SERVER_PATH, getRegisteredServers(),
                org.restlet.Server.class);
        registerDefaultConnectors();
    }

    /**
     * Discovers the converter helpers and register the default helpers.
     *
     * @throws IOException
     */
    private void discoverConverters() throws IOException {
        registerHelpers(DESCRIPTOR_CONVERTER_PATH, getRegisteredConverters(),
                null);
        registerDefaultConverters();
    }

    /**
     * Discovers the protocol helpers and register the default helpers.
     *
     * @throws IOException
     */
    private void discoverProtocols() throws IOException {
        registerHelpers(DESCRIPTOR_PROTOCOL_PATH, getRegisteredProtocols(),
                null);
        registerDefaultProtocols();
    }

    /**
     * Finds the converter helper supporting the given conversion.
     *
     * @return The converter helper or null.
     */
    public org.restlet.engine.converter.ConverterHelper findHelper() {

        return null;
    }

    /**
     * Finds the authenticator helper supporting the given scheme.
     *
     * @param challengeScheme
     *            The challenge scheme to match.
     * @param clientSide
     *            Indicates if client side support is required.
     * @param serverSide
     *            Indicates if server side support is required.
     * @return The authenticator helper or null.
     */
    public org.restlet.engine.security.AuthenticatorHelper findHelper(
            ChallengeScheme challengeScheme, boolean clientSide,
            boolean serverSide) {
        org.restlet.engine.security.AuthenticatorHelper result = null;
        final List<org.restlet.engine.security.AuthenticatorHelper> helpers = getRegisteredAuthenticators();
        org.restlet.engine.security.AuthenticatorHelper current;

        for (int i = 0; (result == null) && (i < helpers.size()); i++) {
            current = helpers.get(i);

            if (current.getChallengeScheme().equals(challengeScheme)
                    && ((clientSide && current.isClientSide()) || !clientSide)
                    && ((serverSide && current.isServerSide()) || !serverSide)) {
                result = helpers.get(i);
            }
        }

        return result;
    }

    /**
     * Returns the class loader. It uses the delegation model with the Engine
     * class's class loader as a parent. If this parent doesn't find a class or
     * resource, it then tries the user class loader (via
     * {@link #getUserClassLoader()} and finally the
     * {@link Thread#getContextClassLoader()}.
     *
     * @return The engine class loader.
     * @see org.restlet.engine.util.EngineClassLoader
     */
    public ClassLoader getClassLoader() {
        return classLoader;
    }

    /**
     * Returns the logger facade to use.
     *
     * @return The logger facade to use.
     */
    public LoggerFacade getLoggerFacade() {
        return loggerFacade;
    }

    /**
     * Parses a line to extract the provider class name.
     *
     * @param line
     *            The line to parse.
     * @return The provider's class name or an empty string.
     */
    private String getProviderClassName(String line) {
        final int index = line.indexOf('#');
        if (index != -1) {
            line = line.substring(0, index);
        }
        return line.trim();
    }

    /**
     * Returns the list of available authentication helpers.
     *
     * @return The list of available authentication helpers.
     */
    public List<org.restlet.engine.security.AuthenticatorHelper> getRegisteredAuthenticators() {
        return this.registeredAuthenticators;
    }

    /**
     * Returns the list of available client connectors.
     *
     * @return The list of available client connectors.
     */
    public List<ConnectorHelper<Client>> getRegisteredClients() {
        return this.registeredClients;
    }

    /**
     * Returns the list of available converters.
     *
     * @return The list of available converters.
     */
    public List<org.restlet.engine.converter.ConverterHelper> getRegisteredConverters() {
        return registeredConverters;
    }

    /**
     * Returns the list of available protocol connectors.
     *
     * @return The list of available protocol connectors.
     */
    public List<ProtocolHelper> getRegisteredProtocols() {
        return this.registeredProtocols;
    }

    /**
     * Returns the list of available server connectors.
     *
     * @return The list of available server connectors.
     */
    public List<ConnectorHelper<org.restlet.Server>> getRegisteredServers() {
        return this.registeredServers;
    }

    /**
     * Returns the class loader specified by the user and that should be used in
     * priority.
     *
     * @return The user class loader
     */
    public ClassLoader getUserClassLoader() {
        return userClassLoader;
    }

    /**
     * Registers the default authentication helpers.
     */
    public void registerDefaultAuthentications() {
        getRegisteredAuthenticators().add(
                new org.restlet.engine.security.HttpBasicHelper());
        getRegisteredAuthenticators().add(
                new org.restlet.engine.security.SmtpPlainHelper());
    }

    /**
     * Registers the default client and server connectors.
     */
    public void registerDefaultConnectors() {
        getRegisteredClients().add(
                new org.restlet.engine.connector.HttpClientHelper(null));
        getRegisteredClients().add(
                new org.restlet.engine.local.ClapClientHelper(null));
        getRegisteredClients().add(
                new org.restlet.engine.local.RiapClientHelper(null));
        getRegisteredServers().add(
                new org.restlet.engine.local.RiapServerHelper(null));
        getRegisteredServers().add(
                new org.restlet.engine.connector.HttpServerHelper(null));
        getRegisteredClients().add(
                new org.restlet.engine.local.FileClientHelper(null));
        getRegisteredClients().add(
                new org.restlet.engine.local.ZipClientHelper(null));
    }

    /**
     * Registers the default converters.
     */
    public void registerDefaultConverters() {
        getRegisteredConverters().add(
                new org.restlet.engine.converter.DefaultConverter());
    }

    /**
     * Registers the default protocols.
     */
    public void registerDefaultProtocols() {
        getRegisteredProtocols().add(new HttpProtocolHelper());
        getRegisteredProtocols().add(new WebDavProtocolHelper());
    }

    /**
     * Registers a helper.
     *
     * @param classLoader
     *            The classloader to use.
     * @param provider
     *            Bynary name of the helper's class.
     * @param helpers
     *            The list of helpers to update.
     * @param constructorClass
     *            The constructor parameter class to look for.
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void registerHelper(ClassLoader classLoader, String provider,
            List helpers, Class constructorClass) {
        if ((provider != null) && (!provider.equals(""))) {
            // Instantiate the factory
            try {
                Class providerClass = classLoader.loadClass(provider);

                if (constructorClass == null) {
                    helpers.add(providerClass.newInstance());
                } else {
                    helpers.add(providerClass.getConstructor(constructorClass)
                            .newInstance(constructorClass.cast(null)));
                }
            } catch (Throwable t) {
                Context.getCurrentLogger().log(Level.INFO,
                        "Unable to register the helper " + provider, t);
            }
        }
    }

    /**
     * Registers a helper.
     *
     * @param classLoader
     *            The classloader to use.
     * @param configUrl
     *            Configuration URL to parse
     * @param helpers
     *            The list of helpers to update.
     * @param constructorClass
     *            The constructor parameter class to look for.
     */
    public void registerHelpers(ClassLoader classLoader,
            java.net.URL configUrl, List<?> helpers, Class<?> constructorClass) {
        try {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(
                        configUrl.openStream(), "utf-8"), IoUtils.BUFFER_SIZE);
                String line = reader.readLine();

                while (line != null) {
                    registerHelper(classLoader, getProviderClassName(line),
                            helpers, constructorClass);
                    line = reader.readLine();
                }
            } catch (IOException e) {
                Context.getCurrentLogger().log(
                        Level.SEVERE,
                        "Unable to read the provider descriptor: "
                                + configUrl.toString());
            } finally {
                if (reader != null) {
                    reader.close();
                }
            }
        } catch (IOException ioe) {
            Context.getCurrentLogger().log(Level.SEVERE,
                    "Exception while detecting the helpers.", ioe);
        }
    }

    /**
     * Registers a list of helpers.
     *
     * @param descriptorPath
     *            Classpath to the descriptor file.
     * @param helpers
     *            The list of helpers to update.
     * @param constructorClass
     *            The constructor parameter class to look for.
     * @throws IOException
     */
    public void registerHelpers(String descriptorPath, List<?> helpers,
            Class<?> constructorClass) throws IOException {
        final ClassLoader classLoader = getClassLoader();
        Enumeration<java.net.URL> configUrls = classLoader
                .getResources(descriptorPath);

        if (configUrls != null) {
            for (final Enumeration<java.net.URL> configEnum = configUrls; configEnum
                    .hasMoreElements();) {
                registerHelpers(classLoader, configEnum.nextElement(), helpers,
                        constructorClass);
            }
        }
    }

    /**
     * Registers a factory that is used by the URL class to create the
     * {@link java.net.URLConnection} instances when the
     * {@link java.net.URL#openConnection()} or
     * {@link java.net.URL#openStream()} methods are invoked.
     * <p>
     * The implementation is based on the client dispatcher of the current
     * context, as provided by {@link Context#getCurrent()} method.
     */
    public void registerUrlFactory() {
        // Set up an java.net.URLStreamHandlerFactory for
        // proper creation of java.net.URL instances
        java.net.URL
                .setURLStreamHandlerFactory(new java.net.URLStreamHandlerFactory() {
                    public java.net.URLStreamHandler createURLStreamHandler(
                            String protocol) {
                        final java.net.URLStreamHandler result = new java.net.URLStreamHandler() {

                            @Override
                            protected java.net.URLConnection openConnection(
                                    java.net.URL url) throws IOException {
                                return new java.net.URLConnection(url) {

                                    @Override
                                    public void connect() throws IOException {
                                    }

                                    @Override
                                    public InputStream getInputStream()
                                            throws IOException {
                                        InputStream result = null;

                                        // Retrieve the current context
                                        final Context context = Context
                                                .getCurrent();

                                        if (context != null) {
                                            final Response response = context
                                                    .getClientDispatcher()
                                                    .handle(new Request(
                                                            Method.GET,
                                                            this.url.toString()));

                                            if (response.getStatus()
                                                    .isSuccess()) {
                                                result = response.getEntity()
                                                        .getStream();
                                            }
                                        }

                                        return result;
                                    }
                                };
                            }

                        };

                        return result;
                    }

                });
    }

    /**
     * Sets the engine class loader.
     *
     * @param newClassLoader
     *            The new user class loader to use.
     */
    public void setClassLoader(ClassLoader newClassLoader) {
        this.classLoader = newClassLoader;
    }

    /**
     * Sets the logger facade to use.
     *
     * @param loggerFacade
     *            The logger facade to use.
     */
    public void setLoggerFacade(LoggerFacade loggerFacade) {
        this.loggerFacade = loggerFacade;
    }

    /**
     * Sets the list of available authentication helpers.
     *
     * @param registeredAuthenticators
     *            The list of available authentication helpers.
     */
    public void setRegisteredAuthenticators(
            List<org.restlet.engine.security.AuthenticatorHelper> registeredAuthenticators) {
        synchronized (this.registeredAuthenticators) {
            if (registeredAuthenticators != this.registeredAuthenticators) {
                this.registeredAuthenticators.clear();

                if (registeredAuthenticators != null) {
                    this.registeredAuthenticators
                            .addAll(registeredAuthenticators);
                }
            }
        }
    }

    /**
     * Sets the list of available client helpers.
     *
     * @param registeredClients
     *            The list of available client helpers.
     */
    public void setRegisteredClients(
            List<ConnectorHelper<Client>> registeredClients) {
        synchronized (this.registeredClients) {
            if (registeredClients != this.registeredClients) {
                this.registeredClients.clear();

                if (registeredClients != null) {
                    this.registeredClients.addAll(registeredClients);
                }
            }
        }
    }

    /**
     * Sets the list of available converter helpers.
     *
     * @param registeredConverters
     *            The list of available converter helpers.
     */
    public void setRegisteredConverters(
            List<org.restlet.engine.converter.ConverterHelper> registeredConverters) {
        synchronized (this.registeredConverters) {
            if (registeredConverters != this.registeredConverters) {
                this.registeredConverters.clear();

                if (registeredConverters != null) {
                    this.registeredConverters.addAll(registeredConverters);
                }
            }
        }
    }

    /**
     * Sets the list of available protocol helpers.
     *
     * @param registeredProtocols
     *            The list of available protocol helpers.
     */
    public void setRegisteredProtocols(List<ProtocolHelper> registeredProtocols) {
        synchronized (this.registeredProtocols) {
            if (registeredProtocols != this.registeredProtocols) {
                this.registeredProtocols.clear();

                if (registeredProtocols != null) {
                    this.registeredProtocols.addAll(registeredProtocols);
                }
            }
        }
    }

    /**
     * Sets the list of available server helpers.
     *
     * @param registeredServers
     *            The list of available server helpers.
     */
    public void setRegisteredServers(
            List<ConnectorHelper<org.restlet.Server>> registeredServers) {
        synchronized (this.registeredServers) {
            if (registeredServers != this.registeredServers) {
                this.registeredServers.clear();

                if (registeredServers != null) {
                    this.registeredServers.addAll(registeredServers);
                }
            }
        }
    }

    /**
     * Sets the user class loader that should used in priority.
     *
     * @param newClassLoader
     *            The new user class loader to use.
     */
    public void setUserClassLoader(ClassLoader newClassLoader) {
        this.userClassLoader = newClassLoader;
    }

}
TOP

Related Classes of org.restlet.engine.Engine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.