Package org.apache.cocoon.rest.controller

Source Code of org.apache.cocoon.rest.controller.SpringRESTController

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.cocoon.rest.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.cocoon.controller.Controller;
import org.apache.cocoon.pipeline.util.URLConnectionUtils;
import org.apache.cocoon.rest.controller.annotation.BaseURL;
import org.apache.cocoon.rest.controller.annotation.Inject;
import org.apache.cocoon.rest.controller.annotation.RESTController;
import org.apache.cocoon.rest.controller.annotation.RequestHeader;
import org.apache.cocoon.rest.controller.annotation.RequestParameter;
import org.apache.cocoon.rest.controller.annotation.SitemapParameter;
import org.apache.cocoon.rest.controller.response.Page;
import org.apache.cocoon.rest.controller.response.RestResponse;
import org.apache.cocoon.rest.controller.response.Status;
import org.apache.cocoon.rest.controller.util.AnnotationCollector;
import org.apache.cocoon.servlet.controller.ControllerContextHelper;
import org.apache.cocoon.servlet.node.StatusCodeCollector;
import org.apache.cocoon.servlet.util.HttpContextHelper;
import org.apache.cocoon.sitemap.util.ExceptionHandler;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
* <p>
* This controller is responsible for the execution of instances of REST controller beans. Note that each controller
* implementation must be available as Spring bean. For that purpose you can use the {@link RESTController} annotation
* and load all beans from a particular package automatically. See
* http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-classpath-scanning for details.
* </p>
*/
public class SpringRESTController implements Controller, ApplicationContextAware {

    private AnnotationCollector annotationCollector;

    private ApplicationContext applicationContext;

    private MethodDelegator methodDelegator;

    public void invoke(OutputStream outputStream, String functionName, Map<String, Object> inputParameters,
            Map<String, ? extends Object> configuration) {
        if (!this.applicationContext.isPrototype(functionName)) {
            throw new RuntimeException("A REST controller bean MUST run within the 'prototype' scope.");
        }

        try {
            // get the prepared controller
            Object controller = this.getController(functionName, inputParameters, configuration);

            // invoke the appropriate method
            HttpServletRequest request = HttpContextHelper.getRequest(inputParameters);
            RestResponse restResponse = this.methodDelegator.delegate(request, controller);

            // forward the response
            if (restResponse instanceof Status) {
                Status status = (Status) restResponse;
                StatusCodeCollector.setStatusCode(status.getStatus());
            } else if (restResponse instanceof Page) {
                Page page = (Page) restResponse;

                ControllerContextHelper.storeContext(page.getData(), inputParameters);

                URL pageUri = new URL(new URL("servlet:"), page.getUri());
                URLConnection servletConnection = pageUri.openConnection();
                IOUtils.copy(servletConnection.getInputStream(), outputStream);
                URLConnectionUtils.closeQuietly(servletConnection);
            }
        } catch (Exception e) {
            throw ExceptionHandler.getInvocationException(e);
        }
    }

    public void setAnnotationCollector(AnnotationCollector annotationCollector) {
        this.annotationCollector = annotationCollector;
    }

    /**
     * {@inheritDoc}
     *
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void setMethodDelegator(MethodDelegator methodDelegator) {
        this.methodDelegator = methodDelegator;
    }

    @SuppressWarnings("unchecked")
    private Object getController(String controllerName, Map<String, Object> inputParameters,
            Map<String, ? extends Object> configuration) throws Exception {
        Object controller = this.applicationContext.getBean(controllerName);

        Map<Class<? extends Annotation>, List<Field>> annotatedFields = this.annotationCollector
                .getAnnotatedFields(controller.getClass());

        // populate the annotated fields
        populateInjectFields(inputParameters, controller, annotatedFields);
        populateRequestFields(inputParameters, controller, annotatedFields);
        populateRequestHeaderFields(inputParameters, controller, annotatedFields);
        populateSitemapParameters(configuration, controller, annotatedFields);
        this.populateBaseURL(configuration, controller, annotatedFields);

        return controller;
    }

    private void populateBaseURL(Map<String, ? extends Object> configuration, Object controller,
            Map<Class<? extends Annotation>, List<Field>> annotatedFields) throws IllegalAccessException, Exception {
        List<Field> baseURLFields = annotatedFields.get(BaseURL.class);
        if (baseURLFields == null || baseURLFields.isEmpty()) {
            return;
        }

        for (Field field : baseURLFields) {
            field.setAccessible(true);

            Class<?> fieldType = field.getType();
            if (fieldType == URL.class) {
                field.set(controller, configuration.get("baseUrl"));
            } else {
                throw new Exception("The annotation " + BaseURL.class.getName() + " can only be set on fields of type "
                        + URL.class.getName() + "." + " " + "(field=" + field.getName() + ", type="
                        + fieldType.getName() + ")");
            }
        }

    }

    private static void populateInjectFields(Map<String, ? extends Object> parameters, Object controller,
            Map<Class<? extends Annotation>, List<Field>> annotatedFields) throws IllegalAccessException, IOException,
            Exception {
        List<Field> injectFields = annotatedFields.get(Inject.class);
        if (injectFields == null || injectFields.isEmpty()) {
            return;
        }

        HttpServletRequest request = HttpContextHelper.getRequest(parameters);
        HttpServletResponse response = HttpContextHelper.getResponse(parameters);
        for (Field field : injectFields) {
            field.setAccessible(true);

            Class<?> fieldType = field.getType();
            if (fieldType == HttpServletRequest.class) {
                field.set(controller, request);
            } else if (fieldType == HttpServletResponse.class) {
                field.set(controller, response);
            } else if (fieldType == Log.class) {
                field.set(controller, LogFactory.getLog(controller.getClass()));
            } else if (fieldType == ServletInputStream.class || fieldType == InputStream.class) {
                field.set(controller, request.getInputStream());
            } else if (fieldType == ServletOutputStream.class || fieldType == OutputStream.class) {
                field.set(controller, response.getOutputStream());
            } else {
                throw new Exception("The annotation " + Inject.class.getName()
                        + " doesn't support the injection of type " + fieldType.getName() + "." + " " + "(field="
                        + field.getName() + ", type=" + fieldType.getName() + ")");
            }
        }
    }

    private static void populateRequestFields(Map<String, ? extends Object> parameters, Object controller,
            Map<Class<? extends Annotation>, List<Field>> annotatedFields) throws IllegalAccessException, Exception {
        List<Field> requestFields = annotatedFields.get(RequestParameter.class);
        if (requestFields == null || requestFields.isEmpty()) {
            return;
        }

        HttpServletRequest request = HttpContextHelper.getRequest(parameters);
        for (Field field : requestFields) {
            field.setAccessible(true);

            String requestParameterName = field.getAnnotation(RequestParameter.class).value();
            if (isBlank(requestParameterName)) {
                requestParameterName = field.getName();
            }

            Class<?> fieldType = field.getType();
            if (fieldType == String.class) {
                String parameter = request.getParameter(requestParameterName);
                if (parameter != null) {
                    field.set(controller, parameter);
                }
            } else if (fieldType == int.class) {
                String parameter = request.getParameter(requestParameterName);
                if (parameter != null) {
                    field.set(controller, Integer.parseInt(parameter));
                }
            } else if (fieldType == boolean.class) {
                String parameter = request.getParameter(requestParameterName);
                if (parameter != null) {
                    field.set(controller, Boolean.parseBoolean(parameter));
                }
            } else if (fieldType == String[].class) {
                String[] parameterValues = request.getParameterValues(requestParameterName);
                if (parameterValues != null) {
                    field.set(controller, parameterValues);
                }
            } else {
                throw new Exception("The annotation " + RequestParameter.class.getName()
                        + " can only be set on fields of type " + String.class.getName() + ", "
                        + String[].class.getName() + ", " + int.class.getName() + " or " + boolean.class.getName()
                        + ". (field=" + field.getName() + ", type=" + fieldType.getName() + ")");
            }
        }
    }

    private static void populateRequestHeaderFields(Map<String, ? extends Object> parameters, Object controller,
            Map<Class<? extends Annotation>, List<Field>> annotatedFields) throws IllegalAccessException, Exception {
        List<Field> requestHeaderFields = annotatedFields.get(RequestHeader.class);
        if (requestHeaderFields == null || requestHeaderFields.isEmpty()) {
            return;
        }

        HttpServletRequest request = HttpContextHelper.getRequest(parameters);
        for (Field field : requestHeaderFields) {
            field.setAccessible(true);

            String name = field.getAnnotation(RequestHeader.class).value();
            if (isBlank(name)) {
                name = field.getName();
            }

            Class<?> fieldType = field.getType();
            if (fieldType == String.class) {
                String header = request.getHeader(name);
                if (header != null) {
                    field.set(controller, header);
                }
            } else {
                throw new Exception("The annotation " + RequestHeader.class.getName()
                        + " can only be set on fields of type " + String.class.getName() + "." + " " + "(field="
                        + field.getName() + ", type=" + fieldType.getName() + ")");
            }
        }
    }

    private static void populateSitemapParameters(Map<String, ? extends Object> configuration, Object controller,
            Map<Class<? extends Annotation>, List<Field>> annotatedFields) throws IllegalAccessException, Exception {
        List<Field> sitemapParameterFields = annotatedFields.get(SitemapParameter.class);
        if (sitemapParameterFields == null || sitemapParameterFields.isEmpty()) {
            return;
        }

        for (Field field : sitemapParameterFields) {
            field.setAccessible(true);

            String name = field.getAnnotation(SitemapParameter.class).value();
            if (isBlank(name)) {
                name = field.getName();
            }

            Class<?> fieldType = field.getType();
            if (fieldType == String.class) {
                field.set(controller, configuration.get(name));
            } else {
                throw new Exception("The annotation " + SitemapParameter.class.getName()
                        + " can only be set on fields of type " + String.class.getName() + "." + " " + "(field="
                        + field.getName() + ", type=" + fieldType.getName() + ")");
            }
        }
    }

    private static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (Character.isWhitespace(str.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }
}
TOP

Related Classes of org.apache.cocoon.rest.controller.SpringRESTController

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.