Package org.restlet

Source Code of org.restlet.Component

/**
* 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;

import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;

import org.restlet.data.Reference;
import org.restlet.engine.Engine;
import org.restlet.engine.component.ComponentHelper;
import org.restlet.engine.component.ComponentXmlParser;
import org.restlet.engine.component.InternalRouter;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
import org.restlet.routing.Router;
import org.restlet.routing.VirtualHost;
import org.restlet.security.Realm;
import org.restlet.service.LogService;
import org.restlet.service.Service;
import org.restlet.service.StatusService;
import org.restlet.util.ClientList;
import org.restlet.util.ServerList;
import org.restlet.util.ServiceList;

/**
* Restlet managing a set of {@link Connector}s, {@link VirtualHost}s,
* {@link Service}s and {@link Application}s. Applications are expected to be
* directly attached to virtual hosts or to the internal router (see RIAP
* pseudo-protocol for usage). Components also expose several services: access
* logging and status setting. <br>
* <br>
* From an architectural point of view, here is the REST definition: "A
* component is an abstract unit of software instructions and internal state
* that provides a transformation of data via its interface." Roy T. Fielding<br>
* <br>
* The configuration of a Component can be done programmatically or by using a
* XML document. There are dedicated constructors that accept either an URI
* reference to such XML document or a representation of such XML document,
* allowing easy configuration of the list of supported client and server
* connectors as well as services. In addition, you can add and configure
* virtual hosts (including the default one). Finally, you can attach
* applications either using their fully qualified class name or by pointing to
* a descriptor document (at this time only WADL description are supported, see
* the WADL Restlet extension for details).<br>
* <br>
* The XML Schema of the configuration files is available both <a
* href="http://www.restlet.org/schemas/2.0/Component">online</a> and inside the
* API JAR under the "org.restlet.Component.xsd" name. Here is a sample of XML
* configuration:
*
* <pre>
* &lt;?xml version=&quot;1.0&quot;?&gt;
* &lt;component xmlns=&quot;http://www.restlet.org/schemas/2.0/Component&quot;&gt;
*    &lt;client protocol=&quot;CLAP&quot; /&gt;
*    &lt;client protocol=&quot;FILE&quot; /&gt;
*    &lt;client protocols=&quot;HTTP HTTPS&quot; /&gt;
*    &lt;server protocols=&quot;HTTP HTTPS&quot; /&gt;
*
*    &lt;defaultHost&gt;
*       &lt;attach uriPattern=&quot;/abcd/{xyz}&quot;
*                  targetClass=&quot;org.restlet.test.MyApplication&quot; /&gt;
*       &lt;attach uriPattern=&quot;/efgh/{xyz}&quot;
*                  targetDescriptor=&quot;clap://class/org/restlet/test/MyApplication.wadl&quot; /&gt;
*    &lt;/defaultHost&gt;
* &lt;/component&gt;
* </pre>
*
* <br>
* Components also have useful services associated. They are all enabled by
* default and are available as properties that can be eventually overridden:
* <ul>
* <li>"logService" to configure access logging.</li>
* <li>"statusService" to provide common representations for exception status.</li>
* </ul>
*
* Concurrency note: instances of this class or its subclasses can be invoked by
* several threads at the same time and therefore must be thread-safe. You
* should be especially careful when storing state in member variables.
*
* @see <a
*      href="http://roy.gbiv.com/pubs/dissertation/software_arch.htm#sec_1_2_1">Source
*      dissertation</a>
*
* @author Jerome Louvel
*/
public class Component extends Restlet {

    /**
     * Used as bootstrap for configuring and running a component in command
     * line. Just provide as first and unique parameter the URI to the XML file.
     * Note that relative paths are accepted.
     *
     * @param args
     *            The list of in-line parameters.
     */
    public static void main(String[] args) throws Exception {
        try {
            if ((args == null) || (args.length != 1)) {
                // Display program arguments
                System.err
                        .println("Can't launch the component. Requires the path to an XML configuration file.\n");
            } else {
                // Create and start the component
                URI currentDirURI = (new File(".")).toURI();
                URI confURI = currentDirURI.resolve(args[0]);
                new Component(confURI.toString()).start();
            }
        } catch (Exception e) {
            System.err
                    .println("Can't launch the component.\nAn unexpected exception occurred:");
            e.printStackTrace(System.err);
        }
    }

    /** The modifiable list of client connectors. */
    private final ClientList clients;

    /** The default host. */
    private volatile VirtualHost defaultHost;

    /** The helper provided by the implementation. */
    private volatile ComponentHelper helper;

    /** The modifiable list of virtual hosts. */
    private final List<VirtualHost> hosts;

    /**
     * The private internal router that can be addressed via the RIAP client
     * connector.
     */
    private volatile Router internalRouter;

    /** The modifiable list of security realms. */
    private final List<Realm> realms;

    /** The modifiable list of server connectors. */
    private final ServerList servers;

    /** The list of services. */
    private final ServiceList services;

    /**
     * Constructor.
     */
    public Component() {
        super();
        this.hosts = new CopyOnWriteArrayList<VirtualHost>();
        this.clients = new ClientList(null);
        this.servers = new ServerList(null, this);
        this.realms = new CopyOnWriteArrayList<Realm>();
        this.services = new ServiceList(getContext());

        if (Engine.getInstance() != null) {
            this.helper = new ComponentHelper(this);
            this.defaultHost = new VirtualHost(getContext()
                    .createChildContext());
            this.internalRouter = new InternalRouter(getContext()
                    .createChildContext());
            this.services.add(new LogService());
            this.services.add(new StatusService());
            this.clients.setContext(getContext());
            this.servers.setContext(getContext());
        }
    }

    /**
     * Constructor with the reference to the XML configuration file.
     *
     * @param xmlConfigRef
     *            The URI reference to the XML configuration file.
     */
    public Component(Reference xmlConfigRef) {
        this();

        // Get the representation of the configuration file.
        Representation xmlConfigRepresentation = null;

        if (xmlConfigRef != null) {
            ClientResource cr = new ClientResource(xmlConfigRef);
            xmlConfigRepresentation = cr.get();

            if (xmlConfigRepresentation != null) {
                new ComponentXmlParser(this, xmlConfigRepresentation).parse();
            } else {
                getLogger().log(
                        Level.WARNING,
                        "Unable to get the Component XML configuration located at this URI: "
                                + xmlConfigRef);
            }
        }
    }

    /**
     * Constructor with the representation of the XML configuration file.
     *
     * @param xmlConfigRepresentation
     *            The representation of the XML configuration file.
     */
    public Component(Representation xmlConfigRepresentation) {
        this();

        if (xmlConfigRepresentation != null) {
            new ComponentXmlParser(this, xmlConfigRepresentation).parse();
        } else {
            getLogger().log(Level.WARNING,
                    "Unable to parse the Component XML configuration.");
        }
    }

    /**
     * Constructor with the URI reference to the XML configuration file.
     *
     * @param xmlConfigurationRef
     *            The URI reference to the XML configuration file.
     */
    public Component(String xmlConfigurationRef) {
        this((xmlConfigurationRef == null) ? null : new Reference(
                xmlConfigurationRef));
    }

    /**
     * Returns a modifiable list of client connectors.
     *
     * @return A modifiable list of client connectors.
     */
    public ClientList getClients() {
        return this.clients;
    }

    /**
     * Returns the default virtual host.
     *
     * @return The default virtual host.
     */
    public VirtualHost getDefaultHost() {
        return this.defaultHost;
    }

    /**
     * Returns the helper provided by the implementation.
     *
     * @return The helper provided by the implementation.
     */
    private ComponentHelper getHelper() {
        return this.helper;
    }

    /**
     * Returns the modifiable list of virtual hosts. Note that the order of
     * virtual hosts in this list will be used to check the first one that
     * matches.
     *
     * @return The modifiable list of virtual hosts.
     */
    public List<VirtualHost> getHosts() {
        return this.hosts;
    }

    /**
     * Returns the private internal router where Restlets like Applications can
     * be attached. Those Restlets can be addressed via the
     * {@link org.restlet.data.Protocol#RIAP} (Restlet Internal Access Protocol)
     * client connector. This is used to manage private, internal and optimized
     * access to local applications.<br>
     * <br>
     * The first use case is the modularization of a large application into
     * modules or layers. This can also be achieved using the
     * {@link Context#getServerDispatcher()} method, but the internal router is
     * easily addressable via an URI scheme and can be fully private to the
     * current Component.<br>
     * <br>
     * The second use case is the composition/mash-up of several representations
     * via the org.restlet.ext.xml.Transformer class for example. For this you
     * can leverage the XPath's document() function or the XSLT's include and
     * import elements with RIAP URIs.
     *
     * @return The private internal router.
     */
    public Router getInternalRouter() {
        return this.internalRouter;
    }

    /**
     * Returns the global log service. On the first call, if no log service was
     * defined via the {@link #setLogService(LogService)} method, then a default
     * logger service is created. This service will be enabled by default and
     * has a logger name composed the "org.restlet." prefix followed by the
     * simple component class name (without packages), followed by the
     * ".LogService" suffix.
     *
     * @return The global log service.
     */
    public LogService getLogService() {
        return getServices().get(LogService.class);
    }

    /**
     * Finds the realm with the given name.
     *
     * @param name
     *            The name.
     * @return The realm found or null.
     */
    public Realm getRealm(String name) {
        if (name != null) {
            for (Realm realm : getRealms()) {
                if (name.equals(realm.getName())) {
                    return realm;
                }
            }
        }

        return null;
    }

    /**
     * Returns the modifiable list of security realms.
     *
     * @return The modifiable list of security realms.
     */
    public List<Realm> getRealms() {
        return realms;
    }

    /**
     * Returns the modifiable list of server connectors.
     *
     * @return The modifiable list of server connectors.
     */
    public ServerList getServers() {
        return this.servers;
    }

    /**
     * Returns the modifiable list of services.
     *
     * @return The modifiable list of services.
     */
    public ServiceList getServices() {
        return services;
    }

    /**
     * Returns the status service, enabled by default.
     *
     * @return The status service.
     */
    public StatusService getStatusService() {
        return getServices().get(StatusService.class);
    }

    @Override
    public void handle(Request request, Response response) {
        super.handle(request, response);

        if (getHelper() != null) {
            getHelper().handle(request, response);
        }
    }

    /**
     * Sets the modifiable list of client connectors. This method clears the
     * current list and adds all entries in the parameter list.
     *
     * @param clients
     *            A list of client connectors.
     */
    public void setClients(ClientList clients) {
        synchronized (getClients()) {
            if (clients != getClients()) {
                getClients().clear();

                if (clients != null) {
                    getClients().addAll(clients);
                }
            }
        }
    }

    @Override
    public void setContext(Context context) {
        super.setContext(context);
        getServices().setContext(context);
    }

    /**
     * Sets the default virtual host.
     *
     * @param defaultHost
     *            The default virtual host.
     */
    public void setDefaultHost(VirtualHost defaultHost) {
        this.defaultHost = defaultHost;
    }

    /**
     * Sets the modifiable list of virtual hosts. Note that the order of virtual
     * hosts in this list will be used to check the first one that matches. This
     * method clears the current list and adds all entries in the parameter
     * list.
     *
     * @param hosts
     *            A list of virtual hosts.
     */
    public void setHosts(List<VirtualHost> hosts) {
        synchronized (getHosts()) {
            if (hosts != getHosts()) {
                getHosts().clear();

                if (hosts != null) {
                    getHosts().addAll(hosts);
                }
            }
        }
    }

    /**
     * Sets the private internal router were Restlets like Applications can be
     * attached.
     *
     * @param internalRouter
     *            The private internal router.
     * @see #getInternalRouter()
     */
    public void setInternalRouter(Router internalRouter) {
        this.internalRouter = internalRouter;
    }

    /**
     * Sets the global log service.
     *
     * @param logService
     *            The global log service.
     */
    public void setLogService(LogService logService) {
        getServices().set(logService);
    }

    /**
     * Sets the list of realms. This method clears the current list and adds all
     * entries in the parameter list.
     *
     * @param realms
     *            A list of realms.
     */
    public void setRealms(List<Realm> realms) {
        synchronized (getRealms()) {
            if (realms != getRealms()) {
                getRealms().clear();

                if (realms != null) {
                    getRealms().addAll(realms);
                }
            }
        }
    }

    /**
     * Sets the modifiable list of server connectors. This method clears the
     * current list and adds all entries in the parameter list.
     *
     * @param servers
     *            A list of server connectors.
     */
    public void setServers(ServerList servers) {
        synchronized (getServers()) {
            if (servers != getServers()) {
                getServers().clear();

                if (servers != null) {
                    getServers().addAll(servers);
                }
            }
        }
    }

    /**
     * Sets the status service.
     *
     * @param statusService
     *            The status service.
     */
    public void setStatusService(StatusService statusService) {
        getServices().set(statusService);
    }

    /**
     * Starts the component. First it starts all the connectors (clients then
     * servers), the routers, the services, the realms and then the component's
     * internal helper. Finally it calls the start method of the super class.
     *
     * @see #startClients()
     * @see #startServers()
     * @see #startRouters()
     * @see #startServices()
     * @see #startRealms()
     * @see #startHelper()
     */
    @Override
    public synchronized void start() throws Exception {
        if (isStopped()) {
            startClients();
            startServers();
            startRouters();
            startServices();
            startRealms();
            startHelper();
            super.start();
        }
    }

    /**
     * Starts the client connectors.
     *
     * @throws Exception
     */
    protected synchronized void startClients() throws Exception {
        if (this.clients != null) {
            for (final Client client : this.clients) {
                client.start();
            }
        }
    }

    /**
     * Starts the internal helper allowing incoming requests to be served.
     *
     * @throws Exception
     */
    protected synchronized void startHelper() throws Exception {
        if (getHelper() != null) {
            getHelper().start();
        }
    }

    /**
     * Starts the realms.
     *
     * @throws Exception
     */
    protected synchronized void startRealms() throws Exception {
        if (this.realms != null) {
            for (Realm realm : this.realms) {
                realm.start();
            }
        }
    }

    /**
     * Starts the virtual hosts and the internal router.
     *
     * @throws Exception
     */
    protected synchronized void startRouters() throws Exception {
        if (this.internalRouter != null) {
            this.internalRouter.start();
        }

        if (this.defaultHost != null) {
            this.defaultHost.start();
        }

        for (VirtualHost host : getHosts()) {
            host.start();
        }
    }

    /**
     * Starts the server connectors.
     *
     * @throws Exception
     */
    protected synchronized void startServers() throws Exception {
        if (this.servers != null) {
            for (final Server server : this.servers) {
                server.start();
            }
        }
    }

    /**
     * Starts the associated services.
     *
     * @throws Exception
     */
    protected synchronized void startServices() throws Exception {
        getServices().start();
    }

    /**
     * Stops the component. First it stops the component's internal helper, the
     * realms, the services, the routers and then stops all the connectors
     * (servers then clients) Finally it calls the stop method of the super
     * class.
     *
     * @see #stopHelper()
     * @see #stopRealms()
     * @see #stopServices()
     * @see #stopRouters()
     * @see #stopServers()
     * @see #stopClients()
     */
    @Override
    public synchronized void stop() throws Exception {
        stopHelper();
        stopRealms();
        stopServices();
        stopRouters();
        stopServers();
        stopClients();
        super.stop();
    }

    /**
     * Stops the client connectors.
     *
     * @throws Exception
     */
    protected synchronized void stopClients() throws Exception {
        if (this.clients != null) {
            for (final Client client : this.clients) {
                client.stop();
            }
        }
    }

    /**
     * Stops the internal helper allowing incoming requests to be served.
     *
     * @throws Exception
     */
    protected synchronized void stopHelper() throws Exception {
        if (getHelper() != null) {
            getHelper().stop();
        }
    }

    /**
     * Stops the realms.
     *
     * @throws Exception
     */
    protected synchronized void stopRealms() throws Exception {
        if (this.realms != null) {
            for (Realm realm : this.realms) {
                realm.stop();
            }
        }
    }

    /**
     * Stops the virtual hosts and the internal router.
     *
     * @throws Exception
     */
    protected synchronized void stopRouters() throws Exception {
        for (VirtualHost host : getHosts()) {
            host.stop();
        }

        if (this.defaultHost != null) {
            this.defaultHost.stop();
        }

        if (this.internalRouter != null) {
            this.internalRouter.stop();
        }
    }

    /**
     * Stops the server connectors.
     *
     * @throws Exception
     */
    protected synchronized void stopServers() throws Exception {
        if (this.servers != null) {
            for (final Server server : this.servers) {
                server.stop();
            }
        }
    }

    /**
     * Stops the associated services.
     *
     * @throws Exception
     */
    protected synchronized void stopServices() throws Exception {
        getServices().stop();
    }

    /**
     * Updates the component to take into account changes to the virtual hosts.
     * This method doesn't stop the connectors or the applications or Restlets
     * attached to the virtual hosts. It just updates the internal routes
     * between the virtual hosts and the attached Restlets or applications.<br>
     */
    public synchronized void updateHosts() throws Exception {
        getHelper().update();
    }
}
TOP

Related Classes of org.restlet.Component

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.