This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch 2.1.X
in repository https://gitbox.apache.org/repos/asf/mina.git

commit cdb59eb6131696a440870ab89ad0e20804eb5ca7
Author: emmanuel lecharny <[email protected]>
AuthorDate: Wed Nov 6 18:22:41 2024 +0100

    Added some controls on the classes that can be deserialized; Bumped up some 
plugin dependencies, and some dependencies; Fixed some javadoc issues; Fixed 
some Maven issues
---
 mina-core/pom.xml                                  |   2 +
 .../apache/mina/core/buffer/AbstractIoBuffer.java  | 105 +++-
 .../java/org/apache/mina/core/buffer/IoBuffer.java |  38 ++
 .../apache/mina/core/buffer/IoBufferWrapper.java   |  37 ++
 .../mina/core/buffer/matcher/ClassNameMatcher.java |  33 ++
 .../mina/core/buffer/matcher/FileSystem.java       | 527 +++++++++++++++++++++
 .../mina/core/buffer/matcher/FilenameUtils.java    | 175 +++++++
 .../core/buffer/matcher/FullClassNameMatcher.java  |  49 ++
 .../apache/mina/core/buffer/matcher/IOCase.java    | 276 +++++++++++
 .../buffer/matcher/RegexpClassNameMatcher.java     |  57 +++
 .../buffer/matcher/WildcardClassNameMatcher.java   |  45 ++
 .../mina/core/session/AbstractIoSession.java       |   2 +
 .../mina/core/write/DefaultWriteRequest.java       |   4 +-
 .../ObjectSerializationCodecFactory.java           |  38 ++
 .../serialization/ObjectSerializationDecoder.java  |  44 ++
 .../org/apache/mina/core/buffer/IoBufferTest.java  |  63 ++-
 mina-example/pom.xml                               |  11 +
 mina-legal/pom.xml                                 |   4 +-
 pom.xml                                            | 121 +++--
 19 files changed, 1553 insertions(+), 78 deletions(-)

diff --git a/mina-core/pom.xml b/mina-core/pom.xml
index 12b97deb2..93aba2eac 100644
--- a/mina-core/pom.xml
+++ b/mina-core/pom.xml
@@ -32,6 +32,7 @@
   <packaging>bundle</packaging>
 
   <dependencies>
+    <!-- Test dependencies -->
     <dependency>
       <groupId>org.easymock</groupId>
       <artifactId>easymock</artifactId>
@@ -52,6 +53,7 @@
             <Export-Package>
               org.apache.mina.core;version=${project.version};-noimport:=true,
               
org.apache.mina.core.buffer;version=${project.version};-noimport:=true,
+              
org.apache.mina.core.buffer.matcher;version=${project.version};-noimport:=true,
               
org.apache.mina.core.file;version=${project.version};-noimport:=true,
               
org.apache.mina.core.filterchain;version=${project.version};-noimport:=true,
               
org.apache.mina.core.future;version=${project.version};-noimport:=true,
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java 
b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
index 1ea5a89f5..2ea560916 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
@@ -43,8 +43,17 @@ import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.EnumSet;
+import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.mina.core.buffer.matcher.ClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.FullClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
+
 
 /**
  * A base implementation of {@link IoBuffer}. This implementation assumes that
@@ -80,6 +89,8 @@ public abstract class AbstractIoBuffer extends IoBuffer {
     /** A mask for an int */
     private static final long INT_MASK = 0xFFFFFFFFL;
 
+    private final List<ClassNameMatcher> acceptMatchers = new ArrayList<>();
+
     /**
      * We don't have any access to Buffer.markValue(), so we need to track it 
down,
      * which will cause small extra overhead.
@@ -2154,18 +2165,22 @@ public abstract class AbstractIoBuffer extends IoBuffer 
{
             @Override
             protected ObjectStreamClass readClassDescriptor() throws 
IOException, ClassNotFoundException {
                 int type = read();
+
                 if (type < 0) {
                     throw new EOFException();
                 }
+
                 switch (type) {
-                case 0: // NON-Serializable class or Primitive types
-                    return super.readClassDescriptor();
-                case 1: // Serializable class
-                    String className = readUTF();
-                    Class<?> clazz = Class.forName(className, true, 
classLoader);
-                    return ObjectStreamClass.lookup(clazz);
-                default:
-                    throw new StreamCorruptedException("Unexpected class 
descriptor type: " + type);
+                    case 0: // NON-Serializable class or Primitive types
+                        return super.readClassDescriptor();
+
+                    case 1: // Serializable class
+                        String className = readUTF();
+                        Class<?> clazz = Class.forName(className, true, 
classLoader);
+                        return ObjectStreamClass.lookup(clazz);
+
+                    default:
+                        throw new StreamCorruptedException("Unexpected class 
descriptor type: " + type);
                 }
             }
 
@@ -2181,7 +2196,21 @@ public abstract class AbstractIoBuffer extends IoBuffer {
                         return super.resolveClass(desc);
                     }
                 } else {
-                    return clazz;
+                    boolean found = false;
+                    String className = desc.getName();
+                    
+                    for (ClassNameMatcher matcher : acceptMatchers) {
+                        if (matcher.matches(className)) {
+                            found = true;
+                            break;
+                        }
+                    }
+
+                    if (found) {
+                        return clazz;
+                    }
+                    
+                    throw new ClassNotFoundException();
                 }
             }
         }) {
@@ -2737,4 +2766,62 @@ public abstract class AbstractIoBuffer extends IoBuffer {
             throw new IllegalArgumentException("fieldSize cannot be negative: 
" + fieldSize);
         }
     }
+
+    /**
+     * Accept the specified classes for deserialization, unless they
+     * are otherwise rejected.
+     *
+     * @param classes Classes to accept
+     * @return this object
+     */
+    public IoBuffer accept(Class<?>... classes) {
+        for (Class<?> clazz:classes) {
+            acceptMatchers.add(new FullClassNameMatcher(clazz.getName()));
+        }
+
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(ClassNameMatcher m) {
+        acceptMatchers.add(m);
+        
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(Pattern pattern) {
+        acceptMatchers.add(new RegexpClassNameMatcher(pattern));
+        
+        return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(String... patterns) {
+        for (String pattern:patterns) {
+            acceptMatchers.add(new WildcardClassNameMatcher(pattern));
+        }
+        
+        return this;
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setMatchers(List<ClassNameMatcher> matchers) {
+        acceptMatchers.clear();
+        
+        for (ClassNameMatcher matcher:matchers) {
+            acceptMatchers.add(matcher);
+        }
+    }
 }
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java 
b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
index 2da89b7b3..31b34220f 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
@@ -35,8 +35,11 @@ import java.nio.charset.CharacterCodingException;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
 import java.util.EnumSet;
+import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
+import org.apache.mina.core.buffer.matcher.ClassNameMatcher;
 import org.apache.mina.core.session.IoSession;
 
 /**
@@ -2108,4 +2111,39 @@ public abstract class IoBuffer implements 
Comparable<IoBuffer> {
      * @return the modified IoBuffer
      */
     public abstract <E extends Enum<E>> IoBuffer putEnumSetLong(int index, 
Set<E> set);
+    
+    /**
+     * Accept class names where the supplied ClassNameMatcher matches for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param m the matcher to use
+     * @return this object
+     */
+    public abstract IoBuffer accept(ClassNameMatcher m);
+
+    /**
+     * Accept class names that match the supplied pattern for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param pattern standard Java regexp
+     * @return this object
+     */
+    public abstract IoBuffer accept(Pattern pattern);
+
+    /**
+     * Accept the wildcard specified classes for deserialization,
+     * unless they are otherwise rejected.
+     *
+     * @param patterns Wildcard file name patterns as defined by
+     *                  {@link 
org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) 
FilenameUtils.wildcardMatch}
+     * @return this object
+     */
+    public abstract IoBuffer accept(String... patterns);
+    
+    /**
+     * Set the list of class matchers for in incoming buffer
+     * 
+     * @param matchers The list of matchers
+     */
+    public abstract void setMatchers(List<ClassNameMatcher> matchers);
 }
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java 
b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
index 437483fb8..c59d42e07 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
@@ -33,7 +33,13 @@ import java.nio.ShortBuffer;
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
+import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.mina.core.buffer.matcher.ClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
 
 /**
  * A {@link IoBuffer} that wraps a buffer and proxies any operations to it.
@@ -1535,4 +1541,35 @@ public class IoBufferWrapper extends IoBuffer {
         buf.putUnsigned(index, value);
         return this;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(ClassNameMatcher m) {
+        return buf.accept(m);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(Pattern pattern) {
+        return buf.accept(pattern);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IoBuffer accept(String... patterns) {
+        return buf.accept(patterns);
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void setMatchers(List<ClassNameMatcher> matchers) {
+        buf.setMatchers(matchers);
+    }
 }
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/ClassNameMatcher.java
 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/ClassNameMatcher.java
new file mode 100644
index 000000000..42961beba
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/ClassNameMatcher.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+/**
+ * An object that matches a Class name to a condition.
+ */
+public interface ClassNameMatcher {
+    /**
+     * Returns {@code true} if the supplied class name matches this object's 
condition.
+     *
+     * @param className fully qualified class name
+     * @return {@code true} if the class name matches this object's condition
+     */
+    boolean matches(String className);
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FileSystem.java 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FileSystem.java
new file mode 100644
index 000000000..f76465915
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FileSystem.java
@@ -0,0 +1,527 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Abstracts an OS' file system details, currently supporting the single use 
case of converting a file name String to a
+ * legal file name with {@link #toLegalFileName(String, char)}.
+ * <p>
+ * The starting point of any operation is {@link #getCurrent()} which gets you 
the enum for the file system that matches
+ * the OS hosting the running JVM.
+ * </p>
+ *
+ * @since 2.7
+ */
+public enum FileSystem {
+
+    /**
+     * Generic file system.
+     */
+    GENERIC(4096, false, false, Integer.MAX_VALUE, Integer.MAX_VALUE, new 
int[] { 0 }, new String[] {}, false, false, '/'),
+
+    /**
+     * Linux file system.
+     */
+    LINUX(8192, true, true, 255, 4096, new int[] {
+            // KEEP THIS ARRAY SORTED!
+            // @formatter:off
+            // ASCII NUL
+            0,
+             '/'
+            // @formatter:on
+    }, new String[] {}, false, false, '/'),
+
+    /**
+     * MacOS file system.
+     */
+    MAC_OSX(4096, true, true, 255, 1024, new int[] {
+            // KEEP THIS ARRAY SORTED!
+            // @formatter:off
+            // ASCII NUL
+            0,
+            '/',
+             ':'
+            // @formatter:on
+    }, new String[] {}, false, false, '/'),
+
+    /**
+     * Windows file system.
+     * <p>
+     * The reserved characters are defined in the
+     * <a 
href="https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file";>Naming
 Conventions
+     * (microsoft.com)</a>.
+     * </p>
+     *
+     * @see <a 
href="https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file";>Naming
 Conventions
+     *      (microsoft.com)</a>
+     * @see <a 
href="https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles";>
+     *      CreateFileA function - Consoles (microsoft.com)</a>
+     */
+    WINDOWS(4096, false, true,
+            255, 32000, // KEEP THIS ARRAY SORTED!
+            new int[] {
+                    // KEEP THIS ARRAY SORTED!
+                    // @formatter:off
+                    // ASCII NUL
+                    0,
+                    // 1-31 may be allowed in file streams
+                    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+                    29, 30, 31,
+                    '"', '*', '/', ':', '<', '>', '?', '\\', '|'
+                    // @formatter:on
+            }, new String[] { "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", 
"COM6", "COM7", "COM8", "COM9", "CON", "CONIN$", "CONOUT$",
+                            "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", 
"LPT7", "LPT8", "LPT9", "NUL", "PRN" }, true, true, '\\');
+
+    /**
+     * <p>
+     * Is {@code true} if this is Linux.
+     * </p>
+     * <p>
+     * The field will return {@code false} if {@code OS_NAME} is {@code null}.
+     * </p>
+     */
+    private static final boolean IS_OS_LINUX = getOsMatchesName("Linux");
+
+    /**
+     * <p>
+     * Is {@code true} if this is Mac.
+     * </p>
+     * <p>
+     * The field will return {@code false} if {@code OS_NAME} is {@code null}.
+     * </p>
+     */
+    private static final boolean IS_OS_MAC = getOsMatchesName("Mac");
+
+    /**
+     * The prefix String for all Windows OS.
+     */
+    private static final String OS_NAME_WINDOWS_PREFIX = "Windows";
+
+    /**
+     * <p>
+     * Is {@code true} if this is Windows.
+     * </p>
+     * <p>
+     * The field will return {@code false} if {@code OS_NAME} is {@code null}.
+     * </p>
+     */
+    private static final boolean IS_OS_WINDOWS = 
getOsMatchesName(OS_NAME_WINDOWS_PREFIX);
+
+    /**
+     * The current FileSystem.
+     */
+    private static final FileSystem CURRENT = current();
+
+    /**
+     * Gets the current file system.
+     *
+     * @return the current file system
+     */
+    private static FileSystem current() {
+        if (IS_OS_LINUX) {
+            return LINUX;
+        }
+        if (IS_OS_MAC) {
+            return MAC_OSX;
+        }
+        if (IS_OS_WINDOWS) {
+            return WINDOWS;
+        }
+        return GENERIC;
+    }
+
+    /**
+     * Gets the current file system.
+     *
+     * @return the current file system
+     */
+    public static FileSystem getCurrent() {
+        return CURRENT;
+    }
+
+    /**
+     * Decides if the operating system matches.
+     *
+     * @param osNamePrefix
+     *            the prefix for the os name
+     * @return true if matches, or false if not or can't determine
+     */
+    private static boolean getOsMatchesName(final String osNamePrefix) {
+        return isOsNameMatch(getSystemProperty("os.name"), osNamePrefix);
+    }
+
+    /**
+     * <p>
+     * Gets a System property, defaulting to {@code null} if the property 
cannot be read.
+     * </p>
+     * <p>
+     * If a {@link SecurityException} is caught, the return value is {@code 
null} and a message is written to
+     * {@code System.err}.
+     * </p>
+     *
+     * @param property
+     *            the system property name
+     * @return the system property value or {@code null} if a security problem 
occurs
+     */
+    private static String getSystemProperty(final String property) {
+        try {
+            return System.getProperty(property);
+        } catch (final SecurityException ex) {
+            // we are not allowed to look at this property
+            System.err.println("Caught a SecurityException reading the system 
property '" + property
+                    + "'; the SystemUtils property value will default to 
null.");
+            return null;
+        }
+    }
+
+    /**
+     * Copied from Apache Commons Lang CharSequenceUtils.
+     *
+     * Returns the index within {@code cs} of the first occurrence of the
+     * specified character, starting the search at the specified index.
+     * <p>
+     * If a character with value {@code searchChar} occurs in the
+     * character sequence represented by the {@code cs}
+     * object at an index no smaller than {@code start}, then
+     * the index of the first such occurrence is returned. For values
+     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
+     * this is the smallest value <i>k</i> such that:
+     * </p>
+     * <blockquote><pre>
+     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= start)
+     * </pre></blockquote>
+     * is true. For other values of {@code searchChar}, it is the
+     * smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= 
start)
+     * </pre></blockquote>
+     * <p>
+     * is true. In either case, if no such character occurs inm {@code cs}
+     * at or after position {@code start}, then
+     * {@code -1} is returned.
+     * </p>
+     * <p>
+     * There is no restriction on the value of {@code start}. If it
+     * is negative, it has the same effect as if it were zero: the entire
+     * {@link CharSequence} may be searched. If it is greater than
+     * the length of {@code cs}, it has the same effect as if it were
+     * equal to the length of {@code cs}: {@code -1} is returned.
+     * </p>
+     * <p>All indices are specified in {@code char} values
+     * (Unicode code units).
+     * </p>
+     *
+     * @param cs  the {@link CharSequence} to be processed, not null
+     * @param searchChar  the char to be searched for
+     * @param start  the start index, negative starts at the string start
+     * @return the index where the search char was found, -1 if not found
+     * @since 3.6 updated to behave more like {@link String}
+     */
+    private static int indexOf(final CharSequence cs, final int searchChar, 
int start) {
+        if (cs instanceof String) {
+            return ((String) cs).indexOf(searchChar, start);
+        }
+        final int sz = cs.length();
+        if (start < 0) {
+            start = 0;
+        }
+        if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            for (int i = start; i < sz; i++) {
+                if (cs.charAt(i) == searchChar) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+        //supplementary characters (LANG1300)
+        if (searchChar <= Character.MAX_CODE_POINT) {
+            final char[] chars = Character.toChars(searchChar);
+            for (int i = start; i < sz - 1; i++) {
+                final char high = cs.charAt(i);
+                final char low = cs.charAt(i + 1);
+                if (high == chars[0] && low == chars[1]) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Decides if the operating system matches.
+     * <p>
+     * This method is package private instead of private to support unit test 
invocation.
+     * </p>
+     *
+     * @param osName
+     *            the actual OS name
+     * @param osNamePrefix
+     *            the prefix for the expected OS name
+     * @return true if matches, or false if not or can't determine
+     */
+    private static boolean isOsNameMatch(final String osName, final String 
osNamePrefix) {
+        if (osName == null) {
+            return false;
+        }
+        return 
osName.toUpperCase(Locale.ROOT).startsWith(osNamePrefix.toUpperCase(Locale.ROOT));
+    }
+
+    /**
+     * Null-safe replace.
+     *
+     * @param path the path to be changed, null ignored.
+     * @param oldChar the old character.
+     * @param newChar the new character.
+     * @return the new path.
+     */
+    private static String replace(final String path, final char oldChar, final 
char newChar) {
+        return path == null ? null : path.replace(oldChar, newChar);
+    }
+
+    private final int blockSize;
+    private final boolean casePreserving;
+    private final boolean caseSensitive;
+    private final int[] illegalFileNameChars;
+    private final int maxFileNameLength;
+    private final int maxPathLength;
+    private final String[] reservedFileNames;
+    private final boolean reservedFileNamesExtensions;
+    private final boolean supportsDriveLetter;
+    private final char nameSeparator;
+    private final char nameSeparatorOther;
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param blockSize file allocation block size in bytes.
+     * @param caseSensitive Whether this file system is case-sensitive.
+     * @param casePreserving Whether this file system is case-preserving.
+     * @param maxFileLength The maximum length for file names. The file name 
does not include folders.
+     * @param maxPathLength The maximum length of the path to a file. This can 
include folders.
+     * @param illegalFileNameChars Illegal characters for this file system.
+     * @param reservedFileNames The reserved file names.
+     * @param reservedFileNamesExtensions TODO
+     * @param supportsDriveLetter Whether this file system support driver 
letters.
+     * @param nameSeparator The name separator, '\\' on Windows, '/' on Linux.
+     */
+    FileSystem(final int blockSize, final boolean caseSensitive, final boolean 
casePreserving,
+        final int maxFileLength, final int maxPathLength, final int[] 
illegalFileNameChars,
+        final String[] reservedFileNames, final boolean 
reservedFileNamesExtensions, final boolean supportsDriveLetter, final char 
nameSeparator) {
+        this.blockSize = blockSize;
+        this.maxFileNameLength = maxFileLength;
+        this.maxPathLength = maxPathLength;
+        this.illegalFileNameChars = 
Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars");
+        this.reservedFileNames = Objects.requireNonNull(reservedFileNames, 
"reservedFileNames");
+        this.reservedFileNamesExtensions = reservedFileNamesExtensions;
+        this.caseSensitive = caseSensitive;
+        this.casePreserving = casePreserving;
+        this.supportsDriveLetter = supportsDriveLetter;
+        this.nameSeparator = nameSeparator;
+        this.nameSeparatorOther = FilenameUtils.flipSeparator(nameSeparator);
+    }
+
+    /**
+     * Gets the file allocation block size in bytes.
+     * @return the file allocation block size in bytes.
+     *
+     * @since 2.12.0
+     */
+    public int getBlockSize() {
+        return blockSize;
+    }
+
+    /**
+     * Gets a cloned copy of the illegal characters for this file system.
+     *
+     * @return the illegal characters for this file system.
+     */
+    public char[] getIllegalFileNameChars() {
+        final char[] chars = new char[illegalFileNameChars.length];
+        for (int i = 0; i < illegalFileNameChars.length; i++) {
+            chars[i] = (char) illegalFileNameChars[i];
+        }
+        return chars;
+    }
+
+    /**
+     * Gets a cloned copy of the illegal code points for this file system.
+     *
+     * @return the illegal code points for this file system.
+     * @since 2.12.0
+     */
+    public int[] getIllegalFileNameCodePoints() {
+        return this.illegalFileNameChars.clone();
+    }
+
+    /**
+     * Gets the maximum length for file names. The file name does not include 
folders.
+     *
+     * @return the maximum length for file names.
+     */
+    public int getMaxFileNameLength() {
+        return maxFileNameLength;
+    }
+
+    /**
+     * Gets the maximum length of the path to a file. This can include folders.
+     *
+     * @return the maximum length of the path to a file.
+     */
+    public int getMaxPathLength() {
+        return maxPathLength;
+    }
+
+    /**
+     * Gets the name separator, '\\' on Windows, '/' on Linux.
+     *
+     * @return '\\' on Windows, '/' on Linux.
+     *
+     * @since 2.12.0
+     */
+    public char getNameSeparator() {
+        return nameSeparator;
+    }
+
+    /**
+     * Gets a cloned copy of the reserved file names.
+     *
+     * @return the reserved file names.
+     */
+    public String[] getReservedFileNames() {
+        return reservedFileNames.clone();
+    }
+
+    /**
+     * Tests whether this file system preserves case.
+     *
+     * @return Whether this file system preserves case.
+     */
+    public boolean isCasePreserving() {
+        return casePreserving;
+    }
+
+    /**
+     * Tests whether this file system is case-sensitive.
+     *
+     * @return Whether this file system is case-sensitive.
+     */
+    public boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+    /**
+     * Tests if the given character is illegal in a file name, {@code false} 
otherwise.
+     *
+     * @param c
+     *            the character to test
+     * @return {@code true} if the given character is illegal in a file name, 
{@code false} otherwise.
+     */
+    private boolean isIllegalFileNameChar(final int c) {
+        return Arrays.binarySearch(illegalFileNameChars, c) >= 0;
+    }
+
+    /**
+     * Tests if a candidate file name (without a path) such as {@code 
"filename.ext"} or {@code "filename"} is a
+     * potentially legal file name. If the file name length exceeds {@link 
#getMaxFileNameLength()}, or if it contains
+     * an illegal character then the check fails.
+     *
+     * @param candidate
+     *            a candidate file name (without a path) like {@code 
"filename.ext"} or {@code "filename"}
+     * @return {@code true} if the candidate name is legal
+     */
+    public boolean isLegalFileName(final CharSequence candidate) {
+        if (candidate == null || candidate.length() == 0 || candidate.length() 
> maxFileNameLength) {
+            return false;
+        }
+        if (isReservedFileName(candidate)) {
+            return false;
+        }
+        return candidate.chars().noneMatch(this::isIllegalFileNameChar);
+    }
+
+    /**
+     * Tests whether the given string is a reserved file name.
+     *
+     * @param candidate
+     *            the string to test
+     * @return {@code true} if the given string is a reserved file name.
+     */
+    public boolean isReservedFileName(final CharSequence candidate) {
+        final CharSequence test = reservedFileNamesExtensions ? 
trimExtension(candidate) : candidate;
+        return Arrays.binarySearch(reservedFileNames, test) >= 0;
+    }
+
+    /**
+     * Converts all separators to the Windows separator of backslash.
+     *
+     * @param path the path to be changed, null ignored
+     * @return the updated path
+     * @since 2.12.0
+     */
+    public String normalizeSeparators(final String path) {
+        return replace(path, nameSeparatorOther, nameSeparator);
+    }
+
+    /**
+     * Tests whether this file system support driver letters.
+     * <p>
+     * Windows supports driver letters as do other operating systems. Whether 
these other OS's still support Java like
+     * OS/2, is a different matter.
+     * </p>
+     *
+     * @return whether this file system support driver letters.
+     * @since 2.9.0
+     * @see <a 
href="https://en.wikipedia.org/wiki/Drive_letter_assignment";>Operating systems 
that use drive letter
+     *      assignment</a>
+     */
+    public boolean supportsDriveLetter() {
+        return supportsDriveLetter;
+    }
+
+    /**
+     * Converts a candidate file name (without a path) like {@code 
"filename.ext"} or {@code "filename"} to a legal file
+     * name. Illegal characters in the candidate name are replaced by the 
{@code replacement} character. If the file
+     * name length exceeds {@link #getMaxFileNameLength()}, then the name is 
truncated to
+     * {@link #getMaxFileNameLength()}.
+     *
+     * @param candidate
+     *            a candidate file name (without a path) like {@code 
"filename.ext"} or {@code "filename"}
+     * @param replacement
+     *            Illegal characters in the candidate name are replaced by 
this character
+     * @return a String without illegal characters
+     */
+    public String toLegalFileName(final String candidate, final char 
replacement) {
+        if (isIllegalFileNameChar(replacement)) {
+            // %s does not work properly with NUL
+            throw new IllegalArgumentException(String.format("The replacement 
character '%s' cannot be one of the %s illegal characters: %s",
+                replacement == '\0' ? "\\0" : replacement, name(), 
Arrays.toString(illegalFileNameChars)));
+        }
+        final String truncated = candidate.length() > maxFileNameLength ? 
candidate.substring(0, maxFileNameLength) : candidate;
+        final int[] array = truncated.chars().map(i -> 
isIllegalFileNameChar(i) ? replacement : i).toArray();
+        return new String(array, 0, array.length);
+    }
+
+    CharSequence trimExtension(final CharSequence cs) {
+        final int index = indexOf(cs, '.', 0);
+        return index < 0 ? cs : cs.subSequence(0, index);
+    }
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FilenameUtils.java
 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FilenameUtils.java
new file mode 100644
index 000000000..37b780709
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FilenameUtils.java
@@ -0,0 +1,175 @@
+package org.apache.mina.core.buffer.matcher;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+
+public class FilenameUtils
+{
+    private static final int NOT_FOUND = -1;
+
+    private static final String[] EMPTY_STRING_ARRAY = {};
+
+    /**
+     * The Unix separator character.
+     */
+    private static final char UNIX_NAME_SEPARATOR = '/';
+
+    /**
+     * The Windows separator character.
+     */
+    private static final char WINDOWS_NAME_SEPARATOR = '\\';
+
+    /**
+     * Checks a fileName to see if it matches the specified wildcard matcher
+     * allowing control over case-sensitivity.
+     * <p>
+     * The wildcard matcher uses the characters '?' and '*' to represent a
+     * single or multiple (zero or more) wildcard characters.
+     * N.B. the sequence "*?" does not work properly at present in match 
strings.
+     *
+     * @param fileName  the fileName to match on
+     * @param wildcardMatcher  the wildcard string to match against
+     * @param ioCase  what case sensitivity rule to use, null means 
case-sensitive
+     * @return true if the fileName matches the wildcard string
+     * @since 1.3
+     */
+    public static boolean wildcardMatch(final String fileName, final String 
wildcardMatcher, IOCase ioCase) {
+        if (fileName == null && wildcardMatcher == null) {
+            return true;
+        }
+        if (fileName == null || wildcardMatcher == null) {
+            return false;
+        }
+        ioCase = IOCase.value(ioCase, IOCase.SENSITIVE);
+        final String[] wcs = splitOnTokens(wildcardMatcher);
+        boolean anyChars = false;
+        int textIdx = 0;
+        int wcsIdx = 0;
+        final Deque<int[]> backtrack = new ArrayDeque<>(wcs.length);
+
+        // loop around a backtrack stack, to handle complex * matching
+        do {
+            if (!backtrack.isEmpty()) {
+                final int[] array = backtrack.pop();
+                wcsIdx = array[0];
+                textIdx = array[1];
+                anyChars = true;
+            }
+
+            // loop whilst tokens and text left to process
+            while (wcsIdx < wcs.length) {
+
+                if (wcs[wcsIdx].equals("?")) {
+                    // ? so move to next text char
+                    textIdx++;
+                    if (textIdx > fileName.length()) {
+                        break;
+                    }
+                    anyChars = false;
+
+                } else if (wcs[wcsIdx].equals("*")) {
+                    // set any chars status
+                    anyChars = true;
+                    if (wcsIdx == wcs.length - 1) {
+                        textIdx = fileName.length();
+                    }
+
+                } else {
+                    // matching text token
+                    if (anyChars) {
+                        // any chars then try to locate text token
+                        textIdx = ioCase.checkIndexOf(fileName, textIdx, 
wcs[wcsIdx]);
+                        if (textIdx == NOT_FOUND) {
+                            // token not found
+                            break;
+                        }
+                        final int repeat = ioCase.checkIndexOf(fileName, 
textIdx + 1, wcs[wcsIdx]);
+                        if (repeat >= 0) {
+                            backtrack.push(new int[] {wcsIdx, repeat});
+                        }
+                    } else if (!ioCase.checkRegionMatches(fileName, textIdx, 
wcs[wcsIdx])) {
+                        // matching from current position
+                        // couldn't match token
+                        break;
+                    }
+
+                    // matched text token, move text index to end of matched 
token
+                    textIdx += wcs[wcsIdx].length();
+                    anyChars = false;
+                }
+
+                wcsIdx++;
+            }
+
+            // full match
+            if (wcsIdx == wcs.length && textIdx == fileName.length()) {
+                return true;
+            }
+
+        } while (!backtrack.isEmpty());
+
+        return false;
+    }
+
+
+    /**
+     * Splits a string into a number of tokens.
+     * The text is split by '?' and '*'.
+     * Where multiple '*' occur consecutively they are collapsed into a single 
'*'.
+     *
+     * @param text  the text to split
+     * @return the array of tokens, never null
+     */
+    static String[] splitOnTokens(final String text) {
+        // used by wildcardMatch
+        // package level so a unit test may run on this
+
+        if (text.indexOf('?') == NOT_FOUND && text.indexOf('*') == NOT_FOUND) {
+            return new String[] { text };
+        }
+
+        final char[] array = text.toCharArray();
+        final ArrayList<String> list = new ArrayList<>();
+        final StringBuilder buffer = new StringBuilder();
+        char prevChar = 0;
+        for (final char ch : array) {
+            if (ch == '?' || ch == '*') {
+                if (buffer.length() != 0) {
+                    list.add(buffer.toString());
+                    buffer.setLength(0);
+                }
+                if (ch == '?') {
+                    list.add("?");
+                } else if (prevChar != '*') {// ch == '*' here; check if 
previous char was '*'
+                    list.add("*");
+                }
+            } else {
+                buffer.append(ch);
+            }
+            prevChar = ch;
+        }
+        if (buffer.length() != 0) {
+            list.add(buffer.toString());
+        }
+
+        return list.toArray(EMPTY_STRING_ARRAY);
+    }
+
+    /**
+     * Flips the Windows name separator to Linux and vice-versa.
+     *
+     * @param ch The Windows or Linux name separator.
+     * @return The Windows or Linux name separator.
+     */
+    static char flipSeparator(final char ch) {
+        if (ch == UNIX_NAME_SEPARATOR) {
+            return WINDOWS_NAME_SEPARATOR;
+        }
+        if (ch == WINDOWS_NAME_SEPARATOR) {
+            return UNIX_NAME_SEPARATOR;
+        }
+        throw new IllegalArgumentException(String.valueOf(ch));
+    }
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FullClassNameMatcher.java
 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FullClassNameMatcher.java
new file mode 100644
index 000000000..137b9fbcd
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/FullClassNameMatcher.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A {@link ClassNameMatcher} that matches on full class names.
+ * <p>
+ * This object is immutable and thread-safe.
+ * </p>
+ */
+public final class FullClassNameMatcher implements ClassNameMatcher {
+    private final Set<String> classesSet;
+
+    /**
+     * Constructs an object based on the specified class names.
+     *
+     * @param classes a list of class names
+     */
+    public FullClassNameMatcher(String... classes) {
+        classesSet = Collections.unmodifiableSet(new 
HashSet<>(Arrays.asList(classes)));
+    }
+
+    @Override
+    public boolean matches(String className) {
+        return classesSet.contains(className);
+    }
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/IOCase.java 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/IOCase.java
new file mode 100644
index 000000000..10f481364
--- /dev/null
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/IOCase.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * Enumeration of IO case sensitivity.
+ * <p>
+ * Different filing systems have different rules for case-sensitivity.
+ * Windows is case-insensitive, Unix is case-sensitive.
+ * </p>
+ * <p>
+ * This class captures that difference, providing an enumeration to
+ * control how file name comparisons should be performed. It also provides
+ * methods that use the enumeration to perform comparisons.
+ * </p>
+ * <p>
+ * Wherever possible, you should use the {@code check} methods in this
+ * class to compare file names.
+ * </p>
+ *
+ * @since 1.3
+ */
+public enum IOCase {
+
+    /**
+     * The constant for case-sensitive regardless of operating system.
+     */
+    SENSITIVE("Sensitive", true),
+
+    /**
+     * The constant for case-insensitive regardless of operating system.
+     */
+    INSENSITIVE("Insensitive", false),
+
+    /**
+     * The constant for case sensitivity determined by the current operating 
system.
+     * Windows is case-insensitive when comparing file names, Unix is 
case-sensitive.
+     * <p>
+     * <strong>Note:</strong> This only caters for Windows and Unix. Other 
operating
+     * systems (e.g. OSX and OpenVMS) are treated as case-sensitive if they 
use the
+     * Unix file separator and case-insensitive if they use the Windows file 
separator
+     * (see {@link java.io.File#separatorChar}).
+     * </p>
+     * <p>
+     * If you serialize this constant on Windows, and deserialize on Unix, or 
vice
+     * versa, then the value of the case-sensitivity flag will change.
+     * </p>
+     */
+    SYSTEM("System", FileSystem.getCurrent().isCaseSensitive());
+
+    /** Serialization version. */
+    private static final long serialVersionUID = -6343169151696340687L;
+
+    /**
+     * Factory method to create an IOCase from a name.
+     *
+     * @param name  the name to find
+     * @return the IOCase object
+     * @throws IllegalArgumentException if the name is invalid
+     */
+    public static IOCase forName(final String name) {
+        return Stream.of(IOCase.values()).filter(ioCase -> 
ioCase.getName().equals(name)).findFirst()
+                .orElseThrow(() -> new IllegalArgumentException("Illegal 
IOCase name: " + name));
+    }
+
+    /**
+     * Tests for cases sensitivity in a null-safe manner.
+     *
+     * @param ioCase an IOCase.
+     * @return true if the input is non-null and {@link #isCaseSensitive()}.
+     * @since 2.10.0
+     */
+    public static boolean isCaseSensitive(final IOCase ioCase) {
+        return ioCase != null && ioCase.isCaseSensitive();
+    }
+
+    /**
+     * Returns the given value if not-null, the defaultValue if null.
+     *
+     * @param value the value to test.
+     * @param defaultValue the default value.
+     * @return the given value if not-null, the defaultValue if null.
+     * @since 2.12.0
+     */
+    public static IOCase value(final IOCase value, final IOCase defaultValue) {
+        return value != null ? value : defaultValue;
+    }
+
+    /** The enumeration name. */
+    private final String name;
+
+    /** The sensitivity flag. */
+    private final transient boolean sensitive;
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param name  the name
+     * @param sensitive  the sensitivity
+     */
+    IOCase(final String name, final boolean sensitive) {
+        this.name = name;
+        this.sensitive = sensitive;
+    }
+
+    /**
+     * Compares two strings using the case-sensitivity rule.
+     * <p>
+     * This method mimics {@link String#compareTo} but takes case-sensitivity
+     * into account.
+     * </p>
+     *
+     * @param str1  the first string to compare, not null
+     * @param str2  the second string to compare, not null
+     * @return true if equal using the case rules
+     * @throws NullPointerException if either string is null
+     */
+    public int checkCompareTo(final String str1, final String str2) {
+        Objects.requireNonNull(str1, "str1");
+        Objects.requireNonNull(str2, "str2");
+        return sensitive ? str1.compareTo(str2) : 
str1.compareToIgnoreCase(str2);
+    }
+
+    /**
+     * Checks if one string ends with another using the case-sensitivity rule.
+     * <p>
+     * This method mimics {@link String#endsWith} but takes case-sensitivity
+     * into account.
+     * </p>
+     *
+     * @param str  the string to check
+     * @param end  the end to compare against
+     * @return true if equal using the case rules, false if either input is 
null
+     */
+    public boolean checkEndsWith(final String str, final String end) {
+        if (str == null || end == null) {
+            return false;
+        }
+        final int endLen = end.length();
+        return str.regionMatches(!sensitive, str.length() - endLen, end, 0, 
endLen);
+    }
+
+    /**
+     * Compares two strings using the case-sensitivity rule.
+     * <p>
+     * This method mimics {@link String#equals} but takes case-sensitivity
+     * into account.
+     * </p>
+     *
+     * @param str1  the first string to compare, not null
+     * @param str2  the second string to compare, not null
+     * @return true if equal using the case rules
+     * @throws NullPointerException if either string is null
+     */
+    public boolean checkEquals(final String str1, final String str2) {
+        Objects.requireNonNull(str1, "str1");
+        Objects.requireNonNull(str2, "str2");
+        return sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
+    }
+
+    /**
+     * Checks if one string contains another starting at a specific index 
using the
+     * case-sensitivity rule.
+     * <p>
+     * This method mimics parts of {@link String#indexOf(String, int)}
+     * but takes case-sensitivity into account.
+     * </p>
+     *
+     * @param str  the string to check, not null
+     * @param strStartIndex  the index to start at in str
+     * @param search  the start to search for, not null
+     * @return the first index of the search String,
+     *  -1 if no match or {@code null} string input
+     * @throws NullPointerException if either string is null
+     * @since 2.0
+     */
+    public int checkIndexOf(final String str, final int strStartIndex, final 
String search) {
+        final int endIndex = str.length() - search.length();
+        if (endIndex >= strStartIndex) {
+            for (int i = strStartIndex; i <= endIndex; i++) {
+                if (checkRegionMatches(str, i, search)) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Checks if one string contains another at a specific index using the 
case-sensitivity rule.
+     * <p>
+     * This method mimics parts of {@link String#regionMatches(boolean, int, 
String, int, int)}
+     * but takes case-sensitivity into account.
+     * </p>
+     *
+     * @param str  the string to check, not null
+     * @param strStartIndex  the index to start at in str
+     * @param search  the start to search for, not null
+     * @return true if equal using the case rules
+     * @throws NullPointerException if either string is null
+     */
+    public boolean checkRegionMatches(final String str, final int 
strStartIndex, final String search) {
+        return str.regionMatches(!sensitive, strStartIndex, search, 0, 
search.length());
+    }
+
+    /**
+     * Checks if one string starts with another using the case-sensitivity 
rule.
+     * <p>
+     * This method mimics {@link String#startsWith(String)} but takes 
case-sensitivity
+     * into account.
+     * </p>
+     *
+     * @param str  the string to check
+     * @param start  the start to compare against
+     * @return true if equal using the case rules, false if either input is 
null
+     */
+    public boolean checkStartsWith(final String str, final String start) {
+        return str != null && start != null && str.regionMatches(!sensitive, 
0, start, 0, start.length());
+    }
+
+    /**
+     * Gets the name of the constant.
+     *
+     * @return the name of the constant
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Does the object represent case-sensitive comparison.
+     *
+     * @return true if case-sensitive
+     */
+    public boolean isCaseSensitive() {
+        return sensitive;
+    }
+
+    /**
+     * Replaces the enumeration from the stream with a real one.
+     * This ensures that the correct flag is set for SYSTEM.
+     *
+     * @return the resolved object
+     */
+    private Object readResolve() {
+        return forName(name);
+    }
+
+    /**
+     * Gets a string describing the sensitivity.
+     *
+     * @return a string describing the sensitivity
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/RegexpClassNameMatcher.java
 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/RegexpClassNameMatcher.java
new file mode 100644
index 000000000..909d9c56e
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/RegexpClassNameMatcher.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+/**
+ * A {@link ClassNameMatcher} that uses regular expressions.
+ * <p>
+ * This object is immutable and thread-safe.
+ * </p>
+ */
+public final class RegexpClassNameMatcher implements ClassNameMatcher {
+    private final Pattern pattern; // Class is thread-safe
+
+    /**
+     * Constructs an object based on the specified pattern.
+     *
+     * @param pattern a pattern for evaluating acceptable class names
+     * @throws NullPointerException if {@code pattern} is null
+     */
+    public RegexpClassNameMatcher(Pattern pattern) {
+        this.pattern = Objects.requireNonNull(pattern, "pattern");
+    }
+
+    /**
+     * Constructs an object based on the specified regular expression.
+     *
+     * @param regex a regular expression for evaluating acceptable class names
+     */
+    public RegexpClassNameMatcher(String regex) {
+        this(Pattern.compile(regex));
+    }
+
+    @Override
+    public boolean matches(String className) {
+        return pattern.matcher(className).matches();
+    }
+}
+
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/WildcardClassNameMatcher.java
 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/WildcardClassNameMatcher.java
new file mode 100644
index 000000000..a7b80f30a
--- /dev/null
+++ 
b/mina-core/src/main/java/org/apache/mina/core/buffer/matcher/WildcardClassNameMatcher.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.mina.core.buffer.matcher;
+
+/**
+ * A {@link ClassNameMatcher} that uses simplified regular expressions
+ *  provided by {@link 
org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) 
FilenameUtils.wildcardMatch}
+ * <p>
+ * This object is immutable and thread-safe.
+ * </p>
+ */
+public final class WildcardClassNameMatcher implements ClassNameMatcher {
+
+    private final String pattern;
+
+    /**
+     * Constructs an object based on the specified simplified regular 
expression.
+     *
+     * @param pattern a {@link FilenameUtils#wildcardMatch} pattern.
+     */
+    public WildcardClassNameMatcher(String pattern) {
+        this.pattern = pattern;
+    }
+
+    @Override
+    public boolean matches(String className) {
+        return FilenameUtils.wildcardMatch(className, pattern, 
IOCase.SENSITIVE);
+    }
+}
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java 
b/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
index 524dfa0e7..860f1eb12 100644
--- 
a/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
+++ 
b/mina-core/src/main/java/org/apache/mina/core/session/AbstractIoSession.java
@@ -304,6 +304,7 @@ public abstract class AbstractIoSession implements 
IoSession {
     /**
      * {@inheritDoc}
      */
+     @Deprecated
     public final CloseFuture close(boolean rightNow) {
         if (rightNow) {
             return closeNow();
@@ -315,6 +316,7 @@ public abstract class AbstractIoSession implements 
IoSession {
     /**
      * {@inheritDoc}
      */
+     @Deprecated
     public final CloseFuture close() {
         return closeNow();
     }
diff --git 
a/mina-core/src/main/java/org/apache/mina/core/write/DefaultWriteRequest.java 
b/mina-core/src/main/java/org/apache/mina/core/write/DefaultWriteRequest.java
index 49fe96120..429e9cae5 100644
--- 
a/mina-core/src/main/java/org/apache/mina/core/write/DefaultWriteRequest.java
+++ 
b/mina-core/src/main/java/org/apache/mina/core/write/DefaultWriteRequest.java
@@ -65,6 +65,7 @@ public class DefaultWriteRequest implements WriteRequest {
         /**
          * {@inheritDoc}
          */
+        @Deprecated
         @Override
         public void join() {
             // Do nothing
@@ -73,6 +74,7 @@ public class DefaultWriteRequest implements WriteRequest {
         /**
          * {@inheritDoc}
          */
+        @Deprecated
         @Override
         public boolean join(long timeoutInMillis) {
             return true;
@@ -315,4 +317,4 @@ public class DefaultWriteRequest implements WriteRequest {
     public boolean isEncoded() {
         return false;
     }
-}
\ No newline at end of file
+}
diff --git 
a/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationCodecFactory.java
 
b/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationCodecFactory.java
index d48dddab5..7e0a61907 100644
--- 
a/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationCodecFactory.java
+++ 
b/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationCodecFactory.java
@@ -19,7 +19,12 @@
  */
 package org.apache.mina.filter.codec.serialization;
 
+import java.util.regex.Pattern;
+
 import org.apache.mina.core.buffer.BufferDataException;
+import org.apache.mina.core.buffer.matcher.ClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;
 import org.apache.mina.filter.codec.ProtocolDecoder;
@@ -122,4 +127,37 @@ public class ObjectSerializationCodecFactory implements 
ProtocolCodecFactory {
     public void setDecoderMaxObjectSize(int maxObjectSize) {
         decoder.setMaxObjectSize(maxObjectSize);
     }
+
+    /**
+     * Accept class names where the supplied ClassNameMatcher matches for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param classNameMatcher the matcher to use
+     */
+    public void accept(ClassNameMatcher classNameMatcher) {
+        decoder.accept(classNameMatcher);
+    }
+
+    /**
+     * Accept class names that match the supplied pattern for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param pattern standard Java regexp
+     */
+    public void accept(Pattern pattern) {
+        decoder.accept(new RegexpClassNameMatcher(pattern));
+    }
+
+    /**
+     * Accept the wildcard specified classes for deserialization,
+     * unless they are otherwise rejected.
+     *
+     * @param patterns Wildcard file name patterns as defined by
+     *                  {@link 
org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) 
FilenameUtils.wildcardMatch}
+     */
+    public void accept(String... patterns) {
+        for (String pattern:patterns) {
+            decoder.accept(new WildcardClassNameMatcher(pattern));
+        }
+    }
 }
diff --git 
a/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationDecoder.java
 
b/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationDecoder.java
index 542fb422e..a45d929fb 100644
--- 
a/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationDecoder.java
+++ 
b/mina-core/src/main/java/org/apache/mina/filter/codec/serialization/ObjectSerializationDecoder.java
@@ -20,9 +20,15 @@
 package org.apache.mina.filter.codec.serialization;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
 
 import org.apache.mina.core.buffer.BufferDataException;
 import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.buffer.matcher.ClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
 import org.apache.mina.filter.codec.ProtocolDecoder;
@@ -39,6 +45,9 @@ public class ObjectSerializationDecoder extends 
CumulativeProtocolDecoder {
 
     private int maxObjectSize = 1048576; // 1MB
 
+    /** The classes we accept when deserializing a binary blob */
+    private final List<ClassNameMatcher> acceptMatchers = new ArrayList<>();
+
     /**
      * Creates a new instance with the {@link ClassLoader} of
      * the current thread.
@@ -93,8 +102,43 @@ public class ObjectSerializationDecoder extends 
CumulativeProtocolDecoder {
         if (!in.prefixedDataAvailable(4, maxObjectSize)) {
             return false;
         }
+        
+        in.setMatchers(acceptMatchers);
 
         out.write(in.getObject(classLoader));
         return true;
     }
+
+    /**
+     * Accept class names where the supplied ClassNameMatcher matches for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param classNameMatcher the matcher to use
+     */
+    public void accept(ClassNameMatcher classNameMatcher) {
+        acceptMatchers.add(classNameMatcher);
+    }
+
+    /**
+     * Accept class names that match the supplied pattern for
+     * deserialization, unless they are otherwise rejected.
+     *
+     * @param pattern standard Java regexp
+     */
+    public void accept(Pattern pattern) {
+        acceptMatchers.add(new RegexpClassNameMatcher(pattern));
+    }
+
+    /**
+     * Accept the wildcard specified classes for deserialization,
+     * unless they are otherwise rejected.
+     *
+     * @param patterns Wildcard file name patterns as defined by
+     *                  {@link 
org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) 
FilenameUtils.wildcardMatch}
+     */
+    public void accept(String... patterns) {
+        for (String pattern:patterns) {
+            acceptMatchers.add(new WildcardClassNameMatcher(pattern));
+        }
+    }
 }
diff --git 
a/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java 
b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
index db99c337b..ef59a3703 100644
--- a/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
+++ b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferTest.java
@@ -41,6 +41,8 @@ import java.util.Date;
 import java.util.EnumSet;
 import java.util.List;
 
+import org.apache.mina.core.buffer.matcher.RegexpClassNameMatcher;
+import org.apache.mina.core.buffer.matcher.WildcardClassNameMatcher;
 import org.apache.mina.util.Bar;
 import org.junit.Test;
 
@@ -374,6 +376,7 @@ public class IoBufferTest {
         List<Object> o = new ArrayList<>();
         o.add(new Date());
         o.add(long.class);
+        buf.accept(ArrayList.class.getName(), Date.class.getName(), 
long.class.getName());
 
         // Test writing an object.
         buf.putObject(o);
@@ -389,12 +392,53 @@ public class IoBufferTest {
 
     @Test
     public void testNonserializableClass() throws Exception {
-        Class<?> c = NonserializableClass.class;
+        Class<?> c = String.class;
 
         IoBuffer buffer = IoBuffer.allocate(16);
         buffer.setAutoExpand(true);
         buffer.putObject(c);
 
+        // Accept the String class
+        buffer.accept(String.class.getName());
+
+        buffer.flip();
+        Object o = buffer.getObject();
+
+        assertEquals(c, o);
+        assertSame(c, o);
+    }
+
+    @Test
+    public void testNonserializableClassAcceptWildcard() throws Exception {
+        Class<?> c = String.class;
+
+        IoBuffer buffer = IoBuffer.allocate(16);
+        buffer.setAutoExpand(true);
+        buffer.putObject(c);
+        
+        // Accept all classes which name starts with 'java.lan'
+        // That includes 'java.lang.String'
+        buffer.accept(new WildcardClassNameMatcher("java.lan*"));
+
+        buffer.flip();
+        Object o = buffer.getObject();
+
+        assertEquals(c, o);
+        assertSame(c, o);
+    }
+    
+    @Test
+    public void testNonserializableClassAcceptRegexp() throws Exception {
+        Class<?> c = String.class;
+
+        IoBuffer buffer = IoBuffer.allocate(16);
+        buffer.setAutoExpand(true);
+        buffer.putObject(c);
+        
+        // Accept all class which contains '.lang.' in their name
+        // That includes java.lang.String
+        buffer.accept(new RegexpClassNameMatcher(".*\\.lang\\..*"));
+
         buffer.flip();
         Object o = buffer.getObject();
 
@@ -402,6 +446,21 @@ public class IoBufferTest {
         assertSame(c, o);
     }
 
+    @Test(expected=ClassNotFoundException.class)
+    public void testNonserializableClassReject() throws Exception {
+        Class<?> c = String.class;
+
+        IoBuffer buffer = IoBuffer.allocate(16);
+        buffer.setAutoExpand(true);
+        buffer.putObject(c);
+        // Don't accept the java.lang.String class
+
+        buffer.flip();
+        
+        // Should throw an exception
+        buffer.getObject();
+    }
+
     @Test
     public void testNonserializableInterface() throws Exception {
         Class<?> c = NonserializableInterface.class;
@@ -409,6 +468,7 @@ public class IoBufferTest {
         IoBuffer buffer = IoBuffer.allocate(16);
         buffer.setAutoExpand(true);
         buffer.putObject(c);
+        buffer.accept(NonserializableInterface.class.getName());
 
         buffer.flip();
         Object o = buffer.getObject();
@@ -949,6 +1009,7 @@ public class IoBufferTest {
 
         // Test writing an object.
         buf.putObject(expected);
+        buf.accept(Bar.class.getName());
 
         // Test reading an object.
         buf.clear();
diff --git a/mina-example/pom.xml b/mina-example/pom.xml
index b2364ab0b..e6f5495be 100644
--- a/mina-example/pom.xml
+++ b/mina-example/pom.xml
@@ -80,5 +80,16 @@
       <artifactId>jcl-over-slf4j</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+      <version>4.0</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>com.nqzero</groupId>
+      <artifactId>permit-reflect</artifactId>
+      <version>0.3</version>
+    </dependency>
   </dependencies>
 </project>
diff --git a/mina-legal/pom.xml b/mina-legal/pom.xml
index d8ad65cd7..a881c25de 100644
--- a/mina-legal/pom.xml
+++ b/mina-legal/pom.xml
@@ -70,8 +70,8 @@
     </dependency>
 
     <dependency>
-      <groupId>pmd</groupId>
-      <artifactId>pmd</artifactId>
+      <groupId>net.sourceforge.pmd</groupId>
+      <artifactId>pmd-core</artifactId>
     </dependency>
   </dependencies>
 </project>
diff --git a/pom.xml b/pom.xml
index e8984a134..a7aeb47f3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
   </parent>
 
   <prerequisites>
-    <maven>3.5.0</maven>
+    <maven>3.8.5</maven>
   </prerequisites>
 
   <organization>
@@ -100,13 +100,14 @@
     <version.build.helper.plugin>3.6.0</version.build.helper.plugin>
     <version.bundle.plugin>5.1.9</version.bundle.plugin>
     <version.changes.plugin>2.12.1</version.changes.plugin>
-    <version.checkstyle.plugin>3.5.0</version.checkstyle.plugin>
+    <version.checkstyle.plugin>3.6.0</version.checkstyle.plugin>
     <version.clean.plugin>3.4.0</version.clean.plugin>
     <version.clirr.plugin>2.8</version.clirr.plugin>
     <version.cobertura.plugin>2.7</version.cobertura.plugin>
     <version.compiler.plugin>3.13.0</version.compiler.plugin>
+    <version.cyclonedx.plugin>2.9.0</version.cyclonedx.plugin>
     <version.dashboard.plugin>1.0.0-beta-1</version.dashboard.plugin>
-    <version.dependency.plugin>3.8.0</version.dependency.plugin>
+    <version.dependency.plugin>3.8.1</version.dependency.plugin>
     <version.deploy.plugin>3.1.3</version.deploy.plugin>
     <version.docck.plugin>1.2</version.docck.plugin>
     <version.eclipse.plugin>2.10</version.eclipse.plugin>
@@ -116,25 +117,26 @@
     <version.install.plugin>3.1.3</version.install.plugin>
     <version.jar.plugin>3.4.2</version.jar.plugin>
     <version.javancss.plugin>2.1</version.javancss.plugin>
-    <version.javadoc.plugin>3.10.1</version.javadoc.plugin>
+    <version.javadoc.plugin>3.11.1</version.javadoc.plugin>
     <version.jdepend.plugin>2.1</version.jdepend.plugin>
-    <version.jxr.plugin>3.5.0</version.jxr.plugin>
+    <version.jxr.plugin>3.6.0</version.jxr.plugin>
     <version.model.plugin>3.9.4</version.model.plugin>
     <version.plexus.utils>4.0.0</version.plexus.utils>
     <version.plugin.plugin>4.0.0-beta-1</version.plugin.plugin>
-    <version.pmd.plugin>3.25.0</version.pmd.plugin>
+    <version.pmd.plugin>3.26.0</version.pmd.plugin>
     <version.project.plugin>3.0-alpha-2</version.project.plugin>
-    
<version.project.info.report.plugin>3.7.0</version.project.info.report.plugin>
+    
<version.project.info.report.plugin>3.8.0</version.project.info.report.plugin>
     <version.rat.maven.plugin>1.0-alpha-3</version.rat.maven.plugin>
     <version.release.plugin>3.1.1</version.release.plugin>
     <version.remote.resources.plugin>3.2.0</version.remote.resources.plugin>
+    <version.replacer.plugin>1.5.3</version.replacer.plugin>
     <version.resources.plugin>3.3.1</version.resources.plugin>
     <version.scm.plugin>2.1.0</version.scm.plugin>
     <version.site.plugin>4.0.0-M16</version.site.plugin>
     <version.source.plugin>3.3.1</version.source.plugin>
     <version.shade.plugin>3.5.0</version.shade.plugin>
-    <version.surefire.plugin>3.5.1</version.surefire.plugin>
-    <version.surfire.report.plugin>3.5.1</version.surfire.report.plugin>
+    <version.surefire.plugin>3.5.2</version.surefire.plugin>
+    <version.surfire.report.plugin>3.5.2</version.surfire.report.plugin>
     <version.taglist.plugin>3.2.1</version.taglist.plugin>
     <version.tools.maven.plugin>1.4</version.tools.maven.plugin>
     <version.versions.plugin>2.17.1</version.versions.plugin>
@@ -149,7 +151,7 @@
     <version.log4j>1.2.17</version.log4j>
     <!-- DO NOT CHANGE. Breaks the build with more recent versions -->
     <version.ognl>3.3.4</version.ognl>
-    <version.pmd>4.3</version.pmd>
+    <version.pmd>7.7.0</version.pmd>
     <version.rmock>2.0.2</version.rmock>
     <version.slf4j.api>1.7.36</version.slf4j.api>
     <version.slf4j.reload4j>1.7.36</version.slf4j.reload4j>
@@ -298,8 +300,8 @@
       </dependency>
 
       <dependency>
-        <groupId>pmd</groupId>
-        <artifactId>pmd</artifactId>
+        <groupId>net.sourceforge.pmd</groupId>
+        <artifactId>pmd-core</artifactId>
         <version>${version.pmd}</version>
       </dependency>
 
@@ -403,10 +405,7 @@
                 <goals>
                   <goal>javadoc</goal>
                 </goals>
-                <configuration>
-                  <aggregate>true</aggregate>
-                  <!-- additionalparam>-Xdoclint:none</additionalparam -->
-                </configuration>
+                <configuration/>
               </execution>
             </executions>
           </plugin>
@@ -418,6 +417,16 @@
       </modules>
     </profile>
 
+    <!-- use JDK8 compilation for JDK9+ compiler -->
+    <profile>
+      <id>java-8-compilation</id>
+      <activation>
+        <jdk>[11,)</jdk>
+      </activation>
+      <properties>
+        <maven.compiler.release>8</maven.compiler.release>
+      </properties>
+    </profile>
   </profiles>
   
   <build>
@@ -458,9 +467,10 @@
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>${version.compiler.plugin}</version>
-          <configuration>
-            <showDeprecations>true</showDeprecations>
-            <encoding>ISO-8859-1</encoding>
+          <configuration>$a
+            <debug>true</debug>
+            <showDeprecation>true</showDeprecation>
+            <encoding>UTF-8</encoding>
           </configuration>
         </plugin>
 
@@ -736,12 +746,19 @@
           <artifactId>taglist-maven-plugin</artifactId>
           <version>${version.taglist.plugin}</version>
           <configuration>
-            <tags>
-              <tag>TODO</tag>
-              <tag>@todo</tag>
-              <tag>@deprecated</tag>
-              <tag>FIXME</tag>
-            </tags>
+            <tagListOptions>
+              <tagClasses>>
+                <tagClass>
+                  <displayName>Documentation Work</displayName>
+                  <tags>
+                    <tag>TODO</tag>
+                    <tag>@todo</tag>
+                    <tag>@deprecated</tag>
+                    <tag>FIXME</tag>
+                  </tags>
+                </tagClass>
+              </tagClasses>
+            </tagListOptions>
           </configuration>
         </plugin>
 
@@ -751,29 +768,21 @@
           <version>${version.versions.plugin}</version>
         </plugin>
 
-        <!--This plugin's configuration is used to store Eclipse m2e settings 
only. It has no influence on the Maven build itself.-->
         <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <version>1.0.0</version>
+          <groupId>org.cyclonedx</groupId>
+          <artifactId>cyclonedx-maven-plugin</artifactId>
+          <version>${version.cyclonedx.plugin}</version>
+          <executions>
+            <execution>
+              <id>make-bom</id>
+              <phase>package</phase>
+              <goals>
+                <goal>makeAggregateBom</goal>
+              </goals>
+            </execution>
+          </executions>
           <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.apache.xbean</groupId>
-                    <artifactId>maven-xbean-plugin</artifactId>
-                    <versionRange>[4.12,)</versionRange>
-                    <goals>
-                      <goal>mapping</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore />
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
+            
<outputName>${project.artifactId}-${project.version}-bom</outputName>
           </configuration>
         </plugin>
       </plugins>
@@ -785,7 +794,7 @@
         <configuration>
           <encoding>UTF-8</encoding>
           <debug>true</debug>
-          <showDeprecations>true</showDeprecations>
+          <showDeprecation>true</showDeprecation>
         </configuration>
       </plugin>
 
@@ -884,7 +893,6 @@
         <version>${version.javadoc.plugin}</version>
         <inherited>false</inherited>
         <configuration>
-          <aggregate>true</aggregate>
           <breakiterator>true</breakiterator>
           <charset>UTF-8</charset>
           <docencoding>UTF-8</docencoding>
@@ -895,7 +903,6 @@
           <links>
             <link>http://java.sun.com/j2se/1.5.0/docs/api/</link>
             <link>http://www.slf4j.org/api/</link>
-            
<link>http://static.springframework.org/spring/docs/2.0.x/api/</link>
           </links>
           <locale>en_US</locale>
         </configuration>
@@ -907,28 +914,12 @@
         <version>${version.jxr.plugin}</version>
         <inherited>false</inherited>
         <configuration>
-          <aggregate>true</aggregate>
           <inputEncoding>UTF-8</inputEncoding>
           <outputEncoding>UTF-8</outputEncoding>
           <windowTitle>Apache MINA ${project.version} Cross 
Reference</windowTitle>
           <docTitle>Apache MINA ${project.version} Cross Reference</docTitle>
         </configuration>
       </plugin>
-
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>rat-maven-plugin</artifactId>
-        <version>${version.rat.maven.plugin}</version>
-        <configuration>
-          <excludes>
-            <exclude>**/target/**/*</exclude>
-            <exclude>**/.*</exclude>
-            <exclude>**/NOTICE.txt</exclude>
-            <exclude>**/LICENSE*.txt</exclude>
-          </excludes>
-          <excludeSubProjects>false</excludeSubProjects>
-        </configuration>
-      </plugin>
     </plugins>
   </reporting>
 </project>

Reply via email to