[tomcat] branch master updated: Add an experimental minimal distribution to be published

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[tomcat] branch master updated: Add an experimental minimal distribution to be published

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

fhanik pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new a9eae94  Add an experimental minimal distribution to be published
a9eae94 is described below

commit a9eae944f0f906b9b5375ac25a796404a1f51095
Author: Filip Hanik <[hidden email]>
AuthorDate: Mon Jul 27 13:35:03 2020 -0700

    Add an experimental minimal distribution to be published
   
    - For usage with optimized for size Java and GraalVM native compilation images
    - Maven groupId is set to org.apache.tomcat.experimental to classify it during evaluation of viability
    - Does not ship as part of the standard Apache Tomcat library and sources
---
 build.xml                                          | 343 +++++++++++++++-
 .../org/apache/tomcat/util/IntrospectionUtils.java |   7 +
 .../tomcat/util/XReflectionIntrospectionUtils.java |  33 ++
 res/graal/build-tomcat-native-image.sh             |   3 +-
 .../ObjectReflectionPropertyInspector.java         | 281 +++++++++++++
 .../xreflection/ReflectionLessCodeGenerator.java   | 273 +++++++++++++
 .../util/xreflection/ReflectionProperty.java       | 119 ++++++
 .../tomcat/util/xreflection/SetPropertyClass.java  | 436 +++++++++++++++++++++
 .../native-image/native-image.properties           |  16 +
 .../native-image/tomcat-reflection.json            |   2 +
 .../native-image/tomcat-resource.json              |  51 +++
 res/maven/mvn-pub.xml                              |  10 +
 res/maven/tomcat-embed-programmatic.pom            |  35 ++
 .../apache/catalina/startup/EmbeddedTomcat.java    |   4 +-
 14 files changed, 1609 insertions(+), 4 deletions(-)

diff --git a/build.xml b/build.xml
index cf79946..41441e4 100644
--- a/build.xml
+++ b/build.xml
@@ -157,11 +157,13 @@
 
   <!-- Embedded JARs & source JARs -->
   <property name="tomcat-embed-core.jar" value="${tomcat.embed}/tomcat-embed-core.jar"/>
+  <property name="tomcat-embed-programmatic.jar" value="${tomcat.embed}/tomcat-embed-programmatic.jar"/>
   <property name="tomcat-embed-jasper.jar" value="${tomcat.embed}/tomcat-embed-jasper.jar"/>
   <property name="tomcat-embed-el.jar" value="${tomcat.embed}/tomcat-embed-el.jar"/>
   <property name="tomcat-embed-websocket.jar" value="${tomcat.embed}/tomcat-embed-websocket.jar"/>
 
   <property name="tomcat-embed-core-sources.jar" value="${tomcat.embed.sources}/tomcat-embed-core-src.jar"/>
+  <property name="tomcat-embed-programmatic-sources.jar" value="${tomcat.embed.sources}/tomcat-embed-programmatic-src.jar"/>
   <property name="tomcat-embed-jasper-sources.jar" value="${tomcat.embed.sources}/tomcat-embed-jasper-src.jar"/>
   <property name="tomcat-embed-el-sources.jar" value="${tomcat.embed.sources}/tomcat-embed-el-src.jar"/>
   <property name="tomcat-embed-websocket-sources.jar" value="${tomcat.embed.sources}/tomcat-embed-websocket-src.jar"/>
@@ -431,6 +433,268 @@
     <exclude name="org/apache/catalina/ssi/**" />
   </patternset>
 
+  <patternset id="files.tomcat-embed-programmatic">
+    <patternset refid="files.jaspic-api" />
+    <patternset refid="files.tomcat-juli" />
+
+    <!-- Servlet -->
+    <include name="jakarta/servlet/**" />
+    <include name="jakarta/servlet/annotation/**" />
+    <include name="jakarta/servlet/http/**" />
+    <exclude name="jakarta/servlet/descriptor/**" />
+    <exclude name="jakarta/servlet/jsp/**"/>
+    <exclude name="jakarta/servlet/resources/**" />
+
+    <!-- AprLifecycleListener is configured by default -->
+    <include name="**/AprLifecycleListener.*"/>
+    <include name="**/AprStatus.*"/>
+
+    <!-- Remove dynamic mbean descriptors -->
+    <exclude name="**/mbeans-descriptors.xml"/>
+    <exclude name="**/mbeans-descriptors.dtd"/>
+    <!-- No JMX Support - But we can't remove the classes -->
+    <include name="org/apache/tomcat/util/modeler/LocalStrings.properties" />
+    <include name="org/apache/tomcat/util/modeler/AttributeInfo*" />
+    <include name="org/apache/tomcat/util/modeler/BaseModelMBean*" />
+    <include name="org/apache/tomcat/util/modeler/FeatureInfo*" />
+    <include name="org/apache/tomcat/util/modeler/ManagedBean*" />
+    <include name="org/apache/tomcat/util/modeler/NoDescriptorRegistry*" />
+    <include name="org/apache/tomcat/util/modeler/NotificationInfo*" />
+    <include name="org/apache/tomcat/util/modeler/Registry*" />
+    <include name="org/apache/tomcat/util/modeler/RegistryMBean*" />
+    <include name="org/apache/tomcat/util/modeler/Util*" />
+    <include name="org/apache/tomcat/util/modeler/modules/ModelerSource*" />
+
+    <!-- Apache Tomcat Core Code -->
+    <include name="org/apache/catalina/*"/>
+    <include name="org/apache/catalina/authenticator/**"/>
+    <include name="org/apache/catalina/connector/**"/>
+    <include name="org/apache/catalina/core/**"/>
+    <include name="org/apache/catalina/deploy/**"/>
+    <include name="org/apache/catalina/filters/**"/>
+    <include name="org/apache/catalina/loader/**"/>
+    <include name="org/apache/catalina/mapper/**"/>
+    <include name="org/apache/catalina/mbeans/**"/>
+    <include name="org/apache/catalina/realm/**"/>
+    <include name="org/apache/catalina/security/**"/>
+    <include name="org/apache/catalina/session/**"/>
+    <include name="org/apache/catalina/startup/**"/>
+    <include name="org/apache/catalina/util/**"/>
+    <include name="org/apache/catalina/valves/*"/>
+    <include name="org/apache/catalina/webresources/**"/>
+    <include name="org/apache/coyote/**" />
+    <include name="org/apache/naming/**" />
+    <include name="org/apache/tomcat/*" />
+    <include name="org/apache/tomcat/util/*" />
+    <include name="org/apache/tomcat/util/bcel/**" />
+    <include name="org/apache/tomcat/util/buf/**" />
+    <include name="org/apache/tomcat/util/codec/**" />
+    <include name="org/apache/tomcat/util/collections/**" />
+    <include name="org/apache/tomcat/util/compat/**" />
+    <include name="org/apache/tomcat/util/descriptor/**" />
+    <include name="org/apache/tomcat/util/file/**" />
+    <include name="org/apache/tomcat/util/http/**" />
+    <include name="org/apache/tomcat/util/json/**" />
+    <include name="org/apache/tomcat/util/log/**" />
+    <include name="org/apache/tomcat/util/net/**" />
+    <include name="org/apache/tomcat/util/res/**" />
+    <include name="org/apache/tomcat/util/security/**" />
+    <include name="org/apache/tomcat/util/threads/**" />
+
+    <!-- Some of the core code depends on the jar scanner -->
+    <include name="org/apache/tomcat/util/scan/StandardJarScan*" />
+    <include name="org/apache/tomcat/util/scan/LocalStrings.properties" />
+
+    <!-- Minimize JNI to what doesn't throw an error -->
+    <include name="org/apache/tomcat/jni/Library.class" />
+    <include name="org/apache/tomcat/jni/LibraryNotFoundError*" />
+    <exclude name="org/apache/tomcat/jni" />
+
+    <!-- Remove connectors that are not default -->
+    <exclude name="**/AbstractAjpProtocol.class"/>
+    <exclude name="**/Ajp*.class"/>
+    <exclude name="**/AjpApr*.class"/>
+    <exclude name="**/Http11Apr*.class"/>
+    <exclude name="**/Http11Nio2*.class"/>
+    <exclude name="**/JniLifecycleListener.class"/>
+    <exclude name="org/apache/tomcat/**/*Nio2*.class"/>
+    <exclude name="org/apache/tomcat/**/Apr*.class"/>
+
+    <!-- Minimize bundles to the default set -->
+    <exclude name="org/apache/**/LocalStrings_*.properties"/>
+
+    <!-- Remove digester support -->
+    <exclude name="org/apache/catalina/**/*Rule.class" />
+    <exclude name="org/apache/catalina/**/*RuleSet*.class" />
+    <exclude name="org/apache/tomcat/**/*RuleSet*.class" />
+
+    <!-- Remove various Apache Tomcat modules not used by default in an embedded setting -->
+    <exclude name="org/apache/catalina/ant/**" />
+    <exclude name="org/apache/catalina/ha/**" />
+    <exclude name="org/apache/catalina/manager/**" />
+    <exclude name="org/apache/catalina/ssi/**" />
+    <exclude name="org/apache/catalina/storeconfig/**" />
+    <exclude name="org/apache/catalina/tribes/**" />
+    <exclude name="org/apache/catalina/valves/rewrite/**" />
+    <exclude name="org/apache/tomcat/buildutil" />
+    <exclude name="org/apache/tomcat/dbcp" />
+
+    <!-- Remove authenticator classes -->
+    <exclude name="org/apache/catalina/authenticator/BasicAuthenticator*" />
+    <exclude name="org/apache/catalina/authenticator/DigestAuthenticator*" />
+    <exclude name="org/apache/catalina/authenticator/FormAuthenticator*" />
+    <exclude name="org/apache/catalina/authenticator/SingleSignOnE*" />
+    <exclude name="org/apache/catalina/authenticator/SingleSignOnL*" />
+    <exclude name="org/apache/catalina/authenticator/SingleSignOnS*" />
+    <exclude name="org/apache/catalina/authenticator/Spnego*" />
+    <exclude name="org/apache/catalina/authenticator/SSLAuthenticator*" />
+    <exclude name="org/apache/catalina/authenticator/jaspcic/Simple*" />
+
+    <!-- Remove optional filter classes -->
+    <exclude name="org/apache/catalina/filters/**" />
+
+    <!-- Remove Realm classes -->
+    <exclude name="org/apache/catalina/realm/AuthenticatedUserRealm.class" />
+    <exclude name="org/apache/catalina/realm/CombinedRealm.class" />
+    <exclude name="org/apache/catalina/realm/DataSourceRealm.class" />
+    <exclude name="org/apache/catalina/realm/JAASCallbackHandler.class" />
+    <exclude name="org/apache/catalina/realm/JAASMemoryLoginModule.class" />
+    <exclude name="org/apache/catalina/realm/JAASRealm.class" />
+    <exclude name="org/apache/catalina/realm/JDBCRealm.class" />
+    <exclude name="org/apache/catalina/realm/JNDIRealm$User.class" />
+    <exclude name="org/apache/catalina/realm/JNDIRealm.class" />
+    <exclude name="org/apache/catalina/realm/LockOutRealm*" />
+    <exclude name="org/apache/catalina/realm/MemoryRealm.class" />
+    <exclude name="org/apache/catalina/realm/NestedCredentialHandler.class" />
+    <exclude name="org/apache/catalina/realm/UserDatabaseRealm.class" />
+
+    <!-- Remove optional servlets -->
+    <exclude name="org/apache/catalina/servlets/**" />
+
+    <!-- Remove all but the standard session management -->
+    <exclude name="org/apache/catalina/session/JDBC*" />
+    <exclude name="org/apache/catalina/session/File*" />
+    <exclude name="org/apache/catalina/session/Persistent*" />
+    <exclude name="org/apache/catalina/session/StoreBase*" />
+
+    <!-- Remove users -->
+    <exclude name="org/apache/catalina/users/**" />
+
+    <!-- Remove optional valves -->
+    <exclude name="org/apache/catalina/valves/Crawler*" />
+    <exclude name="org/apache/catalina/valves/ExtendedAccessLogValve*" />
+    <exclude name="org/apache/catalina/valves/ExtendedAccessLogValve*" />
+    <exclude name="org/apache/catalina/valves/HealthCheckValve*" />
+    <exclude name="org/apache/catalina/valves/JDBCAccessLogValve*" />
+    <exclude name="org/apache/catalina/valves/LoadBalancerDrainingValve*" />
+    <exclude name="org/apache/catalina/valves/PersistentValve*" />
+
+    <!-- Remove web resources classes, default is the EmptyResourceSet -->
+    <exclude name="org/apache/catalina/webresources/AbstractArchiveResource*" />
+    <exclude name="org/apache/catalina/webresources/AbstractSingleArchiveResource*" />
+    <exclude name="org/apache/catalina/webresources/ExtractingRoot*" />
+    <exclude name="org/apache/catalina/webresources/FileResource*" />
+    <exclude name="org/apache/catalina/webresources/JarResource*" />
+    <exclude name="org/apache/catalina/webresources/JarWarResource*" />
+    <exclude name="org/apache/catalina/webresources/TomcatJarInputStream*" />
+    <exclude name="org/apache/catalina/webresources/TrackedInputStream*" />
+    <exclude name="org/apache/catalina/webresources/VirtualResource*" />
+    <exclude name="org/apache/catalina/webresources/WarResource*" />
+    <exclude name="org/apache/catalina/webresources/WarResource*" />
+    <exclude name="org/apache/catalina/webresources/war/WarURLConnection*" />
+
+    <!-- Remove most JNDI stuff -->
+    <exclude name="org/apache/naming/EjbRef*" />
+    <exclude name="org/apache/naming/factory/BeanFactory*" />
+    <exclude name="org/apache/naming/factory/DataSourceLinkFactory*" />
+    <exclude name="org/apache/naming/factory/EjbFactory*" />
+    <exclude name="org/apache/naming/factory/LookupFactory*" />
+    <exclude name="org/apache/naming/factory/MailSessionFactory*" />
+    <exclude name="org/apache/naming/factory/OpenEjbFactory*" />
+    <exclude name="org/apache/naming/factory/ResourceEnvFactory*" />
+    <exclude name="org/apache/naming/factory/ResourceFactory*" />
+    <exclude name="org/apache/naming/factory/ResourceLinkFactory*" />
+    <exclude name="org/apache/naming/factory/SendMailFactory*" />
+    <exclude name="org/apache/naming/factory/TransactionFactory*" />
+    <exclude name="org/apache/naming/factory/webservices/*" />
+    <exclude name="org/apache/naming/LookupRef*" />
+    <exclude name="org/apache/naming/NameParserImpl*" />
+    <exclude name="org/apache/naming/NamingContextBindingsEnumeration*" />
+    <exclude name="org/apache/naming/NamingContext*" />
+    <exclude name="org/apache/naming/NamingContextEnumeration*" />
+    <exclude name="org/apache/naming/NamingEntry*" />
+    <exclude name="org/apache/naming/ResourceEnvRef*" />
+    <exclude name="org/apache/naming/ResourceLinkRef*" />
+    <exclude name="org/apache/naming/ResourceRef*" />
+    <exclude name="org/apache/naming/SelectorContext*" />
+    <exclude name="org/apache/naming/ServiceRef*" />
+    <exclude name="org/apache/naming/TransactionRef*" />
+
+    <!-- remove BCEL support -->
+    <exclude name="org/apache/tomcat/util/bcel/**" />
+
+    <!-- remove web descriptor elements -->
+    <exclude name="org/apache/tomcat/util/descriptor/DigesterFactory*" />
+    <exclude name="org/apache/tomcat/util/descriptor/InputSourceUtil*" />
+    <exclude name="org/apache/tomcat/util/descriptor/LocalResolver*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/AbsoluteOrderingRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/CallMethodMultiRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/CallParamMultiRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ContextHandler*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ContextResourceLink*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ContextTransaction*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/FragmentJarScannerCallback*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/IgnoreAnnotationsRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/InjectionTarget*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/JspConfigDescriptorImpl*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/JspPropertyGroup*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/JspPropertyGroupDescriptorImpl*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/LifecycleCallbackRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/MappedNameRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/MultipartDef*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/NameRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/RelativeOrderingRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SecurityCollection*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SecurityRoleRef*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ServiceQnameRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ServletDef*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/ServletDefCreateRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SessionConfig*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetAuthConstraintRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetDenyUncoveredHttpMethodsRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetDistributableRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetJspConfig*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetLoginConfig*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetOverrideRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetPublicIdRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SetSessionConfig*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/SoapHeaderRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/TaglibDescriptorImpl*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/TaglibLocationRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/VersionRule*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/WebXml*" />
+    <exclude name="org/apache/tomcat/util/descriptor/web/WebXmlParser*" />
+    <exclude name="org/apache/tomcat/util/descriptor/XmlErrorHandler*" />
+    <exclude name="org/apache/tomcat/util/descriptor/XmlIdentifiers*" />
+
+    <!-- remove taglibrary support -->
+    <exclude name="org/apache/tomcat/util/descriptor/tagplugin/**"/>
+    <exclude name="org/apache/tomcat/util/descriptor/tld/**"/>
+
+    <!-- Remove Digester Support -->
+    <exclude name="org/apache/tomcat/util/digester/**"/>
+
+    <!-- TODO - For now, remove SSL until we have an example -->
+    <exclude name="org/apache/tomcat/util/net/jsse/**"/>
+    <exclude name="org/apache/tomcat/util/net/openssl/**"/>
+
+    <!-- Remove without-reflection code generator -->
+    <exclude name="org/apache/tomcat/util/xreflection/**" />
+
+    <!-- Remove DefaultServlet -->
+    <exclude name="org/apache/catalina/servlets/DefaultServlet*.*" />
+  </patternset>
+
   <patternset id="files.catalina-tribes">
     <include name="org/apache/catalina/tribes/**" />
   </patternset>
@@ -1445,9 +1709,86 @@
 
   </target>
 
+  <target name="embed-programmatic-jar" description="Create non reflection embedded jar"
+          depends="embed-jars,embed-sources">
+
+    <!-- temporary directory to store the generated code -->
+    <tempfile property="xreflect.directory" destDir="${java.io.tmpdir}" prefix="apache-tomcat-xreflect-"/>
+    <echo>Generating Reflection Less Introspection to: ${xreflect.directory}</echo>
+    <mkdir dir="${xreflect.directory}"/>
+    <copy todir="${xreflect.directory}/sources">
+      <fileset dir="java"/>
+      <fileset dir="res/graal/java"/>
+    </copy>
+    <copy todir="${xreflect.directory}/classes">
+      <fileset dir="${tomcat.classes}"/>
+    </copy>
+
+    <!-- Compile the sources needed to generate XReflectionIntrospectionUtils -->
+    <javac includes="org/apache/tomcat/util/xreflection/*.java"
+           srcdir="${xreflect.directory}/sources"
+           destdir="${xreflect.directory}/classes"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           target="${compile.target}"
+           encoding="ISO-8859-1"
+           includeAntRuntime="true" >
+      <compilerarg value="-XDignore.symbol.file"/>
+      <classpath refid="compile.classpath" />
+    </javac>
+
+    <!-- Generate the reflection less XReflectionIntrospectionUtils .java file -->
+    <java classname="org.apache.tomcat.util.xreflection.ObjectReflectionPropertyInspector"
+          classpath="${xreflect.directory}/classes">
+      <arg value="${xreflect.directory}/sources"/>
+    </java>
+
+    <!-- Compile the generated XReflectionIntrospectionUtils.java class -->
+    <delete file="${xreflect.directory}/classes/org/apache/tomcat/util/XReflectionIntrospectionUtils.class"/>
+    <javac includes="org/apache/tomcat/util/XReflectionIntrospectionUtils.java"
+           srcdir="${xreflect.directory}/sources"
+           destdir="${xreflect.directory}/classes"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           target="${compile.target}"
+           encoding="ISO-8859-1"
+           includeAntRuntime="true" >
+      <compilerarg value="-XDignore.symbol.file"/>
+      <classpath refid="compile.classpath" />
+    </javac>
+
+    <!-- Create the binary JAR file -->
+    <jarIt jarfile="${tomcat-embed-programmatic.jar}"
+           filesDir="${xreflect.directory}/classes"
+           filesId="files.tomcat-embed-programmatic"
+           notice="${tomcat.manifests}/servlet-api.jar.notice"
+           license="${tomcat.manifests}/servlet-api.jar.license"
+           addOSGi="false"
+           addGraal="true"
+           graalPrefix="org.apache.tomcat.embed/tomcat-embed-programmatic"
+           graalFiles="res/graal/tomcat-embed-programmatic/native-image"
+           libs="embed/*.jar"/>
+
+    <!-- Create the source JAR file -->
+    <jarIt jarfile="${tomcat-embed-programmatic-sources.jar}"
+           filesDir="${xreflect.directory}/sources"
+           filesId="files.tomcat-embed-programmatic"
+           notice="${tomcat.manifests}/servlet-api.jar.notice"
+           license="${tomcat.manifests}/servlet-api.jar.license"/>
+
+    <!-- Leave generated code in an easy place for review -->
+    <copy todir="${java.io.tmpdir}"
+          file="${xreflect.directory}/sources/org/apache/tomcat/util/XReflectionIntrospectionUtils.java"
+          overwrite="true"/>
+    <!-- Delete our temporary compilation directory -->
+    <delete dir="${xreflect.directory}"/>
+  </target>
+
   <target name="embed"
           description="Creates the experimental embedded release"
-          depends="embed-jars,embed-sources" >
+          depends="embed-jars,embed-sources,embed-programmatic-jar" >
 
     <fixcrlf srcdir="${tomcat.embed}" eol="crlf"
         encoding="ISO-8859-1" fixlast="false" >
diff --git a/java/org/apache/tomcat/util/IntrospectionUtils.java b/java/org/apache/tomcat/util/IntrospectionUtils.java
index 78ab66f..a6bc510 100644
--- a/java/org/apache/tomcat/util/IntrospectionUtils.java
+++ b/java/org/apache/tomcat/util/IntrospectionUtils.java
@@ -60,6 +60,10 @@ public final class IntrospectionUtils {
             log.debug("IntrospectionUtils: setProperty(" +
                     o.getClass() + " " + name + "=" + value + ")");
 
+        if (actualMethod == null && XReflectionIntrospectionUtils.isEnabled()) {
+            return XReflectionIntrospectionUtils.setPropertyInternal(o, name, value, invokeSetProperty);
+        }
+
         String setter = "set" + capitalize(name);
 
         try {
@@ -222,6 +226,9 @@ public final class IntrospectionUtils {
     }
 
     public static Object getProperty(Object o, String name) {
+        if (XReflectionIntrospectionUtils.isEnabled()) {
+            return XReflectionIntrospectionUtils.getPropertyInternal(o, name);
+        }
         String getter = "get" + capitalize(name);
         String isGetter = "is" + capitalize(name);
 
diff --git a/java/org/apache/tomcat/util/XReflectionIntrospectionUtils.java b/java/org/apache/tomcat/util/XReflectionIntrospectionUtils.java
new file mode 100644
index 0000000..88de048
--- /dev/null
+++ b/java/org/apache/tomcat/util/XReflectionIntrospectionUtils.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.tomcat.util;
+
+final class XReflectionIntrospectionUtils {
+
+    static boolean isEnabled() {
+        return false;
+    }
+
+    static Object getPropertyInternal(Object o, String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    static boolean setPropertyInternal(Object o, String name, String value, boolean invokeSetProperty) {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/res/graal/build-tomcat-native-image.sh b/res/graal/build-tomcat-native-image.sh
index cbc0db1..ec99d53 100755
--- a/res/graal/build-tomcat-native-image.sh
+++ b/res/graal/build-tomcat-native-image.sh
@@ -51,11 +51,12 @@ native-image \
 --initialize-at-run-time=org.apache,jakarta.servlet \
 -H:+TraceClassInitialization \
 -H:+PrintClassInitialization \
+-H:+PrintAnalysisCallTree \
 -H:Name=tc-graal-image \
 -H:+ReportExceptionStackTraces \
 --allow-incomplete-classpath \
 --no-fallback \
--cp ../embed/tomcat-embed-core.jar:../embed/tomcat-embed-websocket.jar:../embed/tomcat-embed-el.jar:tomcat-embedded-sample.jar:../embed/annotations-api.jar \
+-cp ../embed/tomcat-embed-programmatic.jar:tomcat-embedded-sample.jar \
 org.apache.catalina.startup.EmbeddedTomcat
 
 cd $CURDIR
\ No newline at end of file
diff --git a/res/graal/java/org/apache/tomcat/util/xreflection/ObjectReflectionPropertyInspector.java b/res/graal/java/org/apache/tomcat/util/xreflection/ObjectReflectionPropertyInspector.java
new file mode 100644
index 0000000..5f2ebb3
--- /dev/null
+++ b/res/graal/java/org/apache/tomcat/util/xreflection/ObjectReflectionPropertyInspector.java
@@ -0,0 +1,281 @@
+/*
+ * 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.tomcat.util.xreflection;
+
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+public final class ObjectReflectionPropertyInspector {
+
+    public static void main(String... args) throws Exception {
+        if (args.length == 0) {
+            System.err.println("Usage:\n\t"+
+                "org.apache.tomcat.util.xreflection.ObjectReflectionPropertyInspector" +
+                " <destination directory>"
+            );
+            System.exit(1);
+        }
+
+        File outputDir = new File(args[0]);
+        if (!outputDir.exists() || !outputDir.isDirectory()) {
+            System.err.println("Invalid output directory: "+ outputDir.getAbsolutePath());
+            System.exit(1);
+        }
+
+
+        Set<SetPropertyClass> baseClasses = getKnownClasses()
+            .stream()
+            .map(c -> processClass(c))
+            .collect(Collectors.toSet());
+        generateCode(
+            baseClasses,
+            "org.apache.tomcat.util",
+            outputDir,
+            "XReflectionIntrospectionUtils"
+        );
+    }
+
+    private static final Set<Class<?>> getKnownClasses() throws ClassNotFoundException {
+        return
+            Collections.unmodifiableSet(new HashSet<>(
+                    Arrays.asList(
+                        Class.forName("org.apache.catalina.authenticator.jaspic.SimpleAuthConfigProvider"),
+                        Class.forName("org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations$Property"),
+                        Class.forName("org.apache.catalina.authenticator.jaspic.PersistentProviderRegistrations$Provider"),
+                        Class.forName("org.apache.catalina.connector.Connector"),
+                        Class.forName("org.apache.catalina.core.AprLifecycleListener"),
+                        Class.forName("org.apache.catalina.core.ContainerBase"),
+                        Class.forName("org.apache.catalina.core.StandardContext"),
+                        Class.forName("org.apache.catalina.core.StandardEngine"),
+                        Class.forName("org.apache.catalina.core.StandardHost"),
+                        Class.forName("org.apache.catalina.core.StandardServer"),
+                        Class.forName("org.apache.catalina.core.StandardService"),
+                        Class.forName("org.apache.catalina.filters.AddDefaultCharsetFilter"),
+                        Class.forName("org.apache.catalina.filters.RestCsrfPreventionFilter"),
+                        Class.forName("org.apache.catalina.loader.ParallelWebappClassLoader"),
+                        Class.forName("org.apache.catalina.loader.WebappClassLoaderBase"),
+                        Class.forName("org.apache.catalina.realm.UserDatabaseRealm"),
+                        Class.forName("org.apache.catalina.valves.AccessLogValve"),
+                        Class.forName("org.apache.coyote.AbstractProtocol"),
+                        Class.forName("org.apache.coyote.ajp.AbstractAjpProtocol"),
+                        Class.forName("org.apache.coyote.ajp.AjpAprProtocol"),
+                        Class.forName("org.apache.coyote.ajp.AjpNio2Protocol"),
+                        Class.forName("org.apache.coyote.ajp.AjpNioProtocol"),
+                        Class.forName("org.apache.coyote.http11.AbstractHttp11JsseProtocol"),
+                        Class.forName("org.apache.coyote.http11.AbstractHttp11Protocol"),
+                        Class.forName("org.apache.coyote.http11.Http11AprProtocol"),
+                        Class.forName("org.apache.coyote.http11.Http11Nio2Protocol"),
+                        Class.forName("org.apache.coyote.http11.Http11NioProtocol"),
+                        Class.forName("org.apache.tomcat.util.descriptor.web.ContextResource"),
+                        Class.forName("org.apache.tomcat.util.descriptor.web.ResourceBase"),
+                        Class.forName("org.apache.tomcat.util.modeler.AttributeInfo"),
+                        Class.forName("org.apache.tomcat.util.modeler.FeatureInfo"),
+                        Class.forName("org.apache.tomcat.util.modeler.ManagedBean"),
+                        Class.forName("org.apache.tomcat.util.modeler.OperationInfo"),
+                        Class.forName("org.apache.tomcat.util.modeler.ParameterInfo"),
+                        Class.forName("org.apache.tomcat.util.net.AbstractEndpoint"),
+                        Class.forName("org.apache.tomcat.util.net.AprEndpoint"),
+                        Class.forName("org.apache.tomcat.util.net.Nio2Endpoint"),
+                        Class.forName("org.apache.tomcat.util.net.NioEndpoint"),
+                        Class.forName("org.apache.tomcat.util.net.SocketProperties")
+                    )
+                )
+            );
+    }
+
+    //types of properties that IntrospectionUtils.setProperty supports
+    private static final Set<Class<?>> ALLOWED_TYPES = Collections.unmodifiableSet(new HashSet<>(
+        Arrays.asList(
+            Boolean.TYPE,
+            Integer.TYPE,
+            Long.TYPE,
+            String.class,
+            InetAddress.class
+        )
+    ));
+    private static Map<Class<?>, SetPropertyClass> classes = new HashMap<>();
+
+    public static void generateCode(Set<SetPropertyClass> baseClasses, String packageName, File location, String className) throws Exception {
+        String packageDirectory = packageName.replace('.','/');
+        File sourceFileLocation = new File(location, packageDirectory);
+        ReflectionLessCodeGenerator.generateCode(sourceFileLocation, className, packageName, baseClasses);
+    }
+
+
+    private static boolean isAllowedField(Field field) {
+        return ALLOWED_TYPES.contains(field.getType()) && !Modifier.isFinal(field.getModifiers());
+    }
+
+    private static boolean isAllowedSetMethod(Method method) {
+        return method.getName().startsWith("set") &&
+            method.getParameterTypes() != null &&
+            method.getParameterTypes().length == 1 &&
+            ALLOWED_TYPES.contains(method.getParameterTypes()[0]) &&
+            !Modifier.isPrivate(method.getModifiers());
+    }
+
+    private static boolean isAllowedGetMethod(Method method) {
+        return (method.getName().startsWith("get") || method.getName().startsWith("is")) &&
+            (method.getParameterTypes() == null ||
+            method.getParameterTypes().length == 0) &&
+            ALLOWED_TYPES.contains(method.getReturnType()) &&
+            !Modifier.isPrivate(method.getModifiers());
+    }
+
+
+    private static SetPropertyClass getOrCreateSetPropertyClass(Class<?> clazz) {
+        boolean base = (clazz.getSuperclass() == null || clazz.getSuperclass() == Object.class);
+        SetPropertyClass spc = classes.get(clazz);
+        if (spc == null) {
+            spc = new SetPropertyClass(clazz, base ? null : getOrCreateSetPropertyClass(clazz.getSuperclass()));
+            classes.put(clazz, spc);
+        }
+        return spc;
+    }
+
+    static Method findGetter(Class<?> declaringClass, String propertyName) {
+        for (String getterName : Arrays.asList("get" + IntrospectionUtils.capitalize(propertyName), "is" + propertyName)) {
+            try {
+                Method method = declaringClass.getMethod(getterName);
+                if (!Modifier.isPrivate(method.getModifiers())) {
+                    return method;
+                }
+            } catch (NoSuchMethodException e) {
+            }
+        }
+        try {
+            Method method = declaringClass.getMethod("getProperty", String.class, String.class);
+            if (!Modifier.isPrivate(method.getModifiers())) {
+                return method;
+            }
+        } catch (NoSuchMethodException e) {
+        }
+
+        return null;
+    }
+
+    static Method findSetter(Class<?> declaringClass, String propertyName, Class<?> propertyType) {
+        try {
+            Method method = declaringClass.getMethod("set" + IntrospectionUtils.capitalize(propertyName), propertyType);
+            if (!Modifier.isPrivate(method.getModifiers())) {
+                return method;
+            }
+        } catch (NoSuchMethodException e) {
+        }
+        try {
+            Method method = declaringClass.getMethod("setProperty", String.class, String.class);
+            if (!Modifier.isPrivate(method.getModifiers())) {
+                return method;
+            }
+        } catch (NoSuchMethodException e) {
+        }
+        return null;
+    }
+
+    static String decapitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
+            Character.isUpperCase(name.charAt(0))) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toLowerCase(chars[0]);
+        return new String(chars);
+    }
+
+
+    static SetPropertyClass processClass(Class<?> clazz) {
+        SetPropertyClass spc = getOrCreateSetPropertyClass(clazz);
+        final Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (isAllowedSetMethod(method)) {
+                String propertyName = decapitalize(method.getName().substring(3));
+                Class<?> propertyType = method.getParameterTypes()[0];
+                Method getter = findGetter(clazz, propertyName);
+                Method setter = findSetter(clazz, propertyName, propertyType);
+                ReflectionProperty property = new ReflectionProperty(
+                    spc.getClazz().getName(),
+                    propertyName,
+                    propertyType,
+                    setter,
+                    getter
+                );
+                spc.addProperty(property);
+            } else if (isAllowedGetMethod(method)) {
+                boolean startsWithIs = method.getName().startsWith("is");
+                String propertyName = decapitalize(method.getName().substring(startsWithIs ? 2 : 3));
+                Class<?> propertyType = method.getReturnType();
+                Method getter = findGetter(clazz, propertyName);
+                Method setter = findSetter(clazz, propertyName, propertyType);
+                ReflectionProperty property = new ReflectionProperty(
+                    spc.getClazz().getName(),
+                    propertyName,
+                    propertyType,
+                    setter,
+                    getter
+                );
+                spc.addProperty(property);
+            }
+        }
+
+        final Field[] fields = clazz.getDeclaredFields();
+        for (Field field : fields) {
+            if (isAllowedField(field)) {
+                Method getter = findGetter(
+                    field.getDeclaringClass(),
+                    IntrospectionUtils.capitalize(field.getName())
+                );
+                Method setter = findSetter(
+                    field.getDeclaringClass(),
+                    IntrospectionUtils.capitalize(field.getName()),
+                    field.getType()
+                );
+                ReflectionProperty property = new ReflectionProperty(
+                    spc.getClazz().getName(),
+                    field.getName(),
+                    field.getType(),
+                    setter,
+                    getter
+                );
+                spc.addProperty(property);
+            }
+        }
+
+        if (!spc.isBaseClass()) {
+            SetPropertyClass parent = getOrCreateSetPropertyClass(spc.getClazz().getSuperclass());
+            parent.addSubClass(spc);
+            return processClass(parent.getClazz());
+        } else {
+            return spc;
+        }
+    }
+}
diff --git a/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionLessCodeGenerator.java b/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionLessCodeGenerator.java
new file mode 100644
index 0000000..a06d78d
--- /dev/null
+++ b/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionLessCodeGenerator.java
@@ -0,0 +1,273 @@
+/*
+ * 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.tomcat.util.xreflection;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Set;
+
+final class ReflectionLessCodeGenerator {
+    private static final String INDENT = "    ";
+
+    static StringBuilder getIndent(int multiplier) {
+        StringBuilder indent = new StringBuilder();
+        while ((multiplier--) > 0) {
+            indent.append(INDENT);
+        }
+        return indent;
+    }
+
+    static void generateCode(
+        File directory,
+        String className,
+        String packageName,
+        Set<SetPropertyClass> baseClasses
+    ) throws IOException {
+        //begin - class
+        StringBuilder code = new StringBuilder(AL20_HEADER)
+            .append("package ")
+            .append(packageName)
+            .append(";")
+            .append(System.lineSeparator())
+            .append(System.lineSeparator())
+            .append("final class ")
+            .append(className)
+            .append(" {")
+            .append(System.lineSeparator())
+            .append(System.lineSeparator());
+
+        //begin - isEnabled method
+        code.append(getIndent(1))
+            .append("static boolean isEnabled() {")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("return true;")
+            .append(System.lineSeparator())
+            .append(getIndent(1))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(System.lineSeparator())
+        ;
+        //end - isEnabled method
+
+        //begin - getInetAddress method
+        code.append(getIndent(1))
+            .append("private static java.net.InetAddress getInetAddress(String value) {")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("try {")
+            .append(System.lineSeparator())
+            .append(getIndent(3))
+            .append("return java.net.InetAddress.getByName(value);")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("} catch (java.net.UnknownHostException x) { throw new RuntimeException(x); }")
+            .append(System.lineSeparator())
+            .append(getIndent(1))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(System.lineSeparator())
+            ;
+        //end - getInetAddress method
+
+        //begin - getPropertyInternal method
+        code.append(getIndent(1))
+            .append("static Object getPropertyInternal(Object ")
+            .append(SetPropertyClass.OBJECT_VAR_NAME)
+            .append(", String ")
+            .append(SetPropertyClass.NAME_VAR_NAME)
+            .append(") {")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("Class<?> checkThisClass = o.getClass();")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("Object result = null;")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("while (checkThisClass != Object.class && result == null) {")
+            .append(System.lineSeparator())
+            .append(getIndent(3))
+            .append("switch (checkThisClass.getName()) {")
+            .append(System.lineSeparator());
+
+        //generate case statements for getPropertyInternal
+        generateCaseStatementsForGetPropertyInternal(baseClasses, code);
+
+
+        code
+            .append(getIndent(3))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(getIndent(3))
+            .append("checkThisClass = checkThisClass.getSuperclass();")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("return result;")
+            .append(System.lineSeparator())
+            .append(getIndent(1))
+            .append("}")
+            .append(System.lineSeparator());
+        //end - getPropertyInternal method
+
+        //begin - getPropertyForXXX methods
+        generateGetPropertyForMethods(baseClasses, code);
+        //end - getPropertyForXXX methods
+
+        //begin - setPropertyInternal method
+        code.append(getIndent(1))
+            .append("static boolean setPropertyInternal(Object ")
+            .append(SetPropertyClass.OBJECT_VAR_NAME)
+            .append(", String ")
+            .append(SetPropertyClass.NAME_VAR_NAME)
+            .append(", String ")
+            .append(SetPropertyClass.VALUE_VAR_NAME)
+            .append(", boolean ")
+            .append(SetPropertyClass.SETP_VAR_NAME)
+            .append(") {")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("Class<?> checkThisClass = o.getClass();")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("while (checkThisClass != Object.class) {")
+            .append(System.lineSeparator())
+            .append(getIndent(3))
+            .append("switch (checkThisClass.getName()) {")
+            .append(System.lineSeparator());
+
+        //generate case statements for setPropertyInternal
+        generateCaseStatementsForSetPropertyInternal(baseClasses, code);
+
+
+        code
+            .append(getIndent(3))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(getIndent(3))
+            .append("checkThisClass = checkThisClass.getSuperclass();")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("}")
+            .append(System.lineSeparator())
+            .append(getIndent(2))
+            .append("return false;")
+            .append(System.lineSeparator())
+            .append(getIndent(1))
+            .append("}")
+            .append(System.lineSeparator());
+        //end - setPropertyInternal method
+
+        //begin - setPropertyForXXX methods
+        generateSetPropertyForMethods(baseClasses, code);
+        //end - setPropertyForXXX methods
+
+        code.append("}")
+            .append(System.lineSeparator());
+        //end - class
+        File destination = new File(directory, className+".java");
+        BufferedWriter writer = new BufferedWriter(new FileWriter(destination, false));
+        writer.write(code.toString());
+        writer.flush();
+        writer.close();
+
+    }
+
+    private static void generateCaseStatementForSetPropertyInternal(SetPropertyClass clazz, StringBuilder code) {
+        for (SetPropertyClass child : clazz.getChildren()) {
+            generateCaseStatementForSetPropertyInternal(child, code);
+        }
+        if (!clazz.isAbstract()) {
+            code.append(clazz.generateInvocationSetForPropertyCaseStatement(4));
+        }
+    }
+
+    private static void generateCaseStatementsForSetPropertyInternal(Set<SetPropertyClass> baseClasses, StringBuilder code) {
+        for (SetPropertyClass clazz : baseClasses) {
+            generateCaseStatementForSetPropertyInternal(clazz, code);
+        }
+    }
+
+    private static void generateSetPropertyForMethod(SetPropertyClass clazz, StringBuilder code) {
+        for (SetPropertyClass child : clazz.getChildren()) {
+            generateSetPropertyForMethod(child, code);
+        }
+        code.append(clazz.generateSetPropertyForMethod())
+            .append(System.lineSeparator())
+            .append(System.lineSeparator());
+    }
+
+    private static void generateSetPropertyForMethods(Set<SetPropertyClass> baseClasses, StringBuilder code) {
+        for (SetPropertyClass clazz : baseClasses) {
+            generateSetPropertyForMethod(clazz, code);
+        }
+    }
+
+
+
+    private static void generateCaseStatementForGetPropertyInternal(SetPropertyClass clazz, StringBuilder code) {
+        for (SetPropertyClass child : clazz.getChildren()) {
+            generateCaseStatementForGetPropertyInternal(child, code);
+        }
+        if (!clazz.isAbstract()) {
+            code.append(clazz.generateInvocationGetForPropertyCaseStatement(4));
+        }
+    }
+
+    private static void generateCaseStatementsForGetPropertyInternal(Set<SetPropertyClass> baseClasses, StringBuilder code) {
+        for (SetPropertyClass clazz : baseClasses) {
+            generateCaseStatementForGetPropertyInternal(clazz, code);
+        }
+    }
+
+    private static void generateGetPropertyForMethod(SetPropertyClass clazz, StringBuilder code) {
+        for (SetPropertyClass child : clazz.getChildren()) {
+            generateGetPropertyForMethod(child, code);
+        }
+        code.append(clazz.generateGetPropertyForMethod())
+            .append(System.lineSeparator())
+            .append(System.lineSeparator());
+    }
+
+    private static void generateGetPropertyForMethods(Set<SetPropertyClass> baseClasses, StringBuilder code) {
+        for (SetPropertyClass clazz : baseClasses) {
+            generateGetPropertyForMethod(clazz, code);
+        }
+    }
+
+    private static final String AL20_HEADER = "/*\n" +
+        " * Licensed to the Apache Software Foundation (ASF) under one or more\n" +
+        " * contributor license agreements.  See the NOTICE file distributed with\n" +
+        " * this work for additional information regarding copyright ownership.\n" +
+        " * The ASF licenses this file to You under the Apache License, Version 2.0\n" +
+        " * (the \"License\"); you may not use this file except in compliance with\n" +
+        " * the License.  You may obtain a copy of the License at\n" +
+        " *\n" +
+        " *      http://www.apache.org/licenses/LICENSE-2.0\n" +
+        " *\n" +
+        " * Unless required by applicable law or agreed to in writing, software\n" +
+        " * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+        " * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+        " * See the License for the specific language governing permissions and\n" +
+        " * limitations under the License.\n" +
+        " */\n";
+}
diff --git a/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionProperty.java b/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionProperty.java
new file mode 100644
index 0000000..f74f7c0
--- /dev/null
+++ b/res/graal/java/org/apache/tomcat/util/xreflection/ReflectionProperty.java
@@ -0,0 +1,119 @@
+/*
+ * 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.tomcat.util.xreflection;
+
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+
+final class ReflectionProperty {
+    private final String clazz;
+    private final String propertyName;
+    private final Class<?> propertyType;
+    private final Method setMethod;
+    private final Method getMethod;
+
+    ReflectionProperty(String clazz, String propertyName, Class<?> propertyType, Method setMethod, Method getMethod) {
+        this.clazz = clazz;
+        this.propertyName = propertyName;
+        this.propertyType = propertyType;
+        this.setMethod = setMethod;
+        this.getMethod = getMethod;
+    }
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    public Class<?> getPropertyType() {
+        return propertyType;
+    }
+
+    public boolean hasSetPropertySetter() {
+        return hasSetter() && "setProperty".equals(setMethod.getName());
+    }
+
+    public boolean hasGetPropertyGetter() {
+        return hasGetter() && "getProperty".equals(getMethod.getName());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ReflectionProperty property1 = (ReflectionProperty) o;
+
+        if (!clazz.equals(property1.clazz)) return false;
+        return propertyName.equals(property1.propertyName);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = clazz.hashCode();
+        result = 31 * result + propertyName.hashCode();
+        return result;
+    }
+
+    public String getClazz() {
+        return clazz;
+    }
+
+    public Method getGetMethod() {
+        return getMethod;
+    }
+
+    public String getConversion(String valueVarName) {
+        if (getPropertyType() == String.class) {
+            return valueVarName;
+        }
+        if (getPropertyType() == Boolean.TYPE) {
+            return "Boolean.valueOf(" + valueVarName + ")";
+        }
+        if (getPropertyType() == Long.TYPE) {
+            return "Long.valueOf(" + valueVarName + ")";
+        }
+        if (getPropertyType() == Integer.TYPE) {
+            return "Integer.valueOf(" + valueVarName + ")";
+        }
+        if (getPropertyType() == InetAddress.class) {
+            return "getInetAddress(" + valueVarName + ")";
+        }
+        throw new IllegalStateException("Unexpected Type:" + getPropertyType());
+
+    }
+
+    public boolean hasSetter() {
+        return setMethod != null;
+    }
+
+    public boolean hasGetter() {
+        return getMethod != null;
+    }
+
+    public Method getSetMethod() {
+        return setMethod;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("ReflectionProperty{");
+        sb.append("name='").append(propertyName).append('\'');
+        sb.append(", type=").append(propertyType);
+        sb.append('}');
+        return sb.toString();
+    }
+}
diff --git a/res/graal/java/org/apache/tomcat/util/xreflection/SetPropertyClass.java b/res/graal/java/org/apache/tomcat/util/xreflection/SetPropertyClass.java
new file mode 100644
index 0000000..55a68c4
--- /dev/null
+++ b/res/graal/java/org/apache/tomcat/util/xreflection/SetPropertyClass.java
@@ -0,0 +1,436 @@
+/*
+ * 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.tomcat.util.xreflection;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+final class SetPropertyClass {
+
+    static final String OBJECT_VAR_NAME = "o";
+    static final String NAME_VAR_NAME = "name";
+    static final String VALUE_VAR_NAME = "value";
+    static final String SETP_VAR_NAME = "invokeSetProperty";
+
+    private final SetPropertyClass parent;
+    private final Class<?> clazz;
+    private Set<SetPropertyClass> children = new HashSet<>();
+    private Set<ReflectionProperty> properties = new HashSet<>();
+    private final boolean isAbstract;
+    private final Method genericSetPropertyMethod;
+    private final Method genericGetPropertyMethod;
+
+    SetPropertyClass(Class<?> clazz, SetPropertyClass parent) {
+        this.clazz = clazz;
+        this.parent = parent;
+        this.isAbstract = Modifier.isAbstract(clazz.getModifiers());
+        Method classSetter, classGetter;
+        try {
+            classSetter = clazz.getDeclaredMethod("setProperty", String.class, String.class);
+        } catch (NoSuchMethodException e) {
+            try {
+                classSetter = clazz.getDeclaredMethod("setProperty", String.class, Object.class);
+            } catch (NoSuchMethodException x) {
+                classSetter = null;
+            }
+        }
+        try {
+            classGetter = clazz.getDeclaredMethod("getProperty", String.class);
+        } catch (NoSuchMethodException e) {
+            classGetter = null;
+        }
+        genericSetPropertyMethod = classSetter;
+        genericGetPropertyMethod = classGetter;
+    }
+
+    boolean isAbstract() {
+        return isAbstract;
+    }
+
+    void addSubClass(SetPropertyClass clazz) {
+        this.children.add(clazz);
+    }
+
+    boolean isBaseClass() {
+        return parent == null;
+    }
+
+    public Set<SetPropertyClass> getChildren() {
+        return children;
+    }
+
+    public Set<ReflectionProperty> getProperties() {
+        return properties;
+    }
+
+    public Method getGenericSetPropertyMethod() {
+        return genericSetPropertyMethod;
+    }
+
+    public Method getGenericGetPropertyMethod() {
+        return genericGetPropertyMethod;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        SetPropertyClass that = (SetPropertyClass) o;
+
+        return clazz.equals(that.clazz);
+    }
+
+    @Override
+    public int hashCode() {
+        return clazz.hashCode();
+    }
+
+    public SetPropertyClass getParent() {
+        return parent;
+    }
+
+    public Class<?> getClazz() {
+        return clazz;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("SetPropertyClass{");
+        sb.append("clazz=").append(clazz.getName());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public void addProperty(ReflectionProperty property) {
+        properties.add(property);
+    }
+
+
+
+    public String generateSetPropertyMethod(ReflectionProperty property) {
+        //this property has a setProperty method
+        if (property.hasSetPropertySetter()) {
+            return "((" + this.getClazz().getName().replace('$','.') + ")" + OBJECT_VAR_NAME + ")." +
+                property.getSetMethod().getName() + "(" + NAME_VAR_NAME + ", " + VALUE_VAR_NAME + ");";
+        }
+
+        //direct setter
+        if (property.hasSetter()) {
+            return "((" + this.getClazz().getName().replace('$','.') + ")" + OBJECT_VAR_NAME + ")." +
+                property.getSetMethod().getName() + "(" + property.getConversion(VALUE_VAR_NAME) + ");";
+        }
+        return null;
+    }
+
+    public String generateGetPropertyMethod(ReflectionProperty property) {
+        //this property has a getProperty method
+        if (property.hasGetPropertyGetter()) {
+            return "result = ((" + this.getClazz().getName().replace('$','.') + ")" + OBJECT_VAR_NAME + ")." +
+                property.getGetMethod().getName() + "(" + NAME_VAR_NAME + ");";
+        }
+
+        //direct getter
+        if (property.hasGetter()) {
+            return "result = ((" + this.getClazz().getName().replace('$','.') + ")" + OBJECT_VAR_NAME + ")." +
+                property.getGetMethod().getName() + "();";
+        }
+        return null;
+    }
+
+    public String generateSetPropertyForMethod() {
+        StringBuilder code = new StringBuilder(ReflectionLessCodeGenerator.getIndent(1))
+            .append(generatesSetPropertyForMethodHeader())
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("switch (")
+            .append(NAME_VAR_NAME)
+            .append(") {")
+            .append(System.lineSeparator());
+
+        //case statements for each property
+        for (ReflectionProperty property : getProperties()) {
+            String invocation = generateSetPropertyMethod(property);
+            if (invocation != null) {
+                code.append(ReflectionLessCodeGenerator.getIndent(3))
+                    .append("case \"")
+                    .append(property.getPropertyName())
+                    .append("\" : ")
+                    .append(System.lineSeparator());
+
+                code.append(ReflectionLessCodeGenerator.getIndent(4))
+                    .append(invocation)
+                    .append(System.lineSeparator())
+                    .append(ReflectionLessCodeGenerator.getIndent(4))
+                    .append("return true;")
+                    .append(System.lineSeparator())
+                ;
+
+            } else {
+                code.append(ReflectionLessCodeGenerator.getIndent(3))
+                    .append("//no set" + IntrospectionUtils.capitalize(property.getPropertyName())+ " method found on this class")
+                    .append(System.lineSeparator())
+                    ;
+            }
+        }
+
+
+
+        //end switch statement
+        code.append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("}")
+            .append(System.lineSeparator());
+
+        //we have a generic setProperty(String, String) method, invoke it
+        if (getGenericSetPropertyMethod() != null) {
+            ReflectionProperty p = new ReflectionProperty(
+                clazz.getName(),
+                "property",
+                String.class,
+                getGenericSetPropertyMethod(),
+                null
+            );
+           code.append(ReflectionLessCodeGenerator.getIndent(2))
+               .append("if (")
+               .append(SETP_VAR_NAME)
+               .append(") {")
+               .append(System.lineSeparator())
+               .append(ReflectionLessCodeGenerator.getIndent(3))
+               .append(generateSetPropertyMethod(p))
+               .append(System.lineSeparator())
+               .append(ReflectionLessCodeGenerator.getIndent(3))
+               .append("return true;")
+               .append(System.lineSeparator())
+               .append(ReflectionLessCodeGenerator.getIndent(2))
+               .append("}")
+               .append(System.lineSeparator());
+        }
+
+        //invoke parent or return false
+        code.append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("return ")
+            .append(getSetPropertyForExitStatement())
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(1))
+            .append("}");
+
+        return code.toString();
+    }
+
+    private String getSetPropertyForExitStatement() {
+
+        return (getParent() != null) ?
+            //invoke the parent if we have one
+            getParent().generateParentSetPropertyForMethodInvocation() :
+            //if we invoke setProperty, return true, return false otherwise
+            getGenericSetPropertyMethod() != null ? "true;" : "false;";
+    }
+
+    public String generateInvocationSetForPropertyCaseStatement(int level) {
+        StringBuilder code = new StringBuilder(ReflectionLessCodeGenerator.getIndent(level))
+            .append("case \"")
+            .append(getClazz().getName())
+            .append("\" : ")
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(level+1))
+            .append("return ")
+            .append(generateParentSetPropertyForMethodInvocation())
+            .append(System.lineSeparator());
+        return code.toString();
+    }
+
+    public String generateParentSetPropertyForMethodInvocation() {
+        String[] classParts = clazz.getName().split("\\.|\\$");
+        StringBuilder methodInvocation = new StringBuilder("setPropertyFor");
+        for (String s : classParts) {
+            methodInvocation.append(IntrospectionUtils.capitalize(s));
+        }
+        methodInvocation.append("(")
+        .append(OBJECT_VAR_NAME)
+            .append(", ")
+            .append(NAME_VAR_NAME)
+            .append(", ")
+            .append(VALUE_VAR_NAME)
+            .append(", ")
+            .append(SETP_VAR_NAME)
+            .append(");");
+        return methodInvocation.toString();
+    }
+
+    public String generatesSetPropertyForMethodHeader() {
+        String[] classParts = clazz.getName().split("\\.|\\$");
+        StringBuilder methodInvocation = new StringBuilder("private static boolean setPropertyFor");
+        for (String s : classParts) {
+            methodInvocation.append(IntrospectionUtils.capitalize(s));
+        }
+        methodInvocation.append("(Object ")
+            .append(OBJECT_VAR_NAME)
+            .append(", String ")
+            .append(NAME_VAR_NAME)
+            .append(", String ")
+            .append(VALUE_VAR_NAME)
+            .append(", boolean ")
+            .append(SETP_VAR_NAME)
+            .append(") {");
+        return methodInvocation.toString();
+    }
+
+    public String generateInvocationGetForPropertyCaseStatement(int level) {
+        StringBuilder code = new StringBuilder(ReflectionLessCodeGenerator.getIndent(level))
+            .append("case \"")
+            .append(getClazz().getName())
+            .append("\" : ")
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(level+1))
+            .append("result = ")
+            .append(generateParentGetPropertyForMethodInvocation())
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(level+1))
+            .append("break;")
+            .append(System.lineSeparator())
+            ;
+        return code.toString();
+    }
+
+    public String generateParentGetPropertyForMethodInvocation() {
+        String[] classParts = clazz.getName().split("\\.|\\$");
+        StringBuilder methodInvocation = new StringBuilder("getPropertyFor");
+        for (String s : classParts) {
+            methodInvocation.append(IntrospectionUtils.capitalize(s));
+        }
+        methodInvocation.append("(")
+            .append(OBJECT_VAR_NAME)
+            .append(", ")
+            .append(NAME_VAR_NAME)
+            .append(");");
+        return methodInvocation.toString();
+    }
+
+    public String generatesGetPropertyForMethodHeader() {
+        String[] classParts = clazz.getName().split("\\.|\\$");
+        StringBuilder methodInvocation = new StringBuilder("private static Object getPropertyFor");
+        for (String s : classParts) {
+            methodInvocation.append(IntrospectionUtils.capitalize(s));
+        }
+        methodInvocation.append("(Object ")
+            .append(OBJECT_VAR_NAME)
+            .append(", String ")
+            .append(NAME_VAR_NAME)
+            .append(") {");
+        return methodInvocation.toString();
+    }
+
+    private String getGetPropertyForExitStatement() {
+        if (getParent() != null) {
+            return getParent().generateParentGetPropertyForMethodInvocation();
+        }
+        return "null;";
+    }
+
+
+    public String generateGetPropertyForMethod() {
+        StringBuilder code = new StringBuilder(ReflectionLessCodeGenerator.getIndent(1))
+            .append(generatesGetPropertyForMethodHeader())
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("Object result = null;")
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("switch (")
+            .append(NAME_VAR_NAME)
+            .append(") {")
+            .append(System.lineSeparator());
+
+        //case statements for each property
+        for (ReflectionProperty property : getProperties()) {
+            String invocation = generateGetPropertyMethod(property);
+            if (invocation != null) {
+                code.append(ReflectionLessCodeGenerator.getIndent(3))
+                    .append("case \"")
+                    .append(property.getPropertyName())
+                    .append("\" : ")
+                    .append(System.lineSeparator());
+
+                code.append(ReflectionLessCodeGenerator.getIndent(4))
+                    .append(invocation)
+                    .append(System.lineSeparator())
+                    .append(ReflectionLessCodeGenerator.getIndent(4))
+                    .append("break;")
+                    .append(System.lineSeparator())
+                ;
+
+            } else {
+                code.append(ReflectionLessCodeGenerator.getIndent(3))
+                    .append("//no get" + IntrospectionUtils.capitalize(property.getPropertyName())+ " method found on this class")
+                    .append(System.lineSeparator())
+                ;
+            }
+        }
+
+        //end switch statement
+        code.append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("}")
+            .append(System.lineSeparator());
+
+        //invoke parent or return null
+        code.append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("if (result == null) {")
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(3))
+            .append("result = ")
+            .append(getGetPropertyForExitStatement())
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("}")
+            .append(System.lineSeparator())
+            ;
+
+        //we have a generic getProperty(String, String) method, invoke it
+        if (getGenericGetPropertyMethod() != null) {
+            ReflectionProperty p = new ReflectionProperty(
+                clazz.getName(),
+                "property",
+                String.class,
+                null,
+                getGenericGetPropertyMethod()
+            );
+            code.append(ReflectionLessCodeGenerator.getIndent(2))
+                .append("if (result == null) {")
+                .append(System.lineSeparator())
+                .append(ReflectionLessCodeGenerator.getIndent(3))
+                .append(generateGetPropertyMethod(p))
+                .append(System.lineSeparator())
+                .append(ReflectionLessCodeGenerator.getIndent(2))
+                .append("}")
+                .append(System.lineSeparator());
+        }
+        code.append(ReflectionLessCodeGenerator.getIndent(2))
+            .append("return result;")
+            .append(System.lineSeparator())
+            .append(ReflectionLessCodeGenerator.getIndent(1))
+            .append("}")
+            .append(System.lineSeparator());
+
+
+
+        return code.toString();
+    }
+}
diff --git a/res/graal/tomcat-embed-programmatic/native-image/native-image.properties b/res/graal/tomcat-embed-programmatic/native-image/native-image.properties
new file mode 100644
index 0000000..29b501f
--- /dev/null
+++ b/res/graal/tomcat-embed-programmatic/native-image/native-image.properties
@@ -0,0 +1,16 @@
+# 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.
+
+Args = -H:ReflectionConfigurationResources=${.}/tomcat-reflection.json -H:ResourceConfigurationResources=${.}/tomcat-resource.json
\ No newline at end of file
diff --git a/res/graal/tomcat-embed-programmatic/native-image/tomcat-reflection.json b/res/graal/tomcat-embed-programmatic/native-image/tomcat-reflection.json
new file mode 100644
index 0000000..0d4f101
--- /dev/null
+++ b/res/graal/tomcat-embed-programmatic/native-image/tomcat-reflection.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/res/graal/tomcat-embed-programmatic/native-image/tomcat-resource.json b/res/graal/tomcat-embed-programmatic/native-image/tomcat-resource.json
new file mode 100644
index 0000000..1ac95cf
--- /dev/null
+++ b/res/graal/tomcat-embed-programmatic/native-image/tomcat-resource.json
@@ -0,0 +1,51 @@
+{
+  "bundles":[
+    {"name":"jakarta.servlet.LocalStrings"},
+    {"name":"jakarta.servlet.http.LocalStrings"},
+    {"name":"org.apache.catalina.authenticator.LocalStrings"},
+    {"name":"org.apache.catalina.authenticator.jaspic.LocalStrings"},
+    {"name":"org.apache.catalina.connector.LocalStrings"},
+    {"name":"org.apache.catalina.core.LocalStrings"},
+    {"name":"org.apache.catalina.deploy.LocalStrings"},
+    {"name":"org.apache.catalina.loader.LocalStrings"},
+    {"name":"org.apache.catalina.mapper.LocalStrings"},
+    {"name":"org.apache.catalina.realm.LocalStrings"},
+    {"name":"org.apache.catalina.security.LocalStrings"},
+    {"name":"org.apache.catalina.session.LocalStrings"},
+    {"name":"org.apache.catalina.startup.LocalStrings"},
+    {"name":"org.apache.catalina.util.LocalStrings"},
+    {"name":"org.apache.catalina.valves.LocalStrings"},
+    {"name":"org.apache.catalina.webresources.LocalStrings"},
+    {"name":"org.apache.coyote.LocalStrings"},
+    {"name":"org.apache.coyote.http11.LocalStrings"},
+    {"name":"org.apache.coyote.http11.filters.LocalStrings"},
+    {"name":"org.apache.coyote.http11.upgrade.LocalStrings"},
+    {"name":"org.apache.coyote.http2.LocalStrings"},
+    {"name":"org.apache.naming.LocalStrings"},
+    {"name":"org.apache.naming.factory.LocalStrings"},
+    {"name":"org.apache.tomcat.util.LocalStrings"},
+    {"name":"org.apache.tomcat.util.buf.LocalStrings"},
+    {"name":"org.apache.tomcat.util.codec.binary.LocalStrings"},
+    {"name":"org.apache.tomcat.util.compat.LocalStrings"},
+    {"name":"org.apache.tomcat.util.http.LocalStrings"},
+    {"name":"org.apache.tomcat.util.http.parser.LocalStrings"},
+    {"name":"org.apache.tomcat.util.json.LocalStrings"},
+    {"name":"org.apache.tomcat.util.modeler.LocalStrings"},
+    {"name":"org.apache.tomcat.util.net.LocalStrings"},
+    {"name":"org.apache.tomcat.util.scan.LocalStrings"},
+    {"name":"org.apache.tomcat.util.security.LocalStrings"},
+    {"name":"org.apache.tomcat.util.threads.res.LocalStrings"}
+  ],
+  "resources":[
+    {"pattern":".*/Authenticators.properties$"},
+    {"pattern":".*/MimeTypeMappings.properties$"},
+    {"pattern":".*/catalina.properties$"},
+    {"pattern":".*/CharsetMapperDefault.properties$"},
+    {"pattern":".*/ServerInfo.properties$"},
+    {"pattern":".*/RestrictedServlets.properties$"},
+    {"pattern":".*/RestrictedListeners.properties$"},
+    {"pattern":".*/RestrictedFilters.properties$"},
+    {"pattern":".*/*.dtd$"},
+    {"pattern":".*/*.xsd$"}
+  ]
+}
diff --git a/res/maven/mvn-pub.xml b/res/maven/mvn-pub.xml
index 0f5d6d2..887578b 100644
--- a/res/maven/mvn-pub.xml
+++ b/res/maven/mvn-pub.xml
@@ -347,6 +347,11 @@
          file="${tomcat.embed.path}/tomcat-embed-core.jar"
          pom="tomcat-embed-core.pom"
          src="${tomcat.embed.src.path}/tomcat-embed-core-src.jar"/>
+     <doMavenInstall artifactId="tomcat-embed-programmatic"
+         groupId="org.apache.tomcat.experimental"
+         file="${tomcat.embed.path}/tomcat-embed-programmatic.jar"
+         pom="tomcat-embed-programmatic.pom"
+         src="${tomcat.embed.src.path}/tomcat-embed-programmatic-src.jar"/>
      <doMavenInstall artifactId="tomcat-embed-jasper"
          groupId="org.apache.tomcat.embed"
          file="${tomcat.embed.path}/tomcat-embed-jasper.jar"
@@ -455,6 +460,11 @@
         file="${tomcat.embed.path}/tomcat-embed-core.jar"
         pom="tomcat-embed-core.pom"
         src="${tomcat.embed.src.path}/tomcat-embed-core-src.jar"/>
+    <doMavenDeploy artifactId="tomcat-embed-programmatic"
+                   groupId="org.apache.tomcat.experimental"
+                   file="${tomcat.embed.path}/tomcat-embed-programmatic.jar"
+                   pom="tomcat-embed-programmatic.pom"
+                   src="${tomcat.embed.src.path}/tomcat-embed-programmatic-src.jar"/>
     <doMavenDeploy artifactId="tomcat-embed-jasper"
         groupId="org.apache.tomcat.embed"
         file="${tomcat.embed.path}/tomcat-embed-jasper.jar"
diff --git a/res/maven/tomcat-embed-programmatic.pom b/res/maven/tomcat-embed-programmatic.pom
new file mode 100644
index 0000000..84fe088
--- /dev/null
+++ b/res/maven/tomcat-embed-programmatic.pom
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+  http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.tomcat.experimental</groupId>
+  <artifactId>tomcat-embed-programmatic</artifactId>
+  <version>@MAVEN.DEPLOY.VERSION@</version>
+  <description>Exerimental Minimal Tomcat for Programmatic Use</description>
+  <url>https://tomcat.apache.org/</url>
+  <licenses>
+    <license>
+      <name>Apache License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+</project>
diff --git a/test/org/apache/catalina/startup/EmbeddedTomcat.java b/test/org/apache/catalina/startup/EmbeddedTomcat.java
index 5658291..8b5c12c 100644
--- a/test/org/apache/catalina/startup/EmbeddedTomcat.java
+++ b/test/org/apache/catalina/startup/EmbeddedTomcat.java
@@ -35,7 +35,6 @@ import org.apache.catalina.connector.Connector;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.scan.StandardJarScanFilter;
 import org.apache.tomcat.util.scan.StandardJarScanner;
-import org.apache.tomcat.websocket.server.WsContextListener;
 
 @Ignore
 public class EmbeddedTomcat {
@@ -67,7 +66,7 @@ public class EmbeddedTomcat {
         CounterServlet counterServlet = new CounterServlet();
         Tomcat.addServlet(ctx, "counterServlet", counterServlet);
         ctx.addServletMappingDecoded("/", "counterServlet");
-        ctx.addApplicationListener(WsContextListener.class.getName());
+        //ctx.addApplicationListener(new WsContextListener());
 
         tomcat.start();
         Thread.sleep(60*1000);
@@ -88,6 +87,7 @@ public class EmbeddedTomcat {
         @Override
         protected void service(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
+            req.getSession(true);
             resp.setContentType("text/plain");
             resp.getWriter().print("OK: " + req.getRequestURL() + "[" + callCount.incrementAndGet()+ "]");
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]