Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WW-5409 introduce final attribute to package element which make them unextendable #914

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class PackageConfig extends Located implements Comparable<PackageConfig>,
protected String name;
protected String namespace = "";
protected boolean isAbstract = false;
protected boolean isFinal = false; // a final package is unextendable
protected boolean needsRefresh;
protected boolean strictMethodInvocation = true;

Expand All @@ -69,6 +70,7 @@ protected PackageConfig(PackageConfig orig) {
this.name = orig.name;
this.namespace = orig.namespace;
this.isAbstract = orig.isAbstract;
this.isFinal = orig.isFinal;
this.needsRefresh = orig.needsRefresh;
this.actionConfigs = new LinkedHashMap<>(orig.actionConfigs);
this.globalResultConfigs = new LinkedHashMap<>(orig.globalResultConfigs);
Expand All @@ -85,6 +87,10 @@ public boolean isAbstract() {
return isAbstract;
}

public boolean isFinal() {
return isFinal;
}

public Map<String, ActionConfig> getActionConfigs() {
return actionConfigs;
}
Expand Down Expand Up @@ -360,6 +366,7 @@ public boolean equals(Object o) {
PackageConfig that = (PackageConfig) o;

if (isAbstract != that.isAbstract) return false;
if (isFinal != that.isFinal) return false;
if (needsRefresh != that.needsRefresh) return false;
if (strictMethodInvocation != that.strictMethodInvocation) return false;
if (actionConfigs != null ? !actionConfigs.equals(that.actionConfigs) : that.actionConfigs != null)
Expand Down Expand Up @@ -404,6 +411,7 @@ public int hashCode() {
result = 31 * result + name.hashCode();
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
result = 31 * result + (isAbstract ? 1 : 0);
result = 31 * result + (isFinal ? 1 : 0);
result = 31 * result + (needsRefresh ? 1 : 0);
result = 31 * result + (strictMethodInvocation ? 1 : 0);
return result;
Expand Down Expand Up @@ -453,6 +461,11 @@ public Builder isAbstract(boolean isAbstract) {
return this;
}

public Builder isFinal(boolean isFinal) {
target.isFinal = isFinal;
return this;
}

public Builder defaultInterceptorRef(String name) {
target.defaultInterceptorRef = name;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ protected Class<?> verifyResultType(String className, Location loc) {
*/
protected PackageConfig.Builder buildPackageContext(Element packageElement) {
String parent = packageElement.getAttribute("extends");
String abstractVal = packageElement.getAttribute("abstract");
boolean isAbstract = parseBoolean(abstractVal);
boolean isAbstract = parseBoolean(packageElement.getAttribute("abstract"));
boolean isFinal = parseBoolean(packageElement.getAttribute("final"));
String name = defaultString(packageElement.getAttribute("name"));
String namespace = defaultString(packageElement.getAttribute("namespace"));

Expand All @@ -617,6 +617,7 @@ protected PackageConfig.Builder buildPackageContext(Element packageElement) {
PackageConfig.Builder cfg = new PackageConfig.Builder(name)
.namespace(namespace)
.isAbstract(isAbstract)
.isFinal(isFinal)
.strictMethodInvocation(strictDMI)
.location(DomHelper.getLocationObject(packageElement));

Expand All @@ -627,17 +628,23 @@ protected PackageConfig.Builder buildPackageContext(Element packageElement) {
// has parents, let's look it up
List<PackageConfig> parents = new ArrayList<>();
for (String parentPackageName : ConfigurationUtil.buildParentListFromString(parent)) {
if (configuration.getPackageConfigNames().contains(parentPackageName)) {
parents.add(configuration.getPackageConfig(parentPackageName));
} else if (declaredPackages.containsKey(parentPackageName)) {
if (configuration.getPackageConfig(parentPackageName) == null) {
addPackage(declaredPackages.get(parentPackageName));
boolean isParentPackageConfigDefined = false;
if (configuration.getPackageConfigNames().contains(parentPackageName)) { // parent package already added to configuration
isParentPackageConfigDefined = true;
} else if (declaredPackages.containsKey(parentPackageName)) { // parent package declared but yet added to configuration
addPackage(declaredPackages.get(parentPackageName));
isParentPackageConfigDefined = true;
}

if (isParentPackageConfigDefined) {
PackageConfig parentPackageConfig = configuration.getPackageConfig(parentPackageName);
if (parentPackageConfig.isFinal()) {
throw new ConfigurationException("Parent package is final and unextendable: " + parentPackageName);
}
parents.add(configuration.getPackageConfig(parentPackageName));
parents.add(parentPackageConfig);
} else {
throw new ConfigurationException("Parent package is not defined: " + parentPackageName);
}

}

if (parents.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
put("-//Apache Software Foundation//DTD Struts Configuration 6.0//EN", "struts-6.0.dtd");
put("-//Apache Software Foundation//DTD Struts Configuration 6.5//EN", "struts-6.5.dtd");
}});
private File baseDir = null;
private final String filename;
Expand Down
158 changes: 158 additions & 0 deletions core/src/main/resources/struts-6.5.dtd
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?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.
*/
-->
<!-- START SNIPPET: strutsDtd -->

<!--
Struts configuration DTD.
Use the following DOCTYPE
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.5//EN"
"https://struts.apache.org/dtds/struts-6.5.dtd">
-->

<!ELEMENT struts ((package|include|bean|constant)*,bean-selection?, unknown-handler-stack?)>
<!ATTLIST struts
order CDATA #IMPLIED
>

<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-allowed-methods?, global-exception-mappings?, action*)>
<!ATTLIST package
name CDATA #REQUIRED
extends CDATA #IMPLIED
namespace CDATA #IMPLIED
abstract CDATA #IMPLIED
final CDATA #IMPLIED
strict-method-invocation (true|false) "true"
>

<!ELEMENT result-types (result-type+)>

<!ELEMENT result-type (param*)>
<!ATTLIST result-type
name CDATA #REQUIRED
class CDATA #REQUIRED
default (true|false) "false"
>

<!ELEMENT interceptors (interceptor|interceptor-stack)+>

<!ELEMENT interceptor (param*)>
<!ATTLIST interceptor
name CDATA #REQUIRED
class CDATA #REQUIRED
>

<!ELEMENT interceptor-stack (interceptor-ref*)>
<!ATTLIST interceptor-stack
name CDATA #REQUIRED
>

<!ELEMENT interceptor-ref (param*)>
<!ATTLIST interceptor-ref
name CDATA #REQUIRED
>

<!ELEMENT default-interceptor-ref (#PCDATA)>
<!ATTLIST default-interceptor-ref
name CDATA #REQUIRED
>

<!ELEMENT default-action-ref (#PCDATA)>
<!ATTLIST default-action-ref
name CDATA #REQUIRED
>

<!ELEMENT default-class-ref (#PCDATA)>
<!ATTLIST default-class-ref
class CDATA #REQUIRED
>

<!ELEMENT global-results (result+)>

<!ELEMENT global-allowed-methods (#PCDATA)>

<!ELEMENT global-exception-mappings (exception-mapping+)>

<!ELEMENT action ((param|result|interceptor-ref|exception-mapping)*,allowed-methods?)>
<!ATTLIST action
name CDATA #REQUIRED
class CDATA #IMPLIED
method CDATA #IMPLIED
converter CDATA #IMPLIED
>

<!ELEMENT param (#PCDATA)>
<!ATTLIST param
name CDATA #REQUIRED
>

<!ELEMENT result (#PCDATA|param)*>
<!ATTLIST result
name CDATA #IMPLIED
type CDATA #IMPLIED
>

<!ELEMENT exception-mapping (#PCDATA|param)*>
<!ATTLIST exception-mapping
name CDATA #IMPLIED
exception CDATA #REQUIRED
result CDATA #REQUIRED
>

<!ELEMENT allowed-methods (#PCDATA)>

<!ELEMENT include (#PCDATA)>
<!ATTLIST include
file CDATA #REQUIRED
>

<!ELEMENT bean (#PCDATA)>
<!ATTLIST bean
type CDATA #IMPLIED
name CDATA #IMPLIED
class CDATA #REQUIRED
scope CDATA #IMPLIED
static CDATA #IMPLIED
optional CDATA #IMPLIED
>

<!ELEMENT bean-selection (#PCDATA)>
<!ATTLIST bean-selection
name CDATA #IMPLIED
class CDATA #IMPLIED
>

<!ELEMENT constant (#PCDATA)>
<!ATTLIST constant
name CDATA #REQUIRED
value CDATA #REQUIRED
>

<!ELEMENT unknown-handler-stack (unknown-handler-ref*)>
<!ELEMENT unknown-handler-ref (#PCDATA)>
<!ATTLIST unknown-handler-ref
name CDATA #REQUIRED
>

<!-- END SNIPPET: strutsDtd -->

Loading