Package org.restlet

Source Code of org.restlet.Application

/**
* 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.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Filter;

import org.restlet.engine.Engine;
import org.restlet.engine.application.ApplicationHelper;
import org.restlet.engine.resource.AnnotationUtils;
import org.restlet.resource.Finder;
import org.restlet.resource.ServerResource;
import org.restlet.routing.Router;
import org.restlet.routing.VirtualHost;
import org.restlet.security.Role;
import org.restlet.service.ConnectorService;
import org.restlet.service.ConverterService;
import org.restlet.service.DecoderService;
import org.restlet.service.EncoderService;
import org.restlet.service.MetadataService;
import org.restlet.service.RangeService;
import org.restlet.service.StatusService;
import org.restlet.service.TunnelService;
import org.restlet.util.ServiceList;

/**
* Restlet managing a coherent set of Resources and Services. Applications are
* guaranteed to receive calls with their base reference set relatively to the
* {@link VirtualHost} that served them. This class is both a descriptor able to
* create the root Restlet and the actual Restlet that can be attached to one or
* more VirtualHost instances.<br>
* <br>
* Applications also have many useful services associated. They are all enabled
* by default and are available as properties that can be eventually overridden:
* <ul>
* <li>"connectorService" to declare necessary client and server connectors.</li>
* <li>"converterService" to convert between regular objects and
* representations.</li>
* <li>"decoderService" to automatically decode or uncompress received entities.
* </li>
* <li>"encoderService" to automatically encode or compress sent entities.</li>
* <li>"metadataService" to provide access to metadata and their associated
* extension names.</li>
* <li>"rangeService" to automatically exposes ranges of response entities.</li>
* <li>"statusService" to provide common representations for exception status.</li>
* <li>"taskService" to run tasks asynchronously.</li>
* <li>"tunnelService" to tunnel method names or client preferences via query
* parameters.</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.
*
* @author Jerome Louvel
*/
public class Application extends Restlet {
    private static final ThreadLocal<Application> CURRENT = new ThreadLocal<Application>();

    /**
     * This variable is stored internally as a thread local variable and updated
     * each time a call enters an application.
     *
     * Warning: this method should only be used under duress. You should by
     * default prefer obtaining the current application using methods such as
     * {@link org.restlet.resource.UniformResource#getApplication()}
     *
     * @return The current context.
     */
    public static Application getCurrent() {
        return CURRENT.get();
    }

    /**
     * Sets the context to associated with the current thread.
     *
     * @param application
     *            The thread's context.
     */
    public static void setCurrent(Application application) {
        CURRENT.set(application);
    }

    /** Finder class to instantiate. */
    private volatile Class<? extends Finder> finderClass;

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

    /** The modifiable list of roles. */
    private final List<Role> roles;

    /** The inbound root Restlet. */
    private volatile Restlet inboundRoot;

    /** The outbound root Restlet. */
    private volatile Restlet outboundRoot;

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

    /**
     * Constructor. Note this constructor is convenient because you don't have
     * to provide a context like for {@link #Application(Context)}. Therefore
     * the context will initially be null. It's only when you attach the
     * application to a virtual host via one of its attach*() methods that a
     * proper context will be set.
     */
    public Application() {
        this(null);
    }

    /**
     * Constructor.
     *
     * @param context
     *            The context to use based on parent component context. This
     *            context should be created using the
     *            {@link Context#createChildContext()} method to ensure a proper
     *            isolation with the other applications.
     */
    public Application(Context context) {
        super(context);

        if (Engine.getInstance() != null) {
            this.helper = new ApplicationHelper(this);
        }

        this.outboundRoot = null;
        this.inboundRoot = null;
        this.roles = new CopyOnWriteArrayList<Role>();
        this.services = new ServiceList(context);
        this.services.add(new TunnelService(true, true));
        this.services.add(new StatusService());
        this.services.add(new DecoderService());
        this.services.add(new EncoderService(false));
        this.services.add(new RangeService());
        this.services.add(new ConnectorService());
        this.services.add(new ConverterService());
        this.services.add(new MetadataService());

        this.services.add(new org.restlet.service.TaskService());
    }

    /**
     * Creates a inbound root Restlet that will receive all incoming calls. In
     * general, instances of Router, Filter or Finder classes will be used as
     * initial application Restlet. The default implementation returns null by
     * default. This method is intended to be overridden by subclasses.
     *
     * @return The inbound root Restlet.
     */
    public Restlet createInboundRoot() {
        return null;
    }

    /**
     * Creates a outbound root Restlet that will receive all outgoing calls from
     * ClientResource. In general, instances of {@link Router} and
     * {@link Filter} classes will be used. The default implementation returns a
     * Restlet giving access to the the outbound service layer and finally to
     * the {@link Context#getClientDispatcher()}.
     * <p>
     * This method is intended to be overridden by subclasses but in order to
     * benefit from the outbound service filtering layer, the original outbound
     * root must be careful attached again at the end of the user filtering
     * layer.
     *
     * @return The outbound root Restlet.
     */
    public Restlet createOutboundRoot() {
        return getHelper().getFirstOutboundFilter();
    }

    /**
     * Returns the connector service. The service is enabled by default.
     *
     * @return The connector service.
     */
    public ConnectorService getConnectorService() {
        return getServices().get(ConnectorService.class);
    }

    /**
     * Returns the converter service. The service is enabled by default.
     *
     * @return The converter service.
     */
    public ConverterService getConverterService() {
        return getServices().get(ConverterService.class);
    }

    /**
     * Returns the decoder service. The service is enabled by default.
     *
     * @return The decoder service.
     */
    public DecoderService getDecoderService() {
        return getServices().get(DecoderService.class);
    }

    /**
     * Returns the encoder service. The service is disabled by default.
     *
     * @return The encoder service.
     */
    public EncoderService getEncoderService() {
        return getServices().get(EncoderService.class);
    }

    /**
     * Returns the finder class used to instantiate resource classes. By
     * default, it returns the {@link Finder} class. This property is leveraged
     * by {@link #setOutboundRoot(Class)} and {@link #setInboundRoot(Class)}
     * methods.
     *
     * @return the finder class to instantiate.
     */
    public Class<? extends Finder> getFinderClass() {
        return finderClass;
    }

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

    /**
     * Returns the inbound root Restlet.
     *
     * @return The inbound root Restlet.
     */
    public Restlet getInboundRoot() {
        if (this.inboundRoot == null) {
            synchronized (this) {
                if (this.inboundRoot == null) {
                    this.inboundRoot = createInboundRoot();
                }
            }
        }

        return this.inboundRoot;
    }

    /**
     * Returns the metadata service. The service is enabled by default.
     *
     * @return The metadata service.
     */
    public MetadataService getMetadataService() {
        return getServices().get(MetadataService.class);
    }

    /**
     * Returns the outbound root Restlet.
     *
     * @return The outbound root Restlet.
     */
    public Restlet getOutboundRoot() {
        if (this.outboundRoot == null) {
            synchronized (this) {
                if (this.outboundRoot == null) {
                    this.outboundRoot = createOutboundRoot();
                }
            }
        }

        return this.outboundRoot;
    }

    /**
     * Returns the range service.
     *
     * @return The range service.
     */
    public RangeService getRangeService() {
        return getServices().get(RangeService.class);
    }

    /**
     * Returns the role associated to the given name.
     *
     * @param name
     *            The name of the role to find.
     * @return The role matched or null.
     */
    public Role getRole(String name) {
        for (Role role : getRoles()) {
            if (role.getName().equals(name)) {
                return role;
            }
        }

        return null;
    }

    /**
     * Returns the modifiable list of roles.
     *
     * @return The modifiable list of roles.
     */
    public List<Role> getRoles() {
        return roles;
    }

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

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

    /**
     * Returns a task service to run concurrent tasks. The service is enabled by
     * default.
     *
     * @return A task service.
     */
    public org.restlet.service.TaskService getTaskService() {
        return getServices().get(org.restlet.service.TaskService.class);
    }

    /**
     * Returns the tunnel service. The service is enabled by default.
     *
     * @return The tunnel service.
     */
    public TunnelService getTunnelService() {
        return getServices().get(TunnelService.class);
    }

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

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

    /**
     * Sets the client root Resource class.
     *
     * @param clientRootClass
     *            The client root {@link ServerResource} subclass.
     * @deprecated Use {@link #setOutboundRoot(Class)} instead
     */
    @Deprecated
    public synchronized void setClientRoot(
            Class<? extends ServerResource> clientRootClass) {
        setOutboundRoot(clientRootClass);
    }

    /**
     * Sets the connector service.
     *
     * @param connectorService
     *            The connector service.
     */
    public void setConnectorService(ConnectorService connectorService) {
        getServices().set(connectorService);
    }

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

    /**
     * Sets the converter service.
     *
     * @param converterService
     *            The converter service.
     */
    public void setConverterService(ConverterService converterService) {
        getServices().set(converterService);
    }

    /**
     * Sets the decoder service.
     *
     * @param decoderService
     *            The decoder service.
     */
    public void setDecoderService(DecoderService decoderService) {
        getServices().set(decoderService);
    }

    /**
     * Sets the encoder service.
     *
     * @param encoderService
     *            The encoder service.
     */
    public void setEncoderService(EncoderService encoderService) {
        getServices().set(encoderService);
    }

    /**
     * Sets the finder class to instantiate. This property is leveraged by
     * {@link #setOutboundRoot(Class)} and {@link #setInboundRoot(Class)}
     * methods.
     *
     * @param finderClass
     *            The finder class to instantiate.
     */
    public void setFinderClass(Class<? extends Finder> finderClass) {
        this.finderClass = finderClass;
    }

    /**
     * Sets the inbound root Resource class.
     *
     * @param inboundRootClass
     *            The inbound root Resource class.
     */
    public synchronized void setInboundRoot(
            Class<? extends ServerResource> inboundRootClass) {
        setInboundRoot(Finder.createFinder(inboundRootClass, getFinderClass(),
                getContext(), getLogger()));
    }

    /**
     * Sets the inbound root Restlet.
     *
     * @param inboundRoot
     *            The inbound root Restlet.
     */
    public synchronized void setInboundRoot(Restlet inboundRoot) {
        this.inboundRoot = inboundRoot;

        if ((inboundRoot != null) && (inboundRoot.getContext() == null)) {
            inboundRoot.setContext(getContext());
        }
    }

    /**
     * Sets the metadata service.
     *
     * @param metadataService
     *            The metadata service.
     */
    public void setMetadataService(MetadataService metadataService) {
        getServices().set(metadataService);
    }

    /**
     * Sets the outbound root Resource class.
     *
     * @param outboundRootClass
     *            The client root {@link ServerResource} subclass.
     */
    public synchronized void setOutboundRoot(
            Class<? extends ServerResource> outboundRootClass) {
        setOutboundRoot(Finder.createFinder(outboundRootClass,
                getFinderClass(), getContext(), getLogger()));
    }

    /**
     * Sets the outbound root Restlet.
     *
     * @param outboundRoot
     *            The outbound root Restlet.
     */
    public synchronized void setOutboundRoot(Restlet outboundRoot) {
        this.outboundRoot = outboundRoot;

        if ((outboundRoot != null) && (outboundRoot.getContext() == null)) {
            outboundRoot.setContext(getContext());
        }
    }

    /**
     * Sets the range service.
     *
     * @param rangeService
     *            The range service.
     */
    public void setRangeService(RangeService rangeService) {
        getServices().set(rangeService);
    }

    /**
     * Sets the modifiable list of roles. This method clears the current list
     * and adds all entries in the parameter list.
     *
     * @param roles
     *            A list of roles.
     */
    public void setRoles(List<Role> roles) {
        synchronized (getRoles()) {
            if (roles != getRoles()) {
                getRoles().clear();

                if (roles != null) {
                    getRoles().addAll(roles);
                }
            }
        }
    }

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

    /**
     * Sets the task service.
     *
     * @param taskService
     *            The task service.
     */
    public void setTaskService(org.restlet.service.TaskService taskService) {
        getServices().set(taskService);
    }

    /**
     * Sets the tunnel service.
     *
     * @param tunnelService
     *            The tunnel service.
     */
    public void setTunnelService(TunnelService tunnelService) {
        getServices().set(tunnelService);
    }

    /**
     * Starts the application, all the enabled associated services then the
     * inbound and outbound roots.
     */
    @Override
    public synchronized void start() throws Exception {
        if (isStopped()) {
            super.start();

            if (getHelper() != null) {
                getHelper().start();
            }

            getServices().start();

            if (getInboundRoot() != null) {
                getInboundRoot().start();
            }

            if (getOutboundRoot() != null) {
                getOutboundRoot().start();
            }
        }
    }

    /**
     * Stops the application, the inbound and outbound roots then all the
     * enabled associated services. Finally, it clears the internal cache of
     * annotations.
     */
    @Override
    public synchronized void stop() throws Exception {
        if (isStarted()) {
            if (getOutboundRoot() != null) {
                getOutboundRoot().stop();
            }

            if (getInboundRoot() != null) {
                getInboundRoot().stop();
            }

            getServices().stop();

            if (getHelper() != null) {
                getHelper().stop();
            }

            // Clear the annotations cache
            AnnotationUtils.clearCache();

            super.stop();
        }
    }

}
TOP

Related Classes of org.restlet.Application

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.