diff --git a/core/example/src/example/Book.java b/core/example/src/example/Book.java index 9b69ec50d..d57bcd55b 100644 --- a/core/example/src/example/Book.java +++ b/core/example/src/example/Book.java @@ -1,7 +1,7 @@ package example; +import jakarta.servlet.ServletException; import java.io.IOException; -import javax.servlet.ServletException; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; diff --git a/core/example/src/example/BookStore.java b/core/example/src/example/BookStore.java index b1aced233..a9a3b690a 100644 --- a/core/example/src/example/BookStore.java +++ b/core/example/src/example/BookStore.java @@ -1,9 +1,9 @@ package example; +import jakarta.servlet.ServletException; import java.io.IOException; import java.util.Hashtable; import java.util.Map; -import javax.servlet.ServletException; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; diff --git a/core/example/src/example/WebAppMain.java b/core/example/src/example/WebAppMain.java index a832fcc50..2912a6ff8 100644 --- a/core/example/src/example/WebAppMain.java +++ b/core/example/src/example/WebAppMain.java @@ -1,7 +1,7 @@ package example; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; import org.kohsuke.stapler.Stapler; /** diff --git a/core/maven-example/pom.xml b/core/maven-example/pom.xml index 372fd2e2a..3741f4800 100644 --- a/core/maven-example/pom.xml +++ b/core/maven-example/pom.xml @@ -16,21 +16,21 @@ 1.253 - javax.servlet.jsp.jstl - javax.servlet.jsp.jstl-api - 1.2.1 + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + 2.0.0 - javax.servlet - javax.servlet-api - 3.1.0 + jakarta.servlet + jakarta.servlet-api + 5.0.0 provided - javax.servlet.jsp - javax.servlet.jsp-api - 2.3.0 + jakarta.servlet.jsp + jakarta.servlet.jsp-api + 3.0.0 provided diff --git a/core/maven-example/src/main/java/example/Book.java b/core/maven-example/src/main/java/example/Book.java index 9b69ec50d..d57bcd55b 100644 --- a/core/maven-example/src/main/java/example/Book.java +++ b/core/maven-example/src/main/java/example/Book.java @@ -1,7 +1,7 @@ package example; +import jakarta.servlet.ServletException; import java.io.IOException; -import javax.servlet.ServletException; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; diff --git a/core/maven-example/src/main/java/example/BookStore.java b/core/maven-example/src/main/java/example/BookStore.java index b1aced233..a9a3b690a 100644 --- a/core/maven-example/src/main/java/example/BookStore.java +++ b/core/maven-example/src/main/java/example/BookStore.java @@ -1,9 +1,9 @@ package example; +import jakarta.servlet.ServletException; import java.io.IOException; import java.util.Hashtable; import java.util.Map; -import javax.servlet.ServletException; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; diff --git a/core/maven-example/src/main/java/example/WebAppMain.java b/core/maven-example/src/main/java/example/WebAppMain.java index a832fcc50..2912a6ff8 100644 --- a/core/maven-example/src/main/java/example/WebAppMain.java +++ b/core/maven-example/src/main/java/example/WebAppMain.java @@ -1,7 +1,7 @@ package example; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; import org.kohsuke.stapler.Stapler; /** diff --git a/core/pom.xml b/core/pom.xml index 202c6ec42..1f6a80835 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -65,7 +65,7 @@ org.apache.commons - commons-fileupload2-javax + commons-fileupload2-jakarta-servlet5 ${commons-fileupload2.version} @@ -79,6 +79,11 @@ 2.4.21 true + + org.eclipse.jetty.toolchain + jetty-servlet-api + 4.0.6 + org.jenkins-ci annotation-indexer @@ -108,7 +113,7 @@ jakarta.servlet jakarta.servlet-api - 4.0.4 + 5.0.0 provided @@ -140,13 +145,13 @@ test - org.eclipse.jetty.ee8 - jetty-ee8-servlet + org.eclipse.jetty.ee9 + jetty-ee9-servlet test - org.eclipse.jetty.ee8 - jetty-ee8-webapp + org.eclipse.jetty.ee9 + jetty-ee9-webapp test diff --git a/core/src/main/java/io/jenkins/servlet/AsyncContextWrapper.java b/core/src/main/java/io/jenkins/servlet/AsyncContextWrapper.java new file mode 100644 index 000000000..707035675 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/AsyncContextWrapper.java @@ -0,0 +1,192 @@ +package io.jenkins.servlet; + +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import java.util.Objects; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncListener; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class AsyncContextWrapper { + public static jakarta.servlet.AsyncContext toJakartaAsyncContext(AsyncContext from) { + Objects.requireNonNull(from); + return new jakarta.servlet.AsyncContext() { + @Override + public jakarta.servlet.ServletRequest getRequest() { + ServletRequest request = from.getRequest(); + return request instanceof HttpServletRequest + ? HttpServletRequestWrapper.toJakartaHttpServletRequest(((HttpServletRequest) request)) + : io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request); + } + + @Override + public jakarta.servlet.ServletResponse getResponse() { + ServletResponse response = from.getResponse(); + return response instanceof HttpServletResponse + ? HttpServletResponseWrapper.toJakartaHttpServletResponse(((HttpServletResponse) response)) + : ServletResponseWrapper.toJakartaServletResponse(response); + } + + @Override + public boolean hasOriginalRequestAndResponse() { + return from.hasOriginalRequestAndResponse(); + } + + @Override + public void dispatch() { + from.dispatch(); + } + + @Override + public void dispatch(String path) { + from.dispatch(path); + } + + @Override + public void dispatch(jakarta.servlet.ServletContext context, String path) { + from.dispatch(ServletContextWrapper.fromJakartServletContext(context), path); + } + + @Override + public void complete() { + from.complete(); + } + + @Override + public void start(Runnable run) { + from.start(run); + } + + @Override + public void addListener(jakarta.servlet.AsyncListener listener) { + from.addListener(AsyncListenerWrapper.fromJakartaAsyncListener(listener)); + } + + @Override + public void addListener( + jakarta.servlet.AsyncListener listener, + jakarta.servlet.ServletRequest servletRequest, + jakarta.servlet.ServletResponse servletResponse) { + from.addListener( + AsyncListenerWrapper.fromJakartaAsyncListener(listener), + servletRequest instanceof jakarta.servlet.http.HttpServletRequest + ? HttpServletRequestWrapper.fromJakartaHttpServletRequest( + (jakarta.servlet.http.HttpServletRequest) servletRequest) + : io.jenkins.servlet.ServletRequestWrapper.fromJakartaServletRequest(servletRequest), + servletResponse instanceof jakarta.servlet.http.HttpServletResponse + ? HttpServletResponseWrapper.fromJakartaHttpServletResponse( + (jakarta.servlet.http.HttpServletResponse) servletResponse) + : ServletResponseWrapper.fromJakartaServletResponse(servletResponse)); + } + + @Override + public T createListener(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setTimeout(long timeout) { + from.setTimeout(timeout); + } + + @Override + public long getTimeout() { + return from.getTimeout(); + } + }; + } + + public static AsyncContext fromJakartaAsyncContext(jakarta.servlet.AsyncContext from) { + Objects.requireNonNull(from); + return new AsyncContext() { + @Override + public ServletRequest getRequest() { + jakarta.servlet.ServletRequest request = from.getRequest(); + return request instanceof jakarta.servlet.http.HttpServletRequest + ? HttpServletRequestWrapper.fromJakartaHttpServletRequest( + (jakarta.servlet.http.HttpServletRequest) request) + : ServletRequestWrapper.fromJakartaServletRequest(request); + } + + @Override + public ServletResponse getResponse() { + jakarta.servlet.ServletResponse response = from.getResponse(); + return response instanceof jakarta.servlet.http.HttpServletResponse + ? HttpServletResponseWrapper.fromJakartaHttpServletResponse( + (jakarta.servlet.http.HttpServletResponse) response) + : ServletResponseWrapper.fromJakartaServletResponse(response); + } + + @Override + public boolean hasOriginalRequestAndResponse() { + return from.hasOriginalRequestAndResponse(); + } + + @Override + public void dispatch() { + from.dispatch(); + } + + @Override + public void dispatch(String path) { + from.dispatch(path); + } + + @Override + public void dispatch(ServletContext context, String path) { + from.dispatch(ServletContextWrapper.toJakartaServletContext(context), path); + } + + @Override + public void complete() { + from.complete(); + } + + @Override + public void start(Runnable run) { + from.start(run); + } + + @Override + public void addListener(AsyncListener listener) { + from.addListener(AsyncListenerWrapper.toJakartaAsyncListener(listener)); + } + + @Override + public void addListener( + AsyncListener listener, ServletRequest servletRequest, ServletResponse servletResponse) { + from.addListener( + AsyncListenerWrapper.toJakartaAsyncListener(listener), + servletRequest instanceof HttpServletRequest + ? HttpServletRequestWrapper.toJakartaHttpServletRequest( + ((HttpServletRequest) servletRequest)) + : io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(servletRequest), + servletResponse instanceof HttpServletResponse + ? HttpServletResponseWrapper.toJakartaHttpServletResponse( + ((HttpServletResponse) servletResponse)) + : ServletResponseWrapper.toJakartaServletResponse(servletResponse)); + } + + @Override + public T createListener(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setTimeout(long timeout) { + from.setTimeout(timeout); + } + + @Override + public long getTimeout() { + return from.getTimeout(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/AsyncEventWrapper.java b/core/src/main/java/io/jenkins/servlet/AsyncEventWrapper.java new file mode 100644 index 000000000..62fca0d6e --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/AsyncEventWrapper.java @@ -0,0 +1,24 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.AsyncEvent; + +public class AsyncEventWrapper { + public static jakarta.servlet.AsyncEvent toJakartaServletHttpAsyncEvent(AsyncEvent from) { + Objects.requireNonNull(from); + return new jakarta.servlet.AsyncEvent( + AsyncContextWrapper.toJakartaAsyncContext(from.getAsyncContext()), + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(from.getSuppliedRequest()), + ServletResponseWrapper.toJakartaServletResponse(from.getSuppliedResponse()), + from.getThrowable()); + } + + public static AsyncEvent fromJakartaServletHttpAsyncEvent(jakarta.servlet.AsyncEvent from) { + Objects.requireNonNull(from); + return new AsyncEvent( + AsyncContextWrapper.fromJakartaAsyncContext(from.getAsyncContext()), + ServletRequestWrapper.fromJakartaServletRequest(from.getSuppliedRequest()), + ServletResponseWrapper.fromJakartaServletResponse(from.getSuppliedResponse()), + from.getThrowable()); + } +} diff --git a/core/src/main/java/io/jenkins/servlet/AsyncListenerWrapper.java b/core/src/main/java/io/jenkins/servlet/AsyncListenerWrapper.java new file mode 100644 index 000000000..52672e511 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/AsyncListenerWrapper.java @@ -0,0 +1,60 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.util.Objects; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; + +public class AsyncListenerWrapper { + public static jakarta.servlet.AsyncListener toJakartaAsyncListener(AsyncListener from) { + Objects.requireNonNull(from); + return new jakarta.servlet.AsyncListener() { + + @Override + public void onComplete(jakarta.servlet.AsyncEvent event) throws IOException { + from.onComplete(AsyncEventWrapper.fromJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onTimeout(jakarta.servlet.AsyncEvent event) throws IOException { + from.onTimeout(AsyncEventWrapper.fromJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onError(jakarta.servlet.AsyncEvent event) throws IOException { + from.onError(AsyncEventWrapper.fromJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onStartAsync(jakarta.servlet.AsyncEvent event) throws IOException { + from.onStartAsync(AsyncEventWrapper.fromJakartaServletHttpAsyncEvent(event)); + } + }; + } + + public static AsyncListener fromJakartaAsyncListener(jakarta.servlet.AsyncListener from) { + Objects.requireNonNull(from); + return new AsyncListener() { + + @Override + public void onComplete(AsyncEvent event) throws IOException { + from.onComplete(AsyncEventWrapper.toJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onTimeout(AsyncEvent event) throws IOException { + from.onTimeout(AsyncEventWrapper.toJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onError(AsyncEvent event) throws IOException { + from.onError(AsyncEventWrapper.toJakartaServletHttpAsyncEvent(event)); + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException { + from.onStartAsync(AsyncEventWrapper.toJakartaServletHttpAsyncEvent(event)); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/DispatcherTypeWrapper.java b/core/src/main/java/io/jenkins/servlet/DispatcherTypeWrapper.java new file mode 100644 index 000000000..cc113a040 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/DispatcherTypeWrapper.java @@ -0,0 +1,42 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.DispatcherType; + +public class DispatcherTypeWrapper { + public static jakarta.servlet.DispatcherType toJakartaDispatcherType(DispatcherType from) { + Objects.requireNonNull(from); + switch (from) { + case FORWARD: + return jakarta.servlet.DispatcherType.FORWARD; + case INCLUDE: + return jakarta.servlet.DispatcherType.INCLUDE; + case REQUEST: + return jakarta.servlet.DispatcherType.REQUEST; + case ASYNC: + return jakarta.servlet.DispatcherType.ASYNC; + case ERROR: + return jakarta.servlet.DispatcherType.ERROR; + default: + throw new IllegalArgumentException("Unknown DispatcherType: " + from); + } + } + + public static DispatcherType fromJakartaDispatcherType(jakarta.servlet.DispatcherType from) { + Objects.requireNonNull(from); + switch (from) { + case FORWARD: + return DispatcherType.FORWARD; + case INCLUDE: + return DispatcherType.INCLUDE; + case REQUEST: + return DispatcherType.REQUEST; + case ASYNC: + return DispatcherType.ASYNC; + case ERROR: + return DispatcherType.ERROR; + default: + throw new IllegalArgumentException("Unknown DispatcherType: " + from); + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/FilterChainWrapper.java b/core/src/main/java/io/jenkins/servlet/FilterChainWrapper.java new file mode 100644 index 000000000..80e3e73c5 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/FilterChainWrapper.java @@ -0,0 +1,67 @@ +package io.jenkins.servlet; + +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Objects; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class FilterChainWrapper { + public static jakarta.servlet.FilterChain toJakartaFilterChain(FilterChain from) { + Objects.requireNonNull(from); + return new jakarta.servlet.FilterChain() { + @Override + public void doFilter(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) + throws IOException, jakarta.servlet.ServletException { + try { + if (request instanceof jakarta.servlet.http.HttpServletRequest + && response instanceof jakarta.servlet.http.HttpServletResponse) { + jakarta.servlet.http.HttpServletRequest httpRequest = + (jakarta.servlet.http.HttpServletRequest) request; + jakarta.servlet.http.HttpServletResponse httpResponse = + (jakarta.servlet.http.HttpServletResponse) response; + from.doFilter( + HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.fromJakartaHttpServletResponse(httpResponse)); + } else { + from.doFilter( + ServletRequestWrapper.fromJakartaServletRequest(request), + ServletResponseWrapper.fromJakartaServletResponse(response)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + }; + } + + public static FilterChain fromJakartaFilterChain(jakarta.servlet.FilterChain from) { + Objects.requireNonNull(from); + return new FilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + try { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + from.doFilter( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse)); + } else { + from.doFilter( + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response)); + } + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/FilterConfigWrapper.java b/core/src/main/java/io/jenkins/servlet/FilterConfigWrapper.java new file mode 100644 index 000000000..94fe57007 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/FilterConfigWrapper.java @@ -0,0 +1,58 @@ +package io.jenkins.servlet; + +import java.util.Enumeration; +import java.util.Objects; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; + +public class FilterConfigWrapper { + public static jakarta.servlet.FilterConfig toJakartaFilterConfig(FilterConfig from) { + Objects.requireNonNull(from); + return new jakarta.servlet.FilterConfig() { + @Override + public String getFilterName() { + return from.getFilterName(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + }; + } + + public static FilterConfig fromJakartaFilterConfig(jakarta.servlet.FilterConfig from) { + Objects.requireNonNull(from); + return new FilterConfig() { + @Override + public String getFilterName() { + return from.getFilterName(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/FilterRegistrationDynamicWrapper.java b/core/src/main/java/io/jenkins/servlet/FilterRegistrationDynamicWrapper.java new file mode 100644 index 000000000..3c6ec29ca --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/FilterRegistrationDynamicWrapper.java @@ -0,0 +1,162 @@ +package io.jenkins.servlet; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; + +public class FilterRegistrationDynamicWrapper { + public static jakarta.servlet.FilterRegistration.Dynamic toJakartaFilterRegistrationDynamic( + FilterRegistration.Dynamic from) { + Objects.requireNonNull(from); + return new jakarta.servlet.FilterRegistration.Dynamic() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + + @Override + public void addMappingForServletNames( + EnumSet dispatcherTypes, + boolean isMatchAfter, + String... servletNames) { + from.addMappingForServletNames( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::fromJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + servletNames); + } + + @Override + public Collection getServletNameMappings() { + return from.getServletNameMappings(); + } + + @Override + public void addMappingForUrlPatterns( + EnumSet dispatcherTypes, + boolean isMatchAfter, + String... urlPatterns) { + from.addMappingForUrlPatterns( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::fromJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + urlPatterns); + } + + @Override + public Collection getUrlPatternMappings() { + return from.getUrlPatternMappings(); + } + }; + } + + public static FilterRegistration.Dynamic fromJakartaFilterRegistrationDynamic( + jakarta.servlet.FilterRegistration.Dynamic from) { + Objects.requireNonNull(from); + return new FilterRegistration.Dynamic() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + + @Override + public void addMappingForServletNames( + EnumSet dispatcherTypes, boolean isMatchAfter, String... servletNames) { + from.addMappingForServletNames( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::toJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + servletNames); + } + + @Override + public Collection getServletNameMappings() { + return from.getServletNameMappings(); + } + + @Override + public void addMappingForUrlPatterns( + EnumSet dispatcherTypes, boolean isMatchAfter, String... urlPatterns) { + from.addMappingForUrlPatterns( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::toJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + urlPatterns); + } + + @Override + public Collection getUrlPatternMappings() { + return from.getUrlPatternMappings(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/FilterRegistrationWrapper.java b/core/src/main/java/io/jenkins/servlet/FilterRegistrationWrapper.java new file mode 100644 index 000000000..9da77ec37 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/FilterRegistrationWrapper.java @@ -0,0 +1,150 @@ +package io.jenkins.servlet; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; + +public class FilterRegistrationWrapper { + public static jakarta.servlet.FilterRegistration toJakartaFilterRegistration(FilterRegistration from) { + Objects.requireNonNull(from); + return new jakarta.servlet.FilterRegistration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void addMappingForServletNames( + EnumSet dispatcherTypes, + boolean isMatchAfter, + String... servletNames) { + from.addMappingForServletNames( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::fromJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + servletNames); + } + + @Override + public Collection getServletNameMappings() { + return from.getServletNameMappings(); + } + + @Override + public void addMappingForUrlPatterns( + EnumSet dispatcherTypes, + boolean isMatchAfter, + String... urlPatterns) { + from.addMappingForUrlPatterns( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::fromJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + urlPatterns); + } + + @Override + public Collection getUrlPatternMappings() { + return from.getUrlPatternMappings(); + } + }; + } + + public static FilterRegistration fromJakartaFilterRegistration(jakarta.servlet.FilterRegistration from) { + Objects.requireNonNull(from); + return new FilterRegistration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void addMappingForServletNames( + EnumSet dispatcherTypes, boolean isMatchAfter, String... servletNames) { + from.addMappingForServletNames( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::toJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + servletNames); + } + + @Override + public Collection getServletNameMappings() { + return from.getServletNameMappings(); + } + + @Override + public void addMappingForUrlPatterns( + EnumSet dispatcherTypes, boolean isMatchAfter, String... urlPatterns) { + from.addMappingForUrlPatterns( + EnumSet.copyOf(dispatcherTypes.stream() + .map(DispatcherTypeWrapper::toJakartaDispatcherType) + .collect(Collectors.toSet())), + isMatchAfter, + urlPatterns); + } + + @Override + public Collection getUrlPatternMappings() { + return from.getUrlPatternMappings(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/FilterWrapper.java b/core/src/main/java/io/jenkins/servlet/FilterWrapper.java new file mode 100644 index 000000000..8d07ba7d2 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/FilterWrapper.java @@ -0,0 +1,104 @@ +package io.jenkins.servlet; + +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Objects; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class FilterWrapper { + public static jakarta.servlet.Filter toJakartaFilter(Filter from) { + Objects.requireNonNull(from); + return new jakarta.servlet.Filter() { + @Override + public void init(jakarta.servlet.FilterConfig filterConfig) throws jakarta.servlet.ServletException { + try { + from.init(FilterConfigWrapper.fromJakartaFilterConfig(filterConfig)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void doFilter( + jakarta.servlet.ServletRequest request, + jakarta.servlet.ServletResponse response, + jakarta.servlet.FilterChain chain) + throws IOException, jakarta.servlet.ServletException { + try { + if (request instanceof jakarta.servlet.http.HttpServletRequest + && response instanceof jakarta.servlet.http.HttpServletResponse) { + jakarta.servlet.http.HttpServletRequest httpRequest = + (jakarta.servlet.http.HttpServletRequest) request; + jakarta.servlet.http.HttpServletResponse httpResponse = + (jakarta.servlet.http.HttpServletResponse) response; + from.doFilter( + HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.fromJakartaHttpServletResponse(httpResponse), + FilterChainWrapper.fromJakartaFilterChain(chain)); + } else { + from.doFilter( + ServletRequestWrapper.fromJakartaServletRequest(request), + ServletResponseWrapper.fromJakartaServletResponse(response), + FilterChainWrapper.fromJakartaFilterChain(chain)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void destroy() { + from.destroy(); + } + }; + } + + public static Filter fromJakartaFilter(jakarta.servlet.Filter from) { + Objects.requireNonNull(from); + return new Filter() { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + try { + from.init(FilterConfigWrapper.toJakartaFilterConfig(filterConfig)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + try { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + from.doFilter( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse), + FilterChainWrapper.toJakartaFilterChain(chain)); + } else { + from.doFilter( + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response), + FilterChainWrapper.toJakartaFilterChain(chain)); + } + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void destroy() { + from.destroy(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ReadListenerWrapper.java b/core/src/main/java/io/jenkins/servlet/ReadListenerWrapper.java new file mode 100644 index 000000000..8df980756 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ReadListenerWrapper.java @@ -0,0 +1,47 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.util.Objects; +import javax.servlet.ReadListener; + +public class ReadListenerWrapper { + public static jakarta.servlet.ReadListener toJakartaReadListener(ReadListener from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ReadListener() { + @Override + public void onDataAvailable() throws IOException { + from.onDataAvailable(); + } + + @Override + public void onAllDataRead() throws IOException { + from.onAllDataRead(); + } + + @Override + public void onError(Throwable throwable) { + from.onError(throwable); + } + }; + } + + public static ReadListener fromJakartaReadListener(jakarta.servlet.ReadListener from) { + Objects.requireNonNull(from); + return new ReadListener() { + @Override + public void onDataAvailable() throws IOException { + from.onDataAvailable(); + } + + @Override + public void onAllDataRead() throws IOException { + from.onAllDataRead(); + } + + @Override + public void onError(Throwable t) { + from.onError(t); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/RegistrationDynamicWrapper.java b/core/src/main/java/io/jenkins/servlet/RegistrationDynamicWrapper.java new file mode 100644 index 000000000..07f23ef1b --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/RegistrationDynamicWrapper.java @@ -0,0 +1,88 @@ +package io.jenkins.servlet; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.servlet.Registration; + +public class RegistrationDynamicWrapper { + public static jakarta.servlet.Registration.Dynamic toJakartaRegistrationDynamic(Registration.Dynamic from) { + Objects.requireNonNull(from); + return new jakarta.servlet.Registration.Dynamic() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + }; + } + + public static Registration.Dynamic fromJakartaRegistrationDynamic(jakarta.servlet.Registration.Dynamic from) { + Objects.requireNonNull(from); + return new Registration.Dynamic() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/RegistrationWrapper.java b/core/src/main/java/io/jenkins/servlet/RegistrationWrapper.java new file mode 100644 index 000000000..868e61f3e --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/RegistrationWrapper.java @@ -0,0 +1,78 @@ +package io.jenkins.servlet; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.servlet.Registration; + +public class RegistrationWrapper { + public static jakarta.servlet.Registration toJakartaRegistration(Registration from) { + Objects.requireNonNull(from); + return new jakarta.servlet.Registration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + }; + } + + public static Registration fromJakartaRegistration(jakarta.servlet.Registration from) { + Objects.requireNonNull(from); + return new Registration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/RequestDispatcherWrapper.java b/core/src/main/java/io/jenkins/servlet/RequestDispatcherWrapper.java new file mode 100644 index 000000000..49df4816c --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/RequestDispatcherWrapper.java @@ -0,0 +1,111 @@ +package io.jenkins.servlet; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Objects; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class RequestDispatcherWrapper { + public static jakarta.servlet.RequestDispatcher toJakartaRequestDispatcher(RequestDispatcher from) { + Objects.requireNonNull(from); + return new jakarta.servlet.RequestDispatcher() { + @Override + @SuppressFBWarnings(value = "REQUESTDISPATCHER_FILE_DISCLOSURE", justification = "for compatibility") + public void forward(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) + throws jakarta.servlet.ServletException, IOException { + try { + if (request instanceof jakarta.servlet.http.HttpServletRequest + && response instanceof jakarta.servlet.http.HttpServletResponse) { + jakarta.servlet.http.HttpServletRequest httpRequest = + (jakarta.servlet.http.HttpServletRequest) request; + jakarta.servlet.http.HttpServletResponse httpResponse = + (jakarta.servlet.http.HttpServletResponse) response; + from.forward( + HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.fromJakartaHttpServletResponse(httpResponse)); + } else { + from.forward( + io.jenkins.servlet.ServletRequestWrapper.fromJakartaServletRequest(request), + ServletResponseWrapper.fromJakartaServletResponse(response)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + @SuppressFBWarnings(value = "REQUESTDISPATCHER_FILE_DISCLOSURE", justification = "for compatibility") + public void include(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) + throws jakarta.servlet.ServletException, IOException { + try { + if (request instanceof jakarta.servlet.http.HttpServletRequest + && response instanceof jakarta.servlet.http.HttpServletResponse) { + jakarta.servlet.http.HttpServletRequest httpRequest = + (jakarta.servlet.http.HttpServletRequest) request; + jakarta.servlet.http.HttpServletResponse httpResponse = + (jakarta.servlet.http.HttpServletResponse) response; + from.include( + HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.fromJakartaHttpServletResponse(httpResponse)); + } else { + from.include( + ServletRequestWrapper.fromJakartaServletRequest(request), + ServletResponseWrapper.fromJakartaServletResponse(response)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + }; + } + + public static RequestDispatcher fromJakartaRequestDispatcher(jakarta.servlet.RequestDispatcher from) { + Objects.requireNonNull(from); + return new RequestDispatcher() { + @Override + public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { + try { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + from.forward( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse)); + } else { + from.forward( + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response)); + } + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { + try { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + from.include( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse)); + } else { + from.include( + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response)); + } + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletConfigWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletConfigWrapper.java new file mode 100644 index 000000000..cfbc3fe7a --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletConfigWrapper.java @@ -0,0 +1,58 @@ +package io.jenkins.servlet; + +import java.util.Enumeration; +import java.util.Objects; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +public class ServletConfigWrapper { + public static jakarta.servlet.ServletConfig toJakartaServletConfig(ServletConfig from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletConfig() { + @Override + public String getServletName() { + return from.getServletName(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + }; + } + + public static ServletConfig fromJakartaServletConfig(jakarta.servlet.ServletConfig from) { + Objects.requireNonNull(from); + return new ServletConfig() { + @Override + public String getServletName() { + return from.getServletName(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletContextEventWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletContextEventWrapper.java new file mode 100644 index 000000000..23cc232fb --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletContextEventWrapper.java @@ -0,0 +1,17 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.ServletContextEvent; + +public class ServletContextEventWrapper { + public static jakarta.servlet.ServletContextEvent toJakartaServletContextEvent(ServletContextEvent from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletContextEvent( + ServletContextWrapper.toJakartaServletContext(from.getServletContext())); + } + + public static ServletContextEvent fromJakartaServletContextEvent(jakarta.servlet.ServletContextEvent from) { + Objects.requireNonNull(from); + return new ServletContextEvent(ServletContextWrapper.fromJakartServletContext(from.getServletContext())); + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletContextWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletContextWrapper.java new file mode 100644 index 000000000..055a7f342 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletContextWrapper.java @@ -0,0 +1,712 @@ +package io.jenkins.servlet; + +import io.jenkins.servlet.descriptor.JspConfigDescriptorWrapper; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; + +public class ServletContextWrapper { + public static jakarta.servlet.ServletContext toJakartaServletContext(ServletContext from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletContext() { + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public jakarta.servlet.ServletContext getContext(String uripath) { + ServletContext context = from.getContext(uripath); + return context != null ? toJakartaServletContext(context) : null; + } + + @Override + public int getMajorVersion() { + return from.getMajorVersion(); + } + + @Override + public int getMinorVersion() { + return from.getMinorVersion(); + } + + @Override + public int getEffectiveMajorVersion() { + return from.getEffectiveMajorVersion(); + } + + @Override + public int getEffectiveMinorVersion() { + return from.getEffectiveMinorVersion(); + } + + @Override + public String getMimeType(String file) { + return from.getMimeType(file); + } + + @Override + public Set getResourcePaths(String paths) { + return from.getResourcePaths(paths); + } + + @Override + public URL getResource(String path) throws MalformedURLException { + return from.getResource(path); + } + + @Override + public InputStream getResourceAsStream(String path) { + return from.getResourceAsStream(path); + } + + @Override + public jakarta.servlet.RequestDispatcher getRequestDispatcher(String path) { + RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.toJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public jakarta.servlet.RequestDispatcher getNamedDispatcher(String path) { + RequestDispatcher namedDispatcher = from.getNamedDispatcher(path); + return namedDispatcher != null + ? RequestDispatcherWrapper.toJakartaRequestDispatcher(namedDispatcher) + : null; + } + + @Override + public jakarta.servlet.Servlet getServlet(String name) throws jakarta.servlet.ServletException { + try { + return ServletWrapper.toJakartaServlet(from.getServlet(name)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public Enumeration getServlets() { + return Collections.enumeration(Collections.list(from.getServlets()).stream() + .map(ServletWrapper::toJakartaServlet) + .collect(Collectors.toList())); + } + + @Override + public Enumeration getServletNames() { + return from.getServletNames(); + } + + @Override + public void log(String msg) { + from.log(msg); + } + + @Override + public void log(Exception exception, String msg) { + from.log(exception, msg); + } + + @Override + public void log(String message, Throwable throwable) { + from.log(message, throwable); + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public String getServerInfo() { + return from.getServerInfo(); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public void setAttribute(String name, Object object) { + from.setAttribute(name, object); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public String getServletContextName() { + return from.getServletContextName(); + } + + @Override + public jakarta.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className) { + return ServletRegistrationDynamicWrapper.toJakartaServletRegistrationDynamic( + from.addServlet(servletName, className)); + } + + @Override + public jakarta.servlet.ServletRegistration.Dynamic addServlet( + String servletName, jakarta.servlet.Servlet servlet) { + return ServletRegistrationDynamicWrapper.toJakartaServletRegistrationDynamic( + from.addServlet(servletName, ServletWrapper.fromJakartaServlet(servlet))); + } + + @Override + public jakarta.servlet.ServletRegistration.Dynamic addServlet( + String servletName, Class servletClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public jakarta.servlet.ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + return ServletRegistrationDynamicWrapper.toJakartaServletRegistrationDynamic( + from.addJspFile(servletName, jspFile)); + } + + @Override + public T createServlet(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public jakarta.servlet.ServletRegistration getServletRegistration(String servletName) { + return ServletRegistrationWrapper.toJakartaServletRegistration( + from.getServletRegistration(servletName)); + } + + @Override + public Map getServletRegistrations() { + return from.getServletRegistrations().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> ServletRegistrationWrapper.toJakartaServletRegistration(entry.getValue()))); + } + + @Override + public jakarta.servlet.FilterRegistration.Dynamic addFilter(String filterName, String className) { + return FilterRegistrationDynamicWrapper.toJakartaFilterRegistrationDynamic( + from.addFilter(filterName, className)); + } + + @Override + public jakarta.servlet.FilterRegistration.Dynamic addFilter( + String filterName, jakarta.servlet.Filter filter) { + return FilterRegistrationDynamicWrapper.toJakartaFilterRegistrationDynamic( + from.addFilter(filterName, FilterWrapper.fromJakartaFilter(filter))); + } + + @Override + public jakarta.servlet.FilterRegistration.Dynamic addFilter( + String filterName, Class filterClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public T createFilter(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public jakarta.servlet.FilterRegistration getFilterRegistration(String filterName) { + return FilterRegistrationWrapper.toJakartaFilterRegistration(from.getFilterRegistration(filterName)); + } + + @Override + public Map getFilterRegistrations() { + return from.getFilterRegistrations().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> FilterRegistrationWrapper.toJakartaFilterRegistration(entry.getValue()))); + } + + @Override + public jakarta.servlet.SessionCookieConfig getSessionCookieConfig() { + return SessionCookieConfigWrapper.toJakartaSessionCookieConfig(from.getSessionCookieConfig()); + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + from.setSessionTrackingModes(sessionTrackingModes.stream() + .map(SessionTrackingModeWrapper::fromJakartaSessionTrackingMode) + .collect(Collectors.toSet())); + } + + @Override + public Set getDefaultSessionTrackingModes() { + return from.getDefaultSessionTrackingModes().stream() + .map(SessionTrackingModeWrapper::toJakartaSessionTrackingMode) + .collect(Collectors.toSet()); + } + + @Override + public Set getEffectiveSessionTrackingModes() { + return from.getEffectiveSessionTrackingModes().stream() + .map(SessionTrackingModeWrapper::toJakartaSessionTrackingMode) + .collect(Collectors.toSet()); + } + + @Override + public void addListener(String className) { + from.addListener(className); + } + + @Override + public void addListener(T t) { + from.addListener(t); + } + + @Override + public void addListener(Class listenerClass) { + from.addListener(listenerClass); + } + + @Override + public T createListener(Class clazz) throws jakarta.servlet.ServletException { + try { + return from.createListener(clazz); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public jakarta.servlet.descriptor.JspConfigDescriptor getJspConfigDescriptor() { + JspConfigDescriptor jspConfigDescriptor = from.getJspConfigDescriptor(); + return jspConfigDescriptor != null + ? JspConfigDescriptorWrapper.toJakartaJspConfigDescriptor(jspConfigDescriptor) + : null; + } + + @Override + public ClassLoader getClassLoader() { + return from.getClassLoader(); + } + + @Override + public void declareRoles(String... roleNames) { + from.declareRoles(roleNames); + } + + @Override + public String getVirtualServerName() { + return from.getVirtualServerName(); + } + + @Override + public int getSessionTimeout() { + return from.getSessionTimeout(); + } + + @Override + public void setSessionTimeout(int sessionTimeout) { + from.setSessionTimeout(sessionTimeout); + } + + @Override + public String getRequestCharacterEncoding() { + return from.getRequestCharacterEncoding(); + } + + @Override + public void setRequestCharacterEncoding(String encoding) { + from.setRequestCharacterEncoding(encoding); + } + + @Override + public String getResponseCharacterEncoding() { + return from.getResponseCharacterEncoding(); + } + + @Override + public void setResponseCharacterEncoding(String encoding) { + from.setResponseCharacterEncoding(encoding); + } + }; + } + + public static ServletContext fromJakartServletContext(jakarta.servlet.ServletContext from) { + Objects.requireNonNull(from); + return new ServletContext() { + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public ServletContext getContext(String uripath) { + jakarta.servlet.ServletContext context = from.getContext(uripath); + return context != null ? fromJakartServletContext(context) : null; + } + + @Override + public int getMajorVersion() { + return from.getMajorVersion(); + } + + @Override + public int getMinorVersion() { + return from.getMinorVersion(); + } + + @Override + public int getEffectiveMajorVersion() { + return from.getEffectiveMajorVersion(); + } + + @Override + public int getEffectiveMinorVersion() { + return from.getEffectiveMinorVersion(); + } + + @Override + public String getMimeType(String file) { + return from.getMimeType(file); + } + + @Override + public Set getResourcePaths(String path) { + return from.getResourcePaths(path); + } + + @Override + public URL getResource(String path) throws MalformedURLException { + return from.getResource(path); + } + + @Override + public InputStream getResourceAsStream(String path) { + return from.getResourceAsStream(path); + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + jakarta.servlet.RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public RequestDispatcher getNamedDispatcher(String name) { + jakarta.servlet.RequestDispatcher namedDispatcher = from.getNamedDispatcher(name); + return namedDispatcher != null + ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(namedDispatcher) + : null; + } + + @Override + public Servlet getServlet(String name) throws ServletException { + try { + return ServletWrapper.fromJakartaServlet(from.getServlet(name)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public Enumeration getServlets() { + return Collections.enumeration(Collections.list(from.getServlets()).stream() + .map(ServletWrapper::fromJakartaServlet) + .collect(Collectors.toList())); + } + + @Override + public Enumeration getServletNames() { + return from.getServletNames(); + } + + @Override + public void log(String msg) { + from.log(msg); + } + + @Override + public void log(Exception exception, String msg) { + from.log(exception, msg); + } + + @Override + public void log(String message, Throwable throwable) { + from.log(message, throwable); + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public String getServerInfo() { + return from.getServerInfo(); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Enumeration getInitParameterNames() { + return from.getInitParameterNames(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public void setAttribute(String name, Object object) { + from.setAttribute(name, object); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public String getServletContextName() { + return from.getServletContextName(); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, String className) { + return ServletRegistrationDynamicWrapper.fromJakartaServletRegistrationDynamic( + from.addServlet(servletName, className)); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { + return ServletRegistrationDynamicWrapper.fromJakartaServletRegistrationDynamic( + from.addServlet(servletName, ServletWrapper.toJakartaServlet(servlet))); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + return ServletRegistrationDynamicWrapper.fromJakartaServletRegistrationDynamic( + from.addJspFile(servletName, jspFile)); + } + + @Override + public T createServlet(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration getServletRegistration(String servletName) { + return ServletRegistrationWrapper.fromJakartaServletRegistration( + from.getServletRegistration(servletName)); + } + + @Override + public Map getServletRegistrations() { + return from.getServletRegistrations().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> ServletRegistrationWrapper.fromJakartaServletRegistration(entry.getValue()))); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, String className) { + return FilterRegistrationDynamicWrapper.fromJakartaFilterRegistrationDynamic( + from.addFilter(filterName, className)); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + return FilterRegistrationDynamicWrapper.fromJakartaFilterRegistrationDynamic( + from.addFilter(filterName, FilterWrapper.toJakartaFilter(filter))); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public T createFilter(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) { + return FilterRegistrationWrapper.fromJakartaFilterRegistration(from.getFilterRegistration(filterName)); + } + + @Override + public Map getFilterRegistrations() { + return from.getFilterRegistrations().entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> FilterRegistrationWrapper.fromJakartaFilterRegistration(entry.getValue()))); + } + + @Override + public SessionCookieConfig getSessionCookieConfig() { + return SessionCookieConfigWrapper.fromJakartaSessionCookieConfig(from.getSessionCookieConfig()); + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + from.setSessionTrackingModes(sessionTrackingModes.stream() + .map(SessionTrackingModeWrapper::toJakartaSessionTrackingMode) + .collect(Collectors.toSet())); + } + + @Override + public Set getDefaultSessionTrackingModes() { + return from.getDefaultSessionTrackingModes().stream() + .map(SessionTrackingModeWrapper::fromJakartaSessionTrackingMode) + .collect(Collectors.toSet()); + } + + @Override + public Set getEffectiveSessionTrackingModes() { + return from.getEffectiveSessionTrackingModes().stream() + .map(SessionTrackingModeWrapper::fromJakartaSessionTrackingMode) + .collect(Collectors.toSet()); + } + + @Override + public void addListener(String className) { + from.addListener(className); + } + + @Override + public void addListener(T t) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void addListener(Class listenerClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public T createListener(Class clazz) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + jakarta.servlet.descriptor.JspConfigDescriptor jspConfigDescriptor = from.getJspConfigDescriptor(); + return jspConfigDescriptor != null + ? JspConfigDescriptorWrapper.fromJakartaJspConfigDescriptor(jspConfigDescriptor) + : null; + } + + @Override + public ClassLoader getClassLoader() { + return from.getClassLoader(); + } + + @Override + public void declareRoles(String... roleNames) { + from.declareRoles(roleNames); + } + + @Override + public String getVirtualServerName() { + return from.getVirtualServerName(); + } + + @Override + public int getSessionTimeout() { + return from.getSessionTimeout(); + } + + @Override + public void setSessionTimeout(int sessionTimeout) { + from.setSessionTimeout(sessionTimeout); + } + + @Override + public String getRequestCharacterEncoding() { + return from.getRequestCharacterEncoding(); + } + + @Override + public void setRequestCharacterEncoding(String encoding) { + from.setRequestCharacterEncoding(encoding); + } + + @Override + public String getResponseCharacterEncoding() { + return from.getResponseCharacterEncoding(); + } + + @Override + public void setResponseCharacterEncoding(String encoding) { + from.setResponseCharacterEncoding(encoding); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletExceptionWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletExceptionWrapper.java new file mode 100644 index 000000000..3a677d044 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletExceptionWrapper.java @@ -0,0 +1,16 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.ServletException; + +public class ServletExceptionWrapper { + public static jakarta.servlet.ServletException toJakartaServletException(ServletException e) { + Objects.requireNonNull(e); + return new jakarta.servlet.ServletException(e.toString(), e); + } + + public static ServletException fromJakartaServletException(jakarta.servlet.ServletException e) { + Objects.requireNonNull(e); + return new ServletException(e.toString(), e); + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletInputStreamWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletInputStreamWrapper.java new file mode 100644 index 000000000..dbd0603ff --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletInputStreamWrapper.java @@ -0,0 +1,189 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Objects; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; + +public class ServletInputStreamWrapper { + public static jakarta.servlet.ServletInputStream toJakartaServletInputStream(ServletInputStream from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletInputStream() { + @Override + public int read() throws IOException { + return from.read(); + } + + @Override + public int readLine(byte[] b, int off, int len) throws IOException { + return from.readLine(b, off, len); + } + + @Override + public int read(byte[] b) throws IOException { + return from.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return from.read(b, off, len); + } + + @Override + public byte[] readAllBytes() throws IOException { + return from.readAllBytes(); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + return from.readNBytes(len); + } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + return from.readNBytes(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return from.skip(n); + } + + @Override + public int available() throws IOException { + return from.available(); + } + + @Override + public void close() throws IOException { + from.close(); + } + + @Override + public synchronized void mark(int readlimit) { + from.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + from.reset(); + } + + @Override + public boolean markSupported() { + return from.markSupported(); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + return from.transferTo(out); + } + + @Override + public boolean isFinished() { + return from.isFinished(); + } + + @Override + public boolean isReady() { + return from.isReady(); + } + + @Override + public void setReadListener(jakarta.servlet.ReadListener readListener) { + from.setReadListener(ReadListenerWrapper.fromJakartaReadListener(readListener)); + } + }; + } + + public static ServletInputStream fromJakartaServletInputStream(jakarta.servlet.ServletInputStream from) { + Objects.requireNonNull(from); + return new ServletInputStream() { + @Override + public int readLine(byte[] b, int off, int len) throws IOException { + return from.readLine(b, off, len); + } + + @Override + public int read(byte[] b) throws IOException { + return from.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return from.read(b, off, len); + } + + @Override + public byte[] readAllBytes() throws IOException { + return from.readAllBytes(); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + return from.readNBytes(len); + } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + return from.readNBytes(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return from.skip(n); + } + + @Override + public int available() throws IOException { + return from.available(); + } + + @Override + public void close() throws IOException { + from.close(); + } + + @Override + public synchronized void mark(int readlimit) { + from.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + from.reset(); + } + + @Override + public boolean markSupported() { + return from.markSupported(); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + return from.transferTo(out); + } + + @Override + public boolean isFinished() { + return from.isFinished(); + } + + @Override + public boolean isReady() { + return from.isReady(); + } + + @Override + public void setReadListener(ReadListener readListener) { + from.setReadListener(ReadListenerWrapper.toJakartaReadListener(readListener)); + } + + @Override + public int read() throws IOException { + return from.read(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletOutputStreamWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletOutputStreamWrapper.java new file mode 100644 index 000000000..7f4ed470d --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletOutputStreamWrapper.java @@ -0,0 +1,238 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.util.Objects; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; + +public class ServletOutputStreamWrapper { + public static jakarta.servlet.ServletOutputStream toJakartaServletOutputStream(ServletOutputStream from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletOutputStream() { + @Override + public void print(String s) throws IOException { + from.print(s); + } + + @Override + public void print(boolean b) throws IOException { + from.print(b); + } + + @Override + public void print(char c) throws IOException { + from.print(c); + } + + @Override + public void print(int i) throws IOException { + from.print(i); + } + + @Override + public void print(long l) throws IOException { + from.print(l); + } + + @Override + public void print(float f) throws IOException { + from.print(f); + } + + @Override + public void print(double d) throws IOException { + from.print(d); + } + + @Override + public void println() throws IOException { + from.println(); + } + + @Override + public void println(String s) throws IOException { + from.println(s); + } + + @Override + public void println(boolean b) throws IOException { + from.println(b); + } + + @Override + public void println(char c) throws IOException { + from.println(c); + } + + @Override + public void println(int i) throws IOException { + from.println(i); + } + + @Override + public void println(long l) throws IOException { + from.println(l); + } + + @Override + public void println(float f) throws IOException { + from.println(f); + } + + @Override + public void println(double d) throws IOException { + from.println(d); + } + + @Override + public void write(byte[] b) throws IOException { + from.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + from.write(b, off, len); + } + + @Override + public void flush() throws IOException { + from.flush(); + } + + @Override + public void close() throws IOException { + from.close(); + } + + @Override + public boolean isReady() { + return from.isReady(); + } + + @Override + public void setWriteListener(jakarta.servlet.WriteListener writeListener) { + from.setWriteListener(WriteListenerWrapper.fromJakartaWriteListener(writeListener)); + } + + @Override + public void write(int b) throws IOException { + from.write(b); + } + }; + } + + public static ServletOutputStream fromJakartaServletOutputStream(jakarta.servlet.ServletOutputStream from) { + Objects.requireNonNull(from); + return new ServletOutputStream() { + @Override + public void print(String s) throws IOException { + from.print(s); + } + + @Override + public void print(boolean b) throws IOException { + from.print(b); + } + + @Override + public void print(char c) throws IOException { + from.print(c); + } + + @Override + public void print(int i) throws IOException { + from.print(i); + } + + @Override + public void print(long l) throws IOException { + from.print(l); + } + + @Override + public void print(float f) throws IOException { + from.print(f); + } + + @Override + public void print(double d) throws IOException { + from.print(d); + } + + @Override + public void println() throws IOException { + from.println(); + } + + @Override + public void println(String s) throws IOException { + from.println(s); + } + + @Override + public void println(boolean b) throws IOException { + from.println(b); + } + + @Override + public void println(char c) throws IOException { + from.println(c); + } + + @Override + public void println(int i) throws IOException { + from.println(i); + } + + @Override + public void println(long l) throws IOException { + from.println(l); + } + + @Override + public void println(float f) throws IOException { + from.println(f); + } + + @Override + public void println(double d) throws IOException { + from.println(d); + } + + @Override + public void write(byte[] b) throws IOException { + from.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + from.write(b, off, len); + } + + @Override + public void flush() throws IOException { + from.flush(); + } + + @Override + public void close() throws IOException { + from.close(); + } + + @Override + public boolean isReady() { + return from.isReady(); + } + + @Override + public void setWriteListener(WriteListener writeListener) { + from.setWriteListener(WriteListenerWrapper.toJakartaWriteListener(writeListener)); + } + + @Override + public void write(int b) throws IOException { + from.write(b); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletRegistrationDynamicWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletRegistrationDynamicWrapper.java new file mode 100644 index 000000000..5104ec130 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletRegistrationDynamicWrapper.java @@ -0,0 +1,167 @@ +package io.jenkins.servlet; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.servlet.MultipartConfigElement; +import javax.servlet.ServletRegistration; +import javax.servlet.ServletSecurityElement; + +public class ServletRegistrationDynamicWrapper { + public static jakarta.servlet.ServletRegistration.Dynamic toJakartaServletRegistrationDynamic( + ServletRegistration.Dynamic from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletRegistration.Dynamic() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public Set addMapping(String... urlPatterns) { + return from.addMapping(urlPatterns); + } + + @Override + public Collection getMappings() { + return from.getMappings(); + } + + @Override + public String getRunAsRole() { + return from.getRunAsRole(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + + @Override + public void setLoadOnStartup(int loadOnStartup) { + from.setLoadOnStartup(loadOnStartup); + } + + @Override + public Set setServletSecurity(jakarta.servlet.ServletSecurityElement constraint) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setMultipartConfig(jakarta.servlet.MultipartConfigElement multipartConfig) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setRunAsRole(String roleName) { + from.setRunAsRole(roleName); + } + }; + } + + public static ServletRegistration.Dynamic fromJakartaServletRegistrationDynamic( + jakarta.servlet.ServletRegistration.Dynamic from) { + Objects.requireNonNull(from); + return new ServletRegistration.Dynamic() { + @Override + public void setLoadOnStartup(int loadOnStartup) { + from.setLoadOnStartup(loadOnStartup); + } + + @Override + public Set setServletSecurity(ServletSecurityElement constraint) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setMultipartConfig(MultipartConfigElement multipartConfig) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public void setRunAsRole(String roleName) { + from.setRunAsRole(roleName); + } + + @Override + public Set addMapping(String... urlPatterns) { + return from.addMapping(urlPatterns); + } + + @Override + public Collection getMappings() { + return from.getMappings(); + } + + @Override + public String getRunAsRole() { + return from.getRunAsRole(); + } + + @Override + public void setAsyncSupported(boolean isAsyncSupported) { + from.setAsyncSupported(isAsyncSupported); + } + + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletRegistrationWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletRegistrationWrapper.java new file mode 100644 index 000000000..5cc94764f --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletRegistrationWrapper.java @@ -0,0 +1,109 @@ +package io.jenkins.servlet; + +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import javax.servlet.ServletRegistration; + +public class ServletRegistrationWrapper { + public static jakarta.servlet.ServletRegistration toJakartaServletRegistration(ServletRegistration from) { + Objects.requireNonNull(from); + return new jakarta.servlet.ServletRegistration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public Set addMapping(String... urlPatterns) { + return from.addMapping(urlPatterns); + } + + @Override + public Collection getMappings() { + return from.getMappings(); + } + + @Override + public String getRunAsRole() { + return from.getRunAsRole(); + } + }; + } + + public static ServletRegistration fromJakartaServletRegistration(jakarta.servlet.ServletRegistration from) { + Objects.requireNonNull(from); + return new ServletRegistration() { + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getClassName() { + return from.getClassName(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return from.setInitParameter(name, value); + } + + @Override + public String getInitParameter(String name) { + return from.getInitParameter(name); + } + + @Override + public Set setInitParameters(Map initParameters) { + return from.setInitParameters(initParameters); + } + + @Override + public Map getInitParameters() { + return from.getInitParameters(); + } + + @Override + public Set addMapping(String... urlPatterns) { + return from.addMapping(urlPatterns); + } + + @Override + public Collection getMappings() { + return from.getMappings(); + } + + @Override + public String getRunAsRole() { + return from.getRunAsRole(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletRequestWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletRequestWrapper.java new file mode 100644 index 000000000..afb4c68ca --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletRequestWrapper.java @@ -0,0 +1,448 @@ +package io.jenkins.servlet; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class ServletRequestWrapper { + public static jakarta.servlet.ServletRequest toJakartaServletRequest(ServletRequest from) { + if (from instanceof JavaxServletRequestWrapper javax) { + return javax.toJakartaServletRequest(); + } + return new JakartaServletRequestWrapperImpl(from); + } + + public static ServletRequest fromJakartaServletRequest(jakarta.servlet.ServletRequest from) { + if (from instanceof JakartaServletRequestWrapper jakarta) { + return jakarta.toJavaxServletRequest(); + } + return new JavaxServletRequestWrapperImpl(from); + } + + public interface JakartaServletRequestWrapper { + ServletRequest toJavaxServletRequest(); + } + + private static class JakartaServletRequestWrapperImpl + implements jakarta.servlet.ServletRequest, JakartaServletRequestWrapper { + private final ServletRequest from; + + JakartaServletRequestWrapperImpl(ServletRequest from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.toJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public jakarta.servlet.RequestDispatcher getRequestDispatcher(String path) { + RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.toJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public jakarta.servlet.AsyncContext startAsync() { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync()); + } + + @Override + public jakarta.servlet.AsyncContext startAsync( + jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse) { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync( + fromJakartaServletRequest(servletRequest), + ServletResponseWrapper.fromJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public jakarta.servlet.AsyncContext getAsyncContext() { + return AsyncContextWrapper.toJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public jakarta.servlet.DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.toJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public ServletRequest toJavaxServletRequest() { + return from; + } + } + + public interface JavaxServletRequestWrapper { + jakarta.servlet.ServletRequest toJakartaServletRequest(); + } + + private static class JavaxServletRequestWrapperImpl implements ServletRequest, JavaxServletRequestWrapper { + private final jakarta.servlet.ServletRequest from; + + JavaxServletRequestWrapperImpl(jakarta.servlet.ServletRequest from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.fromJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + jakarta.servlet.RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public AsyncContext startAsync() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync()); + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync( + ServletRequestWrapper.toJakartaServletRequest(servletRequest), + ServletResponseWrapper.toJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public AsyncContext getAsyncContext() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.fromJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public jakarta.servlet.ServletRequest toJakartaServletRequest() { + return from; + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletResponseWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletResponseWrapper.java new file mode 100644 index 000000000..784f64334 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletResponseWrapper.java @@ -0,0 +1,219 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; +import java.util.Objects; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; + +public class ServletResponseWrapper { + public static jakarta.servlet.ServletResponse toJakartaServletResponse(ServletResponse from) { + if (from instanceof JavaxServletResponseWrapper javax) { + return javax.toJakartaServletResponse(); + } + return new JakartaServletResponseWrapperImpl(from); + } + + public static ServletResponse fromJakartaServletResponse(jakarta.servlet.ServletResponse from) { + if (from instanceof JakartaServletResponseWrapper jakarta) { + return jakarta.toJavaxServletResponse(); + } + return new JavaxServletResponseWrapperImpl(from); + } + + public interface JakartaServletResponseWrapper { + ServletResponse toJavaxServletResponse(); + } + + private static class JakartaServletResponseWrapperImpl + implements jakarta.servlet.ServletResponse, JakartaServletResponseWrapper { + private final ServletResponse from; + + JakartaServletResponseWrapperImpl(ServletResponse from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.toJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public ServletResponse toJavaxServletResponse() { + return from; + } + } + + public interface JavaxServletResponseWrapper { + jakarta.servlet.ServletResponse toJakartaServletResponse(); + } + + private static class JavaxServletResponseWrapperImpl implements ServletResponse, JavaxServletResponseWrapper { + private final jakarta.servlet.ServletResponse from; + + JavaxServletResponseWrapperImpl(jakarta.servlet.ServletResponse from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.fromJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public jakarta.servlet.ServletResponse toJakartaServletResponse() { + return from; + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/ServletWrapper.java b/core/src/main/java/io/jenkins/servlet/ServletWrapper.java new file mode 100644 index 000000000..7a9d5a79f --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/ServletWrapper.java @@ -0,0 +1,115 @@ +package io.jenkins.servlet; + +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Objects; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class ServletWrapper { + public static jakarta.servlet.Servlet toJakartaServlet(Servlet from) { + Objects.requireNonNull(from); + return new jakarta.servlet.Servlet() { + @Override + public void init(jakarta.servlet.ServletConfig config) throws jakarta.servlet.ServletException { + try { + from.init(ServletConfigWrapper.fromJakartaServletConfig(config)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public jakarta.servlet.ServletConfig getServletConfig() { + return ServletConfigWrapper.toJakartaServletConfig(from.getServletConfig()); + } + + @Override + public void service(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) + throws jakarta.servlet.ServletException, IOException { + try { + if (request instanceof jakarta.servlet.http.HttpServletRequest + && response instanceof jakarta.servlet.http.HttpServletResponse) { + jakarta.servlet.http.HttpServletRequest httpRequest = + (jakarta.servlet.http.HttpServletRequest) request; + jakarta.servlet.http.HttpServletResponse httpResponse = + (jakarta.servlet.http.HttpServletResponse) response; + from.service( + HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.fromJakartaHttpServletResponse(httpResponse)); + } else { + from.service( + ServletRequestWrapper.fromJakartaServletRequest(request), + ServletResponseWrapper.fromJakartaServletResponse(response)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public String getServletInfo() { + return from.getServletInfo(); + } + + @Override + public void destroy() { + from.destroy(); + } + }; + } + + public static Servlet fromJakartaServlet(jakarta.servlet.Servlet from) { + Objects.requireNonNull(from); + return new Servlet() { + @Override + public void init(ServletConfig config) throws ServletException { + try { + from.init(ServletConfigWrapper.toJakartaServletConfig(config)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public ServletConfig getServletConfig() { + return ServletConfigWrapper.fromJakartaServletConfig(from.getServletConfig()); + } + + @Override + public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { + try { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + from.service( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse)); + } else { + from.service( + io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response)); + } + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public String getServletInfo() { + return from.getServletInfo(); + } + + @Override + public void destroy() { + from.destroy(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/SessionCookieConfigWrapper.java b/core/src/main/java/io/jenkins/servlet/SessionCookieConfigWrapper.java new file mode 100644 index 000000000..b6e095062 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/SessionCookieConfigWrapper.java @@ -0,0 +1,156 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.SessionCookieConfig; + +public class SessionCookieConfigWrapper { + public static jakarta.servlet.SessionCookieConfig toJakartaSessionCookieConfig(SessionCookieConfig from) { + Objects.requireNonNull(from); + return new jakarta.servlet.SessionCookieConfig() { + @Override + public void setName(String name) { + from.setName(name); + } + + @Override + public String getName() { + return from.getName(); + } + + @Override + public void setDomain(String domain) { + from.setDomain(domain); + } + + @Override + public String getDomain() { + return from.getDomain(); + } + + @Override + public void setPath(String path) { + from.setPath(path); + } + + @Override + public String getPath() { + return from.getPath(); + } + + @Override + public void setComment(String comment) { + from.setComment(comment); + } + + @Override + public String getComment() { + return from.getComment(); + } + + @Override + public void setHttpOnly(boolean httpOnly) { + from.setHttpOnly(httpOnly); + } + + @Override + public boolean isHttpOnly() { + return from.isHttpOnly(); + } + + @Override + public void setSecure(boolean secure) { + from.setSecure(secure); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public void setMaxAge(int maxAge) { + from.setMaxAge(maxAge); + } + + @Override + public int getMaxAge() { + return from.getMaxAge(); + } + }; + } + + public static SessionCookieConfig fromJakartaSessionCookieConfig(jakarta.servlet.SessionCookieConfig from) { + Objects.requireNonNull(from); + return new SessionCookieConfig() { + @Override + public void setName(String name) { + from.setName(name); + } + + @Override + public String getName() { + return from.getName(); + } + + @Override + public void setDomain(String domain) { + from.setDomain(domain); + } + + @Override + public String getDomain() { + return from.getDomain(); + } + + @Override + public void setPath(String path) { + from.setPath(path); + } + + @Override + public String getPath() { + return from.getPath(); + } + + @Override + public void setComment(String comment) { + from.setComment(comment); + } + + @Override + public String getComment() { + return from.getComment(); + } + + @Override + public void setHttpOnly(boolean httpOnly) { + from.setHttpOnly(httpOnly); + } + + @Override + public boolean isHttpOnly() { + return from.isHttpOnly(); + } + + @Override + public void setSecure(boolean secure) { + from.setSecure(secure); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public void setMaxAge(int maxAge) { + from.setMaxAge(maxAge); + } + + @Override + public int getMaxAge() { + return from.getMaxAge(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/SessionTrackingModeWrapper.java b/core/src/main/java/io/jenkins/servlet/SessionTrackingModeWrapper.java new file mode 100644 index 000000000..e352263bb --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/SessionTrackingModeWrapper.java @@ -0,0 +1,34 @@ +package io.jenkins.servlet; + +import java.util.Objects; +import javax.servlet.SessionTrackingMode; + +public class SessionTrackingModeWrapper { + public static jakarta.servlet.SessionTrackingMode toJakartaSessionTrackingMode(SessionTrackingMode from) { + Objects.requireNonNull(from); + switch (from) { + case COOKIE: + return jakarta.servlet.SessionTrackingMode.COOKIE; + case URL: + return jakarta.servlet.SessionTrackingMode.URL; + case SSL: + return jakarta.servlet.SessionTrackingMode.SSL; + default: + throw new IllegalArgumentException("Unknown SessionTrackingMode: " + from); + } + } + + public static SessionTrackingMode fromJakartaSessionTrackingMode(jakarta.servlet.SessionTrackingMode from) { + Objects.requireNonNull(from); + switch (from) { + case COOKIE: + return SessionTrackingMode.COOKIE; + case URL: + return SessionTrackingMode.URL; + case SSL: + return SessionTrackingMode.SSL; + default: + throw new IllegalArgumentException("Unknown SessionTrackingMode: " + from); + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/WriteListenerWrapper.java b/core/src/main/java/io/jenkins/servlet/WriteListenerWrapper.java new file mode 100644 index 000000000..5faf3eb3b --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/WriteListenerWrapper.java @@ -0,0 +1,37 @@ +package io.jenkins.servlet; + +import java.io.IOException; +import java.util.Objects; +import javax.servlet.WriteListener; + +public class WriteListenerWrapper { + public static jakarta.servlet.WriteListener toJakartaWriteListener(WriteListener from) { + Objects.requireNonNull(from); + return new jakarta.servlet.WriteListener() { + @Override + public void onWritePossible() throws IOException { + from.onWritePossible(); + } + + @Override + public void onError(Throwable t) { + from.onError(t); + } + }; + } + + public static WriteListener fromJakartaWriteListener(jakarta.servlet.WriteListener from) { + Objects.requireNonNull(from); + return new WriteListener() { + @Override + public void onWritePossible() throws IOException { + from.onWritePossible(); + } + + @Override + public void onError(Throwable t) { + from.onError(t); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/descriptor/JspConfigDescriptorWrapper.java b/core/src/main/java/io/jenkins/servlet/descriptor/JspConfigDescriptorWrapper.java new file mode 100644 index 000000000..b215c8c65 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/descriptor/JspConfigDescriptorWrapper.java @@ -0,0 +1,50 @@ +package io.jenkins.servlet.descriptor; + +import java.util.Collection; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.servlet.descriptor.JspConfigDescriptor; +import javax.servlet.descriptor.JspPropertyGroupDescriptor; +import javax.servlet.descriptor.TaglibDescriptor; + +public class JspConfigDescriptorWrapper { + public static jakarta.servlet.descriptor.JspConfigDescriptor toJakartaJspConfigDescriptor( + JspConfigDescriptor from) { + Objects.requireNonNull(from); + return new jakarta.servlet.descriptor.JspConfigDescriptor() { + @Override + public Collection getTaglibs() { + return from.getTaglibs().stream() + .map(TaglibDescriptorWrapper::toJakartaTaglibDescriptor) + .collect(Collectors.toList()); + } + + @Override + public Collection getJspPropertyGroups() { + return from.getJspPropertyGroups().stream() + .map(JspPropertyGroupDescriptorWrapper::toJakartaJspPropertyGroupDescriptor) + .collect(Collectors.toList()); + } + }; + } + + public static JspConfigDescriptor fromJakartaJspConfigDescriptor( + jakarta.servlet.descriptor.JspConfigDescriptor from) { + Objects.requireNonNull(from); + return new JspConfigDescriptor() { + @Override + public Collection getTaglibs() { + return from.getTaglibs().stream() + .map(TaglibDescriptorWrapper::fromJakartaTaglibDescriptor) + .collect(Collectors.toList()); + } + + @Override + public Collection getJspPropertyGroups() { + return from.getJspPropertyGroups().stream() + .map(JspPropertyGroupDescriptorWrapper::fromJakartaJspPropertyGroupDescriptor) + .collect(Collectors.toList()); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/descriptor/JspPropertyGroupDescriptorWrapper.java b/core/src/main/java/io/jenkins/servlet/descriptor/JspPropertyGroupDescriptorWrapper.java new file mode 100644 index 000000000..450420958 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/descriptor/JspPropertyGroupDescriptorWrapper.java @@ -0,0 +1,139 @@ +package io.jenkins.servlet.descriptor; + +import java.util.Collection; +import java.util.Objects; +import javax.servlet.descriptor.JspPropertyGroupDescriptor; + +public class JspPropertyGroupDescriptorWrapper { + public static jakarta.servlet.descriptor.JspPropertyGroupDescriptor toJakartaJspPropertyGroupDescriptor( + JspPropertyGroupDescriptor from) { + Objects.requireNonNull(from); + return new jakarta.servlet.descriptor.JspPropertyGroupDescriptor() { + @Override + public Collection getUrlPatterns() { + return from.getUrlPatterns(); + } + + @Override + public String getElIgnored() { + return from.getElIgnored(); + } + + @Override + public String getPageEncoding() { + return from.getPageEncoding(); + } + + @Override + public String getScriptingInvalid() { + return from.getScriptingInvalid(); + } + + @Override + public String getIsXml() { + return from.getIsXml(); + } + + @Override + public Collection getIncludePreludes() { + return from.getIncludePreludes(); + } + + @Override + public Collection getIncludeCodas() { + return from.getIncludeCodas(); + } + + @Override + public String getDeferredSyntaxAllowedAsLiteral() { + return from.getDeferredSyntaxAllowedAsLiteral(); + } + + @Override + public String getTrimDirectiveWhitespaces() { + return from.getTrimDirectiveWhitespaces(); + } + + @Override + public String getDefaultContentType() { + return from.getDefaultContentType(); + } + + @Override + public String getBuffer() { + return from.getBuffer(); + } + + @Override + public String getErrorOnUndeclaredNamespace() { + return from.getErrorOnUndeclaredNamespace(); + } + }; + } + + public static JspPropertyGroupDescriptor fromJakartaJspPropertyGroupDescriptor( + jakarta.servlet.descriptor.JspPropertyGroupDescriptor from) { + Objects.requireNonNull(from); + return new JspPropertyGroupDescriptor() { + @Override + public Collection getUrlPatterns() { + return from.getUrlPatterns(); + } + + @Override + public String getElIgnored() { + return from.getElIgnored(); + } + + @Override + public String getPageEncoding() { + return from.getPageEncoding(); + } + + @Override + public String getScriptingInvalid() { + return from.getScriptingInvalid(); + } + + @Override + public String getIsXml() { + return from.getIsXml(); + } + + @Override + public Collection getIncludePreludes() { + return from.getIncludePreludes(); + } + + @Override + public Collection getIncludeCodas() { + return from.getIncludeCodas(); + } + + @Override + public String getDeferredSyntaxAllowedAsLiteral() { + return from.getDeferredSyntaxAllowedAsLiteral(); + } + + @Override + public String getTrimDirectiveWhitespaces() { + return from.getTrimDirectiveWhitespaces(); + } + + @Override + public String getDefaultContentType() { + return from.getDefaultContentType(); + } + + @Override + public String getBuffer() { + return from.getBuffer(); + } + + @Override + public String getErrorOnUndeclaredNamespace() { + return from.getErrorOnUndeclaredNamespace(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/descriptor/TaglibDescriptorWrapper.java b/core/src/main/java/io/jenkins/servlet/descriptor/TaglibDescriptorWrapper.java new file mode 100644 index 000000000..147001fe4 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/descriptor/TaglibDescriptorWrapper.java @@ -0,0 +1,36 @@ +package io.jenkins.servlet.descriptor; + +import java.util.Objects; +import javax.servlet.descriptor.TaglibDescriptor; + +public class TaglibDescriptorWrapper { + public static jakarta.servlet.descriptor.TaglibDescriptor toJakartaTaglibDescriptor(TaglibDescriptor from) { + Objects.requireNonNull(from); + return new jakarta.servlet.descriptor.TaglibDescriptor() { + @Override + public String getTaglibURI() { + return from.getTaglibURI(); + } + + @Override + public String getTaglibLocation() { + return from.getTaglibLocation(); + } + }; + } + + public static TaglibDescriptor fromJakartaTaglibDescriptor(jakarta.servlet.descriptor.TaglibDescriptor from) { + Objects.requireNonNull(from); + return new TaglibDescriptor() { + @Override + public String getTaglibURI() { + return from.getTaglibURI(); + } + + @Override + public String getTaglibLocation() { + return from.getTaglibLocation(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/CookieWrapper.java b/core/src/main/java/io/jenkins/servlet/http/CookieWrapper.java new file mode 100644 index 000000000..ae8c01ddc --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/CookieWrapper.java @@ -0,0 +1,48 @@ +package io.jenkins.servlet.http; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.Objects; +import javax.servlet.http.Cookie; + +public class CookieWrapper { + public static jakarta.servlet.http.Cookie toJakartaServletHttpCookie(Cookie from) { + Objects.requireNonNull(from); + jakarta.servlet.http.Cookie result = new jakarta.servlet.http.Cookie(from.getName(), from.getValue()); + if (from.getComment() != null) { + result.setComment(from.getComment()); + } + if (from.getDomain() != null) { + result.setDomain(from.getDomain()); + } + result.setMaxAge(from.getMaxAge()); + if (from.getPath() != null) { + result.setPath(from.getPath()); + } + result.setSecure(from.getSecure()); + result.setVersion(from.getVersion()); + result.setHttpOnly(from.isHttpOnly()); + return result; + } + + @SuppressFBWarnings( + value = {"HTTPONLY_COOKIE", "INSECURE_COOKIE"}, + justification = "for compatibility") + public static Cookie fromJakartaServletHttpCookie(jakarta.servlet.http.Cookie from) { + Objects.requireNonNull(from); + Cookie result = new Cookie(from.getName(), from.getValue()); + if (from.getComment() != null) { + result.setComment(from.getComment()); + } + if (from.getDomain() != null) { + result.setDomain(from.getDomain()); + } + result.setMaxAge(from.getMaxAge()); + if (from.getPath() != null) { + result.setPath(from.getPath()); + } + result.setSecure(from.getSecure()); + result.setVersion(from.getVersion()); + result.setHttpOnly(from.isHttpOnly()); + return result; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpServletMappingWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpServletMappingWrapper.java new file mode 100644 index 000000000..15868bff6 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpServletMappingWrapper.java @@ -0,0 +1,57 @@ +package io.jenkins.servlet.http; + +import java.util.Objects; +import javax.servlet.http.HttpServletMapping; +import javax.servlet.http.MappingMatch; + +public class HttpServletMappingWrapper { + public static jakarta.servlet.http.HttpServletMapping toJakartaHttpServletMapping(HttpServletMapping from) { + Objects.requireNonNull(from); + return new jakarta.servlet.http.HttpServletMapping() { + @Override + public String getMatchValue() { + return from.getMatchValue(); + } + + @Override + public String getPattern() { + return from.getPattern(); + } + + @Override + public String getServletName() { + return from.getServletName(); + } + + @Override + public jakarta.servlet.http.MappingMatch getMappingMatch() { + return MappingMatchWrapper.toJakartaMappingMatch(from.getMappingMatch()); + } + }; + } + + public static HttpServletMapping fromJakartaHttpServletMapping(jakarta.servlet.http.HttpServletMapping from) { + Objects.requireNonNull(from); + return new HttpServletMapping() { + @Override + public String getMatchValue() { + return from.getMatchValue(); + } + + @Override + public String getPattern() { + return from.getPattern(); + } + + @Override + public String getServletName() { + return from.getServletName(); + } + + @Override + public MappingMatch getMappingMatch() { + return MappingMatchWrapper.fromJakartaMappingMatch(from.getMappingMatch()); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpServletRequestWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpServletRequestWrapper.java new file mode 100644 index 000000000..b64239340 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpServletRequestWrapper.java @@ -0,0 +1,897 @@ +package io.jenkins.servlet.http; + +import io.jenkins.servlet.AsyncContextWrapper; +import io.jenkins.servlet.DispatcherTypeWrapper; +import io.jenkins.servlet.RequestDispatcherWrapper; +import io.jenkins.servlet.ServletContextWrapper; +import io.jenkins.servlet.ServletExceptionWrapper; +import io.jenkins.servlet.ServletInputStreamWrapper; +import io.jenkins.servlet.ServletRequestWrapper; +import io.jenkins.servlet.ServletResponseWrapper; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletMapping; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; +import javax.servlet.http.PushBuilder; + +public class HttpServletRequestWrapper { + + public static jakarta.servlet.http.HttpServletRequest toJakartaHttpServletRequest(HttpServletRequest from) { + if (from instanceof JavaxHttpServletRequestWrapper javax) { + return javax.toJakartaHttpServletRequest(); + } + return new JakartaHttpServletRequestWrapperImpl(from); + } + + public static HttpServletRequest fromJakartaHttpServletRequest(jakarta.servlet.http.HttpServletRequest from) { + if (from instanceof JakartaHttpServletRequestWrapper jakarta) { + return jakarta.toJavaxHttpServletRequest(); + } + return new JavaxHttpServletRequestWrapperImpl(from); + } + + public interface JakartaHttpServletRequestWrapper { + HttpServletRequest toJavaxHttpServletRequest(); + } + + private static class JakartaHttpServletRequestWrapperImpl + implements jakarta.servlet.http.HttpServletRequest, ServletRequestWrapper.JakartaServletRequestWrapper { + private final HttpServletRequest from; + + JakartaHttpServletRequestWrapperImpl(HttpServletRequest from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.toJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public jakarta.servlet.RequestDispatcher getRequestDispatcher(String path) { + RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.toJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public jakarta.servlet.AsyncContext startAsync() { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync()); + } + + @Override + public jakarta.servlet.AsyncContext startAsync( + jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse) { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync( + ServletRequestWrapper.fromJakartaServletRequest(servletRequest), + ServletResponseWrapper.fromJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public jakarta.servlet.AsyncContext getAsyncContext() { + return AsyncContextWrapper.toJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public jakarta.servlet.DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.toJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public String getAuthType() { + return from.getAuthType(); + } + + @Override + public jakarta.servlet.http.Cookie[] getCookies() { + Cookie[] cookies = from.getCookies(); + if (cookies == null) { + return null; + } + return Stream.of(cookies) + .map(CookieWrapper::toJakartaServletHttpCookie) + .toArray(jakarta.servlet.http.Cookie[]::new); + } + + @Override + public long getDateHeader(String name) { + return from.getDateHeader(name); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Enumeration getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Enumeration getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public int getIntHeader(String name) { + return from.getIntHeader(name); + } + + @Override + public jakarta.servlet.http.HttpServletMapping getHttpServletMapping() { + return HttpServletMappingWrapper.toJakartaHttpServletMapping(from.getHttpServletMapping()); + } + + @Override + public String getMethod() { + return from.getMethod(); + } + + @Override + public String getPathInfo() { + return from.getPathInfo(); + } + + @Override + public String getPathTranslated() { + return from.getPathTranslated(); + } + + @Override + public jakarta.servlet.http.PushBuilder newPushBuilder() { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public String getQueryString() { + return from.getQueryString(); + } + + @Override + public String getRemoteUser() { + return from.getRemoteUser(); + } + + @Override + public boolean isUserInRole(String role) { + return from.isUserInRole(role); + } + + @Override + public Principal getUserPrincipal() { + return from.getUserPrincipal(); + } + + @Override + public String getRequestedSessionId() { + return from.getRequestedSessionId(); + } + + @Override + public String getRequestURI() { + return from.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return from.getRequestURL(); + } + + @Override + public String getServletPath() { + return from.getServletPath(); + } + + @Override + public jakarta.servlet.http.HttpSession getSession(boolean create) { + HttpSession session = from.getSession(create); + return session != null ? HttpSessionWrapper.toJakartaHttpSession(session) : null; + } + + @Override + public jakarta.servlet.http.HttpSession getSession() { + HttpSession session = from.getSession(); + return session != null ? HttpSessionWrapper.toJakartaHttpSession(session) : null; + } + + @Override + public String changeSessionId() { + return from.changeSessionId(); + } + + @Override + public boolean isRequestedSessionIdValid() { + return from.isRequestedSessionIdValid(); + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return from.isRequestedSessionIdFromCookie(); + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return from.isRequestedSessionIdFromURL(); + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return from.isRequestedSessionIdFromUrl(); + } + + @Override + public boolean authenticate(jakarta.servlet.http.HttpServletResponse response) + throws IOException, jakarta.servlet.ServletException { + try { + return from.authenticate(HttpServletResponseWrapper.fromJakartaHttpServletResponse(response)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void login(String username, String password) throws jakarta.servlet.ServletException { + try { + from.login(username, password); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void logout() throws jakarta.servlet.ServletException { + try { + from.logout(); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public Collection getParts() throws IOException, jakarta.servlet.ServletException { + try { + return from.getParts().stream() + .map(PartWrapper::toJakartaPart) + .collect(Collectors.toCollection(ArrayList::new)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public jakarta.servlet.http.Part getPart(String name) throws IOException, jakarta.servlet.ServletException { + try { + return PartWrapper.toJakartaPart(from.getPart(name)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public T upgrade(Class handlerClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public Map getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public boolean isTrailerFieldsReady() { + return from.isTrailerFieldsReady(); + } + + @Override + public HttpServletRequest toJavaxServletRequest() { + return from; + } + } + + public interface JavaxHttpServletRequestWrapper { + jakarta.servlet.http.HttpServletRequest toJakartaHttpServletRequest(); + } + + private static class JavaxHttpServletRequestWrapperImpl + implements HttpServletRequest, ServletRequestWrapper.JavaxServletRequestWrapper { + private final jakarta.servlet.http.HttpServletRequest from; + + JavaxHttpServletRequestWrapperImpl(jakarta.servlet.http.HttpServletRequest from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.fromJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + jakarta.servlet.RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public AsyncContext startAsync() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync()); + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync( + ServletRequestWrapper.toJakartaServletRequest(servletRequest), + ServletResponseWrapper.toJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public AsyncContext getAsyncContext() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.fromJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public String getAuthType() { + return from.getAuthType(); + } + + @Override + public Cookie[] getCookies() { + jakarta.servlet.http.Cookie[] cookies = from.getCookies(); + if (cookies == null) { + return null; + } + return Stream.of(cookies) + .map(CookieWrapper::fromJakartaServletHttpCookie) + .toArray(Cookie[]::new); + } + + @Override + public long getDateHeader(String name) { + return from.getDateHeader(name); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Enumeration getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Enumeration getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public int getIntHeader(String name) { + return from.getIntHeader(name); + } + + @Override + public HttpServletMapping getHttpServletMapping() { + return HttpServletMappingWrapper.fromJakartaHttpServletMapping(from.getHttpServletMapping()); + } + + @Override + public String getMethod() { + return from.getMethod(); + } + + @Override + public String getPathInfo() { + return from.getPathInfo(); + } + + @Override + public String getPathTranslated() { + return from.getPathTranslated(); + } + + @Override + public PushBuilder newPushBuilder() { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public String getQueryString() { + return from.getQueryString(); + } + + @Override + public String getRemoteUser() { + return from.getRemoteUser(); + } + + @Override + public boolean isUserInRole(String role) { + return from.isUserInRole(role); + } + + @Override + public Principal getUserPrincipal() { + return from.getUserPrincipal(); + } + + @Override + public String getRequestedSessionId() { + return from.getRequestedSessionId(); + } + + @Override + public String getRequestURI() { + return from.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return from.getRequestURL(); + } + + @Override + public String getServletPath() { + return from.getServletPath(); + } + + @Override + public HttpSession getSession(boolean create) { + jakarta.servlet.http.HttpSession session = from.getSession(create); + return session != null ? HttpSessionWrapper.fromJakartaHttpSession(session) : null; + } + + @Override + public HttpSession getSession() { + jakarta.servlet.http.HttpSession session = from.getSession(); + return session != null ? HttpSessionWrapper.fromJakartaHttpSession(session) : null; + } + + @Override + public String changeSessionId() { + return from.changeSessionId(); + } + + @Override + public boolean isRequestedSessionIdValid() { + return from.isRequestedSessionIdValid(); + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return from.isRequestedSessionIdFromCookie(); + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return from.isRequestedSessionIdFromURL(); + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return from.isRequestedSessionIdFromUrl(); + } + + @Override + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + try { + return from.authenticate(HttpServletResponseWrapper.toJakartaHttpServletResponse(response)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void login(String username, String password) throws ServletException { + try { + from.login(username, password); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void logout() throws ServletException { + try { + from.logout(); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public Collection getParts() throws IOException, ServletException { + try { + return from.getParts().stream() + .map(PartWrapper::fromJakartaPart) + .collect(Collectors.toCollection(ArrayList::new)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public Part getPart(String name) throws IOException, ServletException { + try { + return PartWrapper.fromJakartaPart(from.getPart(name)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public T upgrade(Class handlerClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public Map getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public boolean isTrailerFieldsReady() { + return from.isTrailerFieldsReady(); + } + + @Override + public jakarta.servlet.http.HttpServletRequest toJakartaServletRequest() { + return from; + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpServletResponseWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpServletResponseWrapper.java new file mode 100644 index 000000000..e2a0d0da3 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpServletResponseWrapper.java @@ -0,0 +1,475 @@ +package io.jenkins.servlet.http; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.jenkins.servlet.ServletOutputStreamWrapper; +import io.jenkins.servlet.ServletResponseWrapper; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +public class HttpServletResponseWrapper { + public static jakarta.servlet.http.HttpServletResponse toJakartaHttpServletResponse(HttpServletResponse from) { + if (from instanceof JavaxHttpServletResponseWrapper javax) { + return javax.toJakartaHttpServletResponse(); + } + return new JakartaHttpServletResponseWrapperImpl(from); + } + + public static HttpServletResponse fromJakartaHttpServletResponse(jakarta.servlet.http.HttpServletResponse from) { + if (from instanceof JakartaHttpServletResponseWrapper jakarta) { + return jakarta.toJavaxHttpServletResponse(); + } + return new JavaxHttpServletResponseWrapperImpl(from); + } + + public interface JakartaHttpServletResponseWrapper { + HttpServletResponse toJavaxHttpServletResponse(); + } + + @SuppressFBWarnings( + value = {"UNVALIDATED_REDIRECT", "URL_REWRITING", "XSS_SERVLET"}, + justification = "for compatibility") + private static class JakartaHttpServletResponseWrapperImpl + implements jakarta.servlet.http.HttpServletResponse, + ServletResponseWrapper.JakartaServletResponseWrapper, + JakartaHttpServletResponseWrapper { + private final HttpServletResponse from; + + JakartaHttpServletResponseWrapperImpl(HttpServletResponse from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.toJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public void addCookie(jakarta.servlet.http.Cookie cookie) { + from.addCookie(CookieWrapper.fromJakartaServletHttpCookie(cookie)); + } + + @Override + public boolean containsHeader(String name) { + return from.containsHeader(name); + } + + @Override + public String encodeURL(String url) { + return from.encodeURL(url); + } + + @Override + public String encodeRedirectURL(String url) { + return from.encodeRedirectURL(url); + } + + @Override + public String encodeUrl(String url) { + return from.encodeUrl(url); + } + + @Override + public String encodeRedirectUrl(String url) { + return from.encodeRedirectUrl(url); + } + + @Override + public void sendError(int sc, String msg) throws IOException { + from.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + from.sendError(sc); + } + + @Override + public void sendRedirect(String location) throws IOException { + from.sendRedirect(location); + } + + @Override + public void setDateHeader(String name, long date) { + from.setDateHeader(name, date); + } + + @Override + public void addDateHeader(String name, long date) { + from.addDateHeader(name, date); + } + + @Override + public void setHeader(String name, String value) { + from.setHeader(name, value); + } + + @Override + public void addHeader(String name, String value) { + from.addHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + from.setIntHeader(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + from.addIntHeader(name, value); + } + + @Override + public void setStatus(int sc) { + from.setStatus(sc); + } + + @Override + public void setStatus(int sc, String sm) { + from.setStatus(sc, sm); + } + + @Override + public int getStatus() { + return from.getStatus(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public void setTrailerFields(Supplier> supplier) { + from.setTrailerFields(supplier); + } + + @Override + public Supplier> getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public ServletResponse toJavaxServletResponse() { + return from; + } + + @Override + public HttpServletResponse toJavaxHttpServletResponse() { + return from; + } + } + + public interface JavaxHttpServletResponseWrapper { + jakarta.servlet.http.HttpServletResponse toJakartaHttpServletResponse(); + } + + private static class JavaxHttpServletResponseWrapperImpl + implements HttpServletResponse, + ServletResponseWrapper.JavaxServletResponseWrapper, + JavaxHttpServletResponseWrapper { + private final jakarta.servlet.http.HttpServletResponse from; + + JavaxHttpServletResponseWrapperImpl(jakarta.servlet.http.HttpServletResponse from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.fromJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public void addCookie(Cookie cookie) { + from.addCookie(CookieWrapper.toJakartaServletHttpCookie(cookie)); + } + + @Override + public boolean containsHeader(String name) { + return from.containsHeader(name); + } + + @Override + public String encodeURL(String url) { + return from.encodeURL(url); + } + + @Override + public String encodeRedirectURL(String url) { + return from.encodeRedirectURL(url); + } + + @Override + public String encodeUrl(String url) { + return from.encodeUrl(url); + } + + @Override + public String encodeRedirectUrl(String url) { + return from.encodeRedirectUrl(url); + } + + @Override + public void sendError(int sc, String msg) throws IOException { + from.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + from.sendError(sc); + } + + @Override + public void sendRedirect(String location) throws IOException { + from.sendRedirect(location); + } + + @Override + public void setDateHeader(String name, long date) { + from.setDateHeader(name, date); + } + + @Override + public void addDateHeader(String name, long date) { + from.addDateHeader(name, date); + } + + @Override + public void setHeader(String name, String value) { + from.setHeader(name, value); + } + + @Override + public void addHeader(String name, String value) { + from.addHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + from.setIntHeader(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + from.addIntHeader(name, value); + } + + @Override + public void setStatus(int sc) { + from.setStatus(sc); + } + + @Override + public void setStatus(int sc, String sm) { + from.setStatus(sc, sm); + } + + @Override + public int getStatus() { + return from.getStatus(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public void setTrailerFields(Supplier> supplier) { + from.setTrailerFields(supplier); + } + + @Override + public Supplier> getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public jakarta.servlet.ServletResponse toJakartaServletResponse() { + return from; + } + + @Override + public jakarta.servlet.http.HttpServletResponse toJakartaHttpServletResponse() { + return from; + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpSessionContextWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpSessionContextWrapper.java new file mode 100644 index 000000000..1edfe3e03 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpSessionContextWrapper.java @@ -0,0 +1,38 @@ +package io.jenkins.servlet.http; + +import java.util.Enumeration; +import java.util.Objects; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; + +public class HttpSessionContextWrapper { + public static jakarta.servlet.http.HttpSessionContext toJakartaHttpSessionContext(HttpSessionContext from) { + Objects.requireNonNull(from); + return new jakarta.servlet.http.HttpSessionContext() { + @Override + public jakarta.servlet.http.HttpSession getSession(String sessionId) { + return HttpSessionWrapper.toJakartaHttpSession(from.getSession(sessionId)); + } + + @Override + public Enumeration getIds() { + return from.getIds(); + } + }; + } + + public static HttpSessionContext fromJakartaHttpSessionContext(jakarta.servlet.http.HttpSessionContext from) { + Objects.requireNonNull(from); + return new HttpSessionContext() { + @Override + public HttpSession getSession(String sessionId) { + return HttpSessionWrapper.fromJakartaHttpSession(from.getSession(sessionId)); + } + + @Override + public Enumeration getIds() { + return from.getIds(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpSessionEventWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpSessionEventWrapper.java new file mode 100644 index 000000000..0728e4ebe --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpSessionEventWrapper.java @@ -0,0 +1,16 @@ +package io.jenkins.servlet.http; + +import java.util.Objects; +import javax.servlet.http.HttpSessionEvent; + +public class HttpSessionEventWrapper { + public static jakarta.servlet.http.HttpSessionEvent toJakartaHttpSessionEvent(HttpSessionEvent from) { + Objects.requireNonNull(from); + return new jakarta.servlet.http.HttpSessionEvent(HttpSessionWrapper.toJakartaHttpSession(from.getSession())); + } + + public static HttpSessionEvent fromJakartaHttpSessionEvent(jakarta.servlet.http.HttpSessionEvent from) { + Objects.requireNonNull(from); + return new HttpSessionEvent(HttpSessionWrapper.fromJakartaHttpSession(from.getSession())); + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/HttpSessionWrapper.java b/core/src/main/java/io/jenkins/servlet/http/HttpSessionWrapper.java new file mode 100644 index 000000000..301b5a127 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/HttpSessionWrapper.java @@ -0,0 +1,190 @@ +package io.jenkins.servlet.http; + +import io.jenkins.servlet.ServletContextWrapper; +import java.util.Enumeration; +import java.util.Objects; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; + +public class HttpSessionWrapper { + public static jakarta.servlet.http.HttpSession toJakartaHttpSession(HttpSession from) { + Objects.requireNonNull(from); + return new jakarta.servlet.http.HttpSession() { + @Override + public long getCreationTime() { + return from.getCreationTime(); + } + + @Override + public String getId() { + return from.getId(); + } + + @Override + public long getLastAccessedTime() { + return from.getLastAccessedTime(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public void setMaxInactiveInterval(int interval) { + from.setMaxInactiveInterval(interval); + } + + @Override + public int getMaxInactiveInterval() { + return from.getMaxInactiveInterval(); + } + + @Override + public jakarta.servlet.http.HttpSessionContext getSessionContext() { + return HttpSessionContextWrapper.toJakartaHttpSessionContext(from.getSessionContext()); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Object getValue(String name) { + return from.getValue(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String[] getValueNames() { + return from.getValueNames(); + } + + @Override + public void setAttribute(String name, Object value) { + from.setAttribute(name, value); + } + + @Override + public void putValue(String name, Object value) { + from.putValue(name, value); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public void removeValue(String name) { + from.removeValue(name); + } + + @Override + public void invalidate() { + from.invalidate(); + } + + @Override + public boolean isNew() { + return from.isNew(); + } + }; + } + + public static HttpSession fromJakartaHttpSession(jakarta.servlet.http.HttpSession from) { + Objects.requireNonNull(from); + return new HttpSession() { + @Override + public long getCreationTime() { + return from.getCreationTime(); + } + + @Override + public String getId() { + return from.getId(); + } + + @Override + public long getLastAccessedTime() { + return from.getLastAccessedTime(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public void setMaxInactiveInterval(int interval) { + from.setMaxInactiveInterval(interval); + } + + @Override + public int getMaxInactiveInterval() { + return from.getMaxInactiveInterval(); + } + + @Override + public HttpSessionContext getSessionContext() { + return HttpSessionContextWrapper.fromJakartaHttpSessionContext(from.getSessionContext()); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Object getValue(String name) { + return from.getValue(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String[] getValueNames() { + return from.getValueNames(); + } + + @Override + public void setAttribute(String name, Object value) { + from.setAttribute(name, value); + } + + @Override + public void putValue(String name, Object value) { + from.putValue(name, value); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public void removeValue(String name) { + from.removeValue(name); + } + + @Override + public void invalidate() { + from.invalidate(); + } + + @Override + public boolean isNew() { + return from.isNew(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/MappingMatchWrapper.java b/core/src/main/java/io/jenkins/servlet/http/MappingMatchWrapper.java new file mode 100644 index 000000000..193a92866 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/MappingMatchWrapper.java @@ -0,0 +1,42 @@ +package io.jenkins.servlet.http; + +import java.util.Objects; +import javax.servlet.http.MappingMatch; + +public class MappingMatchWrapper { + public static jakarta.servlet.http.MappingMatch toJakartaMappingMatch(MappingMatch from) { + Objects.requireNonNull(from); + switch (from) { + case CONTEXT_ROOT: + return jakarta.servlet.http.MappingMatch.CONTEXT_ROOT; + case DEFAULT: + return jakarta.servlet.http.MappingMatch.DEFAULT; + case EXACT: + return jakarta.servlet.http.MappingMatch.EXACT; + case EXTENSION: + return jakarta.servlet.http.MappingMatch.EXTENSION; + case PATH: + return jakarta.servlet.http.MappingMatch.PATH; + default: + throw new IllegalArgumentException("Unknown MappingMatch: " + from); + } + } + + public static MappingMatch fromJakartaMappingMatch(jakarta.servlet.http.MappingMatch from) { + Objects.requireNonNull(from); + switch (from) { + case CONTEXT_ROOT: + return MappingMatch.CONTEXT_ROOT; + case DEFAULT: + return MappingMatch.DEFAULT; + case EXACT: + return MappingMatch.EXACT; + case EXTENSION: + return MappingMatch.EXTENSION; + case PATH: + return MappingMatch.PATH; + default: + throw new IllegalArgumentException("Unknown MappingMatch: " + from); + } + } +} diff --git a/core/src/main/java/io/jenkins/servlet/http/PartWrapper.java b/core/src/main/java/io/jenkins/servlet/http/PartWrapper.java new file mode 100644 index 000000000..addfe4ec0 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/http/PartWrapper.java @@ -0,0 +1,119 @@ +package io.jenkins.servlet.http; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.Objects; +import javax.servlet.http.Part; + +public class PartWrapper { + public static jakarta.servlet.http.Part toJakartaPart(Part from) { + Objects.requireNonNull(from); + return new jakarta.servlet.http.Part() { + @Override + public InputStream getInputStream() throws IOException { + return from.getInputStream(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getSubmittedFileName() { + return from.getSubmittedFileName(); + } + + @Override + public long getSize() { + return from.getSize(); + } + + @Override + public void write(String fileName) throws IOException { + from.write(fileName); + } + + @Override + public void delete() throws IOException { + from.delete(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + }; + } + + public static Part fromJakartaPart(jakarta.servlet.http.Part from) { + Objects.requireNonNull(from); + return new Part() { + @Override + public InputStream getInputStream() throws IOException { + return from.getInputStream(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public String getName() { + return from.getName(); + } + + @Override + public String getSubmittedFileName() { + return from.getSubmittedFileName(); + } + + @Override + public long getSize() { + return from.getSize(); + } + + @Override + public void write(String fileName) throws IOException { + from.write(fileName); + } + + @Override + public void delete() throws IOException { + from.delete(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + }; + } +} diff --git a/core/src/main/java/io/jenkins/servlet/package-info.java b/core/src/main/java/io/jenkins/servlet/package-info.java new file mode 100644 index 000000000..ba36eee03 --- /dev/null +++ b/core/src/main/java/io/jenkins/servlet/package-info.java @@ -0,0 +1,8 @@ +/** + * Compatibility layer to convert to/from EE 8/9. + * + *

All files in this package are kept separate from the {@code javax.servlet} package namespace to avoid potential + * trademark issues. Unfortunately, this results in a lot of static methods rather than object-oriented programming. The + * resulting loss of readability is unfortunate but necessary. + */ +package io.jenkins.servlet; diff --git a/core/src/main/java/org/kohsuke/stapler/AcceptHeader.java b/core/src/main/java/org/kohsuke/stapler/AcceptHeader.java index 9af006944..bfd90f21f 100644 --- a/core/src/main/java/org/kohsuke/stapler/AcceptHeader.java +++ b/core/src/main/java/org/kohsuke/stapler/AcceptHeader.java @@ -23,12 +23,12 @@ of this software and associated documentation files (the "Software"), to deal package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.Nullable; +import jakarta.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.Converter; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; diff --git a/core/src/main/java/org/kohsuke/stapler/Ancestor.java b/core/src/main/java/org/kohsuke/stapler/Ancestor.java index 06ee8c438..4857c9708 100644 --- a/core/src/main/java/org/kohsuke/stapler/Ancestor.java +++ b/core/src/main/java/org/kohsuke/stapler/Ancestor.java @@ -23,7 +23,7 @@ package org.kohsuke.stapler; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Information about ancestor of the "it" node. diff --git a/core/src/main/java/org/kohsuke/stapler/AncestorImpl.java b/core/src/main/java/org/kohsuke/stapler/AncestorImpl.java index ad6e070ae..03f153cc4 100644 --- a/core/src/main/java/org/kohsuke/stapler/AncestorImpl.java +++ b/core/src/main/java/org/kohsuke/stapler/AncestorImpl.java @@ -88,7 +88,7 @@ public String getRestOfUrl() { @Override public String getFullUrl() { StringBuilder buf = new StringBuilder(); - StaplerRequest req = Stapler.getCurrentRequest(); + StaplerRequest2 req = Stapler.getCurrentRequest2(); buf.append(req.getScheme()); buf.append("://"); buf.append(req.getServerName()); diff --git a/core/src/main/java/org/kohsuke/stapler/AncestorInPath.java b/core/src/main/java/org/kohsuke/stapler/AncestorInPath.java index c899cc3e8..10c66060d 100644 --- a/core/src/main/java/org/kohsuke/stapler/AncestorInPath.java +++ b/core/src/main/java/org/kohsuke/stapler/AncestorInPath.java @@ -23,17 +23,17 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.servlet.ServletException; import org.kohsuke.stapler.AncestorInPath.HandlerImpl; /** * Indicates that this parameter is injected by evaluating - * {@link StaplerRequest#findAncestorObject(Class)} with the parameter type. + * {@link StaplerRequest2#findAncestorObject(Class)} with the parameter type. * * @author Kohsuke Kawaguchi */ @@ -44,7 +44,7 @@ public @interface AncestorInPath { class HandlerImpl extends AnnotationHandler { @Override - public Object parse(StaplerRequest request, AncestorInPath a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, AncestorInPath a, Class type, String parameterName) throws ServletException { return request.findAncestorObject(type); } diff --git a/core/src/main/java/org/kohsuke/stapler/AnnotationHandler.java b/core/src/main/java/org/kohsuke/stapler/AnnotationHandler.java index 3ef661589..feb3abaa6 100644 --- a/core/src/main/java/org/kohsuke/stapler/AnnotationHandler.java +++ b/core/src/main/java/org/kohsuke/stapler/AnnotationHandler.java @@ -23,9 +23,10 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.ServletExceptionWrapper; +import jakarta.servlet.ServletException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.apache.commons.beanutils.Converter; /** @@ -48,10 +49,54 @@ public abstract class AnnotationHandler { * @param parameterName * Name of the parameter. */ - public abstract Object parse(StaplerRequest request, T a, Class type, String parameterName) throws ServletException; + public /* abstract */ Object parse(StaplerRequest2 request, T a, Class type, String parameterName) + throws ServletException { + if (ReflectionUtils.isOverridden( + AnnotationHandler.class, + getClass(), + "parse", + StaplerRequest.class, + Annotation.class, + Class.class, + String.class)) { + try { + return parse(StaplerRequest.fromStaplerRequest2(request), a, type, parameterName); + } catch (javax.servlet.ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + AnnotationHandler.class.getSimpleName() + ".parse methods"); + } + } + + /** + * @deprecated use {@link #parse(StaplerRequest2, Annotation, Class, String)} + */ + @Deprecated + public Object parse(StaplerRequest request, T a, Class type, String parameterName) + throws javax.servlet.ServletException { + if (ReflectionUtils.isOverridden( + AnnotationHandler.class, + getClass(), + "parse", + StaplerRequest2.class, + Annotation.class, + Class.class, + String.class)) { + try { + return parse(StaplerRequest.toStaplerRequest2(request), a, type, parameterName); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + AnnotationHandler.class.getSimpleName() + ".parse methods"); + } + } /** - * Helper method for {@link #parse(StaplerRequest, Annotation, Class, String)} to convert to the right type + * Helper method for {@link #parse(StaplerRequest2, Annotation, Class, String)} to convert to the right type * from String. */ protected final Object convert(Class targetType, String value) { @@ -63,7 +108,7 @@ protected final Object convert(Class targetType, String value) { return converter.convert(targetType, value); } - static Object handle(StaplerRequest request, Annotation[] annotations, String parameterName, Class targetType) + static Object handle(StaplerRequest2 request, Annotation[] annotations, String parameterName, Class targetType) throws ServletException { for (Annotation a : annotations) { Class at = a.annotationType(); @@ -98,7 +143,7 @@ protected AnnotationHandler computeValue(Class at) { private static final AnnotationHandler NOT_HANDLER = new AnnotationHandler() { @Override - public Object parse(StaplerRequest request, Annotation a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, Annotation a, Class type, String parameterName) throws ServletException { return null; } diff --git a/core/src/main/java/org/kohsuke/stapler/AttributeKey.java b/core/src/main/java/org/kohsuke/stapler/AttributeKey.java index 427aaba55..95d282f90 100644 --- a/core/src/main/java/org/kohsuke/stapler/AttributeKey.java +++ b/core/src/main/java/org/kohsuke/stapler/AttributeKey.java @@ -1,9 +1,9 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; import java.util.UUID; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; /** * Type-safe attribute accessor. @@ -39,15 +39,15 @@ public AttributeKey(String name) { public abstract void remove(HttpServletRequest req); public final T get() { - return get(Stapler.getCurrentRequest()); + return get(Stapler.getCurrentRequest2()); } public final void set(T value) { - set(Stapler.getCurrentRequest(), value); + set(Stapler.getCurrentRequest2(), value); } public final void remove() { - remove(Stapler.getCurrentRequest()); + remove(Stapler.getCurrentRequest2()); } /** diff --git a/core/src/main/java/org/kohsuke/stapler/BindInterceptor.java b/core/src/main/java/org/kohsuke/stapler/BindInterceptor.java index 0db793f44..e17007130 100644 --- a/core/src/main/java/org/kohsuke/stapler/BindInterceptor.java +++ b/core/src/main/java/org/kohsuke/stapler/BindInterceptor.java @@ -7,7 +7,7 @@ * Intercepts (and receives callbacks) about the JSON → object binding process. * * @author Kohsuke Kawaguchi - * @see StaplerRequest#setBindInterceptor(BindInterceptor) + * @see StaplerRequest2#setBindInterceptor(BindInterceptor) * @see WebApp#bindInterceptors */ public class BindInterceptor { diff --git a/core/src/main/java/org/kohsuke/stapler/ClassDescriptor.java b/core/src/main/java/org/kohsuke/stapler/ClassDescriptor.java index 6351184b1..cd6a4e3e4 100644 --- a/core/src/main/java/org/kohsuke/stapler/ClassDescriptor.java +++ b/core/src/main/java/org/kohsuke/stapler/ClassDescriptor.java @@ -155,8 +155,8 @@ public int compare(Method m1, Method m2) { } else if (!m1d && m2d) { return -1; } else { - // Sort by string representation, so for example doFoo() is preferred to doFoo(StaplerRequest, - // StaplerResponse). + // Sort by string representation, so for example doFoo() is preferred to doFoo(StaplerRequest2, + // StaplerResponse2). return m1.toString().compareTo(m2.toString()); } } diff --git a/core/src/main/java/org/kohsuke/stapler/CompatibleFilter.java b/core/src/main/java/org/kohsuke/stapler/CompatibleFilter.java new file mode 100644 index 000000000..0290a7f19 --- /dev/null +++ b/core/src/main/java/org/kohsuke/stapler/CompatibleFilter.java @@ -0,0 +1,59 @@ +package org.kohsuke.stapler; + +import io.jenkins.servlet.FilterChainWrapper; +import io.jenkins.servlet.FilterConfigWrapper; +import io.jenkins.servlet.ServletExceptionWrapper; +import io.jenkins.servlet.ServletRequestWrapper; +import io.jenkins.servlet.ServletResponseWrapper; +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import java.io.IOException; + +public interface CompatibleFilter extends Filter { + /** + * @deprecated use {@link #init(FilterConfig)} + */ + @Deprecated + default void init(javax.servlet.FilterConfig filterConfig) throws javax.servlet.ServletException { + try { + init(FilterConfigWrapper.toJakartaFilterConfig(filterConfig)); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + /** + * @deprecated use {@link #doFilter(ServletRequest, ServletResponse, FilterChain)} + */ + @Deprecated + default void doFilter( + javax.servlet.ServletRequest request, + javax.servlet.ServletResponse response, + javax.servlet.FilterChain chain) + throws IOException, javax.servlet.ServletException { + try { + if (request instanceof javax.servlet.http.HttpServletRequest + && response instanceof javax.servlet.http.HttpServletResponse) { + javax.servlet.http.HttpServletRequest httpRequest = (javax.servlet.http.HttpServletRequest) request; + javax.servlet.http.HttpServletResponse httpResponse = (javax.servlet.http.HttpServletResponse) response; + doFilter( + HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest), + HttpServletResponseWrapper.toJakartaHttpServletResponse(httpResponse), + FilterChainWrapper.toJakartaFilterChain(chain)); + } else { + doFilter( + ServletRequestWrapper.toJakartaServletRequest(request), + ServletResponseWrapper.toJakartaServletResponse(response), + FilterChainWrapper.toJakartaFilterChain(chain)); + } + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } +} diff --git a/core/src/main/java/org/kohsuke/stapler/CrumbIssuer.java b/core/src/main/java/org/kohsuke/stapler/CrumbIssuer.java index 5d5737955..dc2b8b57a 100644 --- a/core/src/main/java/org/kohsuke/stapler/CrumbIssuer.java +++ b/core/src/main/java/org/kohsuke/stapler/CrumbIssuer.java @@ -1,7 +1,7 @@ package org.kohsuke.stapler; +import jakarta.servlet.http.HttpSession; import java.util.UUID; -import javax.servlet.http.HttpSession; /** * Generates a nonce value that allows us to protect against cross-site request forgery (CSRF) attacks. @@ -17,10 +17,30 @@ public abstract class CrumbIssuer { /** * Issues a crumb for the given request. */ - public abstract String issueCrumb(StaplerRequest request); + public /* abstract */ String issueCrumb(StaplerRequest2 request) { + return ReflectionUtils.ifOverridden( + () -> issueCrumb(StaplerRequest.fromStaplerRequest2(request)), + CrumbIssuer.class, + getClass(), + "issueCrumb", + StaplerRequest.class); + } + + /** + * @deprecated use {@link #issueCrumb(StaplerRequest2)} + */ + @Deprecated + public String issueCrumb(StaplerRequest request) { + return ReflectionUtils.ifOverridden( + () -> issueCrumb(StaplerRequest.toStaplerRequest2(request)), + CrumbIssuer.class, + getClass(), + "issueCrumb", + StaplerRequest2.class); + } public final String issueCrumb() { - return issueCrumb(Stapler.getCurrentRequest()); + return issueCrumb(Stapler.getCurrentRequest2()); } /** @@ -41,18 +61,26 @@ public HttpResponse doCrumb() { * @throws SecurityException * If the crumb doesn't match and the request processing should abort. */ - public void validateCrumb(StaplerRequest request, String submittedCrumb) { + public void validateCrumb(StaplerRequest2 request, String submittedCrumb) { if (!issueCrumb(request).equals(submittedCrumb)) { throw new SecurityException("Request failed to pass the crumb test (try clearing your cookies)"); } } + /** + * @deprecated use {@link #validateCrumb(StaplerRequest2, String)} + */ + @Deprecated + public void validateCrumb(StaplerRequest request, String submittedCrumb) { + validateCrumb(StaplerRequest.toStaplerRequest2(request), submittedCrumb); + } + /** * Default crumb issuer. */ public static final CrumbIssuer DEFAULT = new CrumbIssuer() { @Override - public String issueCrumb(StaplerRequest request) { + public String issueCrumb(StaplerRequest2 request) { HttpSession s = request.getSession(); String v = (String) s.getAttribute(ATTRIBUTE_NAME); if (v != null) { diff --git a/core/src/main/java/org/kohsuke/stapler/DataBoundConstructor.java b/core/src/main/java/org/kohsuke/stapler/DataBoundConstructor.java index 749d20aaf..7406967a7 100644 --- a/core/src/main/java/org/kohsuke/stapler/DataBoundConstructor.java +++ b/core/src/main/java/org/kohsuke/stapler/DataBoundConstructor.java @@ -33,13 +33,13 @@ /** * Designates the constructor to be created * from methods like - * {@link StaplerRequest#bindJSON(Class, JSONObject)} and - * {@link StaplerRequest#bindParameters(Class, String)}. + * {@link StaplerRequest2#bindJSON(Class, JSONObject)} and + * {@link StaplerRequest2#bindParameters(Class, String)}. * *

* Stapler will invoke the designated constructor by using arguments from the corresponding - * {@link JSONObject} (in case of {@link StaplerRequest#bindJSON(Class, JSONObject)}) or request parameters - * (in case of {@link StaplerRequest#bindParameters(Class, String)}). + * {@link JSONObject} (in case of {@link StaplerRequest2#bindJSON(Class, JSONObject)}) or request parameters + * (in case of {@link StaplerRequest2#bindParameters(Class, String)}). * *

* The matching is done by using the constructor parameter name. Since this information is not available diff --git a/core/src/main/java/org/kohsuke/stapler/DataBoundResolvable.java b/core/src/main/java/org/kohsuke/stapler/DataBoundResolvable.java index b0723709e..a86821644 100644 --- a/core/src/main/java/org/kohsuke/stapler/DataBoundResolvable.java +++ b/core/src/main/java/org/kohsuke/stapler/DataBoundResolvable.java @@ -4,12 +4,12 @@ /** * For data-bound class (that has a constructor marked with {@link DataBoundConstructor}, the - * {@link #bindResolve(StaplerRequest, JSONObject)} allows an instance to replace the object + * {@link #bindResolve(StaplerRequest2, JSONObject)} allows an instance to replace the object * bound from submitted JSON object. * *

* This method is automatically invoked by Stapler during databinding method like - * {@link StaplerRequest#bindJSON(Class, JSONObject)}. + * {@link StaplerRequest2#bindJSON(Class, JSONObject)}. * *

* This method definition is inspired by Java serialization's {@code readResolve()} method. @@ -31,5 +31,5 @@ public interface DataBoundResolvable { * Can be any value, including null. Typically, this method would have to return an * instance of a type compatible to the caller's expectation. */ - Object bindResolve(StaplerRequest request, JSONObject src); + Object bindResolve(StaplerRequest2 request, JSONObject src); } diff --git a/core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java b/core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java index 7ed4c5930..7d0d2de03 100644 --- a/core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java +++ b/core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java @@ -11,8 +11,8 @@ /** * Designates a setter method or a field used to databind JSON values into objects in methods like - * {@link StaplerRequest#bindJSON(Class, JSONObject)} and - * {@link StaplerRequest#bindParameters(Class, String)}. + * {@link StaplerRequest2#bindJSON(Class, JSONObject)} and + * {@link StaplerRequest2#bindParameters(Class, String)}. * *

* Stapler will first invoke {@link DataBoundConstructor}-annotated constructor, and if there's any diff --git a/core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java b/core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java index 7cef9f850..1b72836b1 100644 --- a/core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java +++ b/core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java @@ -1,20 +1,20 @@ package org.kohsuke.stapler; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; /** * {@link Filter} that sets the thread name to reflect the current request being processed. * * @author Kohsuke Kawaguchi */ -public class DiagnosticThreadNameFilter implements Filter { +public class DiagnosticThreadNameFilter implements CompatibleFilter { @Override public void init(FilterConfig filterConfig) throws ServletException {} diff --git a/core/src/main/java/org/kohsuke/stapler/DirectoryishDispatcher.java b/core/src/main/java/org/kohsuke/stapler/DirectoryishDispatcher.java index 9970c7088..3e7cd5404 100644 --- a/core/src/main/java/org/kohsuke/stapler/DirectoryishDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/DirectoryishDispatcher.java @@ -1,10 +1,10 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; /** * {@link Dispatcher} that tells browsers to append '/' to the request path and try again. diff --git a/core/src/main/java/org/kohsuke/stapler/DispatchValidator.java b/core/src/main/java/org/kohsuke/stapler/DispatchValidator.java index e21a84060..e5237cf76 100644 --- a/core/src/main/java/org/kohsuke/stapler/DispatchValidator.java +++ b/core/src/main/java/org/kohsuke/stapler/DispatchValidator.java @@ -48,7 +48,7 @@ public interface DispatchValidator { * @return true if the request should be dispatched, false if not, or null if unknown or neutral */ @CheckForNull - Boolean isDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp); + Boolean isDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp); /** * Checks if the given request and response should be allowed to dispatch a view on an optionally present node @@ -61,24 +61,24 @@ public interface DispatchValidator { * @return true if the view should be allowed to dispatch, false if it should not, or null if unknown */ default @CheckForNull Boolean isDispatchAllowed( - @NonNull StaplerRequest req, - @NonNull StaplerResponse rsp, + @NonNull StaplerRequest2 req, + @NonNull StaplerResponse2 rsp, @NonNull String viewName, @CheckForNull Object node) { return isDispatchAllowed(req, rsp); } /** - * Allows the given request to be dispatched. Further calls to {@link #isDispatchAllowed(StaplerRequest, StaplerResponse)} + * Allows the given request to be dispatched. Further calls to {@link #isDispatchAllowed(StaplerRequest2, StaplerResponse2)} * should return true for the same request. */ - void allowDispatch(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp); + void allowDispatch(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp); /** * Throws a {@link CancelRequestHandlingException} if the given request is not - * {@linkplain #isDispatchAllowed(StaplerRequest, StaplerResponse) allowed}. + * {@linkplain #isDispatchAllowed(StaplerRequest2, StaplerResponse2) allowed}. */ - default void requireDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) + default void requireDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) throws CancelRequestHandlingException { Boolean allowed = isDispatchAllowed(req, rsp); if (allowed == null || !allowed) { @@ -91,12 +91,12 @@ default void requireDispatchAllowed(@NonNull StaplerRequest req, @NonNull Staple */ DispatchValidator DEFAULT = new DispatchValidator() { @Override - public Boolean isDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) { + public Boolean isDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) { return true; } @Override - public void allowDispatch(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) { + public void allowDispatch(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) { // no-op } }; diff --git a/core/src/main/java/org/kohsuke/stapler/Dispatcher.java b/core/src/main/java/org/kohsuke/stapler/Dispatcher.java index 17e52b5ee..6b5fd1f63 100644 --- a/core/src/main/java/org/kohsuke/stapler/Dispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/Dispatcher.java @@ -24,6 +24,7 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -31,7 +32,6 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; /** * Controls the dispatching of incoming HTTP requests. @@ -63,7 +63,7 @@ public static boolean traceable() { return TRACE || TRACE_PER_REQUEST || LOGGER.isLoggable(Level.FINE); } - public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node) { + public static void traceEval(StaplerRequest2 req, StaplerResponse2 rsp, Object node) { trace( req, rsp, @@ -75,14 +75,14 @@ public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object nod } public static void anonymizedTraceEval( - StaplerRequest req, StaplerResponse rsp, Object node, String format, String... args) { + StaplerRequest2 req, StaplerResponse2 rsp, Object node, String format, String... args) { List arg = new ArrayList<>(); arg.add(node == null ? "(null)" : node.getClass().getName()); arg.addAll(Arrays.asList(args)); EvaluationTrace.ApplicationTracer.trace(req, String.format(format, arg.toArray())); } - public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node, String prefix, String suffix) { + public static void traceEval(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String prefix, String suffix) { trace( req, rsp, @@ -91,7 +91,7 @@ public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object nod prefix, node, suffix, ((RequestImpl) req).tokens.assembleOriginalRestOfPath())); } - public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object node, String expression) { + public static void traceEval(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression) { trace( req, rsp, @@ -100,11 +100,11 @@ public static void traceEval(StaplerRequest req, StaplerResponse rsp, Object nod node, expression, ((RequestImpl) req).tokens.assembleOriginalRestOfPath())); } - public static void trace(StaplerRequest req, StaplerResponse rsp, String msg, Object... args) { + public static void trace(StaplerRequest2 req, StaplerResponse2 rsp, String msg, Object... args) { trace(req, rsp, String.format(msg, args)); } - public static void trace(StaplerRequest req, StaplerResponse rsp, String msg) { + public static void trace(StaplerRequest2 req, StaplerResponse2 rsp, String msg) { if (isTraceEnabled(req)) { EvaluationTrace.get(req).trace(rsp, msg); } @@ -119,7 +119,7 @@ public static void trace(StaplerRequest req, StaplerResponse rsp, String msg) { * can be enabled per-request by setting "stapler.trace.per-request=true" * and sending an "X-Stapler-Trace" header set to "true" with the request. */ - public static boolean isTraceEnabled(StaplerRequest req) { + public static boolean isTraceEnabled(StaplerRequest2 req) { if (TRACE) { return true; } diff --git a/core/src/main/java/org/kohsuke/stapler/EvaluationTrace.java b/core/src/main/java/org/kohsuke/stapler/EvaluationTrace.java index 0d012985a..7a6e6ff5f 100644 --- a/core/src/main/java/org/kohsuke/stapler/EvaluationTrace.java +++ b/core/src/main/java/org/kohsuke/stapler/EvaluationTrace.java @@ -42,7 +42,7 @@ public class EvaluationTrace { private static final Logger LOGGER = Logger.getLogger(EvaluationTrace.class.getName()); - public void trace(StaplerResponse rsp, String msg) { + public void trace(StaplerResponse2 rsp, String msg) { traces.add(msg); // Firefox Live HTTP header plugin cannot nicely render multiple headers // with the same name, so give each one unique name. @@ -57,7 +57,7 @@ public void printHtml(PrintWriter w) { } } - public static EvaluationTrace get(StaplerRequest req) { + public static EvaluationTrace get(StaplerRequest2 req) { EvaluationTrace et = (EvaluationTrace) req.getAttribute(KEY); if (et == null) { req.setAttribute(KEY, et = new EvaluationTrace()); @@ -71,9 +71,9 @@ public static EvaluationTrace get(StaplerRequest req) { private static final String KEY = EvaluationTrace.class.getName(); public abstract static class ApplicationTracer { - protected abstract void record(StaplerRequest req, String message); + protected abstract void record(StaplerRequest2 req, String message); - public static void trace(StaplerRequest req, String message) { + public static void trace(StaplerRequest2 req, String message) { List tracers = getTracers(); for (ApplicationTracer tracer : tracers) { tracer.record(req, message); diff --git a/core/src/main/java/org/kohsuke/stapler/Facet.java b/core/src/main/java/org/kohsuke/stapler/Facet.java index d77416ac8..277a5940b 100644 --- a/core/src/main/java/org/kohsuke/stapler/Facet.java +++ b/core/src/main/java/org/kohsuke/stapler/Facet.java @@ -26,6 +26,8 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; @@ -33,8 +35,6 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.logging.Logger; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.event.FilteredDispatchTriggerListener; import org.kohsuke.stapler.lang.Klass; diff --git a/core/src/main/java/org/kohsuke/stapler/ForwardToView.java b/core/src/main/java/org/kohsuke/stapler/ForwardToView.java index 2357e8ab5..641e39b9c 100644 --- a/core/src/main/java/org/kohsuke/stapler/ForwardToView.java +++ b/core/src/main/java/org/kohsuke/stapler/ForwardToView.java @@ -24,12 +24,12 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; /** * {@link HttpResponse} that forwards to a {@link RequestDispatcher}, such as a view. @@ -44,13 +44,13 @@ public class ForwardToView extends RuntimeException implements HttpResponse { private final Map attributes = new HashMap<>(); private interface DispatcherFactory { - RequestDispatcher get(StaplerRequest req) throws IOException; + RequestDispatcher get(StaplerRequest2 req) throws IOException; } public ForwardToView(final RequestDispatcher dispatcher) { this.factory = new DispatcherFactory() { @Override - public RequestDispatcher get(StaplerRequest req) { + public RequestDispatcher get(StaplerRequest2 req) { return dispatcher; } }; @@ -59,7 +59,7 @@ public RequestDispatcher get(StaplerRequest req) { public ForwardToView(final Object it, final String view) { this.factory = new DispatcherFactory() { @Override - public RequestDispatcher get(StaplerRequest req) throws IOException { + public RequestDispatcher get(StaplerRequest2 req) throws IOException { return req.getView(it, view); } }; @@ -68,7 +68,7 @@ public RequestDispatcher get(StaplerRequest req) throws IOException { public ForwardToView(final Class c, final String view) { this.factory = new DispatcherFactory() { @Override - public RequestDispatcher get(StaplerRequest req) throws IOException { + public RequestDispatcher get(StaplerRequest2 req) throws IOException { return req.getView(c, view); } }; @@ -98,7 +98,7 @@ public ForwardToView optional() { @SuppressFBWarnings( value = "REQUESTDISPATCHER_FILE_DISCLOSURE", justification = "Forwarded to a view to handle correctly.") - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { for (Entry e : attributes.entrySet()) { req.setAttribute(e.getKey(), e.getValue()); diff --git a/core/src/main/java/org/kohsuke/stapler/ForwardingFunction.java b/core/src/main/java/org/kohsuke/stapler/ForwardingFunction.java index 66e08b5ef..de80df956 100644 --- a/core/src/main/java/org/kohsuke/stapler/ForwardingFunction.java +++ b/core/src/main/java/org/kohsuke/stapler/ForwardingFunction.java @@ -1,9 +1,9 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; -import javax.servlet.ServletException; /** * {@link Function} that forwards calls to another. Usually used @@ -85,7 +85,7 @@ public String[] getParameterNames() { } @Override - public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException, ServletException { return next.invoke(req, rsp, o, args); } diff --git a/core/src/main/java/org/kohsuke/stapler/Function.java b/core/src/main/java/org/kohsuke/stapler/Function.java index 79c371097..e615a8d64 100644 --- a/core/src/main/java/org/kohsuke/stapler/Function.java +++ b/core/src/main/java/org/kohsuke/stapler/Function.java @@ -23,6 +23,10 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.ServletExceptionWrapper; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UncheckedIOException; import java.lang.annotation.Annotation; @@ -39,9 +43,6 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; @@ -125,7 +126,7 @@ public Function contextualize(Object usage) { } /** - * Calls {@link #bindAndInvoke(Object, StaplerRequest, StaplerResponse, Object...)} and then + * Calls {@link #bindAndInvoke(Object, StaplerRequest2, StaplerResponse2, Object...)} and then * optionally serve the response object. * * @return @@ -171,7 +172,7 @@ static boolean renderResponse(RequestImpl req, ResponseImpl rsp, Object node, Ob * then figure out the rest of the arguments by looking at parameter annotations, * then finally call {@link #invoke}. */ - Object bindAndInvoke(Object o, StaplerRequest req, StaplerResponse rsp, Object... headArgs) + Object bindAndInvoke(Object o, StaplerRequest2 req, StaplerResponse2 rsp, Object... headArgs) throws IllegalAccessException, InvocationTargetException, ServletException { Class[] types = getParameterTypes(); Annotation[][] annotations = getParameterAnnotations(); @@ -186,13 +187,18 @@ Object bindAndInvoke(Object o, StaplerRequest req, StaplerResponse rsp, Object.. // find the rest of the arguments. either known types, or with annotations for (int i = headArgs.length; i < types.length; i++) { Class t = types[i]; - if (t == StaplerRequest.class || t == HttpServletRequest.class) { + if (t == StaplerRequest2.class || t == HttpServletRequest.class) { arguments[i] = req; continue; - } - if (t == StaplerResponse.class || t == HttpServletResponse.class) { + } else if (t == StaplerRequest.class || t == javax.servlet.http.HttpServletRequest.class) { + arguments[i] = StaplerRequest.fromStaplerRequest2(req); + continue; + } else if (t == StaplerResponse2.class || t == HttpServletResponse.class) { arguments[i] = rsp; continue; + } else if (t == StaplerResponse.class || t == javax.servlet.http.HttpServletResponse.class) { + arguments[i] = StaplerResponse.fromStaplerResponse2(rsp); + continue; } // if the databinding method is provided, call that @@ -254,7 +260,7 @@ public Annotation[][] getParameterAnnotations() { } @Override - public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { return m.invoke(null, args); } @@ -276,8 +282,52 @@ public static Object returnNull() { /** * Invokes the method. */ - public abstract Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) - throws IllegalAccessException, InvocationTargetException, ServletException; + public /* abstract */ Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) + throws IllegalAccessException, InvocationTargetException, ServletException { + if (ReflectionUtils.isOverridden( + Function.class, + getClass(), + "invoke", + StaplerRequest.class, + StaplerResponse.class, + Object.class, + Object[].class)) { + try { + return invoke( + StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp), o, args); + } catch (javax.servlet.ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + Function.class.getSimpleName() + ".invoke methods"); + } + } + + /** + * @deprecated use {@link #invoke(StaplerRequest2, StaplerResponse2, Object, Object...)} + */ + @Deprecated + public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + throws IllegalAccessException, InvocationTargetException, javax.servlet.ServletException { + if (ReflectionUtils.isOverridden( + Function.class, + getClass(), + "invoke", + StaplerRequest2.class, + StaplerResponse2.class, + Object.class, + Object[].class)) { + try { + return invoke(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), o, args); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + Function.class.getSimpleName() + ".invoke methods"); + } + } final Function wrapByInterceptors(AnnotatedElement m) { try { @@ -420,7 +470,7 @@ protected MethodHandle handle() { } @Override - public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException { Object[] arguments; if (Modifier.isStatic(m.getModifiers())) { diff --git a/core/src/main/java/org/kohsuke/stapler/Header.java b/core/src/main/java/org/kohsuke/stapler/Header.java index cd4e53072..74faea7a0 100644 --- a/core/src/main/java/org/kohsuke/stapler/Header.java +++ b/core/src/main/java/org/kohsuke/stapler/Header.java @@ -23,12 +23,12 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.servlet.ServletException; import org.kohsuke.stapler.Header.HandlerImpl; /** @@ -53,7 +53,7 @@ class HandlerImpl extends AnnotationHandler

{ @Override - public Object parse(StaplerRequest request, Header a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, Header a, Class type, String parameterName) throws ServletException { String name = a.value(); if (name.isEmpty()) { diff --git a/core/src/main/java/org/kohsuke/stapler/HttpDeletable.java b/core/src/main/java/org/kohsuke/stapler/HttpDeletable.java index 3689859f9..f5278c5b1 100644 --- a/core/src/main/java/org/kohsuke/stapler/HttpDeletable.java +++ b/core/src/main/java/org/kohsuke/stapler/HttpDeletable.java @@ -23,9 +23,10 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.ServletExceptionWrapper; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; /** * Marks the object that can handle HTTP DELETE. @@ -36,7 +37,37 @@ public interface HttpDeletable { /** * Called when HTTP DELETE method is invoked. */ - void delete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException; + default void delete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException { + if (ReflectionUtils.isOverridden( + HttpDeletable.class, getClass(), "delete", StaplerRequest.class, StaplerResponse.class)) { + try { + delete(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp)); + } catch (javax.servlet.ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + HttpDeletable.class.getSimpleName() + ".delete methods"); + } + } + + /** + * @deprecated use {@link #delete(StaplerRequest2, StaplerResponse2)} + */ + @Deprecated + default void delete(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException { + if (ReflectionUtils.isOverridden( + HttpDeletable.class, getClass(), "delete", StaplerRequest2.class, StaplerResponse2.class)) { + try { + delete(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp)); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + HttpDeletable.class.getSimpleName() + ".delete methods"); + } + } /** * {@link Dispatcher} that processes {@link HttpDeletable} diff --git a/core/src/main/java/org/kohsuke/stapler/HttpRedirect.java b/core/src/main/java/org/kohsuke/stapler/HttpRedirect.java index 39e123eba..357034c8b 100644 --- a/core/src/main/java/org/kohsuke/stapler/HttpRedirect.java +++ b/core/src/main/java/org/kohsuke/stapler/HttpRedirect.java @@ -24,9 +24,9 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.NonNull; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; /** * {@link HttpResponse} that dose HTTP 302 redirect. @@ -51,7 +51,7 @@ public HttpRedirect(int statusCode, @NonNull String url) { } @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.sendRedirect(statusCode, url); } diff --git a/core/src/main/java/org/kohsuke/stapler/HttpResponse.java b/core/src/main/java/org/kohsuke/stapler/HttpResponse.java index 44306b867..59d069e51 100644 --- a/core/src/main/java/org/kohsuke/stapler/HttpResponse.java +++ b/core/src/main/java/org/kohsuke/stapler/HttpResponse.java @@ -23,8 +23,9 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.ServletExceptionWrapper; +import jakarta.servlet.ServletException; import java.io.IOException; -import javax.servlet.ServletException; /** * Object that represents the HTTP response, which is defined as a capability to produce the response. @@ -43,5 +44,53 @@ public interface HttpResponse { * @param node * The object whose "doXyz" method created this object. */ - void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException; + default void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) + throws IOException, ServletException { + if (ReflectionUtils.isOverridden( + HttpResponse.class, + getClass(), + "generateResponse", + StaplerRequest.class, + StaplerResponse.class, + Object.class)) { + try { + generateResponse( + req != null ? StaplerRequest.fromStaplerRequest2(req) : null, + rsp != null ? StaplerResponse.fromStaplerResponse2(rsp) : null, + node); + } catch (javax.servlet.ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + HttpResponse.class.getSimpleName() + ".generateResponse methods"); + } + } + + /** + * @deprecated use {@link #generateResponse(StaplerRequest2, StaplerResponse2, Object)} + */ + @Deprecated + default void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + throws IOException, javax.servlet.ServletException { + if (ReflectionUtils.isOverridden( + HttpResponse.class, + getClass(), + "generateResponse", + StaplerRequest2.class, + StaplerResponse2.class, + Object.class)) { + try { + generateResponse( + req != null ? StaplerRequest.toStaplerRequest2(req) : null, + rsp != null ? StaplerResponse.toStaplerResponse2(rsp) : null, + node); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + HttpResponse.class.getSimpleName() + ".generateResponse methods"); + } + } } diff --git a/core/src/main/java/org/kohsuke/stapler/HttpResponseRenderer.java b/core/src/main/java/org/kohsuke/stapler/HttpResponseRenderer.java index b01fd35e6..8ef8d7217 100644 --- a/core/src/main/java/org/kohsuke/stapler/HttpResponseRenderer.java +++ b/core/src/main/java/org/kohsuke/stapler/HttpResponseRenderer.java @@ -23,12 +23,12 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONException; @@ -58,7 +58,7 @@ public abstract class HttpResponseRenderer { * false otherwise, in which case the next {@link HttpResponseRenderer} * will be consulted. */ - public abstract boolean generateResponse(StaplerRequest req, StaplerResponse rsp, Object node, Object response) + public abstract boolean generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node, Object response) throws IOException, ServletException; /** @@ -66,7 +66,7 @@ public abstract boolean generateResponse(StaplerRequest req, StaplerResponse rsp */ public static class Default extends HttpResponseRenderer { @Override - public boolean generateResponse(StaplerRequest req, StaplerResponse rsp, Object node, Object response) + public boolean generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node, Object response) throws IOException, ServletException { return handleHttpResponse(req, rsp, node, response) || handleJSON(rsp, response) @@ -74,7 +74,7 @@ public boolean generateResponse(StaplerRequest req, StaplerResponse rsp, Object || handlePrimitive(rsp, response); } - protected boolean handleJavaScriptProxyMethodCall(StaplerRequest req, StaplerResponse rsp, Object response) + protected boolean handleJavaScriptProxyMethodCall(StaplerRequest2 req, StaplerResponse2 rsp, Object response) throws IOException { if (req.isJavaScriptProxyCall()) { rsp.setContentType(Flavor.JSON.contentType); @@ -112,7 +112,7 @@ protected boolean handleJavaScriptProxyMethodCall(StaplerRequest req, StaplerRes return false; } - protected boolean handlePrimitive(StaplerResponse rsp, Object response) throws IOException { + protected boolean handlePrimitive(StaplerResponse2 rsp, Object response) throws IOException { if (response instanceof String || response instanceof Integer) { rsp.setContentType("text/plain;charset=UTF-8"); rsp.getWriter().print(response); @@ -121,7 +121,7 @@ protected boolean handlePrimitive(StaplerResponse rsp, Object response) throws I return false; } - protected boolean handleHttpResponse(StaplerRequest req, StaplerResponse rsp, Object node, Object response) + protected boolean handleHttpResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node, Object response) throws IOException, ServletException { if (response instanceof HttpResponse r) { // let the result render the response @@ -137,7 +137,7 @@ protected boolean handleHttpResponse(StaplerRequest req, StaplerResponse rsp, Ob return false; } - protected boolean handleJSON(StaplerResponse rsp, Object response) throws IOException { + protected boolean handleJSON(StaplerResponse2 rsp, Object response) throws IOException { if (response instanceof JSON) { rsp.setContentType(Flavor.JSON.contentType); ((JSON) response).write(rsp.getWriter()); diff --git a/core/src/main/java/org/kohsuke/stapler/HttpResponses.java b/core/src/main/java/org/kohsuke/stapler/HttpResponses.java index aa8a8a97e..24a27b0bb 100644 --- a/core/src/main/java/org/kohsuke/stapler/HttpResponses.java +++ b/core/src/main/java/org/kohsuke/stapler/HttpResponses.java @@ -25,12 +25,12 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.ServiceLoader; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; /** * Factory for {@link HttpResponse}. @@ -75,7 +75,7 @@ public static HttpResponseException forbidden() { public static HttpResponseException status(final int code) { return new HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setStatus(code); } @@ -108,7 +108,7 @@ public static HttpResponseException error(final int code, final Throwable cause) @SuppressFBWarnings( value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", justification = "Jenkins handles this issue differently or doesn't care about it") - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setStatus(code); @@ -130,7 +130,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod public static HttpResponseException errorWithoutStack(final int code, final String errorMessage) { return new HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.sendError(code, errorMessage); } @@ -144,7 +144,7 @@ public static HttpResponseException wrap(HttpResponse delegate) { if (delegate instanceof Throwable) { return new HttpResponseException(((Throwable) delegate).getMessage(), (Throwable) delegate) { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { delegate.generateResponse(req, rsp, node); } @@ -152,7 +152,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod } else { return new HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { delegate.generateResponse(req, rsp, node); } @@ -172,7 +172,7 @@ public static HttpResponseException redirectViaContextPath(String relative) { public static HttpResponseException redirectViaContextPath(final int statusCode, final String relative) { return new HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { StringBuilder sb = new StringBuilder(req.getContextPath()); if (!relative.startsWith("/")) { @@ -220,7 +220,7 @@ public static HttpResponseException forwardToPreviousPage() { private static final HttpResponseException FORWARD_TO_PREVIOUS_PAGE = new HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.forwardToPreviousPage(req); } @@ -250,7 +250,7 @@ public static HttpResponse staticResource(URL resource) { public static HttpResponse staticResource(final URL resource, final long expiration) { return new HttpResponse() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.serveFile(req, resource, expiration); } @@ -264,7 +264,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod public static HttpResponse html(final String literalHtml) { return new HttpResponse() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/html;charset=UTF-8"); rsp.getWriter().println(literalHtml); @@ -278,7 +278,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod public static HttpResponse literalHtml(final String text) { return new HttpResponse() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/html;charset=UTF-8"); PrintWriter pw = rsp.getWriter(); @@ -295,7 +295,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod public static HttpResponse plainText(final String plainText) { return new HttpResponse() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/plain;charset=UTF-8"); rsp.getWriter().println(plainText); @@ -309,7 +309,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod public static HttpResponse text(final String text) { return new HttpResponse() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setContentType("text/plain;charset=UTF-8"); PrintWriter pw = rsp.getWriter(); diff --git a/core/src/main/java/org/kohsuke/stapler/IndexDispatcher.java b/core/src/main/java/org/kohsuke/stapler/IndexDispatcher.java index f25266947..9501581e6 100644 --- a/core/src/main/java/org/kohsuke/stapler/IndexDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/IndexDispatcher.java @@ -1,8 +1,8 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; /** * {@link Dispatcher} for url=/ that handles the tail of an URL. diff --git a/core/src/main/java/org/kohsuke/stapler/IndexHtmlDispatcher.java b/core/src/main/java/org/kohsuke/stapler/IndexHtmlDispatcher.java index 6e3ba1eec..2d5002bc1 100644 --- a/core/src/main/java/org/kohsuke/stapler/IndexHtmlDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/IndexHtmlDispatcher.java @@ -1,10 +1,10 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; /** * Serve {@code index.html} from {@code WEB-INF/side-files} if that exists. diff --git a/core/src/main/java/org/kohsuke/stapler/IndexViewDispatcher.java b/core/src/main/java/org/kohsuke/stapler/IndexViewDispatcher.java index af3dd973e..1e47866bd 100644 --- a/core/src/main/java/org/kohsuke/stapler/IndexViewDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/IndexViewDispatcher.java @@ -1,8 +1,8 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; /** * {@link Dispatcher} that deals with the "index" view pages that are used when the request path doesn't contain diff --git a/core/src/main/java/org/kohsuke/stapler/LimitedTo.java b/core/src/main/java/org/kohsuke/stapler/LimitedTo.java index 51c82c0d0..71a21722e 100644 --- a/core/src/main/java/org/kohsuke/stapler/LimitedTo.java +++ b/core/src/main/java/org/kohsuke/stapler/LimitedTo.java @@ -23,12 +23,12 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; @@ -63,7 +63,7 @@ public void setTarget(Function target) { } @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { if (request.isUserInRole(role)) { return target.invoke(request, response, instance, arguments); diff --git a/core/src/main/java/org/kohsuke/stapler/LocaleDrivenResourceProvider.java b/core/src/main/java/org/kohsuke/stapler/LocaleDrivenResourceProvider.java index c82b2282d..f8cadf6b3 100644 --- a/core/src/main/java/org/kohsuke/stapler/LocaleDrivenResourceProvider.java +++ b/core/src/main/java/org/kohsuke/stapler/LocaleDrivenResourceProvider.java @@ -35,7 +35,7 @@ /** * Service provider interface allowing to hook into webapp resource lookup. * - * This cannot be made a property of WebApp as other behavior customizations, as webapp resource lookup is done before we have StaplerRequest/StaplerResponse. + * This cannot be made a property of WebApp as other behavior customizations, as webapp resource lookup is done before we have StaplerRequest2/StaplerResponse2. */ public abstract class LocaleDrivenResourceProvider { /** diff --git a/core/src/main/java/org/kohsuke/stapler/MetaClass.java b/core/src/main/java/org/kohsuke/stapler/MetaClass.java index f9511b1df..92e2903bf 100644 --- a/core/src/main/java/org/kohsuke/stapler/MetaClass.java +++ b/core/src/main/java/org/kohsuke/stapler/MetaClass.java @@ -25,6 +25,8 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import jakarta.annotation.PostConstruct; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; @@ -33,8 +35,6 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONArray; import org.apache.commons.io.IOUtils; import org.kohsuke.stapler.bind.JavaScriptMethod; @@ -156,7 +156,7 @@ public class MetaClass extends TearOffSupport { f.buildIndexDispatchers(this, dispatchers); } - Dispatcher d = IndexHtmlDispatcher.make(webApp.context, clazz); + Dispatcher d = IndexHtmlDispatcher.make(webApp.getServletContext(), clazz); if (d != null) { dispatchers.add(d); } @@ -264,8 +264,8 @@ public String toString() { }); } - // check public selector methods of the form static NODE.getTOKEN(StaplerRequest) - for (final Function f : getMethods.signature(StaplerRequest.class)) { + // check public selector methods of the form static NODE.getTOKEN(StaplerRequest2) + for (final Function f : getMethods.signature(StaplerRequest2.class)) { if (f.getName().length() <= 3) { continue; } @@ -290,6 +290,48 @@ public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) } } + @Override + public String toString() { + if (isAccepted) { + return String.format( + "%3$s %1$s(StaplerRequest2) for url=/%2$s/...", + ff.getQualifiedName(), name, ff.getReturnType().getName()); + } else { + return String.format( + "BLOCKED: %3$s %1$s(StaplerRequest2) for url=/%2$s/...", + ff.getQualifiedName(), name, ff.getReturnType().getName()); + } + } + }); + } + + // check public selector methods of the deprecated form static NODE.getTOKEN(StaplerRequest) + for (final Function f : getMethods.signature(StaplerRequest.class)) { + if (f.getName().length() <= 3) { + continue; + } + String name = camelize(f.getName().substring(3)); // 'getFoo' -> 'foo' + final Function ff = f.contextualize(new TraversalMethodContext(name)); + final boolean isAccepted = filteredGetMethods.contains(f); + + dispatchers.add(new NameBasedDispatcher(name) { + @Override + public boolean doDispatch(RequestImpl req, ResponseImpl rsp, Object node) + throws IOException, ServletException, IllegalAccessException, InvocationTargetException { + if (isAccepted) { + Dispatcher.anonymizedTraceEval(req, rsp, node, "%s#%s(...)", ff.getName()); + if (traceable()) { + traceEval(req, rsp, node, ff.getName() + "(...)"); + } + req.getStapler() + .invoke(req, rsp, ff.invoke(req, rsp, node, StaplerRequest.fromStaplerRequest2(req))); + return true; + } else { + return webApp.getFilteredGetterTriggerListener() + .onGetterTrigger(f, req, rsp, node, ff.getName() + "(...)"); + } + } + @Override public String toString() { if (isAccepted) { @@ -560,7 +602,7 @@ public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) @Override public String toString() { return String.format( - "%2$s %s(String,StaplerRequest,StaplerResponse) for url=/TOKEN/...", + "%2$s %s(String,StaplerRequest[2],StaplerResponse[2]) for url=/TOKEN/...", ff.getQualifiedName(), ff.getReturnType().getName()); } }); @@ -582,7 +624,7 @@ public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) @Override public String toString() { - return String.format("%s(StaplerRequest,StaplerResponse) for any URL", ff.getQualifiedName()); + return String.format("%s(StaplerRequest[2],StaplerResponse[2]) for any URL", ff.getQualifiedName()); } }); } diff --git a/core/src/main/java/org/kohsuke/stapler/NameBasedDispatcher.java b/core/src/main/java/org/kohsuke/stapler/NameBasedDispatcher.java index 30a21b3d6..050920d83 100644 --- a/core/src/main/java/org/kohsuke/stapler/NameBasedDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/NameBasedDispatcher.java @@ -23,9 +23,9 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; /** * @author Kohsuke Kawaguchi diff --git a/core/src/main/java/org/kohsuke/stapler/PreInvokeInterceptedFunction.java b/core/src/main/java/org/kohsuke/stapler/PreInvokeInterceptedFunction.java index 2f39f908a..55ea851da 100644 --- a/core/src/main/java/org/kohsuke/stapler/PreInvokeInterceptedFunction.java +++ b/core/src/main/java/org/kohsuke/stapler/PreInvokeInterceptedFunction.java @@ -1,7 +1,7 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; import org.kohsuke.stapler.interceptor.Stage; @@ -21,7 +21,7 @@ final class PreInvokeInterceptedFunction extends ForwardingFunction { } @Override - public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException, ServletException { return interceptor.invoke(req, rsp, o, args); } diff --git a/core/src/main/java/org/kohsuke/stapler/QueryParameter.java b/core/src/main/java/org/kohsuke/stapler/QueryParameter.java index 6f062399d..d1f8f3e74 100644 --- a/core/src/main/java/org/kohsuke/stapler/QueryParameter.java +++ b/core/src/main/java/org/kohsuke/stapler/QueryParameter.java @@ -23,12 +23,12 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.servlet.ServletException; import org.kohsuke.stapler.QueryParameter.HandlerImpl; /** @@ -60,7 +60,7 @@ class HandlerImpl extends AnnotationHandler { @Override - public Object parse(StaplerRequest request, QueryParameter a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, QueryParameter a, Class type, String parameterName) throws ServletException { String name = a.value(); if (name.isEmpty()) { diff --git a/core/src/main/java/org/kohsuke/stapler/ReflectionUtils.java b/core/src/main/java/org/kohsuke/stapler/ReflectionUtils.java index b21389913..929d16eb1 100644 --- a/core/src/main/java/org/kohsuke/stapler/ReflectionUtils.java +++ b/core/src/main/java/org/kohsuke/stapler/ReflectionUtils.java @@ -23,12 +23,17 @@ package org.kohsuke.stapler; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; /** * @author Kohsuke Kawaguchi @@ -81,4 +86,112 @@ public static Annotation[] union(Annotation[] a, Annotation[] b) { return combined.toArray(new Annotation[0]); } + + /** + * Checks whether the method defined on the base type with the given arguments is overridden in the given derived + * type. + * + * @param base The base type. + * @param derived The derived type. + * @param methodName The name of the method. + * @param types The types of the arguments for the method. + * @return {@code true} when {@code derived} provides the specified method other than as inherited from {@code base}. + * @throws IllegalArgumentException When {@code derived} does not derive from {@code base}, or when {@code base} + * does not contain the specified method. + */ + public static boolean isOverridden( + @NonNull Class base, @NonNull Class derived, @NonNull String methodName, @NonNull Class... types) { + // If derived is not a subclass or implementor of base, it can't override any method + // Technically this should also be triggered when base == derived, because it can't override its own method, but + // the unit tests explicitly test for that as working. + if (!base.isAssignableFrom(derived)) { + throw new IllegalArgumentException("The specified derived class (" + derived.getCanonicalName() + + ") does not derive from the specified base class (" + base.getCanonicalName() + ")."); + } + final Method baseMethod = getMethod(base, null, methodName, types); + if (baseMethod == null) { + throw new IllegalArgumentException("The specified method is not declared by the specified base class (" + + base.getCanonicalName() + "), or it is private, static or final."); + } + final Method derivedMethod = getMethod(derived, base, methodName, types); + // the lookup will either return null or the base method when no override has been found (depending on whether + // the base is an interface) + return derivedMethod != null && derivedMethod != baseMethod; + } + + /** + * Calls the given supplier if the method defined on the base type with the given arguments is overridden in the + * given derived type. + * + * @param supplier The supplier to call if the method is indeed overridden. + * @param base The base type. + * @param derived The derived type. + * @param methodName The name of the method. + * @param types The types of the arguments for the method. + * @return {@code true} when {@code derived} provides the specified method other than as inherited from {@code base}. + * @throws IllegalArgumentException When {@code derived} does not derive from {@code base}, or when {@code base} + * does not contain the specified method. + * @throws AbstractMethodError If the derived class doesn't override the given method. + * @since 2.259 + */ + public static T ifOverridden( + Supplier supplier, + @NonNull Class base, + @NonNull Class derived, + @NonNull String methodName, + @NonNull Class... types) { + if (isOverridden(base, derived, methodName, types)) { + return supplier.get(); + } else { + throw new AbstractMethodError("The class " + derived.getName() + " must override at least one of the " + + base.getSimpleName() + "." + methodName + " methods"); + } + } + + private static Method getMethod( + @NonNull Class clazz, @Nullable Class base, @NonNull String methodName, @NonNull Class... types) { + try { + final Method res = clazz.getDeclaredMethod(methodName, types); + final int mod = res.getModifiers(); + // private and static methods are never ok, and end the search + if (Modifier.isPrivate(mod) || Modifier.isStatic(mod)) { + return null; + } + // when looking for the base/declaring method, final is not ok + if (base == null && Modifier.isFinal(mod)) { + return null; + } + // when looking for the overriding method, abstract is not ok + if (base != null && Modifier.isAbstract(mod)) { + return null; + } + return res; + } catch (NoSuchMethodException e) { + // If the base is an interface, the implementation may come from a default implementation on a derived + // interface. So look at interfaces too. + if (base != null && Modifier.isInterface(base.getModifiers())) { + for (Class iface : clazz.getInterfaces()) { + if (base.equals(iface) || !base.isAssignableFrom(iface)) { + continue; + } + final Method defaultImpl = getMethod(iface, base, methodName, types); + if (defaultImpl != null) { + return defaultImpl; + } + } + } + // Method not found in clazz, let's search in superclasses + Class superclass = clazz.getSuperclass(); + if (superclass != null) { + // if the superclass doesn't derive from base anymore (or IS base), stop looking + if (base != null && (base.equals(superclass) || !base.isAssignableFrom(superclass))) { + return null; + } + return getMethod(superclass, base, methodName, types); + } + return null; + } catch (SecurityException e) { + throw new AssertionError(e); + } + } } diff --git a/core/src/main/java/org/kohsuke/stapler/RequestImpl.java b/core/src/main/java/org/kohsuke/stapler/RequestImpl.java index 12ae78720..1c7c89572 100644 --- a/core/src/main/java/org/kohsuke/stapler/RequestImpl.java +++ b/core/src/main/java/org/kohsuke/stapler/RequestImpl.java @@ -23,6 +23,12 @@ package org.kohsuke.stapler; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import jakarta.servlet.http.HttpServletResponse; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.File; @@ -54,12 +60,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONException; @@ -76,8 +76,8 @@ import org.apache.commons.fileupload2.core.FileUploadException; import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException; import org.apache.commons.fileupload2.core.FileUploadSizeException; -import org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload; -import org.apache.commons.fileupload2.javax.JavaxServletFileUpload; +import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletDiskFileUpload; +import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload; import org.jvnet.tiger_types.Lister; import org.kohsuke.stapler.bind.Bound; import org.kohsuke.stapler.bind.BoundObjectTable; @@ -86,11 +86,11 @@ import org.kohsuke.stapler.util.IllegalReflectiveAccessLogHandler; /** - * {@link StaplerRequest} implementation. + * {@link StaplerRequest2} implementation. * * @author Kohsuke Kawaguchi */ -public class RequestImpl extends HttpServletRequestWrapper implements StaplerRequest { +public class RequestImpl extends HttpServletRequestWrapper implements StaplerRequest2 { /** * Tokenized URLs and consumed tokens. * This object is modified by {@link Stapler} as we parse through the URL. @@ -137,7 +137,7 @@ public class RequestImpl extends HttpServletRequestWrapper implements StaplerReq /** * Limits the number of form fields that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileCountMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload#setFileCountMax(long)}. * Despite the name, this applies to all form fields, not just actual file attachments. * Set to {@code -1} to disable limits. */ @@ -146,7 +146,7 @@ public class RequestImpl extends HttpServletRequestWrapper implements StaplerReq /** * Limits the size (in bytes) of individual fields that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileSizeMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload#setFileSizeMax(long)}. * Despite the name, this applies to all form fields, not just actual file attachments. * Set to {@code -1} to disable limits. */ @@ -155,7 +155,7 @@ public class RequestImpl extends HttpServletRequestWrapper implements StaplerReq /** * Limits the total request size (in bytes) that can be processed in one multipart/form-data request. - * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setSizeMax(long)}. + * Used to set {@link org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload#setSizeMax(long)}. * Set to {@code -1} to disable limits. */ private static /* nonfinal for Jenkins script console */ long FILEUPLOAD_MAX_SIZE = @@ -178,6 +178,22 @@ public RequestImpl(Stapler stapler, HttpServletRequest request, List ancestors, + TokenList tokens) { + this( + stapler, + io.jenkins.servlet.http.HttpServletRequestWrapper.toJakartaHttpServletRequest(request), + ancestors, + tokens); + } + @Override public boolean isJavaScriptProxyCall() { String ct = getContentType(); @@ -408,12 +424,12 @@ public String getOriginalRequestURI() { } @Override - public boolean checkIfModified(long lastModified, StaplerResponse rsp) { + public boolean checkIfModified(long lastModified, StaplerResponse2 rsp) { return checkIfModified(lastModified, rsp, 0); } @Override - public boolean checkIfModified(long lastModified, StaplerResponse rsp, long expiration) { + public boolean checkIfModified(long lastModified, StaplerResponse2 rsp, long expiration) { if (lastModified <= 0) { return false; } @@ -446,12 +462,12 @@ public boolean checkIfModified(long lastModified, StaplerResponse rsp, long expi } @Override - public boolean checkIfModified(Date timestampOfResource, StaplerResponse rsp) { + public boolean checkIfModified(Date timestampOfResource, StaplerResponse2 rsp) { return checkIfModified(timestampOfResource.getTime(), rsp); } @Override - public boolean checkIfModified(Calendar timestampOfResource, StaplerResponse rsp) { + public boolean checkIfModified(Calendar timestampOfResource, StaplerResponse2 rsp) { return checkIfModified(timestampOfResource.getTimeInMillis(), rsp); } @@ -978,7 +994,7 @@ private Object instantiate(Class actualType, JSONObject j) { } /** - * Calls {@link DataBoundResolvable#bindResolve(StaplerRequest, JSONObject)} if the object has it. + * Calls {@link DataBoundResolvable#bindResolve(StaplerRequest2, JSONObject)} if the object has it. */ private Object bindResolve(Object o, JSONObject src) { if (o instanceof DataBoundResolvable dbr) { @@ -1153,7 +1169,7 @@ private void parseMultipartFormData() throws ServletException { parsedFormData = new HashMap<>(); parsedFormDataFormFields = new HashMap<>(); - JavaxServletFileUpload upload; + JakartaServletFileUpload upload; File tmpDir; try { tmpDir = Files.createTempDirectory("jenkins-stapler-uploads").toFile(); @@ -1161,7 +1177,7 @@ private void parseMultipartFormData() throws ServletException { throw new ServletException("Error creating temporary directory", e); } tmpDir.deleteOnExit(); - upload = new JavaxServletDiskFileUpload( + upload = new JakartaServletDiskFileUpload( DiskFileItemFactory.builder().setFile(tmpDir).get()); upload.setFileCountMax(FILEUPLOAD_MAX_FILES); upload.setFileSizeMax(FILEUPLOAD_MAX_FILE_SIZE); @@ -1250,7 +1266,7 @@ public JSONObject getSubmittedForm() throws ServletException { if (p == null || p.isEmpty()) { // no data submitted try { - StaplerResponse rsp = Stapler.getCurrentResponse(); + StaplerResponse2 rsp = Stapler.getCurrentResponse2(); if (isSubmission) { rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "This page expects a form submission"); } else { diff --git a/core/src/main/java/org/kohsuke/stapler/ResponseImpl.java b/core/src/main/java/org/kohsuke/stapler/ResponseImpl.java index 98a00ec72..1ac68ece1 100644 --- a/core/src/main/java/org/kohsuke/stapler/ResponseImpl.java +++ b/core/src/main/java/org/kohsuke/stapler/ResponseImpl.java @@ -25,6 +25,11 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -39,11 +44,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; import net.sf.json.JsonConfig; import org.apache.commons.io.IOUtils; import org.kohsuke.stapler.export.DataWriter; @@ -56,11 +56,11 @@ import org.kohsuke.stapler.export.TreePruner.ByDepth; /** - * {@link StaplerResponse} implementation. + * {@link StaplerResponse2} implementation. * * @author Kohsuke Kawaguchi */ -public class ResponseImpl extends HttpServletResponseWrapper implements StaplerResponse { +public class ResponseImpl extends HttpServletResponseWrapper implements StaplerResponse2 { private final Stapler stapler; private final HttpServletResponse response; @@ -85,6 +85,14 @@ public ResponseImpl(Stapler stapler, HttpServletResponse response) { this.response = response; } + /** + * @deprecated use {@link #ResponseImpl(Stapler, HttpServletResponse)} + */ + @Deprecated + public ResponseImpl(Stapler stapler, javax.servlet.http.HttpServletResponse response) { + this(stapler, io.jenkins.servlet.http.HttpServletResponseWrapper.toJakartaHttpServletResponse(response)); + } + @Override public ServletOutputStream getOutputStream() throws IOException { if (mode == OutputMode.CHAR) { @@ -124,12 +132,12 @@ private T recordOutput(T obj) { } @Override - public void forward(Object it, String url, StaplerRequest request) throws ServletException, IOException { + public void forward(Object it, String url, StaplerRequest2 request) throws ServletException, IOException { stapler.invoke(request, response, it, url); } @Override - public void forwardToPreviousPage(StaplerRequest request) throws ServletException, IOException { + public void forwardToPreviousPage(StaplerRequest2 request) throws ServletException, IOException { String referer = request.getHeader("Referer"); if (referer == null) { referer = "."; @@ -149,7 +157,7 @@ public void sendRedirect(@NonNull String url) throws IOException { } // example: /foo/bar/zot + ../abc -> /foo/bar/../abc - String base = Stapler.getCurrentRequest().getRequestURI(); + String base = Stapler.getCurrentRequest2().getRequestURI(); base = base.substring(0, base.lastIndexOf('/') + 1); if (!url.equals(".")) { base += url; @@ -175,7 +183,7 @@ public void sendRedirect(int statusCode, @NonNull String url) throws IOException // absolute URLs url = encode(url); } else { - StaplerRequest req = Stapler.getCurrentRequest(); + StaplerRequest2 req = Stapler.getCurrentRequest2(); if (!url.startsWith("/")) { // WebSphere doesn't apparently handle relative URLs, so @@ -213,24 +221,24 @@ private void setLocation(@NonNull String url) { } @Override - public void serveFile(StaplerRequest req, URL resource, long expiration) throws ServletException, IOException { + public void serveFile(StaplerRequest2 req, URL resource, long expiration) throws ServletException, IOException { if (!stapler.serveStaticResource(req, this, resource, expiration)) { sendError(HttpServletResponse.SC_NOT_FOUND); } } @Override - public void serveFile(StaplerRequest req, URL resource) throws ServletException, IOException { + public void serveFile(StaplerRequest2 req, URL resource) throws ServletException, IOException { serveFile(req, resource, -1); } @Override - public void serveLocalizedFile(StaplerRequest request, URL res) throws ServletException, IOException { + public void serveLocalizedFile(StaplerRequest2 request, URL res) throws ServletException, IOException { serveLocalizedFile(request, res, -1); } @Override - public void serveLocalizedFile(StaplerRequest request, URL res, long expiration) + public void serveLocalizedFile(StaplerRequest2 request, URL res, long expiration) throws ServletException, IOException { if (!stapler.serveStaticResource( request, this, stapler.selectResourceByLocale(res, request.getLocale()), expiration)) { @@ -240,7 +248,7 @@ public void serveLocalizedFile(StaplerRequest request, URL res, long expiration) @Override public void serveFile( - StaplerRequest req, + StaplerRequest2 req, InputStream data, long lastModified, long expiration, @@ -254,7 +262,7 @@ public void serveFile( @Override public void serveFile( - StaplerRequest req, + StaplerRequest2 req, InputStream data, long lastModified, long expiration, @@ -265,27 +273,27 @@ public void serveFile( } @Override - public void serveFile(StaplerRequest req, InputStream data, long lastModified, long contentLength, String fileName) + public void serveFile(StaplerRequest2 req, InputStream data, long lastModified, long contentLength, String fileName) throws ServletException, IOException { serveFile(req, data, lastModified, -1, contentLength, fileName); } @Override - public void serveFile(StaplerRequest req, InputStream data, long lastModified, int contentLength, String fileName) + public void serveFile(StaplerRequest2 req, InputStream data, long lastModified, int contentLength, String fileName) throws ServletException, IOException { serveFile(req, data, lastModified, (long) contentLength, fileName); } @Override @SuppressWarnings({"unchecked", "rawtypes"}) // API design flaw prevents this from type-checking - public void serveExposedBean(StaplerRequest req, Object exposedBean, Flavor flavor) + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, Flavor flavor) throws ServletException, IOException { serveExposedBean( req, exposedBean, new ExportConfig().withFlavor(flavor).withPrettyPrint(req.hasParameter("pretty"))); } @Override - public void serveExposedBean(StaplerRequest req, Object exposedBean, ExportConfig config) + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, ExportConfig config) throws ServletException, IOException { String pad = null; Flavor flavor = config.getFlavor(); @@ -355,7 +363,7 @@ public Writer getCompressedWriter(HttpServletRequest req) throws IOException { } @Override - public int reverseProxyTo(URL url, StaplerRequest req) throws IOException { + public int reverseProxyTo(URL url, StaplerRequest2 req) throws IOException { HttpURLConnection con = openConnection(url); con.setDoOutput(true); diff --git a/core/src/main/java/org/kohsuke/stapler/ScriptExecutor.java b/core/src/main/java/org/kohsuke/stapler/ScriptExecutor.java index 9a54a6f60..3d63ae5a1 100644 --- a/core/src/main/java/org/kohsuke/stapler/ScriptExecutor.java +++ b/core/src/main/java/org/kohsuke/stapler/ScriptExecutor.java @@ -38,6 +38,7 @@ public interface ScriptExecutor { /** * Executes the given script on the given node and request, rendering output to the given response. */ - void execute(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp, @NonNull S script, @CheckForNull Object it) + void execute( + @NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp, @NonNull S script, @CheckForNull Object it) throws Exception; } diff --git a/core/src/main/java/org/kohsuke/stapler/ScriptRequestDispatcher.java b/core/src/main/java/org/kohsuke/stapler/ScriptRequestDispatcher.java index 803122772..9c63b6562 100644 --- a/core/src/main/java/org/kohsuke/stapler/ScriptRequestDispatcher.java +++ b/core/src/main/java/org/kohsuke/stapler/ScriptRequestDispatcher.java @@ -27,13 +27,13 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; /** * Implements a RequestDispatcher for a given model node and view. Unlike dispatchers created through @@ -91,8 +91,8 @@ private ScriptRequestDispatcher( @Override public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { - StaplerRequest req = (StaplerRequest) request; - StaplerResponse rsp = (StaplerResponse) response; + StaplerRequest2 req = (StaplerRequest2) request; + StaplerResponse2 rsp = (StaplerResponse2) response; DispatchValidator validator = req.getWebApp().getDispatchValidator(); validator.allowDispatch(req, rsp); try { diff --git a/core/src/main/java/org/kohsuke/stapler/SelectionInterceptedFunction.java b/core/src/main/java/org/kohsuke/stapler/SelectionInterceptedFunction.java index c1426796d..d8c1a6517 100644 --- a/core/src/main/java/org/kohsuke/stapler/SelectionInterceptedFunction.java +++ b/core/src/main/java/org/kohsuke/stapler/SelectionInterceptedFunction.java @@ -1,7 +1,7 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; @@ -21,7 +21,7 @@ } @Override - Object bindAndInvoke(Object o, StaplerRequest req, StaplerResponse rsp, Object... headArgs) + Object bindAndInvoke(Object o, StaplerRequest2 req, StaplerResponse2 rsp, Object... headArgs) throws IllegalAccessException, InvocationTargetException, ServletException { return interceptor.invoke(req, rsp, o, headArgs); } @@ -32,7 +32,7 @@ private static final class Adapter extends ForwardingFunction { } @Override - public Object invoke(StaplerRequest req, StaplerResponse rsp, Object o, Object... args) + public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) throws IllegalAccessException, InvocationTargetException, ServletException { return next.bindAndInvoke(o, req, rsp, args); } diff --git a/core/src/main/java/org/kohsuke/stapler/Stapler.java b/core/src/main/java/org/kohsuke/stapler/Stapler.java index 5cd869a1c..8b12af9da 100644 --- a/core/src/main/java/org/kohsuke/stapler/Stapler.java +++ b/core/src/main/java/org/kohsuke/stapler/Stapler.java @@ -24,6 +24,15 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletConfig; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.DataInputStream; import java.io.EOFException; import java.io.File; @@ -59,15 +68,6 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONObject; import org.apache.commons.beanutils.ConversionException; import org.apache.commons.beanutils.ConvertUtils; @@ -462,7 +462,7 @@ OpenConnection selectResourceByLocale(URL url, Locale locale) throws IOException /** * Serves the specified {@link URLConnection} as a static resource. */ - boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, OpenConnection con, long expiration) + boolean serveStaticResource(HttpServletRequest req, StaplerResponse2 rsp, OpenConnection con, long expiration) throws IOException { if (con == null) { return false; @@ -484,7 +484,7 @@ boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, OpenCon /** * Serves the specified {@link URL} as a static resource. */ - boolean serveStaticResource(HttpServletRequest req, StaplerResponse rsp, URL url, long expiration) + boolean serveStaticResource(HttpServletRequest req, StaplerResponse2 rsp, URL url, long expiration) throws IOException { return serveStaticResource(req, rsp, openURL(url), expiration); } @@ -561,7 +561,7 @@ private static URLConnection openConnection(URL url) throws IOException { */ boolean serveStaticResource( HttpServletRequest req, - StaplerResponse rsp, + StaplerResponse2 rsp, InputStream in, long lastModified, long expiration, @@ -974,7 +974,7 @@ void invoke(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, @SuppressFBWarnings( value = "REQUESTDISPATCHER_FILE_DISCLOSURE", justification = "Forwarding the request to be handled correctly.") - public void forward(RequestDispatcher dispatcher, StaplerRequest req, HttpServletResponse rsp) + public void forward(RequestDispatcher dispatcher, StaplerRequest2 req, HttpServletResponse rsp) throws ServletException, IOException { dispatcher.forward(req, new ResponseImpl(this, rsp)); } @@ -1018,7 +1018,7 @@ public static void setRoot(ServletContextEvent event, Object rootApp) { } /** - * Sets the classloader used by {@link StaplerRequest#bindJSON(Class, JSONObject)} and its sibling methods. + * Sets the classloader used by {@link StaplerRequest2#bindJSON(Class, JSONObject)} and its sibling methods. * * @deprecated * Use {@link WebApp#setClassLoader(ClassLoader)} @@ -1047,19 +1047,37 @@ public ClassLoader getClassLoader() { } /** - * Gets the current {@link StaplerRequest} that the calling thread is associated with. + * Gets the current {@link StaplerRequest2} that the calling thread is associated with. */ - public static StaplerRequest getCurrentRequest() { + public static StaplerRequest2 getCurrentRequest2() { return CURRENT_REQUEST.get(); } /** - * Gets the current {@link StaplerResponse} that the calling thread is associated with. + * @deprecated use {@link #getCurrentRequest2()} */ - public static StaplerResponse getCurrentResponse() { + @Deprecated + public static StaplerRequest getCurrentRequest() { + StaplerRequest2 currentRequest = getCurrentRequest2(); + return currentRequest != null ? StaplerRequest.fromStaplerRequest2(currentRequest) : null; + } + + /** + * Gets the current {@link StaplerResponse2} that the calling thread is associated with. + */ + public static StaplerResponse2 getCurrentResponse2() { return CURRENT_RESPONSE.get(); } + /** + * @deprecated use {@link #getCurrentResponse2()} + */ + @Deprecated + public static StaplerResponse getCurrentResponse() { + StaplerResponse2 currentResponse = getCurrentResponse2(); + return currentResponse != null ? StaplerResponse.fromStaplerResponse2(currentResponse) : null; + } + /** * Gets the current {@link Stapler} that the calling thread is associated with. */ @@ -1133,7 +1151,7 @@ static String canonicalPath(String path) { /** * This is the {@link Converter} registry that Stapler uses, primarily - * for form-to-JSON binding in {@link StaplerRequest#bindJSON(Class, JSONObject)} + * for form-to-JSON binding in {@link StaplerRequest2#bindJSON(Class, JSONObject)} * and its family of methods. */ public static final ConvertUtilsBean CONVERT_UTILS = new ConvertUtilsBean(); @@ -1221,7 +1239,7 @@ public FileItem convert(Class type, Object value) { return null; } try { - return Stapler.getCurrentRequest().getFileItem2(value.toString()); + return Stapler.getCurrentRequest2().getFileItem2(value.toString()); } catch (ServletException | IOException e) { throw new ConversionException(e); } @@ -1238,7 +1256,7 @@ public org.apache.commons.fileupload.FileItem convert(Class type, Object value) } try { return org.apache.commons.fileupload.FileItem.fromFileUpload2FileItem( - Stapler.getCurrentRequest().getFileItem2(value.toString())); + Stapler.getCurrentRequest2().getFileItem2(value.toString())); } catch (ServletException | IOException e) { throw new ConversionException(e); } diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java index 448627d1b..0c0ea358b 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest.java @@ -23,17 +23,53 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.AsyncContextWrapper; +import io.jenkins.servlet.DispatcherTypeWrapper; +import io.jenkins.servlet.RequestDispatcherWrapper; +import io.jenkins.servlet.ServletContextWrapper; +import io.jenkins.servlet.ServletExceptionWrapper; +import io.jenkins.servlet.ServletInputStreamWrapper; +import io.jenkins.servlet.ServletRequestWrapper; +import io.jenkins.servlet.ServletResponseWrapper; +import io.jenkins.servlet.http.CookieWrapper; +import io.jenkins.servlet.http.HttpServletMappingWrapper; +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; +import io.jenkins.servlet.http.HttpSessionWrapper; +import io.jenkins.servlet.http.PartWrapper; +import java.io.BufferedReader; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; +import java.security.Principal; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; import java.util.Date; +import java.util.Enumeration; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpUpgradeHandler; +import javax.servlet.http.Part; +import javax.servlet.http.PushBuilder; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.apache.commons.beanutils.BeanUtils; @@ -48,7 +84,9 @@ * * @see Stapler#getCurrentRequest() * @author Kohsuke Kawaguchi + * @deprecated use {@link StaplerRequest2} */ +@Deprecated public interface StaplerRequest extends HttpServletRequest { /** * Gets the {@link Stapler} instance that this belongs to. @@ -553,4 +591,1329 @@ public String getUrlNames() { * {@code makeStaplerProxy}. */ RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported); + + static StaplerRequest2 toStaplerRequest2(StaplerRequest from) { + if (from instanceof StaplerRequestWrapper javax) { + return javax.toStaplerRequest2(); + } + return new StaplerRequest2WrapperImpl(from); + } + + static StaplerRequest fromStaplerRequest2(StaplerRequest2 from) { + if (from instanceof StaplerRequest2Wrapper jakarta) { + return jakarta.toStaplerRequest(); + } + return new StaplerRequestWrapperImpl(from); + } + + interface StaplerRequest2Wrapper { + org.kohsuke.stapler.StaplerRequest toStaplerRequest(); + } + + class StaplerRequest2WrapperImpl + implements StaplerRequest2, + ServletRequestWrapper.JakartaServletRequestWrapper, + HttpServletRequestWrapper.JakartaHttpServletRequestWrapper, + StaplerRequest2Wrapper { + private final StaplerRequest from; + + public StaplerRequest2WrapperImpl(StaplerRequest from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.toJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public jakarta.servlet.RequestDispatcher getRequestDispatcher(String path) { + RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.toJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public Stapler getStapler() { + return from.getStapler(); + } + + @Override + public WebApp getWebApp() { + return from.getWebApp(); + } + + @Override + public String getRestOfPath() { + return from.getRestOfPath(); + } + + @Override + public String getOriginalRestOfPath() { + return from.getOriginalRestOfPath(); + } + + @Override + public jakarta.servlet.ServletContext getServletContext() { + return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); + } + + @Override + public String getRequestURIWithQueryString() { + return from.getRequestURIWithQueryString(); + } + + @Override + public StringBuffer getRequestURLWithQueryString() { + return from.getRequestURLWithQueryString(); + } + + @Override + public jakarta.servlet.RequestDispatcher getView(Object it, String viewName) throws IOException { + RequestDispatcher view = from.getView(it, viewName); + return view != null ? RequestDispatcherWrapper.toJakartaRequestDispatcher(view) : null; + } + + @Override + public jakarta.servlet.RequestDispatcher getView(Class clazz, String viewName) throws IOException { + RequestDispatcher view = from.getView(clazz, viewName); + return view != null ? RequestDispatcherWrapper.toJakartaRequestDispatcher(view) : null; + } + + @Override + public jakarta.servlet.RequestDispatcher getView(Klass clazz, String viewName) throws IOException { + RequestDispatcher view = from.getView(clazz, viewName); + return view != null ? RequestDispatcherWrapper.toJakartaRequestDispatcher(view) : null; + } + + @Override + public String getRootPath() { + return from.getRootPath(); + } + + @Override + public String getReferer() { + return from.getReferer(); + } + + @Override + public List getAncestors() { + return from.getAncestors(); + } + + @Override + public Ancestor findAncestor(Class type) { + return from.findAncestor(type); + } + + @Override + public T findAncestorObject(Class type) { + return from.findAncestorObject(type); + } + + @Override + public Ancestor findAncestor(Object o) { + return from.findAncestor(o); + } + + @Override + public boolean hasParameter(String name) { + return from.hasParameter(name); + } + + @Override + public String getOriginalRequestURI() { + return from.getOriginalRequestURI(); + } + + @Override + public boolean checkIfModified(long timestampOfResource, StaplerResponse2 rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.fromStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(Date timestampOfResource, StaplerResponse2 rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.fromStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(Calendar timestampOfResource, StaplerResponse2 rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.fromStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(long timestampOfResource, StaplerResponse2 rsp, long expiration) { + return from.checkIfModified(timestampOfResource, StaplerResponse.fromStaplerResponse2(rsp)); + } + + @Override + public void bindParameters(Object bean) { + from.bindParameters(bean); + } + + @Override + public void bindParameters(Object bean, String prefix) { + from.bindParameters(bean, prefix); + } + + @Override + public List bindParametersToList(Class type, String prefix) { + return from.bindParametersToList(type, prefix); + } + + @Override + public T bindParameters(Class type, String prefix) { + return from.bindParameters(type, prefix); + } + + @Override + public T bindParameters(Class type, String prefix, int index) { + return from.bindParameters(type, prefix, index); + } + + @Override + public T bindJSON(Class type, JSONObject src) { + return from.bindJSON(type, src); + } + + @Override + public T bindJSON(Type genericType, Class erasure, Object json) { + return from.bindJSON(genericType, erasure, json); + } + + @Override + public void bindJSON(Object bean, JSONObject src) { + from.bindJSON(bean, src); + } + + @Override + public List bindJSONToList(Class type, Object src) { + return from.bindJSONToList(type, src); + } + + @Override + public BindInterceptor getBindInterceptor() { + return from.getBindInterceptor(); + } + + @Override + public BindInterceptor setBindListener(BindInterceptor bindListener) { + return from.setBindListener(bindListener); + } + + @Override + public BindInterceptor setBindInterceptpr(BindInterceptor bindListener) { + return from.setBindInterceptpr(bindListener); + } + + @Override + public BindInterceptor setBindInterceptor(BindInterceptor bindListener) { + return from.setBindInterceptor(bindListener); + } + + @Override + public JSONObject getSubmittedForm() throws jakarta.servlet.ServletException { + try { + return from.getSubmittedForm(); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public FileItem getFileItem2(String name) throws jakarta.servlet.ServletException, IOException { + try { + return from.getFileItem2(name); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public org.apache.commons.fileupload.FileItem getFileItem(String name) + throws jakarta.servlet.ServletException, IOException { + try { + return from.getFileItem(name); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public boolean isJavaScriptProxyCall() { + return from.isJavaScriptProxyCall(); + } + + @Override + public BoundObjectTable getBoundObjectTable() { + return from.getBoundObjectTable(); + } + + @Override + public String createJavaScriptProxy(Object toBeExported) { + return from.createJavaScriptProxy(toBeExported); + } + + @Override + public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { + StaplerRequest.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); + return new RenderOnDemandParameters(result.proxyMethod, result.url, result.crumb, result.urlNames); + } + + @Override + public jakarta.servlet.AsyncContext startAsync() { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync()); + } + + @Override + public jakarta.servlet.AsyncContext startAsync( + jakarta.servlet.ServletRequest servletRequest, jakarta.servlet.ServletResponse servletResponse) { + return AsyncContextWrapper.toJakartaAsyncContext(from.startAsync( + ServletRequestWrapper.fromJakartaServletRequest(servletRequest), + ServletResponseWrapper.fromJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public jakarta.servlet.AsyncContext getAsyncContext() { + return AsyncContextWrapper.toJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public jakarta.servlet.DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.toJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public String getAuthType() { + return from.getAuthType(); + } + + @Override + public jakarta.servlet.http.Cookie[] getCookies() { + Cookie[] cookies = from.getCookies(); + if (cookies == null) { + return null; + } + return Stream.of(cookies) + .map(CookieWrapper::toJakartaServletHttpCookie) + .toArray(jakarta.servlet.http.Cookie[]::new); + } + + @Override + public long getDateHeader(String name) { + return from.getDateHeader(name); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Enumeration getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Enumeration getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public int getIntHeader(String name) { + return from.getIntHeader(name); + } + + @Override + public jakarta.servlet.http.HttpServletMapping getHttpServletMapping() { + return HttpServletMappingWrapper.toJakartaHttpServletMapping(from.getHttpServletMapping()); + } + + @Override + public String getMethod() { + return from.getMethod(); + } + + @Override + public String getPathInfo() { + return from.getPathInfo(); + } + + @Override + public String getPathTranslated() { + return from.getPathTranslated(); + } + + @Override + public jakarta.servlet.http.PushBuilder newPushBuilder() { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public String getQueryString() { + return from.getQueryString(); + } + + @Override + public String getRemoteUser() { + return from.getRemoteUser(); + } + + @Override + public boolean isUserInRole(String role) { + return from.isUserInRole(role); + } + + @Override + public Principal getUserPrincipal() { + return from.getUserPrincipal(); + } + + @Override + public String getRequestedSessionId() { + return from.getRequestedSessionId(); + } + + @Override + public String getRequestURI() { + return from.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return from.getRequestURL(); + } + + @Override + public String getServletPath() { + return from.getServletPath(); + } + + @Override + public jakarta.servlet.http.HttpSession getSession(boolean create) { + HttpSession session = from.getSession(create); + return session != null ? HttpSessionWrapper.toJakartaHttpSession(session) : null; + } + + @Override + public jakarta.servlet.http.HttpSession getSession() { + HttpSession session = from.getSession(); + return session != null ? HttpSessionWrapper.toJakartaHttpSession(session) : null; + } + + @Override + public String changeSessionId() { + return from.changeSessionId(); + } + + @Override + public boolean isRequestedSessionIdValid() { + return from.isRequestedSessionIdValid(); + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return from.isRequestedSessionIdFromCookie(); + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return from.isRequestedSessionIdFromURL(); + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return from.isRequestedSessionIdFromUrl(); + } + + @Override + public boolean authenticate(jakarta.servlet.http.HttpServletResponse response) + throws IOException, jakarta.servlet.ServletException { + try { + return from.authenticate(HttpServletResponseWrapper.fromJakartaHttpServletResponse(response)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void login(String username, String password) throws jakarta.servlet.ServletException { + try { + from.login(username, password); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void logout() throws jakarta.servlet.ServletException { + try { + from.logout(); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public Collection getParts() throws IOException, jakarta.servlet.ServletException { + try { + return from.getParts().stream() + .map(PartWrapper::toJakartaPart) + .collect(Collectors.toCollection(ArrayList::new)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public jakarta.servlet.http.Part getPart(String name) throws IOException, jakarta.servlet.ServletException { + try { + return PartWrapper.toJakartaPart(from.getPart(name)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public T upgrade(Class handlerClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public Map getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public boolean isTrailerFieldsReady() { + return from.isTrailerFieldsReady(); + } + + @Override + public ServletRequest toJavaxServletRequest() { + return from; + } + + @Override + public HttpServletRequest toJavaxHttpServletRequest() { + return from; + } + + @Override + public StaplerRequest toStaplerRequest() { + return from; + } + } + + interface StaplerRequestWrapper { + StaplerRequest2 toStaplerRequest2(); + } + + class StaplerRequestWrapperImpl + implements StaplerRequest, + ServletRequestWrapper.JavaxServletRequestWrapper, + HttpServletRequestWrapper.JavaxHttpServletRequestWrapper, + StaplerRequestWrapper { + private final StaplerRequest2 from; + + public StaplerRequestWrapperImpl(StaplerRequest2 from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public Object getAttribute(String name) { + return from.getAttribute(name); + } + + @Override + public Enumeration getAttributeNames() { + return from.getAttributeNames(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public void setCharacterEncoding(String env) throws UnsupportedEncodingException { + from.setCharacterEncoding(env); + } + + @Override + public int getContentLength() { + return from.getContentLength(); + } + + @Override + public long getContentLengthLong() { + return from.getContentLengthLong(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return ServletInputStreamWrapper.fromJakartaServletInputStream(from.getInputStream()); + } + + @Override + public String getParameter(String name) { + return from.getParameter(name); + } + + @Override + public Enumeration getParameterNames() { + return from.getParameterNames(); + } + + @Override + public String[] getParameterValues(String name) { + return from.getParameterValues(name); + } + + @Override + public Map getParameterMap() { + return from.getParameterMap(); + } + + @Override + public String getProtocol() { + return from.getProtocol(); + } + + @Override + public String getScheme() { + return from.getScheme(); + } + + @Override + public String getServerName() { + return from.getServerName(); + } + + @Override + public int getServerPort() { + return from.getServerPort(); + } + + @Override + public BufferedReader getReader() throws IOException { + return from.getReader(); + } + + @Override + public String getRemoteAddr() { + return from.getRemoteAddr(); + } + + @Override + public String getRemoteHost() { + return from.getRemoteHost(); + } + + @Override + public void setAttribute(String name, Object o) { + from.setAttribute(name, o); + } + + @Override + public void removeAttribute(String name) { + from.removeAttribute(name); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public Enumeration getLocales() { + return from.getLocales(); + } + + @Override + public boolean isSecure() { + return from.isSecure(); + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + jakarta.servlet.RequestDispatcher requestDispatcher = from.getRequestDispatcher(path); + return requestDispatcher != null + ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(requestDispatcher) + : null; + } + + @Override + public String getRealPath(String path) { + return from.getRealPath(path); + } + + @Override + public int getRemotePort() { + return from.getRemotePort(); + } + + @Override + public String getLocalName() { + return from.getLocalName(); + } + + @Override + public String getLocalAddr() { + return from.getLocalAddr(); + } + + @Override + public int getLocalPort() { + return from.getLocalPort(); + } + + @Override + public Stapler getStapler() { + return from.getStapler(); + } + + @Override + public WebApp getWebApp() { + return from.getWebApp(); + } + + @Override + public String getRestOfPath() { + return from.getRestOfPath(); + } + + @Override + public String getOriginalRestOfPath() { + return from.getOriginalRestOfPath(); + } + + @Override + public ServletContext getServletContext() { + return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); + } + + @Override + public String getRequestURIWithQueryString() { + return from.getRequestURIWithQueryString(); + } + + @Override + public StringBuffer getRequestURLWithQueryString() { + return from.getRequestURLWithQueryString(); + } + + @Override + public RequestDispatcher getView(Object it, String viewName) throws IOException { + jakarta.servlet.RequestDispatcher view = from.getView(it, viewName); + return view != null ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(view) : null; + } + + @Override + public RequestDispatcher getView(Class clazz, String viewName) throws IOException { + jakarta.servlet.RequestDispatcher view = from.getView(clazz, viewName); + return view != null ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(view) : null; + } + + @Override + public RequestDispatcher getView(Klass clazz, String viewName) throws IOException { + jakarta.servlet.RequestDispatcher view = from.getView(clazz, viewName); + return view != null ? RequestDispatcherWrapper.fromJakartaRequestDispatcher(view) : null; + } + + @Override + public String getRootPath() { + return from.getRootPath(); + } + + @Override + public String getReferer() { + return from.getReferer(); + } + + @Override + public List getAncestors() { + return from.getAncestors(); + } + + @Override + public Ancestor findAncestor(Class type) { + return from.findAncestor(type); + } + + @Override + public T findAncestorObject(Class type) { + return from.findAncestorObject(type); + } + + @Override + public Ancestor findAncestor(Object o) { + return from.findAncestor(o); + } + + @Override + public boolean hasParameter(String name) { + return from.hasParameter(name); + } + + @Override + public String getOriginalRequestURI() { + return from.getOriginalRequestURI(); + } + + @Override + public boolean checkIfModified(long timestampOfResource, StaplerResponse rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.toStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(Date timestampOfResource, StaplerResponse rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.toStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(Calendar timestampOfResource, StaplerResponse rsp) { + return from.checkIfModified(timestampOfResource, StaplerResponse.toStaplerResponse2(rsp)); + } + + @Override + public boolean checkIfModified(long timestampOfResource, StaplerResponse rsp, long expiration) { + return from.checkIfModified(timestampOfResource, StaplerResponse.toStaplerResponse2(rsp), expiration); + } + + @Override + public void bindParameters(Object bean) { + from.bindParameters(bean); + } + + @Override + public void bindParameters(Object bean, String prefix) { + from.bindParameters(bean, prefix); + } + + @Override + public List bindParametersToList(Class type, String prefix) { + return from.bindParametersToList(type, prefix); + } + + @Override + public T bindParameters(Class type, String prefix) { + return from.bindParameters(type, prefix); + } + + @Override + public T bindParameters(Class type, String prefix, int index) { + return from.bindParameters(type, prefix, index); + } + + @Override + public T bindJSON(Class type, JSONObject src) { + return from.bindJSON(type, src); + } + + @Override + public T bindJSON(Type genericType, Class erasure, Object json) { + return from.bindJSON(genericType, erasure, json); + } + + @Override + public void bindJSON(Object bean, JSONObject src) { + from.bindJSON(bean, src); + } + + @Override + public List bindJSONToList(Class type, Object src) { + return from.bindJSONToList(type, src); + } + + @Override + public BindInterceptor getBindInterceptor() { + return from.getBindInterceptor(); + } + + @Override + public BindInterceptor setBindListener(BindInterceptor bindListener) { + return from.setBindListener(bindListener); + } + + @Override + public BindInterceptor setBindInterceptpr(BindInterceptor bindListener) { + return from.setBindInterceptpr(bindListener); + } + + @Override + public BindInterceptor setBindInterceptor(BindInterceptor bindListener) { + return from.setBindInterceptor(bindListener); + } + + @Override + public JSONObject getSubmittedForm() throws ServletException { + try { + return from.getSubmittedForm(); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public FileItem getFileItem2(String name) throws ServletException, IOException { + try { + return from.getFileItem2(name); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public org.apache.commons.fileupload.FileItem getFileItem(String name) throws ServletException, IOException { + try { + return from.getFileItem(name); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public boolean isJavaScriptProxyCall() { + return from.isJavaScriptProxyCall(); + } + + @Override + public BoundObjectTable getBoundObjectTable() { + return from.getBoundObjectTable(); + } + + @Override + public String createJavaScriptProxy(Object toBeExported) { + return from.createJavaScriptProxy(toBeExported); + } + + @Override + public RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported) { + StaplerRequest2.RenderOnDemandParameters result = from.createJavaScriptProxyParameters(toBeExported); + return new RenderOnDemandParameters(result.proxyMethod, result.crumb, result.url, result.urlNames); + } + + @Override + public AsyncContext startAsync() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync()); + } + + @Override + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) { + return AsyncContextWrapper.fromJakartaAsyncContext(from.startAsync( + ServletRequestWrapper.toJakartaServletRequest(servletRequest), + ServletResponseWrapper.toJakartaServletResponse(servletResponse))); + } + + @Override + public boolean isAsyncStarted() { + return from.isAsyncStarted(); + } + + @Override + public boolean isAsyncSupported() { + return from.isAsyncSupported(); + } + + @Override + public AsyncContext getAsyncContext() { + return AsyncContextWrapper.fromJakartaAsyncContext(from.getAsyncContext()); + } + + @Override + public DispatcherType getDispatcherType() { + return DispatcherTypeWrapper.fromJakartaDispatcherType(from.getDispatcherType()); + } + + @Override + public String getAuthType() { + return from.getAuthType(); + } + + @Override + public Cookie[] getCookies() { + jakarta.servlet.http.Cookie[] cookies = from.getCookies(); + if (cookies == null) { + return null; + } + return Stream.of(cookies) + .map(CookieWrapper::fromJakartaServletHttpCookie) + .toArray(Cookie[]::new); + } + + @Override + public long getDateHeader(String name) { + return from.getDateHeader(name); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Enumeration getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Enumeration getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public int getIntHeader(String name) { + return from.getIntHeader(name); + } + + @Override + public HttpServletMapping getHttpServletMapping() { + return HttpServletMappingWrapper.fromJakartaHttpServletMapping(from.getHttpServletMapping()); + } + + @Override + public String getMethod() { + return from.getMethod(); + } + + @Override + public String getPathInfo() { + return from.getPathInfo(); + } + + @Override + public String getPathTranslated() { + return from.getPathTranslated(); + } + + @Override + public PushBuilder newPushBuilder() { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public String getContextPath() { + return from.getContextPath(); + } + + @Override + public String getQueryString() { + return from.getQueryString(); + } + + @Override + public String getRemoteUser() { + return from.getRemoteUser(); + } + + @Override + public boolean isUserInRole(String role) { + return from.isUserInRole(role); + } + + @Override + public Principal getUserPrincipal() { + return from.getUserPrincipal(); + } + + @Override + public String getRequestedSessionId() { + return from.getRequestedSessionId(); + } + + @Override + public String getRequestURI() { + return from.getRequestURI(); + } + + @Override + public StringBuffer getRequestURL() { + return from.getRequestURL(); + } + + @Override + public String getServletPath() { + return from.getServletPath(); + } + + @Override + public HttpSession getSession(boolean create) { + jakarta.servlet.http.HttpSession session = from.getSession(create); + return session != null ? HttpSessionWrapper.fromJakartaHttpSession(session) : null; + } + + @Override + public HttpSession getSession() { + jakarta.servlet.http.HttpSession session = from.getSession(); + return session != null ? HttpSessionWrapper.fromJakartaHttpSession(session) : null; + } + + @Override + public String changeSessionId() { + return from.changeSessionId(); + } + + @Override + public boolean isRequestedSessionIdValid() { + return from.isRequestedSessionIdValid(); + } + + @Override + public boolean isRequestedSessionIdFromCookie() { + return from.isRequestedSessionIdFromCookie(); + } + + @Override + public boolean isRequestedSessionIdFromURL() { + return from.isRequestedSessionIdFromURL(); + } + + @Override + public boolean isRequestedSessionIdFromUrl() { + return from.isRequestedSessionIdFromUrl(); + } + + @Override + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { + try { + return from.authenticate(HttpServletResponseWrapper.toJakartaHttpServletResponse(response)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void login(String username, String password) throws ServletException { + try { + from.login(username, password); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void logout() throws ServletException { + try { + from.logout(); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public Collection getParts() throws IOException, ServletException { + try { + return from.getParts().stream() + .map(PartWrapper::fromJakartaPart) + .collect(Collectors.toCollection(ArrayList::new)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public Part getPart(String name) throws IOException, ServletException { + try { + return PartWrapper.fromJakartaPart(from.getPart(name)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public T upgrade(Class handlerClass) { + // TODO implement this + throw new UnsupportedOperationException(); + } + + @Override + public Map getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public boolean isTrailerFieldsReady() { + return from.isTrailerFieldsReady(); + } + + @Override + public jakarta.servlet.ServletRequest toJakartaServletRequest() { + return from; + } + + @Override + public jakarta.servlet.http.HttpServletRequest toJakartaHttpServletRequest() { + return from; + } + + @Override + public StaplerRequest2 toStaplerRequest2() { + return from; + } + } } diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java new file mode 100644 index 000000000..91b4eb996 --- /dev/null +++ b/core/src/main/java/org/kohsuke/stapler/StaplerRequest2.java @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2004-2010, Kohsuke Kawaguchi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.kohsuke.stapler; + +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Set; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.beanutils.ConvertUtils; +import org.apache.commons.fileupload2.core.FileItem; +import org.kohsuke.stapler.bind.BoundObjectTable; +import org.kohsuke.stapler.json.SubmittedForm; +import org.kohsuke.stapler.lang.Klass; + +/** + * Defines additional parameters/operations made available by Stapler. + * + * @see Stapler#getCurrentRequest2() + * @author Kohsuke Kawaguchi + */ +public interface StaplerRequest2 extends HttpServletRequest { + /** + * Gets the {@link Stapler} instance that this belongs to. + */ + Stapler getStapler(); + + /** + * Short for {@code getStapler().getWebApp()} + */ + WebApp getWebApp(); + + /** + * Returns the additional URL portion that wasn't used by the stapler, + * excluding the query string. + * + *

+ * For example, if the requested URL is "foo/bar/zot/abc?def=ghi" and + * "foo/bar" portion matched {@code bar.jsp}, this method returns + * "/zot/abc". + * + *

+ * If this method is invoked from getters or {@link StaplerProxy#getTarget()} + * during the object traversal, this method returns the path portion + * that is not yet processed. + * + * @return + * can be empty string, but never null. + */ + String getRestOfPath(); + + /** + * Returns the same thing as {@link #getRestOfPath()} but in the pre-decoded form, + * so all "%HH"s as present in the request URL is intact. + */ + String getOriginalRestOfPath(); + + /** + * Returns the {@link ServletContext} object given to the stapler + * dispatcher servlet. + */ + @Override + ServletContext getServletContext(); + + /** + * {@link #getRequestURI()} plus additional query string part, if it exists. + */ + String getRequestURIWithQueryString(); + + /** + * {@link #getRequestURL()} plus additional query string part, if it exists. + */ + StringBuffer getRequestURLWithQueryString(); + + /** + * Gets the {@link RequestDispatcher} that represents a specific view + * for the given object. + * + * This support both JSP and Jelly. + * + * @param viewName + * If this name is relative name like "foo.jsp" or "bar/zot.jelly", + * then the corresponding "side file" is searched by this name. + *

+ * For Jelly, this also accepts absolute path name that starts + * with '/', such as "/foo/bar/zot.jelly". In this case, + * {@code it.getClass().getClassLoader()} is searched for this script. + * + * @return null + * if neither JSP nor Jelly is not found by the given name. + */ + RequestDispatcher getView(Object it, String viewName) throws IOException; + + /** + * Convenience method to call {@link #getView(Klass, String)} with {@link Class}. + */ + RequestDispatcher getView(Class clazz, String viewName) throws IOException; + + /** + * Gets the {@link RequestDispatcher} that represents a specific view + * for the given class. + * + *

+ * Unlike {@link #getView(Object, String)}, calling this request dispatcher + * doesn't set the "it" variable, so + * {@code getView(it.getClass(),viewName)} and {@code getView(it,viewName)} + * aren't the same thing. + */ + RequestDispatcher getView(Klass clazz, String viewName) throws IOException; + + /** + * Gets the part of the request URL from protocol up to the context path. + * So typically it's something like {@code http://foobar:8080/something} + */ + String getRootPath(); + + /** + * Gets the referer header (like "http://foobar.com/zot") or null. + * + * This is just a convenience method. + */ + String getReferer(); + + /** + * Returns a list of ancestor objects that lead to the "it" object. + * The returned list contains {@link Ancestor} objects sorted in the + * order from root to the "it" object. + * + *

+ * For example, if the URL was "foo/bar/zot" and the "it" object + * was determined as root.getFoo().getBar("zot"), + * then this list will contain the following 3 objects in this order: + *

    + *
  1. the root object + *
  2. root.getFoo() object + *
  3. root.getFoo().getBar("zot") object (the "it" object) + *
+ *

+ * + * + * @return + * list of {@link Ancestor}s. Can be empty, but always non-null. + */ + List getAncestors(); + + /** + * Finds the nearest ancestor that has the object of the given type, or null if not found. + */ + Ancestor findAncestor(Class type); + + /** + * Short for {@code findAncestor(type).getObject()}, with proper handling for null de-reference. + * This version is also type safe. + */ + T findAncestorObject(Class type); + + /** + * Finds the nearest ancestor whose {@link Ancestor#getObject()} matches the given object. + */ + Ancestor findAncestor(Object o); + + /** + * Short for {@code getParameter(name)!=null} + */ + boolean hasParameter(String name); + + /** + * Gets the {@link HttpServletRequest#getRequestURI() request URI} + * of the original request, so that you can access the value even from + * JSP. + */ + String getOriginalRequestURI(); + + /** + * Checks "If-Modified-Since" header and returns false + * if the resource needs to be served. + * + *

+ * This method can behave in three ways. + * + *

    + *
  1. If {@code timestampOfResource} is 0 or negative, + * this method just returns false. + * + *
  2. If "If-Modified-Since" header is sent and if it's bigger than + * {@code timestampOfResource}, then this method sets + * {@link HttpServletResponse#SC_NOT_MODIFIED} as the response code + * and returns true. + * + *
  3. Otherwise, "Last-Modified" header is added with {@code timestampOfResource} value, + * and this method returns false. + *
+ * + *

+ * This method sends out the "Expires" header to force browser + * to re-validate all the time. + * + * @param timestampOfResource + * The time stamp of the resource. + * @param rsp + * This object is updated accordingly to simplify processing. + * + * @return + * false to indicate that the caller has to serve the actual resource. + * true to indicate that the caller should just quit processing right there + * (and send back {@link HttpServletResponse#SC_NOT_MODIFIED}. + */ + boolean checkIfModified(long timestampOfResource, StaplerResponse2 rsp); + + /** + * @see #checkIfModified(long, StaplerResponse2) + */ + boolean checkIfModified(Date timestampOfResource, StaplerResponse2 rsp); + + /** + * @see #checkIfModified(long, StaplerResponse2) + */ + boolean checkIfModified(Calendar timestampOfResource, StaplerResponse2 rsp); + + /** + * @param expiration + * The number of milliseconds until the resource will "expire". + * Until it expires the browser will be allowed to cache it + * and serve it without checking back with the server. + * After it expires, the client will send conditional GET to + * check if the resource is actually modified or not. + * If 0, it will immediately expire. + * + * @see #checkIfModified(long, StaplerResponse2) + */ + boolean checkIfModified(long timestampOfResource, StaplerResponse2 rsp, long expiration); + + /** + * Binds form parameters to a bean by using introspection. + * + * For example, if there's a parameter called 'foo' that has value 'abc', + * then {@code bean.setFoo('abc')} will be invoked. This will be repeated + * for all parameters. Parameters that do not have corresponding setters will + * be simply ignored. + * + *

+ * Values are converted into the right type. See {@link ConvertUtils#convert(String, Class)}. + * + * @see BeanUtils#setProperty(Object, String, Object) + * + * @param bean + * The object which will be filled out. + */ + void bindParameters(Object bean); + + /** + * Binds form parameters to a bean by using introspection. + * + * This method works like {@link #bindParameters(Object)}, but it performs a + * pre-processing on property names. Namely, only property names that start + * with the given prefix will be used for binding, and only the portion of the + * property name after the prefix is used. + * + * So for example, if the prefix is "foo.", then property name "foo.bar" with value + * "zot" will invoke {@code bean.setBar("zot")}. + * + * + * @deprecated + * Instead of using prefix to group object among form parameter names, + * use structured form submission and {@link #bindJSON(Class, JSONObject)}. + */ + @Deprecated + void bindParameters(Object bean, String prefix); + + /** + * Binds collection form parameters to beans by using introspection or + * constructor parameters injection. + * + *

+ * This method works like {@link #bindParameters(Object,String)} and + * {@link #bindParameters(Class, String)}, but it assumes + * that form parameters have multiple-values, and use individual values to + * fill in multiple beans. + * + *

+ * For example, if {@code getParameterValues("foo")=={"abc","def"}} + * and {@code getParameterValues("bar")=={"5","3"}}, then this method will + * return two objects (the first with "abc" and "5", the second with + * "def" and "3".) + * + * @param type + * Type of the bean to be created. This class must have the default no-arg + * constructor. + * + * @param prefix + * See {@link #bindParameters(Object, String)} for details. + * + * @return + * Can be empty but never null. + * + * + * @deprecated + * Instead of using prefix to group object among form parameter names, + * use structured form submission and {@link #bindJSON(Class, JSONObject)}. + */ + @Deprecated + List bindParametersToList(Class type, String prefix); + + /** + * Instantiates a new object by injecting constructor parameters from the form parameters. + * + *

+ * The given class must have a constructor annotated with '@stapler-constructor', + * and must be processed by the maven-stapler-plugin, so that the parameter names + * of the constructor is available at runtime. + * + *

+ * The prefix is used to control the form parameter name. For example, + * if the prefix is "foo." and if the constructor is define as + * Foo(String a, String b), then the constructor will be invoked + * as new Foo(getParameter("foo.a"),getParameter("foo.b")). + * + * @deprecated + * Instead of using prefix to group object among form parameter names, + * use structured form submission and {@link #bindJSON(Class, JSONObject)}. + */ + @Deprecated + T bindParameters(Class type, String prefix); + + /** + * Works like {@link #bindParameters(Class, String)} but uses n-th value + * of all the parameters. + * + *

+ * This is useful for creating multiple instances from repeated form fields. + * + * + * @deprecated + * Instead of using prefix to group object among form parameter names, + * use structured form submission and {@link #bindJSON(Class, JSONObject)}. + */ + @Deprecated + T bindParameters(Class type, String prefix, int index); + + /** + * Data-bind from a {@link JSONObject} to the given target type, + * by using introspection or constructor parameters injection. + * + *

+ * For example, if you have a constructor that looks like the following: + * + *

+     * class Foo {
+     *   @{@link DataBoundConstructor}
+     *   public Foo(Integer x, String y, boolean z, Bar bar) { ... }
+     * }
+     *
+     * class Bar {
+     *   @{@link DataBoundConstructor}
+     *   public Bar(int x, int y) {}
+     * }
+     * 
+ * + * ... and if JSONObject looks like + * + *
{ y:"text", z:true, bar:{x:1,y:2}}
+ * + * then, this method returns + * + *
new Foo(null,"text",true,new Bar(1,2))
+ * + *

Sub-typing: In the above example, + * a new instance of {@code Bar} was created, + * but you can also create a subtype of Bar by having the '$class' property in + * JSON like this: + * + *

+     * class BarEx extends Bar {
+     *   @{@link DataBoundConstructor}
+     *   public BarEx(int a, int b, int c) {}
+     * }
+     *
+     * { y:"text", z:true, bar: { $class:"p.k.g.BarEx", a:1, b:2, c:3 } }
+     * 
+ * + *

+ * The type that shows up in the constructor ({@code Bar} in this case) + * can be an interface or an abstract class. + */ + T bindJSON(Class type, JSONObject src); + + /** + * Data-bind from one of the JSON object types ({@link JSONObject}, {@link JSONArray}, + * {@link String}, {@link Integer}, and so on) to the expected type given as an argument. + * + * @param genericType + * The generic type of the 'erasure' parameter. + * @param erasure + * The expected type to convert the JSON argument to. + * @param json + * One of the JSON value type. + */ + T bindJSON(Type genericType, Class erasure, Object json); + + /** + * Data-binds from {@link JSONObject} to the given object. + * + *

+ * This method is bit like {@link #bindJSON(Class, JSONObject)}, except that this method + * populates an existing object, instead of creating a new instance. + * + *

+ * This method is also bit like {@link #bindParameters(Object, String)}, in that it + * populates an existing object from a form submission, except that this method + * obtains data from {@link JSONObject} thus more structured, whereas {@link #bindParameters(Object, String)} + * uses the map structure of the form submission. + */ + void bindJSON(Object bean, JSONObject src); + + /** + * Data-bind from either {@link JSONObject} or {@link JSONArray} to a list, + * by using {@link #bindJSON(Class, JSONObject)} as the lower-level mechanism. + * + *

+ * If the source is {@link JSONObject}, the returned list will contain + * a single item. If it is {@link JSONArray}, each item will be bound. + * If it is null, then the list will be empty. + */ + List bindJSONToList(Class type, Object src); + + /** + * Gets the {@link BindInterceptor} set for this request. + * + * @see WebApp#bindInterceptors + */ + BindInterceptor getBindInterceptor(); + + /** + * @deprecated + * Typo. Use {@link #setBindInterceptor(BindInterceptor)} + */ + @Deprecated + BindInterceptor setBindListener(BindInterceptor bindListener); + + /** + * @deprecated + * Typo. Use {@link #setBindInterceptor(BindInterceptor)} + */ + @Deprecated + BindInterceptor setBindInterceptpr(BindInterceptor bindListener); + + BindInterceptor setBindInterceptor(BindInterceptor bindListener); + + /** + * Gets the content of the structured form submission. + * + * @see Structured Form Submission + * @see SubmittedForm + */ + JSONObject getSubmittedForm() throws ServletException; + + /** + * Obtains a commons-fileupload2 object that represents an uploaded file. + * + * @return + * null if a file of the given form field name doesn't exist. + * This includes the case where the name corresponds to a simple + * form field (like textbox, checkbox, etc.) + */ + FileItem getFileItem2(String name) throws ServletException, IOException; + + /** + * Obtains a commons-fileupload object that represents an uploaded file. + * + * @return + * null if a file of the given form field name doesn't exist. + * This includes the case where the name corresponds to a simple + * form field (like textbox, checkbox, etc.) + * @deprecated use {@link #getFileItem2(String)} + */ + @Deprecated + org.apache.commons.fileupload.FileItem getFileItem(String name) throws ServletException, IOException; + + /** + * Returns true if this request represents a server method call to a JavaScript proxy object. + */ + boolean isJavaScriptProxyCall(); + + /** + * Short cut for obtaining {@link BoundObjectTable} associated with this webapp. + */ + BoundObjectTable getBoundObjectTable(); + + /** + * Exports the given Java object as a JavaScript proxy and returns a JavaScript expression to create + * a proxy on the client side. + * + * Short cut for {@code getBoundObjectTable().bind(toBeExported).getProxyScript()} + * + * @deprecated Use {@link #createJavaScriptProxyParameters(Object)} and invoke {@code makeStaplerProxy} yourself. + */ + @Deprecated + String createJavaScriptProxy(Object toBeExported); + + /** + * Return value of {@link #createJavaScriptProxyParameters(Object)} + */ + final class RenderOnDemandParameters { + public final String proxyMethod; + public final String url; + public final String crumb; + public final Set urlNames; + + public RenderOnDemandParameters(String proxyMethod, String url, String crumb, Set urlNames) { + this.proxyMethod = proxyMethod; + this.url = url; + this.crumb = crumb; + this.urlNames = urlNames; + } + + public String getUrlNames() { + return String.join(",", urlNames); + } + } + + /** + * Exports the given Java object as a JavaScript proxy and returns the parameters needed to call + * {@code makeStaplerProxy}. + */ + RenderOnDemandParameters createJavaScriptProxyParameters(Object toBeExported); +} diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerResponse.java b/core/src/main/java/org/kohsuke/stapler/StaplerResponse.java index 8282b7c23..37939e6d1 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerResponse.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerResponse.java @@ -24,13 +24,28 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.NonNull; +import io.jenkins.servlet.ServletExceptionWrapper; +import io.jenkins.servlet.ServletOutputStreamWrapper; +import io.jenkins.servlet.ServletResponseWrapper; +import io.jenkins.servlet.http.CookieWrapper; +import io.jenkins.servlet.http.HttpServletRequestWrapper; +import io.jenkins.servlet.http.HttpServletResponseWrapper; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.io.Writer; import java.net.URL; import java.net.URLConnection; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.json.JsonConfig; @@ -45,7 +60,9 @@ * * @see Stapler#getCurrentResponse() * @author Kohsuke Kawaguchi + * @deprecated use {@link StaplerResponse2} */ +@Deprecated public interface StaplerResponse extends HttpServletResponse { /** * Evaluates the url against the given object and @@ -255,4 +272,816 @@ default void serveExposedBean(StaplerRequest req, Object exposedBean, ExportConf * @return the config */ JsonConfig getJsonConfig(); + + static StaplerResponse2 toStaplerResponse2(StaplerResponse from) { + if (from instanceof StaplerResponseWrapper javax) { + return javax.toStaplerResponse2(); + } + return new StaplerResponse2WrapperImpl(from); + } + + static StaplerResponse fromStaplerResponse2(StaplerResponse2 from) { + if (from instanceof StaplerResponse2Wrapper jakarta) { + return jakarta.toStaplerResponse(); + } + return new StaplerResponseWrapperImpl(from); + } + + interface StaplerResponse2Wrapper { + StaplerResponse toStaplerResponse(); + } + + class StaplerResponse2WrapperImpl + implements StaplerResponse2, + ServletResponseWrapper.JakartaServletResponseWrapper, + HttpServletResponseWrapper.JakartaHttpServletResponseWrapper, + StaplerResponse2Wrapper { + private final StaplerResponse from; + + public StaplerResponse2WrapperImpl(StaplerResponse from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public void forward(Object it, String url, StaplerRequest2 request) + throws jakarta.servlet.ServletException, IOException { + try { + from.forward(it, url, StaplerRequest.fromStaplerRequest2(request)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void forwardToPreviousPage(StaplerRequest2 request) + throws jakarta.servlet.ServletException, IOException { + try { + from.forwardToPreviousPage(StaplerRequest.fromStaplerRequest2(request)); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void sendRedirect2(@NonNull String url) throws IOException { + from.sendRedirect2(url); + } + + @Override + public void sendRedirect(int statusCore, @NonNull String url) throws IOException { + from.sendRedirect(statusCore, url); + } + + @Override + public void serveFile(StaplerRequest2 request, URL res) throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile(StaplerRequest.fromStaplerRequest2(request), res); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveFile(StaplerRequest2 request, URL res, long expiration) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile(StaplerRequest.fromStaplerRequest2(request), res, expiration); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveLocalizedFile(StaplerRequest2 request, URL res) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveLocalizedFile(StaplerRequest.fromStaplerRequest2(request), res); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveLocalizedFile(StaplerRequest2 request, URL res, long expiration) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveLocalizedFile(StaplerRequest.fromStaplerRequest2(request), res, expiration); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + long contentLength, + String fileName) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile( + StaplerRequest.fromStaplerRequest2(req), + data, + lastModified, + expiration, + contentLength, + fileName); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + int contentLength, + String fileName) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile( + StaplerRequest.fromStaplerRequest2(req), + data, + lastModified, + expiration, + contentLength, + fileName); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest2 req, InputStream data, long lastModified, long contentLength, String fileName) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile(StaplerRequest.fromStaplerRequest2(req), data, lastModified, contentLength, fileName); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest2 req, InputStream data, long lastModified, int contentLength, String fileName) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveFile(StaplerRequest.fromStaplerRequest2(req), data, lastModified, contentLength, fileName); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, Flavor flavor) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveExposedBean(StaplerRequest.fromStaplerRequest2(req), exposedBean, flavor); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, ExportConfig exportConfig) + throws jakarta.servlet.ServletException, IOException { + try { + from.serveExposedBean(StaplerRequest.fromStaplerRequest2(req), exposedBean, exportConfig); + } catch (ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } + + @Override + public OutputStream getCompressedOutputStream(jakarta.servlet.http.HttpServletRequest req) throws IOException { + return from.getCompressedOutputStream(HttpServletRequestWrapper.fromJakartaHttpServletRequest(req)); + } + + @Override + public Writer getCompressedWriter(jakarta.servlet.http.HttpServletRequest req) throws IOException { + return from.getCompressedWriter(HttpServletRequestWrapper.fromJakartaHttpServletRequest(req)); + } + + @Override + public int reverseProxyTo(URL url, StaplerRequest2 req) throws IOException { + return from.reverseProxyTo(url, StaplerRequest.fromStaplerRequest2(req)); + } + + @Override + public void setJsonConfig(JsonConfig config) { + from.setJsonConfig(config); + } + + @Override + public JsonConfig getJsonConfig() { + return from.getJsonConfig(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public jakarta.servlet.ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.toJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public void addCookie(jakarta.servlet.http.Cookie cookie) { + from.addCookie(CookieWrapper.fromJakartaServletHttpCookie(cookie)); + } + + @Override + public boolean containsHeader(String name) { + return from.containsHeader(name); + } + + @Override + public String encodeURL(String url) { + return from.encodeURL(url); + } + + @Override + public String encodeRedirectURL(String url) { + return from.encodeRedirectURL(url); + } + + @Override + public String encodeUrl(String url) { + return from.encodeUrl(url); + } + + @Override + public String encodeRedirectUrl(String url) { + return from.encodeRedirectUrl(url); + } + + @Override + public void sendError(int sc, String msg) throws IOException { + from.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + from.sendError(sc); + } + + @Override + public void sendRedirect(String location) throws IOException { + from.sendRedirect(location); + } + + @Override + public void setDateHeader(String name, long date) { + from.setDateHeader(name, date); + } + + @Override + public void addDateHeader(String name, long date) { + from.addDateHeader(name, date); + } + + @Override + public void setHeader(String name, String value) { + from.setHeader(name, value); + } + + @Override + public void addHeader(String name, String value) { + from.addHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + from.setIntHeader(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + from.addIntHeader(name, value); + } + + @Override + public void setStatus(int sc) { + from.setStatus(sc); + } + + @Override + public void setStatus(int sc, String sm) { + from.setStatus(sc, sm); + } + + @Override + public int getStatus() { + return from.getStatus(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public void setTrailerFields(Supplier> supplier) { + from.setTrailerFields(supplier); + } + + @Override + public Supplier> getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public ServletResponse toJavaxServletResponse() { + return from; + } + + @Override + public HttpServletResponse toJavaxHttpServletResponse() { + return from; + } + + @Override + public StaplerResponse toStaplerResponse() { + return from; + } + } + + interface StaplerResponseWrapper { + StaplerResponse2 toStaplerResponse2(); + } + + class StaplerResponseWrapperImpl + implements StaplerResponse, + ServletResponseWrapper.JavaxServletResponseWrapper, + HttpServletResponseWrapper.JavaxHttpServletResponseWrapper, + StaplerResponseWrapper { + private final StaplerResponse2 from; + + public StaplerResponseWrapperImpl(StaplerResponse2 from) { + this.from = Objects.requireNonNull(from); + } + + @Override + public void forward(Object it, String url, StaplerRequest request) throws ServletException, IOException { + try { + from.forward(it, url, StaplerRequest.toStaplerRequest2(request)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void forwardToPreviousPage(StaplerRequest request) throws ServletException, IOException { + try { + from.forwardToPreviousPage(StaplerRequest.toStaplerRequest2(request)); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void sendRedirect2(@NonNull String url) throws IOException { + from.sendRedirect2(url); + } + + @Override + public void sendRedirect(int statusCore, @NonNull String url) throws IOException { + from.sendRedirect(statusCore, url); + } + + @Override + public void serveFile(StaplerRequest request, URL res) throws ServletException, IOException { + try { + from.serveFile(StaplerRequest.toStaplerRequest2(request), res); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveFile(StaplerRequest request, URL res, long expiration) throws ServletException, IOException { + try { + from.serveFile(StaplerRequest.toStaplerRequest2(request), res, expiration); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveLocalizedFile(StaplerRequest request, URL res) throws ServletException, IOException { + try { + from.serveLocalizedFile(StaplerRequest.toStaplerRequest2(request), res); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveLocalizedFile(StaplerRequest request, URL res, long expiration) + throws ServletException, IOException { + try { + from.serveLocalizedFile(StaplerRequest.toStaplerRequest2(request), res, expiration); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest req, + InputStream data, + long lastModified, + long expiration, + long contentLength, + String fileName) + throws ServletException, IOException { + try { + from.serveFile( + StaplerRequest.toStaplerRequest2(req), data, lastModified, expiration, contentLength, fileName); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest req, + InputStream data, + long lastModified, + long expiration, + int contentLength, + String fileName) + throws ServletException, IOException { + try { + from.serveFile( + StaplerRequest.toStaplerRequest2(req), data, lastModified, expiration, contentLength, fileName); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest req, InputStream data, long lastModified, long contentLength, String fileName) + throws ServletException, IOException { + try { + from.serveFile(StaplerRequest.toStaplerRequest2(req), data, lastModified, contentLength, fileName); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveFile( + StaplerRequest req, InputStream data, long lastModified, int contentLength, String fileName) + throws ServletException, IOException { + try { + from.serveFile(StaplerRequest.toStaplerRequest2(req), data, lastModified, contentLength, fileName); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveExposedBean(StaplerRequest req, Object exposedBean, Flavor flavor) + throws ServletException, IOException { + try { + from.serveExposedBean(StaplerRequest.toStaplerRequest2(req), exposedBean, flavor); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public void serveExposedBean(StaplerRequest req, Object exposedBean, ExportConfig exportConfig) + throws ServletException, IOException { + try { + from.serveExposedBean(StaplerRequest.toStaplerRequest2(req), exposedBean, exportConfig); + } catch (jakarta.servlet.ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } + + @Override + public OutputStream getCompressedOutputStream(HttpServletRequest req) throws IOException { + return from.getCompressedOutputStream(HttpServletRequestWrapper.toJakartaHttpServletRequest(req)); + } + + @Override + public Writer getCompressedWriter(HttpServletRequest req) throws IOException { + return from.getCompressedWriter(HttpServletRequestWrapper.toJakartaHttpServletRequest(req)); + } + + @Override + public int reverseProxyTo(URL url, StaplerRequest req) throws IOException { + return from.reverseProxyTo(url, StaplerRequest.toStaplerRequest2(req)); + } + + @Override + public void setJsonConfig(JsonConfig config) { + from.setJsonConfig(config); + } + + @Override + public JsonConfig getJsonConfig() { + return from.getJsonConfig(); + } + + @Override + public String getCharacterEncoding() { + return from.getCharacterEncoding(); + } + + @Override + public String getContentType() { + return from.getContentType(); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return ServletOutputStreamWrapper.fromJakartaServletOutputStream(from.getOutputStream()); + } + + @Override + public PrintWriter getWriter() throws IOException { + return from.getWriter(); + } + + @Override + public void setCharacterEncoding(String charset) { + from.setCharacterEncoding(charset); + } + + @Override + public void setContentLength(int len) { + from.setContentLength(len); + } + + @Override + public void setContentLengthLong(long len) { + from.setContentLengthLong(len); + } + + @Override + public void setContentType(String type) { + from.setContentType(type); + } + + @Override + public void setBufferSize(int size) { + from.setBufferSize(size); + } + + @Override + public int getBufferSize() { + return from.getBufferSize(); + } + + @Override + public void flushBuffer() throws IOException { + from.flushBuffer(); + } + + @Override + public void resetBuffer() { + from.resetBuffer(); + } + + @Override + public boolean isCommitted() { + return from.isCommitted(); + } + + @Override + public void reset() { + from.reset(); + } + + @Override + public void setLocale(Locale loc) { + from.setLocale(loc); + } + + @Override + public Locale getLocale() { + return from.getLocale(); + } + + @Override + public void addCookie(Cookie cookie) { + from.addCookie(CookieWrapper.toJakartaServletHttpCookie(cookie)); + } + + @Override + public boolean containsHeader(String name) { + return from.containsHeader(name); + } + + @Override + public String encodeURL(String url) { + return from.encodeURL(url); + } + + @Override + public String encodeRedirectURL(String url) { + return from.encodeRedirectURL(url); + } + + @Override + public String encodeUrl(String url) { + return from.encodeUrl(url); + } + + @Override + public String encodeRedirectUrl(String url) { + return from.encodeRedirectUrl(url); + } + + @Override + public void sendError(int sc, String msg) throws IOException { + from.sendError(sc, msg); + } + + @Override + public void sendError(int sc) throws IOException { + from.sendError(sc); + } + + @Override + public void sendRedirect(String location) throws IOException { + from.sendRedirect(location); + } + + @Override + public void setDateHeader(String name, long date) { + from.setDateHeader(name, date); + } + + @Override + public void addDateHeader(String name, long date) { + from.addDateHeader(name, date); + } + + @Override + public void setHeader(String name, String value) { + from.setHeader(name, value); + } + + @Override + public void addHeader(String name, String value) { + from.addHeader(name, value); + } + + @Override + public void setIntHeader(String name, int value) { + from.setIntHeader(name, value); + } + + @Override + public void addIntHeader(String name, int value) { + from.addIntHeader(name, value); + } + + @Override + public void setStatus(int sc) { + from.setStatus(sc); + } + + @Override + public void setStatus(int sc, String sm) { + from.setStatus(sc, sm); + } + + @Override + public int getStatus() { + return from.getStatus(); + } + + @Override + public String getHeader(String name) { + return from.getHeader(name); + } + + @Override + public Collection getHeaders(String name) { + return from.getHeaders(name); + } + + @Override + public Collection getHeaderNames() { + return from.getHeaderNames(); + } + + @Override + public void setTrailerFields(Supplier> supplier) { + from.setTrailerFields(supplier); + } + + @Override + public Supplier> getTrailerFields() { + return from.getTrailerFields(); + } + + @Override + public jakarta.servlet.ServletResponse toJakartaServletResponse() { + return from; + } + + @Override + public jakarta.servlet.http.HttpServletResponse toJakartaHttpServletResponse() { + return from; + } + + @Override + public StaplerResponse2 toStaplerResponse2() { + return from; + } + } } diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerResponse2.java b/core/src/main/java/org/kohsuke/stapler/StaplerResponse2.java new file mode 100644 index 000000000..ecf95a224 --- /dev/null +++ b/core/src/main/java/org/kohsuke/stapler/StaplerResponse2.java @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2004-2010, Kohsuke Kawaguchi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.kohsuke.stapler; + +import edu.umd.cs.findbugs.annotations.NonNull; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.net.URL; +import java.net.URLConnection; +import net.sf.json.JsonConfig; +import org.kohsuke.stapler.export.DataWriter; +import org.kohsuke.stapler.export.ExportConfig; +import org.kohsuke.stapler.export.Flavor; +import org.kohsuke.stapler.export.Model; +import org.kohsuke.stapler.export.NamedPathPruner; + +/** + * Defines additional operations made available by Stapler. + * + * @see Stapler#getCurrentResponse2() + * @author Kohsuke Kawaguchi + */ +public interface StaplerResponse2 extends HttpServletResponse { + /** + * Evaluates the url against the given object and + * forwards the request to the result. + * + *

+ * This can be used for example inside an action method + * to forward a request to a JSP. + * + * @param it + * the URL is evaluated against this object. Must not be null. + * @param url + * the relative URL (e.g., "foo" or "foo/bar") to resolve + * against the "it" object. + * @param request + * Request to be forwarded. + */ + void forward(Object it, String url, StaplerRequest2 request) throws ServletException, IOException; + + /** + * Redirects the browser to where it came from (the referer.) + */ + void forwardToPreviousPage(StaplerRequest2 request) throws ServletException, IOException; + + /** + * Works like {@link #sendRedirect(String)} except that this method + * escapes the URL. + */ + void sendRedirect2(@NonNull String url) throws IOException; + + /** + * Works like {@link #sendRedirect2(String)} but allows the caller to specify the HTTP status code. + */ + void sendRedirect(int statusCore, @NonNull String url) throws IOException; + + /** + * Serves a static resource. + * + *

+ * This method sets content type, HTTP status code, sends the complete data + * and closes the response. This method also handles cache-control HTTP headers + * like "If-Modified-Since" and others. + */ + void serveFile(StaplerRequest2 request, URL res) throws ServletException, IOException; + + void serveFile(StaplerRequest2 request, URL res, long expiration) throws ServletException, IOException; + + /** + * Works like {@link #serveFile(StaplerRequest2, URL)} but chooses the locale specific + * version of the resource if it's available. The convention of "locale specific version" + * is the same as that of property files. + * So Japanese resource for {@code foo.html} would be named {@code foo_ja.html}. + */ + void serveLocalizedFile(StaplerRequest2 request, URL res) throws ServletException, IOException; + + /** + * Works like {@link #serveFile(StaplerRequest2, URL, long)} but chooses the locale + * specific version of the resource if it's available. + * + * See {@link #serveLocalizedFile(StaplerRequest2, URL)} for more details. + */ + void serveLocalizedFile(StaplerRequest2 request, URL res, long expiration) throws ServletException, IOException; + + /** + * Serves a static resource. + * + *

+ * This method works like {@link #serveFile(StaplerRequest2, URL)} but this version + * allows the caller to fetch data from anywhere. + * + * @param data + * {@link InputStream} that contains the data of the static resource. + * @param lastModified + * The timestamp when the resource was last modified. See {@link URLConnection#getLastModified()} + * for the meaning of the value. 0 if unknown, in which case "If-Modified-Since" handling + * will not be performed. + * @param expiration + * The number of milliseconds until the resource will "expire". + * Until it expires the browser will be allowed to cache it + * and serve it without checking back with the server. + * After it expires, the client will send conditional GET to + * check if the resource is actually modified or not. + * If 0, it will immediately expire. + * @param contentLength + * if the length of the input stream is known in advance, specify that value + * so that HTTP keep-alive works. Otherwise specify -1 to indicate that the length is unknown. + * @param fileName + * file name of this resource. Used to determine the MIME type. + * Since the only important portion is the file extension, this could be just a file name, + * or a full path name, or even a pseudo file name that doesn't actually exist. + * It supports both '/' and '\\' as the path separator. + * + * If this string starts with "mime-type:", like "mime-type:foo/bar", then "foo/bar" will + * be used as a MIME type without consulting the servlet container. + */ + void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + long contentLength, + String fileName) + throws ServletException, IOException; + + /** + * @deprecated use form with long contentLength + */ + @Deprecated + void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + int contentLength, + String fileName) + throws ServletException, IOException; + + /** + * Serves a static resource. + * + * Expiration date is set to the value that forces browser to do conditional GET + * for all resources. + * + * @see #serveFile(StaplerRequest2, InputStream, long, long, int, String) + */ + void serveFile(StaplerRequest2 req, InputStream data, long lastModified, long contentLength, String fileName) + throws ServletException, IOException; + + /** + * @deprecated use form with long contentLength + */ + @Deprecated + void serveFile(StaplerRequest2 req, InputStream data, long lastModified, int contentLength, String fileName) + throws ServletException, IOException; + + /** + * Serves the exposed bean in the specified flavor. + * + *

+ * This method performs the complete output from the header to the response body. + * If the flavor is JSON, this method also supports JSONP via the {@code jsonp} query parameter. + * + *

The {@code depth} parameter may be used to specify a recursion depth + * as in {@link Model#writeTo(Object,int,DataWriter)}. + * + *

As of 1.146, the {@code tree} parameter may be used to control the output + * in detail; see {@link NamedPathPruner#NamedPathPruner(String)} for details. + * + * @deprecated Use {@link #serveExposedBean(StaplerRequest2, Object, ExportConfig)} + */ + @Deprecated + void serveExposedBean(StaplerRequest2 req, Object exposedBean, Flavor flavor) throws ServletException, IOException; + + /** + * Serves the exposed bean in the specified flavor. + * + *

+ * This method performs the complete output from the header to the response body. + * If the flavor is JSON, this method also supports JSONP via the {@code jsonp} query parameter. + * + *

The {@code depth} parameter may be used to specify a recursion depth + * as in {@link Model#writeTo(Object,int,DataWriter)} + * + *

As of 1.146, the {@code tree} parameter may be used to control the output + * in detail; see {@link NamedPathPruner#NamedPathPruner(String)} for details. + * + *

{@link ExportConfig} is passed by the caller to control serialization behavior + * @since 1.251 + */ + default void serveExposedBean(StaplerRequest2 req, Object exposedBean, ExportConfig exportConfig) + throws ServletException, IOException { + serveExposedBean(req, exposedBean, exportConfig.getFlavor()); + } + + /** + * @deprecated use {@link #getOutputStream} + */ + @Deprecated + OutputStream getCompressedOutputStream(HttpServletRequest req) throws IOException; + + /** + * @deprecated use {@link #getWriter} + */ + @Deprecated + Writer getCompressedWriter(HttpServletRequest req) throws IOException; + + /** + * Performs the reverse proxy to the given URL. + * + * @return + * The status code of the response. + */ + int reverseProxyTo(URL url, StaplerRequest2 req) throws IOException; + + /** + * The JsonConfig to be used when serializing java beans from js bound methods to JSON. + * Setting this to null will make the default config to be used. + * + * @param config the config + */ + void setJsonConfig(JsonConfig config); + + /** + * The JsonConfig to be used when serializing java beans to JSON previously set by {@link #setJsonConfig(JsonConfig)}. + * Will return the default config if nothing has previously been set. + * + * @return the config + */ + JsonConfig getJsonConfig(); +} diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerResponse2Wrapper.java b/core/src/main/java/org/kohsuke/stapler/StaplerResponse2Wrapper.java new file mode 100644 index 000000000..de2fa1ae9 --- /dev/null +++ b/core/src/main/java/org/kohsuke/stapler/StaplerResponse2Wrapper.java @@ -0,0 +1,397 @@ +package org.kohsuke.stapler; + +import edu.umd.cs.findbugs.annotations.NonNull; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Writer; +import java.net.URL; +import java.util.Collection; +import java.util.Locale; +import net.sf.json.JsonConfig; +import org.kohsuke.stapler.export.ExportConfig; +import org.kohsuke.stapler.export.Flavor; + +/** + * A basic wrapper for a StaplerResponse2, e.g. in order to override some method. + * This simply delegates all method calls to the wrapped instance. + */ +@SuppressWarnings("deprecation") +public abstract class StaplerResponse2Wrapper implements StaplerResponse2 { + private final StaplerResponse2 wrapped; + + public StaplerResponse2Wrapper(StaplerResponse2 wrapped) { + this.wrapped = wrapped; + } + + /** + * Returns the wrapped instance + */ + @NonNull + public StaplerResponse2 getWrapped() { + return wrapped; + } + + /** {@inheritDoc} */ + @Override + public ServletOutputStream getOutputStream() throws IOException { + return getWrapped().getOutputStream(); + } + + /** {@inheritDoc} */ + @Override + public PrintWriter getWriter() throws IOException { + return getWrapped().getWriter(); + } + + /** {@inheritDoc} */ + @Override + public void forward(Object it, String url, StaplerRequest2 request) throws ServletException, IOException { + getWrapped().forward(it, url, request); + } + + /** {@inheritDoc} */ + @Override + public void forwardToPreviousPage(StaplerRequest2 request) throws ServletException, IOException { + getWrapped().forwardToPreviousPage(request); + } + + /** {@inheritDoc} */ + @Override + public void sendRedirect(String url) throws IOException { + getWrapped().sendRedirect(url); + } + + /** {@inheritDoc} */ + @Override + public void sendRedirect2(String url) throws IOException { + getWrapped().sendRedirect2(url); + } + + /** {@inheritDoc} */ + @Override + public void sendRedirect(int statusCode, String url) throws IOException { + getWrapped().sendRedirect(statusCode, url); + } + + /** {@inheritDoc} */ + @Override + public void serveFile(StaplerRequest2 req, URL resource, long expiration) throws ServletException, IOException { + getWrapped().serveFile(req, resource, expiration); + } + + /** {@inheritDoc} */ + @Override + public void serveFile(StaplerRequest2 req, URL resource) throws ServletException, IOException { + getWrapped().serveFile(req, resource); + } + + /** {@inheritDoc} */ + @Override + public void serveLocalizedFile(StaplerRequest2 request, URL res) throws ServletException, IOException { + getWrapped().serveLocalizedFile(request, res); + } + + /** {@inheritDoc} */ + @Override + public void serveLocalizedFile(StaplerRequest2 request, URL res, long expiration) + throws ServletException, IOException { + getWrapped().serveLocalizedFile(request, res, expiration); + } + + /** {@inheritDoc} */ + @Override + public void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + long contentLength, + String fileName) + throws ServletException, IOException { + getWrapped().serveFile(req, data, lastModified, expiration, contentLength, fileName); + } + + /** {@inheritDoc} */ + @Override + public void serveFile( + StaplerRequest2 req, + InputStream data, + long lastModified, + long expiration, + int contentLength, + String fileName) + throws ServletException, IOException { + getWrapped().serveFile(req, data, lastModified, expiration, contentLength, fileName); + } + + /** {@inheritDoc} */ + @Override + public void serveFile(StaplerRequest2 req, InputStream data, long lastModified, long contentLength, String fileName) + throws ServletException, IOException { + getWrapped().serveFile(req, data, lastModified, contentLength, fileName); + } + + /** {@inheritDoc} */ + @Override + public void serveFile(StaplerRequest2 req, InputStream data, long lastModified, int contentLength, String fileName) + throws ServletException, IOException { + getWrapped().serveFile(req, data, lastModified, contentLength, fileName); + } + + /** + * @deprecated Use {@link #serveExposedBean(StaplerRequest2, Object, ExportConfig)} + */ + @Override + @Deprecated + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, Flavor flavor) + throws ServletException, IOException { + getWrapped().serveExposedBean(req, exposedBean, flavor); + } + + /** {@inheritDoc} */ + @Override + public void serveExposedBean(StaplerRequest2 req, Object exposedBean, ExportConfig exportConfig) + throws ServletException, IOException { + getWrapped().serveExposedBean(req, exposedBean, exportConfig); + } + + /** {@inheritDoc} */ + @Override + public OutputStream getCompressedOutputStream(HttpServletRequest req) throws IOException { + return getWrapped().getCompressedOutputStream(req); + } + + /** {@inheritDoc} */ + @Override + public Writer getCompressedWriter(HttpServletRequest req) throws IOException { + return getWrapped().getCompressedWriter(req); + } + + /** {@inheritDoc} */ + @Override + public int reverseProxyTo(URL url, StaplerRequest2 req) throws IOException { + return getWrapped().reverseProxyTo(url, req); + } + + /** {@inheritDoc} */ + @Override + public void setJsonConfig(JsonConfig config) { + getWrapped().setJsonConfig(config); + } + + /** {@inheritDoc} */ + @Override + public JsonConfig getJsonConfig() { + return getWrapped().getJsonConfig(); + } + + /** {@inheritDoc} */ + @Override + public void addCookie(Cookie cookie) { + getWrapped().addCookie(cookie); + } + + /** {@inheritDoc} */ + @Override + public void addDateHeader(String name, long date) { + getWrapped().addDateHeader(name, date); + } + + /** {@inheritDoc} */ + @Override + public void addHeader(String name, String value) { + getWrapped().addHeader(name, value); + } + + /** {@inheritDoc} */ + @Override + public void addIntHeader(String name, int value) { + getWrapped().addIntHeader(name, value); + } + + /** {@inheritDoc} */ + @Override + public boolean containsHeader(String name) { + return getWrapped().containsHeader(name); + } + + /** {@inheritDoc} */ + @Override + public String encodeRedirectURL(String url) { + return getWrapped().encodeRedirectURL(url); + } + + /** {@inheritDoc} */ + @Override + public String encodeRedirectUrl(String url) { + return getWrapped().encodeRedirectUrl(url); + } + + /** {@inheritDoc} */ + @Override + public String encodeURL(String url) { + return getWrapped().encodeURL(url); + } + + /** {@inheritDoc} */ + @Override + public String encodeUrl(String url) { + return getWrapped().encodeUrl(url); + } + + /** {@inheritDoc} */ + @Override + public void sendError(int sc) throws IOException { + getWrapped().sendError(sc); + } + + /** {@inheritDoc} */ + @Override + public void sendError(int sc, String msg) throws IOException { + getWrapped().sendError(sc, msg); + } + + /** {@inheritDoc} */ + @Override + public void setDateHeader(String name, long date) { + getWrapped().setDateHeader(name, date); + } + + /** {@inheritDoc} */ + @Override + public void setHeader(String name, String value) { + getWrapped().setHeader(name, value); + } + + /** {@inheritDoc} */ + @Override + public void setIntHeader(String name, int value) { + getWrapped().setIntHeader(name, value); + } + + /** {@inheritDoc} */ + @Override + public void setStatus(int sc) { + getWrapped().setStatus(sc); + } + + /** {@inheritDoc} */ + @Override + public void setStatus(int sc, String sm) { + getWrapped().setStatus(sc, sm); + } + + /** {@inheritDoc} */ + @Override + public void flushBuffer() throws IOException { + getWrapped().flushBuffer(); + } + + /** {@inheritDoc} */ + @Override + public int getBufferSize() { + return getWrapped().getBufferSize(); + } + + /** {@inheritDoc} */ + @Override + public String getCharacterEncoding() { + return getWrapped().getCharacterEncoding(); + } + + /** {@inheritDoc} */ + @Override + public Locale getLocale() { + return getWrapped().getLocale(); + } + + /** {@inheritDoc} */ + @Override + public boolean isCommitted() { + return getWrapped().isCommitted(); + } + + /** {@inheritDoc} */ + @Override + public void reset() { + getWrapped().reset(); + } + + /** {@inheritDoc} */ + @Override + public void resetBuffer() { + getWrapped().resetBuffer(); + } + + /** {@inheritDoc} */ + @Override + public void setBufferSize(int size) { + getWrapped().setBufferSize(size); + } + + /** {@inheritDoc} */ + @Override + public void setContentLength(int len) { + getWrapped().setContentLength(len); + } + + /** {@inheritDoc} */ + @Override + public void setContentType(String type) { + getWrapped().setContentType(type); + } + + /** {@inheritDoc} */ + @Override + public void setLocale(Locale loc) { + getWrapped().setLocale(loc); + } + + /** {@inheritDoc} */ + @Override + public int getStatus() { + return getWrapped().getStatus(); + } + + /** {@inheritDoc} */ + @Override + public String getHeader(String name) { + return getWrapped().getHeader(name); + } + + /** {@inheritDoc} */ + @Override + public Collection getHeaders(String name) { + return getWrapped().getHeaders(name); + } + + /** {@inheritDoc} */ + @Override + public Collection getHeaderNames() { + return getWrapped().getHeaderNames(); + } + + /** {@inheritDoc} */ + @Override + public String getContentType() { + return getWrapped().getContentType(); + } + + /** {@inheritDoc} */ + @Override + public void setCharacterEncoding(String charset) { + getWrapped().setCharacterEncoding(charset); + } + + /** {@inheritDoc} */ + @Override + public void setContentLengthLong(long len) { + getWrapped().setContentLengthLong(len); + } +} diff --git a/core/src/main/java/org/kohsuke/stapler/StaplerResponseWrapper.java b/core/src/main/java/org/kohsuke/stapler/StaplerResponseWrapper.java index da9cd671d..d6d94c3a8 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaplerResponseWrapper.java +++ b/core/src/main/java/org/kohsuke/stapler/StaplerResponseWrapper.java @@ -22,7 +22,9 @@ * This simply delegates all method calls to the wrapped instance. * * @since TODO + * @deprecated use {@link StaplerResponse2Wrapper} */ +@Deprecated @SuppressWarnings("deprecation") public abstract class StaplerResponseWrapper implements StaplerResponse { private final StaplerResponse wrapped; diff --git a/core/src/main/java/org/kohsuke/stapler/StaticViewFacet.java b/core/src/main/java/org/kohsuke/stapler/StaticViewFacet.java index eda84ed2c..e98258713 100644 --- a/core/src/main/java/org/kohsuke/stapler/StaticViewFacet.java +++ b/core/src/main/java/org/kohsuke/stapler/StaticViewFacet.java @@ -1,17 +1,17 @@ package org.kohsuke.stapler; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.lang.Klass; /** diff --git a/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionFilter.java b/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionFilter.java index cf1715f0f..1493fcb4b 100644 --- a/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionFilter.java +++ b/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionFilter.java @@ -1,18 +1,17 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class UncaughtExceptionFilter implements Filter { + +public class UncaughtExceptionFilter implements CompatibleFilter { private ServletContext context; @Override diff --git a/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionHandler.java b/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionHandler.java index b6b3aa811..9af6c7762 100644 --- a/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionHandler.java +++ b/core/src/main/java/org/kohsuke/stapler/UncaughtExceptionHandler.java @@ -1,15 +1,15 @@ package org.kohsuke.stapler; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.text.MessageFormat; import java.util.Date; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; /** * Handles an exception caught by {@link UncaughtExceptionFilter}. diff --git a/core/src/main/java/org/kohsuke/stapler/WebApp.java b/core/src/main/java/org/kohsuke/stapler/WebApp.java index 75a48d29e..480fa8fbb 100644 --- a/core/src/main/java/org/kohsuke/stapler/WebApp.java +++ b/core/src/main/java/org/kohsuke/stapler/WebApp.java @@ -23,6 +23,10 @@ package org.kohsuke.stapler; +import io.jenkins.servlet.ServletContextWrapper; +import jakarta.servlet.Filter; +import jakarta.servlet.ServletConfig; +import jakarta.servlet.ServletContext; import java.util.HashMap; import java.util.Hashtable; import java.util.List; @@ -31,9 +35,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; -import javax.servlet.Filter; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; import net.sf.json.JSONObject; import org.kohsuke.stapler.bind.BoundObjectTable; import org.kohsuke.stapler.event.FilteredDispatchTriggerListener; @@ -74,10 +75,24 @@ public static WebApp get(ServletContext context) { return (WebApp) o; } + /** + * @deprecated use {@link #get(ServletContext)} + */ + @Deprecated + public static WebApp get(javax.servlet.ServletContext context) { + return get(ServletContextWrapper.toJakartaServletContext(context)); + } + + /** + * @deprecated use {@link #getServletContext} + */ + @Deprecated + public final javax.servlet.ServletContext context; + /** * {@link ServletContext} for this webapp. */ - public final ServletContext context; + private final ServletContext servletContext; /** * @deprecated Unused? @@ -100,7 +115,7 @@ public static WebApp get(ServletContext context) { /** * Global {@link BindInterceptor}s. * - * These are consulted after {@link StaplerRequest#getBindInterceptor()} is consulted. + * These are consulted after {@link StaplerRequest2#getBindInterceptor()} is consulted. * Global bind interceptors are useful to register webapp-wide conversion logic local to the application. * @since 1.220 */ @@ -165,7 +180,8 @@ public static WebApp get(ServletContext context) { private JsonInErrorMessageSanitizer jsonInErrorMessageSanitizer; public WebApp(ServletContext context) { - this.context = context; + this.servletContext = context; + this.context = context != null ? ServletContextWrapper.fromJakartServletContext(context) : null; // TODO: allow classloader to be given? facets.addAll(Facet.discoverExtensions( Facet.class, @@ -179,11 +195,15 @@ public WebApp(ServletContext context) { * sits at the root of the URL hierarchy and handles the request to '/'. */ public Object getApp() { - return context.getAttribute("app"); + return servletContext.getAttribute("app"); } public void setApp(Object app) { - context.setAttribute("app", app); + servletContext.setAttribute("app", app); + } + + public ServletContext getServletContext() { + return servletContext; } public CrumbIssuer getCrumbIssuer() { @@ -222,7 +242,7 @@ public T getFacet(Class type) { } /** - * Sets the classloader used by {@link StaplerRequest#bindJSON(Class, JSONObject)} and its sibling methods. + * Sets the classloader used by {@link StaplerRequest2#bindJSON(Class, JSONObject)} and its sibling methods. */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; diff --git a/core/src/main/java/org/kohsuke/stapler/bind/Bound.java b/core/src/main/java/org/kohsuke/stapler/bind/Bound.java index 5f456e46f..8d4a3a1ba 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/Bound.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/Bound.java @@ -76,7 +76,7 @@ public final String getProxyScript() { */ public static String getProxyScriptURL(String variableName, Bound bound) { if (bound == null) { - return Stapler.getCurrentRequest().getContextPath() + BoundObjectTable.SCRIPT_PREFIX + "/null?var=" + return Stapler.getCurrentRequest2().getContextPath() + BoundObjectTable.SCRIPT_PREFIX + "/null?var=" + variableName; } else { return bound.getProxyScriptURL(variableName); @@ -93,7 +93,7 @@ public final String getProxyScriptURL(String variableName) { final String methodsList = String.join(",", getBoundJavaScriptUrlNames(getTarget().getClass())); // The URL looks like it has some redundant elements, but only if it's not a WithWellKnownURL - return Stapler.getCurrentRequest().getContextPath() + BoundObjectTable.SCRIPT_PREFIX + getURL() + "?var=" + return Stapler.getCurrentRequest2().getContextPath() + BoundObjectTable.SCRIPT_PREFIX + getURL() + "?var=" + variableName + "&methods=" + methodsList; } diff --git a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java index 7683e6dfa..55eda3dc3 100644 --- a/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java +++ b/core/src/main/java/org/kohsuke/stapler/bind/BoundObjectTable.java @@ -24,6 +24,8 @@ package org.kohsuke.stapler.bind; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; @@ -34,8 +36,6 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; -import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.Ancestor; import org.kohsuke.stapler.HttpResponse; @@ -43,8 +43,8 @@ import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerFallback; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * Objects exported and bound by JavaScript proxies. @@ -86,7 +86,7 @@ public static boolean isValidJavaIdentifier(String name) { * @throws IOException If an I/O error occurs */ public void doScript( - StaplerRequest req, StaplerResponse rsp, @QueryParameter String var, @QueryParameter String methods) + StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String var, @QueryParameter String methods) throws IOException { final String boundUrl = req.getRestOfPath(); @@ -111,7 +111,7 @@ public void doScript( final String script; /* If this is not a WithWellKnownURL, look UUID up in bound object table and return null if not found. */ - final String contextAndPrefix = Stapler.getCurrentRequest().getContextPath() + PREFIX; + final String contextAndPrefix = Stapler.getCurrentRequest2().getContextPath() + PREFIX; if (boundUrl.startsWith(contextAndPrefix)) { final String id = boundUrl.replace(contextAndPrefix, ""); final Table table = resolve(false); @@ -172,7 +172,7 @@ public Bound bindWeak(Object o) { * Called from within the request handling of a bound object, to release the object explicitly. */ public void releaseMe() { - Ancestor eot = Stapler.getCurrentRequest().findAncestor(BoundObjectTable.class); + Ancestor eot = Stapler.getCurrentRequest2().findAncestor(BoundObjectTable.class); if (eot == null) { throw new IllegalStateException("The thread is not handling a request to a abound object"); } @@ -185,7 +185,7 @@ public void releaseMe() { * Obtains a {@link Table} associated with this session. */ private Table resolve(boolean createIfNotExist) { - HttpSession session = Stapler.getCurrentRequest().getSession(createIfNotExist); + HttpSession session = Stapler.getCurrentRequest2().getSession(createIfNotExist); if (session == null) { return null; } @@ -240,7 +240,7 @@ public void release() { @Override public String getURL() { - return Stapler.getCurrentRequest().getContextPath() + PREFIX + id; + return Stapler.getCurrentRequest2().getContextPath() + PREFIX + id; } @Override @@ -249,7 +249,7 @@ public Object getTarget() { } @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.sendRedirect2(getURL()); } @@ -313,7 +313,7 @@ public void release() {} @Override public String getURL() { - return Stapler.getCurrentRequest().getContextPath() + url; + return Stapler.getCurrentRequest2().getContextPath() + url; } @Override @@ -322,7 +322,7 @@ public Object getTarget() { } @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.sendRedirect2(getURL()); } diff --git a/core/src/main/java/org/kohsuke/stapler/event/FilteredDispatchTriggerListener.java b/core/src/main/java/org/kohsuke/stapler/event/FilteredDispatchTriggerListener.java index 4574da6ac..fa25cedd5 100644 --- a/core/src/main/java/org/kohsuke/stapler/event/FilteredDispatchTriggerListener.java +++ b/core/src/main/java/org/kohsuke/stapler/event/FilteredDispatchTriggerListener.java @@ -25,8 +25,8 @@ package org.kohsuke.stapler.event; import java.util.logging.Logger; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * Listens to filtered dispatch events from {@link org.kohsuke.stapler.DispatchValidator}. @@ -35,13 +35,13 @@ * @see org.kohsuke.stapler.WebApp#setFilteredDispatchTriggerListener(FilteredDispatchTriggerListener) */ public interface FilteredDispatchTriggerListener { - boolean onDispatchTrigger(StaplerRequest req, StaplerResponse rsp, Object node, String viewName); + boolean onDispatchTrigger(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String viewName); FilteredDispatchTriggerListener JUST_WARN = new FilteredDispatchTriggerListener() { private final Logger LOGGER = Logger.getLogger(FilteredDispatchTriggerListener.class.getName()); @Override - public boolean onDispatchTrigger(StaplerRequest req, StaplerResponse rsp, Object node, String viewName) { + public boolean onDispatchTrigger(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String viewName) { LOGGER.warning(() -> "BLOCKED -> <" + node + ">." + viewName); return false; } diff --git a/core/src/main/java/org/kohsuke/stapler/event/FilteredDoActionTriggerListener.java b/core/src/main/java/org/kohsuke/stapler/event/FilteredDoActionTriggerListener.java index ffa2f9d42..59be7c995 100644 --- a/core/src/main/java/org/kohsuke/stapler/event/FilteredDoActionTriggerListener.java +++ b/core/src/main/java/org/kohsuke/stapler/event/FilteredDoActionTriggerListener.java @@ -27,20 +27,20 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.kohsuke.stapler.Function; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * Listener that is triggered when a doAction function - that is no more accepted - is called. */ public interface FilteredDoActionTriggerListener { - boolean onDoActionTrigger(Function f, StaplerRequest req, StaplerResponse rsp, Object node); + boolean onDoActionTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node); FilteredDoActionTriggerListener JUST_WARN = new FilteredDoActionTriggerListener() { private final Logger LOGGER = Logger.getLogger(FilteredDoActionTriggerListener.class.getName()); @Override - public boolean onDoActionTrigger(Function f, StaplerRequest req, StaplerResponse rsp, Object node) { + public boolean onDoActionTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning(String.format("BLOCKED -> <%s>.%s(...))", node, f.getName())); } diff --git a/core/src/main/java/org/kohsuke/stapler/event/FilteredFieldTriggerListener.java b/core/src/main/java/org/kohsuke/stapler/event/FilteredFieldTriggerListener.java index fc4aceb01..7b73cd6b8 100644 --- a/core/src/main/java/org/kohsuke/stapler/event/FilteredFieldTriggerListener.java +++ b/core/src/main/java/org/kohsuke/stapler/event/FilteredFieldTriggerListener.java @@ -3,19 +3,19 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.kohsuke.stapler.RequestImpl; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.lang.FieldRef; public interface FilteredFieldTriggerListener { - boolean onFieldTrigger(FieldRef f, StaplerRequest req, StaplerResponse rsp, Object node, String expression); + boolean onFieldTrigger(FieldRef f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression); FilteredFieldTriggerListener JUST_WARN = new FilteredFieldTriggerListener() { private final Logger LOGGER = Logger.getLogger(FilteredFieldTriggerListener.class.getName()); @Override public boolean onFieldTrigger( - FieldRef f, StaplerRequest req, StaplerResponse rsp, Object node, String expression) { + FieldRef f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning(String.format( "BLOCKED -> evaluate(<%s>.%s,\"%s\")", diff --git a/core/src/main/java/org/kohsuke/stapler/event/FilteredGetterTriggerListener.java b/core/src/main/java/org/kohsuke/stapler/event/FilteredGetterTriggerListener.java index 01e34647a..2670eed7a 100644 --- a/core/src/main/java/org/kohsuke/stapler/event/FilteredGetterTriggerListener.java +++ b/core/src/main/java/org/kohsuke/stapler/event/FilteredGetterTriggerListener.java @@ -28,21 +28,21 @@ import java.util.logging.Logger; import org.kohsuke.stapler.Function; import org.kohsuke.stapler.RequestImpl; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * Listener that is triggered when a getter function - that is no more accepted - is called. */ public interface FilteredGetterTriggerListener { - boolean onGetterTrigger(Function f, StaplerRequest req, StaplerResponse rsp, Object node, String expression); + boolean onGetterTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression); FilteredGetterTriggerListener JUST_WARN = new FilteredGetterTriggerListener() { private final Logger LOGGER = Logger.getLogger(FilteredGetterTriggerListener.class.getName()); @Override public boolean onGetterTrigger( - Function f, StaplerRequest req, StaplerResponse rsp, Object node, String expression) { + Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression) { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning(String.format( "BLOCKED -> evaluate(<%s>.%s,\"%s\")", diff --git a/core/src/main/java/org/kohsuke/stapler/export/Flavor.java b/core/src/main/java/org/kohsuke/stapler/export/Flavor.java index f308866cd..1b4271fa2 100644 --- a/core/src/main/java/org/kohsuke/stapler/export/Flavor.java +++ b/core/src/main/java/org/kohsuke/stapler/export/Flavor.java @@ -25,7 +25,7 @@ import java.io.IOException; import java.io.Writer; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; /** * Export flavor. @@ -73,7 +73,7 @@ public DataWriter createDataWriter(Object bean, Writer w, ExportConfig config) t this.contentType = contentType; } - public DataWriter createDataWriter(Object bean, StaplerResponse rsp) throws IOException { + public DataWriter createDataWriter(Object bean, StaplerResponse2 rsp) throws IOException { return createDataWriter(bean, rsp.getWriter()); } diff --git a/core/src/main/java/org/kohsuke/stapler/export/XMLDataWriter.java b/core/src/main/java/org/kohsuke/stapler/export/XMLDataWriter.java index 580e27a09..62458ab4b 100644 --- a/core/src/main/java/org/kohsuke/stapler/export/XMLDataWriter.java +++ b/core/src/main/java/org/kohsuke/stapler/export/XMLDataWriter.java @@ -30,7 +30,7 @@ import java.lang.reflect.Type; import java.util.Stack; import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; /** * Writes XML. @@ -65,7 +65,7 @@ final class XMLDataWriter implements DataWriter { // TODO: support pretty printing } - XMLDataWriter(Object bean, StaplerResponse rsp, ExportConfig config) throws IOException { + XMLDataWriter(Object bean, StaplerResponse2 rsp, ExportConfig config) throws IOException { this(bean, rsp.getWriter(), config); } diff --git a/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.java b/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.java index d3453c907..779e2bd61 100644 --- a/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.java +++ b/core/src/main/java/org/kohsuke/stapler/framework/AbstractWebAppMain.java @@ -24,6 +24,9 @@ package org.kohsuke.stapler.framework; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -32,12 +35,9 @@ import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; import org.jvnet.localizer.LocaleProvider; import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.framework.errors.NoHomeDirError; /** @@ -198,7 +198,7 @@ private void installLocaleProvider() { @Override public Locale get() { Locale locale = null; - StaplerRequest req = Stapler.getCurrentRequest(); + StaplerRequest2 req = Stapler.getCurrentRequest2(); if (req != null) { locale = req.getLocale(); } diff --git a/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java b/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java index 48485082e..a59a189fe 100644 --- a/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java +++ b/core/src/main/java/org/kohsuke/stapler/framework/io/LargeText.java @@ -25,6 +25,7 @@ package org.kohsuke.stapler.framework.io; +import jakarta.servlet.http.HttpServletResponse; import java.io.Closeable; import java.io.DataInputStream; import java.io.EOFException; @@ -40,10 +41,12 @@ import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.zip.GZIPInputStream; -import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.output.CountingOutputStream; +import org.kohsuke.stapler.ReflectionUtils; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; /** * Represents a large text data. @@ -263,7 +266,27 @@ public long writeLogTo(long start, OutputStream out) throws IOException { * Implements the progressive text handling. * This method is used as a "web method" with progressiveText.jelly. */ + public void doProgressText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException { + if (ReflectionUtils.isOverridden( + LargeText.class, getClass(), "doProgressText", StaplerRequest.class, StaplerResponse.class)) { + doProgressText(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp)); + } else { + doProgressTextImpl(req, rsp); + } + } + + /** + * Implements the progressive text handling. + * This method is used as a "web method" with progressiveText.jelly. + * + * @deprecated use {@link #doProgressText(StaplerRequest2, StaplerResponse2)} + */ + @Deprecated public void doProgressText(StaplerRequest req, StaplerResponse rsp) throws IOException { + doProgressTextImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp)); + } + + private void doProgressTextImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException { setContentType(rsp); rsp.setStatus(HttpServletResponse.SC_OK); @@ -297,10 +320,40 @@ public void doProgressText(StaplerRequest req, StaplerResponse rsp) throws IOExc w.close(); } + protected void setContentType(StaplerResponse2 rsp) { + if (ReflectionUtils.isOverridden(LargeText.class, getClass(), "setContentType", StaplerResponse.class)) { + setContentType(StaplerResponse.fromStaplerResponse2(rsp)); + } else { + setContentTypeImpl(rsp); + } + } + + /** + * @deprecated use {@link #setContentType(StaplerResponse2)} + */ + @Deprecated protected void setContentType(StaplerResponse rsp) { + setContentTypeImpl(StaplerResponse.toStaplerResponse2(rsp)); + } + + private void setContentTypeImpl(StaplerResponse2 rsp) { rsp.setContentType("text/plain;charset=UTF-8"); } + protected Writer createWriter(StaplerRequest2 req, StaplerResponse2 rsp, long size) throws IOException { + if (ReflectionUtils.isOverridden( + LargeText.class, getClass(), "createWriter", StaplerRequest.class, StaplerResponse.class, long.class)) { + return createWriter( + StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp), size); + } else { + return rsp.getWriter(); + } + } + + /** + * @deprecated use {@link #createWriter(StaplerRequest2, StaplerResponse2, long)} + */ + @Deprecated protected Writer createWriter(StaplerRequest req, StaplerResponse rsp, long size) throws IOException { return rsp.getWriter(); } diff --git a/core/src/main/java/org/kohsuke/stapler/interceptor/Interceptor.java b/core/src/main/java/org/kohsuke/stapler/interceptor/Interceptor.java index 4dfbf6b12..d6923627e 100644 --- a/core/src/main/java/org/kohsuke/stapler/interceptor/Interceptor.java +++ b/core/src/main/java/org/kohsuke/stapler/interceptor/Interceptor.java @@ -1,12 +1,16 @@ package org.kohsuke.stapler.interceptor; +import io.jenkins.servlet.ServletExceptionWrapper; +import jakarta.servlet.ServletException; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.CancelRequestHandlingException; import org.kohsuke.stapler.Function; import org.kohsuke.stapler.HttpResponses; +import org.kohsuke.stapler.ReflectionUtils; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; /** * Intercepts the domain method call from Stapler. @@ -49,6 +53,58 @@ public void setTarget(Function target) { * @throws CancelRequestHandlingException * to cancel this request handling and moves on to the next available dispatch mechanism. */ - public abstract Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) - throws IllegalAccessException, InvocationTargetException, ServletException; + public /* abstract */ Object invoke( + StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) + throws IllegalAccessException, InvocationTargetException, ServletException { + if (ReflectionUtils.isOverridden( + Interceptor.class, + getClass(), + "invoke", + StaplerRequest.class, + StaplerResponse.class, + Object.class, + Object[].class)) { + try { + return invoke( + StaplerRequest.fromStaplerRequest2(request), + StaplerResponse.fromStaplerResponse2(response), + instance, + arguments); + } catch (javax.servlet.ServletException e) { + throw ServletExceptionWrapper.toJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + Interceptor.class.getSimpleName() + ".invoke methods"); + } + } + + /** + * @deprecated use {@link #invoke(StaplerRequest2, StaplerResponse2, Object, Object[])} + */ + @Deprecated + public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + throws IllegalAccessException, InvocationTargetException, javax.servlet.ServletException { + if (ReflectionUtils.isOverridden( + Interceptor.class, + getClass(), + "invoke", + StaplerRequest2.class, + StaplerResponse2.class, + Object.class, + Object[].class)) { + try { + return invoke( + StaplerRequest.toStaplerRequest2(request), + StaplerResponse.toStaplerResponse2(response), + instance, + arguments); + } catch (ServletException e) { + throw ServletExceptionWrapper.fromJakartaServletException(e); + } + } else { + throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + + Interceptor.class.getSimpleName() + ".invoke methods"); + } + } } diff --git a/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.java b/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.java index c588a8cac..b37e9e433 100644 --- a/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.java +++ b/core/src/main/java/org/kohsuke/stapler/interceptor/JsonOutputFilter.java @@ -23,6 +23,7 @@ package org.kohsuke.stapler.interceptor; +import jakarta.servlet.ServletException; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -31,11 +32,10 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import javax.servlet.ServletException; import net.sf.json.JsonConfig; import net.sf.json.util.PropertyFilter; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.bind.JavaScriptMethod; /** @@ -75,7 +75,7 @@ class Processor extends Interceptor { @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { JsonOutputFilter annotation = target.getAnnotation(JsonOutputFilter.class); if (annotation != null) { diff --git a/core/src/main/java/org/kohsuke/stapler/interceptor/RequirePOST.java b/core/src/main/java/org/kohsuke/stapler/interceptor/RequirePOST.java index e439f9aea..a89483a78 100644 --- a/core/src/main/java/org/kohsuke/stapler/interceptor/RequirePOST.java +++ b/core/src/main/java/org/kohsuke/stapler/interceptor/RequirePOST.java @@ -1,6 +1,8 @@ package org.kohsuke.stapler.interceptor; import edu.umd.cs.findbugs.annotations.CheckForNull; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.ElementType; @@ -9,12 +11,10 @@ import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; import java.util.ServiceLoader; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.ForwardToView; import org.kohsuke.stapler.HttpResponses; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.verb.POST; /** @@ -49,7 +49,7 @@ interface ErrorCustomizer { class Processor extends Interceptor { @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { if (!request.getMethod().equals("POST")) { for (ErrorCustomizer handler : ServiceLoader.load( @@ -63,7 +63,7 @@ public Object invoke(StaplerRequest request, StaplerResponse response, Object in } throw new InvocationTargetException(new HttpResponses.HttpResponseException() { @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { rsp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); rsp.addHeader("Allow", "POST"); diff --git a/core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java b/core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java index ec910e3bd..8a677193e 100644 --- a/core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java +++ b/core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java @@ -1,14 +1,14 @@ package org.kohsuke.stapler.interceptor; +import jakarta.servlet.ServletException; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.HttpResponses; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * Used on the web-bound doXyz method to indicate that the successful return of the method should @@ -23,7 +23,7 @@ public @interface RespondSuccess { class Processor extends Interceptor { @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { target.invoke(request, response, instance, arguments); // TODO does this actually do anything? diff --git a/core/src/main/java/org/kohsuke/stapler/json/JsonBody.java b/core/src/main/java/org/kohsuke/stapler/json/JsonBody.java index 77e0dcf25..d95ceef78 100644 --- a/core/src/main/java/org/kohsuke/stapler/json/JsonBody.java +++ b/core/src/main/java/org/kohsuke/stapler/json/JsonBody.java @@ -1,5 +1,6 @@ package org.kohsuke.stapler.json; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; @@ -7,12 +8,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.servlet.ServletException; import net.sf.json.JSONObject; import org.apache.commons.io.IOUtils; import org.kohsuke.stapler.AnnotationHandler; import org.kohsuke.stapler.InjectedParameter; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; /** * Binds the body payload into POJO via json-lib. @@ -60,7 +60,7 @@ public @interface JsonBody { class Handler extends AnnotationHandler { @Override - public Object parse(StaplerRequest request, Annotation a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, Annotation a, Class type, String parameterName) throws ServletException { String ct = request.getContentType(); if (ct == null || !ct.startsWith("application/json")) { diff --git a/core/src/main/java/org/kohsuke/stapler/json/JsonHttpResponse.java b/core/src/main/java/org/kohsuke/stapler/json/JsonHttpResponse.java index 040f5b62a..bd15caf43 100644 --- a/core/src/main/java/org/kohsuke/stapler/json/JsonHttpResponse.java +++ b/core/src/main/java/org/kohsuke/stapler/json/JsonHttpResponse.java @@ -2,15 +2,15 @@ import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import jakarta.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; -import javax.servlet.ServletException; import net.sf.json.JSONObject; import org.kohsuke.stapler.HttpResponses.HttpResponseException; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; /** * {@link JSONObject} as a response. @@ -43,7 +43,7 @@ public JsonHttpResponse(Throwable t, int status) { } @Override - public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) + public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException { if (status > 0) { rsp.setStatus(status); diff --git a/core/src/main/java/org/kohsuke/stapler/json/JsonResponse.java b/core/src/main/java/org/kohsuke/stapler/json/JsonResponse.java index 136032874..1ec0eab54 100644 --- a/core/src/main/java/org/kohsuke/stapler/json/JsonResponse.java +++ b/core/src/main/java/org/kohsuke/stapler/json/JsonResponse.java @@ -1,5 +1,6 @@ package org.kohsuke.stapler.json; +import jakarta.servlet.ServletException; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -8,11 +9,10 @@ import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.ServletException; import net.sf.json.JSONObject; import org.kohsuke.stapler.HttpResponse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; @@ -35,7 +35,7 @@ class Handler extends Interceptor { private static final Logger logger = Logger.getLogger(Handler.class.getName()); @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { try { final Object r = target.invoke(request, response, instance, arguments); diff --git a/core/src/main/java/org/kohsuke/stapler/json/SubmittedForm.java b/core/src/main/java/org/kohsuke/stapler/json/SubmittedForm.java index 7e7c67b52..f42797a84 100644 --- a/core/src/main/java/org/kohsuke/stapler/json/SubmittedForm.java +++ b/core/src/main/java/org/kohsuke/stapler/json/SubmittedForm.java @@ -1,19 +1,19 @@ package org.kohsuke.stapler.json; +import jakarta.servlet.ServletException; import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.servlet.ServletException; import net.sf.json.JSONObject; import org.kohsuke.stapler.AnnotationHandler; import org.kohsuke.stapler.InjectedParameter; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; /** - * Binds {@linkplain StaplerRequest#getSubmittedForm() the submitted form} to a parameter of a web-bound method. + * Binds {@linkplain StaplerRequest2#getSubmittedForm() the submitted form} to a parameter of a web-bound method. * *

* On a web-bound {@code doXyz} method, use this annotation on a parameter to get the submitted @@ -35,7 +35,7 @@ public @interface SubmittedForm { class Handler extends AnnotationHandler { @Override - public Object parse(StaplerRequest request, Annotation a, Class type, String parameterName) + public Object parse(StaplerRequest2 request, Annotation a, Class type, String parameterName) throws ServletException { return request.getSubmittedForm(); } diff --git a/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessor.java b/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessor.java index 57810894e..52fcbfc16 100644 --- a/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessor.java +++ b/core/src/main/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessor.java @@ -3,8 +3,11 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import javax.annotation.processing.Processor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; @@ -37,8 +40,21 @@ public boolean process(Set annotations, RoundEnvironment } } + Map output = new HashMap<>(); for (ExecutableElement m : methods) { - write(m); + String paramNames = m.getParameters().stream() + .map(VariableElement::getSimpleName) + .collect(Collectors.joining(",")); + String existing = output.get(m.getSimpleName().toString()); + /* + * Allow multiple methods to have the same name but different argument types as long as the arguments + * have the same names. This allows deprecated StaplerRequest/StaplerResponse methods to coexist + * alongside non-deprecated StaplerRequest2/StaplerResponse2 methods. + */ + if (existing == null || !existing.equals(paramNames)) { + write(paramNames, m); + output.put(m.getSimpleName().toString(), paramNames); + } } } catch (IOException e) { error(e); @@ -59,22 +75,14 @@ public SourceVersion getSupportedSourceVersion() { * @param m * Method whose parameter has {@link QueryParameter} */ - private void write(ExecutableElement m) throws IOException { - StringBuilder buf = new StringBuilder(); - for (VariableElement p : m.getParameters()) { - if (!buf.isEmpty()) { - buf.append(','); - } - buf.append(p.getSimpleName()); - } - + private void write(String paramNames, ExecutableElement m) throws IOException { TypeElement t = (TypeElement) m.getEnclosingElement(); String name = t.getQualifiedName().toString().replace('.', '/') + "/" + m.getSimpleName() + ".stapler"; FileObject f = createResource(name); notice("Generating " + name, m); try (OutputStream os = f.openOutputStream()) { - os.write(buf.toString().getBytes(StandardCharsets.UTF_8)); + os.write(paramNames.getBytes(StandardCharsets.UTF_8)); } } } diff --git a/core/src/main/java/org/kohsuke/stapler/package-info.java b/core/src/main/java/org/kohsuke/stapler/package-info.java index 2ccc0942b..58ed54042 100644 --- a/core/src/main/java/org/kohsuke/stapler/package-info.java +++ b/core/src/main/java/org/kohsuke/stapler/package-info.java @@ -23,6 +23,6 @@ /** * Stapler {@code URL} → {@code Object} mapping framework. The main entry points are {@link Stapler}, - * {@link StaplerRequest}, and {@link StaplerResponse}. + * {@link StaplerRequest2}, and {@link StaplerResponse2}. */ package org.kohsuke.stapler; diff --git a/core/src/main/java/org/kohsuke/stapler/verb/HttpVerbInterceptor.java b/core/src/main/java/org/kohsuke/stapler/verb/HttpVerbInterceptor.java index 7dbf6b3ce..cca31a6c7 100644 --- a/core/src/main/java/org/kohsuke/stapler/verb/HttpVerbInterceptor.java +++ b/core/src/main/java/org/kohsuke/stapler/verb/HttpVerbInterceptor.java @@ -1,11 +1,11 @@ package org.kohsuke.stapler.verb; +import jakarta.servlet.ServletException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; -import javax.servlet.ServletException; import org.kohsuke.stapler.CancelRequestHandlingException; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.interceptor.Interceptor; import org.kohsuke.stapler.interceptor.InterceptorAnnotation; @@ -42,7 +42,7 @@ */ public class HttpVerbInterceptor extends Interceptor { @Override - public Object invoke(StaplerRequest request, StaplerResponse response, Object instance, Object[] arguments) + public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) throws IllegalAccessException, InvocationTargetException, ServletException { if (matches(request)) { return target.invoke(request, response, instance, arguments); @@ -51,7 +51,7 @@ public Object invoke(StaplerRequest request, StaplerResponse response, Object in } } - private boolean matches(StaplerRequest request) { + private boolean matches(StaplerRequest2 request) { String method = request.getMethod(); for (Annotation a : target.getAnnotations()) { diff --git a/core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java b/core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java index e6da4b47b..2d5beecf5 100644 --- a/core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java +++ b/core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java @@ -1,10 +1,10 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletConfig; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.util.ArrayList; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; import org.kohsuke.stapler.test.AbstractStaplerTest; import org.mockito.Mockito; diff --git a/core/src/test/java/org/kohsuke/stapler/AncestorImplTest.java b/core/src/test/java/org/kohsuke/stapler/AncestorImplTest.java index dc29e2c5c..a3ce90f4f 100644 --- a/core/src/test/java/org/kohsuke/stapler/AncestorImplTest.java +++ b/core/src/test/java/org/kohsuke/stapler/AncestorImplTest.java @@ -15,7 +15,7 @@ class Foo { } class Bar { - public HttpResponse doZot(StaplerRequest req) { + public HttpResponse doZot(StaplerRequest2 req) { assertEquals("testRestOfUrl/bar/zot", req.getAncestors().get(0).getRestOfUrl()); assertEquals("bar/zot", req.getAncestors().get(1).getRestOfUrl()); assertEquals("zot", req.getAncestors().get(2).getRestOfUrl()); diff --git a/core/src/test/java/org/kohsuke/stapler/ClassDescriptorTest.java b/core/src/test/java/org/kohsuke/stapler/ClassDescriptorTest.java index ef1d31d9b..311c73bae 100644 --- a/core/src/test/java/org/kohsuke/stapler/ClassDescriptorTest.java +++ b/core/src/test/java/org/kohsuke/stapler/ClassDescriptorTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; +import jakarta.servlet.ServletException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -12,7 +13,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import javax.servlet.ServletException; import org.junit.Test; /** @@ -97,7 +97,7 @@ public void inheritedWebMethods() { new ClassDescriptor(Sub.class) .methods .name("doDynamic") - .signature(StaplerRequest.class, StaplerResponse.class) + .signature(StaplerRequest2.class, StaplerResponse2.class) .size()); } @@ -117,7 +117,7 @@ private void methodWithManyParams( private static void methodWithParams_static(String abc, long def, Object ghi) {} protected abstract static class Super { - public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {} + public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {} } public static class Sub extends Super {} diff --git a/core/src/test/java/org/kohsuke/stapler/DataBindingTest.java b/core/src/test/java/org/kohsuke/stapler/DataBindingTest.java index 2f44fa16e..b739eadb8 100644 --- a/core/src/test/java/org/kohsuke/stapler/DataBindingTest.java +++ b/core/src/test/java/org/kohsuke/stapler/DataBindingTest.java @@ -81,14 +81,14 @@ public String getContentType() { mr.getParameterMap().put("b", "string"); RequestImpl req = new RequestImpl(new Stapler(), mr, Collections.emptyList(), null); new Function.InstanceFunction( - getClass().getMethod("doFromStaplerMethod", StaplerRequest.class, int.class, Binder.class)) + getClass().getMethod("doFromStaplerMethod", StaplerRequest2.class, int.class, Binder.class)) .bindAndInvoke(this, req, null); assertEquals( 42, new Function.InstanceFunction(getClass().getMethod("doStaticMethod")).bindAndInvoke(this, req, null)); } - public void doFromStaplerMethod(StaplerRequest req, @QueryParameter int a, Binder b) { + public void doFromStaplerMethod(StaplerRequest2 req, @QueryParameter int a, Binder b) { assertEquals(123, a); assertSame(req, b.req); assertEquals("string", b.b); @@ -99,11 +99,11 @@ public static int doStaticMethod() { } public static class Binder { - StaplerRequest req; + StaplerRequest2 req; String b; @CapturedParameterNames({"req", "b"}) - public static Binder fromStapler(StaplerRequest req, @QueryParameter String b) { + public static Binder fromStapler(StaplerRequest2 req, @QueryParameter String b) { Binder r = new Binder(); r.req = req; r.b = b; diff --git a/core/src/test/java/org/kohsuke/stapler/DispatcherTest.java b/core/src/test/java/org/kohsuke/stapler/DispatcherTest.java index d115508ba..08b0aa9a7 100644 --- a/core/src/test/java/org/kohsuke/stapler/DispatcherTest.java +++ b/core/src/test/java/org/kohsuke/stapler/DispatcherTest.java @@ -1,9 +1,9 @@ package org.kohsuke.stapler; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; -import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.HttpMethod; @@ -201,17 +201,17 @@ public void testInheritance() throws Exception { public abstract class PutInheritance { @WebMethod(name = "foo") @PUT - public abstract HttpResponse doBar(StaplerRequest req) throws IOException; + public abstract HttpResponse doBar(StaplerRequest2 req) throws IOException; @POST - public HttpResponse doAcme(StaplerRequest req) throws IOException { + public HttpResponse doAcme(StaplerRequest2 req) throws IOException { return HttpResponses.text("POST: " + IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8)); } } public class PutInheritanceImpl extends PutInheritance { @Override - public HttpResponse doBar(StaplerRequest req) throws IOException { + public HttpResponse doBar(StaplerRequest2 req) throws IOException { return HttpResponses.text(IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8) + " World!"); } } @@ -324,7 +324,7 @@ public void testRequirePostOnBase() throws Exception { public void testOverloads() throws Exception { TextPage p = createWebClient().getPage(new URL(url, "overloaded/x")); - assertEquals("doX(StaplerRequest)", p.getContent()); + assertEquals("doX(StaplerRequest2)", p.getContent()); } public final Object overloaded = new Overloaded(); @@ -335,16 +335,16 @@ public HttpResponse doX() { return HttpResponses.text("doX()"); } - public HttpResponse doX(StaplerRequest req) { - return HttpResponses.text("doX(StaplerRequest)"); + public HttpResponse doX(StaplerRequest2 req) { + return HttpResponses.text("doX(StaplerRequest2)"); } - public HttpResponse doX(StaplerResponse rsp) { - return HttpResponses.text("doX(StaplerResponse)"); + public HttpResponse doX(StaplerResponse2 rsp) { + return HttpResponses.text("doX(StaplerResponse2)"); } - public HttpResponse doX(StaplerRequest req, StaplerResponse rsp) { - return HttpResponses.text("doX(StaplerRequest, StaplerResponse)"); + public HttpResponse doX(StaplerRequest2 req, StaplerResponse2 rsp) { + return HttpResponses.text("doX(StaplerRequest2, StaplerResponse2)"); } @WebMethod(name = "x") @@ -414,7 +414,7 @@ private TestClass getPrivate() { public final StaplerProxyImpl staplerProxyFail = new StaplerProxyImpl(null); public class IndexPage { - public void doIndex(StaplerResponse rsp) { + public void doIndex(StaplerResponse2 rsp) { throw HttpResponses.ok(); } } @@ -433,7 +433,7 @@ public Object getTarget() { return target; } - public void doIndex(StaplerResponse rsp) { + public void doIndex(StaplerResponse2 rsp) { if (target != this) { throw new IllegalStateException("should not be called"); } diff --git a/core/src/test/java/org/kohsuke/stapler/IndexHtmlDispatcherTest.java b/core/src/test/java/org/kohsuke/stapler/IndexHtmlDispatcherTest.java index 11138e777..37c787fa5 100644 --- a/core/src/test/java/org/kohsuke/stapler/IndexHtmlDispatcherTest.java +++ b/core/src/test/java/org/kohsuke/stapler/IndexHtmlDispatcherTest.java @@ -5,8 +5,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import jakarta.servlet.ServletContext; import java.net.MalformedURLException; -import javax.servlet.ServletContext; import org.junit.Test; import org.jvnet.hudson.test.Issue; diff --git a/core/src/test/java/org/kohsuke/stapler/MockRequest.java b/core/src/test/java/org/kohsuke/stapler/MockRequest.java index 06dbaffcb..f1bbc8c2d 100644 --- a/core/src/test/java/org/kohsuke/stapler/MockRequest.java +++ b/core/src/test/java/org/kohsuke/stapler/MockRequest.java @@ -1,5 +1,19 @@ package org.kohsuke.stapler; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import jakarta.servlet.http.HttpUpgradeHandler; +import jakarta.servlet.http.Part; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -9,20 +23,6 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpUpgradeHandler; -import javax.servlet.http.Part; /** * @author Kohsuke Kawaguchi diff --git a/core/src/test/java/org/kohsuke/stapler/MockServletContext.java b/core/src/test/java/org/kohsuke/stapler/MockServletContext.java index c7d6650ea..ceff626fd 100644 --- a/core/src/test/java/org/kohsuke/stapler/MockServletContext.java +++ b/core/src/test/java/org/kohsuke/stapler/MockServletContext.java @@ -1,5 +1,16 @@ package org.kohsuke.stapler; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterRegistration; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.Servlet; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRegistration; +import jakarta.servlet.ServletRegistration.Dynamic; +import jakarta.servlet.SessionCookieConfig; +import jakarta.servlet.SessionTrackingMode; +import jakarta.servlet.descriptor.JspConfigDescriptor; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; @@ -7,17 +18,6 @@ import java.util.EventListener; import java.util.Map; import java.util.Set; -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.ServletRegistration.Dynamic; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; /** * @author Kohsuke Kawaguchi @@ -190,17 +190,18 @@ public ServletRegistration getServletRegistration(String servletName) { } @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, String className) { + public jakarta.servlet.FilterRegistration.Dynamic addFilter(String filterName, String className) { return null; } @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + public jakarta.servlet.FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { return null; } @Override - public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { + public jakarta.servlet.FilterRegistration.Dynamic addFilter( + String filterName, Class filterClass) { // TODO Auto-generated method stub return null; } diff --git a/core/src/test/java/org/kohsuke/stapler/NestedJsonTest.java b/core/src/test/java/org/kohsuke/stapler/NestedJsonTest.java index 0a0cf39d7..efe11b29d 100644 --- a/core/src/test/java/org/kohsuke/stapler/NestedJsonTest.java +++ b/core/src/test/java/org/kohsuke/stapler/NestedJsonTest.java @@ -1,8 +1,8 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletException; import java.util.Collections; import java.util.List; -import javax.servlet.ServletException; import junit.framework.TestCase; import net.sf.json.JSONArray; import net.sf.json.JSONObject; diff --git a/core/src/test/java/org/kohsuke/stapler/RequestImplTest.java b/core/src/test/java/org/kohsuke/stapler/RequestImplTest.java index a8062b735..20122dfdf 100644 --- a/core/src/test/java/org/kohsuke/stapler/RequestImplTest.java +++ b/core/src/test/java/org/kohsuke/stapler/RequestImplTest.java @@ -25,6 +25,11 @@ package org.kohsuke.stapler; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -34,11 +39,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.List; -import javax.servlet.ReadListener; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; import net.sf.json.JSONObject; import org.apache.commons.fileupload2.core.FileItem; import org.apache.http.entity.ContentType; diff --git a/core/src/test/java/org/kohsuke/stapler/ResponseImplTest.java b/core/src/test/java/org/kohsuke/stapler/ResponseImplTest.java index 6a8272d52..622326acc 100644 --- a/core/src/test/java/org/kohsuke/stapler/ResponseImplTest.java +++ b/core/src/test/java/org/kohsuke/stapler/ResponseImplTest.java @@ -3,10 +3,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.test.AbstractStaplerTest; /** diff --git a/core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java b/core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java index 6c1f4b9f2..d951a3226 100644 --- a/core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java +++ b/core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java @@ -1,8 +1,8 @@ package org.kohsuke.stapler; +import jakarta.servlet.ServletConfig; +import jakarta.servlet.ServletContext; import java.util.Enumeration; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; /** * @author Kohsuke Kawaguchi diff --git a/core/src/test/java/org/kohsuke/stapler/Stapler2Test.java b/core/src/test/java/org/kohsuke/stapler/Stapler2Test.java index 3bc8bbd2d..655cb395f 100644 --- a/core/src/test/java/org/kohsuke/stapler/Stapler2Test.java +++ b/core/src/test/java/org/kohsuke/stapler/Stapler2Test.java @@ -28,8 +28,8 @@ import static org.junit.Assert.assertThrows; +import jakarta.servlet.http.HttpServletResponse; import java.net.URL; -import javax.servlet.http.HttpServletResponse; import org.htmlunit.FailingHttpStatusCodeException; import org.htmlunit.WebClient; import org.jvnet.hudson.test.For; diff --git a/core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java b/core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java index 9813670cf..9c86b1acd 100644 --- a/core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java +++ b/core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java @@ -4,7 +4,7 @@ import java.net.URL; import org.htmlunit.TextPage; import org.kohsuke.stapler.HttpResponse; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.test.JettyTestCase; /** @@ -32,7 +32,7 @@ public HelloWorld(String message) { this.message = message; } - public void doIndex(StaplerResponse rsp) throws IOException { + public void doIndex(StaplerResponse2 rsp) throws IOException { rsp.setContentType("text/plain;charset=UTF-8"); rsp.getWriter().write(message); } diff --git a/core/src/test/java/org/kohsuke/stapler/bind/JavaScriptProxyTest.java b/core/src/test/java/org/kohsuke/stapler/bind/JavaScriptProxyTest.java index 63d450aac..17815c041 100644 --- a/core/src/test/java/org/kohsuke/stapler/bind/JavaScriptProxyTest.java +++ b/core/src/test/java/org/kohsuke/stapler/bind/JavaScriptProxyTest.java @@ -9,8 +9,8 @@ import org.htmlunit.html.HtmlPage; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.test.JettyTestCase; @@ -72,7 +72,7 @@ public String jsFoo(int x, String y) { return y + x; } - public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException { + public void doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException { rsp.setContentType("text/html"); String crumb = req.getWebApp().getCrumbIssuer().issueCrumb(); PrintWriter w = rsp.getWriter(); @@ -83,7 +83,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException w.println(""); } - public void doBindAnonymous(StaplerResponse rsp) throws IOException { + public void doBindAnonymous(StaplerResponse2 rsp) throws IOException { rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); w.println(""); diff --git a/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest.java b/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest.java index 68165c02e..9293bdb28 100644 --- a/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest.java +++ b/core/src/test/java/org/kohsuke/stapler/interceptor/JsonOutputFilterTest.java @@ -14,7 +14,7 @@ import org.htmlunit.html.HtmlPage; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.bind.JavaScriptMethod; import org.kohsuke.stapler.test.JettyTestCase; @@ -114,7 +114,7 @@ public MyData getSomeIncludedData() { return new MyData("Bob", "the builder", "super secret value"); } - public void doIndex(StaplerResponse rsp) throws IOException { + public void doIndex(StaplerResponse2 rsp) throws IOException { rsp.setContentType("text/html"); PrintWriter w = rsp.getWriter(); w.println(""); diff --git a/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessorTest.java b/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessorTest.java index 2768ae035..fb666bfe4 100644 --- a/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessorTest.java +++ b/core/src/test/java/org/kohsuke/stapler/jsr269/QueryParameterAnnotationProcessorTest.java @@ -40,6 +40,30 @@ void basicOutput(Results results) { assertEquals("name,address", Utils.getGeneratedResource(results.sources, "some/pkg/Stuff/doAnother.stapler")); } + @Inline( + name = "some.pkg.Stuff", + source = { + "package some.pkg;", + "import org.kohsuke.stapler.QueryParameter;", + "import org.kohsuke.stapler.StaplerRequest;", + "import org.kohsuke.stapler.StaplerResponse;", + "import org.kohsuke.stapler.StaplerRequest2;", + "import org.kohsuke.stapler.StaplerResponse2;", + "public class Stuff {", + " public void doBuild(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter int delay) {}", + " @Deprecated", + " public void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter int delay) {}", + "}" + }) + @Test + void deprecated(Results results) { + Set diagnostics = results.diagnostics.stream() + .map(d -> d.getMessage(Locale.ENGLISH)) + .collect(Collectors.toSet()); + assertEquals(Set.of("Generating some/pkg/Stuff/doBuild.stapler"), diagnostics); + assertEquals("req,rsp,delay", Utils.getGeneratedResource(results.sources, "some/pkg/Stuff/doBuild.stapler")); + } + // TODO nested classes use qualified rather than binary name } diff --git a/core/src/test/java/org/kohsuke/stapler/test/JettyTestCase.java b/core/src/test/java/org/kohsuke/stapler/test/JettyTestCase.java index 0041f9c92..9b32c3b6c 100644 --- a/core/src/test/java/org/kohsuke/stapler/test/JettyTestCase.java +++ b/core/src/test/java/org/kohsuke/stapler/test/JettyTestCase.java @@ -1,15 +1,15 @@ package org.kohsuke.stapler.test; +import jakarta.servlet.ServletContext; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.nio.charset.Charset; -import javax.servlet.ServletContext; import junit.framework.TestCase; -import org.eclipse.jetty.ee8.servlet.ServletContextHandler; -import org.eclipse.jetty.ee8.servlet.ServletHolder; -import org.eclipse.jetty.ee8.webapp.WebAppContext; +import org.eclipse.jetty.ee9.servlet.ServletContextHandler; +import org.eclipse.jetty.ee9.servlet.ServletHolder; +import org.eclipse.jetty.ee9.webapp.WebAppContext; import org.eclipse.jetty.http.UriCompliance; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; diff --git a/docs/getting-started.adoc b/docs/getting-started.adoc index 9b68f37e0..46221d5cc 100644 --- a/docs/getting-started.adoc +++ b/docs/getting-started.adoc @@ -29,7 +29,7 @@ Stapler needs to know the root object of your application. It does that by `ServletContext.getAttribute("app")`, so your application needs to set the root object into a ServletContext. The easiest to do that is to write a -http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContextListener.html[`ServletContextListener`] +https://jakarta.ee/specifications/servlet/5.0/apidocs/jakarta/servlet/ServletContextListener.html[`ServletContextListener`] and use the helper method from `Stapler`. Specifically, you write the following class: @@ -184,7 +184,7 @@ Action methods take the following signature: [source,java] ---- -public void do[Name]( StaplerRequest request, StaplerResponse response ) { +public void do[Name]( StaplerRequest2 request, StaplerResponse2 response ) { ... } ---- @@ -198,12 +198,12 @@ In our example, we define an action method called "hello" in like servlets, you can serve the request from this action method (perhaps by sending the contents out or redirecting clients) in exactly the same way as you'd do in servlets. In the following example, we use a -method on `StaplerResponse` to forward to another side JSP file to +method on `StaplerResponse2` to forward to another side JSP file to generate the response. [source,java] ---- -public void doHello( StaplerRequest request, StaplerResponse response ) { +public void doHello( StaplerRequest2 request, StaplerResponse2 response ) { ... response.forward(this,"helloJSP",request); } diff --git a/docs/jelly-taglib-ref.adoc b/docs/jelly-taglib-ref.adoc index 78d9541c0..7db439b57 100644 --- a/docs/jelly-taglib-ref.adoc +++ b/docs/jelly-taglib-ref.adoc @@ -123,7 +123,7 @@ Sends HTTP redirect. |Attribute Name |Type |Description |url (required) |String |Sets the target URL to redirect to. This just gets passed to -org.kohsuke.stapler.StaplerResponse.sendRedirect2(String). +org.kohsuke.stapler.StaplerResponse2.sendRedirect2(String). |=== This tag does not accept any child elements/text. diff --git a/docs/reference.adoc b/docs/reference.adoc index ef65c98a4..cb21f19b3 100644 --- a/docs/reference.adoc +++ b/docs/reference.adoc @@ -152,7 +152,7 @@ If `url` is "/fooBar/..." and `node` has a public getter method named evaluated against the rest of the URL. Stapler also looks for the public getter of the form -"getXxxx(StaplerRequest)". If such a method exists, then this getter +"getXxxx(StaplerRequest2)". If such a method exists, then this getter method is invoked in a similar way. This version allows the get method to take sophisticated action based on the current request (such as returning the object specific to the current user, or returning null if @@ -234,7 +234,7 @@ ____ ==== Dynamic Getter Method If the current object has a public method -`getDynamic(String,StaplerRequest,StaplerResponse)`, and the URL is +`getDynamic(String,StaplerRequest2,StaplerResponse2)`, and the URL is "/xxxx/..." and then this method is invoked with "xxxx" as the first parameter. The object returned from this method will be evaluated against the rest of the URL "/...." recursively. @@ -253,9 +253,9 @@ ____ ==== Dynamic Action Method If the current object has a public "action" method -`doDynamic(StaplerRequest,StaplerResponse)`, then this method is +`doDynamic(StaplerRequest2,StaplerResponse2)`, then this method is invoked. From within this method, the rest of the URL can be accessed by -`StaplerRequest.getRestOfPath()`. This is convenient for an object that +`StaplerRequest2.getRestOfPath()`. This is convenient for an object that wants to control the URL mapping entirely on its own. The action method is the final consumer of the request. diff --git a/docs/taglib-jelly.xsd b/docs/taglib-jelly.xsd index c84b5fd7f..7e1aa7e44 100644 --- a/docs/taglib-jelly.xsd +++ b/docs/taglib-jelly.xsd @@ -147,7 +147,7 @@ Sets the target URL to redirect to. This just gets passed - to org.kohsuke.stapler.StaplerResponse.sendRedirect2(String). + to org.kohsuke.stapler.StaplerResponse2.sendRedirect2(String). diff --git a/docs/taglib.xsd b/docs/taglib.xsd index 449b0c8ff..0b6625fbc 100644 --- a/docs/taglib.xsd +++ b/docs/taglib.xsd @@ -80,7 +80,7 @@ Kohsuke Kawaguchi Sets the target URL to redirect to. This just gets passed - to org.kohsuke.stapler.StaplerResponse.sendRedirect2(String). + to org.kohsuke.stapler.StaplerResponse2.sendRedirect2(String). diff --git a/groovy/pom.xml b/groovy/pom.xml index 2a11b1198..521dafffa 100644 --- a/groovy/pom.xml +++ b/groovy/pom.xml @@ -30,7 +30,7 @@ jakarta.servlet jakarta.servlet-api - 4.0.4 + 5.0.0 provided diff --git a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyClassTearOff.java b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyClassTearOff.java index bde246739..f0592bede 100644 --- a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyClassTearOff.java +++ b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyClassTearOff.java @@ -23,9 +23,9 @@ package org.kohsuke.stapler.jelly.groovy; +import jakarta.servlet.RequestDispatcher; import java.io.IOException; import java.net.URL; -import javax.servlet.RequestDispatcher; import org.apache.commons.jelly.Script; import org.kohsuke.stapler.AbstractTearOff; import org.kohsuke.stapler.MetaClass; diff --git a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyFacet.java b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyFacet.java index a6c828bf0..4987a6285 100644 --- a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyFacet.java +++ b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyFacet.java @@ -23,13 +23,13 @@ package org.kohsuke.stapler.jelly.groovy; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.ServletException; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.logging.Level; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; import org.apache.commons.jelly.JellyException; import org.kohsuke.MetaInfServices; import org.kohsuke.stapler.Dispatcher; diff --git a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyServerPageTearOff.java b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyServerPageTearOff.java index 45093b6bf..a38d401cc 100644 --- a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyServerPageTearOff.java +++ b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/GroovyServerPageTearOff.java @@ -1,8 +1,8 @@ package org.kohsuke.stapler.jelly.groovy; +import jakarta.servlet.RequestDispatcher; import java.io.IOException; import java.net.URL; -import javax.servlet.RequestDispatcher; import org.kohsuke.stapler.AbstractTearOff; import org.kohsuke.stapler.MetaClass; import org.kohsuke.stapler.jelly.JellyRequestDispatcher; diff --git a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/JellyBuilder.java b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/JellyBuilder.java index e25f54812..1745fb964 100644 --- a/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/JellyBuilder.java +++ b/groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/JellyBuilder.java @@ -29,13 +29,13 @@ import groovy.lang.MissingMethodException; import groovy.lang.MissingPropertyException; import groovy.xml.QName; +import jakarta.servlet.ServletContext; import java.io.IOException; import java.net.URL; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import javax.servlet.ServletContext; import org.apache.commons.beanutils.ConvertingWrapDynaBean; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.DynaProperty; @@ -56,8 +56,8 @@ import org.dom4j.io.SAXContentHandler; import org.kohsuke.stapler.MetaClassLoader; import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.framework.adjunct.AdjunctManager; import org.kohsuke.stapler.framework.adjunct.AdjunctsInPage; import org.kohsuke.stapler.framework.adjunct.NoSuchAdjunctException; @@ -97,8 +97,8 @@ protected GroovyClosureScript computeValue(Class type) { } }; - private final StaplerRequest request; - private StaplerResponse response; + private final StaplerRequest2 request; + private StaplerResponse2 response; private String rootURL; private final AdjunctManager adjunctManager; @@ -110,7 +110,7 @@ protected GroovyClosureScript computeValue(Class type) { public JellyBuilder(JellyContext context, XMLOutput output) { this.context = context; this.output = output; - this.request = Stapler.getCurrentRequest(); + this.request = Stapler.getCurrentRequest2(); this.adjunctManager = AdjunctManager.get(request.getServletContext()); } @@ -639,13 +639,13 @@ public ServletContext getServletContext() { return getRequest().getServletContext(); } - public StaplerRequest getRequest() { + public StaplerRequest2 getRequest() { return request; } - public StaplerResponse getResponse() { + public StaplerResponse2 getResponse() { if (response == null) { - response = Stapler.getCurrentResponse(); + response = Stapler.getCurrentResponse2(); } return response; } @@ -657,7 +657,7 @@ public JellyBuilder getBuilder() { /** * Gets the absolute URL to the top of the webapp. * - * @see StaplerRequest#getContextPath() + * @see StaplerRequest2#getContextPath() */ public String getRootURL() { if (rootURL == null) { diff --git a/jelly/pom.xml b/jelly/pom.xml index 4cf07fb05..9c989c7ae 100644 --- a/jelly/pom.xml +++ b/jelly/pom.xml @@ -12,7 +12,7 @@ Jelly binding for Stapler - 1.1-jenkins-20240510 + 1.1-jenkins-20240903 137.v803fea_a_fb_c75 @@ -48,7 +48,7 @@ jakarta.servlet jakarta.servlet-api - 4.0.4 + 5.0.0 provided @@ -71,13 +71,13 @@ test - org.eclipse.jetty.ee8 - jetty-ee8-servlet + org.eclipse.jetty.ee9 + jetty-ee9-servlet test - org.eclipse.jetty.ee8 - jetty-ee8-webapp + org.eclipse.jetty.ee9 + jetty-ee9-webapp test diff --git a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/Adjunct.java b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/Adjunct.java index 5868e8f7c..f99fe7d5b 100644 --- a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/Adjunct.java +++ b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/Adjunct.java @@ -39,7 +39,7 @@ import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.MetaClassLoader; import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff; import org.kohsuke.stapler.jelly.JellyFacet; @@ -133,14 +133,14 @@ public Adjunct(AdjunctManager manager, String name, final ClassLoader classLoade * Useful as a basis to refer to other resources. */ public String getPackageUrl() { - return getPackageUrl(Stapler.getCurrentRequest()); + return getPackageUrl(Stapler.getCurrentRequest2()); } - private String getPackageUrl(StaplerRequest req) { + private String getPackageUrl(StaplerRequest2 req) { return req.getContextPath() + '/' + manager.rootURL + '/' + packageName; } - private String getBaseName(StaplerRequest req) { + private String getBaseName(StaplerRequest2 req) { return req.getContextPath() + '/' + manager.rootURL + '/' + slashedName; } @@ -200,7 +200,7 @@ public boolean has(Kind k) { } } - public void write(StaplerRequest req, XMLOutput out) throws SAXException, IOException { + public void write(StaplerRequest2 req, XMLOutput out) throws SAXException, IOException { if (inclusionFragment != null) { out.write(inclusionFragment); return; @@ -210,7 +210,7 @@ public void write(StaplerRequest req, XMLOutput out) throws SAXException, IOExce WebApp.getCurrent() .getFacet(JellyFacet.class) .scriptInvoker - .invokeScript(req, Stapler.getCurrentResponse(), script, this, out); + .invokeScript(req, Stapler.getCurrentResponse2(), script, this, out); } catch (JellyTagException e) { throw new IOException("Failed to execute Jelly script for adjunct " + name, e); } diff --git a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManager.java b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManager.java index 3131a89be..04bab4644 100644 --- a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManager.java +++ b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctManager.java @@ -23,17 +23,17 @@ package org.kohsuke.stapler.framework.adjunct; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URL; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.MetaClass; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.WebApp; /** @@ -115,7 +115,7 @@ public AdjunctManager(ServletContext context, ClassLoader classLoader, String ro * @param rootURL * See {@link #rootURL} for the meaning of this parameter. * @param expiration milliseconds from service time until expiration, for {@link #doDynamic} - * (as in {@link StaplerResponse#serveFile(StaplerRequest, URL, long)}); + * (as in {@link StaplerResponse2#serveFile(StaplerRequest2, URL, long)}); * if {@link #rootURL} is unique per session then this can be very long; * otherwise a day might be reasonable */ @@ -160,7 +160,7 @@ public Adjunct get(String name) throws IOException { /** * Serves resources in the class loader. */ - public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { + public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException { String path = req.getRestOfPath(); if (path.isEmpty()) { throw HttpResponses.error( diff --git a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPage.java b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPage.java index 3613c12ce..cfada524b 100644 --- a/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPage.java +++ b/jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/AdjunctsInPage.java @@ -35,7 +35,7 @@ import java.util.logging.Logger; import org.apache.commons.jelly.XMLOutput; import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerRequest2; import org.xml.sax.SAXException; /** @@ -56,23 +56,23 @@ public class AdjunctsInPage { */ private final List pending = new ArrayList<>(); - private final StaplerRequest request; + private final StaplerRequest2 request; /** - * Obtains the instance associated with the current request of the given {@link StaplerRequest}. + * Obtains the instance associated with the current request of the given {@link StaplerRequest2}. */ public static AdjunctsInPage get() { - return get(Stapler.getCurrentRequest()); + return get(Stapler.getCurrentRequest2()); } /** - * Obtains the instance associated with the current request of the given {@link StaplerRequest}. + * Obtains the instance associated with the current request of the given {@link StaplerRequest2}. * *

* This method is handy when the caller already have the request object around, - * so that we can save {@link Stapler#getCurrentRequest()} call. + * so that we can save {@link Stapler#getCurrentRequest2()} call. */ - public static AdjunctsInPage get(StaplerRequest request) { + public static AdjunctsInPage get(StaplerRequest2 request) { AdjunctsInPage aip = (AdjunctsInPage) request.getAttribute(KEY); if (aip == null) { request.setAttribute( @@ -81,7 +81,7 @@ public static AdjunctsInPage get(StaplerRequest request) { return aip; } - private AdjunctsInPage(AdjunctManager manager, StaplerRequest request) { + private AdjunctsInPage(AdjunctManager manager, StaplerRequest2 request) { this.manager = manager; this.request = request; } diff --git a/jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java b/jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java index 22e3595ad..bb0a2c2b9 100644 --- a/jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java +++ b/jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java @@ -23,9 +23,9 @@ package org.kohsuke.stapler.jelly; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.jelly.TagSupport; /** @@ -34,11 +34,11 @@ abstract class AbstractStaplerTag extends TagSupport { protected HttpServletRequest getRequest() { - return (HttpServletRequest) getContext().getVariable("request"); + return (HttpServletRequest) getContext().getVariable("request2"); } protected HttpServletResponse getResponse() { - return (HttpServletResponse) getContext().getVariable("response"); + return (HttpServletResponse) getContext().getVariable("response2"); } protected ServletContext getServletContext() { diff --git a/jelly/src/main/java/org/kohsuke/stapler/jelly/BindTag.java b/jelly/src/main/java/org/kohsuke/stapler/jelly/BindTag.java index 7fa5a5c62..6adb8b319 100644 --- a/jelly/src/main/java/org/kohsuke/stapler/jelly/BindTag.java +++ b/jelly/src/main/java/org/kohsuke/stapler/jelly/BindTag.java @@ -28,6 +28,8 @@ import org.apache.commons.jelly.XMLOutput; import org.jvnet.maven.jellydoc.annotation.NoContent; import org.jvnet.maven.jellydoc.annotation.Required; +import org.kohsuke.stapler.StaplerRequest2; +import org.kohsuke.stapler.StaplerResponse2; import org.kohsuke.stapler.WebApp; import org.kohsuke.stapler.bind.Bound; import org.kohsuke.stapler.bind.BoundObjectTable; @@ -111,7 +113,7 @@ public void doTag(XMLOutput out) throws JellyTagException { /** * Writes a {@code