Package org.springframework.batch.admin.web.util

Source Code of org.springframework.batch.admin.web.util.HomeController

/*
* Copyright 2009-2010 the original author or authors.
*
* 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.springframework.batch.admin.web.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.support.HandlerMethodResolver;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
import org.springframework.web.util.UrlPathHelper;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

/**
* Component that discovers request mappings in its application context and
* reveals their meta data. Any {@link RequestMapping} annotations in controller
* components at method or type level are discovered.
*
* @author Dave Syer
*
*/
@Controller
public class HomeController implements ApplicationContextAware, InitializingBean {

  private static Log logger = LogFactory.getLog(HomeController.class);

  private ApplicationContext applicationContext;

  private Set<String> urls;

  private List<ResourceInfo> defaultResources;

  private List<ResourceInfo> jsonResources;

  private String servletPath;

  private Properties defaultProperties = null;

  private Properties jsonProperties = null;

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

  /**
   * The path that will be added to the model as an attribute ("servletPath")
   * before rendering. Defaults to the parent servlet path (as defined in the
   * http servlet request).
   *
   * @param servletPath the servlet path to set
   */
  public void setServletPath(String servletPath) {
    this.servletPath = servletPath;
  }

  /**
   * Pre-configured mapping from url path to description for default (HTML)
   * resources.
   *
   * @param defaultResources the default resources to set
   */
  public void setDefaultResources(Properties defaultResources) {
    this.defaultProperties = defaultResources;
  }

  /**
   * Pre-configured mapping from url path to description for JSON resources.
   * If empty the description will be replaced with the one from the
   * {@link #setDefaultResources(Properties) default resources}.
   *
   * @param jsonResources the json resources to set
   */
  public void setJsonResources(Properties jsonResources) {
    this.jsonProperties = jsonResources;
  }

  /**
   * Create the meta data by querying the context for mappings.
   *
   * @see InitializingBean#afterPropertiesSet()
   */
  public void afterPropertiesSet() throws Exception {
    if (defaultProperties == null || defaultProperties.isEmpty()) {
      findResources();
    }
    else {
      this.urls = buildUrlsFromProperties(defaultProperties);
      this.defaultResources = buildResourcesFromProperties(defaultProperties, defaultProperties);
      this.jsonResources = buildResourcesFromProperties(jsonProperties, defaultProperties);
    }
  }

  private List<ResourceInfo> buildResourcesFromProperties(Properties properties, Properties defaults) {
    Set<ResourceInfo> resources = new TreeSet<ResourceInfo>();
    if (properties == null) {
      if (defaults == null) {
        return new ArrayList<ResourceInfo>();
      }
      properties = defaults;
    }
    for (Enumeration<?> iterator = properties.propertyNames(); iterator.hasMoreElements();) {
      String key = (String) iterator.nextElement();
      String method = key.substring(0, key.indexOf("/"));
      String url = key.substring(key.indexOf("/"));
      String description = properties.getProperty(key, defaults.getProperty(key));
      resources.add(new ResourceInfo(url, RequestMethod.valueOf(method), description));
    }
    return new ArrayList<ResourceInfo>(resources);
  }

  private Set<String> buildUrlsFromProperties(Properties properties) {
    Set<String> urls = new HashSet<String>();
    if (properties == null) {
      return urls;
    }
    for (Enumeration<?> iterator = properties.propertyNames(); iterator.hasMoreElements();) {
      String key = (String) iterator.nextElement();
      String url = key.substring(key.indexOf("/"));
      urls.add(url);
    }
    return urls;
  }

  private void findResources() {
    Map<String, Object> handlerMap = new HashMap<String, Object>();

    DefaultAnnotationHandlerMapping annotationMapping = new DefaultAnnotationHandlerMapping();
    annotationMapping.setApplicationContext(applicationContext);
    annotationMapping.initApplicationContext();
    handlerMap.putAll(annotationMapping.getHandlerMap());

    BeanNameUrlHandlerMapping beanMapping = new BeanNameUrlHandlerMapping();
    beanMapping.setApplicationContext(applicationContext);
    beanMapping.initApplicationContext();
    handlerMap.putAll(beanMapping.getHandlerMap());

    this.urls = findUniqueUrls(handlerMap.keySet());
    this.defaultResources = findMethods(handlerMap, this.urls);
    this.jsonResources = new ArrayList<ResourceInfo>();
    for (Iterator<ResourceInfo> iterator = this.defaultResources.iterator(); iterator.hasNext();) {
      ResourceInfo info = (ResourceInfo) iterator.next();
      if (info.getUrl().endsWith(".json")) {
        iterator.remove();
        this.jsonResources.add(info);
      }
    }

  }

  private List<ResourceInfo> findMethods(Map<String, Object> handlerMap, Set<String> urls) {

    SortedSet<ResourceInfo> result = new TreeSet<ResourceInfo>();

    for (String key : urls) {

      Object handler = handlerMap.get(key);
      Class<?> handlerType = ClassUtils.getUserClass(handler);
      HandlerMethodResolver resolver = new HandlerMethodResolver();
      resolver.init(handlerType);

      String[] typeMappings = null;
      RequestMapping typeMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
      if (typeMapping != null) {
        typeMappings = typeMapping.value();
      }

      Set<Method> handlerMethods = resolver.getHandlerMethods();
      for (Method method : handlerMethods) {

        RequestMapping mapping = method.getAnnotation(RequestMapping.class);

        Collection<String> computedMappings = new HashSet<String>();
        if (typeMappings != null) {
          computedMappings.addAll(Arrays.asList(typeMappings));
        }

        for (String path : mapping.value()) {
          if (typeMappings != null) {
            for (String parent : computedMappings) {
              if (parent.endsWith("/")) {
                parent = parent.substring(0, parent.length() - 1);
              }
              computedMappings.add(parent + path);
            }
          }
          else {
            computedMappings.add(path);
          }
        }

        logger.debug("Analysing mappings for method:" + method.getName() + ", key:" + key
            + ", computed mappings: " + computedMappings);
        if (computedMappings.contains(key)) {
          RequestMethod[] methods = mapping.method();
          if (methods != null && methods.length > 0) {
            for (RequestMethod requestMethod : methods) {
              logger.debug("Added explicit mapping for path=" + key + "to RequestMethod=" + requestMethod);
              result.add(new ResourceInfo(key, requestMethod));
            }
          }
          else {
            logger.debug("Added implicit mapping for path=" + key + "to RequestMethod=GET");
            result.add(new ResourceInfo(key, RequestMethod.GET));
          }
        }

      }

      if (handlerMethods.isEmpty()) {
        result.add(new ResourceInfo(key, RequestMethod.GET));
      }

    }

    return new ArrayList<ResourceInfo>(result);

  }

  private Set<String> findUniqueUrls(Collection<String> inputs) {
    Set<String> result = new HashSet<String>(inputs);
    for (String url : inputs) {
      String extended = url + ".*";
      if (inputs.contains(extended)) {
        result.remove(extended);
      }
      extended = url + "/";
      if (inputs.contains(extended)) {
        result.remove(extended);
      }
    }
    return result;
  }

  /**
   * Inspect the handler mapping at the level of HTTP {@link RequestMethod}.
   * Each URI pattern that is mapped can be mapped to multiple request
   * methods. If the mapping is not explicit this method only returns GET
   * (even though technically it would respond to POST as well).
   *
   * @param request the current servlet request (used to extract a page
   * attribute "sevletPath")
   * @param model {@link org.springframework.ui.ModelMap} to be used
   *
   * @return a map of URI pattern to request methods accepted
   */
  @RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
  public String getResources(HttpServletRequest request, ModelMap model) {

    String servletPath = this.servletPath;
    if (servletPath == null) {
      servletPath = new UrlPathHelper().getServletPath(request);
    }
    model.addAttribute("servletPath", servletPath);
    List<ResourceInfo> resources = new ArrayList<ResourceInfo>();
    if (!request.getRequestURI().endsWith(".json")) {
      resources.addAll(defaultResources);
    }
    resources.addAll(jsonResources);
    model.addAttribute("resources", resources);
    return "home";
  }

  /**
   * The set of unique URI patterns mapped, excluding implicit mappings.
   * Implicit mappings include all the values here plus patterns created from
   * them by appending "/" (if not already present) and ".*" (if no suffix is
   * already provided).
   *
   * @return the set of unique URI patterns mapped
   */
  public Set<String> getUrlPatterns() {
    return urls;
  }

}
TOP

Related Classes of org.springframework.batch.admin.web.util.HomeController

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.