Save This Page
Home » xwork-2.1.1-src » com.opensymphony.xwork2.config.impl » [javadoc | source]
    1   /*
    2    * Copyright (c) 2002-2006 by OpenSymphony
    3    * All rights reserved.
    4    */
    5   package com.opensymphony.xwork2.config.impl;
    6   
    7   import com.opensymphony.xwork2.ActionContext;
    8   import com.opensymphony.xwork2.DefaultTextProvider;
    9   import com.opensymphony.xwork2.ObjectFactory;
   10   import com.opensymphony.xwork2.TextProvider;
   11   import com.opensymphony.xwork2.config;
   12   import com.opensymphony.xwork2.config.entities;
   13   import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
   14   import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
   15   import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
   16   import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
   17   import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
   18   import com.opensymphony.xwork2.inject;
   19   import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
   20   import com.opensymphony.xwork2.ognl.OgnlUtil;
   21   import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
   22   import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
   23   import com.opensymphony.xwork2.util.CompoundRoot;
   24   import com.opensymphony.xwork2.util.PatternMatcher;
   25   import com.opensymphony.xwork2.util.ValueStack;
   26   import com.opensymphony.xwork2.util.ValueStackFactory;
   27   import com.opensymphony.xwork2.util.location.LocatableProperties;
   28   import com.opensymphony.xwork2.util.logging.Logger;
   29   import com.opensymphony.xwork2.util.logging.LoggerFactory;
   30   import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
   31   import ognl.PropertyAccessor;
   32   
   33   import java.util;
   34   
   35   
   36   /**
   37    * DefaultConfiguration
   38    *
   39    * @author Jason Carreira
   40    *         Created Feb 24, 2003 7:38:06 AM
   41    */
   42   public class DefaultConfiguration implements Configuration {
   43   
   44       protected static final Logger LOG = LoggerFactory.getLogger(DefaultConfiguration.class);
   45   
   46   
   47       // Programmatic Action Configurations
   48       protected Map<String, PackageConfig> packageContexts = new LinkedHashMap<String, PackageConfig>();
   49       protected RuntimeConfiguration runtimeConfiguration;
   50       protected Container container;
   51       protected String defaultFrameworkBeanName;
   52       protected Set<String> loadedFileNames = new TreeSet<String>();
   53   
   54   
   55       ObjectFactory objectFactory;
   56   
   57       public DefaultConfiguration() {
   58           this("xwork");
   59       }
   60       
   61       public DefaultConfiguration(String defaultBeanName) {
   62           this.defaultFrameworkBeanName = defaultBeanName;
   63       }
   64   
   65   
   66       public PackageConfig getPackageConfig(String name) {
   67           return packageContexts.get(name);
   68       }
   69   
   70       public Set getPackageConfigNames() {
   71           return packageContexts.keySet();
   72       }
   73   
   74       public Map getPackageConfigs() {
   75           return packageContexts;
   76       }
   77       
   78       public Set<String> getLoadedFileNames() {
   79           return loadedFileNames;
   80       }
   81   
   82       public RuntimeConfiguration getRuntimeConfiguration() {
   83           return runtimeConfiguration;
   84       }
   85       
   86       /**
   87        * @return the container
   88        */
   89       public Container getContainer() {
   90           return container;
   91       }
   92   
   93       public void addPackageConfig(String name, PackageConfig packageContext) {
   94           PackageConfig check = packageContexts.get(name);
   95           if (check != null) {
   96               if (check.getLocation() != null && packageContext.getLocation() != null
   97                       && check.getLocation().equals(packageContext.getLocation())) {
   98                   if (LOG.isDebugEnabled()) {
   99                       LOG.debug("The package name '" + name 
  100                       + "' is already been loaded by the same location and could be removed: " 
  101                       + packageContext.getLocation());
  102                   } 
  103               } else {
  104                   throw new ConfigurationException("The package name '" + name 
  105                           + "' at location "+packageContext.getLocation()
  106                           + " is already been used by another package at location " + check.getLocation(),
  107                           packageContext);
  108               }
  109           }
  110           packageContexts.put(name, packageContext);
  111       }
  112   
  113       /**
  114        * Allows the configuration to clean up any resources used
  115        */
  116       public void destroy() {
  117           packageContexts.clear();
  118           loadedFileNames.clear();
  119       }
  120   
  121       public void rebuildRuntimeConfiguration() {
  122           runtimeConfiguration = buildRuntimeConfiguration();
  123       }
  124       
  125       /**
  126        * Calls the ConfigurationProviderFactory.getConfig() to tell it to reload the configuration and then calls
  127        * buildRuntimeConfiguration().
  128        *
  129        * @throws ConfigurationException
  130        */
  131       public synchronized void reload(List<ConfigurationProvider> providers) throws ConfigurationException {
  132           
  133           // Silly copy necessary due to lack of ability to cast generic lists
  134           List<ContainerProvider> contProviders = new ArrayList<ContainerProvider>();
  135           contProviders.addAll(providers);
  136           
  137           reloadContainer(contProviders);
  138       }
  139   
  140       /**
  141        * Calls the ConfigurationProviderFactory.getConfig() to tell it to reload the configuration and then calls
  142        * buildRuntimeConfiguration().
  143        *
  144        * @throws ConfigurationException
  145        */
  146       public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
  147           packageContexts.clear();
  148           loadedFileNames.clear();
  149           List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();
  150   
  151           ContainerProperties props = new ContainerProperties();
  152           ContainerBuilder builder = new ContainerBuilder();
  153           for (final ContainerProvider containerProvider : providers)
  154           {
  155               containerProvider.init(this);
  156               containerProvider.register(builder, props);
  157           }
  158           props.setConstants(builder);
  159           
  160           builder.factory(Configuration.class, new Factory<Configuration>() {
  161               public Configuration create(Context context) throws Exception {
  162                   return DefaultConfiguration.this;
  163               }
  164           });
  165           
  166           try {
  167               // Set the bootstrap container for the purposes of factory creation
  168               Container bootstrap = createBootstrapContainer();
  169               setContext(bootstrap);
  170               container = builder.create(false);
  171               setContext(container);
  172               objectFactory = container.getInstance(ObjectFactory.class);
  173   
  174               // Process the configuration providers first
  175               for (final ContainerProvider containerProvider : providers)
  176               {
  177                   if (containerProvider instanceof PackageProvider) {
  178                       container.inject(containerProvider);
  179                       ((PackageProvider)containerProvider).loadPackages();
  180                       packageProviders.add((PackageProvider)containerProvider);
  181                   }
  182               }
  183               
  184               // Then process any package providers from the plugins
  185               Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
  186               if (packageProviderNames != null) {
  187                   for (String name : packageProviderNames) {
  188                       PackageProvider provider = container.getInstance(PackageProvider.class, name);
  189                       provider.init(this);
  190                       provider.loadPackages();
  191                       packageProviders.add(provider);
  192                   }
  193               }
  194       
  195               rebuildRuntimeConfiguration();
  196           } finally {
  197               ActionContext.setContext(null);
  198           }
  199           return packageProviders;
  200       }
  201       
  202       protected ActionContext setContext(Container cont) {
  203           ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();
  204           ActionContext context = new ActionContext(vs.getContext());
  205           ActionContext.setContext(context);
  206           return context;
  207       }
  208   
  209       protected Container createBootstrapContainer() {
  210           ContainerBuilder builder = new ContainerBuilder();
  211           builder.factory(ObjectFactory.class, Scope.SINGLETON);
  212           builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
  213           builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
  214           builder.factory(XWorkConverter.class, Scope.SINGLETON);
  215           builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
  216           builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
  217           builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
  218           builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
  219           builder.factory(OgnlUtil.class, Scope.SINGLETON);
  220           builder.constant("devMode", "false");
  221           return builder.create(true);
  222       }
  223   
  224       /**
  225        * This builds the internal runtime configuration used by Xwork for finding and configuring Actions from the
  226        * programmatic configuration data structures. All of the old runtime configuration will be discarded and rebuilt.
  227        *
  228        * <p>
  229        * It basically flattens the data structures to make the information easier to access.  It will take
  230        * an {@link ActionConfig} and combine its data with all inherited dast.  For example, if the {@link ActionConfig}
  231        * is in a package that contains a global result and it also contains a result, the resulting {@link ActionConfig}
  232        * will have two results.
  233        */
  234       protected synchronized RuntimeConfiguration buildRuntimeConfiguration() throws ConfigurationException {
  235           Map<String, Map<String, ActionConfig>> namespaceActionConfigs = new LinkedHashMap<String, Map<String, ActionConfig>>();
  236           Map<String, String> namespaceConfigs = new LinkedHashMap<String, String>();
  237   
  238           for (PackageConfig packageConfig : packageContexts.values()) {
  239   
  240               if (!packageConfig.isAbstract()) {
  241                   String namespace = packageConfig.getNamespace();
  242                   Map<String, ActionConfig> configs = namespaceActionConfigs.get(namespace);
  243   
  244                   if (configs == null) {
  245                       configs = new LinkedHashMap<String, ActionConfig>();
  246                   }
  247   
  248                   Map actionConfigs = packageConfig.getAllActionConfigs();
  249   
  250                   for (Object o : actionConfigs.keySet()) {
  251                       String actionName = (String) o;
  252                       ActionConfig baseConfig = (ActionConfig) actionConfigs.get(actionName);
  253                       configs.put(actionName, buildFullActionConfig(packageConfig, baseConfig));
  254                   }
  255                   
  256                   
  257                   
  258                   namespaceActionConfigs.put(namespace, configs);
  259                   if (packageConfig.getFullDefaultActionRef() != null) {
  260                       namespaceConfigs.put(namespace, packageConfig.getFullDefaultActionRef());
  261                   }
  262               }
  263           }
  264   
  265           return new RuntimeConfigurationImpl(namespaceActionConfigs, namespaceConfigs);
  266       }
  267   
  268       private void setDefaultResults(Map<String, ResultConfig> results, PackageConfig packageContext) {
  269           String defaultResult = packageContext.getFullDefaultResultType();
  270   
  271           for (Map.Entry<String, ResultConfig> entry : results.entrySet()) {
  272   
  273               if (entry.getValue() == null) {
  274                   ResultTypeConfig resultTypeConfig = packageContext.getAllResultTypeConfigs().get(defaultResult);
  275                   entry.setValue(new ResultConfig.Builder(null, resultTypeConfig.getClassName()).build());
  276               }
  277           }
  278       }
  279   
  280       /**
  281        * Builds the full runtime actionconfig with all of the defaults and inheritance
  282        *
  283        * @param packageContext the PackageConfig which holds the base config we're building from
  284        * @param baseConfig     the ActionConfig which holds only the configuration specific to itself, without the defaults
  285        *                       and inheritance
  286        * @return a full ActionConfig for runtime configuration with all of the inherited and default params
  287        * @throws com.opensymphony.xwork2.config.ConfigurationException
  288        *
  289        */
  290       private ActionConfig buildFullActionConfig(PackageConfig packageContext, ActionConfig baseConfig) throws ConfigurationException {
  291           Map<String, String> params = new TreeMap<String, String>(baseConfig.getParams());
  292           Map<String, ResultConfig> results = new TreeMap<String, ResultConfig>();
  293   
  294           if (!baseConfig.getPackageName().equals(packageContext.getName()) && packageContexts.containsKey(baseConfig.getPackageName())) {
  295               results.putAll(packageContexts.get(baseConfig.getPackageName()).getAllGlobalResults());
  296           } else {
  297               results.putAll(packageContext.getAllGlobalResults());
  298           }
  299   
  300          	results.putAll(baseConfig.getResults());
  301   
  302           setDefaultResults(results, packageContext);
  303   
  304           List<InterceptorMapping> interceptors = new ArrayList<InterceptorMapping>(baseConfig.getInterceptors());
  305   
  306           if (interceptors.size() <= 0) {
  307               String defaultInterceptorRefName = packageContext.getFullDefaultInterceptorRef();
  308   
  309               if (defaultInterceptorRefName != null) {
  310                   interceptors.addAll(InterceptorBuilder.constructInterceptorReference(new PackageConfig.Builder(packageContext), defaultInterceptorRefName,
  311                           new LinkedHashMap(), packageContext.getLocation(), objectFactory));
  312               }
  313           }
  314   
  315           
  316           
  317           ActionConfig config = new ActionConfig.Builder(baseConfig)
  318               .addParams(params)
  319               .addResultConfigs(results)
  320               .defaultClassName(packageContext.getDefaultClassRef())  // fill in default if non class has been provided
  321               .interceptors(interceptors)
  322               .addExceptionMappings(packageContext.getAllExceptionMappingConfigs())
  323               .build();
  324           
  325           return config;
  326       }
  327   
  328   
  329       private class RuntimeConfigurationImpl implements RuntimeConfiguration {
  330           private Map<String, Map<String, ActionConfig>> namespaceActionConfigs;
  331           private Map<String, ActionConfigMatcher> namespaceActionConfigMatchers;
  332           private NamespaceMatcher namespaceMatcher;
  333           private Map<String, String> namespaceConfigs;
  334   
  335           public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs, Map<String, String> namespaceConfigs) {
  336               this.namespaceActionConfigs = namespaceActionConfigs;
  337               this.namespaceConfigs = namespaceConfigs;
  338   
  339               PatternMatcher matcher = container.getInstance(PatternMatcher.class);
  340               
  341               this.namespaceActionConfigMatchers = new LinkedHashMap<String, ActionConfigMatcher>();
  342               this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet());
  343   
  344               for (String ns : namespaceActionConfigs.keySet()) {
  345                   namespaceActionConfigMatchers.put(ns,
  346                           new ActionConfigMatcher(matcher,
  347                                   namespaceActionConfigs.get(ns), true));
  348               }
  349           }
  350   
  351   
  352           /**
  353            * Gets the configuration information for an action name, or returns null if the
  354            * name is not recognized.
  355            *
  356            * @param name      the name of the action
  357            * @param namespace the namespace for the action or null for the empty namespace, ""
  358            * @return the configuration information for action requested
  359            */
  360           public synchronized ActionConfig getActionConfig(String namespace, String name) {
  361               ActionConfig config = findActionConfigInNamespace(namespace, name);
  362   
  363               // try wildcarded namespaces
  364               if (config == null) {
  365                   NamespaceMatch match = namespaceMatcher.match(namespace);
  366                   if (match != null) {
  367                       config = findActionConfigInNamespace(match.getPattern(), name);
  368   
  369                       // If config found, place all the matches found in the namespace processing in the action's parameters
  370                       if (config != null) {
  371                           config = new ActionConfig.Builder(config)
  372                                   .addParams(match.getVariables())
  373                                   .build();
  374                       }
  375                   }
  376               }
  377   
  378               // fail over to empty namespace
  379               if ((config == null) && (namespace != null) && (!namespace.trim().equals(""))) {
  380                   config = findActionConfigInNamespace("", name);
  381               }
  382   
  383   
  384               return config;
  385           }
  386   
  387           ActionConfig findActionConfigInNamespace(String namespace, String name) {
  388               ActionConfig config = null;
  389               if (namespace == null) {
  390                   namespace = "";
  391               }
  392               Map<String, ActionConfig> actions = namespaceActionConfigs.get(namespace);
  393               if (actions != null) {
  394                   config = actions.get(name);
  395                   // Check wildcards
  396                   if (config == null) {
  397                       config = namespaceActionConfigMatchers.get(namespace).match(name);
  398                       // fail over to default action
  399                       if (config == null) {
  400                           String defaultActionRef = namespaceConfigs.get(namespace);
  401                           if (defaultActionRef != null) {
  402                               config = actions.get(defaultActionRef);
  403                           }
  404                       }
  405                   }
  406               }
  407               return config;
  408           }
  409   
  410           /**
  411            * Gets the configuration settings for every action.
  412            *
  413            * @return a Map of namespace - > Map of ActionConfig objects, with the key being the action name
  414            */
  415           public synchronized Map getActionConfigs() {
  416               return namespaceActionConfigs;
  417           }
  418   
  419           public String toString() {
  420               StringBuffer buff = new StringBuffer("RuntimeConfiguration - actions are\n");
  421   
  422               for (String namespace : namespaceActionConfigs.keySet()) {
  423                   Map<String, ActionConfig> actionConfigs = namespaceActionConfigs.get(namespace);
  424   
  425                   for (String s : actionConfigs.keySet()) {
  426                       buff.append(namespace).append("/").append(s).append("\n");
  427                   }
  428               }
  429   
  430               return buff.toString();
  431           }
  432       }
  433       
  434       class ContainerProperties extends LocatableProperties {
  435           private static final long serialVersionUID = -7320625750836896089L;
  436   
  437           public Object setProperty(String key, String value) {
  438               String oldValue = getProperty(key);
  439               if (oldValue != null && !oldValue.equals(value) && !defaultFrameworkBeanName.equals(oldValue)) {
  440                   LOG.info("Overriding property "+key+" - old value: "+oldValue+" new value: "+value);
  441               }
  442               return super.setProperty(key, value);
  443           }
  444   
  445           public void setConstants(ContainerBuilder builder) {
  446               for (Object keyobj : keySet()) {
  447                   String key = (String)keyobj;
  448                   builder.factory(String.class, key, 
  449                           new LocatableConstantFactory<String>(getProperty(key), getPropertyLocation(key)));
  450               }
  451           }
  452       }
  453   }

Save This Page
Home » xwork-2.1.1-src » com.opensymphony.xwork2.config.impl » [javadoc | source]