FileDocCategorySizeDatePackage
ClasspathConfigurationProvider.javaAPI DocExample20299Mon Jul 23 13:26:54 BST 2007org.apache.struts2.config

ClasspathConfigurationProvider

public class ClasspathConfigurationProvider extends Object implements com.opensymphony.xwork2.config.ConfigurationProvider
ClasspathConfigurationProvider loads the configuration by scanning the classpath or selected packages for Action classes.

This provider is only invoked if one or more action packages are passed to the dispatcher, usually from the web.xml. Configurations are created for objects that either implement Action or have classnames that end with "Action".

Fields Summary
private static final String
DEFAULT_PAGE_PREFIX
The default page prefix (or "path"). Some applications may place pages under "/WEB-INF" as an extreme security precaution.
private String
defaultPagePrefix
The default page prefix (none).
private static final String
DEFAULT_PAGE_EXTENSION
The default page extension, to use in place of ".jsp".
private String
defaultPageExtension
The defacto default page extension, usually associated with JavaServer Pages.
private static final String
DEFAULT_PARENT_PACKAGE
A setting to indicate a custom default parent package, to use in place of "struts-default".
private String
defaultParentPackage
Name of the framework's default configuration package, that application configuration packages automatically inherit.
private static final String
FORCE_LOWER_CASE
The default page prefix (or "path"). Some applications may place pages under "/WEB-INF" as an extreme security precaution.
private boolean
forceLowerCase
Whether to use a lowercase letter as the initial letter of an action. If false, actions will retain the initial uppercase letter from the Action class. (view.action (true) versus View.action (false)).
private static final String
ACTION
Default suffix that can be used to indicate POJO "Action" classes.
private PageLocator
pageLocator
Helper class to scan class path for server pages.
private boolean
initialized
Flag to indicate the packages have been loaded.
private String[]
packages
The list of packages to scan for Action classes.
private Map
loadedPackageConfigs
The package configurations for scanned Actions.
private static final Log
LOG
Logging instance for this class.
private com.opensymphony.xwork2.config.Configuration
configuration
The XWork Configuration for this application.
Constructors Summary
public ClasspathConfigurationProvider(String[] pkgs)
Create instance utilizing a list of packages to scan for Action classes.

param
pkgs List of pacaktges to scan for Action Classes.


                               
       
        this.packages = pkgs;
    
Methods Summary
public voiddestroy()
Default destructor. Override to provide behavior.


    
public voidinit(com.opensymphony.xwork2.config.Configuration config)
Register this application's configuration.

param
config The configuration for this application.

        this.configuration = config;
    
protected com.opensymphony.xwork2.config.entities.PackageConfigloadPackageConfig(java.lang.String actionNamespace, java.lang.String actionPackage, java.lang.Class actionClass)
Finds or creates the package configuration for an Action class. The namespace annotation is honored, if found, and the namespace is checked for a parent configuration.

param
actionNamespace The configuration namespace
param
actionPackage The Java package containing our Action classes
param
actionClass The Action class instance
return
PackageConfig object for the Action class

        PackageConfig parent = null;

        if (actionClass != null) {
            Namespace ns = (Namespace) actionClass.getAnnotation(Namespace.class);
            if (ns != null) {
                parent = loadPackageConfig(actionNamespace, actionPackage, null);
                actionNamespace = ns.value();
                actionPackage = actionClass.getName();
            }
        }

        PackageConfig pkgConfig = loadedPackageConfigs.get(actionPackage);
        if (pkgConfig == null) {
            pkgConfig = new PackageConfig();
            pkgConfig.setName(actionPackage);

            if (parent == null) {
                parent = configuration.getPackageConfig(defaultParentPackage);
            }

            if (parent == null) {
                throw new ConfigurationException("ClasspathConfigurationProvider: Unable to locate default parent package: " +
                        defaultParentPackage);
            }
            pkgConfig.addParent(parent);

            pkgConfig.setNamespace(actionNamespace);

            loadedPackageConfigs.put(actionPackage, pkgConfig);
        }
        return pkgConfig;
    
public voidloadPackages()
Clears and loads the list of packages registered at construction.

throws
ConfigurationException

        loadedPackageConfigs.clear();
        loadPackages(packages);
        initialized = true;
    
protected voidloadPackages(java.lang.String[] pkgs)
Scan a list of packages for Action classes. This method loads classes that implement the Action interface or have a class name that ends with the letters "Action".

param
pkgs A list of packages to load
see
#processActionClass


        ResolverUtil<Class> resolver = new ResolverUtil<Class>();
        resolver.find(new Test() {
            // Match Action implementations and classes ending with "Action"
            public boolean matches(Class type) {
                // TODO: should also find annotated classes
                return (Action.class.isAssignableFrom(type) ||
                        type.getSimpleName().endsWith("Action"));
            }

        }, pkgs);

        Set<? extends Class<? extends Class>> actionClasses = resolver.getClasses();
        for (Object obj : actionClasses) {
           Class cls = (Class) obj;
           if (!Modifier.isAbstract(cls.getModifiers())) {
               processActionClass(cls, pkgs);
           }
        }

        for (String key : loadedPackageConfigs.keySet()) {
            configuration.addPackageConfig(key, loadedPackageConfigs.get(key));
        }
    
public booleanneedsReload()
Indicates whether the packages have been initialized.

return
True if the packages have been initialized

        return !initialized;
    
protected voidprocessActionClass(java.lang.Class cls, java.lang.String[] pkgs)
Create a default action mapping for a class instance. The namespace annotation is honored, if found, otherwise the Java package is converted into the namespace by changing the dots (".") to slashes ("/").

param
cls Action or POJO instance to process
param
pkgs List of packages that were scanned for Actions

        String name = cls.getName();
        String actionPackage = cls.getPackage().getName();
        String actionNamespace = null;
        String actionName = null;
        for (String pkg : pkgs) {
            if (name.startsWith(pkg)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("ClasspathConfigurationProvider: Processing class "+name);
                }
                name = name.substring(pkg.length() + 1);

                actionNamespace = "";
                actionName = name;
                int pos = name.lastIndexOf('.");
                if (pos > -1) {
                    actionNamespace = "/" + name.substring(0, pos).replace('.",'/");
                    actionName = name.substring(pos+1);
                }
                break;
            }
        }

        PackageConfig pkgConfig = loadPackageConfig(actionNamespace, actionPackage, cls);

        // In case the package changed due to namespace annotation processing
        if (!actionPackage.equals(pkgConfig.getName())) {
            actionPackage = pkgConfig.getName();
        }

        Annotation annotation = cls.getAnnotation(ParentPackage.class);
        if (annotation != null) {
            String parent = ((ParentPackage)annotation).value();
            PackageConfig parentPkg = configuration.getPackageConfig(parent);
            if (parentPkg == null) {
                throw new ConfigurationException("ClasspathConfigurationProvider: Unable to locate parent package "+parent, annotation);
            }
            pkgConfig.addParent(parentPkg);

            if (!TextUtils.stringSet(pkgConfig.getNamespace()) && TextUtils.stringSet(parentPkg.getNamespace())) {
                pkgConfig.setNamespace(parentPkg.getNamespace());
            }
        }

        // Truncate Action suffix if found
        if (actionName.endsWith(ACTION)) {
            actionName = actionName.substring(0, actionName.length() - ACTION.length());
        }

        // Force initial letter of action to lowercase, if desired
        if ((forceLowerCase) && (actionName.length() > 1)) {
            int lowerPos = actionName.lastIndexOf('/") + 1;
            StringBuilder sb = new StringBuilder();
            sb.append(actionName.substring(0, lowerPos));
            sb.append(Character.toLowerCase(actionName.charAt(lowerPos)));
            sb.append(actionName.substring(lowerPos + 1));
            actionName = sb.toString();
        }

        ActionConfig actionConfig = new ActionConfig();
        actionConfig.setClassName(cls.getName());
        actionConfig.setPackageName(actionPackage);

        actionConfig.setResults(new ResultMap<String,ResultConfig>(cls, actionName, pkgConfig));
        pkgConfig.addActionConfig(actionName, actionConfig);
    
public voidregister(com.opensymphony.xwork2.inject.ContainerBuilder builder, com.opensymphony.xwork2.util.location.LocatableProperties props)

        // Override to provide functionality
    
public voidsetDefaultPageExtension(java.lang.String defaultPageExtension)
Register a default page extension to use when locating pages.

param
defaultPageExtension the new defaultPageExtension

        this.defaultPageExtension = defaultPageExtension;
    
public voidsetDefaultPagePrefix(java.lang.String defaultPagePrefix)
Reigster a default page prefix to use when locating pages.

param
defaultPagePrefix the defaultPagePrefix to set

        this.defaultPagePrefix = defaultPagePrefix;
    
public voidsetDefaultParentPackage(java.lang.String defaultParentPackage)
Register a default parent package for the actions.

param
defaultParentPackage the new defaultParentPackage

        this.defaultParentPackage = defaultParentPackage;
    
public voidsetForceLowerCase(java.lang.String force)
Whether to use a lowercase letter as the initial letter of an action.

param
force If false, actions will retain the initial uppercase letter from the Action class. (view.action (true) versus View.action (false)).

        this.forceLowerCase = "true".equals(force);
    
public voidsetPageLocator(org.apache.struts2.config.ClasspathConfigurationProvider$PageLocator locator)
Register a PageLocation to use to scan for server pages.

param
locator

        this.pageLocator = locator;