Struts 2
  1. Struts 2
  2. WW-3487

The plugin can't find the actions if the war embeded in an ear.

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.2.1
    • Fix Version/s: 2.3.12
    • Component/s: Plugin - Convention
    • Labels:
      None
    • Environment:

      JBoss 5.1

      Description

      If I deploy an ear that contains a war, the plugin can't find the actions under JBoss 5.1. If I only deploy the war everything is fine. Tha actions defined in struts.xml works perfectly in both cases. I did some investigation, and i think the problem is in the method org.apache.struts2.convention.PackageBasedActionConfigBuilder.findActions.

      1. struts2.ear
        2.68 MB
        Böszörményi Péter
      2. struts2-src.tar.gz
        1 kB
        Böszörményi Péter

        Activity

        Hide
        Böszörményi Péter added a comment -

        Simple testcase that show the problem.

        Deploy it into a JBoss 5.1, then open http://localhost:8080/struts2/simple.action.
        Expected result: "Simple" string both in the browser, and the JBoss's log.
        Actual result: "Simple" string in the browser, and nothing in the log.

        Show
        Böszörményi Péter added a comment - Simple testcase that show the problem. Deploy it into a JBoss 5.1, then open http://localhost:8080/struts2/simple.action . Expected result: "Simple" string both in the browser, and the JBoss's log. Actual result: "Simple" string in the browser, and nothing in the log.
        Hide
        Vignesh Manickam Periaswamy added a comment - - edited

        I am facing this same issue and did more investigation to trace the problem. Initially I thought the problem could be that PackageBasedActionConfigBuilder.findActions() is not able to trace the WAR when it is deployed inside an EAR. But I was wrong and the real problem is related to the WAR's protocol recognized as "vfsfile" protocol. I am not part of the Struts developer group but I tried by best to learn internals of Struts and hope my troubeshooting could help resolve the issue.

        I am using Struts 2.2.1.1 on JBoss 5.1. I have configured the below constant in struts.xml as I am using JBoss.
        <constant name="struts.convention.action.fileProtocols" value="jar,vfsfile,vfszip" />

        My troubleshooting involved 3 scenarios based on the way the WAR is deployed. Cases 1 & 2 WAR is deployed inside WAR; exploded and packaged respectively, investigate where the failure happens. Case 3 WAR is deployed directly without EAR, shows why it works correctly without the issues in Cases 1 & 2.

        Case 1: EAR containing a WAR deployed as exploded
        ==========================================

        Step (1): [Detecting the WAR] In URLSet.includeClassesUrl() method (invoked at PackageBasedActionConfigBuilder.buildUrlSet() line: 418), rootUrlEnumeration returns vfsfile:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war/WEB-INF/classes and after truncating "WEB-INF/classes", the WAR's url is vfsfile:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war. Please note that the WAR's protocol is "vfsfile" and not "vfszip", though it is an archive (exploded in my case).
        Step (2): [Converting protocol] The url conversion from "vfsfile" to "file" protocol fails because the URLUtil.isJBoss5Url(URL) method considers only "vfszip" and "vfsmemory" protocols. The WAR is included as it is with "vfsfile" protocol.
        Step (3): [Built URL set] The URL of the WAR is included to the UrlSet passed as argument to the constructor of ClassFinder (at PackageBasedActionConfigBuilder.findActions() line: 377).
        Step (4): [Finding actions] While trying to add all classNames in the WAR file (at ClassFinder.<init>() line: 144) the util method jar(URL) again tries convert "vfsfile" to "file" protocol and returns null. Henceforth the classNames are returned as an empty list.

        And so, the plugin can't find the actions, though it tried looking into the WAR.

        I also tried altering the value "vfsfile" protocol to "vfszip" in the debugger (to skip the vfsfile problem), but ClassFinder.jar(JarInputStream) fails while recognizing WAR as a JAR.

        Case 2: EAR containing a WAR deployed as package
        =========================================

        Step (1): rootUrlEnumeration returns vfszip:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war/WEB-INF/classes as opposted to "vfsfile" protocol in Case 1.
        Step (2): The WAR's protocol is "vfszip", the url is successfully converted to "file" protocol as opposed to Case 1. (file:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war)
        Step (3): Same as Case 1.
        Step (4): As the protocol is "file", it checks if the file is a JAR and at JarURLConnection.getJarFile() gets a java.io.FileNotFoundException: C:_server\jboss-eap-5.1\jboss-as\server\MyServer\deploy\MyTest.ear\MyWeb.war (The system cannot find the path specified), as it is directly pointing to a file inside an archive in the file system. It catches the exception and calls the util method file(URL), but returns no classes.

        Case 3: WAR deployed directly
        ========================

        Step (1): rootUrlEnumeration returns vfszip:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyWeb.war/WEB-INF/classes.
        Step (2): Same as Case 2. (file:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyWeb.war)
        Step (3): Same as Case 1.
        Step (4): As the protocol is "file", it checks if the file is a JAR and JarURLConnection.getJarFile() gets the JAR file without any FileNotFoundException. The util jar(URL) returns all the class names in the WAR file!

        Summary:
        ========
        The issue in Case 1 when compared with Case 3 is the failure of conversion from "vfsfile" protocol of the WAR to "file" protocol (support for exploded WAR).
        The issue in Case 2 when compared with Case 3 is the FileNotFoundException while referencing to the WAR inside an EAR archive in the file system.

        I think both the issues need to be addressed for the bug to be resolved.

        Please correct me if my assumptions about the source code are wrong.

        Show
        Vignesh Manickam Periaswamy added a comment - - edited I am facing this same issue and did more investigation to trace the problem. Initially I thought the problem could be that PackageBasedActionConfigBuilder.findActions() is not able to trace the WAR when it is deployed inside an EAR. But I was wrong and the real problem is related to the WAR's protocol recognized as "vfsfile" protocol. I am not part of the Struts developer group but I tried by best to learn internals of Struts and hope my troubeshooting could help resolve the issue. I am using Struts 2.2.1.1 on JBoss 5.1. I have configured the below constant in struts.xml as I am using JBoss. <constant name="struts.convention.action.fileProtocols" value="jar,vfsfile,vfszip" /> My troubleshooting involved 3 scenarios based on the way the WAR is deployed. Cases 1 & 2 WAR is deployed inside WAR; exploded and packaged respectively, investigate where the failure happens. Case 3 WAR is deployed directly without EAR, shows why it works correctly without the issues in Cases 1 & 2. Case 1: EAR containing a WAR deployed as exploded ========================================== Step (1): [Detecting the WAR] In URLSet.includeClassesUrl() method (invoked at PackageBasedActionConfigBuilder.buildUrlSet() line: 418), rootUrlEnumeration returns vfsfile:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war/WEB-INF/classes and after truncating "WEB-INF/classes", the WAR's url is vfsfile:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war. Please note that the WAR's protocol is "vfsfile" and not "vfszip", though it is an archive (exploded in my case). Step (2): [Converting protocol] The url conversion from "vfsfile" to "file" protocol fails because the URLUtil.isJBoss5Url(URL) method considers only "vfszip" and "vfsmemory" protocols. The WAR is included as it is with "vfsfile" protocol. Step (3): [Built URL set] The URL of the WAR is included to the UrlSet passed as argument to the constructor of ClassFinder (at PackageBasedActionConfigBuilder.findActions() line: 377). Step (4): [Finding actions] While trying to add all classNames in the WAR file (at ClassFinder.<init>() line: 144) the util method jar(URL) again tries convert "vfsfile" to "file" protocol and returns null. Henceforth the classNames are returned as an empty list. And so, the plugin can't find the actions, though it tried looking into the WAR. I also tried altering the value "vfsfile" protocol to "vfszip" in the debugger (to skip the vfsfile problem), but ClassFinder.jar(JarInputStream) fails while recognizing WAR as a JAR. Case 2: EAR containing a WAR deployed as package ========================================= Step (1): rootUrlEnumeration returns vfszip:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war/WEB-INF/classes as opposted to "vfsfile" protocol in Case 1. Step (2): The WAR's protocol is "vfszip", the url is successfully converted to "file" protocol as opposed to Case 1. ( file:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyTest.ear/MyWeb.war ) Step (3): Same as Case 1. Step (4): As the protocol is "file", it checks if the file is a JAR and at JarURLConnection.getJarFile() gets a java.io.FileNotFoundException: C:_server\jboss-eap-5.1\jboss-as\server\MyServer\deploy\MyTest.ear\MyWeb.war (The system cannot find the path specified), as it is directly pointing to a file inside an archive in the file system. It catches the exception and calls the util method file(URL), but returns no classes. Case 3: WAR deployed directly ======================== Step (1): rootUrlEnumeration returns vfszip:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyWeb.war/WEB-INF/classes. Step (2): Same as Case 2. ( file:/C:/_server/jboss-eap-5.1/jboss-as/server/MyServer/deploy/MyWeb.war ) Step (3): Same as Case 1. Step (4): As the protocol is "file", it checks if the file is a JAR and JarURLConnection.getJarFile() gets the JAR file without any FileNotFoundException. The util jar(URL) returns all the class names in the WAR file! Summary: ======== The issue in Case 1 when compared with Case 3 is the failure of conversion from "vfsfile" protocol of the WAR to "file" protocol (support for exploded WAR). The issue in Case 2 when compared with Case 3 is the FileNotFoundException while referencing to the WAR inside an EAR archive in the file system. I think both the issues need to be addressed for the bug to be resolved. Please correct me if my assumptions about the source code are wrong.
        Hide
        John Liptak added a comment -

        For a very long discussion of the problem, see https://jira.springsource.org/browse/SPR-5120

        My total hack workaround, since I am always using Spring, was to change findActions to the following:
        @SuppressWarnings("unchecked")
        protected Set<Class> findActions() {
        Set<Class> classes = new HashSet<Class>();
        try {
        if (actionPackages != null || (packageLocators != null && !disablePackageLocatorsScanning))

        { // By default, ClassFinder scans EVERY class in the specified // url set, which can produce spurious warnings for non-action // classes that can't be loaded. We pass a package filter that // only considers classes that match the action packages // specified by the user Test<String> classPackageTest = getClassPackageTest(); UrlSet s = buildUrlSet(); List<URL> urls = s.getUrls(); addSpringUrls(urls); ClassFinder finder = new ClassFinder(getClassLoaderInterface(), urls, true, this.fileProtocols, classPackageTest); Test<ClassFinder.ClassInfo> test = getActionClassTest(); classes.addAll(finder.findClasses(test)); }

        } catch (Exception ex)

        { if (LOG.isErrorEnabled()) LOG.error("Unable to scan named packages", ex); }

        return classes;
        }

        private void addSpringUrls(List<URL> urls) {
        try {
        PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
        Resource[] resources = scanner.getResources("classpath:/*");
        Set<String> contexts = new HashSet<String>();
        for(Resource r : resources) {
        String description = r.getDescription();
        if(description.contains("FileHandler"))

        { /** * parse out the context from something that looks like this: * FileHandler@24227094[path=WEB-INF/classes/com/qwest/cloud/view context=file:/C:/programs/Red%20Hat/EnterprisePlatform-5.1.0/jboss-eap-5.1/jboss-as/server/default/tmp/a2165f-6gzykk-gkjxxod8-1-gkjy3coe-aa/helloWeb.war/ real=file:/C:/programs/Red%20Hat/EnterprisePlatform-5.1.0/jboss-eap-5.1/jboss-as/server/default/tmp/a2165f-6gzykk-gkjxxod8-1-gkjy3coe-aa/helloWeb.war/WEB-INF/classes/com/qwest/cloud/view/] */ String context = description.substring(description.indexOf("context=")+8, description.indexOf(" real=")); contexts.add(context); }

        }
        for(String context : contexts)

        { urls.add(new URL(context + "WEB-INF/classes/")); }

        } catch (Exception e)

        { LOG.error("didn't load spring URL",e); }

        }

        Show
        John Liptak added a comment - For a very long discussion of the problem, see https://jira.springsource.org/browse/SPR-5120 My total hack workaround, since I am always using Spring, was to change findActions to the following: @SuppressWarnings("unchecked") protected Set<Class> findActions() { Set<Class> classes = new HashSet<Class>(); try { if (actionPackages != null || (packageLocators != null && !disablePackageLocatorsScanning)) { // By default, ClassFinder scans EVERY class in the specified // url set, which can produce spurious warnings for non-action // classes that can't be loaded. We pass a package filter that // only considers classes that match the action packages // specified by the user Test<String> classPackageTest = getClassPackageTest(); UrlSet s = buildUrlSet(); List<URL> urls = s.getUrls(); addSpringUrls(urls); ClassFinder finder = new ClassFinder(getClassLoaderInterface(), urls, true, this.fileProtocols, classPackageTest); Test<ClassFinder.ClassInfo> test = getActionClassTest(); classes.addAll(finder.findClasses(test)); } } catch (Exception ex) { if (LOG.isErrorEnabled()) LOG.error("Unable to scan named packages", ex); } return classes; } private void addSpringUrls(List<URL> urls) { try { PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver(); Resource[] resources = scanner.getResources("classpath:/*"); Set<String> contexts = new HashSet<String>(); for(Resource r : resources) { String description = r.getDescription(); if(description.contains("FileHandler")) { /** * parse out the context from something that looks like this: * FileHandler@24227094[path=WEB-INF/classes/com/qwest/cloud/view context=file:/C:/programs/Red%20Hat/EnterprisePlatform-5.1.0/jboss-eap-5.1/jboss-as/server/default/tmp/a2165f-6gzykk-gkjxxod8-1-gkjy3coe-aa/helloWeb.war/ real=file:/C:/programs/Red%20Hat/EnterprisePlatform-5.1.0/jboss-eap-5.1/jboss-as/server/default/tmp/a2165f-6gzykk-gkjxxod8-1-gkjy3coe-aa/helloWeb.war/WEB-INF/classes/com/qwest/cloud/view/] */ String context = description.substring(description.indexOf("context=")+8, description.indexOf(" real=")); contexts.add(context); } } for(String context : contexts) { urls.add(new URL(context + "WEB-INF/classes/")); } } catch (Exception e) { LOG.error("didn't load spring URL",e); } }
        Hide
        Lukasz Lenart added a comment -

        Did you try the latest snapshot version ? Looks like this issue should be already solved.

        Show
        Lukasz Lenart added a comment - Did you try the latest snapshot version ? Looks like this issue should be already solved.
        Hide
        Lukasz Lenart added a comment -

        Already solved with 2.3.12

        Show
        Lukasz Lenart added a comment - Already solved with 2.3.12

          People

          • Assignee:
            Lukasz Lenart
            Reporter:
            Böszörményi Péter
          • Votes:
            3 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development