Merge pull request #210 from lukaszlenart/jackson-xml

WW-4922: Jackson XML
diff --git a/core/src/main/java/com/opensymphony/xwork2/FileManager.java b/core/src/main/java/com/opensymphony/xwork2/FileManager.java
index c100923..8c70aa9 100644
--- a/core/src/main/java/com/opensymphony/xwork2/FileManager.java
+++ b/core/src/main/java/com/opensymphony/xwork2/FileManager.java
@@ -36,7 +36,7 @@
     void setReloadingConfigs(boolean reloadingConfigs);
 
     /**
-     * Checks if given file changed and must be reloaded if {@link #setReloadingConfigs(boolean)} is true
+     * Checks if given file changed and must be reloaded
      *
      * @param fileName to check
      * @return true if file changed
@@ -44,7 +44,7 @@
     boolean fileNeedsReloading(String fileName);
 
     /**
-     * Checks if file represented by provided URL should be reloaded
+     * Checks if file represented by provided URL changed and must be reloaded
      *
      * @param fileUrl url to a file
      * @return true if file exists and should be reloaded, if url is null return false
@@ -61,7 +61,7 @@
     InputStream loadFile(URL fileUrl);
 
     /**
-     * Adds file to list of monitored files if {@link #setReloadingConfigs(boolean)} is true
+     * Adds file to list of monitored files
      *
      * @param fileUrl {@link URL} to file to be monitored
      */
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/fs/JarEntryRevision.java b/core/src/main/java/com/opensymphony/xwork2/util/fs/JarEntryRevision.java
index dc5f0a7..a0fea58 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/fs/JarEntryRevision.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/fs/JarEntryRevision.java
@@ -37,7 +37,7 @@
     private long lastModified;
 
     public static Revision build(URL fileUrl, FileManager fileManager) {
-        JarURLConnection conn = null;
+        StrutsJarURLConnection conn = null;
         try {
             conn = StrutsJarURLConnection.openConnection(fileUrl);
             conn.setUseCaches(false);
@@ -70,7 +70,7 @@
     }
 
     public boolean needsReloading() {
-        JarURLConnection conn = null;
+        StrutsJarURLConnection conn = null;
         long lastLastModified = lastModified;
         try {
             conn = StrutsJarURLConnection.openConnection(jarFileURL);
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/fs/StrutsJarURLConnection.java b/core/src/main/java/com/opensymphony/xwork2/util/fs/StrutsJarURLConnection.java
index 8c1b71a..44a376a 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/fs/StrutsJarURLConnection.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/fs/StrutsJarURLConnection.java
@@ -20,34 +20,89 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.JarURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.net.URLDecoder;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
 /**
- * WW-4901 Decouples from underlying implementation of {@link URL#openConnection()}
+ * WW-4901 If was needed, decouples from underlying implementation of {@link URL#openConnection()}
  * e.g. from IBM WebSphere com.ibm.ws.classloader.Handler$ClassLoaderURLConnection
+ * WW-4920 Also decouples from and fixes {@link JarURLConnection#parseSpecs(URL)} if was needed
+ * e.g. from Oracle WebLogic which may report jar urls like "zip:C:/web-app-lib-path/some-jar.jar"
+ * but {@link JarURLConnection#parseSpecs(URL)} breaks on such urls
+ * While {@link JarURLConnection#parseSpecs(URL)} is private, then we had to extend {@link URLConnection} instead
  * @since 2.5.15
  */
-class StrutsJarURLConnection extends JarURLConnection {
-    private JarFile jarFile;
+class StrutsJarURLConnection extends URLConnection {
+    private static final String FILE_URL_PREFIX = "file:";
 
-    private StrutsJarURLConnection(URL url) throws MalformedURLException {
+    private JarURLConnection jarURLConnection;
+
+    private JarFile jarFile;
+    private String entryName;
+    private URL jarFileURL;
+
+    private StrutsJarURLConnection(URL url) throws IOException {
         super(url);
+
+        URLConnection conn = this.url.openConnection();
+        if (conn instanceof JarURLConnection) {//decoupling is not needed?
+            jarURLConnection = (JarURLConnection) conn;
+        } else {
+            try {
+                conn.getInputStream().close();
+            } catch (IOException ignored) {
+            }
+            parseSpecs(url);
+        }
     }
 
-    @Override
-    public JarFile getJarFile() throws IOException {
-        connect();
-        return jarFile;
+    /**
+    * A fixed copy of {@link JarURLConnection#parseSpecs(URL)}
+    */
+    private void parseSpecs(URL url) throws MalformedURLException, UnsupportedEncodingException {
+        String spec = url.getFile();
+
+        int separator = spec.indexOf("!/");
+        /*
+         * REMIND: we don't handle nested JAR URLs
+         */
+        if (separator == -1) {
+            throw new MalformedURLException("no !/ found in url spec:" + spec);
+        }
+
+        // start of fixing JarURLConnection#parseSpecs(URL) via handling MalformedURLException
+        String jarFileSpec = spec.substring(0, separator++);
+        try {
+            jarFileURL = new URL(jarFileSpec);
+        } catch (MalformedURLException e) {
+            // Probably no protocol in original jar URL, like "jar:C:/mypath/myjar.jar".
+            // This usually indicates that the jar file resides in the file system.
+            if (!jarFileSpec.startsWith("/")) {
+                jarFileSpec = "/" + jarFileSpec;
+            }
+            jarFileURL = new URL(FILE_URL_PREFIX + jarFileSpec);
+        }
+        // end of fix
+
+        entryName = null;
+
+        /* if ! is the last letter of the innerURL, entryName is null */
+        if (++separator != spec.length()) {
+            entryName = spec.substring(separator, spec.length());
+            entryName = URLDecoder.decode (entryName, "UTF-8");
+        }
     }
 
     @Override
@@ -56,7 +111,12 @@
             return;
         }
 
-        try (final InputStream in = getJarFileURL().openConnection().getInputStream()) {
+        if (jarURLConnection != null) {
+            connected = true;
+            return;
+        }
+
+        try (final InputStream in = jarFileURL.openConnection().getInputStream()) {
             jarFile = AccessController.doPrivileged(
                     new PrivilegedExceptionAction<JarFile>() {
                         public JarFile run() throws IOException {
@@ -84,19 +144,34 @@
         }
     }
 
-
-    static JarURLConnection openConnection(URL url) throws IOException {
-        URLConnection conn = url.openConnection();
-        if (conn instanceof JarURLConnection) {
-            return (JarURLConnection) conn;
+    JarEntry getJarEntry() throws IOException {
+        if (jarURLConnection != null) {
+            return jarURLConnection.getJarEntry();
         } else {
-            try {
-                conn.getInputStream().close();
-            } catch (IOException ignored) {
-            }
+            connect();
+            return jarFile.getJarEntry(entryName);
         }
+    }
 
-        StrutsJarURLConnection result = new StrutsJarURLConnection(url);
-        return result;
+    @Override
+    public void setUseCaches(boolean usecaches) {
+        super.setUseCaches(usecaches);
+
+        if (jarURLConnection != null) {
+            jarURLConnection.setUseCaches(usecaches);
+        }
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        if (jarURLConnection != null) {
+            return jarURLConnection.getInputStream();
+        } else {
+            return jarFile.getInputStream(jarFile.getJarEntry(entryName));
+        }
+    }
+
+    static StrutsJarURLConnection openConnection(URL url) throws IOException {
+        return new StrutsJarURLConnection(url);
     }
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java b/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
index 5fd4215..54a10b9 100644
--- a/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.java
@@ -23,6 +23,7 @@
 import com.opensymphony.xwork2.XWorkTestCase;
 import org.apache.commons.io.IOUtils;
 
+import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -67,6 +68,7 @@
         createJarFile(now);
         URL url = new URL("jar:file:target/JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class");
         Revision entry = JarEntryRevision.build(url, fileManager);
+        assert entry != null;
         assertFalse(entry.needsReloading());
 
         createJarFile(now + 60000);
@@ -81,6 +83,30 @@
                 "jar:file:target/JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
                 new ContainerProvidedURLStreamHandler());
         Revision entry = JarEntryRevision.build(url, fileManager);
+        assert entry != null;
+        assertFalse(entry.needsReloading());
+
+        createJarFile(now + 60000);
+        assertTrue(entry.needsReloading());
+    }
+
+    public void testNeedsReloadingWithContainerProvidedURLConnectionEmptyProtocol() throws Exception {
+        long now = System.currentTimeMillis();
+
+        createJarFile(now);
+        File targetDir = new File("target");
+        String targetUrlStr = targetDir.toURI().toURL().toString();
+        if (targetUrlStr.startsWith("file:")) {
+            targetUrlStr = targetUrlStr.substring(5);//emptying protocol; we expect framework will fix it
+        }
+        if (targetUrlStr.startsWith("/")) {
+            targetUrlStr = targetUrlStr.substring(1);//we expect framework will fix it also
+        }
+        URL url = new URL(null,
+                "zip:" + targetUrlStr + "JarEntryRevisionTest_testNeedsReloading.jar!/com/opensymphony/xwork2/util/fs/JarEntryRevisionTest.class",
+                new ContainerProvidedURLStreamHandler());
+        Revision entry = JarEntryRevision.build(url, fileManager);
+        assert entry != null;
         assertFalse(entry.needsReloading());
 
         createJarFile(now + 60000);
@@ -107,7 +133,7 @@
      */
     private class ContainerProvidedURLConnection extends URLConnection {
 
-        protected ContainerProvidedURLConnection(URL url) {
+        ContainerProvidedURLConnection(URL url) {
             super(url);
         }
 
diff --git a/plugins/jasperreports/pom.xml b/plugins/jasperreports/pom.xml
index e42ffa7..00b651d 100644
--- a/plugins/jasperreports/pom.xml
+++ b/plugins/jasperreports/pom.xml
@@ -49,6 +49,32 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.struts</groupId>
+            <artifactId>struts2-junit-plugin</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>jsp-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <properties>
     	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/plugins/jasperreports/src/main/java/org/apache/struts2/views/jasperreports/JasperReportsResult.java b/plugins/jasperreports/src/main/java/org/apache/struts2/views/jasperreports/JasperReportsResult.java
index 2424690..c79e1b6 100644
--- a/plugins/jasperreports/src/main/java/org/apache/struts2/views/jasperreports/JasperReportsResult.java
+++ b/plugins/jasperreports/src/main/java/org/apache/struts2/views/jasperreports/JasperReportsResult.java
@@ -384,7 +384,10 @@
             throw new ServletException(e.getMessage(), e);
         } finally {
             try {
-                conn.close();
+                if (conn != null) {
+                    // avoid NPE if connection was not used for the report
+                    conn.close();
+                }
             } catch (Exception e) {
                 LOG.warn("Could not close db connection properly", e);
             }
diff --git a/plugins/jasperreports/src/test/java/org/apache/struts2/views/jasperreports/JasperReportsResultTest.java b/plugins/jasperreports/src/test/java/org/apache/struts2/views/jasperreports/JasperReportsResultTest.java
new file mode 100644
index 0000000..1bf55ac
--- /dev/null
+++ b/plugins/jasperreports/src/test/java/org/apache/struts2/views/jasperreports/JasperReportsResultTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.struts2.views.jasperreports;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.mock.MockActionInvocation;
+import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import com.opensymphony.xwork2.util.ValueStack;
+import net.sf.jasperreports.engine.JasperCompileManager;
+import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.StrutsTestCase;
+import org.easymock.IAnswer;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+
+import java.net.URL;
+import java.sql.Connection;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+public class JasperReportsResultTest extends StrutsTestCase {
+    private MockActionInvocation invocation;
+    private ValueStack stack;
+
+    public void testConnClose() throws Exception {
+        JasperReportsResult result = new JasperReportsResult();
+        URL url = ClassLoaderUtil.getResource("org/apache/struts2/views/jasperreports/empty.jrxml", this.getClass());
+        JasperCompileManager.compileReportToFile(url.getFile(), url.getFile() + ".jasper");
+        result.setLocation("org/apache/struts2/views/jasperreports/empty.jrxml.jasper");
+        result.setFormat(JasperReportConstants.FORMAT_XML);
+
+        Connection connection = createMock(Connection.class);
+        final Boolean[] closed = {false};
+        connection.close();
+        expectLastCall().andAnswer(new IAnswer() {
+            @Override
+            public Object answer() throws Throwable {
+                closed[0] = true;
+                return null;
+            }
+        });
+        replay(connection);
+
+        stack.push(connection);
+        result.setConnection("top");
+
+        assertFalse(closed[0]);
+        result.execute(this.invocation);
+        verify(connection);
+        assertTrue(closed[0]);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        request.setRequestURI("http://sumeruri");
+        ActionContext context = ActionContext.getContext();
+        context.put(StrutsStatics.HTTP_RESPONSE, response);
+        context.put(StrutsStatics.HTTP_REQUEST, request);
+        this.stack = context.getValueStack();
+        MockServletContext servletContext = new MockServletContext();
+        context.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
+        this.invocation = new MockActionInvocation();
+        this.invocation.setInvocationContext(context);
+        this.invocation.setStack(this.stack);
+    }
+}
diff --git a/plugins/jasperreports/src/test/resources/org/apache/struts2/views/jasperreports/empty.jrxml b/plugins/jasperreports/src/test/resources/org/apache/struts2/views/jasperreports/empty.jrxml
new file mode 100644
index 0000000..816d860
--- /dev/null
+++ b/plugins/jasperreports/src/test/resources/org/apache/struts2/views/jasperreports/empty.jrxml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+-->
+<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="test" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e65f69ca-7c62-4b4b-abc6-2e1a8710f23e">
+</jasperReport>
\ No newline at end of file
diff --git a/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java b/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
index b39349d..9a917e3 100644
--- a/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
+++ b/plugins/junit/src/main/java/org/apache/struts2/StrutsJUnit4TestCase.java
@@ -37,6 +37,7 @@
 import org.springframework.core.io.DefaultResourceLoader;

 import org.springframework.mock.web.MockHttpServletRequest;

 import org.springframework.mock.web.MockHttpServletResponse;

+import org.springframework.mock.web.MockHttpSession;

 import org.springframework.mock.web.MockPageContext;

 import org.springframework.mock.web.MockServletContext;

 

@@ -155,10 +156,7 @@
         ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(

                 namespace, name, method, new HashMap<String, Object>(), true, false);

 

-        ActionContext invocationContext = proxy.getInvocation().getInvocationContext();

-        invocationContext.setParameters(HttpParameters.create(request.getParameterMap()).build());

-        // set the action context to the one used by the proxy

-        ActionContext.setContext(invocationContext);

+        initActionContext(proxy.getInvocation().getInvocationContext());

 

         // this is normally done in onSetUp(), but we are using Struts internal

         // objects (proxy and action invocation)

@@ -170,6 +168,20 @@
         return proxy;

     }

 

+    protected void initActionContext(ActionContext actionContext) {

+        actionContext.setParameters(HttpParameters.create(request.getParameterMap()).build());

+        initSession(actionContext);

+        // set the action context to the one used by the proxy

+        ActionContext.setContext(actionContext);

+    }

+

+    protected void initSession(ActionContext actionContext) {

+        if (actionContext.getSession() == null) {

+            actionContext.setSession(new HashMap<String, Object>());

+            request.setSession(new MockHttpSession(servletContext));

+        }

+    }

+

     /**

      * Finds an ActionMapping for a given request

      */

diff --git a/plugins/junit/src/test/java/org/apache/struts2/StrutsJUnit4TestCaseTest.java b/plugins/junit/src/test/java/org/apache/struts2/StrutsJUnit4TestCaseTest.java
index d3e0d15..8bc6915 100644
--- a/plugins/junit/src/test/java/org/apache/struts2/StrutsJUnit4TestCaseTest.java
+++ b/plugins/junit/src/test/java/org/apache/struts2/StrutsJUnit4TestCaseTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.struts2;
 
+import com.opensymphony.xwork2.ActionProxy;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -33,6 +34,13 @@
         Assert.assertEquals("Test-2", output);
     }
 
+    @Test
+    public void testSessionInitialized() throws Exception {
+        ActionProxy proxy = getActionProxy("/test/testAction-2.action");
+        Assert.assertNotNull("invocation session should being initialized",
+                proxy.getInvocation().getInvocationContext().getSession());
+    }
+
     @Override
     protected String getConfigPath() {
         return "struts-test.xml";
diff --git a/pom.xml b/pom.xml
index fbd9375..4476fde 100644
--- a/pom.xml
+++ b/pom.xml
@@ -311,12 +311,12 @@
                 <plugin>
                     <groupId>org.owasp</groupId>
                     <artifactId>dependency-check-maven</artifactId>
-                    <version>3.0.2</version>
+                    <version>3.1.1</version>
                     <configuration>
                         <suppressionFiles>
                             <suppressionFile>src/etc/project-suppression.xml</suppressionFile>
                         </suppressionFiles>
-                        <failBuildOnCVSS>8</failBuildOnCVSS>
+                        <failBuildOnCVSS>7</failBuildOnCVSS>
                         <skipProvidedScope>true</skipProvidedScope>
                         <skipRuntimeScope>true</skipRuntimeScope>
                     </configuration>
diff --git a/src/etc/project-suppression.xml b/src/etc/project-suppression.xml
index 2ef62e2..19454e3 100644
--- a/src/etc/project-suppression.xml
+++ b/src/etc/project-suppression.xml
@@ -22,16 +22,22 @@
         <notes><![CDATA[
         This suppresses false positives identified on Struts Annotations.
         ]]></notes>
-        <gav regex="true">org\.apache\.struts:struts\-annotations\:1\.0\.6</gav>
+        <gav regex="true">org\.apache\.struts:struts\-annotations\:1\.0\.6.*$</gav>
         <cpe>cpe:/a:apache:struts:1.0.6</cpe>
     </suppress>
     <suppress>
-        <notes><![CDATA[
-        This suppresses false positives identified on Struts 1.
-        ]]></notes>
-        <gav regex="true">org\.apache\.struts\:struts\-*:1\.3\.8</gav>
-        <cpe>cpe:/a:apache:struts:1.3.8</cpe>
-        <cpe>cpe:/a:apache:tiles:1.3.8</cpe>
-        <cpe>cpe:/a:apache:struts:1.3.8</cpe>
+        <notes><![CDATA[file name: struts-core-1.3.8.jar]]></notes>
+        <gav regex="true">^org\.apache\.struts:struts\-core\:1\.3\.8.*$</gav>
+        <cpe>cpe:/a:apache:struts</cpe>
+    </suppress>
+    <suppress>
+        <notes><![CDATA[file name: struts-tiles-1.3.8.jar]]></notes>
+        <gav regex="true">^org\.apache\.struts:struts\-tiles\:1\.3\.8.*$</gav>
+        <cpe>cpe:/a:apache:struts</cpe>
+    </suppress>
+    <suppress>
+        <notes><![CDATA[file name: struts-taglib-1.3.8.jar]]></notes>
+        <gav regex="true">^org\.apache\.struts:struts\-taglib\:1\.3\.8.*$</gav>
+        <cpe>cpe:/a:apache:struts</cpe>
     </suppress>
 </suppressions>
\ No newline at end of file