mirror of
https://github.com/apache/struts.git
synced 2026-08-10 00:57:04 +00:00
Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 941d88d115 | |||
| 8c4a90f6e3 | |||
| 16c2948f1a | |||
| 58a76162a6 | |||
| b5e802174a | |||
| cdb70e6bed | |||
| 1380802b75 | |||
| 253d8558e5 | |||
| a97ee9e9cb | |||
| 23969abc19 | |||
| 2707bf0489 | |||
| 74d4e23716 | |||
| 2a03047e9e | |||
| b1c1be6e40 | |||
| 6536dc65d8 | |||
| 915386816b | |||
| 80c2de9e92 | |||
| b62e583646 | |||
| 8b359383a1 | |||
| 11e716f979 | |||
| 71c7064f29 | |||
| 09472808aa | |||
| d119ba8e13 | |||
| 86b45e96fc | |||
| 3c9465b857 | |||
| 0c73cf2e05 | |||
| 6785997412 | |||
| 5a7fce066f | |||
| 4fbada4cd9 | |||
| 15bbf0ef1d | |||
| 3119eb65db | |||
| de3dabbe44 | |||
| 82f7904206 | |||
| 42e3da550f | |||
| f3cb89202d | |||
| 836a27692e | |||
| 6312572331 | |||
| e7db7ade62 | |||
| b77c2f476a | |||
| e6c1cec7f8 | |||
| a781b5a27b | |||
| b71732fa14 | |||
| 3f79d64e6a | |||
| 039fd9f4ee | |||
| 393d5be50c | |||
| 24e279b165 | |||
| cb59974903 | |||
| ecfdee137d | |||
| 8c37b1523f | |||
| 62b83021a2 | |||
| f3f2d52a1c | |||
| 61ded9a3e7 | |||
| 963b473e6c | |||
| d639b59f6d | |||
| 8e468a368e | |||
| ebe1b80ed2 | |||
| 957292ecdb | |||
| 06290cef91 | |||
| a6a4529503 | |||
| 64d054221f | |||
| dc4e403d30 | |||
| e6bc93daf2 | |||
| 0e4d5962e1 | |||
| 69102e9075 | |||
| 1c2b491a27 | |||
| 5af840b160 | |||
| b6b74a46ea | |||
| fc2aebd10a | |||
| ba041e1ee6 | |||
| 0c3534e8b4 | |||
| 9a2996f9b7 | |||
| 3825229f44 | |||
| 4b3ee53f93 |
+1
-1
@@ -14,5 +14,5 @@
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
dist: trusty
|
||||
dist: jammy
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- oraclejdk9
|
||||
- oraclejdk11
|
||||
- openjdk11
|
||||
- openjdk17
|
||||
|
||||
install: true
|
||||
|
||||
@@ -13,8 +13,8 @@ global:
|
||||
- secure: iI7IpfDtS+LUyS2yNuRCR3KelNyvBHuoMQ3gb1UNmR5SSL7jO/p3olQWrQROs28FJ+dpE3lHyIjoHrebKQGJHHAgTG2XWxn+G3fDsf+wSSFSLoDGj0o2SgGXooBbR2dccnNZHCyQaOyE2cIPWaOxrQZFE4No70LQB4mrP/gdkoc=
|
||||
matrix:
|
||||
include:
|
||||
- jdk: oraclejdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 9 and 11 tests prospered
|
||||
- jdk: openjdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 11 and 17 tests prospered
|
||||
|
||||
script:
|
||||
- if [ "$STRUTS_IT" == "true" ]; then
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<web-app id="starter" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Struts 2 Rest Example</display-name>
|
||||
|
||||
|
||||
<!-- Filters -->
|
||||
<!-- START SNIPPET: filter -->
|
||||
<filter>
|
||||
|
||||
+14
-7
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -121,6 +121,11 @@
|
||||
<artifactId>log4j-jcl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>opensymphony</groupId>
|
||||
@@ -150,9 +155,9 @@
|
||||
|
||||
<!-- BeanValidation Example -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.1.2.Final</version>
|
||||
<version>${hibernate-validator.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@@ -167,6 +172,9 @@
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
</includes>
|
||||
<systemPropertyVariables>
|
||||
<http.port>8090</http.port>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -191,15 +199,14 @@
|
||||
<stopKey>CTRL+C</stopKey>
|
||||
<stopPort>8999</stopPort>
|
||||
<systemProperties>
|
||||
<systemProperty>
|
||||
<name>log4j.configuration</name>
|
||||
<value>file:${basedir}/src/main/resources/log4j2.xml</value>
|
||||
</systemProperty>
|
||||
<systemProperty>
|
||||
<name>slf4j</name>
|
||||
<value>false</value>
|
||||
</systemProperty>
|
||||
</systemProperties>
|
||||
<httpConnector>
|
||||
<port>8090</port>
|
||||
</httpConnector>
|
||||
<scanIntervalSeconds>10</scanIntervalSeconds>
|
||||
<webAppSourceDirectory>${basedir}/src/main/webapp/</webAppSourceDirectory>
|
||||
<webAppConfig>
|
||||
|
||||
+158
-171
@@ -22,16 +22,13 @@ package org.apache.struts2.showcase.source;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.action.ServletContextAware;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -42,202 +39,192 @@ import java.util.List;
|
||||
*/
|
||||
public class ViewSourceAction extends ActionSupport implements ServletContextAware {
|
||||
|
||||
private String page;
|
||||
private String className;
|
||||
private String config;
|
||||
private String page;
|
||||
private String className;
|
||||
private String config;
|
||||
|
||||
private List pageLines;
|
||||
private List classLines;
|
||||
private List configLines;
|
||||
private List<String> pageLines;
|
||||
private List<String> classLines;
|
||||
private List<String> configLines;
|
||||
|
||||
private int configLine;
|
||||
private int padding = 10;
|
||||
private int configLine;
|
||||
private int padding = 10;
|
||||
|
||||
private ServletContext servletContext;
|
||||
private ServletContext servletContext;
|
||||
|
||||
public String execute() throws MalformedURLException, IOException {
|
||||
public String execute() throws IOException {
|
||||
|
||||
if (page != null) {
|
||||
if (page != null) {
|
||||
|
||||
InputStream in = ClassLoaderUtil.getResourceAsStream(page.substring(page.indexOf("//") + 1), getClass());
|
||||
page = page.replace("//", "/");
|
||||
InputStream in = ClassLoaderUtil.getResourceAsStream(page.substring(page.indexOf("//") + 1), getClass());
|
||||
page = page.replace("//", "/");
|
||||
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
while (in == null && page.indexOf('/', 1) > 0) {
|
||||
page = page.substring(page.indexOf('/', 1));
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
}
|
||||
}
|
||||
pageLines = read(in, -1);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
while (in == null && page.indexOf('/', 1) > 0) {
|
||||
page = page.substring(page.indexOf('/', 1));
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
}
|
||||
}
|
||||
pageLines = read(in, -1);
|
||||
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (className != null) {
|
||||
className = "/" + className.replace('.', '/') + ".java";
|
||||
InputStream in = getClass().getResourceAsStream(className);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream("/WEB-INF/src" + className);
|
||||
}
|
||||
classLines = read(in, -1);
|
||||
if (className != null) {
|
||||
className = "/" + className.replace('.', '/') + ".java";
|
||||
InputStream in = getClass().getResourceAsStream(className);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream("/WEB-INF/src/java" + className);
|
||||
}
|
||||
classLines = read(in, -1);
|
||||
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
final String rootPath = ServletActionContext.getServletContext().getRealPath("/");
|
||||
final String rootPathUnix = (rootPath != null ? rootPath.replace(File.separator, "/") : null); // Make path Unix-like for comparison (e.g. on Windows)
|
||||
final String rootPathFileURI = "file://" + rootPathUnix;
|
||||
final String collapsedRootPathFileURI = rootPathFileURI.replace("//", "/"); // Config string may have been transformed
|
||||
final String rootPathWarFileURI = "war:file://" + rootPathUnix;
|
||||
final String collapsedRootPathWarFileURI = rootPathWarFileURI.replace("//", "/"); // Config string may have been transformed
|
||||
|
||||
if (config != null && (rootPath == null || config.startsWith(rootPath) ||
|
||||
config.startsWith(rootPathFileURI) || config.startsWith(collapsedRootPathFileURI) ||
|
||||
config.startsWith(rootPathWarFileURI) || config.startsWith(collapsedRootPathWarFileURI))) {
|
||||
int pos = config.lastIndexOf(':');
|
||||
configLine = Integer.parseInt(config.substring(pos + 1));
|
||||
config = config.substring(0, pos).replace("//", "/");
|
||||
configLines = read(new URL(config).openStream(), configLine);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
if (config != null && config.startsWith("file:/")) {
|
||||
int pos = config.lastIndexOf(':');
|
||||
configLine = Integer.parseInt(config.substring(pos + 1));
|
||||
configLines = read(new URL(config.substring(0, pos)).openStream(), configLine);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param className the className to set
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
if (className != null && className.trim().length() > 0) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param className the className to set
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
if (className != null && className.trim().length() > 0) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param config the config to set
|
||||
*/
|
||||
public void setConfig(String config) {
|
||||
if (config != null && config.trim().length() > 0) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param config the config to set
|
||||
*/
|
||||
public void setConfig(String config) {
|
||||
if (config != null && config.trim().length() > 0) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param page the page to set
|
||||
*/
|
||||
public void setPage(String page) {
|
||||
if (page != null && page.trim().length() > 0) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param page the page to set
|
||||
*/
|
||||
public void setPage(String page) {
|
||||
if (page != null && page.trim().length() > 0) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param padding the padding to set
|
||||
*/
|
||||
public void setPadding(int padding) {
|
||||
this.padding = padding;
|
||||
}
|
||||
/**
|
||||
* @param padding the padding to set
|
||||
*/
|
||||
public void setPadding(int padding) {
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the classLines
|
||||
*/
|
||||
public List getClassLines() {
|
||||
return classLines;
|
||||
}
|
||||
/**
|
||||
* @return the classLines
|
||||
*/
|
||||
public List<String> getClassLines() {
|
||||
return classLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configLines
|
||||
*/
|
||||
public List getConfigLines() {
|
||||
return configLines;
|
||||
}
|
||||
/**
|
||||
* @return the configLines
|
||||
*/
|
||||
public List<String> getConfigLines() {
|
||||
return configLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pageLines
|
||||
*/
|
||||
public List getPageLines() {
|
||||
return pageLines;
|
||||
}
|
||||
/**
|
||||
* @return the pageLines
|
||||
*/
|
||||
public List<String> getPageLines() {
|
||||
return pageLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the className
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
/**
|
||||
* @return the className
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the config
|
||||
*/
|
||||
public String getConfig() {
|
||||
return config;
|
||||
}
|
||||
/**
|
||||
* @return the config
|
||||
*/
|
||||
public String getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the page
|
||||
*/
|
||||
public String getPage() {
|
||||
return page;
|
||||
}
|
||||
/**
|
||||
* @return the page
|
||||
*/
|
||||
public String getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configLine
|
||||
*/
|
||||
public int getConfigLine() {
|
||||
return configLine;
|
||||
}
|
||||
/**
|
||||
* @return the configLine
|
||||
*/
|
||||
public int getConfigLine() {
|
||||
return configLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the padding
|
||||
*/
|
||||
public int getPadding() {
|
||||
return padding;
|
||||
}
|
||||
/**
|
||||
* @return the padding
|
||||
*/
|
||||
public int getPadding() {
|
||||
return padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a stream, optionally only including the target line number
|
||||
* and its padding
|
||||
*
|
||||
* @param in The input stream
|
||||
* @param targetLineNumber The target line number, negative to read all
|
||||
* @return A list of lines
|
||||
*/
|
||||
private List read(InputStream in, int targetLineNumber) {
|
||||
List snippet = null;
|
||||
if (in != null) {
|
||||
snippet = new ArrayList();
|
||||
int startLine = 0;
|
||||
int endLine = Integer.MAX_VALUE;
|
||||
if (targetLineNumber > 0) {
|
||||
startLine = targetLineNumber - padding;
|
||||
endLine = targetLineNumber + padding;
|
||||
}
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
/**
|
||||
* Reads in a stream, optionally only including the target line number
|
||||
* and its padding
|
||||
*
|
||||
* @param in The input stream
|
||||
* @param targetLineNumber The target line number, negative to read all
|
||||
* @return A list of lines
|
||||
*/
|
||||
private List<String> read(InputStream in, int targetLineNumber) {
|
||||
List<String> snippet = null;
|
||||
if (in != null) {
|
||||
snippet = new ArrayList<>();
|
||||
int startLine = 0;
|
||||
int endLine = Integer.MAX_VALUE;
|
||||
if (targetLineNumber > 0) {
|
||||
startLine = targetLineNumber - padding;
|
||||
endLine = targetLineNumber + padding;
|
||||
}
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
int lineno = 0;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineno++;
|
||||
if (lineno >= startLine && lineno <= endLine) {
|
||||
snippet.add(line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignoring as snippet not available isn't a big deal
|
||||
}
|
||||
}
|
||||
return snippet;
|
||||
}
|
||||
int lineno = 0;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineno++;
|
||||
if (lineno >= startLine && lineno <= endLine) {
|
||||
snippet.add(line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignoring as snippet not available isn't a big deal
|
||||
}
|
||||
}
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public void withServletContext(ServletContext arg0) {
|
||||
this.servletContext = arg0;
|
||||
}
|
||||
public void withServletContext(ServletContext arg0) {
|
||||
this.servletContext = arg0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,15 +22,14 @@
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
|
||||
<PatternLayout pattern="[%-5p] %C{2} (%F:%L) - %m%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="com.opensymphony.xwork2" level="info"/>
|
||||
<Logger name="org.apache.struts2" level="info"/>
|
||||
<Logger name="org.springframework" level="info"/>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
</Root>
|
||||
<Logger name="org.apache.struts2" level="info"/>
|
||||
<Logger name="com.opensymphony.xwork2" level="info"/>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
</Configuration>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="dispatcher" extends="struts-default" namespace="/dispatcher">
|
||||
|
||||
<action name="dispatch">
|
||||
<result type="dispatcher">
|
||||
/WEB-INF/dispatcher/dispatch-result.jsp
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="forward">
|
||||
<result type="dispatcher">/dispatcher/dispatch.action</result>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
@@ -78,6 +78,8 @@
|
||||
|
||||
<include file="struts-async.xml" />
|
||||
|
||||
<include file="struts-dispatcher.xml" />
|
||||
|
||||
<package name="default" extends="struts-default">
|
||||
<interceptors>
|
||||
<interceptor-stack name="crudStack">
|
||||
|
||||
@@ -244,6 +244,8 @@
|
||||
<li><s:url var="url" namespace="/modelDriven" action="modelDriven"/><s:a
|
||||
href="%{url}">Model Driven</s:a></li>
|
||||
<li><s:a value="/async/index.html">Async</s:a></li>
|
||||
<li><s:a value="/dispatcher/dispatch.action">Dispatcher result - dispatch</s:a></li>
|
||||
<li><s:a value="/dispatcher/forward.action">Dispatcher result - forward</s:a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Dispatcher result Example</title>
|
||||
<s:head theme="xhtml"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Dispatcher Result Example</h1>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div id="dispatcher-result" class="col-md-12">
|
||||
This page is a result of "dispatching" to it from an action
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +1,19 @@
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* 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
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@@ -26,49 +26,46 @@
|
||||
<body>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>View Sources</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>View Sources</h1>
|
||||
|
||||
<ul class="nav nav-tabs" id="codeTab">
|
||||
<li class="active"><a href="#page">Page</a></li>
|
||||
<li><a href="#config">Configuration</a></li>
|
||||
<li><a href="#java">Java Action</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-tabs" id="codeTab">
|
||||
<li class="active"><a href="#page">Page</a></li>
|
||||
<li><a href="#config">Configuration</a></li>
|
||||
<li><a href="#java">Java Action</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="page">
|
||||
<h3><s:property default="Unknown page" value="page"/></h3>
|
||||
<pre class="prettyprint lang-html linenums">
|
||||
<s:iterator value="pageLines" status="row">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="page">
|
||||
<h3><s:property default="Unknown page" value="page"/></h3>
|
||||
<pre class="prettyprint lang-html linenums"><s:iterator value="pageLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="config">
|
||||
<h3><s:property default="Unknown configuration" value="config"/></h3>
|
||||
<pre class="prettyprint lang-xml linenums">
|
||||
<s:iterator value="configLines" status="row">
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="config">
|
||||
<h3><s:property default="Unknown configuration" value="config"/></h3>
|
||||
<pre class="prettyprint lang-xml linenums"><s:iterator value="configLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="java">
|
||||
<h3><s:property default="Unknown or unavailable Action class" value="className"/></h3>
|
||||
<pre class="prettyprint lang-java linenums">
|
||||
<s:iterator value="classLines" status="row">
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="java">
|
||||
<h3><s:property default="Unknown or unavailable Action class" value="className"/></h3>
|
||||
<pre class="prettyprint lang-java linenums"><s:iterator value="classLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<s:script>
|
||||
$('#codeTab a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
})
|
||||
$('#codeTab a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
})
|
||||
</s:script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?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
|
||||
@@ -16,20 +17,16 @@
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<web-app id="starter" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Struts Showcase Application</display-name>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.apache.tiles.definition.DefinitionsFactory.DEFINITIONS_CONFIG</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/tiles.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>async</filter-name>
|
||||
<filter-class>org.apache.struts2.showcase.async.AsyncFilter</filter-class>
|
||||
@@ -39,18 +36,20 @@
|
||||
<filter>
|
||||
<filter-name>struts-prepare</filter-name>
|
||||
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>struts-execute</filter-name>
|
||||
<filter-class>org.apache.struts2.dispatcher.filter.StrutsExecuteFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
|
||||
<filter>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
|
||||
</filter>
|
||||
<filter>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>async</filter-name>
|
||||
@@ -60,16 +59,22 @@
|
||||
<filter-mapping>
|
||||
<filter-name>struts-prepare</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>struts-execute</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
@@ -81,18 +86,18 @@
|
||||
org.apache.struts2.tiles.StrutsTilesListener
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
|
||||
<!-- Chat Example in Showcase -->
|
||||
<listener>
|
||||
<listener-class>
|
||||
org.apache.struts2.showcase.chat.ChatSessionListener
|
||||
</listener-class>
|
||||
<listener-class>
|
||||
org.apache.struts2.showcase.chat.ChatSessionListener
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.apache.struts2.dispatcher.listener.StrutsListener</listener-class>
|
||||
</listener>
|
||||
|
||||
|
||||
<!-- SNIPPET START: dwr -->
|
||||
|
||||
<servlet>
|
||||
@@ -103,13 +108,20 @@
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>JspSupportServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>JspSupportServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!-- Sitemesh Freemarker and Velocity Decorator Servlets. Shares configuration with Struts.-->
|
||||
<servlet>
|
||||
<servlet-name>strutsServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.dispatcher.servlet.StrutsServlet</servlet-class>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
|
||||
<!-- Sitemesh Freemarker and Velocity Decorator Servlets. Shares configuration with Struts.-->
|
||||
<servlet>
|
||||
<servlet-name>sitemesh-freemarker</servlet-name>
|
||||
<servlet-class>org.apache.struts2.sitemesh.FreemarkerDecoratorServlet</servlet-class>
|
||||
@@ -117,7 +129,7 @@
|
||||
<param-name>default_encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<load-on-startup>3</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
@@ -127,14 +139,7 @@
|
||||
<param-name>default_encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>strutsServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.dispatcher.servlet.StrutsServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
<load-on-startup>4</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DispatcherResultTest {
|
||||
|
||||
@Test
|
||||
public void testDispatchingToJSP() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/dispatch.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/forward.action");
|
||||
|
||||
//DomElement div = page.getElementById("dispatcher-result");
|
||||
//Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
// support for forwarding to another action is broken on StrutsPrepareFilter/StrutsExecuteFilter
|
||||
// it only works in StrutsPrepareAndExecuteFilter
|
||||
// this will be fixed in Struts 6.1.x
|
||||
|
||||
Assert.assertEquals(404, page.getWebResponse().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+13
-3
@@ -29,7 +29,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.0.0</struts-version.version>
|
||||
<struts-version.version>6.0.3</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -56,6 +56,11 @@
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-async-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-bean-validation-plugin</artifactId>
|
||||
@@ -171,11 +176,16 @@
|
||||
<artifactId>struts2-tiles-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_0_0</tag>
|
||||
<tag>STRUTS_6_0_3</tag>
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Admin Bundle - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Admin Bundle - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Demo Bundle - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Demo Bundle - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
+2
-2
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Bundles - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Bundles - since 6.0.0</name>
|
||||
|
||||
<modules>
|
||||
<module>admin</module>
|
||||
|
||||
+2
-2
@@ -24,14 +24,14 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Struts 2 Core</name>
|
||||
|
||||
<properties>
|
||||
<tlib.version>2.6</tlib.version>
|
||||
<tlib.version>6.0</tlib.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.Callable;
|
||||
* Adds support for invoke async actions. This allows us to support action methods that return {@link Callable}
|
||||
* as well as invoking them in separate not-container thread then executing the result in another container thread.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface AsyncManager {
|
||||
boolean hasAsyncActionResult();
|
||||
|
||||
@@ -298,8 +298,8 @@ public class DefaultConfiguration implements Configuration {
|
||||
|
||||
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
|
||||
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(OgnlUtil.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
|
||||
+2
-2
@@ -217,8 +217,8 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
|
||||
@@ -82,7 +82,9 @@ public class OgnlUtil {
|
||||
*/
|
||||
@Deprecated
|
||||
public OgnlUtil() {
|
||||
this(null, null); // Instantiate default Expression and BeanInfo caches (null factories)
|
||||
// Instantiate default Expression and BeanInfo caches (factories must be non-null).
|
||||
this(new DefaultOgnlExpressionCacheFactory<String, Object>(),
|
||||
new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +98,17 @@ public class OgnlUtil {
|
||||
* @param ognlExpressionCacheFactory factory for Expression cache instance. If null, it uses a default
|
||||
* @param ognlBeanInfoCacheFactory factory for BeanInfo cache instance. If null, it uses a default
|
||||
*/
|
||||
@Inject
|
||||
public OgnlUtil(
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, required = false) ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, required = false) BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
|
||||
@Inject ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
|
||||
) {
|
||||
if (ognlExpressionCacheFactory == null) {
|
||||
throw new IllegalArgumentException("ExpressionCacheFactory parameter cannot be null");
|
||||
}
|
||||
if (ognlBeanInfoCacheFactory == null) {
|
||||
throw new IllegalArgumentException("BeanInfoCacheFactory parameter cannot be null");
|
||||
}
|
||||
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
@@ -108,11 +117,8 @@ public class OgnlUtil {
|
||||
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
OgnlCacheFactory<String, Object> ognlExpressionCacheFactory1 = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>());
|
||||
OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory1 = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>());
|
||||
|
||||
this.expressionCache = ognlExpressionCacheFactory1.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory1.buildOgnlCache();
|
||||
this.expressionCache = ognlExpressionCacheFactory.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory.buildOgnlCache();
|
||||
}
|
||||
|
||||
@Inject
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ package com.opensymphony.xwork2.security;
|
||||
/**
|
||||
* Used across different places to check if given string is not excluded and is accepted
|
||||
* @see <a href="https://securitylab.github.com/research/apache-struts-double-evaluation/">here</a>
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface NotExcludedAcceptedPatternsChecker extends ExcludedPatternsChecker, AcceptedPatternsChecker {
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
*
|
||||
* @param bundleName The bundle to remove from the bundle map
|
||||
*
|
||||
* @deprecated A "no-op" since 2.6. Use {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
|
||||
* @deprecated A "no-op" since 6.0.0. Use {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
|
||||
*/
|
||||
public void clearBundle(final String bundleName) {
|
||||
LOG.debug("No-op. Did NOT clear resource bundle [{}], result: false.", bundleName);
|
||||
@@ -248,7 +248,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* @param bundleName The bundle (combined with locale) to remove from the bundle map
|
||||
* @param locale Provides the locale to combine with the bundle to get the key
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected void clearBundle(final String bundleName, Locale locale) {
|
||||
final String key = createMissesKey(String.valueOf(getCurrentThreadContextClassLoader().hashCode()), bundleName, locale);
|
||||
@@ -266,7 +266,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
|
||||
* lookups of a given key, or some transitory state made a bundle lookup fail.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected void clearMissingBundlesCache() {
|
||||
missingBundles.clear();
|
||||
@@ -313,7 +313,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* The <code>clearCache()</code> methods have been available since Java 1.6, so
|
||||
* it is anticipated the logic will work on any subsequent JVM versions.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
private void clearResourceBundleClassloaderCaches() {
|
||||
final ClassLoader ccl = getCurrentThreadContextClassLoader();
|
||||
@@ -436,7 +436,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
*
|
||||
* @param searchDefaultBundlesFirst provide {@link String} "true" or "false" to set the flag state accordingly.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST, required = false)
|
||||
public void setSearchDefaultBundlesFirst(String searchDefaultBundlesFirst) {
|
||||
|
||||
@@ -29,11 +29,11 @@ import java.util.List;
|
||||
/**
|
||||
* ClassFinder searches the classpath of the specified ClassLoaderInterface for
|
||||
* packages, classes, constructors, methods, or fields with specific annotations.
|
||||
*
|
||||
* <p>
|
||||
* For security reasons ASM is used to find the annotations. Classes are not
|
||||
* loaded unless they match the requirements of a called findAnnotated* method.
|
||||
* Once loaded, these classes are cached.
|
||||
*
|
||||
* <p>
|
||||
* The getClassesNotLoaded() method can be used immediately after any find*
|
||||
* method to get a list of classes which matched the find requirements (i.e.
|
||||
* contained the annotation), but were unable to be loaded.
|
||||
@@ -67,32 +67,32 @@ public interface ClassFinder {
|
||||
|
||||
List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Field> findAnnotatedFields(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findClassesInPackage(String packageName, boolean recursive);
|
||||
List<Class<?>> findClassesInPackage(String packageName, boolean recursive);
|
||||
|
||||
List<Class> findClasses(Test<ClassInfo> test);
|
||||
List<Class<?>> findClasses(Test<ClassInfo> test);
|
||||
|
||||
List<Class> findClasses();
|
||||
List<Class<?>> findClasses();
|
||||
|
||||
ClassLoaderInterface getClassLoaderInterface();
|
||||
|
||||
public static interface Info {
|
||||
interface Info {
|
||||
String getName();
|
||||
|
||||
List<AnnotationInfo> getAnnotations();
|
||||
}
|
||||
|
||||
public class AnnotationInfo extends Annotatable implements Info {
|
||||
class AnnotationInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
|
||||
public AnnotationInfo(Annotation annotation){
|
||||
public AnnotationInfo(Annotation annotation) {
|
||||
this(annotation.getClass().getName());
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class Annotatable {
|
||||
class Annotatable {
|
||||
private final List<AnnotationInfo> annotations = new ArrayList<>();
|
||||
|
||||
public Annotatable(AnnotatedElement element) {
|
||||
@@ -134,12 +134,12 @@ public interface ClassFinder {
|
||||
|
||||
}
|
||||
|
||||
public class PackageInfo extends Annotatable implements Info {
|
||||
class PackageInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final ClassInfo info;
|
||||
private final Package pkg;
|
||||
|
||||
public PackageInfo(Package pkg){
|
||||
public PackageInfo(Package pkg) {
|
||||
super(pkg);
|
||||
this.pkg = pkg;
|
||||
this.name = pkg.getName();
|
||||
@@ -157,11 +157,11 @@ public interface ClassFinder {
|
||||
}
|
||||
|
||||
public Package get() throws ClassNotFoundException {
|
||||
return (pkg != null)?pkg:info.get().getPackage();
|
||||
return (pkg != null) ? pkg : info.get().getPackage();
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassInfo extends Annotatable implements Info {
|
||||
class ClassInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final List<MethodInfo> methods = new ArrayList<>();
|
||||
private final List<MethodInfo> constructors = new ArrayList<>();
|
||||
@@ -169,17 +169,18 @@ public interface ClassFinder {
|
||||
private final List<String> interfaces = new ArrayList<>();
|
||||
private final List<String> superInterfaces = new ArrayList<>();
|
||||
private final List<FieldInfo> fields = new ArrayList<>();
|
||||
private final ClassFinder classFinder;
|
||||
|
||||
private Class<?> clazz;
|
||||
private ClassFinder classFinder;
|
||||
private ClassNotFoundException notFound;
|
||||
|
||||
public ClassInfo(Class clazz, ClassFinder classFinder) {
|
||||
public ClassInfo(Class<?> clazz, ClassFinder classFinder) {
|
||||
super(clazz);
|
||||
this.clazz = clazz;
|
||||
this.classFinder = classFinder;
|
||||
this.name = clazz.getName();
|
||||
Class superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName(): null;
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName() : null;
|
||||
}
|
||||
|
||||
public ClassInfo(String name, String superType, ClassFinder classFinder) {
|
||||
@@ -188,8 +189,8 @@ public interface ClassFinder {
|
||||
this.classFinder = classFinder;
|
||||
}
|
||||
|
||||
public String getPackageName(){
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "" ;
|
||||
public String getPackageName() {
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "";
|
||||
}
|
||||
|
||||
public List<MethodInfo> getConstructors() {
|
||||
@@ -220,7 +221,7 @@ public interface ClassFinder {
|
||||
return superType;
|
||||
}
|
||||
|
||||
public Class get() throws ClassNotFoundException {
|
||||
public Class<?> get() throws ClassNotFoundException {
|
||||
if (clazz != null) return clazz;
|
||||
if (notFound != null) throw notFound;
|
||||
try {
|
||||
@@ -239,20 +240,20 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodInfo extends Annotatable implements Info {
|
||||
class MethodInfo extends Annotatable implements Info {
|
||||
private final ClassInfo declaringClass;
|
||||
private final String returnType;
|
||||
private final String name;
|
||||
private final List<List<AnnotationInfo>> parameterAnnotations = new ArrayList<>();
|
||||
|
||||
public MethodInfo(ClassInfo info, Constructor constructor){
|
||||
public MethodInfo(ClassInfo info, Constructor<?> constructor) {
|
||||
super(constructor);
|
||||
this.declaringClass = info;
|
||||
this.name = "<init>";
|
||||
this.returnType = Void.TYPE.getName();
|
||||
}
|
||||
|
||||
public MethodInfo(ClassInfo info, Method method){
|
||||
public MethodInfo(ClassInfo info, Method method) {
|
||||
super(method);
|
||||
this.declaringClass = info;
|
||||
this.name = method.getName();
|
||||
@@ -297,12 +298,12 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class FieldInfo extends Annotatable implements Info {
|
||||
class FieldInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final ClassInfo declaringClass;
|
||||
|
||||
public FieldInfo(ClassInfo info, Field field){
|
||||
public FieldInfo(ClassInfo info, Field field) {
|
||||
super(field);
|
||||
this.declaringClass = info;
|
||||
this.name = field.getName();
|
||||
|
||||
@@ -43,7 +43,7 @@ public final class StrutsConstants {
|
||||
* Note: This control flag may not be meaningful to all provider implementations, and should be false by default.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST = "struts.i18n.search.defaultbundles.first";
|
||||
|
||||
@@ -254,7 +254,7 @@ public final class StrutsConstants {
|
||||
* Specifies an OGNL expression cache factory implementation. A default implementation is provided, but
|
||||
* could be replaced by a custom one if desired.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_FACTORY = "struts.ognl.expressionCacheFactory";
|
||||
|
||||
@@ -262,7 +262,7 @@ public final class StrutsConstants {
|
||||
* Specifies an OGNL BeanInfo cache factory implementation. A default implementation is provided, but
|
||||
* could be replaced by a custom one if desired.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_FACTORY = "struts.ognl.beanInfoCacheFactory";
|
||||
|
||||
@@ -275,7 +275,7 @@ public final class StrutsConstants {
|
||||
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
|
||||
* removed when a new entry needs to be added (cache is fully-utilized).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE = "struts.ognl.beanInfoCacheMaxSize";
|
||||
|
||||
@@ -287,32 +287,32 @@ public final class StrutsConstants {
|
||||
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE})
|
||||
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE = "struts.ognl.beanInfoCacheLRUMode";
|
||||
|
||||
/**
|
||||
* Logs properties that are not found (very verbose)
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_LOG_MISSING_PROPERTIES = "struts.ognl.logMissingProperties";
|
||||
|
||||
/**
|
||||
* Logs properties that are not found (very verbose)
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_LOG_MISSING_PROPERTIES} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_LOG_MISSING_PROPERTIES} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String STRUTS_LOG_MISSING_PROPERTIES = STRUTS_OGNL_LOG_MISSING_PROPERTIES;
|
||||
|
||||
/**
|
||||
* Enables caching of parsed OGNL expressions
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_ENABLE_EXPRESSION_CACHE = "struts.ognl.enableExpressionCache";
|
||||
|
||||
/**
|
||||
* Enables caching of parsed OGNL expressions
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_ENABLE_EXPRESSION_CACHE} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_ENABLE_EXPRESSION_CACHE} instead.
|
||||
*/
|
||||
public static final String STRUTS_ENABLE_OGNL_EXPRESSION_CACHE = STRUTS_OGNL_ENABLE_EXPRESSION_CACHE;
|
||||
|
||||
@@ -325,7 +325,7 @@ public final class StrutsConstants {
|
||||
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
|
||||
* removed when a new entry needs to be added (cache is fully-utilized).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE = "struts.ognl.expressionCacheMaxSize";
|
||||
|
||||
@@ -337,19 +337,19 @@ public final class StrutsConstants {
|
||||
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE})
|
||||
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE = "struts.ognl.expressionCacheLRUMode";
|
||||
|
||||
/**
|
||||
* Enables evaluation of OGNL expressions
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_ENABLE_EVAL_EXPRESSION = "struts.ognl.enableEvalExpression";
|
||||
|
||||
/**
|
||||
* Enables evaluation of OGNL expressions
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_ENABLE_EVAL_EXPRESSION} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_ENABLE_EVAL_EXPRESSION} instead.
|
||||
*/
|
||||
public static final String STRUTS_ENABLE_OGNL_EVAL_EXPRESSION = STRUTS_OGNL_ENABLE_EVAL_EXPRESSION;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Map;
|
||||
* Please note that the {@link CookieInterceptor} needs to be
|
||||
* activated to receive a cookies map.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface CookiesAware {
|
||||
/**
|
||||
@@ -37,4 +37,4 @@ public interface CookiesAware {
|
||||
* @param cookies the cookies
|
||||
*/
|
||||
void withCookies(Map<String, String> cookies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.apache.struts2.dispatcher.HttpParameters;
|
||||
* One common use for this is to have the action propagate parameters to internally instantiated data
|
||||
* objects.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface ParametersAware {
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import javax.servlet.ServletContext;
|
||||
/**
|
||||
* For components that have a dependence on the Servlet context.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface ServletContextAware {
|
||||
|
||||
|
||||
@@ -538,7 +538,7 @@ public class Component {
|
||||
* Override to set if body content should be HTML-escaped.
|
||||
*
|
||||
* @return always true (default) for this component.
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public boolean escapeHtmlBody() {
|
||||
return escapeHtmlBody;
|
||||
@@ -600,7 +600,7 @@ public class Component {
|
||||
*
|
||||
* @param expression of the component
|
||||
* @return true|false
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
|
||||
@@ -59,7 +59,7 @@ import java.util.List;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note</b>: Since Struts 2.6 a new Java 8 API has been used to format the Date, it's based on
|
||||
* <b>Note</b>: Since Struts 6.0.0 a new Java 8 API has been used to format the Date, it's based on
|
||||
* <a href="https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html">DateTimeFormatter</a>
|
||||
* which uses a bit different patterns.
|
||||
* </p>
|
||||
@@ -293,7 +293,9 @@ public class Date extends ContextBean {
|
||||
final ZoneId tz = getTimeZone();
|
||||
// find the name on the valueStack
|
||||
Object dateObject = findValue(name);
|
||||
if (dateObject instanceof java.util.Date) {
|
||||
if (dateObject instanceof java.sql.Date) {
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atStartOfDay(tz);
|
||||
} else if (dateObject instanceof java.util.Date) {
|
||||
date = ((java.util.Date) dateObject).toInstant().atZone(tz);
|
||||
} else if (dateObject instanceof Calendar) {
|
||||
date = ((Calendar) dateObject).toInstant().atZone(tz);
|
||||
|
||||
@@ -80,4 +80,8 @@ public class Radio extends ListUIBean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Class<?> getValueClassType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.6//EN", "struts-2.6.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 6.0//EN", "struts-6.0.dtd");
|
||||
setDtdMappings(dtdMappings);
|
||||
File file = new File(filename);
|
||||
if (file.getParent() != null) {
|
||||
this.baseDir = file.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#register(com.opensymphony.xwork2.inject.ContainerBuilder, java.util.Properties)
|
||||
*/
|
||||
@@ -175,7 +175,7 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return ("Struts XML configuration provider ("+filename+")");
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -612,20 +613,12 @@ public class Dispatcher {
|
||||
}
|
||||
|
||||
try {
|
||||
String namespace = mapping.getNamespace();
|
||||
String name = mapping.getName();
|
||||
String method = mapping.getMethod();
|
||||
String actionNamespace = mapping.getNamespace();
|
||||
String actionName = mapping.getName();
|
||||
String actionMethod = mapping.getMethod();
|
||||
|
||||
ActionProxy proxy;
|
||||
|
||||
//check if we are probably in an async resuming
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
if (invocation == null || invocation.isExecuted()) {
|
||||
proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method,
|
||||
extraContext, true, false);
|
||||
} else {
|
||||
proxy = invocation.getProxy();
|
||||
}
|
||||
LOG.trace("Processing action, namespace: {}, name: {}, method: {}", actionNamespace, actionName, actionMethod);
|
||||
ActionProxy proxy = prepareActionProxy(extraContext, actionNamespace, actionName, actionMethod);
|
||||
|
||||
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
|
||||
|
||||
@@ -656,6 +649,36 @@ public class Dispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private ActionProxy prepareActionProxy(Map<String, Object> extraContext, String actionNamespace, String actionName, String actionMethod) {
|
||||
ActionProxy proxy;
|
||||
//check if we are probably in an async resuming
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
if (invocation == null || invocation.isExecuted()) {
|
||||
LOG.trace("Creating a new action, namespace: {}, name: {}, method: {}", actionNamespace, actionName, actionMethod);
|
||||
proxy = createActionProxy(actionNamespace, actionName, actionMethod, extraContext);
|
||||
} else {
|
||||
proxy = invocation.getProxy();
|
||||
if (isSameAction(proxy, actionNamespace, actionName, actionMethod)) {
|
||||
LOG.trace("Proxy: {} matches requested action, namespace: {}, name: {}, method: {} - reusing proxy", proxy, actionNamespace, actionName, actionMethod);
|
||||
} else {
|
||||
LOG.trace("Proxy: {} doesn't match action namespace: {}, name: {}, method: {} - creating new proxy", proxy, actionNamespace, actionName, actionMethod);
|
||||
proxy = createActionProxy(actionNamespace, actionName, actionMethod, extraContext);
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private ActionProxy createActionProxy(String namespace, String name, String method, Map<String, Object> extraContext) {
|
||||
ActionProxyFactory actionProxyFactory = getContainer().getInstance(ActionProxyFactory.class);
|
||||
return actionProxyFactory.createActionProxy(namespace, name, method, extraContext, true, false);
|
||||
}
|
||||
|
||||
private boolean isSameAction(ActionProxy actionProxy, String namespace, String actionName, String method) {
|
||||
return Objects.equals(namespace, actionProxy.getNamespace())
|
||||
&& Objects.equals(actionName, actionProxy.getActionName())
|
||||
&& Objects.equals(method, actionProxy.getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs logging of missing action/result configuration exception
|
||||
*
|
||||
|
||||
+4
-4
@@ -126,18 +126,18 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
LOG.trace("Checking if {} is a static resource", uri);
|
||||
boolean handled = execute.executeStaticResourceRequest(request, response);
|
||||
if (!handled) {
|
||||
LOG.trace("Assuming uri {} as a normal action", uri);
|
||||
LOG.trace("Uri {} is not a static resource, assuming action", uri);
|
||||
prepare.setEncodingAndLocale(request, response);
|
||||
prepare.createActionContext(request, response);
|
||||
prepare.assignDispatcherToThread();
|
||||
request = prepare.wrapRequest(request);
|
||||
ActionMapping mapping = prepare.findActionMapping(request, response, true);
|
||||
HttpServletRequest wrappedRequest = prepare.wrapRequest(request);
|
||||
ActionMapping mapping = prepare.findActionMapping(wrappedRequest, response, true);
|
||||
if (mapping == null) {
|
||||
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
LOG.trace("Found mapping {} for {}", mapping, uri);
|
||||
execute.executeAction(request, response, mapping);
|
||||
execute.executeAction(wrappedRequest, response, mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.dispatcher.mapper;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
@@ -29,7 +30,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.RequestUtils;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.util.PrefixTrie;
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
protected boolean allowDynamicMethodCalls = false;
|
||||
protected boolean allowSlashesInActionNames = false;
|
||||
protected boolean alwaysSelectFullNamespace = false;
|
||||
protected PrefixTrie prefixTrie = null;
|
||||
protected PrefixTrie prefixTrie;
|
||||
|
||||
protected Pattern allowedNamespaceNames = Pattern.compile("[a-zA-Z0-9._/\\-]*");
|
||||
protected String defaultNamespaceName = "/";
|
||||
@@ -139,39 +139,35 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
public DefaultActionMapper() {
|
||||
prefixTrie = new PrefixTrie() {
|
||||
{
|
||||
put(METHOD_PREFIX, new ParameterAction() {
|
||||
public void execute(String key, ActionMapping mapping) {
|
||||
if (allowDynamicMethodCalls) {
|
||||
mapping.setMethod(cleanupMethodName(key.substring(METHOD_PREFIX.length())));
|
||||
}
|
||||
put(METHOD_PREFIX, (ParameterAction) (key, mapping) -> {
|
||||
if (allowDynamicMethodCalls) {
|
||||
mapping.setMethod(cleanupMethodName(key.substring(METHOD_PREFIX.length())));
|
||||
}
|
||||
});
|
||||
|
||||
put(ACTION_PREFIX, new ParameterAction() {
|
||||
public void execute(final String key, ActionMapping mapping) {
|
||||
if (allowActionPrefix) {
|
||||
String name = key.substring(ACTION_PREFIX.length());
|
||||
if (allowDynamicMethodCalls) {
|
||||
int bang = name.indexOf('!');
|
||||
if (bang != -1) {
|
||||
String method = cleanupMethodName(name.substring(bang + 1));
|
||||
mapping.setMethod(method);
|
||||
name = name.substring(0, bang);
|
||||
}
|
||||
put(ACTION_PREFIX, (ParameterAction) (key, mapping) -> {
|
||||
if (allowActionPrefix) {
|
||||
String name = key.substring(ACTION_PREFIX.length());
|
||||
if (allowDynamicMethodCalls) {
|
||||
int bang = name.indexOf('!');
|
||||
if (bang != -1) {
|
||||
String method = cleanupMethodName(name.substring(bang + 1));
|
||||
mapping.setMethod(method);
|
||||
name = name.substring(0, bang);
|
||||
}
|
||||
String actionName = cleanupActionName(name);
|
||||
if (allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.startsWith("/")) {
|
||||
actionName = actionName.substring(1);
|
||||
}
|
||||
}
|
||||
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.lastIndexOf('/') != -1) {
|
||||
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
mapping.setName(actionName);
|
||||
}
|
||||
String actionName = cleanupActionName(name);
|
||||
if (allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.startsWith("/")) {
|
||||
actionName = actionName.substring(1);
|
||||
}
|
||||
}
|
||||
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.lastIndexOf('/') != -1) {
|
||||
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
mapping.setName(actionName);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -293,6 +289,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
|
||||
parseNameAndNamespace(uri, mapping, configManager);
|
||||
extractMethodName(mapping, configManager);
|
||||
handleSpecialParameters(request, mapping);
|
||||
return parseActionName(mapping);
|
||||
}
|
||||
@@ -324,9 +321,8 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) {
|
||||
// handle special parameter prefixes.
|
||||
Set<String> uniqueParameters = new HashSet<>();
|
||||
Map parameterMap = request.getParameterMap();
|
||||
for (Object o : parameterMap.keySet()) {
|
||||
String key = (String) o;
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
for (String key : parameterMap.keySet()) {
|
||||
|
||||
// Strip off the image button location info, if found
|
||||
if (key.endsWith(".x") || key.endsWith(".y")) {
|
||||
@@ -353,33 +349,33 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
* @param configManager configuration manager
|
||||
*/
|
||||
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {
|
||||
String namespace, name;
|
||||
String actionNamespace, actionName;
|
||||
int lastSlash = uri.lastIndexOf('/');
|
||||
if (lastSlash == -1) {
|
||||
namespace = "";
|
||||
name = uri;
|
||||
actionNamespace = "";
|
||||
actionName = uri;
|
||||
} else if (lastSlash == 0) {
|
||||
// ww-1046, assume it is the root namespace, it will fallback to
|
||||
// default
|
||||
// namespace anyway if not found in root namespace.
|
||||
namespace = "/";
|
||||
name = uri.substring(lastSlash + 1);
|
||||
actionNamespace = "/";
|
||||
actionName = uri.substring(lastSlash + 1);
|
||||
} else if (alwaysSelectFullNamespace) {
|
||||
// Simply select the namespace as everything before the last slash
|
||||
namespace = uri.substring(0, lastSlash);
|
||||
name = uri.substring(lastSlash + 1);
|
||||
actionNamespace = uri.substring(0, lastSlash);
|
||||
actionName = uri.substring(lastSlash + 1);
|
||||
} else {
|
||||
// Try to find the namespace in those defined, defaulting to ""
|
||||
Configuration config = configManager.getConfiguration();
|
||||
String prefix = uri.substring(0, lastSlash);
|
||||
namespace = "";
|
||||
actionNamespace = "";
|
||||
boolean rootAvailable = false;
|
||||
// Find the longest matching namespace, defaulting to the default
|
||||
for (PackageConfig cfg : config.getPackageConfigs().values()) {
|
||||
String ns = cfg.getNamespace();
|
||||
if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
|
||||
if (ns.length() > namespace.length()) {
|
||||
namespace = ns;
|
||||
if (ns.length() > actionNamespace.length()) {
|
||||
actionNamespace = ns;
|
||||
}
|
||||
}
|
||||
if ("/".equals(ns)) {
|
||||
@@ -387,23 +383,23 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
}
|
||||
|
||||
name = uri.substring(namespace.length() + 1);
|
||||
actionName = uri.substring(actionNamespace.length() + 1);
|
||||
|
||||
// Still none found, use root namespace if found
|
||||
if (rootAvailable && "".equals(namespace)) {
|
||||
namespace = "/";
|
||||
if (rootAvailable && "".equals(actionNamespace)) {
|
||||
actionNamespace = "/";
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowSlashesInActionNames) {
|
||||
int pos = name.lastIndexOf('/');
|
||||
if (pos > -1 && pos < name.length() - 1) {
|
||||
name = name.substring(pos + 1);
|
||||
int pos = actionName.lastIndexOf('/');
|
||||
if (pos > -1 && pos < actionName.length() - 1) {
|
||||
actionName = actionName.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
mapping.setNamespace(cleanupNamespaceName(namespace));
|
||||
mapping.setName(cleanupActionName(name));
|
||||
mapping.setNamespace(cleanupNamespaceName(actionNamespace));
|
||||
mapping.setName(cleanupActionName(actionName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,6 +450,30 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads defined method name for a given action from configuration
|
||||
*
|
||||
* @param mapping current instance of {@link ActionMapping}
|
||||
* @param configurationManager current instance of {@link ConfigurationManager}
|
||||
*/
|
||||
protected void extractMethodName(ActionMapping mapping, ConfigurationManager configurationManager) {
|
||||
String methodName = null;
|
||||
for (PackageConfig cfg : configurationManager.getConfiguration().getPackageConfigs().values()) {
|
||||
if (cfg.getNamespace().equals(mapping.getNamespace())) {
|
||||
ActionConfig actionCfg = cfg.getActionConfigs().get(mapping.getName());
|
||||
if (actionCfg != null) {
|
||||
methodName = actionCfg.getMethodName();
|
||||
LOG.trace("Using method: {} for action mapping: {}", methodName, mapping);
|
||||
} else {
|
||||
LOG.debug("No action config for action mapping: {}", mapping);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mapping.setMethod(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the extension from the action name, storing it in the mapping for later use
|
||||
*
|
||||
@@ -551,7 +571,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
String extension = lookupExtension(mapping.getExtension());
|
||||
|
||||
if (extension != null) {
|
||||
if (extension.length() == 0 || (extension.length() > 0 && uri.indexOf('.' + extension) == -1)) {
|
||||
if (extension.length() == 0 || uri.indexOf('.' + extension) == -1) {
|
||||
if (extension.length() > 0) {
|
||||
uri.append(".").append(extension);
|
||||
}
|
||||
|
||||
@@ -52,21 +52,30 @@ public class CoepInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
invocation.addPreResultListener(this);
|
||||
if (disabled) {
|
||||
LOG.trace("COEP interceptor has been disabled");
|
||||
} else {
|
||||
invocation.addPreResultListener(this);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
HttpServletRequest req = invocation.getInvocationContext().getServletRequest();
|
||||
HttpServletResponse res = invocation.getInvocationContext().getServletResponse();
|
||||
final String path = req.getContextPath();
|
||||
|
||||
if (exemptedPaths.contains(path)) {
|
||||
// no need to add headers
|
||||
LOG.debug("Skipping COEP header for exempted path {}", path);
|
||||
} else if (!disabled) {
|
||||
res.setHeader(header, REQUIRE_COEP_HEADER);
|
||||
LOG.debug("Skipping COEP header for exempted path: {}", path);
|
||||
} else {
|
||||
LOG.trace("Applying COEP header: {} with value: {}", header, REQUIRE_COEP_HEADER);
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
response.setHeader(header, REQUIRE_COEP_HEADER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,25 +49,34 @@ public class CoopInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
private static final String COOP_HEADER = "Cross-Origin-Opener-Policy";
|
||||
|
||||
private final Set<String> exemptedPaths = new HashSet<>();
|
||||
private boolean disabled = false;
|
||||
private String mode = SAME_ORIGIN;
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
invocation.addPreResultListener(this);
|
||||
if (disabled) {
|
||||
LOG.trace("COOP interceptor has been disabled");
|
||||
} else {
|
||||
invocation.addPreResultListener(this);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
String path = request.getContextPath();
|
||||
|
||||
if (isExempted(path)) {
|
||||
// no need to add headers
|
||||
LOG.debug("Skipping COOP header for exempted path {}", path);
|
||||
} else {
|
||||
response.setHeader(COOP_HEADER, getMode());
|
||||
LOG.trace("Applying COOP header: {} with value: {}", COOP_HEADER, mode);
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
response.setHeader(COOP_HEADER, mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +88,6 @@ public class CoopInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
|
||||
}
|
||||
|
||||
private String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
if (!(mode.equals(SAME_ORIGIN) || mode.equals(SAME_ORIGIN_ALLOW_POPUPS) || mode.equals(UNSAFE_NONE))) {
|
||||
throw new IllegalArgumentException(String.format("Mode '%s' not recognized!", mode));
|
||||
@@ -90,4 +95,7 @@ public class CoopInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
this.disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,24 +18,25 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_USER_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_DEST_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_MODE_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_SITE_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SEC_FETCH_USER_HEADER;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
|
||||
|
||||
/**
|
||||
* Interceptor that implements Fetch Metadata policy on incoming requests used to protect against
|
||||
* CSRF, XSSI, and cross-origin information leaks. Uses {@link StrutsResourceIsolationPolicy} to
|
||||
@@ -46,6 +47,7 @@ import org.apache.logging.log4j.Logger;
|
||||
**/
|
||||
|
||||
public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(FetchMetadataInterceptor.class);
|
||||
private static final String VARY_HEADER_VALUE = String.format("%s,%s,%s,%s", SEC_FETCH_DEST_HEADER, SEC_FETCH_MODE_HEADER, SEC_FETCH_SITE_HEADER, SEC_FETCH_USER_HEADER);
|
||||
private static final String SC_FORBIDDEN = String.valueOf(HttpServletResponse.SC_FORBIDDEN);
|
||||
@@ -53,13 +55,19 @@ public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
private final Set<String> exemptedPaths = new HashSet<>();
|
||||
private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
|
||||
|
||||
@Inject (required=false)
|
||||
private boolean disabled = false;
|
||||
|
||||
@Inject(required = false)
|
||||
public void setExemptedPaths(String paths) {
|
||||
this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (disabled) {
|
||||
LOG.trace("Fetch Metadata interceptor has been disabled");
|
||||
return invocation.invoke();
|
||||
}
|
||||
ActionContext context = invocation.getInvocationContext();
|
||||
HttpServletRequest request = context.getServletRequest();
|
||||
|
||||
@@ -76,31 +84,34 @@ public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
LOG.info("Fetch metadata rejected cross-origin request to [{}]", contextPath);
|
||||
LOG.warn("Fetch metadata rejected cross-origin request to: {}", contextPath);
|
||||
return SC_FORBIDDEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link SEC_FETCH_DEST_HEADER}, {@link SEC_FETCH_MODE_HEADER}, {@link SEC_FETCH_SITE_HEADER}, and {@link SEC_FETCH_USER_HEADER}
|
||||
* elements in the provided ActionInvocation's HttpServletResponse {@link VARY_HEADER} response header.
|
||||
*
|
||||
* Sets {@link ResourceIsolationPolicy#SEC_FETCH_DEST_HEADER}, {@link ResourceIsolationPolicy#SEC_FETCH_MODE_HEADER},
|
||||
* {@link ResourceIsolationPolicy#SEC_FETCH_SITE_HEADER}, and {@link ResourceIsolationPolicy#SEC_FETCH_USER_HEADER}
|
||||
* elements in the provided ActionInvocation's HttpServletResponse {@link ResourceIsolationPolicy#VARY_HEADER} response header.
|
||||
* <p>
|
||||
* Note: This method will replace any previous Vary header content already set for the response.
|
||||
* Note: In order to be effective, the Vary header modification must take place at (or very near) the start of this interceptor's processing.
|
||||
*
|
||||
* @param invocation Supplies the HttpServletResponse (if present) to which the SEC_FETCH_* header names are be added to its {@link VARY_HEADER} response header.
|
||||
* Note: In order to be effective, the Vary header modification must take place at (or very near) the start of this
|
||||
* interceptor's processing.
|
||||
*
|
||||
* @param invocation Supplies the HttpServletResponse (if present) to which the SEC_FETCH_* header names are be added
|
||||
* to its {@link ResourceIsolationPolicy#VARY_HEADER} response header.
|
||||
*/
|
||||
private void addVaryHeaders(ActionInvocation invocation) {
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
if (response != null) {
|
||||
// TODO: Whenever servlet 3.x becomes the baseline for Struts, consider revising this method to use
|
||||
// getHeader(VARY_HEADER) and preserve any VARY_HEADER content already set in the response.
|
||||
// This will probably require some tokenization logic for the header contents.
|
||||
if (LOG.isDebugEnabled() && response.containsHeader(VARY_HEADER)) {
|
||||
LOG.debug("HTTP response already has a [{}] header set, the old value will be overwritten (replaced)", VARY_HEADER);
|
||||
}
|
||||
response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
|
||||
} else {
|
||||
LOG.debug("HTTP response is null, cannot add a new [{}] header", VARY_HEADER);
|
||||
// TODO: Whenever servlet 3.x becomes the baseline for Struts, consider revising this method to use
|
||||
// getHeader(VARY_HEADER) and preserve any VARY_HEADER content already set in the response.
|
||||
// This will probably require some tokenization logic for the header contents.
|
||||
if (LOG.isDebugEnabled() && response.containsHeader(VARY_HEADER)) {
|
||||
LOG.debug("HTTP response already has header: {} set, the old value will be overwritten (replaced)", VARY_HEADER);
|
||||
}
|
||||
response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
this.disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,13 @@ package org.apache.struts2.interceptor.csp;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Interceptor that implements Content Security Policy on incoming requests used to protect against
|
||||
@@ -36,17 +40,30 @@ import javax.servlet.http.HttpServletResponse;
|
||||
* @see DefaultCspSettings
|
||||
**/
|
||||
public final class CspInterceptor extends AbstractInterceptor implements PreResultListener {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(CspInterceptor.class);
|
||||
|
||||
private final CspSettings settings = new DefaultCspSettings();
|
||||
|
||||
private boolean disabled = false;
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
invocation.addPreResultListener(this);
|
||||
if (disabled) {
|
||||
LOG.trace("CSP interceptor has been disabled");
|
||||
} else {
|
||||
invocation.addPreResultListener(this);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
settings.addCspHeaders(response);
|
||||
settings.addCspHeaders(request, response);
|
||||
}
|
||||
|
||||
public void setReportUri(String reportUri) {
|
||||
@@ -71,8 +88,12 @@ public final class CspInterceptor extends AbstractInterceptor implements PreResu
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void setEnforcingMode(String value){
|
||||
public void setEnforcingMode(String value) {
|
||||
boolean enforcingMode = Boolean.parseBoolean(value);
|
||||
settings.setEnforcingMode(enforcingMode);
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
this.disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor.csp;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
@@ -42,9 +43,17 @@ public interface CspSettings {
|
||||
String HTTPS = "https:";
|
||||
String CSP_REPORT_TYPE = "application/csp-report";
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #addCspHeaders(HttpServletRequest, HttpServletResponse)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
void addCspHeaders(HttpServletResponse response);
|
||||
|
||||
void addCspHeaders(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
// sets the uri where csp violation reports will be sent
|
||||
void setReportUri(String uri);
|
||||
|
||||
// sets CSP headers in enforcing mode when true, and report-only when false
|
||||
void setEnforcingMode(boolean value);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor.csp;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CspSettings}.
|
||||
@@ -37,57 +37,62 @@ import java.util.Map;
|
||||
* @see CspInterceptor
|
||||
*/
|
||||
public class DefaultCspSettings implements CspSettings {
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
// this lazy supplier computes a policy format the first time it's called and caches the result
|
||||
// to reduce string operations when attaching policies to HTTP responses
|
||||
private final Supplier<String> lazyPolicyBuilder = new Supplier<String>() {
|
||||
boolean hasBeenCalled;
|
||||
String policyFormat;
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
if (!hasBeenCalled) {
|
||||
StringBuilder policyFormatBuilder = new StringBuilder()
|
||||
.append(OBJECT_SRC)
|
||||
.append(format(" '%s'; ", NONE))
|
||||
.append(SCRIPT_SRC)
|
||||
.append(" 'nonce-%s' ") // nonce placeholder
|
||||
.append(format("'%s' ", STRICT_DYNAMIC))
|
||||
.append(format("%s %s; ", HTTP, HTTPS))
|
||||
.append(BASE_URI)
|
||||
.append(format(" '%s'; ", NONE));
|
||||
private final static Logger LOG = LogManager.getLogger(DefaultCspSettings.class);
|
||||
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
}
|
||||
|
||||
policyFormat = policyFormatBuilder.toString();
|
||||
}
|
||||
|
||||
return format(policyFormat, getNonceString());
|
||||
}
|
||||
};
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
|
||||
private String reportUri;
|
||||
// default to reporting mode
|
||||
private String cspHeader = CSP_REPORT_HEADER;
|
||||
|
||||
@Override
|
||||
public void addCspHeaders(HttpServletResponse response) {
|
||||
associateNonceWithSession();
|
||||
response.setHeader(cspHeader, lazyPolicyBuilder.get());
|
||||
throw new UnsupportedOperationException("Unsupported implementation, use #addCspHeaders(HttpServletRequest request, HttpServletResponse response)");
|
||||
}
|
||||
|
||||
private String getNonceString() {
|
||||
Map<String, Object> session = ActionContext.getContext().getSession();
|
||||
return (String) session.get("nonce");
|
||||
public void addCspHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (isSessionActive(request)) {
|
||||
LOG.trace("Session is active, applying CSP settings");
|
||||
associateNonceWithSession(request);
|
||||
response.setHeader(cspHeader, cratePolicyFormat(request));
|
||||
} else {
|
||||
LOG.trace("Session is not active, ignoring CSP settings");
|
||||
}
|
||||
}
|
||||
|
||||
private void associateNonceWithSession() {
|
||||
Map<String, Object> session = ActionContext.getContext().getSession();
|
||||
private boolean isSessionActive(HttpServletRequest request) {
|
||||
return request.getSession(false) != null;
|
||||
}
|
||||
|
||||
private void associateNonceWithSession(HttpServletRequest request) {
|
||||
String nonceValue = Base64.getUrlEncoder().encodeToString(getRandomBytes());
|
||||
session.put("nonce", nonceValue);
|
||||
request.getSession().setAttribute("nonce", nonceValue);
|
||||
}
|
||||
|
||||
private String cratePolicyFormat(HttpServletRequest request) {
|
||||
StringBuilder policyFormatBuilder = new StringBuilder()
|
||||
.append(OBJECT_SRC)
|
||||
.append(format(" '%s'; ", NONE))
|
||||
.append(SCRIPT_SRC)
|
||||
.append(" 'nonce-%s' ") // nonce placeholder
|
||||
.append(format("'%s' ", STRICT_DYNAMIC))
|
||||
.append(format("%s %s; ", HTTP, HTTPS))
|
||||
.append(BASE_URI)
|
||||
.append(format(" '%s'; ", NONE));
|
||||
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
}
|
||||
|
||||
return format(policyFormatBuilder.toString(), getNonceString(request));
|
||||
}
|
||||
|
||||
private String getNonceString(HttpServletRequest request) {
|
||||
Object nonce = request.getSession().getAttribute("nonce");
|
||||
return Objects.toString(nonce);
|
||||
}
|
||||
|
||||
private byte[] getRandomBytes() {
|
||||
@@ -105,4 +110,5 @@ public class DefaultCspSettings implements CspSettings {
|
||||
public void setReportUri(String reportUri) {
|
||||
this.reportUri = reportUri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public class StreamResult extends StrutsResultSupport {
|
||||
*
|
||||
* @param expression of result
|
||||
* @return true|false
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
|
||||
@@ -154,7 +154,7 @@ public class AnchorTag extends AbstractClosingTag {
|
||||
*
|
||||
* @param escapeHtmlBody
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void setEscapeHtmlBody(String escapeHtmlBody) {
|
||||
this.escapeHtmlBody = escapeHtmlBody;
|
||||
|
||||
@@ -81,7 +81,7 @@ public class SubmitTag extends AbstractClosingTag {
|
||||
*
|
||||
* @param escapeHtmlBody
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void setEscapeHtmlBody(boolean escapeHtmlBody) {
|
||||
this.escapeHtmlBody = escapeHtmlBody;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TextareaTag extends AbstractUITag {
|
||||
public void setWrap(String wrap) {
|
||||
this.wrap = wrap;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxlength(String maxlength) {
|
||||
this.maxlength = maxlength;
|
||||
}
|
||||
@@ -100,6 +100,8 @@ public class TextareaTag extends AbstractUITag {
|
||||
this.readonly = null;
|
||||
this.rows = null;
|
||||
this.wrap = null;
|
||||
this.maxlength = null;
|
||||
this.minlength = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -231,8 +231,8 @@ struts.ognl.enableExpressionCache=true
|
||||
|
||||
### Specify the OGNL expression cache factory and BeanInfo cache factory to use.
|
||||
### Currently, the default implementations are used, but can be replaced with custom ones if desired.
|
||||
struts.ognl.expressionCacheFactory=defaultOgnlExpressionCacheFactory
|
||||
struts.ognl.beanInfoCacheFactory=defaultOgnlBeanInfoCacheFactory
|
||||
# struts.ognl.expressionCacheFactory=customOgnlExpressionCacheFactory
|
||||
# struts.ognl.beanInfoCacheFactory=customOgnlBeanInfoCacheFactory
|
||||
|
||||
### Specify a limit to the number of entries in the OGNL expressionCache.
|
||||
### For the standard expressionCache mode, when the limit is exceeded the entire cache's
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
Use the following DOCTYPE
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"http://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
-->
|
||||
|
||||
<!ELEMENT struts ((package|include|bean|constant)*,bean-selection?, unknown-handler-stack?)>
|
||||
@@ -31,8 +31,8 @@
|
||||
and {@link com.opensymphony.xwork2.inject.Inject}
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
@@ -231,8 +231,8 @@
|
||||
<bean type="org.apache.struts2.components.date.DateFormatter" name="simpleDateFormatter" class="org.apache.struts2.components.date.SimpleDateFormatAdapter" scope="singleton"/>
|
||||
<bean type="org.apache.struts2.components.date.DateFormatter" name="dateTimeFormatter" class="org.apache.struts2.components.date.DateTimeFormatterAdapter" scope="singleton"/>
|
||||
|
||||
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="ognlExpressionCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="ognlBeanInfoCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.ognl.ExpressionCacheFactory" name="struts" class="com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.ognl.BeanInfoCacheFactory" name="struts" class="com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory" scope="singleton" />
|
||||
|
||||
<package name="struts-default" abstract="true">
|
||||
<result-types>
|
||||
@@ -392,6 +392,7 @@
|
||||
<interceptor-ref name="servletConfig"/>
|
||||
<interceptor-ref name="i18n"/>
|
||||
<interceptor-ref name="cspInterceptor">
|
||||
<param name="disabled">false</param>
|
||||
<param name="enforcingMode">false</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="prepare"/>
|
||||
@@ -407,15 +408,18 @@
|
||||
<interceptor-ref name="params"/>
|
||||
<interceptor-ref name="conversionError"/>
|
||||
<interceptor-ref name="coepInterceptor">
|
||||
<param name="enforcingMode">false</param>
|
||||
<param name="disabled">false</param>
|
||||
<param name="enforcingMode">false</param>
|
||||
<param name="exemptedPaths"/>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="coopInterceptor">
|
||||
<param name="disabled">false</param>
|
||||
<param name="exemptedPaths"/>
|
||||
<param name="mode">same-origin</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="fetchMetadata"/>
|
||||
<interceptor-ref name="fetchMetadata">
|
||||
<param name="disabled">false</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="validation">
|
||||
<param name="excludeMethods">input,back,cancel,browse</param>
|
||||
</interceptor-ref>
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
<#if parameters.title?has_content>
|
||||
title="${parameters.title}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.maxlength?has_content>
|
||||
maxlength="${parameters.maxlength}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.minlength?has_content>
|
||||
minlength="${parameters.minlength}"<#rt/>
|
||||
</#if>
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
|
||||
@@ -52,10 +58,4 @@
|
||||
<#if parameters.nameValue??>
|
||||
<@s.property value="parameters.nameValue"/><#t/>
|
||||
</#if>
|
||||
<#if parameters.maxlength?has_content>
|
||||
maxlength="${parameters.maxlength}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.minlength?has_content>
|
||||
minlength="${parameters.minlength}"<#rt/>
|
||||
</#if>
|
||||
</textarea>
|
||||
</textarea>
|
||||
|
||||
@@ -1313,11 +1313,20 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
|
||||
}
|
||||
|
||||
public void testDefaultOgnlUtilExclusionsAlternateConstructor() {
|
||||
OgnlUtil basicOgnlUtil = new OgnlUtil(null, null);
|
||||
|
||||
internalTestInitialEmptyOgnlUtilExclusions(basicOgnlUtil);
|
||||
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
|
||||
public void testDefaultOgnlUtilAlternateConstructorArguments() {
|
||||
// Code coverage test for the OgnlUtil alternate constructor method, and verify expected behaviour.
|
||||
try {
|
||||
OgnlUtil basicOgnlUtil = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), null);
|
||||
fail("null beanInfoCacheFactory should result in exception");
|
||||
} catch (IllegalArgumentException iaex) {
|
||||
// expected result
|
||||
}
|
||||
try {
|
||||
OgnlUtil basicOgnlUtil = new OgnlUtil(null, new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
fail("null expressionCacheFactory should result in exception");
|
||||
} catch (IllegalArgumentException iaex) {
|
||||
// expected result
|
||||
}
|
||||
}
|
||||
|
||||
public void testDefaultOgnlUtilExclusionsAlternateConstructorPopulated() {
|
||||
@@ -1690,20 +1699,6 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedPackageNamesAlternateConstructor() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(null, null);
|
||||
util.setExcludedPackageNames("java.lang,java.awt");
|
||||
assertEquals(util.getExcludedPackageNames().size(), 2);
|
||||
try {
|
||||
util.getExcludedPackageNames().clear();
|
||||
} catch (Exception ex) {
|
||||
assertTrue(ex instanceof UnsupportedOperationException);
|
||||
} finally {
|
||||
assertEquals(util.getExcludedPackageNames().size(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedPackageNamesAlternateConstructorPopulated() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
@@ -1732,20 +1727,6 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedClassesAlternateConstructor() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(null, null);
|
||||
util.setExcludedClasses("java.lang.Runtime,java.lang.ProcessBuilder,java.net.URL");
|
||||
assertEquals(util.getExcludedClasses().size(), 3);
|
||||
try {
|
||||
util.getExcludedClasses().clear();
|
||||
} catch (Exception ex) {
|
||||
assertTrue(ex instanceof UnsupportedOperationException);
|
||||
} finally {
|
||||
assertEquals(util.getExcludedClasses().size(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedClassesAlternateConstructorPopulated() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
@@ -1774,20 +1755,6 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedPackageNamePatternsAlternateConstructor() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(null, null);
|
||||
util.setExcludedPackageNamePatterns("java.lang.");
|
||||
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
|
||||
try {
|
||||
util.getExcludedPackageNamePatterns().clear();
|
||||
} catch (Exception ex) {
|
||||
assertTrue(ex instanceof UnsupportedOperationException);
|
||||
} finally {
|
||||
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetExcludedPackageNamePatternsAlternateConstructorPopulated() {
|
||||
// Getter should return an immutable collection
|
||||
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
|
||||
+3
-3
@@ -264,7 +264,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
* Unit test to confirm expected behaviour of "clearing methods" provided to
|
||||
* StrutsLocalizedTextProvider (from AbstractLocalizedTextProvider).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void testLocalizedTextProviderClearingMethods() {
|
||||
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
|
||||
@@ -331,7 +331,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
* Unit test to confirm the basic behaviour of bundle reload methods provided to
|
||||
* StrutsLocalizedTextProvider (from AbstractLocalizedTextProvider).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void testLocalizedTextProviderReloadMethods() {
|
||||
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
|
||||
@@ -582,7 +582,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
/**
|
||||
* Basic test class to allow specific testing of StrutsLocalizedTextProvider.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
class TestStrutsLocalizedTextProvider extends StrutsLocalizedTextProvider {
|
||||
|
||||
|
||||
@@ -27,11 +27,12 @@ import com.opensymphony.xwork2.validator.annotations.Validations;
|
||||
import com.opensymphony.xwork2.validator.annotations.ValidatorType;
|
||||
import org.apache.struts2.views.jsp.ui.User;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TestAction extends ActionSupport {
|
||||
|
||||
private static final long serialVersionUID = -8891365561914451494L;
|
||||
@@ -50,22 +51,22 @@ public class TestAction extends ActionSupport {
|
||||
private SomeEnum status = SomeEnum.COMPLETED;
|
||||
private Float floatNumber;
|
||||
private Long id;
|
||||
private List<SomeEnum> enumList;
|
||||
private List<Integer> intList;
|
||||
|
||||
private final Map<String, String> texts = new HashMap<String, String>();
|
||||
private final Map<String, String> texts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Define a text resource within this action that will be returned by the getText methods
|
||||
* here before delegating to the default TextProvider
|
||||
*
|
||||
* call
|
||||
* @param key
|
||||
* @param value
|
||||
* here before delegating to the default TextProvider call
|
||||
*/
|
||||
public void setText(String key, String value) {
|
||||
this.texts.put(key, value);
|
||||
}
|
||||
|
||||
/** Returns the test value if defined otherwise delegates to the default TextProvider */
|
||||
/**
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider
|
||||
*/
|
||||
public String getText(String key) {
|
||||
if (this.texts.containsKey(key)) {
|
||||
return this.texts.get(key);
|
||||
@@ -73,8 +74,10 @@ public class TestAction extends ActionSupport {
|
||||
return super.getText(key);
|
||||
}
|
||||
|
||||
/** This is the method invoked by the {@link org.apache.struts2.util.TextProviderHelper}.
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider */
|
||||
/**
|
||||
* This is the method invoked by the {@link org.apache.struts2.util.TextProviderHelper}.
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider
|
||||
*/
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
if (this.texts.containsKey(key)) {
|
||||
return this.texts.get(key);
|
||||
@@ -180,20 +183,21 @@ public class TestAction extends ActionSupport {
|
||||
}
|
||||
|
||||
@Validations(
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
},
|
||||
requiredStrings = {
|
||||
@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = "result", message = "You must enter a value for field.")
|
||||
}
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
},
|
||||
requiredStrings = {
|
||||
@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = "result", message = "You must enter a value for field.")
|
||||
}
|
||||
)
|
||||
public String annotatedExecute1() throws Exception {
|
||||
return Action.SUCCESS;
|
||||
}
|
||||
|
||||
@Validations(
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
}
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
}
|
||||
)
|
||||
public String annotatedExecute2() throws Exception {
|
||||
return Action.SUCCESS;
|
||||
@@ -207,16 +211,16 @@ public class TestAction extends ActionSupport {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
public SomeEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
public SomeEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(SomeEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
public void setStatus(SomeEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<SomeEnum> getStatusList() {
|
||||
return Arrays.asList(SomeEnum.values());
|
||||
return Arrays.asList(SomeEnum.values());
|
||||
}
|
||||
|
||||
public Float getFloatNumber() {
|
||||
@@ -235,4 +239,19 @@ public class TestAction extends ActionSupport {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<SomeEnum> getEnumList() {
|
||||
return enumList;
|
||||
}
|
||||
|
||||
public void setEnumList(List<SomeEnum> enumList) {
|
||||
this.enumList = enumList;
|
||||
}
|
||||
|
||||
public List<Integer> getIntList() {
|
||||
return intList;
|
||||
}
|
||||
|
||||
public void setIntList(List<Integer> intList) {
|
||||
this.intList = intList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,28 @@ public class DateTest extends StrutsInternalTestCase {
|
||||
assertEquals(expected, writer.toString());
|
||||
}
|
||||
|
||||
public void testJavaSqlDate() {
|
||||
// given
|
||||
Date date = new Date(stack);
|
||||
date.setDateFormatter(new SimpleDateFormatAdapter());
|
||||
|
||||
java.sql.Date now = new java.sql.Date(System.currentTimeMillis());
|
||||
|
||||
String expected = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, ActionContext.getContext().getLocale()).format(now);
|
||||
context.put("myDate", now);
|
||||
|
||||
Writer writer = new StringWriter();
|
||||
|
||||
// when
|
||||
date.setName("myDate");
|
||||
date.setNice(false);
|
||||
date.start(writer);
|
||||
date.end(writer, "");
|
||||
|
||||
// then
|
||||
assertEquals(expected, writer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -104,4 +104,60 @@ public class StrutsJavaConfigurationProviderTest {
|
||||
Assert.assertTrue(names.contains("struts"));
|
||||
Assert.assertTrue(names.contains("struts.test.bean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* This test is purely to provide code coverage for {@link AbstractBeanSelectionProvider}.
|
||||
* It uses an arbitrary setup to ensure a code path not followed in the registration test
|
||||
* is traversed.
|
||||
*/
|
||||
public void testAbstractBeanProviderCoverage() throws Exception {
|
||||
final ConstantConfig constantConfig = new ConstantConfig();
|
||||
final String expectedUnknownHandler = "expectedUnknownHandler";
|
||||
|
||||
StrutsJavaConfiguration javaConfig = new StrutsJavaConfiguration() {
|
||||
@Override
|
||||
public List<String> unknownHandlerStack() {
|
||||
return Collections.singletonList(expectedUnknownHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConstantConfig> constants() {
|
||||
return Collections.singletonList(constantConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanConfig> beans() {
|
||||
return Arrays.asList(
|
||||
new BeanConfig(TestBean.class, "struts")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BeanSelectionConfig> beanSelection() {
|
||||
return Optional.of(new BeanSelectionConfig(TestBeanSelectionProvider.class, "testBeans"));
|
||||
}
|
||||
};
|
||||
|
||||
StrutsJavaConfigurationProvider provider = new StrutsJavaConfigurationProvider(javaConfig);
|
||||
Configuration configuration = new MockConfiguration();
|
||||
ContainerBuilder builder = new ContainerBuilder();
|
||||
LocatableProperties props = new LocatableProperties();
|
||||
|
||||
provider.init(configuration);
|
||||
provider.register(builder, props);
|
||||
|
||||
props.put(CodeCoverageTestClass1.ALIAS_KEY, CodeCoverageTestClass1.ALIAS_VALUE);
|
||||
TestBeanSelectionProvider testBeanSelectionProvider = new TestBeanSelectionProvider();
|
||||
testBeanSelectionProvider.aliasCallCoverage(CodeCoverageTestClass1.class, builder, props, CodeCoverageTestClass1.ALIAS_KEY, Scope.THREAD);
|
||||
}
|
||||
|
||||
final class CodeCoverageTestClass1 extends Object {
|
||||
public static final String ALIAS_KEY = "testAliasKey";
|
||||
public static final String ALIAS_VALUE = "testAliasValue";
|
||||
|
||||
public CodeCoverageTestClass1() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.config;
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
|
||||
public class TestBeanSelectionProvider extends AbstractBeanSelectionProvider {
|
||||
@@ -30,4 +31,9 @@ public class TestBeanSelectionProvider extends AbstractBeanSelectionProvider {
|
||||
alias(TestBean.class, "struts.test.bean", builder, props);
|
||||
}
|
||||
|
||||
public void aliasCallCoverage(Class aliasClass, ContainerBuilder builder, LocatableProperties props, String aliasKey, Scope scope) throws ConfigurationException {
|
||||
// Allow for coverage testing of AbstractBeanSelectionProvider.
|
||||
alias(aliasClass, aliasKey, builder, props, scope);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.dispatcher;
|
||||
import com.mockobjects.dynamic.C;
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.StubValueStack;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
@@ -30,7 +31,6 @@ import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.mock.MockActionProxy;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
@@ -54,24 +54,23 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test case for Dispatcher.
|
||||
*
|
||||
*/
|
||||
public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testDefaultResurceBundlePropertyLoaded() throws Exception {
|
||||
public void testDefaultResourceBundlePropertyLoaded() {
|
||||
LocalizedTextProvider localizedTextProvider = container.getInstance(LocalizedTextProvider.class);
|
||||
|
||||
// some i18n messages from xwork-messages.properties
|
||||
assertEquals(localizedTextProvider.findDefaultText("xwork.error.action.execution", Locale.US),
|
||||
"Error during Action invocation");
|
||||
"Error during Action invocation");
|
||||
|
||||
// some i18n messages from struts-messages.properties
|
||||
assertEquals(localizedTextProvider.findDefaultText("struts.messages.error.uploading", Locale.US,
|
||||
new Object[] { "some error messages" }),
|
||||
"Error uploading: some error messages");
|
||||
new Object[]{"some error messages"}),
|
||||
"Error uploading: some error messages");
|
||||
}
|
||||
|
||||
public void testPrepareSetEncodingProperly() throws Exception {
|
||||
public void testPrepareSetEncodingProperly() {
|
||||
HttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
@@ -84,7 +83,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertEquals(res.getCharacterEncoding(), "utf-8");
|
||||
}
|
||||
|
||||
public void testEncodingForXMLHttpRequest() throws Exception {
|
||||
public void testEncodingForXMLHttpRequest() {
|
||||
// given
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.addHeader("X-Requested-With", "XMLHttpRequest");
|
||||
@@ -103,7 +102,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertEquals(res.getCharacterEncoding(), "UTF-8");
|
||||
}
|
||||
|
||||
public void testSetEncodingIfDiffer() throws Exception {
|
||||
public void testSetEncodingIfDiffer() {
|
||||
// given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8");
|
||||
@@ -127,7 +126,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testPrepareSetEncodingPropertyWithMultipartRequest() throws Exception {
|
||||
public void testPrepareSetEncodingPropertyWithMultipartRequest() {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
@@ -147,7 +146,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=asdcvb345asd");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
@@ -160,7 +159,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=01=23a.bC:D((e)d'z?p+o_r,e-");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
@@ -173,46 +172,46 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=01=2;3a.bC:D((e)d'z?p+o_r,e-");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
assertFalse(wrapped instanceof MultiPartRequestWrapper);
|
||||
}
|
||||
|
||||
public void testDispatcherListener() throws Exception {
|
||||
public void testDispatcherListener() {
|
||||
|
||||
final DispatcherListenerState state = new DispatcherListenerState();
|
||||
final DispatcherListenerState state = new DispatcherListenerState();
|
||||
|
||||
Dispatcher.addDispatcherListener(new DispatcherListener() {
|
||||
public void dispatcherDestroyed(Dispatcher du) {
|
||||
state.isDestroyed = true;
|
||||
}
|
||||
public void dispatcherInitialized(Dispatcher du) {
|
||||
state.isInitialized = true;
|
||||
}
|
||||
});
|
||||
Dispatcher.addDispatcherListener(new DispatcherListener() {
|
||||
public void dispatcherDestroyed(Dispatcher du) {
|
||||
state.isDestroyed = true;
|
||||
}
|
||||
|
||||
public void dispatcherInitialized(Dispatcher du) {
|
||||
state.isInitialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assertFalse(state.isDestroyed);
|
||||
assertFalse(state.isInitialized);
|
||||
assertFalse(state.isDestroyed);
|
||||
assertFalse(state.isInitialized);
|
||||
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>() );
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
|
||||
assertTrue(state.isInitialized);
|
||||
assertTrue(state.isInitialized);
|
||||
|
||||
du.cleanup();
|
||||
du.cleanup();
|
||||
|
||||
assertTrue(state.isDestroyed);
|
||||
assertTrue(state.isDestroyed);
|
||||
}
|
||||
|
||||
|
||||
public void testConfigurationManager() {
|
||||
Dispatcher du;
|
||||
final InternalConfigurationManager configurationManager = new InternalConfigurationManager(Container.DEFAULT_NAME);
|
||||
try {
|
||||
du = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), configurationManager);
|
||||
du.init();
|
||||
Dispatcher du;
|
||||
final InternalConfigurationManager configurationManager = new InternalConfigurationManager(Container.DEFAULT_NAME);
|
||||
try {
|
||||
du = new MockDispatcher(new MockServletContext(), new HashMap<>(), configurationManager);
|
||||
du.init();
|
||||
Dispatcher.setInstance(du);
|
||||
|
||||
assertFalse(configurationManager.destroyConfiguration);
|
||||
@@ -221,18 +220,17 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
assertTrue(configurationManager.destroyConfiguration);
|
||||
|
||||
}
|
||||
finally {
|
||||
Dispatcher.setInstance(null);
|
||||
}
|
||||
} finally {
|
||||
Dispatcher.setInstance(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInitLoadsDefaultConfig() {
|
||||
Dispatcher du = new Dispatcher(new MockServletContext(), new HashMap<String, String>());
|
||||
Dispatcher du = new Dispatcher(new MockServletContext(), new HashMap<>());
|
||||
du.init();
|
||||
Configuration config = du.getConfigurationManager().getConfiguration();
|
||||
assertNotNull(config);
|
||||
HashSet<String> expected = new HashSet<String>();
|
||||
HashSet<String> expected = new HashSet<>();
|
||||
expected.add("struts-default.xml");
|
||||
expected.add("struts-plugin.xml");
|
||||
expected.add("struts.xml");
|
||||
@@ -243,17 +241,17 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue(packageConfig.getResultTypeConfigs().size() > 0);
|
||||
}
|
||||
|
||||
public void testObjectFactoryDestroy() throws Exception {
|
||||
public void testObjectFactoryDestroy() {
|
||||
|
||||
ConfigurationManager cm = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
Dispatcher du = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), cm);
|
||||
Dispatcher du = new MockDispatcher(new MockServletContext(), new HashMap<>(), cm);
|
||||
Mock mockConfiguration = new Mock(Configuration.class);
|
||||
cm.setConfiguration((Configuration)mockConfiguration.proxy());
|
||||
cm.setConfiguration((Configuration) mockConfiguration.proxy());
|
||||
|
||||
Mock mockContainer = new Mock(Container.class);
|
||||
String reloadConfigs = container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD);
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)),
|
||||
reloadConfigs);
|
||||
reloadConfigs);
|
||||
final InnerDestroyableObjectFactory destroyedObjectFactory = new InnerDestroyableObjectFactory();
|
||||
destroyedObjectFactory.setContainer((Container) mockContainer.proxy());
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), destroyedObjectFactory);
|
||||
@@ -271,7 +269,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mockContainer.verify();
|
||||
}
|
||||
|
||||
public void testInterceptorDestroy() throws Exception {
|
||||
public void testInterceptorDestroy() {
|
||||
Mock mockInterceptor = new Mock(Interceptor.class);
|
||||
mockInterceptor.matchAndReturn("hashCode", 0);
|
||||
mockInterceptor.expect("destroy");
|
||||
@@ -282,14 +280,14 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
PackageConfig packageConfig = new PackageConfig.Builder("test").addInterceptorStackConfig(isc).build();
|
||||
|
||||
Map<String, PackageConfig> packageConfigs = new HashMap<String, PackageConfig>();
|
||||
Map<String, PackageConfig> packageConfigs = new HashMap<>();
|
||||
packageConfigs.put("test", packageConfig);
|
||||
|
||||
Mock mockContainer = new Mock(Container.class);
|
||||
mockContainer.matchAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), new ObjectFactory());
|
||||
String reloadConfigs = container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD);
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)),
|
||||
reloadConfigs);
|
||||
reloadConfigs);
|
||||
|
||||
Mock mockConfiguration = new Mock(Configuration.class);
|
||||
mockConfiguration.matchAndReturn("getPackageConfigs", packageConfigs);
|
||||
@@ -299,7 +297,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
ConfigurationManager configurationManager = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
configurationManager.setConfiguration((Configuration) mockConfiguration.proxy());
|
||||
|
||||
Dispatcher dispatcher = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), configurationManager);
|
||||
Dispatcher dispatcher = new MockDispatcher(new MockServletContext(), new HashMap<>(), configurationManager);
|
||||
dispatcher.init();
|
||||
dispatcher.cleanup();
|
||||
|
||||
@@ -308,22 +306,22 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mockConfiguration.verify();
|
||||
}
|
||||
|
||||
public void testMultipartSupportEnabledByDefault() throws Exception {
|
||||
public void testMultipartSupportEnabledByDefault() {
|
||||
HttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
|
||||
assertTrue(du.isMultipartSupportEnabled(req));
|
||||
}
|
||||
|
||||
public void testIsMultipartRequest() throws Exception {
|
||||
public void testIsMultipartRequest() {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
req.setMethod("POST");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
|
||||
req.setContentType("multipart/form-data");
|
||||
@@ -370,7 +368,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testServiceActionResumePreviousProxy() throws Exception {
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
ActionContext.getContext().withActionInvocation(mai);
|
||||
@@ -393,14 +391,41 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue("should execute previous proxy", actionProxy.isExecutedCalled());
|
||||
}
|
||||
|
||||
public void testServiceActionCreatesNewProxyIfDifferentMapping() throws Exception {
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
container.inject(du);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
ActionContext.getContext().withActionInvocation(mai);
|
||||
|
||||
MockActionProxy previousActionProxy = new MockActionProxy();
|
||||
previousActionProxy.setActionName("first-action");
|
||||
previousActionProxy.setNamespace("namespace1");
|
||||
previousActionProxy.setInvocation(mai);
|
||||
mai.setProxy(previousActionProxy);
|
||||
|
||||
mai.setStack(new StubValueStack());
|
||||
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, mai.getStack());
|
||||
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
assertFalse(previousActionProxy.isExecutedCalled());
|
||||
|
||||
ActionMapping newActionMapping = new ActionMapping();
|
||||
newActionMapping.setName("hello");
|
||||
du.serviceAction(request, response, newActionMapping);
|
||||
|
||||
assertFalse(previousActionProxy.isExecutedCalled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify proper default (true) handleExceptionState for Dispatcher and that
|
||||
* it properly reflects a manually configured change to false.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testHandleException() throws Exception {
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>());
|
||||
public void testHandleException() {
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
assertTrue("Default Dispatcher handleException state not true ?", du.isHandleException());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
@@ -412,11 +437,9 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
/**
|
||||
* Verify proper default (false) devMode for Dispatcher and that
|
||||
* it properly reflects a manually configured change to true.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testDevMode() throws Exception {
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>());
|
||||
public void testDevMode() {
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
assertFalse("Default Dispatcher devMode state not false ?", du.isDevMode());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
@@ -425,7 +448,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue("Modified Dispatcher devMode state not true ?", du2.isDevMode());
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_FromConfiguration() throws Exception {
|
||||
public void testGetLocale_With_DefaultLocale_FromConfiguration() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -451,7 +474,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_fr_CA() throws Exception {
|
||||
public void testGetLocale_With_DefaultLocale_fr_CA() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -477,7 +500,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_RequestLocale_en_UK() throws Exception {
|
||||
public void testGetLocale_With_BadDefaultLocale_RequestLocale_en_UK() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -505,7 +528,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_And_RuntimeException() throws Exception {
|
||||
public void testGetLocale_With_BadDefaultLocale_And_RuntimeException() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -533,7 +556,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale() throws Exception {
|
||||
public void testGetLocale_With_NullDefaultLocale() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -563,7 +586,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale_And_RuntimeException() throws Exception {
|
||||
public void testGetLocale_With_NullDefaultLocale_And_RuntimeException() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -595,19 +618,14 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
/**
|
||||
* Create a test context Map from a Dispatcher instance.
|
||||
*
|
||||
* <p>
|
||||
* The method directly calls getParameterMap() and getSession(true) on the HttpServletRequest.
|
||||
*
|
||||
* <p>
|
||||
* The method indirectly calls getLocale(request) on the Dispatcher instance, allowing a test of that code path.
|
||||
* The derived Struts Dispatcher Locale can be retrieved from the Map afterwards.
|
||||
*
|
||||
* @param dispatcher
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
protected static Map<String, Object> createTestContextMap(Dispatcher dispatcher,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
if (dispatcher == null) {
|
||||
throw new IllegalArgumentException("Cannot create a test ContextMap from a null Dispatcher");
|
||||
}
|
||||
@@ -619,31 +637,31 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
return dispatcher.createContextMap(new RequestMap(request),
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
new SessionMap(request),
|
||||
new ApplicationMap(request.getSession(true).getServletContext()),
|
||||
request,
|
||||
response);
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
new SessionMap(request),
|
||||
new ApplicationMap(request.getSession(true).getServletContext()),
|
||||
request,
|
||||
response);
|
||||
}
|
||||
|
||||
class InternalConfigurationManager extends ConfigurationManager {
|
||||
public boolean destroyConfiguration = false;
|
||||
static class InternalConfigurationManager extends ConfigurationManager {
|
||||
public boolean destroyConfiguration = false;
|
||||
|
||||
public InternalConfigurationManager(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void destroyConfiguration() {
|
||||
super.destroyConfiguration();
|
||||
destroyConfiguration = true;
|
||||
}
|
||||
public synchronized void destroyConfiguration() {
|
||||
super.destroyConfiguration();
|
||||
destroyConfiguration = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DispatcherListenerState {
|
||||
public boolean isInitialized = false;
|
||||
public boolean isDestroyed = false;
|
||||
static class DispatcherListenerState {
|
||||
public boolean isInitialized = false;
|
||||
public boolean isDestroyed = false;
|
||||
}
|
||||
|
||||
public static class InnerDestroyableObjectFactory extends ObjectFactory implements ObjectFactoryDestroyable {
|
||||
|
||||
@@ -34,7 +34,6 @@ public class CoopInterceptorTest extends StrutsInternalTestCase {
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
String SAME_ORIGIN = "same-origin";
|
||||
String SAME_SITE = "same-site";
|
||||
String UNSAFE_NONE = "unsafe-none";
|
||||
String COOP_HEADER = "Cross-Origin-Opener-Policy";
|
||||
|
||||
@@ -65,7 +64,7 @@ public class CoopInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals("Coop header is not same-origin", UNSAFE_NONE, header);
|
||||
}
|
||||
|
||||
public void testErrorNotRecognizedMode() throws Exception {
|
||||
public void testErrorNotRecognizedMode() {
|
||||
request.setContextPath("/some");
|
||||
|
||||
try{
|
||||
@@ -76,6 +75,15 @@ public class CoopInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testDisabled() throws Exception {
|
||||
interceptor.setDisabled("true");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
String header = response.getHeader(COOP_HEADER);
|
||||
assertTrue("COOP is not disabled", Strings.isEmpty(header));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -21,16 +21,25 @@ package org.apache.struts2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
import org.apache.struts2.interceptor.csp.CspInterceptor;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.*;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.BASE_URI;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.CSP_ENFORCE_HEADER;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.CSP_REPORT_HEADER;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.HTTP;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.HTTPS;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.NONE;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.OBJECT_SRC;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.REPORT_URI;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.SCRIPT_SRC;
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.STRICT_DYNAMIC;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
@@ -38,7 +47,8 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
private final MockActionInvocation mai = new MockActionInvocation();
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
private final Map<String, Object> session = new HashMap<>();
|
||||
|
||||
private HttpSession session;
|
||||
|
||||
public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContainsIt() throws Exception {
|
||||
String reportUri = "/barfoo";
|
||||
@@ -48,8 +58,8 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertNotNull("Nonce key does not exist", session.getAttribute("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.getAttribute("nonce")));
|
||||
checkHeader(reportUri, reporting);
|
||||
}
|
||||
|
||||
@@ -58,13 +68,13 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
String enforcingMode = "true";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
session.setAttribute("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
assertNotNull("Nonce key does not exist", session.getAttribute("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.getAttribute("nonce")));
|
||||
assertNotEquals("New nonce value couldn't be set", "foo", session.getAttribute("nonce"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
@@ -73,13 +83,13 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
String enforcingMode = "true";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
session.setAttribute("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
assertNotNull("Nonce key does not exist", session.getAttribute("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.getAttribute("nonce")));
|
||||
assertNotEquals("New nonce value couldn't be set", "foo", session.getAttribute("nonce"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
@@ -88,13 +98,12 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
session.setAttribute("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
assertNotNull("Nonce value is empty", session.getAttribute("nonce"));
|
||||
assertNotEquals("New nonce value couldn't be set", "foo", session.getAttribute("nonce"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
@@ -112,49 +121,60 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
public void testCannotParseUri() throws Exception {
|
||||
public void testCannotParseUri() {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try{
|
||||
try {
|
||||
interceptor.setReportUri("ww w. google.@com");
|
||||
assert(false);
|
||||
} catch (IllegalArgumentException e){
|
||||
assert(true);
|
||||
assert (false);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assert (true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCannotParseRelativeUri() throws Exception {
|
||||
public void testCannotParseRelativeUri() {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try{
|
||||
try {
|
||||
interceptor.setReportUri("some-uri");
|
||||
assert(false);
|
||||
} catch (IllegalArgumentException e){
|
||||
assert(true);
|
||||
assert (false);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assert (true);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, String enforcingMode){
|
||||
String expectedCspHeader = "";
|
||||
public void testDisabled() throws Exception {
|
||||
interceptor.setDisabled("true");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
String header = response.getHeader(CSP_ENFORCE_HEADER);
|
||||
assertTrue("CSP is not disabled", Strings.isEmpty(header));
|
||||
header = response.getHeader(CSP_REPORT_HEADER);
|
||||
assertTrue("CSP is not disabled", Strings.isEmpty(header));
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, String enforcingMode) {
|
||||
String expectedCspHeader;
|
||||
if (Strings.isEmpty(reportUri)) {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ",
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.get("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.getAttribute("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE
|
||||
);
|
||||
} else {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; %s %s",
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.get("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE,
|
||||
REPORT_URI, reportUri
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.getAttribute("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE,
|
||||
REPORT_URI, reportUri
|
||||
);
|
||||
}
|
||||
|
||||
String header = "";
|
||||
if (enforcingMode.equals("true")){
|
||||
String header;
|
||||
if (enforcingMode.equals("true")) {
|
||||
header = response.getHeader(CSP_ENFORCE_HEADER);
|
||||
} else {
|
||||
header = response.getHeader(CSP_REPORT_HEADER);
|
||||
@@ -168,10 +188,12 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
container.inject(interceptor);
|
||||
ServletActionContext.setRequest(request);
|
||||
ServletActionContext.setResponse(response);
|
||||
ActionContext context = ServletActionContext.getActionContext().bind();
|
||||
context.withSession(session);
|
||||
ActionContext context = ActionContext.getContext()
|
||||
.withServletRequest(request)
|
||||
.withServletResponse(response)
|
||||
.withSession(new SessionMap<>(request))
|
||||
.bind();
|
||||
mai.setInvocationContext(context);
|
||||
session = request.getSession();
|
||||
}
|
||||
}
|
||||
|
||||
+33
-23
@@ -18,6 +18,27 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.RuntimeConfiguration;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.DEST_EMBED;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.DEST_OBJECT;
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.DEST_SCRIPT;
|
||||
@@ -32,25 +53,6 @@ import static org.apache.struts2.interceptor.ResourceIsolationPolicy.SITE_SAME_S
|
||||
import static org.apache.struts2.interceptor.ResourceIsolationPolicy.VARY_HEADER;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.RuntimeConfiguration;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public class FetchMetadataInterceptorTest extends XWorkTestCase {
|
||||
|
||||
private final FetchMetadataInterceptor interceptor = new FetchMetadataInterceptor();
|
||||
@@ -79,7 +81,7 @@ public class FetchMetadataInterceptorTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
public void testValidSite() throws Exception {
|
||||
for (String header : Arrays.asList(SITE_SAME_ORIGIN, SITE_SAME_SITE, SITE_NONE)){
|
||||
for (String header : Arrays.asList(SITE_SAME_ORIGIN, SITE_SAME_SITE, SITE_NONE)) {
|
||||
request.addHeader(SEC_FETCH_SITE_HEADER, header);
|
||||
|
||||
assertNotEquals("Expected interceptor to accept this request", SC_FORBIDDEN, interceptor.intercept(mai));
|
||||
@@ -147,12 +149,12 @@ public class FetchMetadataInterceptorTest extends XWorkTestCase {
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Expected vary header to be included", response.containsHeader(VARY_HEADER));
|
||||
assertFalse("Expected original vary header content to be replaced", response.getHeader(VARY_HEADER).contains(ACCEPT_ENCODING_VALUE));
|
||||
assertTrue("Expected added vary header content to be present", response.getHeader(VARY_HEADER).contains(VARY_HEADER_VALUE));
|
||||
assertFalse("Expected original vary header content to be replaced", Objects.requireNonNull(response.getHeader(VARY_HEADER)).contains(ACCEPT_ENCODING_VALUE));
|
||||
assertTrue("Expected added vary header content to be present", Objects.requireNonNull(response.getHeader(VARY_HEADER)).contains(VARY_HEADER_VALUE));
|
||||
}
|
||||
|
||||
public void testSetExemptedPathsInjectionIndirectly() throws Exception {
|
||||
// Perform a multi-step test to confirm (indirectly) that the method parameter injection of setExemptedPaths() for
|
||||
// Perform a multistep test to confirm (indirectly) that the method parameter injection of setExemptedPaths() for
|
||||
// the FetchMetadataInterceptor is functioning as expected, when configured appropriately.
|
||||
// Ensure we're using the specific test configuration, not the default simple configuration.
|
||||
XmlConfigurationProvider configurationProvider = new StrutsXmlConfigurationProvider("struts-testing.xml");
|
||||
@@ -259,4 +261,12 @@ public class FetchMetadataInterceptorTest extends XWorkTestCase {
|
||||
assertNotEquals("Expected interceptor to accept this request [" + "/" + fetchMetadataExemptedGlobalActionConfig.getName() + "]", SC_FORBIDDEN, configuredFetchMetadataInterceptor.intercept(mai));
|
||||
}
|
||||
|
||||
public void testDisabled() throws Exception {
|
||||
interceptor.setDisabled("true");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
String header = response.getHeader(VARY_HEADER);
|
||||
assertTrue("Fetch Metadata is not disabled", Strings.isEmpty(header));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,8 @@ public class FreemarkerResultMockedTest extends StrutsInternalTestCase {
|
||||
EasyMock.replay(servletContext);
|
||||
|
||||
init();
|
||||
// create session
|
||||
request.getSession();
|
||||
|
||||
request.setRequestURI("/tutorial/test10.action");
|
||||
ActionMapping mapping = container.getInstance(ActionMapper.class).getMapping(request, configurationManager);
|
||||
|
||||
@@ -18,36 +18,31 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.dispatcher.ApplicationMap;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.MockDispatcher;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.MockDispatcher;
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class to extend for unit testing UI Tags.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
protected Action action;
|
||||
@@ -62,7 +57,7 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
protected StrutsMockHttpServletRequest request;
|
||||
protected StrutsMockPageContext pageContext;
|
||||
protected HttpServletResponse response;
|
||||
|
||||
|
||||
protected Mock mockContainer;
|
||||
|
||||
/**
|
||||
@@ -114,11 +109,11 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
Dispatcher.setInstance(du);
|
||||
session = new SessionMap<>(request);
|
||||
Map<String, Object> extraContext = du.createContextMap(new RequestMap(request),
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
session,
|
||||
new ApplicationMap(pageContext.getServletContext()),
|
||||
request,
|
||||
response);
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
session,
|
||||
new ApplicationMap(pageContext.getServletContext()),
|
||||
request,
|
||||
response);
|
||||
// let's not set the locale -- there is a test that checks if Dispatcher actually picks this up...
|
||||
// ... but generally we want to just use no locale (let it stay system default)
|
||||
extraContext = ActionContext.of(extraContext).withLocale(null).getContextMap();
|
||||
@@ -149,18 +144,18 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare if two component tags are considered equal according to their fields as accessed
|
||||
* Compare if two component tags are considered equal according to their fields as accessed
|
||||
* via reflection.
|
||||
*
|
||||
* Utilizes {@link EqualsBuilder#reflectionEquals(java.lang.Object, java.lang.Object, boolean)} to perform
|
||||
* <p>
|
||||
* Utilizes {@link EqualsBuilder#reflectionEquals(java.lang.Object, java.lang.Object, boolean)} to perform
|
||||
* the check, and compares transient fields as well. This may fail when run while a security manager is
|
||||
* active, due to a need to user reflection.
|
||||
*
|
||||
* <p>
|
||||
* This method may be useful for checking if the state of a tag is what is expected after a given set of operations,
|
||||
* or after clearing state such as for calls involving {@link StrutsBodyTagSupport#clearTagStateForTagPoolingServers()}
|
||||
* has taken place following {@link StrutsBodyTagSupport#doEndTag()} processing. When making comparisons, keep in mind the
|
||||
* pageContext and parent Tag state are not cleared by clearTagStateForTagPoolingServers().
|
||||
*
|
||||
*
|
||||
* @param tag1 the first {@link StrutsBodyTagSupport} to compare against the other.
|
||||
* @param tag2 the second {@link StrutsBodyTagSupport} to compare against the other.
|
||||
* @return true if the Tags are equal based on field comparisons by reflection, false otherwise.
|
||||
@@ -170,15 +165,16 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to simplify setting the performClearTagStateForTagPoolingServers state for a
|
||||
* {@link ComponentTagSupport} tag's {@link Component} to match expectations for the test.
|
||||
*
|
||||
* Helper method to simplify setting the performClearTagStateForTagPoolingServers state for a
|
||||
* {@link ComponentTagSupport} tag's {@link import org.apache.struts2.components.Component} to match expectations
|
||||
* for the test.
|
||||
* <p>
|
||||
* The component reference is not available to the tag until after the doStartTag() method is called.
|
||||
* We need to ensure the component's {@link Component#performClearTagStateForTagPoolingServers} state matches
|
||||
* what we set for the Tag when a non-default (true) value is used, so this method accesses the component instance,
|
||||
* sets the value specified and forces the tag's parameters to be repopulated again.
|
||||
*
|
||||
* @param tag The ComponentTagSupport tag upon whose component we will set the performClearTagStateForTagPoolingServers state.
|
||||
* We need to ensure the component's {@link import org.apache.struts2.components.Component#performClearTagStateForTagPoolingServers}
|
||||
* state matches what we set for the Tag when a non-default (true) value is used, so this method accesses
|
||||
* the component instance, sets the value specified and forces the tag's parameters to be repopulated again.
|
||||
*
|
||||
* @param tag The ComponentTagSupport tag upon whose component we will set the performClearTagStateForTagPoolingServers state.
|
||||
* @param performClearTagStateForTagPoolingServers true to clear tag state, false otherwise
|
||||
*/
|
||||
protected void setComponentTagClearTagState(ComponentTagSupport tag, boolean performClearTagStateForTagPoolingServers) {
|
||||
|
||||
@@ -18,77 +18,82 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp.ui;
|
||||
|
||||
import org.apache.struts2.SomeEnum;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.views.jsp.AbstractUITagTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RadioTest extends AbstractUITagTest {
|
||||
|
||||
public void testMapWithBooleanAsKey() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
HashMap map = new LinkedHashMap();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
public void testMapWithBooleanAsKey() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
public void testMapWithBooleanAsKey_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
Map<Boolean, String> map = new LinkedHashMap<>();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
HashMap map = new LinkedHashMap();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
tag.doEndTag();
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
public void testMapWithBooleanAsKey_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
Map<Boolean, String> map = new LinkedHashMap<>();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapChecked() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
@@ -103,7 +108,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("\"1\"");
|
||||
tag.setValue("1");
|
||||
tag.setList("map");
|
||||
tag.setListKey("key");
|
||||
tag.setListValue("value");
|
||||
@@ -118,7 +123,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapChecked_clearTagStateSet() throws Exception {
|
||||
@@ -135,7 +140,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("\"1\"");
|
||||
tag.setValue("1");
|
||||
tag.setList("map");
|
||||
tag.setListKey("key");
|
||||
tag.setListValue("value");
|
||||
@@ -152,14 +157,122 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingEnum() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-9.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingEnum_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-9.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingInteger() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2));
|
||||
testAction.setIntList(intList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("2");
|
||||
tag.setList("intList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-10.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingInt_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2));
|
||||
testAction.setIntList(intList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("2");
|
||||
tag.setList("intList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-10.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedNull() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
|
||||
HashMap map = new HashMap();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("1", "One");
|
||||
map.put("2", "Two");
|
||||
testAction.setMap(map);
|
||||
@@ -181,14 +294,14 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedNull_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
|
||||
HashMap map = new HashMap();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("1", "One");
|
||||
map.put("2", "Two");
|
||||
testAction.setMap(map);
|
||||
@@ -213,15 +326,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -243,15 +356,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimple_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -276,13 +389,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithStringMap() throws Exception {
|
||||
final Map<String, String> myMap = new TreeMap<String, String>();
|
||||
final Map<String, String> myMap = new TreeMap<>();
|
||||
myMap.put("name", "Std.");
|
||||
stack.push(new HashMap() {{ put ("myMap", myMap); }});
|
||||
stack.push(new HashMap<String, Map<String, String>>() {{
|
||||
put("myMap", myMap);
|
||||
}});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
@@ -298,13 +413,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithStringMap_clearTagStateSet() throws Exception {
|
||||
final Map<String, String> myMap = new TreeMap<String, String>();
|
||||
final Map<String, String> myMap = new TreeMap<>();
|
||||
myMap.put("name", "Std.");
|
||||
stack.push(new HashMap() {{ put ("myMap", myMap); }});
|
||||
stack.push(new HashMap<String, Map<String, String>>() {{
|
||||
put("myMap", myMap);
|
||||
}});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
@@ -323,15 +440,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithLabelSeparator() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -354,15 +471,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithLabelSeparator_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -388,27 +505,27 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testGenericSimple() throws Exception {
|
||||
RadioTag tag = new RadioTag();
|
||||
prepareTagGeneric(tag);
|
||||
verifyGenericProperties(tag, "simple", new String[]{"id","value"});
|
||||
verifyGenericProperties(tag, "simple", new String[]{"id", "value"});
|
||||
}
|
||||
|
||||
public void testGenericXhtml() throws Exception {
|
||||
RadioTag tag = new RadioTag();
|
||||
prepareTagGeneric(tag);
|
||||
verifyGenericProperties(tag, "xhtml", new String[]{"id","value"});
|
||||
verifyGenericProperties(tag, "xhtml", new String[]{"id", "value"});
|
||||
}
|
||||
|
||||
public void testDynamicAttributes() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -431,15 +548,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testDynamicAttributes_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -465,7 +582,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey() throws Exception {
|
||||
@@ -487,7 +604,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey_clearTagStateSet() throws Exception {
|
||||
@@ -512,15 +629,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
private void prepareTagGeneric(RadioTag tag) {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
tag.setList("list");
|
||||
tag.setListKey("top[0]");
|
||||
|
||||
@@ -47,6 +47,8 @@ public class TextareaTest extends AbstractUITagTest {
|
||||
tag.setId("the_id");
|
||||
tag.setOnkeyup("alert('hello');");
|
||||
tag.setReadonly("true");
|
||||
tag.setMaxlength("100");
|
||||
tag.setMinlength("10");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
@@ -81,6 +83,8 @@ public class TextareaTest extends AbstractUITagTest {
|
||||
tag.setId("the_id");
|
||||
tag.setOnkeyup("alert('hello');");
|
||||
tag.setReadonly("true");
|
||||
tag.setMaxlength("100");
|
||||
tag.setMinlength("10");
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
<struts />
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
<struts/>
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
-->
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<!-- CUSTOM ACTION MAPPER -->
|
||||
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
|
||||
name="WW3090" class="org.apache.struts2.views.jsp.URLTagTest$RedBlueActionMapper" />
|
||||
<constant name="struts.mapper.class" value="WW3090" />
|
||||
<!-- CUSTOM ACTION MAPPER -->
|
||||
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
|
||||
name="WW3090" class="org.apache.struts2.views.jsp.URLTagTest$RedBlueActionMapper"/>
|
||||
<constant name="struts.mapper.class" value="WW3090"/>
|
||||
|
||||
</struts>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<input type="radio" name="status" id="status1" value="1"/>
|
||||
<label for="status1">1</label>
|
||||
<input type="radio" name="status" id="status2" checked="checked" value="2"/>
|
||||
<label for="status2">2</label>
|
||||
@@ -0,0 +1,4 @@
|
||||
<input type="radio" name="status" id="statusINIT" checked="checked" value="INIT"/>
|
||||
<label for="statusINIT">INIT</label>
|
||||
<input type="radio" name="status" id="statusCOMPLETED" value="COMPLETED"/>
|
||||
<label for="statusCOMPLETED">COMPLETED</label>
|
||||
@@ -1,4 +1,4 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="the_id" class="label">mylabel:</label></td>
|
||||
<td class="tdInput"><textarea name="myname" cols="20" rows="30" disabled="disabled" readonly="readonly" tabindex="5" id="the_id" title="mytitle" onclick="alert('onclick');" onkeyup="alert('hello');" onchange="alert('goodbye');">bar</textarea></td>
|
||||
<td class="tdInput"><textarea name="myname" cols="20" rows="30" disabled="disabled" readonly="readonly" tabindex="5" id="the_id" title="mytitle" maxlength="100" minlength="10" onclick="alert('onclick');" onkeyup="alert('hello');" onchange="alert('goodbye');">bar</textarea></td>
|
||||
</tr>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
<struts>
|
||||
<constant name="struts.ui.escapeHtmlBody" value="true"/>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
<struts>
|
||||
<package name="default" extends="struts-default">
|
||||
<action name="hello" class="com.opensymphony.xwork2.ActionSupport">
|
||||
@@ -56,25 +56,25 @@
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="test5" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<action name="test5" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result type="freemarker">
|
||||
<param name="location">org/apache/struts2/views/freemarker/callActionFreeMarker2.ftl</param>
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="test6" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<action name="test6" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result type="freemarker">
|
||||
<param name="location">org/apache/struts2/views/freemarker/dynaAttributes.ftl</param>
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="test7" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<action name="test7" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result type="freemarker">
|
||||
<param name="location">org/apache/struts2/views/freemarker/manual-list.ftl</param>
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="test8" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<action name="test8" class="com.opensymphony.xwork2.ActionSupport">
|
||||
<result type="freemarker">
|
||||
<param name="location">org/apache/struts2/views/freemarker/customTextField.ftl</param>
|
||||
</result>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-async-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.Executor;
|
||||
/**
|
||||
* A {@link Callable} with a timeout value and an {@link Executor}.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class AsyncAction implements Callable {
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
/**
|
||||
* Implements {@link AsyncManager} to add support for invoke async actions via Servlet 3's API.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class DefaultAsyncManager implements AsyncManager, AsyncListener {
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultAsyncManager.class);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.1.2.Final</version>
|
||||
<version>${hibernate-validator.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-cdi-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-config-browser-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-convention-plugin</artifactId>
|
||||
|
||||
+52
-118
@@ -38,6 +38,7 @@ import org.objectweb.asm.Opcodes;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -45,7 +46,15 @@ import java.lang.reflect.Method;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
|
||||
@@ -57,9 +66,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
|
||||
private final List<String> classesNotLoaded = new ArrayList<>();
|
||||
|
||||
private boolean extractBaseInterfaces;
|
||||
private ClassLoaderInterface classLoaderInterface;
|
||||
private FileManager fileManager;
|
||||
private final ClassLoaderInterface classLoaderInterface;
|
||||
private final boolean extractBaseInterfaces;
|
||||
private final FileManager fileManager;
|
||||
|
||||
public DefaultClassFinder(ClassLoaderInterface classLoaderInterface, Collection<URL> urls, boolean extractBaseInterfaces, Set<String> protocols, Test<String> classNameFilter) {
|
||||
this.classLoaderInterface = classLoaderInterface;
|
||||
@@ -97,46 +106,6 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultClassFinder(Class... classes){
|
||||
this(Arrays.asList(classes));
|
||||
}
|
||||
|
||||
public DefaultClassFinder(List<Class> classes){
|
||||
this.classLoaderInterface = null;
|
||||
List<Info> infos = new ArrayList<>();
|
||||
List<Package> packages = new ArrayList<>();
|
||||
for (Class clazz : classes) {
|
||||
|
||||
Package aPackage = clazz.getPackage();
|
||||
if (aPackage != null && !packages.contains(aPackage)){
|
||||
infos.add(new PackageInfo(aPackage));
|
||||
packages.add(aPackage);
|
||||
}
|
||||
|
||||
ClassInfo classInfo = new ClassInfo(clazz, this);
|
||||
infos.add(classInfo);
|
||||
classInfos.put(classInfo.getName(), classInfo);
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
infos.add(new MethodInfo(classInfo, method));
|
||||
}
|
||||
|
||||
for (Constructor constructor : clazz.getConstructors()) {
|
||||
infos.add(new MethodInfo(classInfo, constructor));
|
||||
}
|
||||
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
infos.add(new FieldInfo(classInfo, field));
|
||||
}
|
||||
}
|
||||
|
||||
for (Info info : infos) {
|
||||
for (AnnotationInfo annotation : info.getAnnotations()) {
|
||||
List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
|
||||
annotationInfos.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoaderInterface getClassLoaderInterface() {
|
||||
return classLoaderInterface;
|
||||
}
|
||||
@@ -171,15 +140,15 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return packages;
|
||||
}
|
||||
|
||||
public List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation) {
|
||||
public List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation) {
|
||||
classesNotLoaded.clear();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
List<Info> infos = getAnnotationInfos(annotation.getName());
|
||||
for (Info info : infos) {
|
||||
if (info instanceof ClassInfo) {
|
||||
ClassInfo classInfo = (ClassInfo) info;
|
||||
try {
|
||||
Class clazz = classInfo.get();
|
||||
Class<?> clazz = classInfo.get();
|
||||
// double check via proper reflection
|
||||
if (clazz.isAnnotationPresent(annotation)) {
|
||||
classes.add(clazz);
|
||||
@@ -208,7 +177,7 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
seen.add(classInfo);
|
||||
|
||||
try {
|
||||
Class clazz = classInfo.get();
|
||||
Class<?> clazz = classInfo.get();
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(annotation)) {
|
||||
methods.add(method);
|
||||
@@ -223,10 +192,10 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return methods;
|
||||
}
|
||||
|
||||
public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
|
||||
public List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
|
||||
classesNotLoaded.clear();
|
||||
List<ClassInfo> seen = new ArrayList<>();
|
||||
List<Constructor> constructors = new ArrayList<>();
|
||||
List<Constructor<?>> constructors = new ArrayList<>();
|
||||
List<Info> infos = getAnnotationInfos(annotation.getName());
|
||||
for (Info info : infos) {
|
||||
if (info instanceof MethodInfo && "<init>".equals(info.getName())) {
|
||||
@@ -238,8 +207,8 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
seen.add(classInfo);
|
||||
|
||||
try {
|
||||
Class clazz = classInfo.get();
|
||||
for (Constructor constructor : clazz.getConstructors()) {
|
||||
Class<?> clazz = classInfo.get();
|
||||
for (Constructor<?> constructor : clazz.getConstructors()) {
|
||||
if (constructor.isAnnotationPresent(annotation)) {
|
||||
constructors.add(constructor);
|
||||
}
|
||||
@@ -270,7 +239,7 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
seen.add(classInfo);
|
||||
|
||||
try {
|
||||
Class clazz = classInfo.get();
|
||||
Class<?> clazz = classInfo.get();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(annotation)) {
|
||||
fields.add(field);
|
||||
@@ -285,14 +254,14 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public List<Class> findClassesInPackage(String packageName, boolean recursive) {
|
||||
public List<Class<?>> findClassesInPackage(String packageName, boolean recursive) {
|
||||
classesNotLoaded.clear();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (ClassInfo classInfo : classInfos.values()) {
|
||||
try {
|
||||
if (recursive && classInfo.getPackageName().startsWith(packageName)){
|
||||
if (recursive && classInfo.getPackageName().startsWith(packageName)) {
|
||||
classes.add(classInfo.get());
|
||||
} else if (classInfo.getPackageName().equals(packageName)){
|
||||
} else if (classInfo.getPackageName().equals(packageName)) {
|
||||
classes.add(classInfo.get());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
@@ -303,9 +272,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public List<Class> findClasses(Test<ClassInfo> test) {
|
||||
public List<Class<?>> findClasses(Test<ClassInfo> test) {
|
||||
classesNotLoaded.clear();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (ClassInfo classInfo : classInfos.values()) {
|
||||
try {
|
||||
if (test.test(classInfo)) {
|
||||
@@ -319,9 +288,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return classes;
|
||||
}
|
||||
|
||||
public List<Class> findClasses() {
|
||||
public List<Class<?>> findClasses() {
|
||||
classesNotLoaded.clear();
|
||||
List<Class> classes = new ArrayList<>();
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (ClassInfo classInfo : classInfos.values()) {
|
||||
try {
|
||||
classes.add(classInfo.get());
|
||||
@@ -333,9 +302,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return classes;
|
||||
}
|
||||
|
||||
private List<String> file(URL location) {
|
||||
private List<String> file(URL location) throws UnsupportedEncodingException {
|
||||
List<String> classNames = new ArrayList<>();
|
||||
File dir = new File(URLDecoder.decode(location.getPath()));
|
||||
File dir = new File(URLDecoder.decode(location.getPath(), "UTF-8"));
|
||||
if ("META-INF".equals(dir.getName())) {
|
||||
dir = dir.getParentFile(); // Scrape "META-INF" off
|
||||
}
|
||||
@@ -347,15 +316,17 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
|
||||
private void scanDir(File dir, List<String> classNames, String packageName) {
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
scanDir(file, classNames, packageName + file.getName() + ".");
|
||||
} else if (file.getName().endsWith(".class")) {
|
||||
String name = file.getName();
|
||||
name = name.replaceFirst(".class$", "");
|
||||
// Classes packaged in an exploded .war (e.g. in a VFS file system) should not
|
||||
// have WEB-INF.classes in their package name.
|
||||
classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
scanDir(file, classNames, packageName + file.getName() + ".");
|
||||
} else if (file.getName().endsWith(".class")) {
|
||||
String name = file.getName();
|
||||
name = name.replaceFirst(".class$", "");
|
||||
// Classes packaged in an exploded .war (e.g. in a VFS file system) should not
|
||||
// have WEB-INF.classes in their package name.
|
||||
classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,12 +334,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
private List<String> jar(URL location) throws IOException {
|
||||
URL url = fileManager.normalizeToFileProtocol(location);
|
||||
if (url != null) {
|
||||
InputStream in = url.openStream();
|
||||
try {
|
||||
try (InputStream in = url.openStream()) {
|
||||
JarInputStream jarStream = new JarInputStream(in);
|
||||
return jar(jarStream);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
} else {
|
||||
LOG.debug("Unable to read [{}]", location.toExternalForm());
|
||||
@@ -388,7 +356,7 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
className = className.replaceFirst(".class$", "");
|
||||
|
||||
//war files are treated as .jar files, so takeout WEB-INF/classes
|
||||
className = StringUtils.removeStart(className, "WEB-INF/classes/");
|
||||
className = StringUtils.removeStart(className, "WEB-INF/classes/");
|
||||
|
||||
className = className.replace('/', '.');
|
||||
classNames.add(className);
|
||||
@@ -397,40 +365,8 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
return classNames;
|
||||
}
|
||||
|
||||
public class PackageInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final ClassInfo info;
|
||||
private final Package pkg;
|
||||
|
||||
public PackageInfo(Package pkg){
|
||||
super(pkg);
|
||||
this.pkg = pkg;
|
||||
this.name = pkg.getName();
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
public PackageInfo(String name, ClassFinder classFinder) {
|
||||
info = new ClassInfo(name, null, classFinder);
|
||||
this.name = name;
|
||||
this.pkg = null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Package get() throws ClassNotFoundException {
|
||||
return (pkg != null)?pkg:info.get().getPackage();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Info> getAnnotationInfos(String name) {
|
||||
List<Info> infos = annotated.get(name);
|
||||
if (infos == null) {
|
||||
infos = new ArrayList<>();
|
||||
annotated.put(name, infos);
|
||||
}
|
||||
return infos;
|
||||
return annotated.computeIfAbsent(name, k -> new ArrayList<>());
|
||||
}
|
||||
|
||||
private void readClassDef(String className) {
|
||||
@@ -454,19 +390,16 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
}
|
||||
|
||||
public class InfoBuildingVisitor extends ClassVisitor {
|
||||
|
||||
private final ClassFinder classFinder;
|
||||
|
||||
private Info info;
|
||||
private ClassFinder classFinder;
|
||||
|
||||
public InfoBuildingVisitor(ClassFinder classFinder) {
|
||||
super(Opcodes.ASM7);
|
||||
super(Opcodes.ASM9);
|
||||
this.classFinder = classFinder;
|
||||
}
|
||||
|
||||
public InfoBuildingVisitor(Info info, ClassFinder classFinder) {
|
||||
this(classFinder);
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
if (name.endsWith("package-info")) {
|
||||
@@ -480,8 +413,9 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
info = classInfo;
|
||||
classInfos.put(classInfo.getName(), classInfo);
|
||||
|
||||
if (extractBaseInterfaces)
|
||||
if (extractBaseInterfaces) {
|
||||
extractSuperInterfaces(classInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-dwr-plugin</artifactId>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-embeddedjsp-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 Embedded JSP Plugin (since 2.6)</name>
|
||||
<name>DEPRECATED: Struts 2 Embedded JSP Plugin, since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
+2
-2
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-gxp-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 GXP Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 GXP Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jasperreports-plugin</artifactId>
|
||||
@@ -39,7 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>net.sf.jasperreports</groupId>
|
||||
<artifactId>jasperreports</artifactId>
|
||||
<version>6.17.0</version>
|
||||
<version>6.19.1</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<!-- not necessary to compile and it force dependency convergence issues -->
|
||||
@@ -51,6 +51,10 @@
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.lowagie</groupId>
|
||||
<artifactId>itext</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -512,7 +512,7 @@ public class JasperReportsResult extends StrutsResultSupport implements JasperRe
|
||||
*
|
||||
* @param expression of result
|
||||
* @return true|false
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-javatemplates-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jfreechart-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-json-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-junit-plugin</artifactId>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- Define OSGi Core and Compendium dependencies directly here for the plugin.
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.util.List;
|
||||
* registered with the type of the parameterized type
|
||||
*
|
||||
* @param <T> The type of the service
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface ServiceAware<T> {
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-oval-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 OVal Plugin (since 2.6)</name>
|
||||
<name>DEPRECATED: Struts 2 OVal Plugin, since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- OVal -->
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-pell-multipart-plugin</artifactId>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-plexus-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 Plexus Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 Plexus Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-portlet-mocks-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 Portlet Mocks Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 Portlet Mocks Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-portlet-tiles-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 Portlet Tiles Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 Portlet Tiles Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.0.3</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-portlet-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>DEPRECATED: Struts 2 Portlet Plugin - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 Portlet Plugin - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- junit and related JARs are needed for 'compile'! -->
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user