├── .git-blame-ignore-revs ├── .github ├── dependabot.yml ├── release-drafter.yml └── workflows │ └── cd.yaml ├── .gitignore ├── .mvn ├── extensions.xml └── maven.config ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE.txt ├── README.md ├── core ├── LICENSE.txt ├── TODO ├── example │ ├── WEB-INF │ │ ├── lib │ │ │ ├── jstl.jar │ │ │ └── standard.jar │ │ ├── side-files │ │ │ └── example │ │ │ │ ├── Book │ │ │ │ └── index.jsp │ │ │ │ ├── BookStore │ │ │ │ ├── count.jsp │ │ │ │ ├── helloJSP.jsp │ │ │ │ ├── index.jsp │ │ │ │ └── logo.png │ │ │ │ ├── CD │ │ │ │ └── index.jsp │ │ │ │ ├── Item │ │ │ │ └── footer.jsp │ │ │ │ └── Track │ │ │ │ └── index.jsp │ │ └── web.xml │ ├── build.xml │ ├── example.iml │ ├── resources │ │ └── help │ │ │ └── help.html │ └── src │ │ └── example │ │ ├── Book.java │ │ ├── BookStore.java │ │ ├── CD.java │ │ ├── Item.java │ │ ├── Track.java │ │ └── WebAppMain.java ├── maven-example │ ├── META-INF │ │ └── MANIFEST.MF │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── example │ │ │ ├── Book.java │ │ │ ├── BookStore.java │ │ │ ├── CD.java │ │ │ ├── Item.java │ │ │ ├── Track.java │ │ │ └── WebAppMain.java │ │ └── webapp │ │ ├── WEB-INF │ │ ├── side-files │ │ │ └── example │ │ │ │ ├── Book │ │ │ │ └── index.jsp │ │ │ │ ├── BookStore │ │ │ │ ├── count.jsp │ │ │ │ ├── helloJSP.jsp │ │ │ │ ├── index.jsp │ │ │ │ └── logo.png │ │ │ │ ├── CD │ │ │ │ └── index.jsp │ │ │ │ ├── Item │ │ │ │ └── footer.jsp │ │ │ │ └── Track │ │ │ │ └── index.jsp │ │ └── web.xml │ │ └── help │ │ └── help.html ├── pom.xml ├── ref │ └── j2ee │ │ └── package-list ├── release.sh └── src │ ├── main │ ├── java │ │ ├── io │ │ │ └── jenkins │ │ │ │ └── servlet │ │ │ │ ├── AsyncContextWrapper.java │ │ │ │ ├── AsyncEventWrapper.java │ │ │ │ ├── AsyncListenerWrapper.java │ │ │ │ ├── DispatcherTypeWrapper.java │ │ │ │ ├── FilterChainWrapper.java │ │ │ │ ├── FilterConfigWrapper.java │ │ │ │ ├── FilterRegistrationDynamicWrapper.java │ │ │ │ ├── FilterRegistrationWrapper.java │ │ │ │ ├── FilterWrapper.java │ │ │ │ ├── ReadListenerWrapper.java │ │ │ │ ├── RegistrationDynamicWrapper.java │ │ │ │ ├── RegistrationWrapper.java │ │ │ │ ├── RequestDispatcherWrapper.java │ │ │ │ ├── ServletConfigWrapper.java │ │ │ │ ├── ServletContextEventWrapper.java │ │ │ │ ├── ServletContextWrapper.java │ │ │ │ ├── ServletExceptionWrapper.java │ │ │ │ ├── ServletInputStreamWrapper.java │ │ │ │ ├── ServletOutputStreamWrapper.java │ │ │ │ ├── ServletRegistrationDynamicWrapper.java │ │ │ │ ├── ServletRegistrationWrapper.java │ │ │ │ ├── ServletRequestWrapper.java │ │ │ │ ├── ServletResponseWrapper.java │ │ │ │ ├── ServletWrapper.java │ │ │ │ ├── SessionCookieConfigWrapper.java │ │ │ │ ├── SessionTrackingModeWrapper.java │ │ │ │ ├── WriteListenerWrapper.java │ │ │ │ ├── descriptor │ │ │ │ ├── JspConfigDescriptorWrapper.java │ │ │ │ ├── JspPropertyGroupDescriptorWrapper.java │ │ │ │ └── TaglibDescriptorWrapper.java │ │ │ │ ├── http │ │ │ │ ├── CookieWrapper.java │ │ │ │ ├── HttpServletMappingWrapper.java │ │ │ │ ├── HttpServletRequestWrapper.java │ │ │ │ ├── HttpServletResponseWrapper.java │ │ │ │ ├── HttpSessionContextWrapper.java │ │ │ │ ├── HttpSessionEventWrapper.java │ │ │ │ ├── HttpSessionWrapper.java │ │ │ │ ├── MappingMatchWrapper.java │ │ │ │ └── PartWrapper.java │ │ │ │ └── package-info.java │ │ └── org │ │ │ ├── apache │ │ │ └── commons │ │ │ │ └── fileupload │ │ │ │ ├── FileItem.java │ │ │ │ ├── FileItemHeaders.java │ │ │ │ └── InvalidFileNameException.java │ │ │ └── kohsuke │ │ │ └── stapler │ │ │ ├── AbstractTearOff.java │ │ │ ├── AcceptHeader.java │ │ │ ├── Ancestor.java │ │ │ ├── AncestorImpl.java │ │ │ ├── AncestorInPath.java │ │ │ ├── AnnotationHandler.java │ │ │ ├── AttributeKey.java │ │ │ ├── BindInterceptor.java │ │ │ ├── BytecodeReadingParanamer.java │ │ │ ├── CachingScriptLoader.java │ │ │ ├── CancelRequestHandlingException.java │ │ │ ├── CaptureParameterNameTransformation.java │ │ │ ├── CapturedParameterNames.java │ │ │ ├── ClassDescriptor.java │ │ │ ├── ClassLoaderValue.java │ │ │ ├── CompatibleFilter.java │ │ │ ├── CrumbIssuer.java │ │ │ ├── DataBoundConstructor.java │ │ │ ├── DataBoundResolvable.java │ │ │ ├── DataBoundSetter.java │ │ │ ├── DiagnosticThreadNameFilter.java │ │ │ ├── DirectoryishDispatcher.java │ │ │ ├── DispatchValidator.java │ │ │ ├── Dispatcher.java │ │ │ ├── DispatchersFilter.java │ │ │ ├── EvaluationTrace.java │ │ │ ├── Facet.java │ │ │ ├── ForwardToView.java │ │ │ ├── ForwardingFunction.java │ │ │ ├── Function.java │ │ │ ├── FunctionList.java │ │ │ ├── Header.java │ │ │ ├── HttpDeletable.java │ │ │ ├── HttpRedirect.java │ │ │ ├── HttpResponse.java │ │ │ ├── HttpResponseRenderer.java │ │ │ ├── HttpResponses.java │ │ │ ├── IndexDispatcher.java │ │ │ ├── IndexHtmlDispatcher.java │ │ │ ├── IndexViewDispatcher.java │ │ │ ├── InjectedParameter.java │ │ │ ├── JavaScriptMethodContext.java │ │ │ ├── JsonInErrorMessageSanitizer.java │ │ │ ├── KlassDescriptor.java │ │ │ ├── LimitedTo.java │ │ │ ├── LocaleDrivenResourceProvider.java │ │ │ ├── MetaClass.java │ │ │ ├── MetaClassLoader.java │ │ │ ├── MethodHandleFactory.java │ │ │ ├── NameBasedDispatcher.java │ │ │ ├── NoStaplerConstructorException.java │ │ │ ├── PreInvokeInterceptedFunction.java │ │ │ ├── QueryParameter.java │ │ │ ├── RawHtmlArgument.java │ │ │ ├── ReflectionUtils.java │ │ │ ├── RequestImpl.java │ │ │ ├── ResponseImpl.java │ │ │ ├── ScriptExecutor.java │ │ │ ├── ScriptLoadException.java │ │ │ ├── ScriptRequestDispatcher.java │ │ │ ├── SelectionInterceptedFunction.java │ │ │ ├── SingleLinkedList.java │ │ │ ├── Stapler.java │ │ │ ├── StaplerFallback.java │ │ │ ├── StaplerOverridable.java │ │ │ ├── StaplerProxy.java │ │ │ ├── StaplerRequest.java │ │ │ ├── StaplerRequest2.java │ │ │ ├── StaplerResponse.java │ │ │ ├── StaplerResponse2.java │ │ │ ├── StaplerResponse2Wrapper.java │ │ │ ├── StaplerResponseWrapper.java │ │ │ ├── StaticViewFacet.java │ │ │ ├── TearOffSupport.java │ │ │ ├── TokenList.java │ │ │ ├── TraversalMethodContext.java │ │ │ ├── TruncatedInputStream.java │ │ │ ├── UncaughtExceptionFilter.java │ │ │ ├── UncaughtExceptionHandler.java │ │ │ ├── UnionAnnotatedElement.java │ │ │ ├── WebApp.java │ │ │ ├── WebMethod.java │ │ │ ├── WebMethodContext.java │ │ │ ├── WrongTypeException.java │ │ │ ├── bind │ │ │ ├── Bound.java │ │ │ ├── BoundObjectTable.java │ │ │ ├── JavaScriptMethod.java │ │ │ ├── WithWellKnownURL.java │ │ │ └── package-info.java │ │ │ ├── config │ │ │ ├── Configuration.java │ │ │ └── ConfigurationLoader.java │ │ │ ├── event │ │ │ ├── FilteredDispatchTriggerListener.java │ │ │ ├── FilteredDoActionTriggerListener.java │ │ │ ├── FilteredFieldTriggerListener.java │ │ │ └── FilteredGetterTriggerListener.java │ │ │ ├── export │ │ │ ├── ClassAttributeBehaviour.java │ │ │ ├── CustomExportedBean.java │ │ │ ├── DataWriter.java │ │ │ ├── ExportConfig.java │ │ │ ├── ExportInterceptor.java │ │ │ ├── Exported.java │ │ │ ├── ExportedBean.java │ │ │ ├── FieldProperty.java │ │ │ ├── FilteringTreePruner.java │ │ │ ├── Flavor.java │ │ │ ├── Iterators.java │ │ │ ├── JSONDataWriter.java │ │ │ ├── MethodProperty.java │ │ │ ├── Model.java │ │ │ ├── ModelBuilder.java │ │ │ ├── NamedPathPruner.java │ │ │ ├── NotExportableException.java │ │ │ ├── Property.java │ │ │ ├── PythonDataWriter.java │ │ │ ├── Range.java │ │ │ ├── RubyDataWriter.java │ │ │ ├── SchemaGenerator.java │ │ │ ├── TreePruner.java │ │ │ ├── TypeUtil.java │ │ │ ├── XMLDataWriter.java │ │ │ ├── XSD.java │ │ │ ├── XmlChars.java │ │ │ └── package-info.java │ │ │ ├── framework │ │ │ ├── AbstractWebAppMain.java │ │ │ ├── errors │ │ │ │ ├── ErrorObject.java │ │ │ │ └── NoHomeDirError.java │ │ │ └── io │ │ │ │ ├── AtomicFileWriter.java │ │ │ │ ├── ByteBuffer.java │ │ │ │ ├── CharSpool.java │ │ │ │ ├── LargeText.java │ │ │ │ ├── LineEndNormalizingWriter.java │ │ │ │ └── WriterOutputStream.java │ │ │ ├── interceptor │ │ │ ├── Interceptor.java │ │ │ ├── InterceptorAnnotation.java │ │ │ ├── JsonOutputFilter.java │ │ │ ├── RequirePOST.java │ │ │ ├── RespondSuccess.java │ │ │ └── Stage.java │ │ │ ├── json │ │ │ ├── JsonBody.java │ │ │ ├── JsonHttpResponse.java │ │ │ ├── JsonResponse.java │ │ │ └── SubmittedForm.java │ │ │ ├── jsr269 │ │ │ ├── AbstractProcessorImpl.java │ │ │ ├── ConstructorProcessor.java │ │ │ ├── ExportedBeanAnnotationProcessor.java │ │ │ ├── PoormansMultimap.java │ │ │ └── QueryParameterAnnotationProcessor.java │ │ │ ├── lang │ │ │ ├── AnnotatedRef.java │ │ │ ├── FieldRef.java │ │ │ ├── KInstance.java │ │ │ ├── Klass.java │ │ │ ├── KlassNavigator.java │ │ │ ├── MethodRef.java │ │ │ └── util │ │ │ │ ├── FieldRefFilter.java │ │ │ │ └── MethodRefFilter.java │ │ │ ├── package-info.java │ │ │ ├── util │ │ │ └── IllegalReflectiveAccessLogHandler.java │ │ │ └── verb │ │ │ ├── DELETE.java │ │ │ ├── GET.java │ │ │ ├── HttpVerbInterceptor.java │ │ │ ├── POST.java │ │ │ └── PUT.java │ └── resources │ │ └── org │ │ └── kohsuke │ │ └── stapler │ │ ├── bind.js │ │ └── framework │ │ └── errors │ │ └── ErrorObject │ │ └── index.default.jelly │ └── test │ ├── java │ └── org │ │ └── kohsuke │ │ └── stapler │ │ ├── AbstractStaplerTestBase.java │ │ ├── AcceptHeaderTest.java │ │ ├── AncestorImplTest.java │ │ ├── ClassDescriptorTest.java │ │ ├── DataBindingTest.java │ │ ├── DispatcherTest.java │ │ ├── HttpResponseRendererTest.java │ │ ├── IndexHtmlDispatcherTest.java │ │ ├── JsonInErrorMessageSanitizerTest.java │ │ ├── MetaClassLoaderTest.java │ │ ├── MetaClassTest.java │ │ ├── MockRequest.java │ │ ├── MockServletContext.java │ │ ├── NestedJsonTest.java │ │ ├── ObjectWithCustomConverter.java │ │ ├── RequestImplTest.java │ │ ├── ResponseImplTest.java │ │ ├── ServletConfigImpl.java │ │ ├── Stapler2Test.java │ │ ├── StaplerTest.java │ │ ├── bind │ │ ├── BoundObjectTableTest.java │ │ └── JavaScriptProxyTest.java │ │ ├── export │ │ ├── ClassAttributeBehaviourTest.java │ │ ├── JSONDataWriterTest.java │ │ ├── ModelTest.java │ │ ├── NamedPathPrunerTest.java │ │ ├── RangeTest.java │ │ ├── SchemaGeneratorTest.java │ │ └── XMLDataWriterTest.java │ │ ├── framework │ │ └── io │ │ │ ├── LargeTextTest.java │ │ │ ├── LineEndNormalizingWriterTest.java │ │ │ └── WriterOutputStreamTest.java │ │ ├── interceptor │ │ └── JsonOutputFilterTest.java │ │ ├── json │ │ ├── JsonBodyTest.java │ │ └── SubmittedFormTest.java │ │ ├── jsr269 │ │ ├── ConstructorProcessorTest.java │ │ ├── ExportedBeanAnnotationProcessorTest.java │ │ ├── QueryParameterAnnotationProcessorTest.java │ │ ├── SourceGeneratingAnnotation.java │ │ ├── SourceGeneratingAnnotationProcessor.java │ │ └── Utils.java │ │ ├── lang │ │ └── KlassTest.java │ │ └── test │ │ ├── AbstractStaplerTest.java │ │ ├── JettyTestCase.java │ │ └── package-info.java │ └── resources │ └── org │ └── kohsuke │ └── stapler │ └── json │ └── SubmittedFormTest │ └── form.html ├── docs ├── getting-started.adoc ├── i18n.adoc ├── jelly-taglib-ref.adoc ├── reference.adoc ├── stapler.png ├── stapler.vsd ├── taglib-jelly.xsd ├── taglib.xsd └── what-is.adoc ├── groovy ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── kohsuke │ │ └── stapler │ │ └── jelly │ │ └── groovy │ │ ├── GroovierJellyScript.java │ │ ├── GroovyClassLoaderTearOff.java │ │ ├── GroovyClassTearOff.java │ │ ├── GroovyClosureScript.java │ │ ├── GroovyFacet.java │ │ ├── GroovyTagFileLoader.java │ │ ├── JellyBuilder.java │ │ ├── Namespace.java │ │ ├── StaplerClosureScript.java │ │ ├── TagFile.java │ │ ├── TagLibraryUri.java │ │ └── TypedTagLibrary.java │ └── test │ └── java │ └── org │ └── kohsuke │ └── stapler │ └── jelly │ └── groovy │ └── GroovyClassLoaderTearOffTest.java ├── jelly ├── pom.xml └── src │ ├── main │ └── java │ │ └── org │ │ └── kohsuke │ │ └── stapler │ │ ├── framework │ │ └── adjunct │ │ │ ├── Adjunct.java │ │ │ ├── AdjunctManager.java │ │ │ ├── AdjunctsInPage.java │ │ │ ├── NoSuchAdjunctException.java │ │ │ └── package-info.java │ │ └── jelly │ │ ├── AbstractStaplerTag.java │ │ ├── AdjunctTag.java │ │ ├── AnnotationProcessorImpl.java │ │ ├── AttributeConstraintsTag.java │ │ ├── AttributeNameRewritingTagScript.java │ │ ├── AttributeTag.java │ │ ├── BindTag.java │ │ ├── CallTagLibScript.java │ │ ├── CompressTag.java │ │ ├── ContentTypeTag.java │ │ ├── CopyStreamTag.java │ │ ├── CustomJellyContext.java │ │ ├── CustomTagLibrary.java │ │ ├── DefaultScriptInvoker.java │ │ ├── DoctypeTag.java │ │ ├── FindAncestorTag.java │ │ ├── HTMLWriterOutput.java │ │ ├── HeaderTag.java │ │ ├── IncludeTag.java │ │ ├── InternationalizedStringExpression.java │ │ ├── InternationalizedStringExpressionListener.java │ │ ├── IsUserInRoleTag.java │ │ ├── JellyClassLoaderTearOff.java │ │ ├── JellyClassTearOff.java │ │ ├── JellyCompatibleFacet.java │ │ ├── JellyFacet.java │ │ ├── JellyRequestDispatcher.java │ │ ├── JellyTagFileLoader.java │ │ ├── JellyViewScript.java │ │ ├── NbspTag.java │ │ ├── OutTag.java │ │ ├── ParentScopeTag.java │ │ ├── ReallyStaticTagLibrary.java │ │ ├── RedirectTag.java │ │ ├── RequiresView.java │ │ ├── ResourceBundle.java │ │ ├── ResourceBundleFactory.java │ │ ├── ScriptInvoker.java │ │ ├── SetHeaderTag.java │ │ ├── StaplerTagLibrary.java │ │ ├── StatusCodeTag.java │ │ ├── StructuredMessageArgumentTag.java │ │ ├── StructuredMessageFormatTag.java │ │ ├── ThisTagLibrary.java │ │ └── package-info.java │ └── test │ ├── java │ └── org │ │ └── kohsuke │ │ └── stapler │ │ └── jelly │ │ ├── AttributeExpressionTest.java │ │ ├── BindTagTest.java │ │ ├── BodyExpressionTest.java │ │ ├── ResourceBundleTest.java │ │ ├── TagLibNamespaceExportTest.java │ │ └── issue76 │ │ ├── Arm.java │ │ ├── Button.java │ │ ├── Eye.java │ │ ├── Head.java │ │ ├── Issue76Test.java │ │ ├── Leg.java │ │ ├── ProtectedClass.java │ │ ├── Protection.java │ │ └── Robot.java │ └── resources │ └── org │ └── kohsuke │ └── stapler │ └── jelly │ ├── AttributeExpressionTest │ └── index.jelly │ ├── BindTagTest │ └── index.jelly │ ├── BodyExpressionTest │ └── index.jelly │ ├── ResourceBundleTest │ ├── index.properties │ ├── index_en_CA.properties │ ├── index_fr_FR.properties │ ├── index_zh_CN.properties │ └── index_zh_TW.properties │ ├── TagLibNamespaceExportTest │ ├── index.jelly │ ├── sub.jelly │ └── taglib │ │ ├── tagfile.jelly │ │ └── taglib │ └── issue76 │ ├── Button │ └── index.jelly │ ├── Eye │ └── index.jelly │ ├── Head │ └── index.jelly │ └── Leg │ └── index.jelly ├── jsp ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── kohsuke │ │ └── stapler │ │ ├── jsp │ │ ├── JSPFacet.java │ │ └── RequestDispatcherWrapper.java │ │ └── tags │ │ └── Include.java │ └── resources │ └── META-INF │ └── taglib.tld ├── pom.xml └── src └── checkstyle └── checkstyle-configuration.xml /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # .git-blame-ignore-revs 2 | # Format code with Spotless (#545) 3 | 74da67fd82c1cb3b5a810a53079059290e00437f 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/code-security/supply-chain-security/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "daily" 9 | - package-ecosystem: "maven" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | ignore: 14 | # see https://github.com/jenkinsci/jenkins/pull/5112#issuecomment-744429487 and https://github.com/jenkinsci/jenkins/pull/5116#issuecomment-744526638 15 | # it would be good to update it at some point, but requires significant testing 16 | - dependency-name: "org.codehaus.groovy:groovy-all" 17 | versions: [">=2.5.0"] 18 | # Provided by the Web container, so aligned with Jetty. 19 | - dependency-name: "jakarta.servlet:jakarta.servlet-api" 20 | - dependency-name: "jakarta.servlet.jsp:jakarta.servlet.jsp-api" 21 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: jenkinsci/.github 2 | -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.ipr 3 | *.iml 4 | *.iws 5 | target 6 | pom.xml.versionsBackup 7 | 8 | .project 9 | .settings/ 10 | .classpath 11 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.8 6 | 7 | 8 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s 4 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /* 2 | * While this is not a plugin, it is much simpler to reuse the pipeline code for CI. This allows for 3 | * easy Linux/Windows testing and produces incrementals. The only feature that relates to plugins is 4 | * allowing one to test against multiple Jenkins versions. 5 | */ 6 | buildPlugin(useContainerAgent: true, configurations: [ 7 | [platform: 'linux', jdk: 21], 8 | [platform: 'windows', jdk: 17], 9 | ]) 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-, Kohsuke Kawaguchi and other contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | * [What is Stapler?](docs/what-is.adoc) 2 | * [Getting Started](docs/getting-started.adoc) 3 | * Developer Reference 4 | * [URL binding reference](docs/reference.adoc) 5 | * [Internationalization support](docs/i18n.adoc) 6 | * [Javadoc](https://javadoc.jenkins.io/component/stapler/) 7 | * [Stapler jelly tag library reference and XML Schema](docs/jelly-taglib-ref.adoc) 8 | -------------------------------------------------------------------------------- /core/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2010, Kohsuke Kawaguchi 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided 5 | that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of 10 | conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 14 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 15 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 16 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 18 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 19 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 20 | THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /core/TODO: -------------------------------------------------------------------------------- 1 | - need to redesign duck-typing 2 | - document duck-typing. 3 | 4 | - embed jasper to allow multiple class loader system. 5 | generate servlets from jsps/tags. 6 | (needs a ServletContext that can load from hierarchy of webapps) 7 | 8 | - generated servlets need to be wrapped into ResourceDispatcher. 9 | 10 | - if we create child class loaders we have to be careful cleaning them up 11 | -------------------------------------------------------------------------------- /core/example/WEB-INF/lib/jstl.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/core/example/WEB-INF/lib/jstl.jar -------------------------------------------------------------------------------- /core/example/WEB-INF/lib/standard.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/core/example/WEB-INF/lib/standard.jar -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/Book/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> 2 | <%-- 3 | "index.jsp" is used to serve the URL of the object itself. 4 | In this example, this JSP is used to serve "/items/[id]/" 5 | --%> 6 | 7 | Book ${it.title} 8 | 9 | <%-- 10 | "it" variable is set to the target Book object by the Stapler. 11 | --%> 12 | Name: ${it.title}
13 | ISBN: ${it.isbn}
14 | 15 | <%-- 16 | st:include tag lets you include another side JSP from the 17 | inheritance hierarchy of the "it" object. Here, we are 18 | referring to the footer.jsp defined for the Item class, 19 | allowing CD and Book to share some JSPs. 20 | --%> 21 | 22 | 23 | -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/BookStore/count.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 2 | <%-- 3 | An example of another side JSP. 4 | --%> 5 | 6 | 7 | # of items: ${fn:length(it.items)} 8 | 9 | -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/BookStore/helloJSP.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | Current system time is ${systemTime} 5 | 6 | -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/BookStore/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%-- 3 | This side JSP for example.BookStore is used to serve the URL "/" 4 | --%> 5 | 6 | Book Store 7 | 8 | <%-- side files can include static resources. --%> 9 | 10 | 11 |

Inventory

12 | 13 | ${i.value.title}
14 |
15 | 16 |

Others

17 |

18 | <%-- 19 | this jumps to another side file "count.jsp" 20 | --%> 21 | count inventory 22 |

23 | invoke action method 24 |

25 | <%-- resources files are served normally. --%> 26 | regular resources 27 |

28 | 29 | -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/BookStore/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/core/example/WEB-INF/side-files/example/BookStore/logo.png -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/CD/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> 3 | <%-- 4 | "index.jsp" is used to serve the URL of the object itself. 5 | In this example, this JSP is used to serve "/items/[id]/" 6 | --%> 7 | 8 | CD ${it.title} 9 | 10 | <%-- 11 | "it" variable is set to the target CD object by the Stapler. 12 | --%> 13 | Name: ${it.title}
14 | SKU: ${it.sku}
15 | 16 |

Track list

17 |
    18 | 19 |
  1. ${t.name}
  2. 20 |
    21 |
22 | 23 | <%-- 24 | st:include tag lets you include another side JSP from the 25 | inheritance hierarchy of the "it" object. Here, we are 26 | referring to the footer.jsp defined for the Item class, 27 | allowing CD and Book to share some JSPs. 28 | --%> 29 | 30 | 31 | -------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/Item/footer.jsp: -------------------------------------------------------------------------------- 1 |
2 |
3 | Common footer for ${it.title} 4 |
-------------------------------------------------------------------------------- /core/example/WEB-INF/side-files/example/Track/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | Track ${it.name} 3 | 4 | Name: ${it.name} 5 |
6 | 7 | <%-- 8 | because of the way we organize URL, going back to the parent CD object 9 | is as easy as this 10 | --%> 11 | back 12 | 13 | -------------------------------------------------------------------------------- /core/example/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Stapler 7 | org.kohsuke.stapler.Stapler 8 | 9 | 10 | Stapler 11 | / 12 | 13 | 14 | 15 | 16 | example.WebAppMain 17 | 18 | -------------------------------------------------------------------------------- /core/example/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /core/example/resources/help/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Resources can be placed normally, and they can be accessed normally. 4 | This is often useful for site-wide resources (such as images) 5 | and other static resources (like documentations) 6 | 7 | -------------------------------------------------------------------------------- /core/example/src/example/Book.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.io.IOException; 5 | import org.kohsuke.stapler.StaplerRequest; 6 | import org.kohsuke.stapler.StaplerResponse; 7 | 8 | /** 9 | * A book in the bookstore. 10 | * 11 | *

12 | * In this example we define a few side JSP files to 13 | * define views of this object. See 14 | * /resources/WEB-INF/side-files/example/Book/*.jsp 15 | * 16 | * @author Kohsuke Kawaguchi 17 | */ 18 | public class Book extends Item { 19 | 20 | private String isbn; 21 | 22 | public Book(String isbn, String title) { 23 | super(isbn,title); 24 | this.isbn = isbn; 25 | } 26 | 27 | 28 | public String getIsbn() { 29 | return isbn; 30 | } 31 | 32 | 33 | /** 34 | * Defines an action to delete this book from the store. 35 | */ 36 | public void doDelete( StaplerRequest request, StaplerResponse response ) throws IOException, ServletException { 37 | BookStore.theStore.getItems().remove(getSku()); 38 | response.sendRedirect(request.getContextPath()+'/'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/example/src/example/CD.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | 4 | 5 | /** 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public class CD extends Item { 9 | 10 | private final Track[] tracks; 11 | 12 | public CD(String sku, String title, Track[] tracks ) { 13 | super(sku,title); 14 | this.tracks = tracks; 15 | } 16 | 17 | /** 18 | * Allocates the sub directory "track/[num]" to 19 | * the corresponding Track object. 20 | */ 21 | public Track[] getTracks() { 22 | return tracks; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/example/src/example/Item.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | /** 4 | * Item in the bookstore. 5 | * 6 | * This example shows the power of the polymorphic behavior that 7 | * Stapler enables. 8 | * 9 | * We have two kinds of Item in this system -- Book and CD. 10 | * They are both accessible by the same form of URL "/items/[sku]", 11 | * but their index.jsp are different. 12 | * 13 | * @author Kohsuke Kawaguchi 14 | */ 15 | public abstract class Item { 16 | private final String sku; 17 | private final String title; 18 | 19 | protected Item(String sku,String title) { 20 | this.sku = sku; 21 | this.title = title; 22 | } 23 | 24 | public String getSku() { 25 | return sku; 26 | } 27 | 28 | public String getTitle() { 29 | return title; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/example/src/example/Track.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | /** 4 | * A track of a CD. 5 | * 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public class Track { 9 | private String name; 10 | private int length; 11 | 12 | public Track(String name, int length) { 13 | this.name = name; 14 | this.length = length; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public int getLength() { 22 | return length; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/example/src/example/WebAppMain.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import jakarta.servlet.ServletContextEvent; 4 | import jakarta.servlet.ServletContextListener; 5 | import org.kohsuke.stapler.Stapler; 6 | 7 | /** 8 | * This class is invoked by the container at the beginning 9 | * and at the end. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class WebAppMain implements ServletContextListener { 14 | public void contextInitialized(ServletContextEvent event) { 15 | // BookStore.theStore is the singleton instance of the application 16 | Stapler.setRoot(event,BookStore.theStore); 17 | } 18 | 19 | public void contextDestroyed(ServletContextEvent event) { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/maven-example/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Ant-Version: Apache Ant 1.7.0 3 | Created-By: 10.0-b19 (Sun Microsystems Inc.) 4 | 5 | -------------------------------------------------------------------------------- /core/maven-example/src/main/java/example/Book.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.io.IOException; 5 | import org.kohsuke.stapler.StaplerRequest2; 6 | import org.kohsuke.stapler.StaplerResponse2; 7 | 8 | /** 9 | * A book in the bookstore. 10 | * 11 | *

12 | * In this example we define a few side JSP files to 13 | * define views of this object. See 14 | * /resources/WEB-INF/side-files/example/Book/*.jsp 15 | * 16 | * @author Kohsuke Kawaguchi 17 | */ 18 | public class Book extends Item { 19 | 20 | private String isbn; 21 | 22 | public Book(String isbn, String title) { 23 | super(isbn,title); 24 | this.isbn = isbn; 25 | } 26 | 27 | 28 | public String getIsbn() { 29 | return isbn; 30 | } 31 | 32 | 33 | /** 34 | * Defines an action to delete this book from the store. 35 | */ 36 | public void doDelete( StaplerRequest2 request, StaplerResponse2 response ) throws IOException, ServletException { 37 | BookStore.theStore.getItems().remove(getSku()); 38 | response.sendRedirect(request.getContextPath()+'/'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/maven-example/src/main/java/example/CD.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | 4 | 5 | /** 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public class CD extends Item { 9 | 10 | private final Track[] tracks; 11 | 12 | public CD(String sku, String title, Track[] tracks ) { 13 | super(sku,title); 14 | this.tracks = tracks; 15 | } 16 | 17 | /** 18 | * Allocates the sub directory "track/[num]" to 19 | * the corresponding Track object. 20 | */ 21 | public Track[] getTracks() { 22 | return tracks; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/maven-example/src/main/java/example/Item.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | /** 4 | * Item in the bookstore. 5 | * 6 | * This example shows the power of the polymorphic behavior that 7 | * Stapler enables. 8 | * 9 | * We have two kinds of Item in this system -- Book and CD. 10 | * They are both accessible by the same form of URL "/items/[sku]", 11 | * but their index.jsp are different. 12 | * 13 | * @author Kohsuke Kawaguchi 14 | */ 15 | public abstract class Item { 16 | private final String sku; 17 | private final String title; 18 | 19 | protected Item(String sku,String title) { 20 | this.sku = sku; 21 | this.title = title; 22 | } 23 | 24 | public String getSku() { 25 | return sku; 26 | } 27 | 28 | public String getTitle() { 29 | return title; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/maven-example/src/main/java/example/Track.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | /** 4 | * A track of a CD. 5 | * 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public class Track { 9 | private String name; 10 | private int length; 11 | 12 | public Track(String name, int length) { 13 | this.name = name; 14 | this.length = length; 15 | } 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public int getLength() { 22 | return length; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/maven-example/src/main/java/example/WebAppMain.java: -------------------------------------------------------------------------------- 1 | package example; 2 | 3 | import jakarta.servlet.ServletContextEvent; 4 | import jakarta.servlet.ServletContextListener; 5 | import org.kohsuke.stapler.Stapler; 6 | 7 | /** 8 | * This class is invoked by the container at the beginning 9 | * and at the end. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class WebAppMain implements ServletContextListener { 14 | public void contextInitialized(ServletContextEvent event) { 15 | // BookStore.theStore is the singleton instance of the application 16 | Stapler.setRoot(event,BookStore.theStore); 17 | } 18 | 19 | public void contextDestroyed(ServletContextEvent event) { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/Book/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> 2 | <%-- 3 | "index.jsp" is used to serve the URL of the object itself. 4 | In this example, this JSP is used to serve "/items/[id]/" 5 | --%> 6 | 7 | Book ${it.title} 8 | 9 | <%-- 10 | "it" variable is set to the target Book object by the Stapler. 11 | --%> 12 | Name: ${it.title}
13 | ISBN: ${it.isbn}
14 | 15 | <%-- 16 | st:include tag lets you include another side JSP from the 17 | inheritance hierarchy of the "it" object. Here, we are 18 | referring to the footer.jsp defined for the Item class, 19 | allowing CD and Book to share some JSPs. 20 | --%> 21 | 22 | 23 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/count.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 2 | <%-- 3 | An example of another side JSP. 4 | --%> 5 | 6 | 7 | # of items: ${fn:length(it.items)} 8 | 9 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/helloJSP.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | Current system time is ${systemTime} 5 | 6 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%-- 3 | This side JSP for example.BookStore is used to serve the URL "/" 4 | --%> 5 | 6 | Book Store 7 | 8 | <%-- side files can include static resources. --%> 9 | 10 | 11 |

Inventory

12 | 13 | ${i.value.title}
14 |
15 | 16 |

Others

17 |

18 | <%-- 19 | this jumps to another side file "count.jsp" 20 | --%> 21 | count inventory 22 |

23 | invoke action method 24 |

25 | <%-- resources files are served normally. --%> 26 | regular resources 27 |

28 | 29 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/core/maven-example/src/main/webapp/WEB-INF/side-files/example/BookStore/logo.png -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/CD/index.jsp: -------------------------------------------------------------------------------- 1 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@taglib prefix="st" uri="http://stapler.dev.java.net/" %> 3 | <%-- 4 | "index.jsp" is used to serve the URL of the object itself. 5 | In this example, this JSP is used to serve "/items/[id]/" 6 | --%> 7 | 8 | CD ${it.title} 9 | 10 | <%-- 11 | "it" variable is set to the target CD object by the Stapler. 12 | --%> 13 | Name: ${it.title}
14 | SKU: ${it.sku}
15 | 16 |

Track list

17 |
    18 | 19 |
  1. ${t.name}
  2. 20 |
    21 |
22 | 23 | <%-- 24 | st:include tag lets you include another side JSP from the 25 | inheritance hierarchy of the "it" object. Here, we are 26 | referring to the footer.jsp defined for the Item class, 27 | allowing CD and Book to share some JSPs. 28 | --%> 29 | 30 | 31 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/Item/footer.jsp: -------------------------------------------------------------------------------- 1 |
2 |
3 | Common footer for ${it.title} 4 |
-------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/side-files/example/Track/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | Track ${it.name} 3 | 4 | Name: ${it.name} 5 |
6 | 7 | <%-- 8 | because of the way we organize URL, going back to the parent CD object 9 | is as easy as this 10 | --%> 11 | back 12 | 13 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Stapler 7 | org.kohsuke.stapler.Stapler 8 | 9 | 10 | Stapler 11 | / 12 | 13 | 14 | 15 | 16 | example.WebAppMain 17 | 18 | -------------------------------------------------------------------------------- /core/maven-example/src/main/webapp/help/help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Resources can be placed normally, and they can be accessed normally. 4 | This is often useful for site-wide resources (such as images) 5 | and other static resources (like documentations) 6 | 7 | -------------------------------------------------------------------------------- /core/ref/j2ee/package-list: -------------------------------------------------------------------------------- 1 | javax.activation 2 | javax.ejb 3 | javax.ejb.spi 4 | javax.enterprise.deploy.model 5 | javax.enterprise.deploy.shared 6 | javax.enterprise.deploy.shared.factories 7 | javax.enterprise.deploy.spi 8 | javax.enterprise.deploy.spi.exceptions 9 | javax.enterprise.deploy.spi.factories 10 | javax.enterprise.deploy.spi.status 11 | javax.jms 12 | javax.mail 13 | javax.mail.event 14 | javax.mail.internet 15 | javax.mail.search 16 | javax.management 17 | javax.management.j2ee 18 | javax.management.j2ee.statistics 19 | javax.management.loading 20 | javax.management.modelmbean 21 | javax.management.monitor 22 | javax.management.openmbean 23 | javax.management.relation 24 | javax.management.timer 25 | javax.resource 26 | javax.resource.cci 27 | javax.resource.spi 28 | javax.resource.spi.endpoint 29 | javax.resource.spi.security 30 | javax.resource.spi.work 31 | javax.security.jacc 32 | javax.servlet 33 | javax.servlet.http 34 | javax.servlet.jsp 35 | javax.servlet.jsp.el 36 | javax.servlet.jsp.tagext 37 | javax.transaction 38 | javax.transaction.xa 39 | javax.xml.namespace 40 | javax.xml.parsers 41 | javax.xml.registry 42 | javax.xml.registry.infomodel 43 | javax.xml.rpc 44 | javax.xml.rpc.encoding 45 | javax.xml.rpc.handler 46 | javax.xml.rpc.handler.soap 47 | javax.xml.rpc.holders 48 | javax.xml.rpc.server 49 | javax.xml.rpc.soap 50 | javax.xml.soap 51 | javax.xml.transform 52 | javax.xml.transform.dom 53 | javax.xml.transform.sax 54 | javax.xml.transform.stream 55 | -------------------------------------------------------------------------------- /core/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | mvn -B release:prepare release:perform 3 | ver=$(show-pom-version target/checkout/pom.xml) 4 | javanettasks uploadFile stapler /stapler-$ver.zip "$ver release" stable target/checkout/target/stapler-$ver-bin.zip 5 | cp -R target/checkout/target/site/* ../www 6 | cd ../www 7 | rcvsadd . "pushing javadoc for $ver" 8 | 9 | 10 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/AsyncEventWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.AsyncEvent; 5 | 6 | public class AsyncEventWrapper { 7 | public static jakarta.servlet.AsyncEvent toJakartaServletHttpAsyncEvent(AsyncEvent from) { 8 | Objects.requireNonNull(from); 9 | return new jakarta.servlet.AsyncEvent( 10 | AsyncContextWrapper.toJakartaAsyncContext(from.getAsyncContext()), 11 | io.jenkins.servlet.ServletRequestWrapper.toJakartaServletRequest(from.getSuppliedRequest()), 12 | ServletResponseWrapper.toJakartaServletResponse(from.getSuppliedResponse()), 13 | from.getThrowable()); 14 | } 15 | 16 | public static AsyncEvent fromJakartaServletHttpAsyncEvent(jakarta.servlet.AsyncEvent from) { 17 | Objects.requireNonNull(from); 18 | return new AsyncEvent( 19 | AsyncContextWrapper.fromJakartaAsyncContext(from.getAsyncContext()), 20 | ServletRequestWrapper.fromJakartaServletRequest(from.getSuppliedRequest()), 21 | ServletResponseWrapper.fromJakartaServletResponse(from.getSuppliedResponse()), 22 | from.getThrowable()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/DispatcherTypeWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.DispatcherType; 5 | 6 | public class DispatcherTypeWrapper { 7 | public static jakarta.servlet.DispatcherType toJakartaDispatcherType(DispatcherType from) { 8 | Objects.requireNonNull(from); 9 | switch (from) { 10 | case FORWARD: 11 | return jakarta.servlet.DispatcherType.FORWARD; 12 | case INCLUDE: 13 | return jakarta.servlet.DispatcherType.INCLUDE; 14 | case REQUEST: 15 | return jakarta.servlet.DispatcherType.REQUEST; 16 | case ASYNC: 17 | return jakarta.servlet.DispatcherType.ASYNC; 18 | case ERROR: 19 | return jakarta.servlet.DispatcherType.ERROR; 20 | default: 21 | throw new IllegalArgumentException("Unknown DispatcherType: " + from); 22 | } 23 | } 24 | 25 | public static DispatcherType fromJakartaDispatcherType(jakarta.servlet.DispatcherType from) { 26 | Objects.requireNonNull(from); 27 | switch (from) { 28 | case FORWARD: 29 | return DispatcherType.FORWARD; 30 | case INCLUDE: 31 | return DispatcherType.INCLUDE; 32 | case REQUEST: 33 | return DispatcherType.REQUEST; 34 | case ASYNC: 35 | return DispatcherType.ASYNC; 36 | case ERROR: 37 | return DispatcherType.ERROR; 38 | default: 39 | throw new IllegalArgumentException("Unknown DispatcherType: " + from); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/FilterConfigWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Enumeration; 4 | import java.util.Objects; 5 | import javax.servlet.FilterConfig; 6 | import javax.servlet.ServletContext; 7 | 8 | public class FilterConfigWrapper { 9 | public static jakarta.servlet.FilterConfig toJakartaFilterConfig(FilterConfig from) { 10 | Objects.requireNonNull(from); 11 | return new jakarta.servlet.FilterConfig() { 12 | @Override 13 | public String getFilterName() { 14 | return from.getFilterName(); 15 | } 16 | 17 | @Override 18 | public jakarta.servlet.ServletContext getServletContext() { 19 | return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); 20 | } 21 | 22 | @Override 23 | public String getInitParameter(String name) { 24 | return from.getInitParameter(name); 25 | } 26 | 27 | @Override 28 | public Enumeration getInitParameterNames() { 29 | return from.getInitParameterNames(); 30 | } 31 | }; 32 | } 33 | 34 | public static FilterConfig fromJakartaFilterConfig(jakarta.servlet.FilterConfig from) { 35 | Objects.requireNonNull(from); 36 | return new FilterConfig() { 37 | @Override 38 | public String getFilterName() { 39 | return from.getFilterName(); 40 | } 41 | 42 | @Override 43 | public ServletContext getServletContext() { 44 | return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); 45 | } 46 | 47 | @Override 48 | public String getInitParameter(String name) { 49 | return from.getInitParameter(name); 50 | } 51 | 52 | @Override 53 | public Enumeration getInitParameterNames() { 54 | return from.getInitParameterNames(); 55 | } 56 | }; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/ReadListenerWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.io.IOException; 4 | import java.util.Objects; 5 | import javax.servlet.ReadListener; 6 | 7 | public class ReadListenerWrapper { 8 | public static jakarta.servlet.ReadListener toJakartaReadListener(ReadListener from) { 9 | Objects.requireNonNull(from); 10 | return new jakarta.servlet.ReadListener() { 11 | @Override 12 | public void onDataAvailable() throws IOException { 13 | from.onDataAvailable(); 14 | } 15 | 16 | @Override 17 | public void onAllDataRead() throws IOException { 18 | from.onAllDataRead(); 19 | } 20 | 21 | @Override 22 | public void onError(Throwable throwable) { 23 | from.onError(throwable); 24 | } 25 | }; 26 | } 27 | 28 | public static ReadListener fromJakartaReadListener(jakarta.servlet.ReadListener from) { 29 | Objects.requireNonNull(from); 30 | return new ReadListener() { 31 | @Override 32 | public void onDataAvailable() throws IOException { 33 | from.onDataAvailable(); 34 | } 35 | 36 | @Override 37 | public void onAllDataRead() throws IOException { 38 | from.onAllDataRead(); 39 | } 40 | 41 | @Override 42 | public void onError(Throwable t) { 43 | from.onError(t); 44 | } 45 | }; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/ServletConfigWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Enumeration; 4 | import java.util.Objects; 5 | import javax.servlet.ServletConfig; 6 | import javax.servlet.ServletContext; 7 | 8 | public class ServletConfigWrapper { 9 | public static jakarta.servlet.ServletConfig toJakartaServletConfig(ServletConfig from) { 10 | Objects.requireNonNull(from); 11 | return new jakarta.servlet.ServletConfig() { 12 | @Override 13 | public String getServletName() { 14 | return from.getServletName(); 15 | } 16 | 17 | @Override 18 | public jakarta.servlet.ServletContext getServletContext() { 19 | return ServletContextWrapper.toJakartaServletContext(from.getServletContext()); 20 | } 21 | 22 | @Override 23 | public String getInitParameter(String name) { 24 | return from.getInitParameter(name); 25 | } 26 | 27 | @Override 28 | public Enumeration getInitParameterNames() { 29 | return from.getInitParameterNames(); 30 | } 31 | }; 32 | } 33 | 34 | public static ServletConfig fromJakartaServletConfig(jakarta.servlet.ServletConfig from) { 35 | Objects.requireNonNull(from); 36 | return new ServletConfig() { 37 | @Override 38 | public String getServletName() { 39 | return from.getServletName(); 40 | } 41 | 42 | @Override 43 | public ServletContext getServletContext() { 44 | return ServletContextWrapper.fromJakartServletContext(from.getServletContext()); 45 | } 46 | 47 | @Override 48 | public String getInitParameter(String name) { 49 | return from.getInitParameter(name); 50 | } 51 | 52 | @Override 53 | public Enumeration getInitParameterNames() { 54 | return from.getInitParameterNames(); 55 | } 56 | }; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/ServletContextEventWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.ServletContextEvent; 5 | 6 | public class ServletContextEventWrapper { 7 | public static jakarta.servlet.ServletContextEvent toJakartaServletContextEvent(ServletContextEvent from) { 8 | Objects.requireNonNull(from); 9 | return new jakarta.servlet.ServletContextEvent( 10 | ServletContextWrapper.toJakartaServletContext(from.getServletContext())); 11 | } 12 | 13 | public static ServletContextEvent fromJakartaServletContextEvent(jakarta.servlet.ServletContextEvent from) { 14 | Objects.requireNonNull(from); 15 | return new ServletContextEvent(ServletContextWrapper.fromJakartServletContext(from.getServletContext())); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/ServletExceptionWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.ServletException; 5 | 6 | public class ServletExceptionWrapper { 7 | public static jakarta.servlet.ServletException toJakartaServletException(ServletException e) { 8 | Objects.requireNonNull(e); 9 | return new jakarta.servlet.ServletException(e.toString(), e); 10 | } 11 | 12 | public static ServletException fromJakartaServletException(jakarta.servlet.ServletException e) { 13 | Objects.requireNonNull(e); 14 | return new ServletException(e.toString(), e); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/SessionTrackingModeWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.SessionTrackingMode; 5 | 6 | public class SessionTrackingModeWrapper { 7 | public static jakarta.servlet.SessionTrackingMode toJakartaSessionTrackingMode(SessionTrackingMode from) { 8 | Objects.requireNonNull(from); 9 | switch (from) { 10 | case COOKIE: 11 | return jakarta.servlet.SessionTrackingMode.COOKIE; 12 | case URL: 13 | return jakarta.servlet.SessionTrackingMode.URL; 14 | case SSL: 15 | return jakarta.servlet.SessionTrackingMode.SSL; 16 | default: 17 | throw new IllegalArgumentException("Unknown SessionTrackingMode: " + from); 18 | } 19 | } 20 | 21 | public static SessionTrackingMode fromJakartaSessionTrackingMode(jakarta.servlet.SessionTrackingMode from) { 22 | Objects.requireNonNull(from); 23 | switch (from) { 24 | case COOKIE: 25 | return SessionTrackingMode.COOKIE; 26 | case URL: 27 | return SessionTrackingMode.URL; 28 | case SSL: 29 | return SessionTrackingMode.SSL; 30 | default: 31 | throw new IllegalArgumentException("Unknown SessionTrackingMode: " + from); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/WriteListenerWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet; 2 | 3 | import java.io.IOException; 4 | import java.util.Objects; 5 | import javax.servlet.WriteListener; 6 | 7 | public class WriteListenerWrapper { 8 | public static jakarta.servlet.WriteListener toJakartaWriteListener(WriteListener from) { 9 | Objects.requireNonNull(from); 10 | return new jakarta.servlet.WriteListener() { 11 | @Override 12 | public void onWritePossible() throws IOException { 13 | from.onWritePossible(); 14 | } 15 | 16 | @Override 17 | public void onError(Throwable t) { 18 | from.onError(t); 19 | } 20 | }; 21 | } 22 | 23 | public static WriteListener fromJakartaWriteListener(jakarta.servlet.WriteListener from) { 24 | Objects.requireNonNull(from); 25 | return new WriteListener() { 26 | @Override 27 | public void onWritePossible() throws IOException { 28 | from.onWritePossible(); 29 | } 30 | 31 | @Override 32 | public void onError(Throwable t) { 33 | from.onError(t); 34 | } 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/descriptor/JspConfigDescriptorWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.descriptor; 2 | 3 | import java.util.Collection; 4 | import java.util.Objects; 5 | import java.util.stream.Collectors; 6 | import javax.servlet.descriptor.JspConfigDescriptor; 7 | import javax.servlet.descriptor.JspPropertyGroupDescriptor; 8 | import javax.servlet.descriptor.TaglibDescriptor; 9 | 10 | public class JspConfigDescriptorWrapper { 11 | public static jakarta.servlet.descriptor.JspConfigDescriptor toJakartaJspConfigDescriptor( 12 | JspConfigDescriptor from) { 13 | Objects.requireNonNull(from); 14 | return new jakarta.servlet.descriptor.JspConfigDescriptor() { 15 | @Override 16 | public Collection getTaglibs() { 17 | return from.getTaglibs().stream() 18 | .map(TaglibDescriptorWrapper::toJakartaTaglibDescriptor) 19 | .collect(Collectors.toList()); 20 | } 21 | 22 | @Override 23 | public Collection getJspPropertyGroups() { 24 | return from.getJspPropertyGroups().stream() 25 | .map(JspPropertyGroupDescriptorWrapper::toJakartaJspPropertyGroupDescriptor) 26 | .collect(Collectors.toList()); 27 | } 28 | }; 29 | } 30 | 31 | public static JspConfigDescriptor fromJakartaJspConfigDescriptor( 32 | jakarta.servlet.descriptor.JspConfigDescriptor from) { 33 | Objects.requireNonNull(from); 34 | return new JspConfigDescriptor() { 35 | @Override 36 | public Collection getTaglibs() { 37 | return from.getTaglibs().stream() 38 | .map(TaglibDescriptorWrapper::fromJakartaTaglibDescriptor) 39 | .collect(Collectors.toList()); 40 | } 41 | 42 | @Override 43 | public Collection getJspPropertyGroups() { 44 | return from.getJspPropertyGroups().stream() 45 | .map(JspPropertyGroupDescriptorWrapper::fromJakartaJspPropertyGroupDescriptor) 46 | .collect(Collectors.toList()); 47 | } 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/descriptor/TaglibDescriptorWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.descriptor; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.descriptor.TaglibDescriptor; 5 | 6 | public class TaglibDescriptorWrapper { 7 | public static jakarta.servlet.descriptor.TaglibDescriptor toJakartaTaglibDescriptor(TaglibDescriptor from) { 8 | Objects.requireNonNull(from); 9 | return new jakarta.servlet.descriptor.TaglibDescriptor() { 10 | @Override 11 | public String getTaglibURI() { 12 | return from.getTaglibURI(); 13 | } 14 | 15 | @Override 16 | public String getTaglibLocation() { 17 | return from.getTaglibLocation(); 18 | } 19 | }; 20 | } 21 | 22 | public static TaglibDescriptor fromJakartaTaglibDescriptor(jakarta.servlet.descriptor.TaglibDescriptor from) { 23 | Objects.requireNonNull(from); 24 | return new TaglibDescriptor() { 25 | @Override 26 | public String getTaglibURI() { 27 | return from.getTaglibURI(); 28 | } 29 | 30 | @Override 31 | public String getTaglibLocation() { 32 | return from.getTaglibLocation(); 33 | } 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/http/CookieWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.http; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import java.util.Objects; 5 | import javax.servlet.http.Cookie; 6 | 7 | public class CookieWrapper { 8 | @SuppressFBWarnings( 9 | value = {"HTTPONLY_COOKIE", "INSECURE_COOKIE"}, 10 | justification = "TODO needs triage") 11 | public static jakarta.servlet.http.Cookie toJakartaServletHttpCookie(Cookie from) { 12 | Objects.requireNonNull(from); 13 | jakarta.servlet.http.Cookie result = new jakarta.servlet.http.Cookie(from.getName(), from.getValue()); 14 | if (from.getComment() != null) { 15 | result.setComment(from.getComment()); 16 | } 17 | if (from.getDomain() != null) { 18 | result.setDomain(from.getDomain()); 19 | } 20 | result.setMaxAge(from.getMaxAge()); 21 | if (from.getPath() != null) { 22 | result.setPath(from.getPath()); 23 | } 24 | result.setSecure(from.getSecure()); 25 | result.setVersion(from.getVersion()); 26 | result.setHttpOnly(from.isHttpOnly()); 27 | return result; 28 | } 29 | 30 | @SuppressFBWarnings( 31 | value = {"HTTPONLY_COOKIE", "INSECURE_COOKIE"}, 32 | justification = "for compatibility") 33 | public static Cookie fromJakartaServletHttpCookie(jakarta.servlet.http.Cookie from) { 34 | Objects.requireNonNull(from); 35 | Cookie result = new Cookie(from.getName(), from.getValue()); 36 | if (from.getComment() != null) { 37 | result.setComment(from.getComment()); 38 | } 39 | if (from.getDomain() != null) { 40 | result.setDomain(from.getDomain()); 41 | } 42 | result.setMaxAge(from.getMaxAge()); 43 | if (from.getPath() != null) { 44 | result.setPath(from.getPath()); 45 | } 46 | result.setSecure(from.getSecure()); 47 | result.setVersion(from.getVersion()); 48 | result.setHttpOnly(from.isHttpOnly()); 49 | return result; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/http/HttpServletMappingWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.http; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.http.HttpServletMapping; 5 | import javax.servlet.http.MappingMatch; 6 | 7 | public class HttpServletMappingWrapper { 8 | public static jakarta.servlet.http.HttpServletMapping toJakartaHttpServletMapping(HttpServletMapping from) { 9 | Objects.requireNonNull(from); 10 | return new jakarta.servlet.http.HttpServletMapping() { 11 | @Override 12 | public String getMatchValue() { 13 | return from.getMatchValue(); 14 | } 15 | 16 | @Override 17 | public String getPattern() { 18 | return from.getPattern(); 19 | } 20 | 21 | @Override 22 | public String getServletName() { 23 | return from.getServletName(); 24 | } 25 | 26 | @Override 27 | public jakarta.servlet.http.MappingMatch getMappingMatch() { 28 | return MappingMatchWrapper.toJakartaMappingMatch(from.getMappingMatch()); 29 | } 30 | }; 31 | } 32 | 33 | public static HttpServletMapping fromJakartaHttpServletMapping(jakarta.servlet.http.HttpServletMapping from) { 34 | Objects.requireNonNull(from); 35 | return new HttpServletMapping() { 36 | @Override 37 | public String getMatchValue() { 38 | return from.getMatchValue(); 39 | } 40 | 41 | @Override 42 | public String getPattern() { 43 | return from.getPattern(); 44 | } 45 | 46 | @Override 47 | public String getServletName() { 48 | return from.getServletName(); 49 | } 50 | 51 | @Override 52 | public MappingMatch getMappingMatch() { 53 | return MappingMatchWrapper.fromJakartaMappingMatch(from.getMappingMatch()); 54 | } 55 | }; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/http/HttpSessionContextWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.http; 2 | 3 | import java.util.Enumeration; 4 | import java.util.Objects; 5 | import javax.servlet.http.HttpSession; 6 | import javax.servlet.http.HttpSessionContext; 7 | 8 | public class HttpSessionContextWrapper { 9 | public static jakarta.servlet.http.HttpSessionContext toJakartaHttpSessionContext(HttpSessionContext from) { 10 | Objects.requireNonNull(from); 11 | return new jakarta.servlet.http.HttpSessionContext() { 12 | @Override 13 | public jakarta.servlet.http.HttpSession getSession(String sessionId) { 14 | return HttpSessionWrapper.toJakartaHttpSession(from.getSession(sessionId)); 15 | } 16 | 17 | @Override 18 | public Enumeration getIds() { 19 | return from.getIds(); 20 | } 21 | }; 22 | } 23 | 24 | public static HttpSessionContext fromJakartaHttpSessionContext(jakarta.servlet.http.HttpSessionContext from) { 25 | Objects.requireNonNull(from); 26 | return new HttpSessionContext() { 27 | @Override 28 | public HttpSession getSession(String sessionId) { 29 | return HttpSessionWrapper.fromJakartaHttpSession(from.getSession(sessionId)); 30 | } 31 | 32 | @Override 33 | public Enumeration getIds() { 34 | return from.getIds(); 35 | } 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/http/HttpSessionEventWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.http; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.http.HttpSessionEvent; 5 | 6 | public class HttpSessionEventWrapper { 7 | public static jakarta.servlet.http.HttpSessionEvent toJakartaHttpSessionEvent(HttpSessionEvent from) { 8 | Objects.requireNonNull(from); 9 | return new jakarta.servlet.http.HttpSessionEvent(HttpSessionWrapper.toJakartaHttpSession(from.getSession())); 10 | } 11 | 12 | public static HttpSessionEvent fromJakartaHttpSessionEvent(jakarta.servlet.http.HttpSessionEvent from) { 13 | Objects.requireNonNull(from); 14 | return new HttpSessionEvent(HttpSessionWrapper.fromJakartaHttpSession(from.getSession())); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/http/MappingMatchWrapper.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.servlet.http; 2 | 3 | import java.util.Objects; 4 | import javax.servlet.http.MappingMatch; 5 | 6 | public class MappingMatchWrapper { 7 | public static jakarta.servlet.http.MappingMatch toJakartaMappingMatch(MappingMatch from) { 8 | Objects.requireNonNull(from); 9 | switch (from) { 10 | case CONTEXT_ROOT: 11 | return jakarta.servlet.http.MappingMatch.CONTEXT_ROOT; 12 | case DEFAULT: 13 | return jakarta.servlet.http.MappingMatch.DEFAULT; 14 | case EXACT: 15 | return jakarta.servlet.http.MappingMatch.EXACT; 16 | case EXTENSION: 17 | return jakarta.servlet.http.MappingMatch.EXTENSION; 18 | case PATH: 19 | return jakarta.servlet.http.MappingMatch.PATH; 20 | default: 21 | throw new IllegalArgumentException("Unknown MappingMatch: " + from); 22 | } 23 | } 24 | 25 | public static MappingMatch fromJakartaMappingMatch(jakarta.servlet.http.MappingMatch from) { 26 | Objects.requireNonNull(from); 27 | switch (from) { 28 | case CONTEXT_ROOT: 29 | return MappingMatch.CONTEXT_ROOT; 30 | case DEFAULT: 31 | return MappingMatch.DEFAULT; 32 | case EXACT: 33 | return MappingMatch.EXACT; 34 | case EXTENSION: 35 | return MappingMatch.EXTENSION; 36 | case PATH: 37 | return MappingMatch.PATH; 38 | default: 39 | throw new IllegalArgumentException("Unknown MappingMatch: " + from); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/io/jenkins/servlet/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Compatibility layer to convert to/from EE 8/9. 3 | * 4 | *

All files in this package are kept separate from the {@code javax.servlet} package namespace to avoid potential 5 | * trademark issues. Unfortunately, this results in a lot of static methods rather than object-oriented programming. The 6 | * resulting loss of readability is unfortunate but necessary. 7 | */ 8 | package io.jenkins.servlet; 9 | -------------------------------------------------------------------------------- /core/src/main/java/org/apache/commons/fileupload/InvalidFileNameException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.apache.commons.fileupload; 19 | 20 | /** 21 | * This exception is thrown in case of an invalid file name. 22 | * A file name is invalid, if it contains a NUL character. 23 | * Attackers might use this to circumvent security checks: 24 | * For example, a malicious user might upload a file with the name 25 | * "foo.exe\0.png". This file name might pass security checks (i.e. 26 | * checks for the extension ".png"), while, depending on the underlying 27 | * C library, it might create a file named "foo.exe", as the NUL 28 | * character is the string terminator in C. 29 | */ 30 | public class InvalidFileNameException extends RuntimeException { 31 | 32 | /** 33 | * Serial version UID, being used, if the exception 34 | * is serialized. 35 | */ 36 | private static final long serialVersionUID = 7922042602454350470L; 37 | 38 | /** 39 | * The file name causing the exception. 40 | */ 41 | private final String name; 42 | 43 | /** 44 | * Creates a new instance. 45 | * 46 | * @param pName The file name causing the exception. 47 | * @param pMessage A human readable error message. 48 | */ 49 | public InvalidFileNameException(String pName, String pMessage) { 50 | super(pMessage); 51 | name = pName; 52 | } 53 | 54 | /** 55 | * Returns the invalid file name. 56 | * 57 | * @return the invalid file name. 58 | */ 59 | public String getName() { 60 | return name; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/BindInterceptor.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.lang.reflect.Type; 4 | import net.sf.json.JSONObject; 5 | 6 | /** 7 | * Intercepts (and receives callbacks) about the JSON → object binding process. 8 | * 9 | * @author Kohsuke Kawaguchi 10 | * @see StaplerRequest2#setBindInterceptor(BindInterceptor) 11 | * @see WebApp#bindInterceptors 12 | */ 13 | public class BindInterceptor { 14 | /** 15 | * Called for each object conversion, after the expected type is determined. 16 | * 17 | * @param targetType 18 | * Type that the converted object must be assignable to. 19 | * @param targetTypeErasure 20 | * Erasure of the {@code targetType} parameter. 21 | * @param jsonSource 22 | * JSON object to be mapped to Java object. 23 | * @return 24 | * {@link #DEFAULT} to indicate that the default conversion process should proceed. 25 | * Any other values (including null) will override the process. 26 | */ 27 | public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSource) { 28 | return DEFAULT; 29 | } 30 | 31 | /** 32 | * Called for each object conversion, after the actual subtype to instantiate is determined. 33 | * 34 | * @param actualType 35 | * The type to instantiate 36 | * @param json 37 | * JSON object to be mapped to Java object. 38 | * @return 39 | * {@link #DEFAULT} to indicate that the default conversion process should proceed. 40 | * Any other values (including null) will override the process. 41 | */ 42 | public Object instantiate(Class actualType, JSONObject json) { 43 | return DEFAULT; 44 | } 45 | 46 | /** 47 | * Indicates that the conversion should proceed as it normally does, 48 | * and that the listener isn't replacing the process. 49 | */ 50 | public static final Object DEFAULT = new Object(); 51 | 52 | /** 53 | * Default {@link BindInterceptor} that does nothing. 54 | */ 55 | public static final BindInterceptor NOOP = new BindInterceptor(); 56 | } 57 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/CancelRequestHandlingException.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | /** 4 | * Signals that the request dispatching to the current method is cancelled, 5 | * and that Stapler should resume the search for the next request dispatcher 6 | * and dispatch the request accordingly. 7 | * 8 | *

9 | * This is useful in conjunction with {@link StaplerOverridable} to delegate 10 | * requests selectively to original object after examining the request, 11 | * or in a request handling method like {@code doXyz()} method to then fall 12 | * back to {@code getDynamic()} or anything else. 13 | * 14 | * @author Kohsuke Kawaguchi 15 | * @since 1.210 16 | */ 17 | public class CancelRequestHandlingException extends RuntimeException {} 18 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/CapturedParameterNames.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler; 25 | 26 | import java.lang.annotation.Retention; 27 | import java.lang.annotation.RetentionPolicy; 28 | 29 | /** 30 | * This "hidden" annotation is injected by Groovy compiler to capture parameter names 31 | * in the class file. Groovyc doesn't let me generate additional files, so this is easier 32 | * to do than generating the same files that the annotation processor does. 33 | * 34 | * @author Kohsuke Kawaguchi 35 | * @see CaptureParameterNameTransformation 36 | */ 37 | @Retention(RetentionPolicy.RUNTIME) 38 | public @interface CapturedParameterNames { 39 | String[] value(); 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/DataBoundResolvable.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import net.sf.json.JSONObject; 4 | 5 | /** 6 | * For data-bound class (that has a constructor marked with {@link DataBoundConstructor}, the 7 | * {@link #bindResolve(StaplerRequest2, JSONObject)} allows an instance to replace the object 8 | * bound from submitted JSON object. 9 | * 10 | *

11 | * This method is automatically invoked by Stapler during databinding method like 12 | * {@link StaplerRequest2#bindJSON(Class, JSONObject)}. 13 | * 14 | *

15 | * This method definition is inspired by Java serialization's {@code readResolve()} method. 16 | * 17 | * @author Kohsuke Kawaguchi 18 | * @see JENKINS-201262 19 | */ 20 | public interface DataBoundResolvable { 21 | /** 22 | * Called after the object is instantiated to allow the object to nominate its replacement. 23 | * 24 | * @param request 25 | * Request object that's currently performing databinding. Passed in as a contextual 26 | * parameter. 27 | * @param src 28 | * JSON object that originally constructed the 'this' instance on which this method 29 | * is being invoked. 30 | * @return 31 | * Can be any value, including null. Typically, this method would have to return an 32 | * instance of a type compatible to the caller's expectation. 33 | */ 34 | Object bindResolve(StaplerRequest2 request, JSONObject src); 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/DataBoundSetter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.annotation.PostConstruct; 4 | import java.beans.Introspector; 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | import net.sf.json.JSONObject; 11 | 12 | /** 13 | * Designates a setter method or a field used to databind JSON values into objects in methods like 14 | * {@link StaplerRequest2#bindJSON(Class, JSONObject)} and 15 | * {@link StaplerRequest2#bindParameters(Class, String)}. 16 | * 17 | *

18 | * Stapler will first invoke {@link DataBoundConstructor}-annotated constructor, and if there's any 19 | * remaining properties in JSON, it'll try to find a matching {@link DataBoundSetter}-annotated setter 20 | * method or a field. 21 | * 22 | *

23 | * The setter method is discovered through {@link Introspector}, so setter method name must match 24 | * the property name (such as {@code setFoo} for the {@code foo} property), and it needs to be public. 25 | * 26 | *

27 | * The field is discovered through simple reflection, so its name must match the property name, but 28 | * its access modifier can be anything. 29 | * 30 | *

31 | * To create a method to be called after all the setter injections are complete, annotate a method 32 | * with {@link PostConstruct}. 33 | * 34 | * @author Kohsuke Kawaguchi 35 | */ 36 | @Retention(RetentionPolicy.RUNTIME) 37 | @Target({ElementType.METHOD, ElementType.FIELD}) 38 | @Documented 39 | public @interface DataBoundSetter {} 40 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/DiagnosticThreadNameFilter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.Filter; 4 | import jakarta.servlet.FilterChain; 5 | import jakarta.servlet.FilterConfig; 6 | import jakarta.servlet.ServletException; 7 | import jakarta.servlet.ServletRequest; 8 | import jakarta.servlet.ServletResponse; 9 | import jakarta.servlet.http.HttpServletRequest; 10 | import java.io.IOException; 11 | 12 | /** 13 | * {@link Filter} that sets the thread name to reflect the current request being processed. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | public class DiagnosticThreadNameFilter implements CompatibleFilter { 18 | @Override 19 | public void init(FilterConfig filterConfig) throws ServletException {} 20 | 21 | @Override 22 | public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain) 23 | throws IOException, ServletException { 24 | Thread t = Thread.currentThread(); 25 | final String oldName = t.getName(); 26 | try { 27 | HttpServletRequest hreq = (HttpServletRequest) req; 28 | t.setName("Handling " + hreq.getMethod() + ' ' + hreq.getRequestURI() + " from " + hreq.getRemoteAddr() 29 | + " : " + oldName); 30 | 31 | chain.doFilter(req, rsp); 32 | } finally { 33 | t.setName(oldName); 34 | } 35 | } 36 | 37 | @Override 38 | public void destroy() {} 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/DirectoryishDispatcher.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.io.IOException; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.util.logging.Level; 7 | import java.util.logging.Logger; 8 | 9 | /** 10 | * {@link Dispatcher} that tells browsers to append '/' to the request path and try again. 11 | * 12 | * If we are serving the index page, we demand that the URL be '/some/dir/' not '/some/dir' 13 | * so that relative links in the page will resolve correctly. Apache does the same thing. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | class DirectoryishDispatcher extends Dispatcher { 18 | @Override 19 | public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) 20 | throws IOException, ServletException, IllegalAccessException, InvocationTargetException { 21 | if (!req.tokens.hasMore()) { 22 | String servletPath = req.stapler.getServletPath(req); 23 | if (!servletPath.endsWith("/")) { 24 | String target = req.getContextPath() + servletPath + '/'; 25 | if (req.getQueryString() != null) { 26 | target += '?' + req.getQueryString(); 27 | } 28 | if (LOGGER.isLoggable(Level.FINER)) { 29 | LOGGER.finer("Redirecting to " + target); 30 | } 31 | rsp.sendRedirect2(target); 32 | return true; 33 | } 34 | } 35 | 36 | return false; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "If path ends without '/' insert it"; 42 | } 43 | 44 | private static final Logger LOGGER = Logger.getLogger(DirectoryishDispatcher.class.getName()); 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/DispatchersFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler; 26 | 27 | import java.util.List; 28 | 29 | /** 30 | * Registered inside {@link WebApp#setDispatchersFilter(DispatchersFilter)} and then used after the creation of 31 | * the dispatchers for a {@link MetaClass} in order to add / remove / edit the dispatchers that are created. 32 | */ 33 | public interface DispatchersFilter { 34 | void applyOn(MetaClass metaClass, FunctionList methods, List dispatcherList); 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/IndexDispatcher.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.io.IOException; 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | /** 8 | * {@link Dispatcher} for url=/ that handles the tail of an URL. 9 | * 10 | * @author Kohsuke Kawaguchi 11 | */ 12 | class IndexDispatcher extends Dispatcher { 13 | private final Function f; 14 | 15 | IndexDispatcher(Function f) { 16 | this.f = f; 17 | } 18 | 19 | @Override 20 | public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) 21 | throws IllegalAccessException, InvocationTargetException, ServletException, IOException { 22 | if (req.tokens.hasMore()) { 23 | return false; // applicable only when there's no more token 24 | } 25 | 26 | Dispatcher.anonymizedTraceEval(req, rsp, node, "%s: Index: %s", f.getName()); 27 | if (traceable()) { 28 | trace(req, rsp, "-> <%s>.%s(...)", node, f.getName()); 29 | } 30 | 31 | return f.bindAndInvokeAndServeResponse(node, req, rsp); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return f.getQualifiedName() + "(...) for url=/"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/IndexHtmlDispatcher.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletContext; 4 | import jakarta.servlet.ServletException; 5 | import java.io.IOException; 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | 9 | /** 10 | * Serve {@code index.html} from {@code WEB-INF/side-files} if that exists. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | class IndexHtmlDispatcher extends Dispatcher { 15 | private final URL html; 16 | 17 | IndexHtmlDispatcher(URL html) { 18 | this.html = html; 19 | } 20 | 21 | @Override 22 | public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) throws IOException, ServletException { 23 | if (!req.tokens.hasMore()) { 24 | rsp.serveFile(req, html, 0); 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "index.html for url=/"; 33 | } 34 | 35 | /** 36 | * Returns a {@link IndexHtmlDispatcher} if and only if the said class has {@code index.html} as a side-file. 37 | * @param c Class from where to start the index.html inspection. Will go through class hierarchy (unless interface) 38 | * @return Index dispatcher or {@code null} if it cannot be found 39 | */ 40 | static Dispatcher make(ServletContext context, Class c) { 41 | for (; c != null && c != Object.class; c = c.getSuperclass()) { 42 | String name = "/WEB-INF/side-files/" + c.getName().replace('.', '/') + "/index.html"; 43 | try { 44 | URL url = context.getResource(name); 45 | if (url != null) { 46 | return new IndexHtmlDispatcher(url); 47 | } 48 | } catch (MalformedURLException e) { 49 | throw new IllegalArgumentException(e); 50 | } 51 | } 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/IndexViewDispatcher.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.io.IOException; 5 | import java.lang.reflect.InvocationTargetException; 6 | 7 | /** 8 | * {@link Dispatcher} that deals with the "index" view pages that are used when the request path doesn't contain 9 | * any token for the current object. 10 | * 11 | *

12 | * It is analogous to Apache serving a directory index if a directory itself is requested, as opposed to a file in it. 13 | * 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | class IndexViewDispatcher extends Dispatcher { 17 | private final MetaClass metaClass; 18 | private final Facet facet; 19 | 20 | IndexViewDispatcher(MetaClass metaClass, Facet facet) { 21 | this.metaClass = metaClass; 22 | this.facet = facet; 23 | } 24 | 25 | @Override 26 | public boolean dispatch(RequestImpl req, ResponseImpl rsp, Object node) 27 | throws IOException, ServletException, IllegalAccessException, InvocationTargetException { 28 | if (req.tokens.hasMore()) { 29 | return false; 30 | } 31 | 32 | // always allow index views to be dispatched 33 | req.getWebApp().getDispatchValidator().allowDispatch(req, rsp); 34 | return facet.handleIndexRequest(req, rsp, node, metaClass); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "index view of " + facet + " for url=/"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/InjectedParameter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Used on annotations to indicate that it signals a parameter injection in web-bound "doXyz" methods. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.ANNOTATION_TYPE) 16 | @Documented 17 | public @interface InjectedParameter { 18 | /** 19 | * Code that computes the actual value to inject. 20 | * 21 | * One instance of this is created lazily and reused concurrently. 22 | */ 23 | Class value(); 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/JavaScriptMethodContext.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import org.kohsuke.stapler.bind.JavaScriptMethod; 4 | 5 | /** 6 | * {@link Function#contextualize(Object)} parameter that indicates 7 | * the function is called to serve JavaScript method invocation from a proxy. 8 | * 9 | * @author Kohsuke Kawaguchi 10 | * @see JavaScriptMethod 11 | */ 12 | public final class JavaScriptMethodContext { 13 | private final String name; 14 | 15 | // instantiation restricted to this class 16 | /*package*/ JavaScriptMethodContext(String name) { 17 | this.name = name; 18 | } 19 | 20 | /** 21 | * Name of the web method. "" for index route. 22 | */ 23 | public String getName() { 24 | return name; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/JsonInErrorMessageSanitizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler; 26 | 27 | import net.sf.json.JSONObject; 28 | 29 | /** 30 | * Customize / sanitize the JSON before putting it in the stack trace / error messages. 31 | * Mainly thought to avoid leaking secrets / credentials in the log. 32 | */ 33 | public interface JsonInErrorMessageSanitizer { 34 | /** 35 | * Removes/redacts all the confidential information to let the result to be printed in the log / stack trace / error message. 36 | * Must return a new instance of the JSON. 37 | */ 38 | JSONObject sanitize(JSONObject jsonData); 39 | 40 | /** 41 | * Used by default when no other sanitizer are configured. Has no effect on the information, just returning a copy. 42 | */ 43 | JsonInErrorMessageSanitizer NOOP = JSONObject::fromObject; 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/KlassDescriptor.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.util.List; 4 | import org.kohsuke.stapler.lang.FieldRef; 5 | import org.kohsuke.stapler.lang.Klass; 6 | 7 | /** 8 | * Reflection information of a {@link Klass} that drives the request routing. 9 | * 10 | *

11 | * Born as a generalization of {@link ClassDescriptor} to {@link Klass}. 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | class KlassDescriptor { 15 | final Klass clazz; 16 | final FunctionList methods; 17 | final List fields; 18 | 19 | /** 20 | * @param klazz 21 | * The class to build a descriptor around. 22 | */ 23 | KlassDescriptor(Klass klazz) { 24 | this.clazz = klazz; 25 | this.fields = klazz.getFields(); 26 | this.methods = new FunctionList(klazz.getFunctions()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/MethodHandleFactory.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodHandles.Lookup; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * Implementation detail in Stapler. Do not use from outside. 10 | */ 11 | public final class MethodHandleFactory { 12 | private static final Lookup LOOKUP = MethodHandles.lookup(); 13 | 14 | public static MethodHandle get(Method method) { 15 | try { 16 | /* 17 | Stapler generally deals with 18 | */ 19 | method.setAccessible(true); 20 | 21 | return LOOKUP.unreflect(method); 22 | } catch (IllegalAccessException e) { 23 | throw (Error) new IllegalAccessError("Protected method: " + method).initCause(e); 24 | } 25 | } 26 | 27 | private MethodHandleFactory() {} 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/NoStaplerConstructorException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler; 25 | 26 | /** 27 | * @author Kohsuke Kawaguchi 28 | */ 29 | public class NoStaplerConstructorException extends IllegalArgumentException { 30 | public NoStaplerConstructorException(String s) { 31 | super(s); 32 | } 33 | 34 | public NoStaplerConstructorException(String message, Throwable cause) { 35 | super(message, cause); 36 | } 37 | 38 | public NoStaplerConstructorException(Throwable cause) { 39 | super(cause); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/PreInvokeInterceptedFunction.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.lang.reflect.InvocationTargetException; 5 | import org.kohsuke.stapler.interceptor.Interceptor; 6 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 7 | import org.kohsuke.stapler.interceptor.Stage; 8 | 9 | /** 10 | * Function that's wrapped by {@link Interceptor} for {@link Stage#PREINVOKE} 11 | * 12 | * @see InterceptorAnnotation 13 | */ 14 | final class PreInvokeInterceptedFunction extends ForwardingFunction { 15 | private final Interceptor interceptor; 16 | 17 | /*package*/ PreInvokeInterceptedFunction(Function next, Interceptor i) { 18 | super(next); 19 | this.interceptor = i; 20 | interceptor.setTarget(next); 21 | } 22 | 23 | @Override 24 | public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) 25 | throws IllegalAccessException, InvocationTargetException, ServletException { 26 | return interceptor.invoke(req, rsp, o, args); 27 | } 28 | 29 | @Override 30 | public Function contextualize(Object usage) { 31 | Function f = next.contextualize(usage); 32 | if (f == next) { 33 | return this; // the base function didn't care 34 | } 35 | return new PreInvokeInterceptedFunction(f, interceptor); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/RawHtmlArgument.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | /** 4 | * Argument to expressions that indicates this value is raw HTML 5 | * and therefore should not be further escaped. 6 | */ 7 | public class RawHtmlArgument { 8 | private final Object value; 9 | 10 | public RawHtmlArgument(Object value) { 11 | this.value = value; 12 | } 13 | 14 | public Object getValue() { 15 | return value; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return value == null ? "null" : value.toString(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/ScriptExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler; 26 | 27 | import edu.umd.cs.findbugs.annotations.CheckForNull; 28 | import edu.umd.cs.findbugs.annotations.NonNull; 29 | 30 | /** 31 | * Execution strategy for handling views written in other scripting languages. 32 | * 33 | * @param script type 34 | * @since TODO 35 | */ 36 | public interface ScriptExecutor { 37 | 38 | /** 39 | * Executes the given script on the given node and request, rendering output to the given response. 40 | */ 41 | void execute( 42 | @NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp, @NonNull S script, @CheckForNull Object it) 43 | throws Exception; 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/ScriptLoadException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler; 25 | 26 | /** 27 | * @deprecated No longer used. 28 | */ 29 | @Deprecated 30 | public class ScriptLoadException extends RuntimeException { 31 | public ScriptLoadException(String message, Throwable cause) { 32 | super(message, cause); 33 | } 34 | 35 | public ScriptLoadException(Throwable cause) { 36 | super(cause); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/SelectionInterceptedFunction.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.lang.reflect.InvocationTargetException; 5 | import org.kohsuke.stapler.interceptor.Interceptor; 6 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 7 | 8 | /** 9 | * {@link Function} that uses {@link Interceptor} for method selection phase. 10 | * 11 | * @see InterceptorAnnotation 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | /*package*/ class SelectionInterceptedFunction extends ForwardingFunction { 15 | private final Interceptor interceptor; 16 | 17 | /*package*/ SelectionInterceptedFunction(Function next, Interceptor i) { 18 | super(next); 19 | this.interceptor = i; 20 | interceptor.setTarget(new Adapter(next)); 21 | } 22 | 23 | @Override 24 | Object bindAndInvoke(Object o, StaplerRequest2 req, StaplerResponse2 rsp, Object... headArgs) 25 | throws IllegalAccessException, InvocationTargetException, ServletException { 26 | return interceptor.invoke(req, rsp, o, headArgs); 27 | } 28 | 29 | private static final class Adapter extends ForwardingFunction { 30 | Adapter(Function next) { 31 | super(next); 32 | } 33 | 34 | @Override 35 | public Object invoke(StaplerRequest2 req, StaplerResponse2 rsp, Object o, Object... args) 36 | throws IllegalAccessException, InvocationTargetException, ServletException { 37 | return next.bindAndInvoke(o, req, rsp, args); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/SingleLinkedList.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.util.AbstractList; 4 | import java.util.Iterator; 5 | import java.util.NoSuchElementException; 6 | 7 | /** 8 | * Single linked list which allows sharing of the suffix. 9 | * 10 | * @author Kohsuke Kawaguchi 11 | * @since 1.220 12 | */ 13 | public class SingleLinkedList extends AbstractList { 14 | public final T head; 15 | public final SingleLinkedList tail; 16 | 17 | public SingleLinkedList(T head, SingleLinkedList tail) { 18 | this.head = head; 19 | this.tail = tail; 20 | } 21 | 22 | /** 23 | * Creates a new list by adding a new element as the head. 24 | */ 25 | public SingleLinkedList grow(T item) { 26 | return new SingleLinkedList<>(item, this); 27 | } 28 | 29 | @Override 30 | public Iterator iterator() { 31 | return new Iterator<>() { 32 | SingleLinkedList next = SingleLinkedList.this; 33 | 34 | @Override 35 | public boolean hasNext() { 36 | return next != EMPTY_LIST; 37 | } 38 | 39 | @Override 40 | public T next() { 41 | if (!hasNext()) { 42 | throw new NoSuchElementException(); 43 | } 44 | T r = next.head; 45 | next = next.tail; 46 | return r; 47 | } 48 | 49 | @Override 50 | public void remove() { 51 | throw new UnsupportedOperationException(); 52 | } 53 | }; 54 | } 55 | 56 | @Override 57 | public T get(int index) { 58 | return null; 59 | } 60 | 61 | @Override 62 | public int size() { 63 | int sz = 0; 64 | for (SingleLinkedList head = this; head != EMPTY_LIST; head = head.tail) { 65 | sz++; 66 | } 67 | return sz; 68 | } 69 | 70 | @Override 71 | public boolean isEmpty() { 72 | return this == EMPTY_LIST; 73 | } 74 | 75 | public static SingleLinkedList empty() { 76 | return EMPTY_LIST; 77 | } 78 | 79 | private static final SingleLinkedList EMPTY_LIST = new SingleLinkedList(null, null); 80 | } 81 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/StaplerFallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler; 25 | 26 | /** 27 | * An object can fall back to another object for a part of its UI processing, 28 | * by implementing this interface and designating another object from 29 | * {@link #getStaplerFallback()}. 30 | * 31 | *

32 | * Compared to {@link StaplerProxy}, stapler handles this interface at the very end, 33 | * whereas {@link StaplerProxy} is handled at the very beginning. 34 | * 35 | * @author Kohsuke Kawaguchi 36 | * @see StaplerProxy 37 | */ 38 | public interface StaplerFallback { 39 | /** 40 | * Returns the object that is further searched for processing web requests. 41 | * 42 | * @return 43 | * If null or {@code this} is returned, stapler behaves as if the object 44 | * didn't implement this interface (which means the request processing 45 | * fails with 404.) 46 | */ 47 | Object getStaplerFallback(); 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/TraversalMethodContext.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | /** 4 | * {@link Function#contextualize(Object)} parameter that indicates 5 | * the function is called to traverse an object graph. 6 | * 7 | * @author Kohsuke Kawaguchi 8 | * @see WebMethod 9 | */ 10 | public final class TraversalMethodContext { 11 | private final String name; 12 | 13 | // instantiation restricted to this class 14 | /*package*/ TraversalMethodContext(String name) { 15 | this.name = name; 16 | } 17 | 18 | /** 19 | * Name of the web method. "" for index route. 20 | */ 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | /** 26 | * Used as a special name that represents {@code getDynamic(...)} that does dynamic traversal. 27 | */ 28 | public static final String DYNAMIC = "\u0000"; 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/UnionAnnotatedElement.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.AnnotatedElement; 5 | import java.util.List; 6 | 7 | /** 8 | * Presents combined view of all the annotations. 9 | * 10 | * The item in the source list with smaller index is preferred (think of it as 'override') 11 | * over the item with larger index. 12 | */ 13 | class UnionAnnotatedElement implements AnnotatedElement { 14 | private final List sources; 15 | 16 | UnionAnnotatedElement(List sources) { 17 | this.sources = sources; 18 | } 19 | 20 | @Override 21 | public boolean isAnnotationPresent(Class annotationClass) { 22 | for (AnnotatedElement s : sources) { 23 | if (s.isAnnotationPresent(annotationClass)) { 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | @Override 31 | public T getAnnotation(Class annotationClass) { 32 | for (AnnotatedElement s : sources) { 33 | T a = s.getAnnotation(annotationClass); 34 | if (a != null) { 35 | return a; 36 | } 37 | } 38 | return null; 39 | } 40 | 41 | @Override 42 | public Annotation[] getAnnotations() { 43 | Annotation[] a = null; 44 | for (AnnotatedElement s : sources) { 45 | Annotation[] next = s.getAnnotations(); 46 | if (a == null) { 47 | a = next; 48 | } else { 49 | a = ReflectionUtils.union(a, next); 50 | } 51 | } 52 | return a; 53 | } 54 | 55 | @Override 56 | public Annotation[] getDeclaredAnnotations() { 57 | return sources.get(sources.size() - 1).getAnnotations(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/WebMethodContext.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | /** 4 | * {@link Function#contextualize(Object)} parameter that indicates 5 | * the function is called to serve request, such as {@code doFoo(...)} or {@code doIndex(...)} 6 | * 7 | * @author Kohsuke Kawaguchi 8 | * @see WebMethod 9 | */ 10 | public final class WebMethodContext { 11 | private final String name; 12 | 13 | // instantiation restricted to this class 14 | /*package*/ WebMethodContext(String name) { 15 | this.name = name; 16 | } 17 | 18 | /** 19 | * Name of the web method. "" for index route. 20 | */ 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | /** 26 | * Used as a special name that represents {@code doDynamic(...)} that does dynamic traversal. 27 | */ 28 | public static final String DYNAMIC = "\u0000"; 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/WrongTypeException.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | public class WrongTypeException extends IllegalArgumentException { 4 | public WrongTypeException(String s) { 5 | super(s); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/bind/WithWellKnownURL.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.bind; 25 | 26 | /** 27 | * Marker interface for objects that have known URLs. 28 | * 29 | * If objects that implement this interface are exported, the well-known URLs 30 | * are used instead of assigning temporary URLs to objects. In this way, the application 31 | * can reduce memory consumption. This also enables objects to have "identities" 32 | * that outlive their GC life (for example, instance of the JPA-bound "User" class can 33 | * come and go, but they represent the single identity that's pointed by its primary key.) 34 | * 35 | * @author Kohsuke Kawaguchi 36 | */ 37 | public interface WithWellKnownURL { 38 | /** 39 | * @return a URL appended to the context path, such as {@code /myWidget} 40 | */ 41 | String getWellKnownUrl(); 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/bind/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /** 25 | * Subsystem for exposing arbitrary objects on per-session basis to the URL space. 26 | */ 27 | package org.kohsuke.stapler.bind; 28 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/config/Configuration.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.config; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Customizes how the property retrieval is handled. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | * @see ConfigurationLoader 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target(ElementType.METHOD) 17 | @Documented 18 | public @interface Configuration { 19 | 20 | /** 21 | * Name of the property. 22 | */ 23 | String name() default UNSPECIFIED; 24 | 25 | /** 26 | * Default value to be applied if the actual configuration source doesn't specify this property. 27 | */ 28 | String defaultValue() default UNSPECIFIED; 29 | 30 | String UNSPECIFIED = "\u0000"; 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/event/FilteredDispatchTriggerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2019 CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler.event; 26 | 27 | import java.util.logging.Logger; 28 | import org.kohsuke.stapler.StaplerRequest2; 29 | import org.kohsuke.stapler.StaplerResponse2; 30 | 31 | /** 32 | * Listens to filtered dispatch events from {@link org.kohsuke.stapler.DispatchValidator}. 33 | * 34 | * @since TODO 35 | * @see org.kohsuke.stapler.WebApp#setFilteredDispatchTriggerListener(FilteredDispatchTriggerListener) 36 | */ 37 | public interface FilteredDispatchTriggerListener { 38 | boolean onDispatchTrigger(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String viewName); 39 | 40 | FilteredDispatchTriggerListener JUST_WARN = new FilteredDispatchTriggerListener() { 41 | private final Logger LOGGER = Logger.getLogger(FilteredDispatchTriggerListener.class.getName()); 42 | 43 | @Override 44 | public boolean onDispatchTrigger(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String viewName) { 45 | LOGGER.warning(() -> "BLOCKED -> <" + node + ">." + viewName); 46 | return false; 47 | } 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/event/FilteredDoActionTriggerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler.event; 26 | 27 | import java.util.logging.Level; 28 | import java.util.logging.Logger; 29 | import org.kohsuke.stapler.Function; 30 | import org.kohsuke.stapler.StaplerRequest2; 31 | import org.kohsuke.stapler.StaplerResponse2; 32 | 33 | /** 34 | * Listener that is triggered when a doAction function - that is no more accepted - is called. 35 | */ 36 | public interface FilteredDoActionTriggerListener { 37 | boolean onDoActionTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node); 38 | 39 | FilteredDoActionTriggerListener JUST_WARN = new FilteredDoActionTriggerListener() { 40 | private final Logger LOGGER = Logger.getLogger(FilteredDoActionTriggerListener.class.getName()); 41 | 42 | @Override 43 | public boolean onDoActionTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node) { 44 | if (LOGGER.isLoggable(Level.WARNING)) { 45 | LOGGER.warning(String.format("BLOCKED -> <%s>.%s(...))", node, f.getName())); 46 | } 47 | return false; 48 | } 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/event/FilteredFieldTriggerListener.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.event; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | import org.kohsuke.stapler.RequestImpl; 6 | import org.kohsuke.stapler.StaplerRequest2; 7 | import org.kohsuke.stapler.StaplerResponse2; 8 | import org.kohsuke.stapler.lang.FieldRef; 9 | 10 | public interface FilteredFieldTriggerListener { 11 | boolean onFieldTrigger(FieldRef f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression); 12 | 13 | FilteredFieldTriggerListener JUST_WARN = new FilteredFieldTriggerListener() { 14 | private final Logger LOGGER = Logger.getLogger(FilteredFieldTriggerListener.class.getName()); 15 | 16 | @Override 17 | public boolean onFieldTrigger( 18 | FieldRef f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression) { 19 | if (LOGGER.isLoggable(Level.WARNING)) { 20 | LOGGER.warning(String.format( 21 | "BLOCKED -> evaluate(<%s>.%s,\"%s\")", 22 | node, expression, ((RequestImpl) req).tokens.assembleOriginalRestOfPath())); 23 | } 24 | return false; 25 | } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/export/CustomExportedBean.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.export; 25 | 26 | /** 27 | * Interface that an exposed bean can implement, to do the equivalent 28 | * of {@code writeReplace} in Java serialization. 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | public interface CustomExportedBean { 32 | /** 33 | * The returned object will be introspected and written as JSON/XML. 34 | */ 35 | Object toExportedObject(); 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/export/FilteringTreePruner.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.export; 2 | 3 | import java.util.function.Predicate; 4 | 5 | /** 6 | * Decorates a base {@link TreePruner} by refusing additional properties 7 | * instructed by {@linkplain Predicate an external logic.} 8 | * 9 | * @author Kohsuke Kawaguchi 10 | */ 11 | class FilteringTreePruner extends TreePruner { 12 | private final Predicate predicate; 13 | private final TreePruner base; 14 | 15 | FilteringTreePruner(Predicate predicate, TreePruner base) { 16 | this.predicate = predicate; 17 | this.base = base; 18 | } 19 | 20 | @Override 21 | public TreePruner accept(Object node, Property prop) { 22 | if (predicate.test(prop.name)) { 23 | return null; 24 | } 25 | TreePruner child = base.accept(node, prop); 26 | 27 | // for merge properties, the current restrictions on the property names should 28 | // still apply to the child TreePruner 29 | if (prop.merge && child != null) { 30 | child = new FilteringTreePruner(predicate, child); 31 | } 32 | 33 | return child; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/export/Range.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.export; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | /** 9 | * Specifies the range in a collection. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class Range { 14 | public final int min; 15 | public final int max; 16 | 17 | public Range(int min, int max) { 18 | this.min = min; 19 | this.max = max; 20 | } 21 | 22 | public List apply(T[] a) { 23 | return apply(Arrays.asList(a)); 24 | } 25 | 26 | public List apply(List s) { 27 | if (max < s.size()) { 28 | s = s.subList(0, max); 29 | } 30 | if (min > 0) { 31 | s = s.subList(min, s.size()); 32 | } 33 | return s; 34 | } 35 | 36 | public Iterable apply(final Collection s) { 37 | return apply((Iterable) s); 38 | } 39 | 40 | public Iterable apply(final Iterable s) { 41 | if (s instanceof List) { 42 | return apply((List) s); 43 | } else { 44 | return new Iterable<>() { 45 | @Override 46 | public Iterator iterator() { 47 | Iterator itr = s.iterator(); 48 | itr = Iterators.limit(itr, max); 49 | if (min > 0) { 50 | for (int i = 0; i < min && itr.hasNext(); i++) { 51 | itr.next(); 52 | } 53 | } 54 | return itr; 55 | } 56 | }; 57 | } 58 | } 59 | 60 | /** 61 | * Range that includes natural numbers. 62 | */ 63 | public static final Range ALL = new Range(0, Integer.MAX_VALUE); 64 | } 65 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/export/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /** 25 | * Mechanism for writing out a graph of model objects in a machine readable format. 26 | *

27 | * Annotation driven. 28 | */ 29 | @XmlNamespace(XSD.URI) 30 | package org.kohsuke.stapler.export; 31 | 32 | import com.sun.xml.txw2.annotation.XmlNamespace; 33 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/framework/errors/ErrorObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.framework.errors; 25 | 26 | /** 27 | * Root class of the stapler error objects. 28 | * 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | public abstract class ErrorObject { 32 | /** 33 | * Gets the error message. 34 | */ 35 | public abstract String getMessage(); 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/framework/errors/NoHomeDirError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.framework.errors; 25 | 26 | import java.io.File; 27 | 28 | /** 29 | * Model object used to display the error top page if 30 | * we couldn't create the home directory. 31 | * 32 | *

33 | * {@code index.jelly} would display a nice friendly error page. 34 | * 35 | * @author Kohsuke Kawaguchi 36 | */ 37 | public class NoHomeDirError extends ErrorObject { 38 | public final File home; 39 | 40 | public NoHomeDirError(File home) { 41 | this.home = home; 42 | } 43 | 44 | @Override 45 | public String getMessage() { 46 | return "Unable to create home directory: " + home; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/interceptor/InterceptorAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.interceptor; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Marks the annotation as an interceptor annotation, 11 | * which executes before/after the method invocation of domain objects happen 12 | * as a part of the request processing. 13 | * 14 | *

15 | * This mechanism is useful for performing declarative processing/check on domain objects, 16 | * such as checking HTTP headers, performing the access control, etc. 17 | * 18 | * @author Kohsuke Kawaguchi 19 | * @see Interceptor 20 | * @see RequirePOST 21 | */ 22 | @Target(ElementType.ANNOTATION_TYPE) 23 | @Retention(RetentionPolicy.RUNTIME) 24 | @Documented 25 | public @interface InterceptorAnnotation { 26 | /** 27 | * Actual interceptor logic. Must have a default constructor. 28 | */ 29 | Class value(); 30 | 31 | /** 32 | * The point of invocation of this interceptor. 33 | */ 34 | Stage stage() default Stage.PREINVOKE; 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/interceptor/RespondSuccess.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.interceptor; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import java.lang.reflect.InvocationTargetException; 9 | import org.kohsuke.stapler.HttpResponses; 10 | import org.kohsuke.stapler.StaplerRequest2; 11 | import org.kohsuke.stapler.StaplerResponse2; 12 | 13 | /** 14 | * Used on the web-bound doXyz method to indicate that the successful return of the method should 15 | * result in HTTP 200 Success status. 16 | * 17 | * @author Kohsuke Kawaguchi 18 | * @see HttpResponses#ok() 19 | */ 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Target({ElementType.METHOD, ElementType.FIELD}) 22 | @InterceptorAnnotation(RespondSuccess.Processor.class) 23 | public @interface RespondSuccess { 24 | class Processor extends Interceptor { 25 | @Override 26 | public Object invoke(StaplerRequest2 request, StaplerResponse2 response, Object instance, Object[] arguments) 27 | throws IllegalAccessException, InvocationTargetException, ServletException { 28 | target.invoke(request, response, instance, arguments); 29 | // TODO does this actually do anything? 30 | // Function.bindAndInvokeAndServeResponse ignores return value if the method is declared to return void. 31 | // And it seems Stapler will send a 200 by default anyway. 32 | return HttpResponses.ok(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/interceptor/Stage.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.interceptor; 2 | 3 | import org.kohsuke.stapler.InjectedParameter; 4 | 5 | /** 6 | * Determines when interception happens. 7 | * 8 | * @author Kohsuke Kawaguchi 9 | * @see InterceptorAnnotation#stage() 10 | * @since 1.239 11 | */ 12 | public enum Stage { 13 | /** 14 | * During the method selection, before all the {@link InjectedParameter}s are processed. 15 | */ 16 | SELECTION, 17 | /** 18 | * Right before the dispatch of the method, after all the {@link InjectedParameter}s are processed. 19 | */ 20 | PREINVOKE 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/json/JsonHttpResponse.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.json; 2 | 3 | import edu.umd.cs.findbugs.annotations.Nullable; 4 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 5 | import jakarta.servlet.ServletException; 6 | import java.io.IOException; 7 | import java.io.PrintWriter; 8 | import java.io.StringWriter; 9 | import java.io.Writer; 10 | import net.sf.json.JSONObject; 11 | import org.kohsuke.stapler.HttpResponses.HttpResponseException; 12 | import org.kohsuke.stapler.StaplerRequest2; 13 | import org.kohsuke.stapler.StaplerResponse2; 14 | 15 | /** 16 | * {@link JSONObject} as a response. 17 | * 18 | * @author Carlos Sanchez 19 | */ 20 | public class JsonHttpResponse extends HttpResponseException { 21 | private final @Nullable JSONObject responseJson; 22 | private final int status; 23 | 24 | public JsonHttpResponse(JSONObject o) { 25 | this(o, o == null ? 204 : 200); 26 | } 27 | 28 | public JsonHttpResponse(JSONObject o, int status) { 29 | this.responseJson = o; 30 | this.status = status; 31 | } 32 | 33 | @SuppressFBWarnings( 34 | value = "INFORMATION_EXPOSURE_THROUGH_AN_ERROR_MESSAGE", 35 | justification = "Jenkins handles this issue differently or doesn't care about it") 36 | public JsonHttpResponse(Throwable t, int status) { 37 | StringWriter sw = new StringWriter(); 38 | t.printStackTrace(new PrintWriter(sw)); 39 | this.responseJson = new JSONObject() 40 | .element("error", t.getClass().getName() + ": " + t.getMessage()) 41 | .element("stackTrace", sw.toString()); 42 | this.status = status; 43 | } 44 | 45 | @Override 46 | public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) 47 | throws IOException, ServletException { 48 | if (status > 0) { 49 | rsp.setStatus(status); 50 | } 51 | if (responseJson != null) { 52 | rsp.setContentType("application/json;charset=UTF-8"); 53 | try (Writer w = rsp.getWriter()) { 54 | responseJson.write(w); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/json/SubmittedForm.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.json; 2 | 3 | import jakarta.servlet.ServletException; 4 | import java.lang.annotation.Annotation; 5 | import java.lang.annotation.Documented; 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | import net.sf.json.JSONObject; 11 | import org.kohsuke.stapler.AnnotationHandler; 12 | import org.kohsuke.stapler.InjectedParameter; 13 | import org.kohsuke.stapler.StaplerRequest2; 14 | 15 | /** 16 | * Binds {@linkplain StaplerRequest2#getSubmittedForm() the submitted form} to a parameter of a web-bound method. 17 | * 18 | *

19 | * On a web-bound {@code doXyz} method, use this annotation on a parameter to get the submitted 20 | * structured form content and inject it as {@link JSONObject}. 21 | * For example, 22 | * 23 | *

24 |  * public HttpResponse doConfigSubmit(@SubmittedForm JSONObject o) {
25 |  *   ...
26 |  * }
27 |  * 
28 | * 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | @Target(ElementType.PARAMETER) 32 | @Retention(RetentionPolicy.RUNTIME) 33 | @Documented 34 | @InjectedParameter(SubmittedForm.Handler.class) 35 | public @interface SubmittedForm { 36 | class Handler extends AnnotationHandler { 37 | @Override 38 | public Object parse(StaplerRequest2 request, Annotation a, Class type, String parameterName) 39 | throws ServletException { 40 | return request.getSubmittedForm(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/jsr269/PoormansMultimap.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jsr269; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * Very simple multi-map implementation. 11 | * 12 | *

13 | * We historically used Google Collections, but there have been multiple reports that 14 | * certain versions of Maven (and IDEs such as IntelliJ) fail to correctly compute 15 | * classpath for annotation processors and cause a NoClassDefFoundError. 16 | * 17 | * To work around this problem, we are now using this class. 18 | * 19 | * @author Kohsuke Kawaguchi 20 | */ 21 | class PoormansMultimap { 22 | private final HashMap> store = new HashMap<>(); 23 | 24 | public void put(K k, V v) { 25 | List l = store.computeIfAbsent(k, unused -> new ArrayList<>()); 26 | l.add(v); 27 | } 28 | 29 | public Map> asMap() { 30 | return (Map) store; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/lang/AnnotatedRef.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.lang; 2 | 3 | import java.lang.annotation.Annotation; 4 | 5 | /** 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public abstract class AnnotatedRef { 9 | // no subtyping outside the package 10 | /*package*/ AnnotatedRef() {} 11 | 12 | public abstract T getAnnotation(Class type); 13 | 14 | public boolean hasAnnotation(Class type) { 15 | return getAnnotation(type) != null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/lang/KInstance.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.lang; 2 | 3 | import org.kohsuke.stapler.Facet; 4 | 5 | /** 6 | * Objects can implement this interface to designate its own {@link Klass}. 7 | * 8 | * This allows specific classes or instances to take over the routing rules without 9 | * going through the trouble of creating a new {@link Facet} 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public interface KInstance { 14 | /** 15 | * @return 16 | * null if there's no designated {@link Klass} for this instance, in which 17 | * case Stapler treats this instance normally as if it didn't implement 18 | * {@link KInstance} to begin with (for example, by calling {@link Object#getClass()} 19 | */ 20 | Klass getKlass(); 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/lang/util/FieldRefFilter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.lang.util; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import java.lang.annotation.Annotation; 5 | import java.lang.reflect.Field; 6 | import org.kohsuke.stapler.lang.FieldRef; 7 | 8 | /** 9 | * {@link FieldRef} filter as a convenience class. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public abstract class FieldRefFilter extends FieldRef { 14 | protected abstract FieldRef getBase(); 15 | 16 | @Override 17 | public String getName() { 18 | return getBase().getName(); 19 | } 20 | 21 | @Override 22 | public Object get(Object instance) throws IllegalAccessException { 23 | return getBase().get(instance); 24 | } 25 | 26 | @Override 27 | public boolean isStatic() { 28 | return getBase().isStatic(); 29 | } 30 | 31 | @Override 32 | public String getQualifiedName() { 33 | return getBase().getQualifiedName(); 34 | } 35 | 36 | @Override 37 | public boolean isRoutable() { 38 | return getBase().isRoutable(); 39 | } 40 | 41 | @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "TODO needs triage") 42 | public static FieldRef wrap(Field f) { 43 | return FieldRef.wrap(f); 44 | } 45 | 46 | @Override 47 | public T getAnnotation(Class type) { 48 | return getBase().getAnnotation(type); 49 | } 50 | 51 | @Override 52 | public boolean hasAnnotation(Class type) { 53 | return getBase().hasAnnotation(type); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/lang/util/MethodRefFilter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.lang.util; 2 | 3 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 4 | import java.lang.annotation.Annotation; 5 | import java.lang.reflect.InvocationTargetException; 6 | import java.lang.reflect.Method; 7 | import org.kohsuke.stapler.lang.MethodRef; 8 | 9 | /** 10 | * {@link MethodRef} filter as a convenience class. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | public abstract class MethodRefFilter extends MethodRef { 15 | protected abstract MethodRef getBase(); 16 | 17 | @Override 18 | public boolean isRoutable() { 19 | return getBase().isRoutable(); 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return getBase().getName(); 25 | } 26 | 27 | @Override 28 | public Object invoke(Object _this, Object... args) throws InvocationTargetException, IllegalAccessException { 29 | return getBase().invoke(_this, args); 30 | } 31 | 32 | @SuppressFBWarnings(value = "HSM_HIDING_METHOD", justification = "TODO needs triage") 33 | public static MethodRef wrap(Method m) { 34 | return MethodRef.wrap(m); 35 | } 36 | 37 | @Override 38 | public T getAnnotation(Class type) { 39 | return getBase().getAnnotation(type); 40 | } 41 | 42 | @Override 43 | public boolean hasAnnotation(Class type) { 44 | return getBase().hasAnnotation(type); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /** 25 | * Stapler {@code URL} → {@code Object} mapping framework. The main entry points are {@link Stapler}, 26 | * {@link StaplerRequest2}, and {@link StaplerResponse2}. 27 | */ 28 | package org.kohsuke.stapler; 29 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/util/IllegalReflectiveAccessLogHandler.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.util; 2 | 3 | public class IllegalReflectiveAccessLogHandler { 4 | 5 | public static String get(IllegalAccessException e) { 6 | return e.getClass().getName() 7 | + ": Processing this request relies on deprecated behavior that will be disallowed in future releases of Java. See https://jenkins.io/redirect/stapler-reflective-access/ for more information. Details: " 8 | + e.getMessage(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/verb/DELETE.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.verb; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import org.kohsuke.stapler.WebMethod; 9 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 10 | import org.kohsuke.stapler.interceptor.Stage; 11 | 12 | /** 13 | * Restricts a {@link WebMethod} to a specific HTTP method 'DELETE'. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | @Target(ElementType.METHOD) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Documented 20 | @InterceptorAnnotation(value = HttpVerbInterceptor.class, stage = Stage.SELECTION) 21 | public @interface DELETE {} 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/verb/GET.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.verb; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import org.kohsuke.stapler.WebMethod; 9 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 10 | import org.kohsuke.stapler.interceptor.Stage; 11 | 12 | /** 13 | * Restricts a {@link WebMethod} to a specific HTTP method 'GET'. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | @Target(ElementType.METHOD) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Documented 20 | @InterceptorAnnotation(value = HttpVerbInterceptor.class, stage = Stage.SELECTION) 21 | public @interface GET {} 22 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/verb/POST.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.verb; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import org.kohsuke.stapler.WebMethod; 9 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 10 | import org.kohsuke.stapler.interceptor.RequirePOST; 11 | import org.kohsuke.stapler.interceptor.Stage; 12 | 13 | /** 14 | * Restricts a {@link WebMethod} to a specific HTTP method 'POST'. 15 | * 16 | *

17 | * Unlike {@link RequirePOST}, this annotation simply skips routing the current request 18 | * to the current web method, and continues searching other available routes. 19 | * 20 | * @author Kohsuke Kawaguchi 21 | */ 22 | @Target(ElementType.METHOD) 23 | @Retention(RetentionPolicy.RUNTIME) 24 | @Documented 25 | @InterceptorAnnotation(value = HttpVerbInterceptor.class, stage = Stage.SELECTION) 26 | public @interface POST {} 27 | -------------------------------------------------------------------------------- /core/src/main/java/org/kohsuke/stapler/verb/PUT.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.verb; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import org.kohsuke.stapler.WebMethod; 9 | import org.kohsuke.stapler.interceptor.InterceptorAnnotation; 10 | import org.kohsuke.stapler.interceptor.Stage; 11 | 12 | /** 13 | * Restricts a {@link WebMethod} to a specific HTTP method 'PUT'. 14 | * 15 | * @author Kohsuke Kawaguchi 16 | */ 17 | @Target(ElementType.METHOD) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Documented 20 | @InterceptorAnnotation(value = HttpVerbInterceptor.class, stage = Stage.SELECTION) 21 | public @interface PUT {} 22 | -------------------------------------------------------------------------------- /core/src/main/resources/org/kohsuke/stapler/framework/errors/ErrorObject/index.default.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Error

4 |

5 | ${it.message} 6 |

7 | 8 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/AbstractStaplerTestBase.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletConfig; 4 | import jakarta.servlet.ServletContext; 5 | import jakarta.servlet.http.HttpServletRequest; 6 | import jakarta.servlet.http.HttpServletResponse; 7 | import java.util.ArrayList; 8 | import junit.framework.TestCase; 9 | import org.kohsuke.stapler.test.AbstractStaplerTest; 10 | import org.mockito.Mockito; 11 | 12 | /** 13 | * This class needs to be in this package to access package-protected stuff. 14 | * You should extend from {@link AbstractStaplerTest}. 15 | * 16 | * @author Kohsuke Kawaguchi 17 | */ 18 | public abstract class AbstractStaplerTestBase extends TestCase { 19 | 20 | protected WebApp webApp; 21 | protected RequestImpl request; 22 | protected ResponseImpl response; 23 | protected Stapler stapler = new Stapler(); 24 | protected HttpServletRequest rawRequest; 25 | protected HttpServletResponse rawResponse; 26 | 27 | @Override 28 | protected void setUp() throws Exception { 29 | super.setUp(); 30 | ServletContext servletContext = Mockito.mock(ServletContext.class); 31 | 32 | webApp = new WebApp(servletContext); 33 | 34 | ServletConfig servletConfig = Mockito.mock(ServletConfig.class); 35 | Mockito.when(servletConfig.getServletContext()).thenReturn(servletContext); 36 | stapler.init(servletConfig); 37 | 38 | rawRequest = Mockito.mock(HttpServletRequest.class); 39 | rawResponse = Mockito.mock(HttpServletResponse.class); 40 | 41 | this.request = new RequestImpl(stapler, rawRequest, new ArrayList<>(), new TokenList("")); 42 | Stapler.CURRENT_REQUEST.set(this.request); 43 | 44 | this.response = new ResponseImpl(stapler, rawResponse); 45 | Stapler.CURRENT_RESPONSE.set(this.response); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/AncestorImplTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import java.net.URL; 4 | import org.htmlunit.WebClient; 5 | import org.kohsuke.stapler.test.JettyTestCase; 6 | 7 | /** 8 | * @author Kohsuke Kawaguchi 9 | */ 10 | public class AncestorImplTest extends JettyTestCase { 11 | public Object testRestOfUrl = new Foo(); 12 | 13 | class Foo { 14 | public Object bar = new Bar(); 15 | } 16 | 17 | class Bar { 18 | public HttpResponse doZot(StaplerRequest2 req) { 19 | assertEquals("testRestOfUrl/bar/zot", req.getAncestors().get(0).getRestOfUrl()); 20 | assertEquals("bar/zot", req.getAncestors().get(1).getRestOfUrl()); 21 | assertEquals("zot", req.getAncestors().get(2).getRestOfUrl()); 22 | return HttpResponses.ok(); 23 | } 24 | } 25 | 26 | // issue 34 27 | public void testRestOfUrl() throws Exception { 28 | WebClient wc = createWebClient(); 29 | wc.getPage(new URL(url, "testRestOfUrl/bar/zot")); 30 | } 31 | 32 | @Override 33 | protected String getContextPath() { 34 | return "/contextPathPart"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/IndexHtmlDispatcherTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import static org.junit.Assert.assertNull; 4 | import static org.mockito.Mockito.any; 5 | import static org.mockito.Mockito.mock; 6 | import static org.mockito.Mockito.when; 7 | 8 | import jakarta.servlet.ServletContext; 9 | import java.net.MalformedURLException; 10 | import org.junit.Test; 11 | import org.jvnet.hudson.test.Issue; 12 | 13 | public class IndexHtmlDispatcherTest { 14 | 15 | @Test 16 | @Issue("#109") 17 | public void ignoreInterfaces() throws MalformedURLException { 18 | ServletContext context = mock(ServletContext.class); 19 | when(context.getResource(any(String.class))).thenReturn(null); 20 | 21 | assertNull(IndexHtmlDispatcher.make(context, TestInterface.class)); 22 | } 23 | 24 | private interface TestInterface {} 25 | } 26 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/JsonInErrorMessageSanitizerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License 3 | * 4 | * Copyright (c) 2018, CloudBees, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | package org.kohsuke.stapler; 26 | 27 | import junit.framework.TestCase; 28 | import net.sf.json.JSONObject; 29 | 30 | public class JsonInErrorMessageSanitizerTest extends TestCase { 31 | public void testNoopToReturnCopy() { 32 | JSONObject input = new JSONObject(); 33 | input.accumulate("a", 1); 34 | input.accumulate("a", 2); 35 | input.accumulate("a", 3); 36 | input.accumulate("b", 4); 37 | 38 | JSONObject sub = new JSONObject(); 39 | sub.accumulate("d", 5); 40 | input.accumulate("c", sub); 41 | 42 | JSONObject output = JsonInErrorMessageSanitizer.NOOP.sanitize(input); 43 | assertNotSame(output, input); 44 | assertEquals(output.getJSONArray("a").get(0), input.getJSONArray("a").get(0)); 45 | assertEquals(output.getJSONArray("a").get(2), input.getJSONArray("a").get(2)); 46 | assertEquals(output.getInt("b"), input.getInt("b")); 47 | assertEquals( 48 | output.getJSONObject("c").getInt("d"), input.getJSONObject("c").getInt("d")); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/MetaClassTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import junit.framework.TestCase; 4 | import org.junit.Assert; 5 | import org.kohsuke.stapler.lang.Klass; 6 | 7 | public class MetaClassTest extends TestCase { 8 | public void testGetObjectProhibited() { 9 | MetaClass metaClass = new MetaClass(new WebApp(new MockServletContext()), Klass.java(Object.class)); 10 | 11 | // ensure no getClass dispatcher for Object 12 | Assert.assertFalse(metaClass.dispatchers.stream() 13 | .filter(d -> d instanceof NameBasedDispatcher) 14 | .anyMatch(d -> ((NameBasedDispatcher) d).name.equals("class"))); 15 | 16 | // in fact, there should be no name based dispatchers at all 17 | Assert.assertFalse(metaClass.dispatchers.stream().anyMatch(d -> d instanceof NameBasedDispatcher)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/ObjectWithCustomConverter.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import org.apache.commons.beanutils.Converter; 4 | 5 | /** 6 | * @author Kohsuke Kawaguchi 7 | */ 8 | public class ObjectWithCustomConverter { 9 | public final int x, y; 10 | 11 | public ObjectWithCustomConverter(int x, int y) { 12 | this.x = x; 13 | this.y = y; 14 | } 15 | 16 | public static class StaplerConverterImpl implements Converter { 17 | @Override 18 | public Object convert(Class type, Object value) { 19 | String[] tokens = value.toString().split(","); 20 | return new ObjectWithCustomConverter(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1])); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/ServletConfigImpl.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler; 2 | 3 | import jakarta.servlet.ServletConfig; 4 | import jakarta.servlet.ServletContext; 5 | import java.util.Enumeration; 6 | 7 | /** 8 | * @author Kohsuke Kawaguchi 9 | */ 10 | public class ServletConfigImpl implements ServletConfig { 11 | ServletContext context = new MockServletContext(); 12 | 13 | @Override 14 | public String getServletName() { 15 | return ""; 16 | } 17 | 18 | @Override 19 | public ServletContext getServletContext() { 20 | return context; 21 | } 22 | 23 | @Override 24 | public String getInitParameter(String name) { 25 | return null; 26 | } 27 | 28 | @Override 29 | public Enumeration getInitParameterNames() { 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/bind/BoundObjectTableTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.bind; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | import org.htmlunit.TextPage; 6 | import org.kohsuke.stapler.HttpResponse; 7 | import org.kohsuke.stapler.StaplerResponse2; 8 | import org.kohsuke.stapler.test.JettyTestCase; 9 | 10 | /** 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class BoundObjectTableTest extends JettyTestCase { 14 | /** 15 | * Exports an object and see if it can be reached. 16 | */ 17 | public void testExport() throws Exception { 18 | TextPage page = createWebClient().getPage(new URL(url, "/bind")); 19 | assertEquals("hello world", page.getContent()); 20 | } 21 | 22 | public HttpResponse doBind() throws IOException { 23 | Bound h = webApp.boundObjectTable.bind(new HelloWorld("hello world")); 24 | System.out.println(h.getURL()); 25 | return h; 26 | } 27 | 28 | public static class HelloWorld { 29 | private final String message; 30 | 31 | public HelloWorld(String message) { 32 | this.message = message; 33 | } 34 | 35 | public void doIndex(StaplerResponse2 rsp) throws IOException { 36 | rsp.setContentType("text/plain;charset=UTF-8"); 37 | rsp.getWriter().write(message); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/export/RangeTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.export; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.contains; 5 | 6 | import java.util.Arrays; 7 | import java.util.LinkedHashSet; 8 | import java.util.List; 9 | import java.util.Set; 10 | import org.junit.Test; 11 | 12 | public class RangeTest { 13 | String[] array = new String[] {"a", "b", "c", "d", "e", "f"}; 14 | List list = Arrays.asList(array); 15 | Set set = new LinkedHashSet<>(list); 16 | 17 | @Test 18 | public void normalRange() { 19 | Range r = new Range(2, 4); 20 | assertThat(r.apply(array), contains("c", "d")); 21 | assertThat(r.apply(list), contains("c", "d")); 22 | assertThat(r.apply(set), contains("c", "d")); 23 | } 24 | 25 | @Test 26 | public void maxOnlyRange() { 27 | Range r = new Range(-1, 2); 28 | assertThat(r.apply(array), contains("a", "b")); 29 | assertThat(r.apply(list), contains("a", "b")); 30 | assertThat(r.apply(set), contains("a", "b")); 31 | } 32 | 33 | @Test 34 | public void minOnlyRange() { 35 | Range r = new Range(4, Integer.MAX_VALUE); 36 | assertThat(r.apply(array), contains("e", "f")); 37 | assertThat(r.apply(list), contains("e", "f")); 38 | assertThat(r.apply(set), contains("e", "f")); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/framework/io/LineEndNormalizingWriterTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.framework.io; 2 | 3 | import java.io.IOException; 4 | import java.io.StringWriter; 5 | import java.io.Writer; 6 | import junit.framework.TestCase; 7 | 8 | /** 9 | * @author Kohsuke Kawaguchi 10 | */ 11 | public class LineEndNormalizingWriterTest extends TestCase { 12 | public void test1() throws IOException { 13 | StringWriter sw = new StringWriter(); 14 | Writer w = new LineEndNormalizingWriter(sw); 15 | 16 | w.write("abc\r\ndef\r"); 17 | w.write("\n"); 18 | 19 | assertEquals(sw.toString(), "abc\r\ndef\r\n"); 20 | } 21 | 22 | public void test2() throws IOException { 23 | StringWriter sw = new StringWriter(); 24 | Writer w = new LineEndNormalizingWriter(sw); 25 | 26 | w.write("abc\ndef\n"); 27 | w.write("\n"); 28 | 29 | assertEquals(sw.toString(), "abc\r\ndef\r\n\r\n"); 30 | } 31 | 32 | public void test3() throws IOException { 33 | StringWriter sw = new StringWriter(); 34 | Writer w = new LineEndNormalizingWriter(sw); 35 | 36 | w.write("\r\n\n"); 37 | 38 | assertEquals(sw.toString(), "\r\n\r\n"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/framework/io/WriterOutputStreamTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.framework.io; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.io.OutputStreamWriter; 6 | import java.io.PrintStream; 7 | import junit.framework.TestCase; 8 | 9 | /** 10 | * TODO: make it a real junit test 11 | * 12 | * @author jglick 13 | */ 14 | public class WriterOutputStreamTest extends TestCase { 15 | public void testFoo() {} // otherwise surefire will be unhappy 16 | 17 | public static void main(String[] args) throws IOException { 18 | OutputStream os = new WriterOutputStream(new OutputStreamWriter(System.out)); 19 | PrintStream ps = new PrintStream(os); 20 | for (int i = 0; i < 200; i++) { 21 | ps.println("#" + i + " blah blah blah"); 22 | } 23 | os.close(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/json/JsonBodyTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.json; 2 | 3 | import java.net.URL; 4 | import org.htmlunit.HttpMethod; 5 | import org.htmlunit.WebRequest; 6 | import org.htmlunit.WebResponse; 7 | import org.kohsuke.stapler.test.JettyTestCase; 8 | 9 | public class JsonBodyTest extends JettyTestCase { 10 | 11 | public void testSmokes() throws Exception { 12 | WebRequest req = new WebRequest(new URL(url, "double"), HttpMethod.POST); 13 | req.setAdditionalHeader("Content-Type", "application/json"); 14 | req.setRequestBody("{\"x\":10,\"y\":5}"); 15 | WebResponse response = createWebClient().getPage(req).getWebResponse(); 16 | assertEquals("application/json", response.getContentType()); 17 | assertEquals("{\"x\":20,\"y\":10}", response.getContentAsString()); 18 | } 19 | 20 | @JsonResponse 21 | public Point doDouble(@JsonBody Point p) { 22 | Point pt = new Point(); 23 | pt.x = p.x * 2; 24 | pt.y = p.y * 2; 25 | return pt; 26 | } 27 | 28 | public static class Point { 29 | public int x, y; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/json/SubmittedFormTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.json; 2 | 3 | import java.net.URL; 4 | import net.sf.json.JSONObject; 5 | import org.htmlunit.WebClient; 6 | import org.htmlunit.html.HtmlForm; 7 | import org.htmlunit.html.HtmlPage; 8 | import org.kohsuke.stapler.HttpResponse; 9 | import org.kohsuke.stapler.HttpResponses; 10 | import org.kohsuke.stapler.StaticViewFacet; 11 | import org.kohsuke.stapler.test.JettyTestCase; 12 | 13 | /** 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | public class SubmittedFormTest extends JettyTestCase { 17 | /** 18 | * To load form for test, allow *.html to be served as a view 19 | */ 20 | @Override 21 | protected void setUp() throws Exception { 22 | super.setUp(); 23 | webApp.facets.add(new StaticViewFacet("html")); 24 | } 25 | 26 | public void testMainFeature() throws Exception { 27 | WebClient wc = createWebClient(); 28 | HtmlPage page = wc.getPage(new URL(url, "/form.html")); 29 | HtmlForm f = page.getFormByName("main"); 30 | f.getInputByName("json").setValue("{\"first\":\"Kohsuke\",\"last\":\"Kawaguchi\"}"); 31 | f.submit(null); 32 | } 33 | 34 | public HttpResponse doSubmit(@SubmittedForm JSONObject o) { 35 | assertEquals("Kohsuke", o.getString("first")); 36 | assertEquals("Kawaguchi", o.getString("last")); 37 | return HttpResponses.ok(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/jsr269/SourceGeneratingAnnotation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Jesse Glick 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | package org.kohsuke.stapler.jsr269; 28 | 29 | import java.lang.annotation.ElementType; 30 | import java.lang.annotation.Retention; 31 | import java.lang.annotation.RetentionPolicy; 32 | import java.lang.annotation.Target; 33 | import javax.annotation.processing.RoundEnvironment; 34 | 35 | /** 36 | * Stick this on something to demonstrate that your processor is wrong if it writes a resource before {@link RoundEnvironment#processingOver}. 37 | * You will get a {@code javax.annotation.processing.FilerException: Attempt to reopen a file for path …} error because the processor is run in two rounds. 38 | * @see HICKORY-14 39 | */ 40 | @Retention(RetentionPolicy.SOURCE) 41 | @Target(ElementType.TYPE) 42 | public @interface SourceGeneratingAnnotation {} 43 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/jsr269/Utils.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jsr269; 2 | 3 | import java.io.IOException; 4 | import java.io.StringReader; 5 | import java.io.UncheckedIOException; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import java.util.TreeMap; 9 | import javax.tools.JavaFileObject; 10 | import javax.tools.StandardLocation; 11 | 12 | class Utils { 13 | public static String getGeneratedResource(List generated, String filename) { 14 | JavaFileObject fo = generated.stream() 15 | .filter(it -> it.getName().equals("/" + StandardLocation.CLASS_OUTPUT + "/" + filename)) 16 | .findFirst() 17 | .orElse(null); 18 | if (fo == null) { 19 | return null; 20 | } 21 | try { 22 | return fo.getCharContent(true).toString(); 23 | } catch (IOException e) { 24 | throw new UncheckedIOException(e); 25 | } 26 | } 27 | 28 | /** 29 | * Converts the text content of a properties file to a sorted map. 30 | * Otherwise you get junk like the header comment with a timestamp, the list is randomly sorted, etc. 31 | * @param props text content in *.properties format 32 | * @return string representation of a map (sorted ascending by key) 33 | */ 34 | public static String normalizeProperties(String props) { 35 | if (props == null) { 36 | return null; 37 | } 38 | Properties p = new Properties(); 39 | try { 40 | p.load(new StringReader(props)); 41 | } catch (IOException x) { 42 | throw new AssertionError(x); 43 | } 44 | return new TreeMap<>(p).toString(); 45 | } 46 | 47 | private Utils() {} 48 | } 49 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/lang/KlassTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.lang; 2 | 3 | import java.util.List; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | import org.kohsuke.stapler.Function; 7 | 8 | /** 9 | * Contains tests for {@link Klass}. 10 | * @author Oleg Nenashev. 11 | */ 12 | public class KlassTest { 13 | 14 | @Test 15 | public void shouldProperlyAccessJavaDeclaredMethods() throws Exception { 16 | final Klass classInstance = Klass.java(FooClass.class); 17 | final List declaredFunctions = classInstance.getDeclaredMethods(); 18 | for (MethodRef ref : declaredFunctions) { 19 | if ("doDynamic".equals(ref.getName())) { 20 | // TODO: check field parameters once Stapler provides such info 21 | return; 22 | } 23 | } 24 | Assert.fail("Have not found the 'doDynamic' declared method for FooClass"); 25 | } 26 | 27 | @Test 28 | public void shouldProperlyAccessJavaDeclaredFields() throws Exception { 29 | final Klass classInstance = Klass.java(FooClass.class); 30 | final List declaredFields = classInstance.getDeclaredFields(); 31 | for (FieldRef ref : declaredFields) { 32 | if ("fooField".equals(ref.getName())) { 33 | // TODO: check field parameters once Stapler provides such info 34 | return; 35 | } 36 | } 37 | Assert.fail("Have not found 'fooField' in the returned field list"); 38 | } 39 | 40 | @Test 41 | public void shouldProperlyAccessJavaDeclaredFunctions() throws Exception { 42 | final Klass classInstance = Klass.java(FooClass.class); 43 | final List declaredFunctions = classInstance.getFunctions(); 44 | for (Function ref : declaredFunctions) { 45 | if ("doDynamic".equals(ref.getName())) { 46 | // TODO: check field parameters once Stapler provides such info 47 | return; 48 | } 49 | } 50 | Assert.fail("Have not found 'doDynamic' function for FooClass"); 51 | } 52 | 53 | private static final class FooClass { 54 | private int fooField; 55 | 56 | public Object doDynamic(String token) { 57 | // Just return something potentially routable 58 | return Integer.valueOf(0); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/test/AbstractStaplerTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.test; 2 | 3 | import org.kohsuke.stapler.AbstractStaplerTestBase; 4 | 5 | /** 6 | * Just to make the class visible in the test package. 7 | * @author Kohsuke Kawaguchi 8 | */ 9 | public abstract class AbstractStaplerTest extends AbstractStaplerTestBase {} 10 | -------------------------------------------------------------------------------- /core/src/test/java/org/kohsuke/stapler/test/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Reusable test utility code. 3 | */ 4 | package org.kohsuke.stapler.test; 5 | -------------------------------------------------------------------------------- /core/src/test/resources/org/kohsuke/stapler/json/SubmittedFormTest/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | -------------------------------------------------------------------------------- /docs/i18n.adoc: -------------------------------------------------------------------------------- 1 | == i18n support 2 | 3 | Stapler depends on https://localizer.dev.java.net/[localizer] for the 4 | i18n support. 5 | 6 | === i18n from Jelly view scripts 7 | 8 | For Jelly view scripts, the convention is to place localized message 9 | resource files by using the same base name. For example, if you are 10 | writing `foo.jelly`, its property files will be placed in files like 11 | `foo.properties` and `foo_ja.properties`. 12 | 13 | In this set up, Jelly view scripts can refer to message resources by 14 | using a special expression of the form `${%KEY(arg1,arg2,...)}`. The 15 | messages are formatted by using `MessageFormat`, and arguments are 16 | individually parsed as JEXL scripts. If there's no arguments, 17 | parenthesis can be omitted and thus it can be simply written as 18 | `${%KEY}`. 19 | 20 | If you need to refer to message resources from within a JEXL expression, 21 | you can use a string literal notation `"%KEY(arg1,arg2,...)"` or its 22 | argument-less short form `"%KEY"`. For example, 23 | `${obj.methodCall(1,true,"%Message")}` 24 | 25 | If the specified KEY is not available in the property files, the key 26 | itself will be used as a formatting string. The key can contain any 27 | character except '(' and '}'. This convenient defaulting allows you to 28 | skip writing `foo.properties` most of the time (that is, you'd only need 29 | property files for translations.) 30 | -------------------------------------------------------------------------------- /docs/stapler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/docs/stapler.png -------------------------------------------------------------------------------- /docs/stapler.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/docs/stapler.vsd -------------------------------------------------------------------------------- /groovy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.kohsuke.stapler 6 | stapler-parent 7 | ${changelist} 8 | 9 | 10 | stapler-groovy 11 | Stapler Groovy module 12 | Groovy binding for Stapler 13 | 14 | 15 | 16 | ${project.groupId} 17 | stapler-jelly 18 | ${project.version} 19 | 20 | 21 | org.codehaus.groovy 22 | groovy-all 23 | 2.4.21 24 | 25 | 26 | org.kohsuke.metainf-services 27 | metainf-services 28 | true 29 | 30 | 31 | jakarta.servlet 32 | jakarta.servlet-api 33 | 5.0.0 34 | provided 35 | 36 | 37 | ${project.groupId} 38 | stapler 39 | ${project.version} 40 | tests 41 | test 42 | 43 | 44 | org.hamcrest 45 | hamcrest 46 | test 47 | 48 | 49 | org.junit.jupiter 50 | junit-jupiter 51 | test 52 | 53 | 54 | org.junit.vintage 55 | junit-vintage-engine 56 | test 57 | 58 | 59 | org.mockito 60 | mockito-core 61 | test 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/TagFile.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.groovy; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Used on methods of {@link TypedTagLibrary} to 11 | * indicate a real tag file name. 12 | * 13 | *

14 | * This is used when the real tag file name is not 15 | * a valid Java identifier. 16 | * 17 | * @author Kohsuke Kawaguchi 18 | */ 19 | @Retention(RetentionPolicy.RUNTIME) 20 | @Documented 21 | @Target(ElementType.METHOD) 22 | public @interface TagFile { 23 | String value(); 24 | } 25 | -------------------------------------------------------------------------------- /groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/TagLibraryUri.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.groovy; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Used on subtypes of {@link TypedTagLibrary} to associate the namespace URI to look up tags from. 11 | * 12 | * @author Kohsuke Kawaguchi 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Documented 16 | @Target(ElementType.TYPE) 17 | public @interface TagLibraryUri { 18 | String value(); 19 | } 20 | -------------------------------------------------------------------------------- /groovy/src/main/java/org/kohsuke/stapler/jelly/groovy/TypedTagLibrary.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.groovy; 2 | 3 | import groovy.lang.GroovyObject; 4 | 5 | /** 6 | * Typed interface to provide auto-completion for IDEs when invoking taglibs. 7 | * 8 | * Subtype must have the {@link TagLibraryUri} annotation 9 | * 10 | * @author Kohsuke Kawaguchi 11 | */ 12 | public interface TypedTagLibrary extends GroovyObject {} 13 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/framework/adjunct/NoSuchAdjunctException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.framework.adjunct; 25 | 26 | import java.io.IOException; 27 | 28 | /** 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | public class NoSuchAdjunctException extends IOException { 32 | public NoSuchAdjunctException() {} 33 | 34 | public NoSuchAdjunctException(String message) { 35 | super(message); 36 | } 37 | 38 | public NoSuchAdjunctException(String message, Throwable cause) { 39 | super(message); 40 | initCause(cause); 41 | } 42 | 43 | public NoSuchAdjunctException(Throwable cause) { 44 | initCause(cause); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/AbstractStaplerTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | import jakarta.servlet.ServletContext; 27 | import jakarta.servlet.http.HttpServletRequest; 28 | import jakarta.servlet.http.HttpServletResponse; 29 | import org.apache.commons.jelly.TagSupport; 30 | 31 | /** 32 | * @author Kohsuke Kawaguchi 33 | */ 34 | abstract class AbstractStaplerTag extends TagSupport { 35 | 36 | protected HttpServletRequest getRequest() { 37 | return (HttpServletRequest) getContext().getVariable("request2"); 38 | } 39 | 40 | protected HttpServletResponse getResponse() { 41 | return (HttpServletResponse) getContext().getVariable("response2"); 42 | } 43 | 44 | protected ServletContext getServletContext() { 45 | return (ServletContext) getContext().getVariable("servletContext"); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/AttributeConstraintsTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | import org.apache.commons.jelly.TagSupport; 27 | import org.apache.commons.jelly.XMLOutput; 28 | import org.jvnet.maven.jellydoc.annotation.Required; 29 | 30 | /** 31 | * DTD-like expression that specifies the constraints on attribute appearances. 32 | * 33 | *

34 | * This tag should be placed right inside {@code } 35 | * to describe attributes of a tag. 36 | * 37 | * @author Kohsuke Kawaguchi 38 | */ 39 | public class AttributeConstraintsTag extends TagSupport { 40 | @Override 41 | public void doTag(XMLOutput output) { 42 | // noop 43 | } 44 | 45 | /** 46 | * Constraint expression. 47 | */ 48 | @Required 49 | public void setExpr(String v) {} 50 | } 51 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/InternationalizedStringExpressionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | /** 27 | * Receives a notification of the {@link InternationalizedStringExpression} usage. 28 | * 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | public interface InternationalizedStringExpressionListener { 32 | void onUsed(InternationalizedStringExpression exp, Object[] args); 33 | } 34 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/JellyCompatibleFacet.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import java.util.Collection; 4 | import org.apache.commons.jelly.Script; 5 | import org.kohsuke.stapler.AbstractTearOff; 6 | import org.kohsuke.stapler.Facet; 7 | 8 | /** 9 | * {@link Facet} subtype (although not captured in a type hierarchy) that loads Jelly-compatible scripts. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public interface JellyCompatibleFacet { 14 | /** 15 | * 16 | */ 17 | Collection>> getClassTearOffTypes(); 18 | 19 | /** 20 | * Gets the list of view script extensions, such as ".jelly". 21 | */ 22 | Collection getScriptExtensions(); 23 | } 24 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/NbspTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | import org.apache.commons.jelly.JellyTagException; 27 | import org.apache.commons.jelly.MissingAttributeException; 28 | import org.apache.commons.jelly.TagSupport; 29 | import org.apache.commons.jelly.XMLOutput; 30 | import org.jvnet.maven.jellydoc.annotation.NoContent; 31 | import org.xml.sax.SAXException; 32 | 33 | /** 34 | * Writes out '&nbsp;'. 35 | * 36 | * @author Kohsuke Kawaguchi 37 | */ 38 | @NoContent 39 | public class NbspTag extends TagSupport { 40 | @Override 41 | public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { 42 | try { 43 | output.write("\u00A0"); // nbsp 44 | } catch (SAXException e) { 45 | throw new JellyTagException(e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/ParentScopeTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | import org.apache.commons.jelly.JellyTagException; 27 | import org.apache.commons.jelly.TagSupport; 28 | import org.apache.commons.jelly.XMLOutput; 29 | 30 | /** 31 | * Executes the body in the parent scope. 32 | * This is useful for creating a 'local' scope. 33 | * 34 | * @author Kohsuke Kawaguchi 35 | */ 36 | public class ParentScopeTag extends TagSupport { 37 | @Override 38 | public void doTag(XMLOutput output) throws JellyTagException { 39 | getBody().run(context.getParent(), output); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/ResourceBundleFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | /** 27 | * Factory for {@link ResourceBundle}s. 28 | * 29 | * @author Kohsuke Kawaguchi 30 | */ 31 | public class ResourceBundleFactory { 32 | public ResourceBundle create(String baseName) { 33 | return new ResourceBundle(baseName); 34 | } 35 | 36 | public static final ResourceBundleFactory INSTANCE = new ResourceBundleFactory(); 37 | } 38 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/SetHeaderTag.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import org.apache.commons.jelly.JellyTagException; 4 | import org.apache.commons.jelly.XMLOutput; 5 | import org.jvnet.maven.jellydoc.annotation.NoContent; 6 | import org.jvnet.maven.jellydoc.annotation.Required; 7 | 8 | /** 9 | * Sets an HTTP header to the response. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | * @see HeaderTag 13 | */ 14 | @NoContent 15 | public class SetHeaderTag extends AbstractStaplerTag { 16 | private String name; 17 | private String value; 18 | 19 | /** 20 | * Header name. 21 | */ 22 | @Required 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | /** 28 | * Header value. 29 | */ 30 | @Required 31 | public void setValue(String value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void doTag(XMLOutput output) throws JellyTagException { 37 | if (name == null || value == null) { 38 | return; 39 | } 40 | getResponse().setHeader(name, value); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/StatusCodeTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | package org.kohsuke.stapler.jelly; 25 | 26 | import org.apache.commons.jelly.JellyTagException; 27 | import org.apache.commons.jelly.XMLOutput; 28 | import org.jvnet.maven.jellydoc.annotation.NoContent; 29 | import org.jvnet.maven.jellydoc.annotation.Required; 30 | 31 | /** 32 | * Sets HTTP status code. 33 | * 34 | *

35 | * This is generally useful for programatically creating the error page. 36 | * 37 | * @author Kohsuke Kawaguchi 38 | */ 39 | @NoContent 40 | public class StatusCodeTag extends AbstractStaplerTag { 41 | private int code; 42 | 43 | /** 44 | * HTTP status code to send back. 45 | */ 46 | @Required 47 | public void setValue(int code) { 48 | this.code = code; 49 | } 50 | 51 | @Override 52 | public void doTag(XMLOutput output) throws JellyTagException { 53 | getResponse().setStatus(code); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jelly/src/main/java/org/kohsuke/stapler/jelly/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2010, Kohsuke Kawaguchi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, are permitted provided 6 | * that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this list of 9 | * conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | * conditions and the following disclaimer in the documentation and/or other materials 12 | * provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 15 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 16 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 19 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 20 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 21 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /** 25 | * Optional Jelly support, to write views in Jelly. 26 | */ 27 | @TagLibUri("jelly:stapler") 28 | package org.kohsuke.stapler.jelly; 29 | 30 | import org.jvnet.maven.jellydoc.annotation.TagLibUri; 31 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/AttributeExpressionTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import hudson.util.VersionNumber; 4 | import io.jenkins.lib.versionnumber.JavaSpecificationVersion; 5 | import java.net.URL; 6 | import org.htmlunit.WebClient; 7 | import org.htmlunit.html.HtmlDivision; 8 | import org.htmlunit.html.HtmlPage; 9 | import org.kohsuke.stapler.test.JettyTestCase; 10 | 11 | public class AttributeExpressionTest extends JettyTestCase { 12 | 13 | public void testAttributeExpression() throws Exception { 14 | WebClient wc = createWebClient(); 15 | HtmlPage page = wc.getPage(new URL(url, "/")); 16 | 17 | HtmlDivision div = page.getHtmlElementById("build-timeline-div"); 18 | assertEquals("Timezone", div.asNormalizedText()); 19 | if (JavaSpecificationVersion.forCurrentJVM().isOlderThan(new VersionNumber("16"))) { 20 | // TODO JENKINS-68215 does not yet work on Java 16+ 21 | assertNotNull(Float.parseFloat(div.getAttribute("data-hour-local-timezone"))); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/BindTagTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import java.net.URL; 4 | import org.htmlunit.WebClient; 5 | import org.htmlunit.html.HtmlPage; 6 | import org.kohsuke.stapler.framework.adjunct.AdjunctManager; 7 | import org.kohsuke.stapler.test.JettyTestCase; 8 | 9 | /** 10 | * @author Kohsuke Kawaguchi 11 | */ 12 | public class BindTagTest extends JettyTestCase { 13 | private String value; 14 | 15 | public AdjunctManager am; 16 | private int number; 17 | 18 | @Override 19 | protected void setUp() throws Exception { 20 | super.setUp(); 21 | this.am = new AdjunctManager(servletContext, getClass().getClassLoader(), "am"); 22 | } 23 | 24 | public void test1() throws Exception { 25 | WebClient wc = createWebClient(); 26 | HtmlPage page = wc.getPage(new URL(url, "/")); 27 | String content = page.getWebResponse().getContentAsString(); 28 | System.out.println(content); 29 | page.executeJavaScript("v.foo('hello world', 2);"); 30 | wc.getJavaScriptEngine().processPostponedActions(); 31 | wc.waitForBackgroundJavaScript(10000); 32 | assertEquals("hello world", value); 33 | assertEquals(2, number); 34 | } 35 | 36 | public void jsFoo(String arg, int arg2) { 37 | this.value = arg; 38 | this.number = arg2; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/BodyExpressionTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import hudson.util.VersionNumber; 4 | import io.jenkins.lib.versionnumber.JavaSpecificationVersion; 5 | import java.net.URL; 6 | import org.htmlunit.WebClient; 7 | import org.htmlunit.html.DomElement; 8 | import org.htmlunit.html.DomNodeList; 9 | import org.htmlunit.html.HtmlDefinitionDescription; 10 | import org.htmlunit.html.HtmlDefinitionTerm; 11 | import org.htmlunit.html.HtmlPage; 12 | import org.kohsuke.stapler.test.JettyTestCase; 13 | 14 | public class BodyExpressionTest extends JettyTestCase { 15 | 16 | public void testBodyExpression() throws Exception { 17 | WebClient wc = createWebClient(); 18 | HtmlPage page = wc.getPage(new URL(url, "/")); 19 | 20 | DomNodeList dts = page.getElementsByTagName("dt"); 21 | assertEquals(1, dts.size()); 22 | HtmlDefinitionTerm dt = (HtmlDefinitionTerm) dts.get(0); 23 | assertEquals("Timezone", dt.asNormalizedText()); 24 | 25 | DomNodeList dds = page.getElementsByTagName("dd"); 26 | assertEquals(1, dds.size()); 27 | HtmlDefinitionDescription dd = (HtmlDefinitionDescription) dds.get(0); 28 | if (JavaSpecificationVersion.forCurrentJVM().isOlderThan(new VersionNumber("16"))) { 29 | // TODO JENKINS-68215 does not yet work on Java 16+ 30 | assertNotNull(Float.parseFloat(dd.asNormalizedText())); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/ResourceBundleTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.core.Is.is; 5 | 6 | import java.net.URL; 7 | import java.util.Locale; 8 | import org.junit.Test; 9 | 10 | public class ResourceBundleTest { 11 | 12 | private static final URL RESOURCE_BUNDLE = 13 | ResourceBundleTest.class.getResource("/org/kohsuke/stapler/jelly/ResourceBundleTest/index.properties"); 14 | private static final String FILE_PATH = RESOURCE_BUNDLE.toExternalForm().replace(".properties", ""); 15 | private static final ResourceBundle resourceBundle = new ResourceBundle(FILE_PATH); 16 | 17 | @Test 18 | public void format() { 19 | String helloWorld = resourceBundle.format(Locale.ENGLISH, "hello_world"); 20 | 21 | assertThat(helloWorld, is("Hello, World!")); 22 | } 23 | 24 | @Test 25 | public void formatFallsBackToDefaultIfMissing() { 26 | String helloWorld = resourceBundle.format(Locale.FRANCE, "hello_world"); 27 | 28 | assertThat(helloWorld, is("Hello, World!")); 29 | } 30 | 31 | @Test 32 | public void formatLocaleOverrideInPlace() { 33 | String helloWorld = resourceBundle.format(Locale.CANADA, "hello_world"); 34 | 35 | assertThat(helloWorld, is("Welcome, World!")); 36 | } 37 | 38 | @Test 39 | public void formatLocaleNonISO_8859_1() { 40 | String helloWorld = resourceBundle.format(Locale.CHINA, "hello_world"); 41 | 42 | assertThat(helloWorld, is("你好,世界!简化")); 43 | } 44 | 45 | @Test 46 | public void formatLocaleNonISO_8859_1_encoded_with_utf8() { 47 | String helloWorld = resourceBundle.format(Locale.TRADITIONAL_CHINESE, "hello_world"); 48 | 49 | assertThat(helloWorld, is("你好世界!")); 50 | } 51 | 52 | @Test 53 | public void formatLocaleISO_8859_1_high_range_character_invalid_utf_8() { 54 | String helloWorld = resourceBundle.format(Locale.FRANCE, "french"); 55 | 56 | assertThat(helloWorld, is("Français")); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly; 2 | 3 | import java.net.URL; 4 | import org.htmlunit.WebClient; 5 | import org.htmlunit.html.HtmlPage; 6 | import org.kohsuke.stapler.test.JettyTestCase; 7 | 8 | /** 9 | * @author Kohsuke Kawaguchi 10 | */ 11 | public class TagLibNamespaceExportTest extends JettyTestCase { 12 | public void test1() throws Exception { 13 | WebClient wc = createWebClient(); 14 | HtmlPage page = wc.getPage(new URL(url, "/")); 15 | String content = page.getWebResponse().getContentAsString(); 16 | System.out.println(content); 17 | assertTrue(content.contains("foo")); 18 | assertFalse(content.contains("bar")); 19 | assertFalse(content.contains("zot")); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Arm.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | import org.kohsuke.stapler.HttpResponse; 4 | import org.kohsuke.stapler.HttpResponses; 5 | import org.kohsuke.stapler.StaplerRequest2; 6 | 7 | /** 8 | * @author Kohsuke Kawaguchi 9 | */ 10 | public class Arm { 11 | public HttpResponse doDynamic(StaplerRequest2 req) { 12 | return HttpResponses.plainText(req.getRestOfPath()); 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return "arm"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Button.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | /** 4 | * @author Kohsuke Kawaguchi 5 | */ 6 | public class Button { 7 | public final String color; 8 | 9 | public Button(String color) { 10 | this.color = color; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return color + " button"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Eye.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | /** 4 | * @author Kohsuke Kawaguchi 5 | */ 6 | public class Eye { 7 | public final int i; 8 | 9 | public Eye(int i) { 10 | this.i = i; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return "eye #" + i; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Head.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | import org.kohsuke.stapler.HttpResponse; 4 | import org.kohsuke.stapler.HttpResponses; 5 | 6 | /** 7 | * @author Kohsuke Kawaguchi 8 | */ 9 | public class Head { 10 | public Eye getEye(int i) { 11 | return new Eye(i); 12 | } 13 | 14 | public HttpResponse doNose() { 15 | return HttpResponses.plainText("nose"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Issue76Test.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | import java.net.URL; 4 | import org.htmlunit.TextPage; 5 | import org.htmlunit.WebClient; 6 | import org.htmlunit.html.HtmlPage; 7 | import org.kohsuke.stapler.test.JettyTestCase; 8 | 9 | /** 10 | * @author Kohsuke Kawaguchi 11 | */ 12 | public class Issue76Test extends JettyTestCase { 13 | // bound to /robot 14 | public final Robot robot = new Robot(); 15 | 16 | // protected version of /robot which mimics the URL structure but tweaks its routes 17 | public final Protection protectedRobot = new Protection(robot); 18 | 19 | public void testRouting() throws Exception { 20 | WebClient wc = createWebClient(); 21 | HtmlPage p = wc.getPage(new URL(url, "robot/head/eye/3/")); 22 | assertTrue(p.getWebResponse().getContentAsString().contains("This is eye 3")); 23 | 24 | // protected parts have different index view 25 | TextPage tp = wc.getPage(new URL(url, "protectedRobot/head/eye/3/")); 26 | assertTrue(tp.getContent().startsWith("protected eye #3")); 27 | 28 | tp = wc.getPage(new URL(url, "protectedRobot/head/nose")); 29 | assertEquals("nose", tp.getContent().trim()); 30 | 31 | tp = wc.getPage(new URL(url, "protectedRobot/arm/hand/nail")); 32 | assertEquals("/hand/nail", tp.getContent().trim()); 33 | 34 | tp = wc.getPage(new URL(url, "protectedRobot/arm")); 35 | assertEquals("protected arm", tp.getContent().trim()); 36 | 37 | { // list lookup 38 | p = wc.getPage(new URL(url, "robot/legs/0/")); 39 | assertTrue(p.getWebResponse().getContentAsString().contains("left leg")); 40 | 41 | tp = wc.getPage(new URL(url, "protectedRobot/legs/1/")); 42 | assertEquals("protected right leg", tp.getContent().trim()); 43 | } 44 | 45 | { // map lookup 46 | p = wc.getPage(new URL(url, "robot/buttons/red/")); 47 | assertTrue(p.getWebResponse().getContentAsString().contains("This is a button")); 48 | 49 | tp = wc.getPage(new URL(url, "protectedRobot/buttons/red/")); 50 | assertEquals("protected red button", tp.getContent().trim()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Leg.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | /** 4 | * @author Kohsuke Kawaguchi 5 | */ 6 | public class Leg { 7 | public final String name; 8 | 9 | public Leg(String name) { 10 | this.name = name; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return name + " leg"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Protection.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | import org.kohsuke.stapler.HttpResponse; 4 | import org.kohsuke.stapler.HttpResponses; 5 | import org.kohsuke.stapler.lang.KInstance; 6 | import org.kohsuke.stapler.lang.Klass; 7 | 8 | /** 9 | * Wraps various parts of robots and tweaks its routing behaviour. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class Protection implements KInstance { 14 | /** 15 | * Object being wrapped. 16 | */ 17 | public final Object o; 18 | 19 | public Protection(Object o) { 20 | this.o = o; 21 | } 22 | 23 | /** 24 | * Fool the reflection so that Stapler sees routes exposed by {@code o.getClass()}. 25 | */ 26 | @Override 27 | public Klass getKlass() { 28 | return new Klass<>(new ProtectedClass(o.getClass()), ProtectedClass.NAVIGATOR); 29 | } 30 | 31 | /** 32 | * Override doIndex. 33 | */ 34 | public HttpResponse doIndex() { 35 | return HttpResponses.plainText("protected " + o); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jelly/src/test/java/org/kohsuke/stapler/jelly/issue76/Robot.java: -------------------------------------------------------------------------------- 1 | package org.kohsuke.stapler.jelly.issue76; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Root of the model object. 10 | * 11 | *

12 | * Test ground of various traversal logic. 13 | * 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | public class Robot { 17 | public final Head head = new Head(); 18 | 19 | public final List legs = Arrays.asList(new Leg("left"), new Leg("right")); 20 | 21 | public final Map buttons = new HashMap<>(); 22 | 23 | public Robot() { 24 | buttons.put("red", new Button("red")); 25 | buttons.put("blue", new Button("blue")); 26 | } 27 | 28 | public Object getDynamic(String part) { 29 | if (part.equals("arm")) { 30 | return new Arm(); 31 | } 32 | return null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/AttributeExpressionTest/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

Timezone
6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/BindTagTest/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/BodyExpressionTest/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
Timezone
7 |
${(tz.rawOffset + tz.DSTSavings) / 3600000}
8 |
9 | 10 | 11 |
12 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index.properties: -------------------------------------------------------------------------------- 1 | hello_world=Hello, World! 2 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index_en_CA.properties: -------------------------------------------------------------------------------- 1 | hello_world=Welcome, World! 2 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index_fr_FR.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index_fr_FR.properties -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index_zh_CN.properties: -------------------------------------------------------------------------------- 1 | hello_world=\u4f60\u597d\uff0c\u4e16\u754c\uff01\u7b80\u5316 2 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/ResourceBundleTest/index_zh_TW.properties: -------------------------------------------------------------------------------- 1 | hello_world=你好世界! 2 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/index.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | foo 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/sub.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | bar 4 | 5 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/tagfile.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | zot 4 | 5 | -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/taglib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenkinsci/stapler/ac0b57d437a17843e5e8004d20b85347c8dd658f/jelly/src/test/resources/org/kohsuke/stapler/jelly/TagLibNamespaceExportTest/taglib/taglib -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/issue76/Button/index.jelly: -------------------------------------------------------------------------------- 1 | This is a button -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/issue76/Eye/index.jelly: -------------------------------------------------------------------------------- 1 | This is eye ${it.i} -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/issue76/Head/index.jelly: -------------------------------------------------------------------------------- 1 | This is head -------------------------------------------------------------------------------- /jelly/src/test/resources/org/kohsuke/stapler/jelly/issue76/Leg/index.jelly: -------------------------------------------------------------------------------- 1 | ${it.name} leg -------------------------------------------------------------------------------- /jsp/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.kohsuke.stapler 6 | stapler-parent 7 | ${changelist} 8 | 9 | 10 | stapler-jsp 11 | Stapler JSP module 12 | JSP binding for Stapler 13 | 14 | 15 | 16 | ${project.groupId} 17 | stapler 18 | ${project.version} 19 | 20 | 21 | org.kohsuke.metainf-services 22 | metainf-services 23 | true 24 | 25 | 26 | jakarta.servlet 27 | jakarta.servlet-api 28 | 5.0.0 29 | provided 30 | 31 | 32 | jakarta.servlet.jsp 33 | jakarta.servlet.jsp-api 34 | 3.0.0 35 | provided 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /jsp/src/main/resources/META-INF/taglib.tld: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.0 5 | 1.1 6 | stapler 7 | http://stapler.dev.java.net/ 8 | 9 | The stapler tag library contains tags that takes advantage of 10 | the stapler request dispatching mechanism. 11 | 12 | 13 | include 14 | org.kohsuke.stapler.tags.Include 15 | empty 16 | 17 | page 18 | yes 19 | yes 20 | 21 | 22 | it 23 | no 24 | yes 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------