org.j2free.invoker.ServiceChain.java Source code

Java tutorial

Introduction

Here is the source code for org.j2free.invoker.ServiceChain.java

Source

/*
 * ServiceChain.java
 *
 * Copyright 2011 FooBrew, Inc.
 *
 * 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.j2free.invoker;

import java.io.IOException;

import java.util.Iterator;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.j2free.jpa.Controller;

/**
 *
 * @author Ryan Wilson
 */
final class ServiceChain {
    private final Log log = LogFactory.getLog(getClass());

    private final Iterator<FilterMapping> filters;
    private final String path;
    private final ServletMapping endPoint;

    public ServiceChain(Iterator<FilterMapping> filters, String path, ServletMapping endPoint) {
        this.filters = filters;
        this.path = path;
        this.endPoint = endPoint;
    }

    /**
     * Recursively processes any filters until arriving at, and processing
     * the end-point.
     *
     * @param request a Servlet request
     * @param response a Servlet response
     * @param mapping The last FilterMaping to be processes, may be null to start
     *
     * @throws IOException
     * @throws ServletException
     */
    protected void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        // Try to get the next filter on the current depth (we're overwriting
        // the param, since we only need it in the call to mappings.ceiting(mapping).
        FilterMapping next = filters.hasNext() ? filters.next() : null;

        // If we found one, skip past any that don't apply to this path
        while (next != null && !next.appliesTo(path)) {
            if (log.isTraceEnabled()) {
                log.trace("Skipping filter [name=" + next.getName() + ", path=" + path + "]");
            }
            next = filters.hasNext() ? filters.next() : null;
        }

        // Set the link to be either the found filter or the endPoint,
        // if there were no more filters remaining, since the two are
        // polymorphically referencable as a Servicable.
        final Servicable link = next == null ? endPoint : next;

        boolean release = false; // Holds whether we need to release the Controller here
        try {
            if (link.requiresController()) // If the next Servicable requires a Controller
            {
                log.trace("Next link requires Controller");

                Controller controller = Controller.get(false); // Try to get an existing one
                if (controller == null) // If there wasn't one already
                {
                    log.trace("No Controller associated with Thread, creating...");
                    controller = Controller.get(); // Create a new one
                    release = true; // And take responsibility for closing it
                }

                // If the Servicable requires a Controller and we don't have one,
                // then blow up loudly because all resources futher down the chain
                // will be expecting a Controller and we can't provide that.
                if (controller == null) {
                    throw new ServletException(
                            String.format("Error providing required Controller to %s, [cause=NULL, release=%b]",
                                    link.getName(), release));
                } else if (!controller.isTransactionOpen()) {
                    throw new ServletException(
                            String.format("Error providing required Controller to %s, [cause=NO TX, release=%b]",
                                    link.getName(), release));
                } else
                    request.setAttribute(Controller.ATTRIBUTE_KEY, controller); // But if we got it, set it as a req attribute
            }

            if (log.isTraceEnabled())
                log.trace("Servicing link [name=" + link.getName() + "]");

            link.service(request, response, this);
        } catch (Exception e) {
            throw new ServletException("Error servicing chain", e); // Wrap any exceptions as ServletException
        } finally {
            // If this Servicable has the responsibility to release a Controller
            // Don't need to check requiresController() again, since release can ONLY
            // be true if requiresController() was true.
            if (release) {
                log.trace("Releasing Controller");
                Controller.release();
            }
        }
    }
}