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

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