/* * This software is distributed under the terms of the FSF * Gnu Lesser General Public License (see lgpl.txt). * * This program is distributed WITHOUT ANY WARRANTY. See the * GNU General Public License for more details. */ package com.scooterframework.web.route; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.Properties; import com.scooterframework.admin.PropertyFileChangeMonitor; import com.scooterframework.admin.PropertyReader; import com.scooterframework.common.logging.LogUtil; import com.scooterframework.common.util.Converters; import com.scooterframework.common.util.PropertyFileUtil; import com.scooterframework.orm.sqldataexpress.config.DatabaseConfig; /** * RouteConfig class configs the web application during startup time. * * @author (Fei) John Chen */ public class RouteConfig implements Observer { private static LogUtil log = LogUtil.getLogger(RouteConfig.class.getName()); public static final String DATA_PROPERTIES_FILE = "routes.properties"; public static final String DEFAULT_VALUE_autoRest = "false"; private static RouteConfig me; private Properties appProperties = null; private boolean usePluralTableName = DatabaseConfig.getInstance().usePluralTableName(); static { try { me = new RouteConfig(); }catch(Exception ex) { log.fatal("Error instantiating RouteConfig: " + ex.getMessage()); ex.printStackTrace(); } } private RouteConfig() { init(); PropertyFileChangeMonitor.getInstance().registerObserver(this, DATA_PROPERTIES_FILE); DatabaseConfig.getInstance().addObserver(this); } private void init() { loadProperties(); try { loadRoutes(); } catch(Exception ex) { String errorMessage = "ERROR ERROR ERROR -- Error loading routes: " + ex.getMessage(); log.error(errorMessage); } } private void loadProperties() { if (appProperties != null) appProperties.clear(); appProperties = PropertyReader.loadOrderedPropertiesFromFile(DATA_PROPERTIES_FILE); if (appProperties == null) appProperties = new Properties(); } private void loadRoutes() { MatchMaker.getInstance().clear(); String nameValueSpliter = RouteConstants.PROPERTY_SYMBOL_NAMEVALUESPLITER; String propertyDelimiter = RouteConstants.PROPERTY_SYMBOL_PROPERTYDELIMITER; Enumeration<?> en = appProperties.keys(); while (en.hasMoreElements()) { String key = (String) en.nextElement(); if (key.startsWith("routes.name")) { String name = key.substring(key.lastIndexOf('.') +1); Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter); NamedRoute route = new NamedRoute(name, p); MatchMaker.getInstance().addNamedRoute(route); } else if (key.startsWith("routes.regular")) { String name = key.substring(key.lastIndexOf('.') +1); Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter); RegularRoute route = new RegularRoute(name, p); MatchMaker.getInstance().addRegularRoute(route); } else if (key.startsWith("routes.default")) { String name = key.substring(key.lastIndexOf('.') +1); Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter); DefaultRoute route = new DefaultRoute(name, p); MatchMaker.getInstance().addDefaultRoute(route); } else if (key.startsWith("resources.name")) { String name = key.substring(key.lastIndexOf('.') +1); Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter); Resource resource = new Resource(name, Resource.PLURAL, p); MatchMaker.getInstance().addRestRoutes(resource.getRoutes()); MatchMaker.getInstance().addResource(name, resource); } else if (key.startsWith("resource.name")) { String name = key.substring(key.lastIndexOf('.') +1); Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(getProperty(key), nameValueSpliter, propertyDelimiter); Resource resource = new Resource(name, Resource.SINGLE, p); MatchMaker.getInstance().addRestRoutes(resource.getRoutes()); MatchMaker.getInstance().addResource(name, resource); } else if (key.equals("resources.list")) { String resourceStr = getProperty(key); if (resourceStr != null) { String[] resourceArray = Converters.convertStringToStringArray(resourceStr, ","); int length = resourceArray.length; for (int i = 0; i < length; i++) { String name = resourceArray[i]; Resource resource = new Resource(name, Resource.PLURAL); MatchMaker.getInstance().addRestRoutes(resource.getRoutes()); MatchMaker.getInstance().addResource(name, resource); } } } else if (key.equals("resource.list")) { String resourceStr = getProperty(key); if (resourceStr != null) { String[] resourceArray = Converters.convertStringToStringArray(resourceStr, ","); int length = resourceArray.length; for (int i = 0; i < length; i++) { String name = resourceArray[i]; Resource resource = new Resource(name, Resource.SINGLE); MatchMaker.getInstance().addRestRoutes(resource.getRoutes()); MatchMaker.getInstance().addResource(name, resource); } } } else if (key.equals("routes.root")) { String rootRoute = getProperty(key); if (rootRoute != null) { if (rootRoute.indexOf(nameValueSpliter) != -1) { Properties p = PropertyFileUtil.parseNestedPropertiesFromLine(rootRoute, nameValueSpliter, propertyDelimiter); RootRoute route = new RootRoute("root", p); MatchMaker.getInstance().setRootRoute(route); } else { String name = rootRoute; NamedRoute nroute = MatchMaker.getInstance().getNamedRoute(name); if (nroute == null) { throw new IllegalArgumentException("A route named \"" + name + "\" must be defined before it can be used as a root route."); } RootRoute route = new RootRoute(name, nroute); MatchMaker.getInstance().setRootRoute(route); } } } } //display routes if (log.isDebugEnabled()) { List<Route> allRoutes = MatchMaker.getInstance().getAllRoutes(); Iterator<Route> it = allRoutes.iterator(); while(it.hasNext()) { Route route = it.next(); log.debug("========== route type: " + route.getRouteType() + ", name: " + route.getName()); log.debug("==> " + route); log.debug(""); } } log.info("total routes = " + MatchMaker.getInstance().countRoutes()); } public static RouteConfig getInstance() { return me; } public void update(Observable o, Object arg) { if (o instanceof DatabaseConfig) { boolean up = DatabaseConfig.getInstance().usePluralTableName(); if (usePluralTableName != up) { init(); usePluralTableName = up; } } else { init(); } } /** * Returns all properties. */ public Properties getProperties() { return appProperties; } /** * Returns a String property corresponding to a key. */ public String getProperty(String key) { return appProperties.getProperty(key); } /** * Returns a String property corresponding to a key. The method returns the * default value argument if the property is not found. */ public String getProperty(String key, String defaultValue) { return appProperties.getProperty(key, defaultValue); } /** * Checks if automatically generating restful routes with default built-in * controller class. */ public boolean allowAutoREST() { String autoRest = getProperty("auto.rest", DEFAULT_VALUE_autoRest); return ("true".equalsIgnoreCase(autoRest))?true:false; } }