Skip to content

Commit

Permalink
Merge pull request #111 from StripesFramework/remove_jakarta_mail
Browse files Browse the repository at this point in the history
Remove jakarta mail / update upgrading.txt
  • Loading branch information
rgrashel authored Dec 4, 2023
2 parents 6239be3 + f9f8231 commit 118d794
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 207 deletions.
167 changes: 20 additions & 147 deletions dist/src/assembly/upgrading.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ Upgrading Stripes
http://www.stripesframework.org/

This file documents the steps involved in upgrading an application from Stripes
1.4.x to Stripes 1.5. Since Stripes 1.0-1.4.3 have been backwards compatible it
should be possible to apple these steps to upgrade to Stripes 1.5 from earlier
versions also.
1.6.0 to Stripes 1.6.0-Jakarta.

Contents
--------
Expand All @@ -18,151 +16,26 @@ Contents
of the distribution.
-> Replace your existing commons-logging.jar with the new copy from the lib/
directory of the distribution
-> If you are using commons-fileupload download the latest version from the
apache website http://commons.apache.org/downloads/download_fileupload.cgi
-> Address backward compatibilities listed in section 3 as necessary

2. Suggested Steps
--------------
One significant new feature in Stripes 1.5 that you may wish to leverage at upgrade
time is the concept of "Extension Packages". Using this feature you can inform Stripes
of one or more extension packages, e.g.:
<init-param>
<param-name>Extension.Packages</param-name>
<param-value>com.myco.myapp.web.stripesext</param-value>
</init-param>

If one or more packages are specified Stripes will search these packages for classes
that implement various interfaces and wire them up without requiring you to configure
them manually in web.xml. This includes custom:
-> ActionBeanContext classes
-> Interceptor classes
-> ConfigurableComponent classes (e.g. ActionResolvers, LocalePickers)
-> Formatter classes
-> TypeConverter classes

To reduce your configuration it is recommended that you move any and all such
custom classes into a single package hierarchy and specify the root package. Once
done you can remove all web.xml configuration for these custom classes.

3. Backwards Incompatibilities
-> For security reasons, Log4jLogger has been removed and replaced with SimpleJdk14Logger.
If you want to continue to use log4j, copy the source from the Stripes 1.6.0 branch
into your application source and use at your own risk.
-> If you are using cos.jar it has been removed for security reasons. Commons-fileupload2 is now
the default. Remove cos.jar and remove the CosMultipartWrapper from your web.xml if it is
referenced there.

2. Backwards Incompatibilities
---------------------------
Stripes 1.5 is the first major release of Stripes that is not completely
backwards compatible with earlier versions of Stripes. However most of the
Stripes 1.6.0-Jakarta is not completely
backwards compatible with Stripes 1.6.0 (non-Jakarta). However, most of the
incompatible change are quite small and require only minor edits to your
application (often achievable with search & replace functionality). This
section documents these incompatibilities.

-> ActionResolver.PackageFilters has been replaced by ActionResolver.Packages
which is now a required configuration property. Changes in class scanning to
make it more efficient and robust across containers have changed the meaning
of this property and we have therefore changed the name to reflect this. If you
already specified ActionResolver.PackageFilters simply renaming it will do.
Otherwise you must specify ActionResolver.Packages to be the list of root
packages to scan for ActionBeans in your application

-> Attribute name change in @Before and @After annotations. Previously the
lifecycle changes were specified using the 'value' attribute which
allowed the abbreviated form of '@Before(LifecycleStage.BindingAndValidation)'.
Due to the addition of the 'on' attribute to support selective execution this
is no longer desirable and the 'value' attribute has been renamed to 'stages'.
In most cases replacing '@Before(' with '@Before(stages=' (and the same for
@After) will be enough to ix this problem.

-> The Validatable interface has been removed. Where it was used remove the
implemented clause from your ActionBean and annotate your validate() method
with the @ValidationMethod annotation

-> The link-param tag has been removed in preference to the param tag. A search
and replace of 'link-param' to 'param' is sufficient to fix this.

-> SpringAwareActionResolver has been removed. Please instead use the
SpringInterceptor introduced in Stripes 1.3.

-> Stripes now performs stricter checking of various annotations. If you have
multiple methods annotated with @DefaultHandler or if you have @Validate
annotations in multiple locations (e.g. getter and setter) for a single
property Stripes will throw an exception instead of producing non-deterministic
behaviour.
application (mentioned above). This section documents these incompatibilities.

-> The _sourcePage parameter is no longer inserted into links (using the link and
url tags) by default (it is still submitted in forms). If the _sourcePage parameter
is relied on in certain places you can request Stripes insert it using the new
attribute addSourcePage="true".

-> The _sourcePage parameter is always encrypted to avoid revealing potentially
sensitive information. The plaintext value can be easily accessed by calling
the new method ActionBeanContext.getSourcePage().

-> The way Interceptor classes are configured has changed. Two configuration
properties are supported: 'Interceptor.Classes' and 'CoreInterceptor.Classes'.
The first has the same name as before but the behaviour has changed. Now specifying
this property does NOT require you to specify the interceptors that Stripes
executes by default, only additional interceptors you would like to use. To
override the set of core interceptors used by Stripes you may now separately
specify the 'CoreInterceptor.Classes' property. When upgrading you should
remove referenced to the BeforeAfterMethodInterceptor from the
'Interceptor.Classes' property.

-> Behaviour of file uploads when using commons-fileupload has changed to match
the behaviour when using the cos implementation. When the user does not provide
a file a null FileBean will be produced instead of one containing a zero-length
file. In addition the filenames returned will never have path information
(previously path information would be included if the user was using IE).

-> ActionClassCache has been removed. If you require a list of all ActionBeans
configured use ActionResolver.getActionBeanClasses() instead.

-> All parameter values are now trimmed before validation, type conversion and
binding. If your app has any fields that allow whitespace as valid input or need
to retain leading and trailing whitespace during binding, you must use
@Validate(trim=false) on the field to override this behavior.

-> The special parameter _eventName now overrides all request parameters that would
otherwise indicate the event name. E.g., given an ActionBean with events foo, bar
and blah and request parameters foo=foo, bar=bar and _eventName=blah, the event to
be executed will be blah because _eventName overrides the other two parameters.
Previous versions gave _eventName a lower precedence than other parameters.

-> If multiple request parameters match event names, Stripes will throw an exception
reporting the conflict. In such a case, it cannot be determined which event should
execute. However, if the _eventName parameter is present, as noted in the previous
bullet, it overrides all others, even in case of such a conflict. The behavior of
previous versions of Stripes was indeterminate.

-> When flashing an ActionBean and redirecting to that same ActionBean, as in:

return new RedirectResolution(getClass(), "event").flash(this);

the ActionBean receives a newly created ActionBeanContext on the ensuing request.
(In cases where the flashed bean is not the target of the redirect, the bean
retains its old ActionBeanContext.) One side-effect of this is that
ValidationErrors no longer carry over to the next request. It is recommended
that you use Messages instead of ValidationErrors when flashing and redirecting
to the same ActionBean.

In addition to the above changes there have also been changes to several core classes.
In most cases these changes will be invisible to application developers, but where you
have implemented your own ConfigurableComponents from scratch (as opposed to extending
the default implementations) you may notice additional interface methods and changes
to signatures. Please refer to the javadoc for the 1.5 release in these cases. The
following is a non-exhaustive list of core classes with interface changes in 1.5:
-> Configuration (and implementations thereof)
-> ActionResolver (and implementations thereof)
-> BootstrapPropertyResolver
-> UrlBuilder

-> The default PopulationStrategy is now BeanFirstPopulationStrategy instead of
DefaultPopulationStrategy. This may cause backward compatibility issues if
you were relying on the behavior of DefaultPopulationStrategy. You can revert
back to this behavior by configuring the population strategy in web.xml:

<init-param>
<param-name>PopulationStrategy.Class</param-name>
<param-value>net.sourceforge.stripes.tag.DefaultPopulationStrategy</param-value>
</init-param>

On the other hand, if you had the above configuration present in web.xml but with
BeanFirstPopulationStrategy, it is no longer required since it has become the
default. Leaving it there would be redundant, but would cause no harm.
-> Log4jLogger has been removed and the dependency on log4j has been removed.
-> cos.jar and CosMultipartWrapper have been removed.
-> commons-fileupload has been replaced with commons-fileupload2
-> jakarta.mail dependency has been removed.

2. More Information
---------------------------
For more information about the release, you can look at the release page on GitHub
located here: https://github.com/StripesFramework/stripes/releases/tag/1.6.0-Jakarta-beta
5 changes: 0 additions & 5 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
Expand Down
14 changes: 0 additions & 14 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,6 @@
<version>1.1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>2.1.2</version>
<scope>provided</scope>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
Expand Down
4 changes: 0 additions & 4 deletions stripes/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@
<version>5.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
*/
package net.sourceforge.stripes.validation;

import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import java.util.Collection;
import java.util.Locale;
import java.util.regex.Pattern;

/**
* A faux TypeConverter that validates that the String supplied is a valid email address. Relies on
Expand All @@ -42,6 +41,14 @@
* @since Stripes 1.2
*/
public class EmailTypeConverter implements TypeConverter<String> {

/**
* This RegEx is taken from the HTML5 <a
* href="https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address">spec</a>.
*/
private static final Pattern EMAIL_VALIDATION_REGEX =
Pattern.compile(
"[ \\a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[[\\[]a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[]a-zA-Z0-9])?)*");
/** Accepts the Locale provided, but does nothing with it since emails are Locale-less. */
public void setLocale(Locale locale) {
/** Doesn't matter for email. */
Expand All @@ -59,19 +66,31 @@ public void setLocale(Locale locale) {
public String convert(
String input, Class<? extends String> targetType, Collection<ValidationError> errors) {

String result = null;
// Used to test for more than one @ symbol
int atSymbolOccurrences = (input.length() - input.replace("@", "").length());

// Used to test for no dots after the last @ sign
boolean noDotsAfterLastAtSign =
input.contains("@") && !input.substring(input.lastIndexOf("@")).contains(".");

// Used to test for starts with a dot
boolean startsWithDot = input.split("@")[0].startsWith(".");

// Used to test for ends with a dot
boolean endsWithDot = input.split("@")[0].endsWith(".");

// Used to test for two consecutive dots
boolean twoConsecutiveDots = input.split("@")[0].contains("..");

try {
InternetAddress address = new InternetAddress(input, true);
result = address.getAddress();
if (!result.contains("@")) {
result = null;
throw new AddressException();
}
} catch (AddressException ae) {
if (atSymbolOccurrences > 1
|| noDotsAfterLastAtSign
|| startsWithDot
|| endsWithDot
|| twoConsecutiveDots
|| !EMAIL_VALIDATION_REGEX.matcher(input).matches()) {
errors.add(new ScopedLocalizableError("converter.email", "invalidEmail"));
}

return result;
return input;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
*/
package net.sourceforge.stripes.action;

import jakarta.mail.internet.ContentDisposition;
import jakarta.mail.internet.ParseException;
import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.sourceforge.stripes.mock.MockHttpServletResponse;
import org.apache.commons.fileupload2.core.ParameterParser;
import org.junit.Assert;
import org.junit.Test;

Expand All @@ -34,7 +34,7 @@ public void testContentDisposition() throws Exception {
}

private void doTestContentDisposition(boolean attachment, String filename) throws Exception {
byte[] data = UUID.randomUUID().toString().getBytes(Charset.forName("UTF-8"));
byte[] data = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);
ByteArrayInputStream is = new ByteArrayInputStream(data);

StreamingResolution resolution = new StreamingResolution("application/octet-stream", is);
Expand All @@ -48,32 +48,35 @@ private void doTestContentDisposition(boolean attachment, String filename) throw
resolution.stream(response);
Assert.assertArrayEquals(data, response.getOutputBytes());

ContentDisposition disposition = getContentDisposition(response);
// Use commons-fileupload to parse the Content-Disposition header
String disposition = null;
String cdAttachment = null;
String cdFilename = null;
final List<Object> list = response.getHeaderMap().get("Content-Disposition");
if (list != null && !list.isEmpty()) {
disposition = list.get(0).toString();
final ParameterParser parser = new ParameterParser();
parser.setLowerCaseNames(true);
final Map<String, String> params = parser.parse(disposition, ';');
cdAttachment = params.containsKey("attachment") ? "attachment" : null;
cdFilename = params.getOrDefault("filename", null);
}
if (attachment) {
Assert.assertNotNull(disposition);
Assert.assertEquals("attachment", cdAttachment);
if (filename == null) {
Assert.assertNotNull(disposition);
Assert.assertEquals("attachment", disposition.getDisposition());
Assert.assertNull(disposition.getParameter("filename"));
Assert.assertNull(cdFilename);
} else {
Assert.assertNotNull(disposition);
Assert.assertEquals("attachment", disposition.getDisposition());
Assert.assertNotNull(disposition.getParameter("filename"));
Assert.assertNotNull(cdFilename);
}
} else {
if (filename == null) {
Assert.assertNull(disposition);
} else {
Assert.assertNotNull(disposition);
Assert.assertEquals("attachment", disposition.getDisposition());
Assert.assertNotNull(disposition.getParameter("filename"));
Assert.assertEquals("attachment", cdAttachment);
Assert.assertNotNull(cdFilename);
}
}
}

private ContentDisposition getContentDisposition(MockHttpServletResponse response)
throws ParseException {
final List<Object> list = response.getHeaderMap().get("Content-Disposition");
if (list == null || list.isEmpty()) return null;
else return new ContentDisposition(list.get(0).toString());
}
}
Loading

0 comments on commit 118d794

Please sign in to comment.