This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f7a50935 WW-5279 Improve readability of XmlConfigurationProvider class
     new 930c6de80 Merge pull request #657 from 
atlassian/WW-5279-xml-config-provider
2f7a50935 is described below

commit 2f7a50935bab9384df5da6d6270838646e70d635
Author: Kusal Kithul-Godage <g...@kusal.io>
AuthorDate: Tue Jan 31 03:02:24 2023 +1100

    WW-5279 Improve readability of XmlConfigurationProvider class
---
 .../config/providers/XmlConfigurationProvider.java | 993 ++++++++++-----------
 .../java/com/opensymphony/xwork2/inject/Scope.java |  24 +-
 .../config/StrutsXmlConfigurationProvider.java     |  14 +-
 3 files changed, 496 insertions(+), 535 deletions(-)

diff --git 
a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
 
b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
index 8d9699aae..8c980b724 100644
--- 
a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
+++ 
b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
@@ -44,7 +44,6 @@ import com.opensymphony.xwork2.inject.Scope;
 import com.opensymphony.xwork2.util.ClassLoaderUtil;
 import com.opensymphony.xwork2.util.ClassPathFinder;
 import com.opensymphony.xwork2.util.DomHelper;
-import com.opensymphony.xwork2.util.TextParseUtil;
 import com.opensymphony.xwork2.util.location.LocatableProperties;
 import com.opensymphony.xwork2.util.location.Location;
 import com.opensymphony.xwork2.util.location.LocationUtils;
@@ -75,6 +74,17 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.Vector;
+import java.util.function.Consumer;
+
+import static 
com.opensymphony.xwork2.util.TextParseUtil.commaDelimitedStringToSet;
+import static java.lang.Boolean.parseBoolean;
+import static java.lang.Character.isLowerCase;
+import static java.lang.Character.toUpperCase;
+import static java.lang.String.format;
+import static java.util.Collections.emptyList;
+import static org.apache.commons.lang3.StringUtils.defaultString;
+import static org.apache.commons.lang3.StringUtils.isNotEmpty;
+import static org.apache.commons.lang3.StringUtils.trimToNull;
 
 
 /**
@@ -164,13 +174,10 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         if (this == o) {
             return true;
         }
-
         if (!(o instanceof XmlConfigurationProvider)) {
             return false;
         }
-
-        final XmlConfigurationProvider xmlConfigurationProvider = 
(XmlConfigurationProvider) o;
-
+        XmlConfigurationProvider xmlConfigurationProvider = 
(XmlConfigurationProvider) o;
         return Objects.equals(configFileName, 
xmlConfigurationProvider.configFileName);
     }
 
@@ -179,6 +186,34 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         return ((configFileName != null) ? configFileName.hashCode() : 0);
     }
 
+    public static void iterateElementChildren(Document doc, Consumer<Element> 
function) {
+        iterateElementChildren(doc.getDocumentElement(), function);
+    }
+
+    public static void iterateElementChildren(Node node, Consumer<Element> 
function) {
+        iterateChildren(node, childNode -> {
+            if (!(childNode instanceof Element)) {
+                return;
+            }
+            function.accept((Element) childNode);
+        });
+    }
+
+    public static void iterateChildren(Node node, Consumer<Node> function) {
+        NodeList children = node.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            function.accept(children.item(i));
+        }
+    }
+
+    public static void iterateChildrenByTagName(Element el, String tagName, 
Consumer<Element> function) {
+        NodeList childrenByTag = el.getElementsByTagName(tagName);
+        for (int i = 0; i < childrenByTag.getLength(); i++) {
+            Element childEl = (Element) childrenByTag.item(i);
+            function.accept(childEl);
+        }
+    }
+
     private void loadDocuments(String configFileName) {
         try {
             loadedFileUrls.clear();
@@ -194,145 +229,129 @@ public abstract class XmlConfigurationProvider 
implements ConfigurationProvider
         LOG.trace("Parsing configuration file [{}]", configFileName);
         Map<String, Node> loadedBeans = new HashMap<>();
         for (Document doc : documents) {
-            Element rootElement = doc.getDocumentElement();
-            NodeList children = rootElement.getChildNodes();
-            int childSize = children.getLength();
-
-            for (int i = 0; i < childSize; i++) {
-                Node childNode = children.item(i);
-
-                if (childNode instanceof Element) {
-                    Element child = (Element) childNode;
-
-                    final String nodeName = child.getNodeName();
-
-                    if ("bean-selection".equals(nodeName)) {
-                        String name = child.getAttribute("name");
-                        String impl = child.getAttribute("class");
-                        try {
-                            Class classImpl = ClassLoaderUtil.loadClass(impl, 
getClass());
-                            if 
(BeanSelectionProvider.class.isAssignableFrom(classImpl)) {
-                                BeanSelectionProvider provider = 
(BeanSelectionProvider) classImpl.newInstance();
-                                provider.register(containerBuilder, props);
-                            } else {
-                                throw new ConfigurationException("The 
bean-provider: name:" + name + " class:" + impl + " does not implement " + 
BeanSelectionProvider.class.getName(), childNode);
-                            }
-                        } catch (ClassNotFoundException | 
IllegalAccessException | InstantiationException e) {
-                            throw new ConfigurationException("Unable to load 
bean-provider: name:" + name + " class:" + impl, e, childNode);
-                        }
-                    } else if ("bean".equals(nodeName)) {
-                        String type = child.getAttribute("type");
-                        String name = child.getAttribute("name");
-                        String impl = child.getAttribute("class");
-                        String onlyStatic = child.getAttribute("static");
-                        String scopeStr = child.getAttribute("scope");
-                        boolean optional = 
"true".equals(child.getAttribute("optional"));
-                        Scope scope;
-                        if ("prototype".equals(scopeStr)) {
-                            scope = Scope.PROTOTYPE;
-                        } else if ("request".equals(scopeStr)) {
-                            scope = Scope.REQUEST;
-                        } else if ("session".equals(scopeStr)) {
-                            scope = Scope.SESSION;
-                        } else if ("singleton".equals(scopeStr)) {
-                            scope = Scope.SINGLETON;
-                        } else if ("thread".equals(scopeStr)) {
-                            scope = Scope.THREAD;
-                        } else {
-                            scope = Scope.SINGLETON;
-                        }
-
-                        if (StringUtils.isEmpty(name)) {
-                            name = Container.DEFAULT_NAME;
-                        }
-
-                        try {
-                            Class classImpl = ClassLoaderUtil.loadClass(impl, 
getClass());
-                            Class classType = classImpl;
-                            if (StringUtils.isNotEmpty(type)) {
-                                classType = ClassLoaderUtil.loadClass(type, 
getClass());
-                            }
-                            if ("true".equals(onlyStatic)) {
-                                // Force loading of class to detect no class 
def found exceptions
-                                classImpl.getDeclaredClasses();
-                                containerBuilder.injectStatics(classImpl);
-                            } else {
-                                if (containerBuilder.contains(classType, 
name)) {
-                                    Location loc = 
LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
-                                    if (throwExceptionOnDuplicateBeans) {
-                                        throw new ConfigurationException("Bean 
type " + classType + " with the name " +
-                                                name + " has already been 
loaded by " + loc, child);
-                                    }
-                                }
-
-                                // Force loading of class to detect no class 
def found exceptions
-                                classImpl.getDeclaredConstructors();
-
-                                LOG.debug("Loaded type: {} name: {} impl: {}", 
type, name, impl);
-                                containerBuilder.factory(classType, name, new 
LocatableFactory(name, classType, classImpl, scope, childNode), scope);
-                            }
-                            loadedBeans.put(classType.getName() + name, child);
-                        } catch (Throwable ex) {
-                            if (!optional) {
-                                throw new ConfigurationException("Unable to 
load bean: type:" + type + " class:" + impl, ex, childNode);
-                            } else {
-                                LOG.debug("Unable to load optional class: {}", 
impl);
-                            }
-                        }
-                    } else if ("constant".equals(nodeName)) {
-                        String name = child.getAttribute("name");
-                        String value = child.getAttribute("value");
-
-                        if (valueSubstitutor != null) {
-                            LOG.debug("Substituting value [{}] using [{}]", 
value, valueSubstitutor.getClass().getName());
-                            value = valueSubstitutor.substitute(value);
-                        }
+            iterateElementChildren(doc, child -> {
+                switch (child.getNodeName()) {
+                    case "bean-selection": {
+                        registerBeanSelection(child, containerBuilder, props);
+                        break;
+                    }
+                    case "bean": {
+                        registerBean(child, loadedBeans, containerBuilder);
+                        break;
+                    }
+                    case "constant": {
+                        registerConstant(child, props);
+                        break;
+                    }
+                    case "unknown-handler-stack":
+                        registerUnknownHandlerStack(child);
+                        break;
+                }
+            });
+        }
+    }
 
-                        props.setProperty(name, value, childNode);
-                    } else if (nodeName.equals("unknown-handler-stack")) {
-                        List<UnknownHandlerConfig> unknownHandlerStack = new 
ArrayList<UnknownHandlerConfig>();
-                        NodeList unknownHandlers = 
child.getElementsByTagName("unknown-handler-ref");
-                        int unknownHandlersSize = unknownHandlers.getLength();
+    protected void registerBeanSelection(Element child, ContainerBuilder 
containerBuilder, LocatableProperties props) {
+        String name = child.getAttribute("name");
+        String impl = child.getAttribute("class");
+        try {
+            Class<?> classImpl = ClassLoaderUtil.loadClass(impl, getClass());
+            if (BeanSelectionProvider.class.isAssignableFrom(classImpl)) {
+                BeanSelectionProvider provider = (BeanSelectionProvider) 
classImpl.newInstance();
+                provider.register(containerBuilder, props);
+            } else {
+                throw new ConfigurationException(format("The bean-provider: 
name:%s class:%s does not implement %s", name, impl, 
BeanSelectionProvider.class.getName()), child);
+            }
+        } catch (ClassNotFoundException | IllegalAccessException | 
InstantiationException e) {
+            throw new ConfigurationException(format("Unable to load 
bean-provider: name:%s class:%s", name, impl), e, child);
+        }
+    }
 
-                        for (int k = 0; k < unknownHandlersSize; k++) {
-                            Element unknownHandler = (Element) 
unknownHandlers.item(k);
-                            Location location = 
LocationUtils.getLocation(unknownHandler);
-                            unknownHandlerStack.add(new 
UnknownHandlerConfig(unknownHandler.getAttribute("name"), location));
-                        }
+    protected void registerBean(Element child, Map<String, Node> loadedBeans, 
ContainerBuilder containerBuilder) {
+        String type = child.getAttribute("type");
+        String name = child.getAttribute("name");
+        String impl = child.getAttribute("class");
+        String onlyStatic = child.getAttribute("static");
+        String scopeStr = child.getAttribute("scope");
+        boolean optional = "true".equals(child.getAttribute("optional"));
+        Scope scope = Scope.fromString(scopeStr);
+
+        if (name.isEmpty()) {
+            name = Container.DEFAULT_NAME;
+        }
 
-                        if (!unknownHandlerStack.isEmpty())
-                            
configuration.setUnknownHandlerStack(unknownHandlerStack);
+        try {
+            Class<?> classImpl = ClassLoaderUtil.loadClass(impl, getClass());
+            Class<?> classType = classImpl;
+            if (!type.isEmpty()) {
+                classType = ClassLoaderUtil.loadClass(type, getClass());
+            }
+            if ("true".equals(onlyStatic)) {
+                // Force loading of class to detect no class def found 
exceptions
+                classImpl.getDeclaredClasses();
+                containerBuilder.injectStatics(classImpl);
+            } else {
+                if (containerBuilder.contains(classType, name)) {
+                    Location loc = 
LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
+                    if (throwExceptionOnDuplicateBeans) {
+                        throw new ConfigurationException(format("Bean type %s 
with the name %s has already been loaded by %s", classType, name, loc), child);
                     }
                 }
+
+                // Force loading of class to detect no class def found 
exceptions
+                classImpl.getDeclaredConstructors();
+
+                LOG.debug("Loaded type: {} name: {} impl: {}", type, name, 
impl);
+                containerBuilder.factory(classType, name, new 
LocatableFactory<>(name, classType, classImpl, scope, child), scope);
+            }
+            loadedBeans.put(classType.getName() + name, child);
+        } catch (Throwable ex) {
+            if (!optional) {
+                throw new ConfigurationException("Unable to load bean: type:" 
+ type + " class:" + impl, ex, child);
+            } else {
+                LOG.debug("Unable to load optional class: {}", impl);
             }
         }
     }
 
-    public void loadPackages() throws ConfigurationException {
-        List<Element> reloads = new ArrayList<Element>();
-        verifyPackageStructure();
+    protected void registerConstant(Element child, LocatableProperties props) {
+        String name = child.getAttribute("name");
+        String value = child.getAttribute("value");
 
-        for (Document doc : documents) {
-            Element rootElement = doc.getDocumentElement();
-            NodeList children = rootElement.getChildNodes();
-            int childSize = children.getLength();
+        if (valueSubstitutor != null) {
+            LOG.debug("Substituting value [{}] using [{}]", value, 
valueSubstitutor.getClass().getName());
+            value = valueSubstitutor.substitute(value);
+        }
 
-            for (int i = 0; i < childSize; i++) {
-                Node childNode = children.item(i);
+        props.setProperty(name, value, child);
+    }
 
-                if (childNode instanceof Element) {
-                    Element child = (Element) childNode;
+    protected void registerUnknownHandlerStack(Element child) {
+        List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<>();
 
-                    final String nodeName = child.getNodeName();
+        iterateChildrenByTagName(child, "unknown-handler-ref", unknownHandler 
-> {
+            Location location = LocationUtils.getLocation(unknownHandler);
+            unknownHandlerStack.add(new 
UnknownHandlerConfig(unknownHandler.getAttribute("name"), location));
+        });
 
-                    if ("package".equals(nodeName)) {
-                        PackageConfig cfg = addPackage(child);
-                        if (cfg.isNeedsRefresh()) {
-                            reloads.add(child);
-                        }
+        if (!unknownHandlerStack.isEmpty()) {
+            configuration.setUnknownHandlerStack(unknownHandlerStack);
+        }
+    }
+
+    public void loadPackages() throws ConfigurationException {
+        List<Element> reloads = new ArrayList<>();
+        verifyPackageStructure();
+
+        for (Document doc : documents) {
+            iterateElementChildren(doc, child -> {
+                if ("package".equals(child.getNodeName())) {
+                    PackageConfig cfg = addPackage(child);
+                    if (cfg.isNeedsRefresh()) {
+                        reloads.add(child);
                     }
                 }
-            }
+            });
             loadExtraConfiguration(doc);
         }
 
@@ -353,30 +372,21 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         DirectedGraph<String> graph = new DirectedGraph<>();
 
         for (Document doc : documents) {
-            Element rootElement = doc.getDocumentElement();
-            NodeList children = rootElement.getChildNodes();
-            int childSize = children.getLength();
-            for (int i = 0; i < childSize; i++) {
-                Node childNode = children.item(i);
-                if (childNode instanceof Element) {
-                    Element child = (Element) childNode;
-
-                    final String nodeName = child.getNodeName();
-
-                    if ("package".equals(nodeName)) {
-                        String packageName = child.getAttribute("name");
-                        declaredPackages.put(packageName, child);
-                        graph.addNode(packageName);
-
-                        String extendsAttribute = 
child.getAttribute("extends");
-                        List<String> parents = 
ConfigurationUtil.buildParentListFromString(extendsAttribute);
-                        for (String parent : parents) {
-                            graph.addNode(parent);
-                            graph.addEdge(packageName, parent);
-                        }
-                    }
+            iterateElementChildren(doc, child -> {
+                if (!"package".equals(child.getNodeName())) {
+                    return;
                 }
-            }
+
+                String packageName = child.getAttribute("name");
+                declaredPackages.put(packageName, child);
+                graph.addNode(packageName);
+
+                String extendsAttribute = child.getAttribute("extends");
+                for (String parent : 
ConfigurationUtil.buildParentListFromString(extendsAttribute)) {
+                    graph.addNode(parent);
+                    graph.addEdge(packageName, parent);
+                }
+            });
         }
 
         CycleDetector<String> detector = new CycleDetector<>(graph);
@@ -391,30 +401,27 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
     }
 
     private void reloadRequiredPackages(List<Element> reloads) {
-        if (reloads.size() > 0) {
-            List<Element> result = new ArrayList<>();
-            for (Element pkg : reloads) {
-                PackageConfig cfg = addPackage(pkg);
-                if (cfg.isNeedsRefresh()) {
-                    result.add(pkg);
-                }
-            }
-            if ((result.size() > 0) && (result.size() != reloads.size())) {
-                reloadRequiredPackages(result);
-                return;
+        if (reloads.isEmpty()) {
+            return;
+        }
+
+        List<Element> result = new ArrayList<>();
+        for (Element pkg : reloads) {
+            PackageConfig cfg = addPackage(pkg);
+            if (cfg.isNeedsRefresh()) {
+                result.add(pkg);
             }
+        }
+        if (!result.isEmpty() && result.size() != reloads.size()) {
+            reloadRequiredPackages(result);
+            return;
+        }
 
-            // Print out error messages for all misconfigured inheritance 
packages
-            if (result.size() > 0) {
-                for (Element rp : result) {
-                    String parent = rp.getAttribute("extends");
-                    if (parent != null) {
-                        List<PackageConfig> parents = 
ConfigurationUtil.buildParentsFromString(configuration, parent);
-                        if (parents != null && parents.size() <= 0) {
-                            LOG.error("Unable to find parent packages {}", 
parent);
-                        }
-                    }
-                }
+        // Print out error messages for all misconfigured inheritance packages
+        for (Element rp : result) {
+            String parent = rp.getAttribute("extends");
+            if (!parent.isEmpty() && 
ConfigurationUtil.buildParentsFromString(configuration, parent).isEmpty()) {
+                LOG.error("Unable to find parent packages {}", parent);
             }
         }
     }
@@ -426,7 +433,6 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
      * @return true if the file has been changed since the last time we read it
      */
     public boolean needsReload() {
-
         for (String url : loadedFileUrls) {
             if (fileManager.fileNeedsReloading(url)) {
                 return true;
@@ -439,28 +445,16 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         String name = actionElement.getAttribute("name");
         String className = actionElement.getAttribute("class");
         //methodName should be null if it's not set
-        String methodName = 
StringUtils.trimToNull(actionElement.getAttribute("method"));
+        String methodName = trimToNull(actionElement.getAttribute("method"));
         Location location = DomHelper.getLocationObject(actionElement);
 
         if (location == null) {
             LOG.warn("Location null for {}", className);
         }
 
-        // if there isn't a class name specified for an <action/> then try to
-        // use the default-class-ref from the <package/>
-        if (StringUtils.isEmpty(className)) {
-            // if there is a package default-class-ref use that, otherwise use 
action support
-           /* if (StringUtils.isNotEmpty(packageContext.getDefaultClassRef())) 
{
-                className = packageContext.getDefaultClassRef();
-            } else {
-                className = ActionSupport.class.getName();
-            }*/
-
-        } else {
-            if (!verifyAction(className, name, location)) {
-                LOG.error("Unable to verify action [{}] with class [{}], from 
[{}]", name, className, location);
-                return;
-            }
+        if (!className.isEmpty() && !verifyAction(className, name, location)) {
+            LOG.error("Unable to verify action [{}] with class [{}], from 
[{}]", name, className, location);
+            return;
         }
 
         Map<String, ResultConfig> results;
@@ -489,7 +483,7 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         packageContext.addActionConfig(name, actionConfig);
 
         LOG.debug("Loaded {}{} in '{}' package: {}",
-                StringUtils.isNotEmpty(packageContext.getNamespace()) ? 
(packageContext.getNamespace() + "/") : "",
+                isNotEmpty(packageContext.getNamespace()) ? 
(packageContext.getNamespace() + "/") : "",
                 name, packageContext.getName(), actionConfig);
     }
 
@@ -500,11 +494,11 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         }
         try {
             if (objectFactory.isNoArgConstructorRequired()) {
-                Class clazz = objectFactory.getClassInstance(className);
+                Class<?> clazz = objectFactory.getClassInstance(className);
                 if (!Modifier.isPublic(clazz.getModifiers())) {
                     throw new ConfigurationException("Action class [" + 
className + "] is not public", loc);
                 }
-                clazz.getConstructor(new Class[]{});
+                clazz.getConstructor();
             }
         } catch (ClassNotFoundException e) {
             LOG.debug("Class not found for action [{}]", className, e);
@@ -568,12 +562,7 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         loadGlobalExceptionMappings(newPackage, packageElement);
 
         // get actions
-        NodeList actionList = packageElement.getElementsByTagName("action");
-
-        for (int i = 0; i < actionList.getLength(); i++) {
-            Element actionElement = (Element) actionList.item(i);
-            addAction(actionElement, newPackage);
-        }
+        iterateChildrenByTagName(packageElement, "action", actionElement -> 
addAction(actionElement, newPackage));
 
         // load the default action reference for this package
         loadDefaultActionRef(newPackage, packageElement);
@@ -584,92 +573,82 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
     }
 
     protected void addResultTypes(PackageConfig.Builder packageContext, 
Element element) {
-        NodeList resultTypeList = element.getElementsByTagName("result-type");
-
-        for (int i = 0; i < resultTypeList.getLength(); i++) {
-            Element resultTypeElement = (Element) resultTypeList.item(i);
+        iterateChildrenByTagName(element, "result-type", resultTypeElement -> {
             String name = resultTypeElement.getAttribute("name");
             String className = resultTypeElement.getAttribute("class");
             String def = resultTypeElement.getAttribute("default");
 
             Location loc = DomHelper.getLocationObject(resultTypeElement);
 
-            Class clazz = verifyResultType(className, loc);
-            if (clazz != null) {
-                String paramName = null;
-                try {
-                    paramName = (String) 
clazz.getField("DEFAULT_PARAM").get(null);
-                } catch (Throwable t) {
-                    LOG.debug("The result type [{}] doesn't have a default 
param [DEFAULT_PARAM] defined!", className, t);
-                }
-                ResultTypeConfig.Builder resultType = new 
ResultTypeConfig.Builder(name, className).defaultResultParam(paramName)
-                        
.location(DomHelper.getLocationObject(resultTypeElement));
+            Class<?> clazz = verifyResultType(className, loc);
+            if (clazz == null) {
+                return;
+            }
+            String paramName = null;
+            try {
+                paramName = (String) clazz.getField("DEFAULT_PARAM").get(null);
+            } catch (Throwable t) {
+                LOG.debug("The result type [{}] doesn't have a default param 
[DEFAULT_PARAM] defined!", className, t);
+            }
+            ResultTypeConfig.Builder resultType = new 
ResultTypeConfig.Builder(name, className).defaultResultParam(paramName)
+                    .location(DomHelper.getLocationObject(resultTypeElement));
 
-                Map<String, String> params = 
XmlHelper.getParams(resultTypeElement);
+            Map<String, String> params = 
XmlHelper.getParams(resultTypeElement);
 
-                if (!params.isEmpty()) {
-                    resultType.addParams(params);
-                }
-                packageContext.addResultTypeConfig(resultType.build());
+            if (!params.isEmpty()) {
+                resultType.addParams(params);
+            }
+            packageContext.addResultTypeConfig(resultType.build());
 
-                // set the default result type
-                if (BooleanUtils.toBoolean(def)) {
-                    packageContext.defaultResultType(name);
-                }
+            // set the default result type
+            if (BooleanUtils.toBoolean(def)) {
+                packageContext.defaultResultType(name);
             }
-        }
+        });
     }
 
-    protected Class verifyResultType(String className, Location loc) {
+    protected Class<?> verifyResultType(String className, Location loc) {
         try {
             return objectFactory.getClassInstance(className);
         } catch (ClassNotFoundException | NoClassDefFoundError e) {
             LOG.warn("Result class [{}] doesn't exist ({}) at {}, ignoring", 
className, e.getClass().getSimpleName(), loc, e);
         }
-
         return null;
     }
 
     protected List<InterceptorMapping> buildInterceptorList(Element element, 
PackageConfig.Builder context) throws ConfigurationException {
         List<InterceptorMapping> interceptorList = new ArrayList<>();
-        NodeList interceptorRefList = 
element.getElementsByTagName("interceptor-ref");
-
-        for (int i = 0; i < interceptorRefList.getLength(); i++) {
-            Element interceptorRefElement = (Element) 
interceptorRefList.item(i);
 
-            if (interceptorRefElement.getParentNode().equals(element) || 
interceptorRefElement.getParentNode().getNodeName().equals(element.getNodeName()))
 {
-                List<InterceptorMapping> interceptors = 
lookupInterceptorReference(context, interceptorRefElement);
-                interceptorList.addAll(interceptors);
+        iterateChildrenByTagName(element, "interceptor-ref", 
interceptorRefElement -> {
+            Node parNode = interceptorRefElement.getParentNode();
+            if (!parNode.equals(element) && 
!parNode.getNodeName().equals(element.getNodeName())) {
+                return;
             }
-        }
+            List<InterceptorMapping> interceptors = 
lookupInterceptorReference(context, interceptorRefElement);
+            interceptorList.addAll(interceptors);
+        });
 
         return interceptorList;
     }
 
     /**
-     * <p>
-     * This method builds a package context by looking for the parents of this 
new package.
-     * </p>
-     *
-     * <p>
-     * If no parents are found, it will return a root package.
-     * </p>
+     * <p>This method builds a package context by looking for the parents of 
this new package.</p>
+     * <p>If no parents are found, it will return a root package.</p>
      *
      * @param packageElement the package element
-     *
      * @return the package config builder
      */
     protected PackageConfig.Builder buildPackageContext(Element 
packageElement) {
         String parent = packageElement.getAttribute("extends");
         String abstractVal = packageElement.getAttribute("abstract");
-        boolean isAbstract = Boolean.parseBoolean(abstractVal);
-        String name = 
StringUtils.defaultString(packageElement.getAttribute("name"));
-        String namespace = 
StringUtils.defaultString(packageElement.getAttribute("namespace"));
+        boolean isAbstract = parseBoolean(abstractVal);
+        String name = defaultString(packageElement.getAttribute("name"));
+        String namespace = 
defaultString(packageElement.getAttribute("namespace"));
 
-        // Strict DMI is enabled by default, it can disabled by user
+        // Strict DMI is enabled by default, it can be disabled by user
         boolean strictDMI = true;
         if (packageElement.hasAttribute("strict-method-invocation")) {
-            strictDMI = 
Boolean.parseBoolean(packageElement.getAttribute("strict-method-invocation"));
+            strictDMI = 
parseBoolean(packageElement.getAttribute("strict-method-invocation"));
         }
 
         PackageConfig.Builder cfg = new PackageConfig.Builder(name)
@@ -678,27 +657,30 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
                 .strictMethodInvocation(strictDMI)
                 .location(DomHelper.getLocationObject(packageElement));
 
-        if (StringUtils.isNotEmpty(StringUtils.defaultString(parent))) { // 
has parents, let's look it up
-            List<PackageConfig> parents = new ArrayList<>();
-            for (String parentPackageName : 
ConfigurationUtil.buildParentListFromString(parent)) {
-                if 
(configuration.getPackageConfigNames().contains(parentPackageName)) {
-                    
parents.add(configuration.getPackageConfig(parentPackageName));
-                } else if (declaredPackages.containsKey(parentPackageName)) {
-                    if (configuration.getPackageConfig(parentPackageName) == 
null) {
-                        addPackage(declaredPackages.get(parentPackageName));
-                    }
-                    
parents.add(configuration.getPackageConfig(parentPackageName));
-                } else {
-                    throw new ConfigurationException("Parent package is not 
defined: " + parentPackageName);
-                }
-
-            }
+        if (parent.isEmpty()) {
+            return cfg;
+        }
 
-            if (parents.size() <= 0) {
-                cfg.needsRefresh(true);
+        // has parents, let's look it up
+        List<PackageConfig> parents = new ArrayList<>();
+        for (String parentPackageName : 
ConfigurationUtil.buildParentListFromString(parent)) {
+            if 
(configuration.getPackageConfigNames().contains(parentPackageName)) {
+                parents.add(configuration.getPackageConfig(parentPackageName));
+            } else if (declaredPackages.containsKey(parentPackageName)) {
+                if (configuration.getPackageConfig(parentPackageName) == null) 
{
+                    addPackage(declaredPackages.get(parentPackageName));
+                }
+                parents.add(configuration.getPackageConfig(parentPackageName));
             } else {
-                cfg.addParents(parents);
+                throw new ConfigurationException("Parent package is not 
defined: " + parentPackageName);
             }
+
+        }
+
+        if (parents.isEmpty()) {
+            cfg.needsRefresh(true);
+        } else {
+            cfg.addParents(parents);
         }
 
         return cfg;
@@ -707,129 +689,125 @@ public abstract class XmlConfigurationProvider 
implements ConfigurationProvider
     /**
      * Build a map of ResultConfig objects from below a given XML element.
      *
-     * @param element the given XML element
+     * @param element        the given XML element
      * @param packageContext the package context
-     *
      * @return map of result config objects
      */
     protected Map<String, ResultConfig> buildResults(Element element, 
PackageConfig.Builder packageContext) {
-        NodeList resultEls = element.getElementsByTagName("result");
-
         Map<String, ResultConfig> results = new LinkedHashMap<>();
 
-        for (int i = 0; i < resultEls.getLength(); i++) {
-            Element resultElement = (Element) resultEls.item(i);
-
-            if (resultElement.getParentNode().equals(element) || 
resultElement.getParentNode().getNodeName().equals(element.getNodeName())) {
-                String resultName = resultElement.getAttribute("name");
-                String resultType = resultElement.getAttribute("type");
+        iterateChildrenByTagName(element, "result", resultElement -> {
+            Node parNode = resultElement.getParentNode();
+            if (!parNode.equals(element) && 
!parNode.getNodeName().equals(element.getNodeName())) {
+                return;
+            }
 
-                // if you don't specify a name on <result/>, it defaults to 
"success"
-                if (StringUtils.isEmpty(resultName)) {
-                    resultName = Action.SUCCESS;
-                }
+            String resultName = resultElement.getAttribute("name");
+            String resultType = resultElement.getAttribute("type");
 
-                // there is no result type, so let's inherit from the parent 
package
-                if (StringUtils.isEmpty(resultType)) {
-                    resultType = packageContext.getFullDefaultResultType();
+            // if you don't specify a name on <result/>, it defaults to 
"success"
+            if (StringUtils.isEmpty(resultName)) {
+                resultName = Action.SUCCESS;
+            }
 
-                    // now check if there is a result type now
-                    if (StringUtils.isEmpty(resultType)) {
-                        // uh-oh, we have a problem
-                        throw new ConfigurationException("No result type 
specified for result named '"
-                                + resultName + "', perhaps the parent package 
does not specify the result type?", resultElement);
-                    }
+            // there is no result type, so let's inherit from the parent 
package
+            if (resultType.isEmpty()) {
+                resultType = packageContext.getFullDefaultResultType();
+                // now check if there is a result type now
+                if (resultType.isEmpty()) {
+                    throw new ConfigurationException("No result type specified 
for result named '"
+                            + resultName + "', perhaps the parent package does 
not specify the result type?", resultElement);
                 }
+            }
 
+            ResultTypeConfig config = packageContext.getResultType(resultType);
+            if (config == null) {
+                throw new ConfigurationException(format("There is no result 
type defined for type '%s' mapped with name '%s'. Did you mean '%s'?", 
resultType, resultName, guessResultType(resultType)), resultElement);
+            }
 
-                ResultTypeConfig config = 
packageContext.getResultType(resultType);
+            String resultClass = config.getClassName();
+            if (resultClass == null) {
+                throw new ConfigurationException("Result type '" + resultType 
+ "' is invalid");
+            }
 
-                if (config == null) {
-                    throw new ConfigurationException("There is no result type 
defined for type '" + resultType
-                            + "' mapped with name '" + resultName + "'."
-                            + "  Did you mean '" + guessResultType(resultType) 
+ "'?", resultElement);
-                }
+            Map<String, String> params = buildResultParams(resultElement, 
config);
 
-                String resultClass = config.getClassName();
+            Set<String> resultNamesSet = commaDelimitedStringToSet(resultName);
+            if (resultNamesSet.isEmpty()) {
+                resultNamesSet.add(resultName);
+            }
 
-                // invalid result type specified in result definition
-                if (resultClass == null) {
-                    throw new ConfigurationException("Result type '" + 
resultType + "' is invalid");
-                }
+            for (String name : resultNamesSet) {
+                ResultConfig resultConfig = new ResultConfig.Builder(name, 
resultClass)
+                        .addParams(params)
+                        .location(DomHelper.getLocationObject(element))
+                        .build();
+                results.put(resultConfig.getName(), resultConfig);
+            }
+        });
+
+        return results;
+    }
 
-                Map<String, String> resultParams = 
XmlHelper.getParams(resultElement);
-
-                if (resultParams.size() == 0) // maybe we just have a body - 
therefore a default parameter
-                {
-                    // if <result ...>something</result> then we add a 
parameter of 'something' as this is the most used result param
-                    if (resultElement.getChildNodes().getLength() >= 1) {
-                        resultParams = new LinkedHashMap<>();
-
-                        String paramName = config.getDefaultResultParam();
-                        if (paramName != null) {
-                            StringBuilder paramValue = new StringBuilder();
-                            for (int j = 0; j < 
resultElement.getChildNodes().getLength(); j++) {
-                                if 
(resultElement.getChildNodes().item(j).getNodeType() == Node.TEXT_NODE) {
-                                    String val = 
resultElement.getChildNodes().item(j).getNodeValue();
-                                    if (val != null) {
-                                        paramValue.append(val);
-                                    }
-                                }
-                            }
-                            String val = paramValue.toString().trim();
-                            if (val.length() > 0) {
-                                resultParams.put(paramName, val);
-                            }
-                        } else {
-                            LOG.debug("No default parameter defined for result 
[{}] of type [{}] ", config.getName(), config.getClassName());
+    protected Map<String, String> buildResultParams(Element resultElement, 
ResultTypeConfig config) {
+        Map<String, String> resultParams = XmlHelper.getParams(resultElement);
+
+        // maybe we just have a body - therefore a default parameter
+        if (resultParams.isEmpty() && 
resultElement.getChildNodes().getLength() > 0) {
+            // if <result ...>something</result> then we add a parameter of 
'something' as this is the most used result param
+            resultParams = new LinkedHashMap<>();
+
+            String paramName = config.getDefaultResultParam();
+            if (paramName != null) {
+                StringBuilder paramValue = new StringBuilder();
+                iterateChildren(resultElement, child -> {
+                    if (child.getNodeType() == Node.TEXT_NODE) {
+                        String val = child.getNodeValue();
+                        if (val != null) {
+                            paramValue.append(val);
                         }
                     }
+                });
+                String val = paramValue.toString().trim();
+                if (val.length() > 0) {
+                    resultParams.put(paramName, val);
                 }
-
-                // create new param map, so that the result param can override 
the config param
-                Map<String, String> params = new LinkedHashMap<String, 
String>();
-                Map<String, String> configParams = config.getParams();
-                if (configParams != null) {
-                    params.putAll(configParams);
-                }
-                params.putAll(resultParams);
-
-                Set<String> resultNamesSet = 
TextParseUtil.commaDelimitedStringToSet(resultName);
-                if (resultNamesSet.isEmpty()) {
-                    resultNamesSet.add(resultName);
-                }
-
-                for (String name : resultNamesSet) {
-                    ResultConfig resultConfig = new ResultConfig.Builder(name, 
resultClass)
-                            .addParams(params)
-                            .location(DomHelper.getLocationObject(element))
-                            .build();
-                    results.put(resultConfig.getName(), resultConfig);
-                }
+            } else {
+                LOG.debug(
+                        "No default parameter defined for result [{}] of type 
[{}] ",
+                        config.getName(),
+                        config.getClassName());
             }
         }
 
-        return results;
+        // create new param map, so that the result param can override the 
config param
+        Map<String, String> params = new LinkedHashMap<>();
+        Map<String, String> configParams = config.getParams();
+        if (configParams != null) {
+            params.putAll(configParams);
+        }
+        params.putAll(resultParams);
+        return params;
     }
 
-    protected String guessResultType(String type) {
-        StringBuilder sb = null;
-        if (type != null) {
-            sb = new StringBuilder();
-            boolean capNext = false;
-            for (int x=0; x<type.length(); x++) {
-                char c = type.charAt(x);
-                if (c == '-') {
-                    capNext = true;
-                    continue;
-                } else if (Character.isLowerCase(c) && capNext) {
-                    c = Character.toUpperCase(c);
-                    capNext = false;
-                }
-                sb.append(c);
+    protected static String guessResultType(String type) {
+        if (type == null) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        boolean capNext = false;
+        for (int x = 0; x < type.length(); x++) {
+            char c = type.charAt(x);
+            if (c == '-') {
+                capNext = true;
+                continue;
+            } else if (isLowerCase(c) && capNext) {
+                c = toUpperCase(c);
+                capNext = false;
             }
+            sb.append(c);
         }
-        return (sb != null ? sb.toString() : null);
+        return sb.toString();
     }
 
     /**
@@ -841,31 +819,28 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
      * @return list of exception mapping config objects
      */
     protected List<ExceptionMappingConfig> buildExceptionMappings(Element 
element, PackageConfig.Builder packageContext) {
-        NodeList exceptionMappingEls = 
element.getElementsByTagName("exception-mapping");
-
         List<ExceptionMappingConfig> exceptionMappings = new ArrayList<>();
 
-        for (int i = 0; i < exceptionMappingEls.getLength(); i++) {
-            Element ehElement = (Element) exceptionMappingEls.item(i);
-
-            if (ehElement.getParentNode().equals(element) || 
ehElement.getParentNode().getNodeName().equals(element.getNodeName())) {
-                String emName = ehElement.getAttribute("name");
-                String exceptionClassName = 
ehElement.getAttribute("exception");
-                String exceptionResult = ehElement.getAttribute("result");
-
-                Map<String, String> params = XmlHelper.getParams(ehElement);
-
-                if (StringUtils.isEmpty(emName)) {
-                    emName = exceptionResult;
-                }
+        iterateChildrenByTagName(element, "exception-mapping", ehElement -> {
+            Node parNode = ehElement.getParentNode();
+            if (!parNode.equals(element) && 
!parNode.getNodeName().equals(element.getNodeName())) {
+                return;
+            }
 
-                ExceptionMappingConfig ehConfig = new 
ExceptionMappingConfig.Builder(emName, exceptionClassName, exceptionResult)
-                        .addParams(params)
-                        .location(DomHelper.getLocationObject(ehElement))
-                        .build();
-                exceptionMappings.add(ehConfig);
+            String emName = ehElement.getAttribute("name");
+            String exceptionClassName = ehElement.getAttribute("exception");
+            String exceptionResult = ehElement.getAttribute("result");
+            Map<String, String> params = XmlHelper.getParams(ehElement);
+            if (emName.isEmpty()) {
+                emName = exceptionResult;
             }
-        }
+
+            ExceptionMappingConfig ehConfig = new 
ExceptionMappingConfig.Builder(emName, exceptionClassName, exceptionResult)
+                    .addParams(params)
+                    .location(DomHelper.getLocationObject(ehElement))
+                    .build();
+            exceptionMappings.add(ehConfig);
+        });
 
         return exceptionMappings;
     }
@@ -878,26 +853,10 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
             // user defined 'allowed-methods' so used them whatever Strict DMI 
was enabled or not
             allowedMethods = new 
HashSet<>(packageContext.getGlobalAllowedMethods());
             // Fix for WW-5029 (concatenate all possible text node children)
-            final Node allowedMethodsNode = allowedMethodsEls.item(0);
-            if (allowedMethodsNode != null) {
-                final NodeList allowedMethodsChildren = 
allowedMethodsNode.getChildNodes();
-                final StringBuilder allowedMethodsSB = new StringBuilder();
-                for (int i = 0; i < allowedMethodsChildren.getLength(); i++) {
-                    Node allowedMethodsChildNode = 
allowedMethodsChildren.item(i);
-                    if (allowedMethodsChildNode != null && 
allowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
-                        String childNodeValue = 
allowedMethodsChildNode.getNodeValue();
-                        childNodeValue = (childNodeValue != null ? 
childNodeValue.trim() : "");
-                        if (childNodeValue.length() > 0) {
-                            allowedMethodsSB.append(childNodeValue);
-                        }
-                    }
-                }
-                if (allowedMethodsSB.length() > 0) {
-                    
allowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(allowedMethodsSB.toString()));
-                }
-            }
+            Node allowedMethodsNode = allowedMethodsEls.item(0);
+            addAllowedMethodsToSet(allowedMethodsNode, allowedMethods);
         } else if (packageContext.isStrictMethodInvocation()) {
-            // user enabled Strict DMI but didn't defined action specific 
'allowed-methods' so we use 'global-allowed-methods' only
+            // user enabled Strict DMI but didn't define action specific 
'allowed-methods' so we use 'global-allowed-methods' only
             allowedMethods = new 
HashSet<>(packageContext.getGlobalAllowedMethods());
         } else {
             // Strict DMI is disabled so any method can be called
@@ -929,7 +888,7 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
     }
 
     /**
-     * Load all of the global results for this package from the XML element.
+     * Load all the global results for this package from the XML element.
      *
      * @param packageContext the package context
      * @param packageElement the given XML element
@@ -950,25 +909,28 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
         if (globalAllowedMethodsElms.getLength() > 0) {
             Set<String> globalAllowedMethods = new HashSet<>();
             // Fix for WW-5029 (concatenate all possible text node children)
-            Node globaAllowedMethodsNode = globalAllowedMethodsElms.item(0);
-            if (globaAllowedMethodsNode != null) {
-                NodeList globaAllowedMethodsChildren = 
globaAllowedMethodsNode.getChildNodes();
-                final StringBuilder globalAllowedMethodsSB = new 
StringBuilder();
-                for (int i = 0; i < globaAllowedMethodsChildren.getLength(); 
i++) {
-                    Node globalAllowedMethodsChildNode = 
globaAllowedMethodsChildren.item(i);
-                    if (globalAllowedMethodsChildNode != null && 
globalAllowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
-                        String childNodeValue = 
globalAllowedMethodsChildNode.getNodeValue();
-                        childNodeValue = (childNodeValue != null ? 
childNodeValue.trim() : "");
-                        if (childNodeValue.length() > 0) {
-                            globalAllowedMethodsSB.append(childNodeValue);
-                        }
-                    }
-                }
-                if (globalAllowedMethodsSB.length() > 0) {
-                    
globalAllowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(globalAllowedMethodsSB.toString()));
+            Node globalAllowedMethodsNode = globalAllowedMethodsElms.item(0);
+            addAllowedMethodsToSet(globalAllowedMethodsNode, 
globalAllowedMethods);
+            packageContext.addGlobalAllowedMethods(globalAllowedMethods);
+        }
+    }
+
+    protected static void addAllowedMethodsToSet(Node allowedMethodsNode, 
Set<String> allowedMethodsSet) {
+        if (allowedMethodsNode == null) {
+            return;
+        }
+        StringBuilder allowedMethodsSB = new StringBuilder();
+        iterateChildren(allowedMethodsNode, allowedMethodsChildNode -> {
+            if (allowedMethodsChildNode != null && 
allowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
+                String childNodeValue = allowedMethodsChildNode.getNodeValue();
+                childNodeValue = (childNodeValue != null ? 
childNodeValue.trim() : "");
+                if (childNodeValue.length() > 0) {
+                    allowedMethodsSB.append(childNodeValue);
                 }
             }
-            packageContext.addGlobalAllowedMethods(globalAllowedMethods);
+        });
+        if (allowedMethodsSB.length() > 0) {
+            
allowedMethodsSet.addAll(commaDelimitedStringToSet(allowedMethodsSB.toString()));
         }
     }
 
@@ -981,7 +943,7 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
     }
 
     /**
-     * Load all of the global results for this package from the XML element.
+     * Load all the global results for this package from the XML element.
      *
      * @param packageContext the package context
      * @param packageElement the given XML element
@@ -998,37 +960,26 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
 
     protected InterceptorStackConfig loadInterceptorStack(Element element, 
PackageConfig.Builder context) throws ConfigurationException {
         String name = element.getAttribute("name");
-
         InterceptorStackConfig.Builder config = new 
InterceptorStackConfig.Builder(name)
                 .location(DomHelper.getLocationObject(element));
-        NodeList interceptorRefList = 
element.getElementsByTagName("interceptor-ref");
 
-        for (int j = 0; j < interceptorRefList.getLength(); j++) {
-            Element interceptorRefElement = (Element) 
interceptorRefList.item(j);
+        iterateChildrenByTagName(element, "interceptor-ref", 
interceptorRefElement -> {
             List<InterceptorMapping> interceptors = 
lookupInterceptorReference(context, interceptorRefElement);
             config.addInterceptors(interceptors);
-        }
+        });
 
         return config.build();
     }
 
     protected void loadInterceptorStacks(Element element, 
PackageConfig.Builder context) throws ConfigurationException {
-        NodeList interceptorStackList = 
element.getElementsByTagName("interceptor-stack");
-
-        for (int i = 0; i < interceptorStackList.getLength(); i++) {
-            Element interceptorStackElement = (Element) 
interceptorStackList.item(i);
-
+        iterateChildrenByTagName(element, "interceptor-stack", 
interceptorStackElement -> {
             InterceptorStackConfig config = 
loadInterceptorStack(interceptorStackElement, context);
-
             context.addInterceptorStackConfig(config);
-        }
+        });
     }
 
     protected void loadInterceptors(PackageConfig.Builder context, Element 
element) throws ConfigurationException {
-        NodeList interceptorList = element.getElementsByTagName("interceptor");
-
-        for (int i = 0; i < interceptorList.getLength(); i++) {
-            Element interceptorElement = (Element) interceptorList.item(i);
+        iterateChildrenByTagName(element, "interceptor", interceptorElement -> 
{
             String name = interceptorElement.getAttribute("name");
             String className = interceptorElement.getAttribute("class");
 
@@ -1039,109 +990,103 @@ public abstract class XmlConfigurationProvider 
implements ConfigurationProvider
                     .build();
 
             context.addInterceptorConfig(config);
-        }
+        });
 
         loadInterceptorStacks(element, context);
     }
 
     private List<Document> loadConfigurationFiles(String fileName, Element 
includeElement) {
-        List<Document> docs = new ArrayList<>();
-        List<Document> finalDocs = new ArrayList<>();
-        if (!includedFileNames.contains(fileName)) {
-            LOG.debug("Loading action configurations from: {}", fileName);
+        if (includedFileNames.contains(fileName)) {
+            return emptyList();
+        }
+        LOG.debug("Loading action configurations from: {}", fileName);
+        includedFileNames.add(fileName);
 
-            includedFileNames.add(fileName);
+        Iterator<URL> urls = getURLs(fileName);
+        if (urls == null) {
+            return emptyList();
+        }
 
-            Iterator<URL> urls = null;
-            InputStream is = null;
+        List<Document> docs = getDocs(urls, fileName, includeElement);
+        List<Document> finalDocs = getFinalDocs(docs);
+        LOG.debug("Loaded action configuration from: {}", fileName);
+        return finalDocs;
+    }
 
-            IOException ioException = null;
-            try {
-                urls = getConfigurationUrls(fileName);
-            } catch (IOException ex) {
-                ioException = ex;
-            }
+    private Iterator<URL> getURLs(String fileName) {
+        Iterator<URL> urls = null;
+        try {
+            urls = getConfigurationUrls(fileName);
+        } catch (IOException ex) {
+            LOG.debug("Ignoring file that does not exist: " + fileName, ex);
+        }
+        if (urls != null && !urls.hasNext()) {
+            LOG.debug("Ignoring file that has no URLs: " + fileName);
+            urls = null;
+        }
+        return urls;
+    }
 
-            if (urls == null || !urls.hasNext()) {
-                LOG.debug("Ignoring file that does not exist: " + fileName, 
ioException);
-                return docs;
-            }
+    private List<Document> getDocs(Iterator<URL> urls, String fileName, 
Element includeElement) {
+        List<Document> docs = new ArrayList<>();
 
+        while (urls.hasNext()) {
+            InputStream is = null;
             URL url = null;
-            while (urls.hasNext()) {
-                try {
-                    url = urls.next();
-                    is = fileManager.loadFile(url);
-
-                    InputSource in = new InputSource(is);
-
-                    in.setSystemId(url.toString());
-                    
-                    Document helperDoc = DomHelper.parse(in, dtdMappings);
-                    if (helperDoc != null) {
-                        docs.add(helperDoc);
-                    }
-                    
-                    loadedFileUrls.add(url.toString());
-                } catch (StrutsException e) {
-                    if (includeElement != null) {
-                        throw new ConfigurationException("Unable to load " + 
url, e, includeElement);
-                    } else {
-                        throw new ConfigurationException("Unable to load " + 
url, e);
-                    }
-                } catch (Exception e) {
-                    throw new ConfigurationException("Caught exception while 
loading file " + fileName, e, includeElement);
-                } finally {
-                    if (is != null) {
-                        try {
-                            is.close();
-                        } catch (IOException e) {
-                            LOG.error("Unable to close input stream", e);
-                        }
+            try {
+                url = urls.next();
+                is = fileManager.loadFile(url);
+                InputSource in = new InputSource(is);
+                in.setSystemId(url.toString());
+                Document helperDoc = DomHelper.parse(in, dtdMappings);
+                if (helperDoc != null) {
+                    docs.add(helperDoc);
+                }
+                loadedFileUrls.add(url.toString());
+            } catch (StrutsException e) {
+                if (includeElement != null) {
+                    throw new ConfigurationException("Unable to load " + url, 
e, includeElement);
+                } else {
+                    throw new ConfigurationException("Unable to load " + url, 
e);
+                }
+            } catch (Exception e) {
+                throw new ConfigurationException("Caught exception while 
loading file " + fileName, e, includeElement);
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                        LOG.error("Unable to close input stream", e);
                     }
                 }
             }
+        }
+        return docs;
+    }
 
-            //sort the documents, according to the "order" attribute
-            Collections.sort(docs, new Comparator<Document>() {
-                public int compare(Document doc1, Document doc2) {
-                    return 
XmlHelper.getLoadOrder(doc1).compareTo(XmlHelper.getLoadOrder(doc2));
+    private List<Document> getFinalDocs(List<Document> docs) {
+        List<Document> finalDocs = new ArrayList<>();
+        docs.sort(Comparator.comparing(XmlHelper::getLoadOrder));
+        for (Document doc : docs) {
+            iterateElementChildren(doc, child -> {
+                if (!"include".equals(child.getNodeName())) {
+                    return;
                 }
-            });
 
-            for (Document doc : docs) {
-                Element rootElement = doc.getDocumentElement();
-                NodeList children = rootElement.getChildNodes();
-                int childSize = children.getLength();
-
-                for (int i = 0; i < childSize; i++) {
-                    Node childNode = children.item(i);
-
-                    if (childNode instanceof Element) {
-                        Element child = (Element) childNode;
-
-                        final String nodeName = child.getNodeName();
-
-                        if ("include".equals(nodeName)) {
-                            String includeFileName = 
child.getAttribute("file");
-                            if (includeFileName.indexOf('*') != -1) {
-                                // handleWildCardIncludes(includeFileName, 
docs, child);
-                                ClassPathFinder wildcardFinder = new 
ClassPathFinder();
-                                wildcardFinder.setPattern(includeFileName);
-                                Vector<String> wildcardMatches = 
wildcardFinder.findMatches();
-                                for (String match : wildcardMatches) {
-                                    
finalDocs.addAll(loadConfigurationFiles(match, child));
-                                }
-                            } else {
-                                
finalDocs.addAll(loadConfigurationFiles(includeFileName, child));
-                            }
-                        }
-                    }
+                String includeFileName = child.getAttribute("file");
+                if (includeFileName.indexOf('*') == -1) {
+                    finalDocs.addAll(loadConfigurationFiles(includeFileName, 
child));
+                    return;
                 }
-                finalDocs.add(doc);
-            }
-
-            LOG.debug("Loaded action configuration from: {}", fileName);
+                // handleWildCardIncludes(includeFileName, docs, child);
+                ClassPathFinder wildcardFinder = new ClassPathFinder();
+                wildcardFinder.setPattern(includeFileName);
+                Vector<String> wildcardMatches = wildcardFinder.findMatches();
+                for (String match : wildcardMatches) {
+                    finalDocs.addAll(loadConfigurationFiles(match, child));
+                }
+            });
+            finalDocs.add(doc);
         }
         return finalDocs;
     }
@@ -1163,7 +1108,7 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
      * Looks up the Interceptor Class from the interceptor-ref name and 
creates an instance, which is added to the
      * provided List, or, if this is a ref to a stack, it adds the Interceptor 
instances from the List to this stack.
      *
-     * @param context               The PackageConfig to lookup the 
interceptor from
+     * @param context               The PackageConfig to look up the 
interceptor from
      * @param interceptorRefElement Element to pull interceptor ref data from
      * @return A list of Interceptor objects
      * @throws ConfigurationException in case of configuration errors
@@ -1182,8 +1127,6 @@ public abstract class XmlConfigurationProvider implements 
ConfigurationProvider
 
     @Override
     public String toString() {
-        return "XmlConfigurationProvider{" +
-                "configFileName='" + configFileName + '\'' +
-                '}';
+        return format("XmlConfigurationProvider{configFileName='%s'}", 
configFileName);
     }
 }
diff --git a/core/src/main/java/com/opensymphony/xwork2/inject/Scope.java 
b/core/src/main/java/com/opensymphony/xwork2/inject/Scope.java
index 3974d6c8b..8f74b3a76 100644
--- a/core/src/main/java/com/opensymphony/xwork2/inject/Scope.java
+++ b/core/src/main/java/com/opensymphony/xwork2/inject/Scope.java
@@ -201,11 +201,25 @@ public enum Scope {
 
     <T> Callable<? extends T> toCallable(final InternalContext context,
                                          final InternalFactory<? extends T> 
factory) {
-        return new Callable<T>() {
-            public T call() throws Exception {
-                return 
InitializableFactory.wrapIfNeeded(factory).create(context);
-            }
-        };
+        return (Callable<T>) () -> 
InitializableFactory.wrapIfNeeded(factory).create(context);
+    }
+
+    public static Scope fromString(String scopeStr) {
+        switch (scopeStr) {
+            case "prototype":
+                return Scope.PROTOTYPE;
+            case "request":
+                return Scope.REQUEST;
+            case "session":
+                return Scope.SESSION;
+            case "thread":
+                return Scope.THREAD;
+            case "wizard":
+                return Scope.WIZARD;
+            case "singleton":
+            default:
+                return Scope.SINGLETON;
+        }
     }
 
     /**
diff --git 
a/core/src/main/java/org/apache/struts2/config/StrutsXmlConfigurationProvider.java
 
b/core/src/main/java/org/apache/struts2/config/StrutsXmlConfigurationProvider.java
index 168a9224b..f7f469420 100644
--- 
a/core/src/main/java/org/apache/struts2/config/StrutsXmlConfigurationProvider.java
+++ 
b/core/src/main/java/org/apache/struts2/config/StrutsXmlConfigurationProvider.java
@@ -33,7 +33,11 @@ import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Override Xwork class so we can use an arbitrary config file
@@ -42,9 +46,9 @@ public class StrutsXmlConfigurationProvider extends 
XmlConfigurationProvider {
 
     private static final Logger LOG = 
LogManager.getLogger(StrutsXmlConfigurationProvider.class);
     private File baseDir = null;
-    private String filename;
-    private String reloadKey;
-    private ServletContext servletContext;
+    private final String filename;
+    private final String reloadKey;
+    private final ServletContext servletContext;
 
     /**
      * Constructs the configuration provider
@@ -77,7 +81,7 @@ public class StrutsXmlConfigurationProvider extends 
XmlConfigurationProvider {
         this.servletContext = ctx;
         this.filename = filename;
         reloadKey = "configurationReload-" + filename;
-        Map<String,String> dtdMappings = new 
HashMap<String,String>(getDtdMappings());
+        Map<String,String> dtdMappings = new HashMap<>(getDtdMappings());
         dtdMappings.put("-//Apache Software Foundation//DTD Struts 
Configuration 2.0//EN", "struts-2.0.dtd");
         dtdMappings.put("-//Apache Software Foundation//DTD Struts 
Configuration 2.1//EN", "struts-2.1.dtd");
         dtdMappings.put("-//Apache Software Foundation//DTD Struts 
Configuration 2.1.7//EN", "struts-2.1.7.dtd");

Reply via email to