Package ca.simplegames.micro.route

Source Code of ca.simplegames.micro.route.RouteManager

/*
* Copyright (c)2012. Florin T.PATRASCU
*
* 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 ca.simplegames.micro.route;

import ca.simplegames.micro.Globals;
import ca.simplegames.micro.MicroContext;
import ca.simplegames.micro.Route;
import ca.simplegames.micro.SiteContext;
import ca.simplegames.micro.utils.Assert;
import ca.simplegames.micro.utils.CollectionUtils;
import ca.simplegames.micro.utils.MicroConfigFileMonitor;
import ca.simplegames.micro.utils.Reloadable;
import org.apache.wink.common.internal.uritemplate.UriTemplateMatcher;
import org.jrack.Rack;
import org.jrack.RackResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;

import javax.ws.rs.core.MultivaluedMap;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;

/**
* The Route manager is responsible for initializing various Routes at startup time, and for executing those
* {@link Route} instances that are matching the request path at runtime
*
* @author <a href="mailto:florin.patrascu@gmail.com">Florin T.PATRASCU</a>
* @since $Revision$ (created: 2012-12-21 6:04 PM)
*/
public class RouteManager implements Reloadable {
  private Logger log = LoggerFactory.getLogger(getClass());
  private MicroConfigFileMonitor monitor;
  private SiteContext site;
  private File routesConfig;

  private List<Route> routes = new ArrayList<Route>();
  private Map<String, Route> routesMap = new HashMap<String, Route>();

  private void load(SiteContext site, List<Map<String, Object>> routeMaps) {
    if (!CollectionUtils.isEmpty(routeMaps)) {
      for (Map<String, Object> routeMap : routeMaps) {
        try {
          String routePath = (String) routeMap.get("route");
          Route route = new RouteWrapper(routePath, routeMap);
          add(route);
        } catch (Exception e) {
          log.error("cannot load the following router for: " + routeMaps);
          e.printStackTrace();
        }
      }
    } else {
      log.warn("Empty route config file, nothing to do.");
    }
  }

  @Override
  @SuppressWarnings("unchecked")
  public void reload() throws Exception {
    routes = new ArrayList<Route>();
    routesMap = new HashMap<String, Route>();

    load(site, (List<Map<String, Object>>) new Yaml().load(new FileInputStream(routesConfig)));
  }

  @SuppressWarnings("unchecked")
  public RouteManager(SiteContext site, File routesConfig) throws Exception {
    Assert.notNull(site, "invalid initial state, you can't load the routes if the site object is null");
    Assert.notNull(routesConfig, "routes cannot be defined from a null config file");

    this.site = site;
    this.routesConfig = routesConfig;

    if (site.isDevelopment()) {
      int seconds = 2;

      log.info("The routes config file will be monitored every " + seconds + " seconds and reloaded if modified.");
      monitor = new MicroConfigFileMonitor(routesConfig, this, seconds);
      // todo: think about a future usage of the monitor field
    } else {
      load(site, (List<Map<String, Object>>) new Yaml().load(new FileInputStream(routesConfig)));
    }
  }

  /**
   * add a new Route
   *
   * @param route the route instance
   */
  public void add(Route route) {
    if (route != null) {
      routes.add(route);
      routesMap.put(route.getPath(), route);
    }
  }

  /**
   * method used by various admin tools
   *
   * @return a read only map containing all the route paths and their associated route instances
   */
  public Map<String, Route> getRoutesMap() {
    return Collections.unmodifiableMap(routesMap);
  }

  /**
   * assess and call one ore more {@link Route} instances that matches the request path parameter. The
   * execution flow can be interrupted if the Route implementation is requiring a full stop: aka context.halt()
   *
   * @param path    the request path
   * @param context the current micro context
   * @throws Exception if underlining Controllers or Views will throw any errors
   */
  @SuppressWarnings("unchecked")
  public void call(String path, MicroContext context) throws Exception {
    String requestedMethod = (String) context.getRackInput().get(Rack.REQUEST_METHOD);

    if (requestedMethod != null) {
      for (Route route : routes) {
        if (route.getMethod().isEmpty() || route.getMethod().contains(requestedMethod)) {

          UriTemplateMatcher templateMatcher = route.match(path, route.getPath());

          if (templateMatcher != null) {
            MultivaluedMap<String, String> routeParams = templateMatcher.getVariables(true);
            Map<String, Object> params = (Map<String, Object>) context.get(Globals.PARAMS);

            if (CollectionUtils.isEmpty(params)) {
              params = new HashMap<String, Object>();
              context.with(Globals.PARAMS, params);
            }

            for (Map.Entry<String, List<String>> param : routeParams.entrySet()) {
              Object paramValue = param.getValue() != null && param.getValue().size() == 1
                  ? param.getValue().get(0) :
                  param.getValue().toArray(new String[param.getValue().size()]);
              params.put(param.getKey(), paramValue);
            }

            RackResponse response = route.call(context);
            if (response != null) {
              context.setRackResponse(response);
            }

            // first matching route wins
            break;
          }
        }
      }
    }
  }
}
TOP

Related Classes of ca.simplegames.micro.route.RouteManager

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.