[
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file\n\nversion: 2\nupdates:\n  - package-ecosystem: \"maven\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/maven.yml",
    "content": "# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: Java CI with Maven\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up JDK 17\n      uses: actions/setup-java@v3\n      with:\n        java-version: '17'\n        distribution: 'temurin'\n        cache: maven\n    - name: Build with Maven\n      run: mvn -B package --file pom.xml\n\n    # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive\n    #- name: Update dependency graph\n    #  uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6\n"
  },
  {
    "path": ".gitignore",
    "content": "/target/\n/.settings/\n.classpath\n.project\n.idea/\n*.iml"
  },
  {
    "path": "README.adoc",
    "content": "= Wicket autoconfiguration with Spring Boot\n\nCurrent release version:\n\n* 4.1.x - http://wicket.apache.org/[Wicket 10.6] with Spring Boot 3.5.x - Branch master\n* 4.0.x - http://wicket.apache.org/[Wicket 10.0] with Spring Boot 3.2.x - Branch master\n\nNOTE: http://search.maven.org/#search|ga|1|com.giffing.wicket.spring.boot\n\nNOTE: Example projects: https://github.com/MarcGiffing/wicket-spring-boot-examples\n\n* <<introduction>>\n* <<getting_started>>\n* <<how_does_it_work>>\n* <<spring_profile_dev_configuration>>\n* <<custom-conditions>>\n* <<extension>>\n* <<war_deployment>>\n\n[[introduction]]\n== Introduction\n\nhttps://dzone.com/articles/enhance-wicket-with-spring-boot *by Andrea Del Bene*\n\nThis project makes it easy to create a new Wicket projects with a minimum\nof configuration effort. It uses Spring Boot to autoconfigure Wickets core and\nits extension (related projects like wicketstuff, beanvalidation...) with an reasonable default value which can be overridden over property files.\n\n* Core Features\n\n** Configures an embedded Servlet Container by default (Spring Boot Feature).\n** Autoconfiguration of the needed link:wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/WicketWebInitializer.java[Wicket Servlet filters].\n** Autoconfiguration for Spring/Spring-Security and dependency injection support with @SpringBean.\n** Autoconfiguration of Wicket <<extension>>.\n** Faster development support with <<extension-springboot-devtools>>\n\n[[getting_started]]\n== Getting started\n\nTo get started you have to create a new Maven Project (or another preferred dependency/build-management tool)\nand add the *wicket-spring-boot-starter* dependency to your configuration. \n\n[source,xml]\n----\n<dependency>\n  <groupId>com.giffing.wicket.spring.boot.starter</groupId>\n  <artifactId>wicket-spring-boot-starter</artifactId>\n</dependency>\n----\n\nBeside the Maven dependency configuration we need the following steps to do\n\n. Create a class which is marked with @SpringBootApplication - see http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-using-springbootapplication-annotation[Springs documentation]\n. Create your HomePage class (with HTML) which will me marked with @WicketHomePage\n\n\n[source,java]\n----\n@SpringBootApplication\npublic class WicketApplication {\n  public static void main(String[] args) throws Exception {\n    new SpringApplicationBuilder()\n      .sources(WicketApplication.class)\n      .run(args);\n  }\n\n}\n\n@WicketHomePage\npublic class HomePage extends WebPage {\n}\n\n<html xmlns:wicket=\"http://wicket.apache.org\">\n\t<head></head>\n\t<body>\n\t\tYou content\n\t\t<wicket:child/>\n\t</body>\n</html>\n\n----\n\nThats all! When you execute the main method you will get a fully working and configured \nWicket application. An embedded Tomcat is automatically started.\n\nIn a usal Wicket application you would like to provide custom configuration in Wickets WebApplication init() method.\nYou could create your own 'extension' by creating a bean which implements WicketApplicationInitConfiguration\n\n[source,java]\n----\n@ApplicationInitExtension\npublic class YouExtensionConif implements WicketApplicationInitConfiguration {\n\n  @Override\n  public void init(WebApplication webApplication) {\n  \t// your custom configuration\n  }\n\n}\n----\n\nIf this configuration is not enough and you want to override special methods of Wickets WebApplication class you have\nto create a bean which extends one of the following two classes\n\n* WicketBootStandardWebApplication - Without Security\n* WicketBootSecuredWebApplication  - With Security - You'll need a security provider like <<extension-spring-security>>\n\n[source,java]\n----\n@Component\npublic class WicketWebApplication extends WicketBootSecuredWebApplication {\n  @Override\n  protected void init() {\n    super.init();\n  }\n}\n----\n\nThe custom WicketWebApplication is automatically picked up instead of the default provided one.\nYou can also override the getHomePage method() if you don't want to use the special @WicketHomePage annotations\nto mark the home page.\n\nTo package the application as an executable jar you have to add the spring-boot-maven-plugin.\n\n[source,xml]\n----\n <plugin>\n  <groupId>org.springframework.boot</groupId>\n  <artifactId>spring-boot-maven-plugin</artifactId>\n</plugin>\n----\n\nResource files (html, css, js, ...) are not copied to the target folder if placed in the *src/main/java*\nfolder. You have to tell Maven to copy these files:\n\n\n[source,xml]\n----\n<resources>\n  <resource>\n    <directory>src/main/resources</directory>\n  </resource>\n  <resource>\n    <directory>src/main/java</directory>\n    <includes>\n      <include>**</include>\n    </includes>\n    <excludes>\n      <exclude>**/*.java</exclude>\n    </excludes>\n  </resource>\n</resources>\n----\n\n[[how_does_it_work]]\n== How does it work?\n\nTo fully understand how http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-developing-auto-configuration[Spring Boots autconfiguration] \nand in general Spring Boot works you should read the excellent \nhttp://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/[documentation] from this fantastic http://projects.spring.io/spring-boot/[project].\n\nAs an an example we will look to the AnnotatedMountScanner configuration. The https://github.com/wicketstuff/core/wiki/Annotation[annotated mount scanner] \nis an project which supports bookmarkable URLs configured by annotations on WebPage classes. If you have this '@MountPath(\"login\")' annotation on a \nWebPage then the Page is mounted to 'http://localhost/login'.\n\nIn this project each configuration is separated in two classes to configure this particular feature/extension. The extension\nconsists of a property and a configuration class.\n\nThe property class holds properties to configure the specific feature. In the AnnotatedMountScannerProperties class we\nfound two properties:\n\n[source,java]\n----\n@ConfigurationProperties(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX)\npublic class AnnotatedMountScannerProperties {\n\tpublic static final String PROPERTY_PREFIX = \"wicket.stuff.annotationscan\";\n\t/**\n\t * @see AnnotatedMountScannerConfig\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * An alternative package name for scanning for mount path if the\n\t * WicketApplication should not used as the root scan package\n\t */\n\tprivate String packagename;\n----\n\nThis property file can be imported in the configuration class AnnotatedMountScannerConfig.\n\n[source,java]\n----\n/**\n * Auto configuration for the {@link AnnotatedMountScanner}.\n * \n * It uses the user defined {@link WebApplication} as the default package scan\n * root directory.\n * \n * Enables annotate mount scanner if the following two condition matches:\n * \n * 1. The {@link AnnotatedMountScanner} is in the classpath.\n * \n * 2. The property {@link AnnotatedMountScannerProperties#PROPERTY_PREFIX}\n * .enabled is true (default = true)\n * \n * \n * @author Marc Giffing\n *\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.wicketstuff.annotation.scan.AnnotatedMountScanner.class)\n@EnableConfigurationProperties({ AnnotatedMountScannerProperties.class })\npublic class AnnotatedMountScannerConfig implements WicketApplicationInitConfiguration {\n\n\t@Autowired\n\tprivate AnnotatedMountScannerProperties prop;\n\n\t@Override\n\tpublic void init(WebApplication webApplication) {\n\t\tString packagename = webApplication.getClass().getPackage().getName();\n\t\tif (prop.getPackagename() != null) {\n\t\t\tpackagename = prop.getPackagename();\n\t\t}\n\t\tnew AnnotatedMountScanner().scanPackage(packagename).mount(webApplication);\n\t}\n}\n----\n\nIf all conditions on the AnnotatedMountScannerConfig matches the configuration class is configured as\na spring bean. All Spring beans which implements the interface WicketApplicationInitConfiguration will\nbe injected as a list in the default WicketBootWebApplication class.  \n\nIn the WicketBootWebApplication class we iterate in Wickets init method over the list and call on each the\ninit method to configure the application.\n\n[source,java]\n----\npublic class WicketBootWebApplication extends AuthenticatedWebApplication {\n  @Autowired(required = false)\n  private List<WicketApplicationInitConfiguration> configurations = new ArrayList<>();\n  @Override\n  protected void init() {\n    super.init();\n    for (WicketApplicationInitConfiguration configuration : configurations) {\n      configuration.init(this);\n    }\n  }\n}\n----\n\n[[spring_profile_dev_configuration]]\n=== Spring profile configuration\n\nThe Wicket Spring Boot Starter project ships with a default development configuration.\nIt can be activated by activating the 'development' Spring profile in the main class or over\nexternal JVM/Maven arguments.\n\nThe default configuration can be overridden with a custom property file. See Spring Boots reference documentation http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config[here].\n\ninclude::wicket-spring-boot-starter/src/main/resources/application-development.yml[]\n[source,yml]\n----\nwicket:\n  core:\n    settings:\n      general:\n        configuration-type: development\n      debug:\n        enabled: true\n        component-use-check: true\n        development-utilities-enabled: true\n  stuff:\n    htmlcompressor:\n      enabled: false\n      features:\n        removeComments: false\n        removeMultiSpaces: false\n        removeIntertagSpaces: false\n        removeQuotes: false\n        compressJavaScript: false\n        compressCss: false\n        simpleDoctype: false\n        removeScriptAttributes: false\n        removeStyleAttributes: false\n        removeLinkAttributes: false\n        removeFormAttributes: false\n        removeInputAttributes: false\n        simpleBooleanAttributes: false\n        removeJavaScriptProtocol: false\n        removeHttpProtocol: false\n        removeHttpsProtocol: false\n        preserveLineBreaks: false\n  external:\n    development:\n      devutils:\n        statelesschecker:\n          enabled: true\n        interceptor:\n          enable-live-sessions-page: true\n        diskstorebrowser:\n          enabled: true\n      wicketsource:\n        enabled: true\n----\n\n[[custom-conditions]]\n== Custom conditions\n\nThis section lists custom conditional configuration like Spring Boot ones. \n\n=== @ConditionalOnWicket\n\nWith the ConditionOnWicket annotation you can check that configuration classes only apply\non a specific Wicket major version. If some functionality is only available on Wicket 7 \nyou can use this annotation.\n\n[source,java]\n----\n@ApplicationInitExtension\n@ConditionalOnWicket(value=7, range=Range.EQUALS_OR_HIGHER)\npublic ConditionalConfig implements WicketApplicationInitConfiguration{\n\t@Override\n\tpublic void init(WebApplication webApplication) {\n\t\t// configuration option which only apply to Wickets major version 7 or higher\n\t}\n}\n----\n\n[[extension]]\n== Extensions\n\nThe following section describes the current extensions and the\nrequired dependencies. An extension is a custom labeling in this project\nwhich is used to auto-configure a specific part of an Wicket application. An extension\nmay require an external dependency or is using Wickets core features. See section\n<<how_does_it_work>> to get a deeper knowledge.\n\n* <<extension-general>>\n** DEPLOYMENT-CONFIGURATIONS\n*** <<extension-spring-security>>\n*** <<extension-wicket-websocket>>\n*** <<extension-beanvalidation>>\n*** <<extension-core-csrf-prevention>>\n*** <<extension-webjars>>\n*** <<extension-wicketstuff-htmlcompressor>>\n*** <<extension-wicketstuff-annotationscan>>\n*** <<extension-core-serializer-deflated>>\n*** <<extension-wicketstuff-serializer-fast2>>\n*** <<extension-wicketstuff-serializer-kryo2>>\n*** <<extension-wicketstuff-restannotations>>\n*** <<extension-datastore-httpsession>>\n*** <<extension-datastore-cassandra>>\n*** <<extension-datastore-hazelcast>>\n*** <<extension-datastore-memcached>>\n*** <<extension-datastore-redis>>\n*** <<extension-wicketstuff-jamon>>\n\n** DEVELOPMENT-CONFIGURATIONS\n*** <<extension-general-debugsettings>>\n*** <<extension-devutils-diskstorebrowser>>\n*** <<extension-devutils-inspector>>\n*** <<extension-devutils-statelesschecker>>\n*** <<extension-wicketsource>>\n*** <<extension-springboot-devtools>>\n\n[[extension-general]]\n=== General\n\nWicket can be started in DEVELOPMENT and DEPLOYMENT mode. You can change the\nconfiguration type over the following property configuration. The given property\nis automatically mapped to Wickets ConfigurationType enumeration. \n \n\n[source,properties]\n----\nwicket.core.settings.general.configuration-type=development # development/deployment(default)\n\nwicket.web.servlet.filter-mapping-param=/*\nwicket.web.servlet.dispatcher-types=request, error, async # request, error, async, include, forward\nwicket.web.servlet.init-parameters.*= # map<string,string> - configuration support for additional servlet init parameters\n\n#exception settings\nwicket.core.settings.exceptions.thread-dump-strategy=thread_holding_lock\nwicket.core.settings.exceptions.error-handling-strategy-during-ajax-requests=redirect_to_error_page\n\nwicket.core.settings.requestcycle.render-strategy=redirect-to-buffer # redirect-to-buffer / one-pass-render / redirect-to-render\nwicket.core.settings.requestcycle.buffer-response=true\nwicket.core.settings.requestcycle.gather-extended-browser-info=false\nwicket.core.settings.requestcycle.response-request-encoding=UTF-8\nwicket.core.settings.requestcycle.timeout-size=1\nwicket.core.settings.requestcycle.timeout-unit=minutes\nwicket.core.settings.requestcycle.exception-retry-count=10\n\n#Markup - Settings\nwicket.core.settings.markup.default-markup-encoding=UTF-8 # if null it uses the system default \nwicket.core.settings.markup.automatic-linking=false\nwicket.core.settings.markup.compress-whitespace=false\nwicket.core.settings.markup.strip-comments=false\nwicket.core.settings.markup.strip-wicket-tags=true\nwicket.core.settings.markup.throw-exception-on-missing-xml-declaration=false\n\n#RequestLogger - Settings\nwicket.core.settings.requestlogger.enabled=false\nwicket.core.settings.requestlogger.record-session-size\nwicket.core.settings.requestlogger.requests-window-size\n\n\nwicket.core.requestmapper.cryptmapper.enabled=false # URL encryption support\n\n\nwicket.core.settings.pagestore.enabled=false # enables custom store settings\nwicket.core.settings.pagestore.session-size=2\nwicket.core.settings.pagestore.session-unit=megabytes\nwicket.core.settings.pagestore.asynchronous= # overrides wickets default value only when set\nwicket.core.settings.pagestore.asynchronous-queue-capacity= # overrides wickets default value only when set\nwicket.core.settings.pagestore.file-store-folder= # overrides wickets default value only when set\nwicket.core.settings.pagestore.inmemory-cache-size= # overrides wickets default value only when set\n\t\n----\nIf you insert e.g. developmentx you will get a startup error:\n[listing]\nField error in object 'wicket' on field 'configurationType': rejected value [developmentx]; codes [typeMismatch.wicket.configurationType\n\n==== Special Annotations\n\n* @WicketHomePage\n** A Page marked with this annotation will be configured as the default home page. If multiple WicketHomePage annotation found an exception is thrown.\n* @WicketSignInPage\n** A Page marked with this annotation will be configured as the default login page. A security provider like Spring Security is needed. If multiple annotations found an exception is thrown. \n* @WicketAccessDeniedPage\n** A Page marked with this annotation will be configured as the default access denied page.  \n* @WicketInternalErrorPage\n** A Page marked with this annotation will be configured as the default internal error page.\n* @WicketExpiredPage  \n** A Page marked with this annotation will be configured as the default expired page.\n\n[[extension-spring-security]]\n=== Spring Security\n\nThis starter detects automatically Spring Security if the Spring Boot Starter Security dependency is added. \nInternally the WicketBootSecuredWebApplication is used instead of the WicketBootStandardWebApplication class.\n\n[source,xml]\n----\n<dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-security</artifactId>\n</dependency>\n----\n\nIf you wan't to disable the Spring Security configuration for Wicket use the following property.\n\n[source,properties]\n----\nwicket.external.spring.security=false\n----\n\n\n[[extension-wicket-websocket]]\n=== Wicket Native WebSockets\n\nhttps://ci.apache.org/projects/wicket/guide/7.x/guide/single.html#nativewebsockets[Documentation]\n\nThis project provides an auto configuration support for native WebSockets. If the required dependencies\nare in the classpath a JavaxWebSocketFilter servlet filter is configured instead of the default WicketFilter. \n\nTo simplify the usage of sending WebSocket messages a class named WebSocketMessageBroadcaster is automatically registered as a \nspring bean. You can inject the class anywhere with @SpringBean and use the 'send' method to send WebSocket messages.\n\n\n[source,properties]\n----\nwicket.external.websocket=true # enables WebSocket support - dependency required (move documentation to seperated section)\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.apache.wicket</groupId>\n  <artifactId>wicket-native-websocket-javax</artifactId>\n</dependency>\n----\n\n\n[[extension-beanvalidation]]\n=== Bean validation\n\nWicket support for JSR 303 Bean validation.\nSee Wickets user guide \nhttps://ci.apache.org/projects/wicket/guide/7.x/guide/single.html[Validation with JSR 303]\n\nTo enable Wickets bean validation you have to add the *wicket-bean-validation* dependency to your\nproject. It will automatically configured and can be used in the project.\n\n[source,properties]\n----\nwicket.external.beanvalidation.enabled=true # enabled by default if bean validation project is present\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.apache.wicket</groupId>\n  <artifactId>wicket-bean-validation</artifactId>\n</dependency>\n----\n\n[[extension-core-csrf-prevention]]\n=== Core - Prevention of CSRF Attacks\n\n\n\n[source,properties]\n----\nwicket.core.csrf.enabled=true\nwicket.core.csrf.no-origin-action=allow\nwicket.core.csrf.conflicting-origin-action=abort\nwicket.core.csrf.error-code=400\nwicket.core.csrf.error-message=Origin does not correspond to request\nwicket.core.csrf.accepted-origins[0]=domain.name.tld        # Just the domain name, no protocol\nwicket.core.csrf.accepted-origins[1]=other-domain.name.tld  # Add more origins by increasing the index\n\n#TODO: There are some configuration options which should be added\n----\n\n[[extension-webjars]]\n=== Webjars\n\nhttps://github.com/l0rdn1kk0n/wicket-webjars\n\n[source,properties]\n----\nwicket.external.webjars.enabled=true\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>de.agilecoders.wicket.webjars</groupId>\n  <artifactId>wicket-webjars</artifactId>\n</dependency>\n----\n\n[[extension-wicketstuff-annotationscan]]\n=== Wicketstuff - annotationscan\n\nUse wicketstuff-annotation to use Java Annotations and class path searching to mount your Wicket pages.\n\nSee https://github.com/wicketstuff/core/wiki/Annotation[documentation]\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-annotation</artifactId>\n</dependency>\n----\n\n[source,properties]\n----\nwicket.stuff.annotationscan.enabled=true\nwicket.stuff.annotationscan.packagename=\n----\n\n[[extension-wicketstuff-htmlcompressor]]\n=== Wicketstuff - htmlcompressor\n\nSee https://github.com/wicketstuff/core/wiki/Htmlcompressor[documentation]\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-htmlcompressor</artifactId>\n</dependency>\n<dependency>\n  <groupId>com.yahoo.platform.yui</groupId>\n  <artifactId>yuicompressor</artifactId>\n</dependency>\n----\n\n[source,properties]\n----\nwicket.stuff.htmlcompressor.enabled=true\nwicket.stuff.htmlcompressor.features.*=\n----\n\n[[extension-core-serializer-deflated]]\n=== Core - serializer-deflated\n\n[source,properties]\n----\nwicket.core.serializer.deflated.enabled=false # has to be explicit enabled. deflates the outputstream, reducing page store size by up to a factor 8 at a price of about 2-20ms\n----\n\n[[extension-wicketstuff-serializer-fast2]]\n=== Wicketstuff - serializer-fast2\n\nSee https://github.com/wicketstuff/core/wiki/FastSerializer2[documentation]\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-serializer-fast2</artifactId>\n</dependency>\n----\n\n\n[source,properties]\n----\nwicket.stuff.serializer.fast2.enabled=true\n----\n\n[[extension-wicketstuff-serializer-kryo2]]\n=== Wicketstuff - serializer-kryo2\n\nSee https://github.com/wicketstuff/core/wiki/Kryo-Serializer[documentation]\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-serializer-kryo2</artifactId>\n</dependency>\n----\n\n[source,properties]\n----\nwicket.stuff.serializer.fast2.enabled=true\n----\n\n\n[[extension-wicketstuff-restannotations]]\n=== Wicketstuff - restannotations\n\nSee https://github.com/wicketstuff/core/tree/master/wicketstuff-restannotations-parent[documentation]\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-restannotations</artifactId>\n</dependency>\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-restannotations-json</artifactId>\n</dependency>\n----\n\n[source,properties]\n----\nwicket.stuff.restannotations.enabled=true\nwicket.stuff.restannotations.packagename= # the package name to scan for project specific annotations\n----\n\n\n[[extension-general-debugsettings]]\n=== General - debugsettings\n\nWicket provides some debug settings which could be \n\n[source,properties]\n----\nwicket.core.settings.debug.enabled=false\nwicket.core.settings.debug.developmentUtilitiesEnabled=true # Enables all of the panels and pages, etc, from wicket-devutils package.\nwicket.core.settings.debug.ajaxDebugModeEnabled=true # if true: wicket-ajax-debug.js is added to header\nwicket.core.settings.debug.componentUseCheck=true\nwicket.core.settings.debug.outputMarkupContainerClassName=false\nwicket.core.settings.debug.componentPathAttributeName=\n----\n\n\n\n[[extension-datastore]]\n== Datastore\n\n[[extension-datastore-httpsession]]\n=== Datastore HttpSession\n\n[source,properties]\n----\nwicket.core.datastore.httpsession.enabled=false\nwicket.core.datastore.httpsession.pagesNumber=20 # the maximum number of pages the data store can hold\n----\n\n\n[[extension-datastore-cassandra]]\n=== Datastore cassandra\n\nSee https://github.com/wicketstuff/core/wiki/DataStores[Documentation]\n\n[source,properties]\n----\nwicket.stuff.datastore.cassandra.enabled=true\nwicket.stuff.datastore.cassandra.contact-points= #comma-separated list \nwicket.stuff.datastore.cassandra.table-name=pagestore\nwicket.stuff.datastore.cassandra.keyspace-name=wicket\nwicket.stuff.datastore.cassandra.record-ttl=30\nwicket.stuff.datastore.cassandra.record-ttl-unit=minutes\nwicket.stuff.datastore.cassandra.session-size=2\nwicket.stuff.datastore.cassandra.session-unit=megabytes\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-datastore-cassandra</artifactId>\n</dependency>\n----\n\n[[extension-datastore-hazelcast]]\n=== Datastore hazelcast\n\nSee https://github.com/wicketstuff/core/wiki/DataStores[Documentation]\n\n[source,properties]\n----\nwicket.stuff.datastore.hazelcast.enabled=true\nwicket.stuff.datastore.hazelcast.session-size=2L \nwicket.stuff.datastore.hazelcast.session-unit=megabytes\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-datastore-hazelcast</artifactId>\n</dependency>\n<dependency>\n  <groupId>com.hazelcast</groupId>\n  <artifactId>hazelcast</artifactId>\n</dependency>\n----\n\n[[extension-datastore-memcached]]\n=== Datastore memcached\n\nSee https://github.com/wicketstuff/core/wiki/DataStores[Documentation]\n\n[source,properties]\n----\nwicket.stuff.datastore.memcached.enabled=true\nwicket.stuff.datastore.memcached.session-size=2L \nwicket.stuff.datastore.memcached.session-unit=megabytes\nwicket.stuff.datastore.memcached.expiration-time=30\nwicket.stuff.datastore.memcached.port=11211\nwicket.stuff.datastore.memcached.server-names=\nwicket.stuff.datastore.memcached.shutdown-timeout=30\nwicket.stuff.datastore.memcached.shutdown-timeout-unit=minutes\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-datastore-memcached</artifactId>\n</dependency>\n----\n\n[[extension-datastore-redis]]\n=== Datastore redis\n\nSee https://github.com/wicketstuff/core/wiki/DataStores[Documentation]\n\n[source,properties]\n----\nwicket.stuff.datastore.redis.enabled=true\nwicket.stuff.datastore.redis.session-size=2L \nwicket.stuff.datastore.redis.session-unit=megabytes\nwicket.stuff.datastore.redis.expiration-time=30\nwicket.stuff.datastore.redis.port=11211\nwicket.stuff.datastore.redis.server-names=\nwicket.stuff.datastore.redis.shutdown-timeout=30\nwicket.stuff.datastore.redis.shutdown-timeout-unit=minutes\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-datastore-redis</artifactId>\n</dependency>\n----\n\n\n[[extension-wicketstuff-jamon]]\n=== Wicketstuff - JAMon\n\nUsed to monitor page requests. Provides a statistic page.\n\nSee https://github.com/wicketstuff/core/blob/master/jamon-parent/[Github]\n\n[source,properties]\n----\nwicket.stuff.monitoring.jamon.enabled=true\nwicket.stuff.monitoring.jamon.include-source-name-in-monitor-label=true\nwicket.stuff.monitoring.jamon.mountPage=/monitoring/jamon # the url to which the statistic page is mounted\n----\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.wicketstuff</groupId>\n  <artifactId>wicketstuff-jamon</artifactId>\n</dependency>\n----\n\nNOTE: JAMon includes hazelcast to gather statistics. You may need to disable the datastore hazelcast support: <<extension-datastore-hazelcast>>\n\n[[extension-devutils]]\n=== Devutils\n\n[source,xml]\n----\n<dependency>\n  <groupId>org.apache.wicket</groupId>\n  <artifactId>wicket-devutils</artifactId>\n</dependency>\n----\n\n[[extension-devutils-diskstorebrowser]]\n==== Devutils - diskstorebrowser\n\n[source,properties]\n----\nwicket.external.development.devutils.diskstorebrowser.enabled=false\nwicket.external.development.devutils.diskstorebrowser.mountPage=devutils/diskstore/browser\n----\n\n[[extension-devutils-inspector]]\n==== Devutils - inspector\n\n[source,properties]\n----\nwicket.external.development.devutils.diskstorebrowser.enabled=false\nwicket.external.development.devutils.diskstorebrowser.mountPage=devutils/diskstore/browser\n----\n\n[[extension-devutils-statelesschecker]]\n==== Devutils - statelesschecker\n\n[source,properties]\n----\nwicket.external.development.devutils.interceptor.enableLiveSessionsPage=false\nwicket.external.development.devutils.interceptor.liveSessionPageMount=devutils/inspector/live-session-page\n----\n\n[[extension-wicketsource]]\n=== Wicket-Source\n\nSee https://github.com/jennybrown8/wicket-source/wiki[documentation]\n\n[source,xml]\n----\n<dependency>\n\t<groupId>com.github.jennybrown8.wicket-source</groupId>\n\t<artifactId>wicket-source</artifactId>\n</dependency>\n----\n\n[source,properties]\n----\nwicket.external.development.wicketsource.enabled=false\n----\n\n[[extension-springboot-devtools]]\n==== Spring Boot - DevTools\n\nSee https://spring.io/blog/2015/06/17/devtools-in-spring-boot-1-3[Spring Boot DevTools]\n\nThe project tries to improve the development-time experience when working with Spring Boot. \nThere is a problem with Wickets default and other serializer (fast2, kryo2...). See https://github.com/MarcGiffing/wicket-spring-boot/issues/29[Issue 29]\nIf the spring-boot-devtools dependency is in the classpath a \nlink:/wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/SpringDevToolsSerializer.java[special Spring serializer]\nwill be activated. \n\nAll other serializer will only be activated if the Spring Boot DevTools dependency is not in the classpath.\n\n[source,xml]\n----\n<dependencies>\n    <dependency>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-devtools</artifactId>\n    </dependency>\n</dependencies>\n----\n\n[[war_deployment]]\n== Configure as WAR for deploy on Servlet Container\n\n#115\n\nTo run the application as a *war* file in the Servlet Container like Tomcat you have to do the following steps.\n\n* Set the packaging to war in your build system (maven, gradle)\n* Mark the *spring-boot-starter-tomcat* dependency as provided\n* Use the Spring provided plugins to repackage the project\n* Extend from SpringBootServletInitializer\n** Here you can optionally set configurations which only apply when deployed as a war in a Servlet Container  \n** http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-maven-packaging[maven]\n** http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-gradle-repackage-configuration[gradle] \n\n\n[source,java]\n----\n@SpringBootApplication\npublic class WicketApplication extends SpringBootServletInitializer  {\n\n//Can be used while developing\npublic static void main(String[] args) throws Exception {\n\tnew SpringApplicationBuilder()\n\t\t.sources(WicketApplication.class)\n\t\t.run(args);\n}\n\n//Executed when deployed as a WAR in a Servlet container.\n@Override\nprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\tbuilder.properties( WebSocketWicketWebInitializerAutoConfiguration.REGISTER_SERVER_ENDPOINT_ENABLED + \"=false\" );\n\treturn super.configure( builder );\n}\n\n}\n----\n\nIf you already extend from a Wicket specific class you can create a separated class which extends from SpringBootServletInitializer (https://github.com/MarcGiffing/wicket-spring-boot/issues/115#issuecomment-311712298).\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\n\t<artifactId>wicket-spring-boot-starter-parent</artifactId>\n\t<version>4.1.1</version>\n\t<packaging>pom</packaging>\n\n\t<name>Wicket Spring Boot Starter Parent</name>\n\t<description>\n\t\tThis project (should) makes it easy to create \n\t\tWicket projects with a minimum of configuration effort. \n\t\tIs uses Spring Boot to autoconfigure Wickets core and extension \n\t\twith an reasonable default value which can be overridden \n\t\tover property files.\n\t\t\n\t\tThis parent project holds default configuration for the underlying \n\t\tsub modules \n\t</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>3.5.5</version>\n\t\t<relativePath /> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<url>https://github.com/MarcGiffing/wicket-spring-boot</url>\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0</url>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<url>https://github.com/MarcGiffing/wicket-spring-boot/</url>\n\t\t<connection>scm:git:https://github.com/MarcGiffing/wicket-spring-boot.git</connection>\n\t\t<tag>wicket-spring-boot-starter-parent-3.1.2</tag>\n\t</scm>\n\n\t<developers>\n\t\t<developer>\n\t\t\t<id>mgiffing</id>\n\t\t\t<name>Marc Giffing</name>\n\t\t\t<roles>\n\t\t\t\t<role>Project lead</role>\n\t\t\t</roles>\n\t\t</developer>\n\t</developers>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t\t<apache-shiro.version>2.0.5</apache-shiro.version>\n\t\t<wicket.version>10.6.0</wicket.version>\n\t\t<wicketstuff.version>10.6.0</wicketstuff.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<!-- internal dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\n\t\t\t\t<artifactId>wicket-spring-boot-context</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\n\t\t\t\t<artifactId>wicket-spring-boot-starter</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- Wicket dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-core</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-auth-roles</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-ioc</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-extensions</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n            <dependency>\n                <groupId>org.apache.wicket</groupId>\n                <artifactId>wicket-request</artifactId>\n                <version>${wicket.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.wicket</groupId>\n                <artifactId>wicket-spring</artifactId>\n                <version>${wicket.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.wicket</groupId>\n                <artifactId>wicket-util</artifactId>\n                <version>${wicket.version}</version>\n            </dependency>\n\t\t\t<!-- Wicketstuff dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-annotation</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-htmlcompressor</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency> <!-- required for the wicketstuff-htmlcompressor -->\n\t\t\t\t<groupId>com.yahoo.platform.yui</groupId>\n\t\t\t\t<artifactId>yuicompressor</artifactId>\n\t\t\t\t<version>2.4.8</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-serializer-kryo2</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-serializer-fast2</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-restannotations</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-restannotations-json</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-springreference</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff.htmlvalidator</groupId>\n\t\t\t\t<artifactId>wicketstuff-htmlvalidator</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-jamon</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- Wicket other dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-bean-validation</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>de.agilecoders.wicket.webjars</groupId>\n\t\t\t\t<artifactId>wicket-webjars</artifactId>\n\t\t\t\t<version>4.0.11</version>\n\t\t\t</dependency>\n\t\t\t<!-- Wicket datastore dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-datastore-common</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-datastore-cassandra</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-datastore-hazelcast</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-datastore-memcached</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-datastore-redis</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- Wicket websockets -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-native-websocket-javax</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- Wicket development dependencies -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-devutils</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.github.jennybrown8.wicket-source</groupId>\n\t\t\t\t<artifactId>wicket-source</artifactId>\n\t\t\t\t<version>9.0.0</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t\t<artifactId>wicket-tester</artifactId>\n\t\t\t\t<version>${wicket.version}</version>\n\t\t\t</dependency>\n\t\t\t<!-- Security - Apache Shiro -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t\t<artifactId>wicketstuff-shiro</artifactId>\n\t\t\t\t<version>${wicketstuff.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.shiro</groupId>\n\t\t\t\t<artifactId>shiro-spring-boot-web-starter</artifactId>\n\t\t\t\t<version>${apache-shiro.version}</version>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>ossrh</id>\n\t\t\t<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t\t<repository>\n\t\t\t<id>ossrh</id>\n\t\t\t<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t</repository>\n\t</distributionManagement>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>release</id>\n\t\t\t<modules>\n\t\t\t\t<module>wicket-spring-boot-context</module>\n\t\t\t\t<module>wicket-spring-boot-starter</module>\n\t\t\t\t<module>wicket-spring-boot-starter-example</module>\n\t\t\t</modules>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t\t<version>3.2.8</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>sign-artifacts</id>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n                        <version>3.3.1</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n                        <version>3.11.3</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<source>${java.version}</source>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n                    <plugin>\n                        <groupId>org.sonatype.plugins</groupId>\n                        <artifactId>nexus-staging-maven-plugin</artifactId>\n                        <version>1.7.0</version>\n                        <extensions>true</extensions>\n                        <configuration>\n                            <serverId>ossrh</serverId>\n                            <nexusUrl>https://ossrh-staging-api.central.sonatype.com</nexusUrl>\n                            <autoReleaseAfterClose>true</autoReleaseAfterClose>\n                        </configuration>\n                    </plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>default</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<modules>\n\t\t\t\t<module>wicket-spring-boot-context</module>\n\t\t\t\t<module>wicket-spring-boot-starter</module>\n\t\t\t\t<module>wicket-spring-boot-starter-example</module>\n\t\t\t</modules>\n\t\t</profile>\n\t</profiles>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.sonatype.plugins</groupId>\n\t\t\t\t<artifactId>nexus-staging-maven-plugin</artifactId>\n\t\t\t\t<version>1.7.0</version>\n\t\t\t\t<extensions>true</extensions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<serverId>ossrh</serverId>\n\t\t\t\t\t<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>\n\t\t\t\t\t<autoReleaseAfterClose>true</autoReleaseAfterClose>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>apache.snapshots.https</id>\n\t\t\t<url>https://repository.apache.org/content/repositories/snapshots</url>\n\t\t\t<releases>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</releases>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>sonatype</id>\n\t\t\t<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n\t\t\t<releases>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</releases>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n</project>\n"
  },
  {
    "path": "wicket-spring-boot-context/.gitignore",
    "content": "/target/\n/.settings/\n.classpath\n.project"
  },
  {
    "path": "wicket-spring-boot-context/README.md",
    "content": "# wicket-spring-boot-context\n\nAdvanced Level, a typical spring-boot user does not need this module.\n\n###Description\n\nThis module is used to create **custom auto configuration classes**. All necessary code\nis decoupled, thus a developer does not depend on the wicket-spring-boot-starter module\nitself.\n\nAll dependencies in the wicket-spring-boot-context module are scoped as `provided` so the\nuser of the context module is not forced to use any spring/wicket dependencies.\n\nEach configuration class should be marked with the annotation **@ApplicationInitExtension** \nand has to implement `WicketApplicationInitConfiguration`.\n\nThe module contains also common exceptions which should be used on e.g. configuration errors.\n\nHere is also the place for common configuration checks which can be used by other projects.\nThe annotation **@ConditionalOnWicket**  can be used to activate a configuration only on a \nspecific version of `Apache Wicket`.\n"
  },
  {
    "path": "wicket-spring-boot-context/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\r\n\t<modelVersion>4.0.0</modelVersion>\r\n\r\n\t<parent>\r\n\t\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\r\n\t\t<artifactId>wicket-spring-boot-starter-parent</artifactId>\r\n\t\t<version>4.1.1</version>\r\n\t</parent>\r\n\r\n\t<artifactId>wicket-spring-boot-context</artifactId>\r\n\t<name>Context</name>\r\n\t<description>\r\n\t\tProvides several constructs which allow developers to build\r\n                custom auto-configuration classes.\r\n\t</description>\r\n\r\n\t<dependencies>\r\n\t\t<dependency>\r\n\t\t\t<groupId>org.apache.wicket</groupId>\r\n\t\t\t<artifactId>wicket-core</artifactId>\r\n\t\t\t<scope>provided</scope>\r\n\t\t</dependency>\r\n\t\t<dependency>\r\n\t\t\t<groupId>org.apache.wicket</groupId>\r\n\t\t\t<artifactId>wicket-auth-roles</artifactId>\r\n\t\t\t<scope>provided</scope>\r\n\t\t</dependency>\r\n\t\t<dependency>\r\n\t\t\t<groupId>org.springframework</groupId>\r\n\t\t\t<artifactId>spring-context-support</artifactId>\r\n\t\t\t<scope>provided</scope>\r\n\t\t</dependency>\r\n\t\t<dependency>\r\n\t\t\t<groupId>org.projectlombok</groupId>\r\n\t\t\t<artifactId>lombok</artifactId>\r\n\t\t\t<scope>provided</scope>\r\n\t\t</dependency>\r\n\t\t<dependency>\r\n\t\t\t<groupId>org.springframework.boot</groupId>\r\n\t\t\t<artifactId>spring-boot-autoconfigure</artifactId>\r\n\t\t\t<scope>provided</scope>\r\n\t\t</dependency>\r\n\t</dependencies>\r\n\r\n</project>"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/condition/ConditionalOnWicket.java",
    "content": "package com.giffing.wicket.spring.boot.context.condition;\n\nimport org.springframework.context.annotation.Conditional;\n\nimport java.lang.annotation.*;\n\n/**\n * Conditional annotation to pre-check if an extension should be picked for autoconfiguration.\n * <p>\n * You can define the major Wicket version on which the extension\n * should or should not be executed.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(WicketSettingsCondition.class)\npublic @interface ConditionalOnWicket {\n\n    /**\n     * @return The major java version to check with the current value\n     */\n    int value();\n\n    /**\n     * @return Defines how the given major version should be checked with the current version\n     */\n    Range range() default Range.EQUALS_OR_HIGHER;\n\n\n    enum Range {\n        /**\n         * The Wicket major version equals the\n         */\n        EQUALS,\n        /**\n         * The Wicket major version equals or is newer\n         */\n        EQUALS_OR_HIGHER,\n\n        /**\n         * The Wicket major version equals or is lower\n         */\n        EQUALS_OR_LOWER,\n\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/condition/WicketSettingsCondition.java",
    "content": "package com.giffing.wicket.spring.boot.context.condition;\n\nimport com.giffing.wicket.spring.boot.context.condition.ConditionalOnWicket.Range;\nimport org.apache.wicket.settings.FrameworkSettings;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\nimport java.util.Map;\n\n/**\n * Retrieves the current major Wicket Version from the classpath and matches it against\n * the given conditional value in the {@link ConditionalOnWicket} annotation.\n *\n * @author Marc Giffing\n */\npublic class WicketSettingsCondition extends SpringBootCondition {\n\n    @Override\n    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n        String wicketVersion = retrieveWicketVersion();\n\n        Map<String, Object> attributes = metadata\n                .getAnnotationAttributes(ConditionalOnWicket.class.getName());\n        Range range = (Range) attributes.get(\"range\");\n        int expectedVersion = (int) attributes.get(\"value\");\n        String[] splittedWicketVersion = wicketVersion.split(\"\\\\.\");\n        int majorWicketVersion = Integer.parseInt(splittedWicketVersion[0]);\n        return getMatchOutcome(range, majorWicketVersion, expectedVersion);\n    }\n\n    protected ConditionOutcome getMatchOutcome(Range range, int runningVersion,\n                                               int expectedVersion) {\n        boolean match = matches(range, expectedVersion, runningVersion);\n        return new ConditionOutcome(match, getMessage(match, range, runningVersion, expectedVersion));\n    }\n\n    private boolean matches(Range range, int expectedVersion, int runningVersion) {\n        return switch (range) {\n            case EQUALS -> runningVersion == expectedVersion;\n            case EQUALS_OR_LOWER -> runningVersion <= expectedVersion;\n            case EQUALS_OR_HIGHER -> runningVersion >= expectedVersion;\n        };\n    }\n\n    private String getMessage(boolean matches, Range range, int runningVersion,\n                              int expectedVersion) {\n        if (matches) {\n            return \"Wicket version matches current: \" + runningVersion + \" \" + range + \" expected: \" + expectedVersion;\n        } else {\n            return \"Wicket version does not match current: \" + runningVersion + \" \" + range + \" expected: \" + expectedVersion;\n        }\n    }\n\n    private String retrieveWicketVersion() {\n\n        String implVersion = null;\n        var pkg = FrameworkSettings.class.getPackage();\n        if (pkg != null) {\n            implVersion = pkg.getImplementationVersion();\n        }\n        return StringUtils.hasLength(implVersion) ? implVersion : \"0\";\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/exceptions/WicketSpringBootException.java",
    "content": "package com.giffing.wicket.spring.boot.context.exceptions;\n\n/**\n * General extension from which all exception should extend\n *\n * @author Marc Giffing\n */\npublic class WicketSpringBootException extends RuntimeException {\n\n    public WicketSpringBootException() {\n        super();\n    }\n\n    public WicketSpringBootException(String message,\n                                     Throwable cause,\n                                     boolean enableSuppression,\n                                     boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n\n    public WicketSpringBootException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public WicketSpringBootException(String message) {\n        super(message);\n    }\n\n    public WicketSpringBootException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/exceptions/extensions/ExtensionMisconfigurationException.java",
    "content": "package com.giffing.wicket.spring.boot.context.exceptions.extensions;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.WicketSpringBootException;\n\n/**\n * This exception should be thrown if a extension misconfiguration is detected.\n * <p>\n * It can e.g. thrown if you detect an extension which configures the same aspect\n * as two serializers\n *\n * @author Marc Giffing\n */\npublic class ExtensionMisconfigurationException extends WicketSpringBootException {\n\n    public ExtensionMisconfigurationException(String message) {\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/ApplicationInitExtension.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\n\n/**\n * To be independent of Springs annotation this annotation was introduced\n * which is a replacement for the {@link Component} annotation.\n * <p>\n * In the future, you may introduce different configuration options.\n *\n * @author Marc Giffing\n */\n@Configuration\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Order(ApplicationInitExtension.DEFAULT_PRECEDENCE)\npublic @interface ApplicationInitExtension {\n\n    int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;\n\n    int DEFAULT_PRECEDENCE = Integer.MAX_VALUE / 2;\n\n    int LOWEST_PRECEDENCE = Integer.MAX_VALUE;\n\n    String value() default \"\";\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/WicketApplicationInitConfiguration.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions;\n\nimport org.apache.wicket.protocol.http.WebApplication;\n\n/**\n * To provide custom modification of the init Method of Wickets {@link WebApplication}\n * class. An extension class should implement this interface. All classes implementing\n * this interface are injected in Wickets starter WicketBootWebApplication class as a list and on\n * each implementation the init method is called with the current {@link WebApplication}.\n * <p>\n * Every Spring Bean regardless to the package location which implements this interface\n * will be considered as an extension. This means that you can write your own extension\n * in a different project. You only have to ensure that the class will picked up by Springs\n * component scan (or other bean configuration possibilities.\n *\n * @author Marc Giffing\n */\npublic interface WicketApplicationInitConfiguration {\n\n    /**\n     * With the given {@link WebApplication} the\n     * {@link WicketApplicationInitConfiguration}s can modify/extend the init()\n     * method of the {@link WebApplication}.\n     *\n     * @param webApplication the current {@link WebApplication}\n     */\n    void init(WebApplication webApplication);\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/boot/actuator/WicketAutoConfig.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions.boot.actuator;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.Collections;\r\nimport java.util.LinkedHashMap;\r\nimport java.util.Map;\r\n\r\nimport lombok.Getter;\r\nimport org.springframework.util.Assert;\r\n\r\n@Getter\r\npublic class WicketAutoConfig implements Serializable {\r\n\r\n\tprivate final String key;\r\n\r\n\tprivate final Map<String, Object> details;\r\n\r\n\tprivate WicketAutoConfig(Builder builder) {\r\n\t\tAssert.notNull(builder, \"Builder must not be null\");\r\n\t\tthis.key = builder.configurationClass != null ? builder.configurationClass.getSimpleName() : null;\r\n\t\tthis.details = Collections.unmodifiableMap(builder.details);\r\n\t}\r\n\r\n\tpublic static class Builder {\r\n\r\n\t\tprivate final Class<?> configurationClass;\r\n\r\n\t\tprivate Map<String, Object> details;\r\n\r\n\t\tpublic Builder() {\r\n\t\t\tthis.configurationClass = null;\r\n\t\t\tthis.details = new LinkedHashMap<>();\r\n\t\t}\r\n\r\n\t\tpublic Builder(Class<?> configurationClass) {\r\n\t\t\tAssert.notNull(configurationClass, \"ConfigurationClass must not be null\");\r\n\t\t\tthis.configurationClass = configurationClass;\r\n\t\t\tthis.details = new LinkedHashMap<>();\r\n\t\t}\r\n\r\n\t\tpublic Builder(Class<?> configurationClass, Map<String, ?> details) {\r\n\t\t\tAssert.notNull(configurationClass, \"ConfigurationClass must not be null\");\r\n\t\t\tAssert.notNull(details, \"Details must not be null\");\r\n\t\t\tthis.configurationClass = configurationClass;\r\n\t\t\tthis.details = new LinkedHashMap<>(details);\r\n\t\t}\r\n\r\n\t\tpublic Builder withDetail(String key, Object value) {\r\n\t\t\tAssert.notNull(key, \"Key must not be null\");\r\n\t\t\tthis.details.put(key, value);\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tpublic WicketAutoConfig build() {\r\n\t\t\treturn new WicketAutoConfig(this);\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/boot/actuator/WicketEndpointRepository.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions.boot.actuator;\r\n\r\nimport java.util.List;\r\n\r\n/**\r\n * This repository can be used to collect Wicket configuration information which can (e.g.) be displayed in\r\n * a Spring Boot Actuator Wicket endpoint.\r\n *\r\n * @author Marc Giffing\r\n */\r\npublic interface WicketEndpointRepository {\r\n\r\n    void add(WicketAutoConfig autoconfig);\r\n\r\n    List<WicketAutoConfig> getConfigs();\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/types/DurationUnit.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions.types;\n\npublic enum DurationUnit {\n\n    MILLISECONDS,\n    SECONDS,\n    MINUTES,\n    HOURS,\n    DAYS,\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/types/SessionUnit.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions.types;\n\npublic enum SessionUnit {\n    BYTES,\n    KILOBYTES,\n    MEGABYTES,\n    TERABYTES\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/extensions/types/TypeParser.java",
    "content": "package com.giffing.wicket.spring.boot.context.extensions.types;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.wicket.util.lang.Bytes;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.WicketSpringBootException;\nimport java.time.Duration;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic class TypeParser {\n\n\tpublic static Bytes parse(Long size, SessionUnit sessionUnit){\n        return switch (sessionUnit) {\n            case BYTES -> Bytes.bytes(size);\n            case KILOBYTES -> Bytes.kilobytes(size);\n            case MEGABYTES -> Bytes.megabytes(size);\n            case TERABYTES -> Bytes.terabytes(size);\n        };\n    }\n\t\n\tpublic static Duration parse(Long time, DurationUnit durationUnit){\n        return switch (durationUnit) {\n            case DAYS -> Duration.ofDays(time);\n            case HOURS -> Duration.ofHours(time);\n            case MILLISECONDS -> Duration.ofMillis(time);\n            case MINUTES -> Duration.ofMinutes(time);\n            case SECONDS -> Duration.ofSeconds(time);\n        };\n\n    }\n\t\n\t\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/scan/WicketAccessDeniedPage.java",
    "content": "package com.giffing.wicket.spring.boot.context.scan;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.settings.ApplicationSettings;\n\n/**\n * This annotation can be used to mark a {@link Page} which will automatically configured\n * as the access denied page in the {@link ApplicationSettings}.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface WicketAccessDeniedPage {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/scan/WicketExpiredPage.java",
    "content": "package com.giffing.wicket.spring.boot.context.scan;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.settings.ApplicationSettings;\n\n/**\n * This annotation can be used to mark a {@link Page} which will automatically configured\n * as the page expired error page in the {@link ApplicationSettings}.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface WicketExpiredPage {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/scan/WicketHomePage.java",
    "content": "package com.giffing.wicket.spring.boot.context.scan;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.protocol.http.WebApplication;\n\n/**\n * Should be used to mark the home page which should automatically configures in the {@link WebApplication}.\n * Only one {@link Page} should be marked with this annotation.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface WicketHomePage {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/scan/WicketInternalErrorPage.java",
    "content": "package com.giffing.wicket.spring.boot.context.scan;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.settings.ApplicationSettings;\n\n/**\n * This annotation can be used to mark a {@link Page} which will automatically configured\n * as the internal error page in the {@link ApplicationSettings}.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface WicketInternalErrorPage {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/scan/WicketSignInPage.java",
    "content": "package com.giffing.wicket.spring.boot.context.scan;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.protocol.http.WebApplication;\n\n/**\n * Should be used to mark the sign-in page which should be automatically configured in the {@link WebApplication} class.\n * Only one {@link Page} should be marked with this annotation.\n *\n * @author Marc Giffing\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface WicketSignInPage {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-context/src/main/java/com/giffing/wicket/spring/boot/context/security/AuthenticatedWebSessionConfig.java",
    "content": "package com.giffing.wicket.spring.boot.context.security;\n\nimport org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;\nimport org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;\n\n/**\n * Enables the dynamic configuration of the {@link AbstractAuthenticatedWebSession} for the\n * {@link AuthenticatedWebApplication}. E.g. if spring security is present it provides a default WebSession\n * configuration.\n * <p>\n * Security providers should provide different implementations.\n *\n * @author Marc Giffing\n */\npublic interface AuthenticatedWebSessionConfig {\n\n    Class<? extends AbstractAuthenticatedWebSession> getAuthenticatedWebSessionClass();\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/.gitignore",
    "content": "/target/\n/.settings/\n/.classpath\n.project\n/.apt_generated/\n.factorypath"
  },
  {
    "path": "wicket-spring-boot-starter/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\n\t\t<artifactId>wicket-spring-boot-starter-parent</artifactId>\n\t\t<version>4.1.1</version>\n\t\t<relativePath>..</relativePath>\n\t</parent>\n\n\t<artifactId>wicket-spring-boot-starter</artifactId>\n\t<name>Wicket Spring Boot Starter</name>\n\t<description>\n                Enables and configures Apache Wicket from within a Spring Boot\n                Application. Used **only** in combination with Spring Boot.\n\t</description>\n\n\t<dependencies>\n\n\t\t<!-- Internal -->\n\n\t\t<dependency>\n\t\t\t<groupId>com.giffing.wicket.spring.boot.starter</groupId>\n\t\t\t<artifactId>wicket-spring-boot-context</artifactId>\n\t\t</dependency>\n\n\t\t<!-- Spring -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-autoconfigure</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-security</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-actuator</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- Wicket -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-auth-roles</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-ioc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-spring</artifactId>\n\t\t</dependency>\n\n\t\t<!-- The following modules are *not* linked. They are used from the starters \n\t\t\tconditional configuration (if a module exists, then some comfiguration is \n\t\t\tapplied). -->\n\n\t\t<!-- Wicketstuff -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-annotation</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-htmlcompressor</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-serializer-kryo2</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-serializer-fast2</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-bean-validation</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-restannotations</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-springreference</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-shiro</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.shiro</groupId>\n\t\t\t<artifactId>shiro-spring-boot-web-starter</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-jamon</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- Wicket Deployment -->\n\n\t\t<dependency>\n\t\t\t<groupId>de.agilecoders.wicket.webjars</groupId>\n\t\t\t<artifactId>wicket-webjars</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- Wicket Datastore -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-datastore-cassandra</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-datastore-hazelcast</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-datastore-memcached</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.wicketstuff</groupId>\n\t\t\t<artifactId>wicketstuff-datastore-redis</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- Wicket Websockets -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-native-websocket-javax</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- Wicket / Spring Development -->\n\n\t\t<dependency>\n\t\t\t<groupId>com.github.jennybrown8.wicket-source</groupId>\n\t\t\t<artifactId>wicket-source</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.wicket</groupId>\n\t\t\t<artifactId>wicket-devutils</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<resources>\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/resources</directory>\n\t\t\t</resource>\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/java</directory>\n\t\t\t\t<includes>\n\t\t\t\t\t<include>**</include>\n\t\t\t\t</includes>\n\t\t\t\t<excludes>\n\t\t\t\t\t<exclude>**/*.java</exclude>\n\t\t\t\t</excludes>\n\t\t\t</resource>\n\t\t</resources>\n\n\t</build>\n\n</project>\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/WicketAutoConfiguration.java",
    "content": "package com.giffing.wicket.spring.boot.starter;\n\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.ClassCandidateScannerConfiguration;\nimport com.giffing.wicket.spring.boot.starter.app.verifier.WicketDependencyVersionChecker;\nimport com.giffing.wicket.spring.boot.starter.configuration.CustomAnnotationBeanNameGenerator;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.WicketExtensionLocation;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general.GeneralSettingsProperties;\nimport com.giffing.wicket.spring.boot.starter.web.WicketWebInitializer;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * The main starter configuration class which will be called by spring.\n * The class is configured in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports\n *\n * @author Marc Giffing\n */\n@Configuration\n@Import({\n        WicketDependencyVersionChecker.class,\n        ClassCandidateScannerConfiguration.class,\n        WicketBootWebApplicationAutoConfiguration.class,\n        WicketWebInitializer.class\n})\n@EnableConfigurationProperties({GeneralSettingsProperties.class})\n@ComponentScan(basePackageClasses = WicketExtensionLocation.class, nameGenerator = CustomAnnotationBeanNameGenerator.class)\npublic class WicketAutoConfiguration {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/WicketBootWebApplicationAutoConfiguration.java",
    "content": "package com.giffing.wicket.spring.boot.starter;\n\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootSecuredWebApplication;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootStandardWebApplication;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configures the standard {@link WicketBootWebApplication} configuration\n * without security options.\n * <p>\n * The {@link WicketBootStandardWebApplication} will only be activated if there\n * is no other {@link WicketBootWebApplication} present and if there is not\n * {@link WicketBootSecuredWebApplication} present.\n *\n * @author Marc Giffing\n */\n@Configuration\n@ConditionalOnMissingBean({WicketBootSecuredWebApplication.class, WicketBootWebApplication.class})\npublic class WicketBootWebApplicationAutoConfiguration {\n\n    @Bean\n    public WicketBootStandardWebApplication wicketBootWebApplication() {\n        return new WicketBootStandardWebApplication();\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/WicketBootSecuredWebApplication.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.wicket.Page;\nimport org.apache.wicket.RuntimeConfigurationType;\nimport org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;\nimport org.apache.wicket.authroles.authentication.AuthenticatedWebApplication;\nimport org.apache.wicket.markup.html.WebPage;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.apache.wicket.spring.injection.annot.SpringComponentInjector;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\n\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.scan.WicketHomePage;\nimport com.giffing.wicket.spring.boot.context.scan.WicketSignInPage;\nimport com.giffing.wicket.spring.boot.context.security.AuthenticatedWebSessionConfig;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidate;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general.GeneralSettingsProperties;\n\n/**\n * Default Wicket Application which should be subclassed by framework clients to\n * enable autoconfiguration with help of Spring Boot.\n * \n * It automatically configures the {@link SpringComponentInjector} to \n * enable injection of Spring components via the {@link SpringBean} annotation.\n * \n * Beside Springs injection support it also automatically enables security support.\n * You also have to add a security provider like Spring Security (@link SpringSecurityConfig)\n * or Apache shiro. \n * \n * To initialize the application in an decoupled way a list of {@link WicketApplicationInitConfiguration}\n * is injected as a list in this class. Each configuration item will be called in the init method.\n * \n * @author Marc Giffing\n *\n */\n@RequiredArgsConstructor\n@Slf4j\npublic class WicketBootSecuredWebApplication extends AuthenticatedWebApplication implements WicketBootWebApplication {\n\n\t@Autowired\n\t@Getter\n\tprivate ApplicationContext applicationContext;\n\t\n\t@Autowired\n\t@Getter\n\tprivate GeneralSettingsProperties generalSettingsProperties;\n\n\t/**\n\t * Injects all active extension which matches the predefined conditions. May be empty\n\t * if no extension matches the given preconditions.\n\t */\n\t@Autowired\n\t@Getter\n\tprivate List<WicketApplicationInitConfiguration> configurations = new ArrayList<>();\n\t\n\t@Autowired\n\tprivate WicketClassCandidatesHolder classCandidates;\n\t\n\t@Autowired\n\tprivate WicketEndpointRepository wicketEndpointRepository;\n\t\n\t@Override\n\tprotected void init() {\n\t\tsuper.init();\n\t    \n\t\tgetComponentInstantiationListeners().add(new SpringComponentInjector(this, applicationContext));\n\t\t\n\t\tWicketAutoConfig.Builder builder = new WicketAutoConfig.Builder(this.getClass());\n\t\twicketEndpointRepository.add(builder\n\t\t\t\t.withDetail(\"signInPages\", classCandidates.getSignInPageCandidates())\n\t\t\t\t.withDetail(\"homePages\", classCandidates.getHomePageCandidates())\n\t\t\t\t.build());\n\t\t\n\t\tfor (WicketApplicationInitConfiguration configuration : configurations) {\n\t\t\tlog.info(\"init-config: {}\", configuration.getClass().getName());\n\t\t\tconfiguration.init(this);\n\t\t}\n\t\t\n\t}\n\t\n\t@Override\n\tpublic RuntimeConfigurationType getConfigurationType() {\n\t\treturn generalSettingsProperties.getConfigurationType();\n\t}\n\t\n\t@Override\n\tprotected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {\n\t\treturn applicationContext.getBean(AuthenticatedWebSessionConfig.class).getAuthenticatedWebSessionClass();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tprotected Class<? extends WebPage> getSignInPageClass() {\n\t\tif(classCandidates.getSignInPageCandidates().isEmpty()){\n\t\t\tthrow new IllegalStateException(\"Couldn't find sign in page - please annotate the sign in page with @\" + WicketSignInPage.class.getName());\n\t\t}\n\t\tif(classCandidates.getSignInPageCandidates().size() > 1 ){\n\t\t\tString message = \"Multiple sign in pages found - please annotate exactly one class with @\" + WicketSignInPage.class.getName();\n\t\t\tmessage += \"\\n\";\n\t\t\tfor (WicketClassCandidate<WebPage> classCandidate : classCandidates.getSignInPageCandidates()) {\n\t\t\t\tmessage += \"\\t\" + classCandidate.getCandidate() + \"\\n\";\n\t\t\t}\n\t\t\tthrow new IllegalStateException(message);\n\t\t}\n\n\t\treturn classCandidates.getSignInPageCandidates().iterator().next().getCandidate();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic Class<? extends Page> getHomePage() {\n\t\tif(classCandidates.getHomePageCandidates().isEmpty()){\n\t\t\tthrow new IllegalStateException(\"Couldn't find home page - please annotate the home page with @\" + WicketHomePage.class.getName());\n\t\t}\n\t\tif(classCandidates.getHomePageCandidates().size() > 1 ){\n\t\t\tString message = \"Multiple home pages found - please annotate exactly one class with @\" + WicketHomePage.class.getName();\n\t\t\tmessage += \"\\n\";\n\t\t\tfor(WicketClassCandidate<Page> classCandidate : classCandidates.getHomePageCandidates()) {\n\t\t\t\tmessage += \"\\t\" + classCandidate.getCandidate() + \"\\n\";\n\t\t\t}\n\t\t\tthrow new IllegalStateException(message);\n\t\t}\n\n\t\treturn classCandidates.getHomePageCandidates().iterator().next().getCandidate();\n\t}\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/WicketBootStandardWebApplication.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.wicket.Page;\nimport org.apache.wicket.RuntimeConfigurationType;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.apache.wicket.spring.injection.annot.SpringComponentInjector;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Lazy;\n\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.scan.WicketHomePage;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidate;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general.GeneralSettingsProperties;\n\n/**\n * Default Wicket Application which should be subclassed by framework clients to\n * enable autoconfiguration with help of Spring Boot.\n * \n * It automatically configures the {@link SpringComponentInjector} to \n * enable injection of Spring components via the {@link SpringBean} annotation.\n * \n * To initialize the application in an decoupled way a list of {@link WicketApplicationInitConfiguration}\n * is injected as a list in this class. Each configuration item will be called in the init method.\n * \n * @author Marc Giffing\n *\n */\n@Lazy\n@Slf4j\npublic class WicketBootStandardWebApplication extends WebApplication implements WicketBootWebApplication {\n\n\t@Autowired\n\t@Getter\n\tprivate ApplicationContext applicationContext;\n\t\n\t@Autowired\n\t@Getter\n\tprivate GeneralSettingsProperties generalSettingsProperties;\n\t\n\t/**\n\t * Injects all active extension which matches the predefined conditions. May be empty\n\t * if no extension matches the given preconditions.\n\t */\n\t@Autowired(required = false)\n\t@Getter\n\tprivate List<WicketApplicationInitConfiguration> configurations = new ArrayList<>();\n\t\n\t@Autowired\n\t@Getter\n\tprivate WicketClassCandidatesHolder classCandidates;\n\t\n\t@Autowired\n\tprivate WicketEndpointRepository wicketEndpointRepository;\n\t\n\t@Override\n\tprotected void init() {\n\t\tsuper.init();\n\t    \n\t\tgetComponentInstantiationListeners().add(new SpringComponentInjector(this, applicationContext));\n\t\t\n\t\tWicketAutoConfig.Builder builder = new WicketAutoConfig.Builder(this.getClass());\n\t\twicketEndpointRepository.add(builder\n\t\t\t\t.withDetail(\"signInPages\", classCandidates.getSignInPageCandidates())\n\t\t\t\t.withDetail(\"homePages\", classCandidates.getHomePageCandidates())\n\t\t\t\t.build());\n\t\t\n\t\tfor (WicketApplicationInitConfiguration configuration : configurations) {\n\t\t\tlog.info(\"init-config: {}\", configuration.getClass().getName());\n\t\t\tconfiguration.init(this);\n\t\t}\n\t\t\n\t}\n\t\n\t@Override\n\tpublic RuntimeConfigurationType getConfigurationType() {\n\t\treturn generalSettingsProperties.getConfigurationType();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic Class<? extends Page> getHomePage() {\n\t\tif(classCandidates.getHomePageCandidates().isEmpty()){\n\t\t\tthrow new IllegalStateException(\"Couldn't find home page - please annotate the home page with @\" + WicketHomePage.class.getName());\n\t\t}\n\t\tif(classCandidates.getHomePageCandidates().size() > 1 ){\n\t\t\tStringBuilder message = new StringBuilder(\"Multiple home pages found - please annotate exactly one class with @\" + WicketHomePage.class.getName());\n\t\t\tmessage.append(\"\\n\");\n\t\t\tfor(var classCandidate : classCandidates.getHomePageCandidates()) {\n\t\t\t\tmessage.append(\"\\t\").append(classCandidate.getCandidate()).append(\"\\n\");\n\t\t\t}\n\t\t\tthrow new IllegalStateException(message.toString());\n\t\t}\n\n\t\treturn classCandidates.getHomePageCandidates().iterator().next().getCandidate();\n\t}\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/WicketBootWebApplication.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app;\n\nimport org.apache.wicket.protocol.http.WebApplication;\n\nimport com.giffing.wicket.spring.boot.starter.web.WicketWebInitializer;\n\n/**\n * All Wicket Spring Boot Starter {@link WebApplication} classes should\n * implement this interface to access the current configures\n * {@link WebApplication} bean within spring.\n * <p>\n * Look at {@link WicketWebInitializer} to see the dynamical retrieval of the\n * bean name with use of this interface.\n *\n * @author Marc Giffing\n */\npublic interface WicketBootWebApplication {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/classscanner/ClassCandidateScanner.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.classscanner;\r\n\r\nimport com.giffing.wicket.spring.boot.context.scan.*;\r\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidate;\r\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.Page;\r\nimport org.apache.wicket.markup.html.WebPage;\r\nimport org.springframework.beans.factory.BeanFactory;\r\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\r\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\r\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\r\nimport org.springframework.core.env.Environment;\r\nimport org.springframework.core.io.ResourceLoader;\r\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\r\nimport org.springframework.util.ClassUtils;\r\nimport org.springframework.util.StringUtils;\r\n\r\nimport java.util.Collection;\r\nimport java.util.Collections;\r\n\r\n/**\r\n * The candidate class scanner is used to find class with special annotations.\r\n *\r\n * @author Marc Giffing\r\n */\r\n@RequiredArgsConstructor\r\npublic class ClassCandidateScanner {\r\n\r\n    private final Environment environment;\r\n    private final ResourceLoader resourceLoader;\r\n    private final BeanFactory beanFactory;\r\n    private final ClassLoader classLoader;\r\n    private final WicketClassCandidatesHolder classCandidates;\r\n\r\n    public void postConstruct() {\r\n        var scanner = new ClassPathScanningCandidateComponentProvider(false);\r\n        scanner.setEnvironment(this.environment);\r\n        scanner.setResourceLoader(this.resourceLoader);\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(SpringBootApplication.class));\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(WicketHomePage.class));\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(WicketSignInPage.class));\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(WicketAccessDeniedPage.class));\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(WicketExpiredPage.class));\r\n        scanner.addIncludeFilter(new AnnotationTypeFilter(WicketInternalErrorPage.class));\r\n        for (var basePackage : getMappingBasePackages(beanFactory)) {\r\n            if (StringUtils.hasText(basePackage)) {\r\n                classCandidates.getBasePackages().add(basePackage);\r\n                var beanDefinitions = scanner.findCandidateComponents(basePackage);\r\n                for (var beanDefinition : beanDefinitions) {\r\n                    Class<?> beanClass;\r\n                    try {\r\n                        beanClass = ClassUtils.forName(beanDefinition.getBeanClassName(), classLoader);\r\n                    } catch (ClassNotFoundException e) {\r\n                        throw new IllegalStateException(e);\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(WicketHomePage.class)) {\r\n                        classCandidates.getHomePageCandidates()\r\n                                .add(new WicketClassCandidate<>((Class<Page>) beanClass));\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(WicketSignInPage.class)) {\r\n                        classCandidates.getSignInPageCandidates()\r\n                                .add(new WicketClassCandidate<>((Class<WebPage>) beanClass));\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(WicketAccessDeniedPage.class)) {\r\n                        classCandidates.getAccessDeniedPageCandidates()\r\n                                .add(new WicketClassCandidate<>((Class<Page>) beanClass));\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(WicketExpiredPage.class)) {\r\n                        classCandidates.getExpiredPageCandidates()\r\n                                .add(new WicketClassCandidate<>((Class<Page>) beanClass));\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(WicketInternalErrorPage.class)) {\r\n                        classCandidates.getInternalErrorPageCandidates()\r\n                                .add(new WicketClassCandidate<>((Class<Page>) beanClass));\r\n                    }\r\n                    if (beanClass.isAnnotationPresent(SpringBootApplication.class)) {\r\n                        classCandidates.setSpringBootMainClass(beanClass);\r\n                    }\r\n                }\r\n\r\n            }\r\n        }\r\n    }\r\n\r\n    private static Collection<String> getMappingBasePackages(BeanFactory beanFactory) {\r\n        try {\r\n            return AutoConfigurationPackages.get(beanFactory);\r\n        } catch (IllegalStateException ex) {\r\n            // no auto-configuration package registered yet\r\n            return Collections.emptyList();\r\n        }\r\n    }\r\n\r\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/classscanner/ClassCandidateScannerConfiguration.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.classscanner;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\n\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\n\n@Configuration\n@RequiredArgsConstructor\npublic class ClassCandidateScannerConfiguration {\n\n    private final Environment environment;\n\n    private final ResourceLoader resourceLoader;\n\n    private final BeanFactory beanFactory;\n\n    @Bean\n    public WicketClassCandidatesHolder pageCandidates() {\n        var result = new WicketClassCandidatesHolder();\n        // TODO Why is the ClassCandidateScanner initialized?\n        new ClassCandidateScanner(environment,\n                resourceLoader,\n                beanFactory,\n                getClass().getClassLoader(),\n                result)\n                .postConstruct();\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/classscanner/candidates/WicketClassCandidate.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.classscanner.candidates;\n\nimport java.lang.ref.WeakReference;\n\n/**\n * @param <T> candidate class type\n * @author Marc Giffing\n */\npublic class WicketClassCandidate<T> {\n\n    private WeakReference<Class<T>> candidate;\n\n    public WicketClassCandidate(Class<T> candidate) {\n        this.candidate = new WeakReference<>(candidate);\n    }\n\n    public Class<T> getCandidate() {\n        return candidate.get();\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/classscanner/candidates/WicketClassCandidatesHolder.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.classscanner.candidates;\r\n\r\nimport java.util.HashSet;\r\nimport java.util.Set;\r\n\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\nimport org.apache.wicket.Page;\r\nimport org.apache.wicket.markup.html.WebPage;\r\n\r\n/**\r\n * Holds class candidates which should be configured in Wicket.\r\n * It holds e.g. home page classes which should be configured in Wicket.\r\n * \r\n * @author Marc Giffing\r\n *\r\n */\r\n@Getter\r\n@Setter\r\npublic class WicketClassCandidatesHolder {\r\n\t\r\n\tprivate Set<String> basePackages = new HashSet<>();\r\n\t\r\n\tprivate Class<?> springBootMainClass = null;\r\n\t\r\n\tprivate Set<WicketClassCandidate<Page>> homePageCandidates = new HashSet<>();\r\n\t\r\n\tprivate Set<WicketClassCandidate<WebPage>> signInPageCandidates = new HashSet<>();\r\n\t\r\n\tprivate Set<WicketClassCandidate<Page>> accessDeniedPageCandidates = new HashSet<>();\r\n\t\r\n\tprivate Set<WicketClassCandidate<Page>> expiredPageCandidates = new HashSet<>();\r\n\t\r\n\tprivate Set<WicketClassCandidate<Page>> internalErrorPageCandidates = new HashSet<>();\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/verifier/WicketDependencyMismatchDetectedException.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.verifier;\r\n\r\nimport com.giffing.wicket.spring.boot.starter.app.verifier.WicketDependencyVersionChecker.MavenDependency;\r\nimport lombok.Getter;\r\nimport lombok.RequiredArgsConstructor;\r\n\r\nimport java.util.List;\r\n\r\n/**\r\n * Should  be thrown if the version of wicket dependencies doesn't match the core dependency version\r\n *\r\n * @author Marc Giffing\r\n */\r\n@Getter\r\n@RequiredArgsConstructor\r\npublic class WicketDependencyMismatchDetectedException extends RuntimeException {\r\n\r\n    private final String wicketCoreVersion;\r\n\r\n    private final List<MavenDependency> dependencies;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/verifier/WicketDependencyVersionChecker.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.verifier;\r\n\r\nimport java.io.IOException;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Optional;\r\nimport java.util.Properties;\r\nimport java.util.concurrent.atomic.AtomicBoolean;\r\n\r\nimport jakarta.annotation.PostConstruct;\r\n\r\nimport lombok.RequiredArgsConstructor;\r\nimport lombok.extern.slf4j.Slf4j;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\r\nimport org.springframework.context.ResourceLoaderAware;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.core.io.Resource;\r\nimport org.springframework.core.io.ResourceLoader;\r\nimport org.springframework.core.io.support.ResourcePatternResolver;\r\nimport org.springframework.core.io.support.ResourcePatternUtils;\r\n\r\n@Configuration\r\n@ConditionalOnProperty(prefix = WicketDependencyVersionCheckerProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\r\n@EnableConfigurationProperties({WicketDependencyVersionCheckerProperties.class})\r\n@Slf4j\r\npublic class WicketDependencyVersionChecker implements ResourceLoaderAware {\r\n\r\n    private static final String DEFAULT_RESOURCE_PATTERN = \"/META-INF/maven/**/pom.properties\";\r\n\r\n    private static final String WICKETSTUFF_GROUPID = \"org.wicketstuff\";\r\n\r\n    private static final String WICKET_JQUERYUI_GROUPID = \"com.googlecode.wicket-jquery-ui\";\r\n\r\n    private static final String WICKET_CORE_GROUPID = \"org.apache.wicket\";\r\n\r\n    private ResourcePatternResolver resourcePatternResolver;\r\n\r\n    private final WicketDependencyVersionCheckerProperties props;\r\n\r\n    @Autowired\r\n    public WicketDependencyVersionChecker(WicketDependencyVersionCheckerProperties props) {\r\n        this.props = props;\r\n    }\r\n\r\n    @Override\r\n    public void setResourceLoader(ResourceLoader resourceLoader) {\r\n        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);\r\n    }\r\n\r\n    @PostConstruct\r\n    public void detectWicketDependencyVersionMismatch() {\r\n        var wicketMavenDependencies = collectWicketMavenDependencies();\r\n\r\n        List<MavenDependency> mismatchVersionDependencies = new ArrayList<>();\r\n        var versionMismatchFound = new AtomicBoolean(false);\r\n        Optional<String> wicketCoreVersionOpt = findWicketCoreVersion(wicketMavenDependencies);\r\n        wicketCoreVersionOpt.ifPresent(wicketCoreVersion -> {\r\n            for (var mavenDependency : wicketMavenDependencies) {\r\n                if (mavenDependency.groupId.equals(WICKET_CORE_GROUPID)\r\n                        && !mavenDependency.version.equals(wicketCoreVersion)) {\r\n                    log.error(\"########## INVALID WICKET VERSION DETECTED - CORE: {} - DEPENDENCY: {}\",\r\n                            wicketCoreVersion, mavenDependency);\r\n                    versionMismatchFound.set(true);\r\n                    mismatchVersionDependencies.add(mavenDependency);\r\n                } else if (mavenDependency.groupId.equals(WICKETSTUFF_GROUPID) || mavenDependency.groupId.equals(WICKET_JQUERYUI_GROUPID)) {\r\n                    var majorWicketCoreVersion = wicketCoreVersion.substring(0, wicketCoreVersion.indexOf('.'));\r\n                    var majorMavenDependencyVersion = mavenDependency.version.substring(0, mavenDependency.version.indexOf('.'));\r\n                    if (!majorWicketCoreVersion.equals(majorMavenDependencyVersion)) {\r\n                        log.error(\"########## INVALID {} MAJOR VERSION DETECTED - WICKET: {} - DEPENDENCY: {}\",\r\n                                mavenDependency.groupId, majorWicketCoreVersion, majorMavenDependencyVersion);\r\n                        versionMismatchFound.set(true);\r\n                        mismatchVersionDependencies.add(mavenDependency);\r\n                    }\r\n                }\r\n\r\n            }\r\n        });\r\n\r\n\r\n        if (versionMismatchFound.get() && props.isThrowExceptionOnDependencyVersionMismatch()) {\r\n            throw new WicketDependencyMismatchDetectedException(wicketCoreVersionOpt.orElse(\"unknown\"), mismatchVersionDependencies);\r\n        }\r\n\r\n    }\r\n\r\n    private Optional<String> findWicketCoreVersion(List<MavenDependency> wicketMavenDependencies) {\r\n        for (var wicketMavenDependency : wicketMavenDependencies) {\r\n            if (wicketMavenDependency.groupId.equals(WICKET_CORE_GROUPID) && wicketMavenDependency.artifactId.equals(\"wicket-core\")) {\r\n                return Optional.of(wicketMavenDependency.version);\r\n            }\r\n        }\r\n        return Optional.empty();\r\n    }\r\n\r\n    private List<MavenDependency> collectWicketMavenDependencies() {\r\n        var packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + DEFAULT_RESOURCE_PATTERN;\r\n        try {\r\n            var resources = this.resourcePatternResolver.getResources(packageSearchPath);\r\n            return collectWicketMavenDependencies(resources);\r\n        } catch (IOException e) {\r\n            // do not throw checked exception in @PostConstruct method to provide better JavaEE compatibility\r\n            throw new IllegalStateException(e);\r\n        }\r\n    }\r\n\r\n    private List<MavenDependency> collectWicketMavenDependencies(Resource[] resources) throws IOException {\r\n        List<MavenDependency> wicketMavenDependencies = new ArrayList<>();\r\n        for (var resource : resources) {\r\n            if (resource.isReadable()\r\n                    && resource.getURL().getPath().contains(\"wicket\")) {\r\n\r\n                var props = new Properties();\r\n                props.load(resource.getInputStream());\r\n                var groupId = (String) props.get(\"groupId\");\r\n                var artifactId = (String) props.get(\"artifactId\");\r\n                var version = (String) props.get(\"version\");\r\n\r\n                wicketMavenDependencies.add(new MavenDependency(groupId, artifactId, version));\r\n            }\r\n        }\r\n        return wicketMavenDependencies;\r\n    }\r\n\r\n    @RequiredArgsConstructor\r\n    public static class MavenDependency {\r\n        public final String groupId;\r\n        public final String artifactId;\r\n        public final String version;\r\n\r\n        @Override\r\n        public String toString() {\r\n            return groupId + \":\" + artifactId + \":\" + version;\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/verifier/WicketDependencyVersionCheckerFailureAnalyzer.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.verifier;\r\n\r\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\r\nimport org.springframework.boot.diagnostics.FailureAnalysis;\r\n\r\nimport com.giffing.wicket.spring.boot.starter.app.verifier.WicketDependencyVersionChecker.MavenDependency;\r\n\r\npublic class WicketDependencyVersionCheckerFailureAnalyzer extends AbstractFailureAnalyzer<WicketDependencyMismatchDetectedException> {\r\n\r\n    @Override\r\n    protected FailureAnalysis analyze(Throwable rootFailure, WicketDependencyMismatchDetectedException cause) {\r\n        var descriptionMessage = new StringBuilder(\"One or more Wicket dependencies (jars) doesn't match the wicket-core dependency.\\n\\r\"\r\n                + \"Wicket Core Version: %s%s\".formatted(cause.getWicketCoreVersion(), System.lineSeparator()));\r\n        for (MavenDependency dependency : cause.getDependencies()) {\r\n            descriptionMessage.append(\"\\t\").append(dependency).append(System.lineSeparator());\r\n        }\r\n\r\n        String actionMessage = \"\"\"\r\n                Please check the Wicket versions configured in your dependency management system (Maven, Gradle, ...)\r\n                You can disable this check via the property:\r\n                \\twicket.verifier.dependencies.enabled=false.\r\n                You can prevent throwing the exception but still log the detected problems via the property:\r\n                \\twicket.verifier.dependencies.throw-exception-on-dependency-version-mismatch=false\"\"\";\r\n\r\n        return new FailureAnalysis(descriptionMessage.toString(), actionMessage, cause);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/app/verifier/WicketDependencyVersionCheckerProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.app.verifier;\r\n\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n\r\n@ConfigurationProperties(prefix = WicketDependencyVersionCheckerProperties.PROPERTY_PREFIX)\r\n@Getter\r\n@Setter\r\npublic class WicketDependencyVersionCheckerProperties {\r\n\r\n    public static final String PROPERTY_PREFIX = \"wicket.verifier.dependencies\";\r\n\r\n    private boolean enabled = true;\r\n\r\n    private boolean throwExceptionOnDependencyVersionMismatch = true;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/CustomAnnotationBeanNameGenerator.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.AnnotationBeanNameGenerator;\nimport org.springframework.util.StringUtils;\n\n/**\n * To prevent spring bean naming clashes with user defined beans we will\n * prefix each bean name with wicketextension and capitalize the from spring\n * generated bean name.\n *\n * @author Marc Giffing\n */\npublic class CustomAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {\n\n    @Override\n    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {\n        return \"wicketextension\" + StringUtils.capitalize(super.generateBeanName(definition, registry));\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/WicketExtensionLocation.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions;\n\n/**\n * Marker interface to locate the Wicket Extensions.\n * This class is used for Springs component scanning.\n *\n * @author Marc Giffing\n */\npublic interface WicketExtensionLocation {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/csrf/CsrfAttacksPreventionConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.csrf;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\r\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.protocol.http.FetchMetadataResourceIsolationPolicy;\r\nimport org.apache.wicket.protocol.http.OriginResourceIsolationPolicy;\r\nimport org.apache.wicket.protocol.http.ResourceIsolationRequestCycleListener;\r\nimport org.apache.wicket.protocol.http.WebApplication;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\r\n\r\n\r\n/**\r\n * Enables CSRF protection if the following condition matches.\r\n * <p>\r\n * 1. The {@link ResourceIsolationRequestCycleListener} class is in the classpath.\r\n * <p>\r\n * 2. The property {@link CsrfAttacksPreventionProperties#PROPERTY_PREFIX}.enabled has to be true (default = true)\r\n * <p>\r\n * The protection should be enabled by default cause the {@link ResourceIsolationRequestCycleListener} is located\r\n * in Wickets core project.\r\n *\r\n * @author Marc Giffing\r\n */\r\n@ApplicationInitExtension\r\n@ConditionalOnProperty(prefix = CsrfAttacksPreventionProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\r\n@ConditionalOnClass(value = org.apache.wicket.protocol.http.ResourceIsolationRequestCycleListener.class)\r\n@EnableConfigurationProperties({CsrfAttacksPreventionProperties.class})\r\n@RequiredArgsConstructor\r\npublic class CsrfAttacksPreventionConfig implements WicketApplicationInitConfiguration {\r\n\r\n    private final CsrfAttacksPreventionProperties props;\r\n\r\n    private final WicketEndpointRepository wicketEndpointRepository;\r\n\r\n    @Override\r\n    public void init(WebApplication webApplication) {\r\n        var originResourceIsolationPolicy = new OriginResourceIsolationPolicy();\r\n        props.getAcceptedOrigins().forEach(originResourceIsolationPolicy::addAcceptedOrigin);\r\n\r\n        var listener = new ResourceIsolationRequestCycleListener(\r\n                new FetchMetadataResourceIsolationPolicy(),\r\n                originResourceIsolationPolicy);\r\n        listener.setUnknownOutcomeAction(props.getUnknownOutcomeAction());\r\n        listener.setDisallowedOutcomeAction(props.getDisallowedOutcomeAction());\r\n        listener.setErrorCode(props.getErrorCode());\r\n        listener.setErrorMessage(props.getErrorMessage());\r\n        webApplication.getRequestCycleListeners().add(listener);\r\n\r\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\r\n                .withDetail(\"properties\", props)\r\n                .build());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/csrf/CsrfAttacksPreventionProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.csrf;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.protocol.http.ResourceIsolationRequestCycleListener.CsrfAction;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = CsrfAttacksPreventionProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class CsrfAttacksPreventionProperties {\n\t\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.csrf\";\n\t\n\t/**\n\t * Action to perform when a request is disallowed by a resource isolation policy.\n\t * Default is {@link CsrfAction#ABORT}.\n\t */\n\tprivate CsrfAction disallowedOutcomeAction = CsrfAction.ABORT;\n\n\t/**\n\t * Action to perform when none of the resource isolation policies can come to an outcome.\n\t * Default is {@link CsrfAction#ABORT}.\n\t */\n\tprivate CsrfAction unknownOutcomeAction = CsrfAction.ABORT;\n\n\t/**\n\t * The error code to report when the action to take for a CSRF request is\n\t * {@link CsrfAction#ABORT}. Default {@code 400 BAD REQUEST}.\n\t */\n\tprivate int errorCode = jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;\n\n\t/**\n\t * The error message to report when the action to take for a CSRF request is {@code ERROR}.\n\t * Default {@code \"Origin does not correspond to request\"}.\n\t */\n\tprivate String errorMessage = \"Origin does not correspond to request\";\n\n\t/**\n\t * A white list of accepted origins (host names/domain names) presented as\n\t * &lt;domainname&gt;.&lt;TLD&gt;. The domain part can contain subdomains.\n\t */\n\tprivate List<String> acceptedOrigins = new ArrayList<>();\n\t\n\t/**\n\t * Enables Wickets CSRF protection\n\t */\n\tprivate boolean enabled = true;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/datastore/DataStoreHttpSessionConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.datastore;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.DefaultPageManagerProvider;\nimport org.apache.wicket.pageStore.IPageStore;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.shiro.wicket.page.store.SessionPageStore;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DataStoreHttpSessionProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({DataStoreHttpSessionProperties.class})\n@RequiredArgsConstructor\npublic class DataStoreHttpSessionConfig implements WicketApplicationInitConfiguration {\n\n    private final DataStoreHttpSessionProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n\n        webApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\n            @Override\n            protected IPageStore newPersistentStore() {\n                return new SessionPageStore(webApplication.getName(), props.getPagesNumber());\n            }\n        });\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/datastore/DataStoreHttpSessionProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.datastore;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = DataStoreHttpSessionProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DataStoreHttpSessionProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.datastore.httpsession\";\n\n    private boolean enabled = true;\n\n    /**\n     * the maximum number of pages the data store can hold\n     */\n    private int pagesNumber = 20;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/requestmapper/CryptMapperConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.requestmapper;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.core.request.mapper.CryptoMapper;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.core.annotation.Order;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = CryptMapperProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({ CryptMapperProperties.class })\n@Order(ApplicationInitExtension.DEFAULT_PRECEDENCE + 100)\n@RequiredArgsConstructor\npublic class CryptMapperConfig implements WicketApplicationInitConfiguration {\n\t\n\tprivate final CryptMapperProperties props;\n\n\tprivate final WicketEndpointRepository wicketEndpointRepository;\n\t\n\t@Override\n\tpublic void init(WebApplication webApplication) {\n\t\twebApplication.setRootRequestMapper(new CryptoMapper(webApplication.getRootRequestMapper(), webApplication));\n\t\twicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n\t\t\t\t.withDetail(\"properties\", props)\n\t\t\t\t.build());\n\t}\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/requestmapper/CryptMapperProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.requestmapper;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(CryptMapperProperties.PROPERTY_PREFIX)\npublic class CryptMapperProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.requestmapper.cryptmapper\";\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/resources/SpringBootMainClassResourceRegistration.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.resources;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\r\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\r\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.protocol.http.WebApplication;\r\nimport org.apache.wicket.resource.loader.ClassStringResourceLoader;\r\n\r\n@ApplicationInitExtension\r\n@RequiredArgsConstructor\r\npublic class SpringBootMainClassResourceRegistration implements WicketApplicationInitConfiguration {\r\n\r\n    private final WicketClassCandidatesHolder classCandidates;\r\n\r\n    @Override\r\n    public void init(WebApplication webApplication) {\r\n        if (classCandidates.getSpringBootMainClass() != null) {\r\n            webApplication.getResourceSettings().getStringResourceLoaders().add(new ClassStringResourceLoader(classCandidates.getSpringBootMainClass()));\r\n        }\r\n\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/resourcesettings/packageresourceguard/PackageResourceGuardConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.resourcesettings.packageresourceguard;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.markup.html.SecurePackageResourceGuard;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n@ApplicationInitExtension\n@EnableConfigurationProperties({PackageResourceGuardProperties.class})\n@RequiredArgsConstructor\npublic class PackageResourceGuardConfig implements WicketApplicationInitConfiguration {\n\n    private final PackageResourceGuardProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var packageResourceGuard = webApplication.getResourceSettings().getPackageResourceGuard();\n        if (packageResourceGuard instanceof SecurePackageResourceGuard guard) {\n            for (String pattern : props.getPattern()) {\n                guard.addPattern(pattern);\n            }\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/resourcesettings/packageresourceguard/PackageResourceGuardProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.resourcesettings.packageresourceguard;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(PackageResourceGuardProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class PackageResourceGuardProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.resourcesettings.packageresourceguard\";\n\t\n\tprivate List<String> pattern = new ArrayList<>();\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/serializer/deflated/DeflatedJavaSerializerConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.serializer.deflated;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.serialize.ISerializer;\nimport org.apache.wicket.serialize.java.DeflatedJavaSerializer;\nimport org.apache.wicket.serialize.java.JavaSerializer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.extensions.ExtensionMisconfigurationException;\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\n\n\n/**\n * Enables the deflated java serializer if the following condition matches.\n * <p>\n * 1. The property {@link DeflatedJavaSerializerProperties#PROPERTY_PREFIX}.enabled has to be true (default = false)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DeflatedJavaSerializerProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({DeflatedJavaSerializerProperties.class})\n@RequiredArgsConstructor\npublic class DeflatedJavaSerializerConfig implements WicketApplicationInitConfiguration {\n\n    private final DeflatedJavaSerializerProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var currentSerializer = webApplication.getFrameworkSettings().getSerializer();\n        if (currentSerializer instanceof JavaSerializer) {\n            webApplication.getFrameworkSettings().setSerializer(new DeflatedJavaSerializer(webApplication.getApplicationKey()));\n        } else {\n            throw new ExtensionMisconfigurationException(\"DeflatedJavaSerializer: There is already another serializer configured \" + currentSerializer);\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/serializer/deflated/DeflatedJavaSerializerProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.serializer.deflated;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(DeflatedJavaSerializerProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DeflatedJavaSerializerProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.serializer.deflated\";\n\t\n\t/**\n\t * Toggle debug settings\n\t */\n\tprivate boolean enabled = false;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/application/ApplicationSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.application;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig.Builder;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.scan.WicketAccessDeniedPage;\nimport com.giffing.wicket.spring.boot.context.scan.WicketExpiredPage;\nimport com.giffing.wicket.spring.boot.context.scan.WicketInternalErrorPage;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidate;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.Page;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.ApplicationSettings;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@ApplicationInitExtension\n@RequiredArgsConstructor\npublic class ApplicationSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final WicketClassCandidatesHolder holder;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var applicationSettings = webApplication.getApplicationSettings();\n\n        var builder = new WicketAutoConfig.Builder(this.getClass());\n\n        configureExpiredPage(applicationSettings, new ArrayList<>(holder.getExpiredPageCandidates()), builder);\n        configureAccessDeniedPage(applicationSettings, new ArrayList<>(holder.getAccessDeniedPageCandidates()), builder);\n        configureInternalErrorPage(applicationSettings, new ArrayList<>(holder.getInternalErrorPageCandidates()), builder);\n\n        wicketEndpointRepository.add(builder.build());\n\n    }\n\n    private void configureInternalErrorPage(ApplicationSettings applicationSettings, List<WicketClassCandidate<Page>> internalErrorPageCandidates, Builder builder) {\n        Class<Page> candidate = null;\n        if (!internalErrorPageCandidates.isEmpty()) {\n            if (internalErrorPageCandidates.size() == 1) {\n                WicketClassCandidate<Page> internalErrorPage = internalErrorPageCandidates.get(0);\n                candidate = internalErrorPage.getCandidate();\n                applicationSettings.setInternalErrorPage(internalErrorPage.getCandidate());\n\n\n            } else {\n                throwExceptionOnMultipleAnnotations(WicketInternalErrorPage.class, internalErrorPageCandidates);\n            }\n        }\n        builder.withDetail(\"internalErrorPage\", candidate);\n    }\n\n    private void configureAccessDeniedPage(ApplicationSettings applicationSettings, List<WicketClassCandidate<Page>> accessDeniedPageCandidates, Builder builder) {\n        Class<Page> candidate = null;\n        if (!accessDeniedPageCandidates.isEmpty()) {\n            if (accessDeniedPageCandidates.size() == 1) {\n                WicketClassCandidate<Page> accessDeniedPage = accessDeniedPageCandidates.get(0);\n                candidate = accessDeniedPage.getCandidate();\n                applicationSettings.setAccessDeniedPage(accessDeniedPage.getCandidate());\n            } else {\n                throwExceptionOnMultipleAnnotations(WicketAccessDeniedPage.class, accessDeniedPageCandidates);\n            }\n        }\n        builder.withDetail(\"accessDeniedPage\", candidate);\n    }\n\n    private void configureExpiredPage(ApplicationSettings applicationSettings, List<WicketClassCandidate<Page>> expiredPageCandidates, Builder builder) {\n        Class<Page> candidate = null;\n        if (!expiredPageCandidates.isEmpty()) {\n            if (expiredPageCandidates.size() == 1) {\n                WicketClassCandidate<Page> expiredPageCandidate = expiredPageCandidates.get(0);\n                applicationSettings.setPageExpiredErrorPage(expiredPageCandidate.getCandidate());\n                candidate = expiredPageCandidate.getCandidate();\n                builder.withDetail(\"expiredPage\", expiredPageCandidate.getCandidate().getName());\n            } else {\n                throwExceptionOnMultipleAnnotations(WicketExpiredPage.class, expiredPageCandidates);\n            }\n        }\n        builder.withDetail(\"expiredPage\", candidate);\n    }\n\n    private void throwExceptionOnMultipleAnnotations(Class<?> pageClass, List<WicketClassCandidate<Page>> expiredPageCandidates) throws IllegalAccessError {\n        var message = new StringBuilder(\"Multiple annotation of %s found%n\".formatted(pageClass.getName()));\n        for (WicketClassCandidate<Page> classCandidate : expiredPageCandidates) {\n            message.append(\"\\t\").append(classCandidate.getCandidate()).append(\"\\n\");\n        }\n        throw new IllegalAccessError(message.toString());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/debug/DebugSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.debug;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.DebugSettings;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n/**\n * Enables debug settings if the following condition matches.\n * <p>\n * 1. The property {@link DebugSettingsProperties#PROPERTY_PREFIX}.enabled has to be true (default = false)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DebugSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({DebugSettingsProperties.class})\n@RequiredArgsConstructor\npublic class DebugSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final DebugSettingsProperties properties;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        if (properties.isEnabled()) {\n            DebugSettings debugSettings = webApplication.getDebugSettings();\n            debugSettings.setDevelopmentUtilitiesEnabled(properties.isDevelopmentUtilitiesEnabled());\n            debugSettings.setAjaxDebugModeEnabled(properties.isAjaxDebugModeEnabled());\n            debugSettings.setComponentUseCheck(properties.isComponentUseCheck());\n            debugSettings.setLinePreciseReportingOnAddComponentEnabled(properties.isLinePreciseReportingOnAddComponentEnabled());\n            debugSettings.setLinePreciseReportingOnNewComponentEnabled(properties.isLinePreciseReportingOnNewComponentEnabled());\n            debugSettings.setOutputMarkupContainerClassName(properties.isOutputMarkupContainerClassName());\n            debugSettings.setComponentPathAttributeName(properties.getComponentPathAttributeName());\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", properties)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/debug/DebugSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.debug;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(DebugSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DebugSettingsProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.settings.debug\";\n\n    /**\n     * Toggle debug settings\n     */\n    private boolean enabled;\n\n    private boolean developmentUtilitiesEnabled = true;\n\n    private boolean ajaxDebugModeEnabled = true;\n\n    private boolean componentUseCheck = true;\n\n    private boolean outputMarkupContainerClassName = false;\n\n    private String componentPathAttributeName;\n\n    private boolean linePreciseReportingOnNewComponentEnabled;\n\n    private boolean linePreciseReportingOnAddComponentEnabled;\n\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/exceptions/ExceptionSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.exceptions;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.ExceptionSettings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\n\n/**\n * Configuration options for Wickets exception settings. I don't know if someone needs this\n * settings and when they don't need my javadoc :-)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = ExceptionSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@EnableConfigurationProperties({ExceptionSettingsProperties.class})\n@RequiredArgsConstructor\npublic class ExceptionSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final ExceptionSettingsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var exceptionSettings = webApplication.getExceptionSettings();\n\n        exceptionSettings.setAjaxErrorHandlingStrategy(props.getErrorHandlingStrategyDuringAjaxRequests());\n        exceptionSettings.setThreadDumpStrategy(props.getThreadDumpStrategy());\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/exceptions/ExceptionSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.exceptions;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.settings.ExceptionSettings.AjaxErrorStrategy;\nimport org.apache.wicket.settings.ExceptionSettings.ThreadDumpStrategy;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(ExceptionSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class ExceptionSettingsProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.settings.exceptions\";\n\t\n\tprivate ThreadDumpStrategy threadDumpStrategy = ThreadDumpStrategy.THREAD_HOLDING_LOCK;\n\t\n\tprivate AjaxErrorStrategy errorHandlingStrategyDuringAjaxRequests = AjaxErrorStrategy.REDIRECT_TO_ERROR_PAGE;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/general/GeneralSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.general;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.RuntimeConfigurationType;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = \"wicket.core.settings.general\")\n@Getter\n@Setter\npublic class GeneralSettingsProperties {\n\n    /**\n     * Defines the configuration startup mode. It uses Wickets\n     * {@link RuntimeConfigurationType}\n     */\n    private RuntimeConfigurationType configurationType = RuntimeConfigurationType.DEPLOYMENT;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/markup/MarkupSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.markup;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.MarkupSettings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\n\n/**\n * Configuration for the markup settings.\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@EnableConfigurationProperties({MarkupSettingsProperties.class})\n@RequiredArgsConstructor\npublic class MarkupSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final MarkupSettingsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var markupSettings = webApplication.getMarkupSettings();\n\n        if (props.getDefaultMarkupEncoding() != null) {\n            markupSettings.setDefaultMarkupEncoding(props.getDefaultMarkupEncoding());\n        }\n\n        markupSettings.setAutomaticLinking(props.isAutomaticLinking());\n        markupSettings.setCompressWhitespace(props.isCompressWhitespace());\n        markupSettings.setStripComments(props.isStripComments());\n        markupSettings.setStripWicketTags(props.isStripWicketTags());\n        markupSettings.setThrowExceptionOnMissingXmlDeclaration(props.isThrowExceptionOnMissingXmlDeclaration());\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/markup/MarkupSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.markup;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.markup.MarkupFactory;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = MarkupSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class MarkupSettingsProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.settings.markup\";\n\n    /**\n     * Application default for automatically resolving hrefs\n     */\n    private boolean automaticLinking = false;\n\n    /**\n     * True if multiple tabs/spaces should be compressed to a single space\n     */\n    private boolean compressWhitespace = false;\n\n    /**\n     * Default markup encoding. If null, the OS default will be used\n     */\n    private String defaultMarkupEncoding;\n\n    /**\n     * Factory for creating markup parsers\n     */\n    private MarkupFactory markupFactory;\n\n    /**\n     * if true than throw an exception if the xml declaration is missing from the markup file\n     */\n    private boolean throwExceptionOnMissingXmlDeclaration = false;\n\n    /**\n     * Should HTML comments be stripped during rendering?\n     */\n    private boolean stripComments = false;\n\n    /**\n     * If true, wicket tags ( <wicket: ..>) and wicket:id attributes we be removed from output\n     */\n    private boolean stripWicketTags = true;\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/pagestore/StoreSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.pagestore;\n\nimport java.io.File;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.StoreSettings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = StoreSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@EnableConfigurationProperties({StoreSettingsProperties.class})\n@RequiredArgsConstructor\npublic class StoreSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final StoreSettingsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var storeSettings = webApplication.getStoreSettings();\n        if (props.getAsynchronous() != null) {\n            storeSettings.setAsynchronous(props.getAsynchronous());\n        }\n        if (props.getAsynchronousQueueCapacity() != null) {\n            storeSettings.setAsynchronousQueueCapacity(props.getAsynchronousQueueCapacity());\n        }\n        if (props.getFileStoreFolder() != null) {\n            storeSettings.setFileStoreFolder(new File(props.getFileStoreFolder()));\n        }\n        storeSettings.setMaxSizePerSession(TypeParser.parse(props.getSessionSize(), props.getSessionUnit()));\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/pagestore/StoreSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.pagestore;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.types.SessionUnit;\n\n@ConfigurationProperties(StoreSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class StoreSettingsProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.settings.pagestore\";\n\t\n\t/**\n\t * Toggle debug settings\n\t */\n\tprivate boolean enabled;\n\t\n\tprivate Long sessionSize = 2L;\n\n\tprivate SessionUnit sessionUnit = SessionUnit.MEGABYTES;\n\t\n\tprivate Boolean asynchronous;\n\t\n\tprivate Integer asynchronousQueueCapacity;\n\t\n\tprivate String fileStoreFolder;\n\t\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/requestlogger/RequestLoggerSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.requestlogger;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n/**\n * Configuration options for Wickets exception settings. I don't know if someone needs this\n * settings and when they don't need my javadoc :-)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = RequestLoggerSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({RequestLoggerSettingsProperties.class})\n@RequiredArgsConstructor\npublic class RequestLoggerSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final RequestLoggerSettingsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var wicketsRequestLoggerSettings = webApplication.getRequestLoggerSettings();\n\n        wicketsRequestLoggerSettings.setRequestLoggerEnabled(props.isEnabled());\n        wicketsRequestLoggerSettings.setRecordSessionSize(props.isRecordSessionSize());\n        wicketsRequestLoggerSettings.setRequestsWindowSize(props.getRequestsWindowSize());\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/requestlogger/RequestLoggerSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.requestlogger;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(RequestLoggerSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class RequestLoggerSettingsProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.settings.requestlogger\";\n\n    private boolean enabled = false;\n\n    private boolean recordSessionSize = true;\n\n    private int requestsWindowSize = 0;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/requrestcycle/RequestCycleSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.requrestcycle;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.settings.RequestCycleSettings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = RequestCycleSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@EnableConfigurationProperties({RequestCycleSettingsProperties.class})\n@RequiredArgsConstructor\npublic class RequestCycleSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final RequestCycleSettingsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var requestCycleSettings = webApplication.getRequestCycleSettings();\n\n        requestCycleSettings.setRenderStrategy(props.getRenderStrategy());\n        requestCycleSettings.setBufferResponse(props.isBufferResponse());\n        requestCycleSettings.setExceptionRetryCount(props.getExceptionRetryCount());\n        requestCycleSettings.setGatherExtendedBrowserInfo(props.isGatherExtendedBrowserInfo());\n        requestCycleSettings.setResponseRequestEncoding(props.getResponseRequestEncoding());\n        requestCycleSettings.setTimeout(TypeParser.parse(props.getTimeoutSize(), props.getTimeoutUnit()));\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/requrestcycle/RequestCycleSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.requrestcycle;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.settings.RequestCycleSettings.RenderStrategy;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.types.DurationUnit;\n\n@ConfigurationProperties(prefix = RequestCycleSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class RequestCycleSettingsProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.core.settings.requestcycle\";\n\n    private RenderStrategy renderStrategy = RenderStrategy.REDIRECT_TO_BUFFER;\n\n    private boolean bufferResponse = true;\n\n    private boolean gatherExtendedBrowserInfo = false;\n\n    private String responseRequestEncoding = \"UTF-8\";\n\n    private Long timeoutSize = 1L;\n\n    private DurationUnit timeoutUnit = DurationUnit.MINUTES;\n\n    private int exceptionRetryCount = 10;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/resource/ResourceSettingsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.resource;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\n\nimport java.time.Duration;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = ResourceSettingsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\n@EnableConfigurationProperties({ResourceSettingsProperties.class})\n@RequiredArgsConstructor\npublic class ResourceSettingsConfig implements WicketApplicationInitConfiguration {\n\n    private final ResourceSettingsProperties properties;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        webApplication.getResourceSettings().setUseMinifiedResources(properties.isUseMinifiedResources());\n        if (properties.getResourcePollFrequencySeconds() > 0) {\n            webApplication.getResourceSettings().setResourcePollFrequency(Duration.ofSeconds(properties.getResourcePollFrequencySeconds()));\n        }\n    }\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/core/settings/resource/ResourceSettingsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.core.settings.resource;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(ResourceSettingsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class ResourceSettingsProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.core.settings.resource\";\n\n\tprivate boolean useMinifiedResources = true;\n\n\tprivate int resourcePollFrequencySeconds;\n\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/beanvalidation/BeanValidationConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.beanvalidation;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.bean.validation.BeanValidationConfiguration;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * Enables the bean validation support if the following condition matches\n * <p>\n * 1. The {@link BeanValidationConfiguration} class is in the classpath. side\n * note: Bean validation required an validation implementation like hibernate\n * validator.\n * <p>\n * 2. The property wicket.beanvalidation.enabled has to be true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@Component\n@ConditionalOnProperty(prefix = BeanValidationProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.apache.wicket.bean.validation.BeanValidationConfiguration.class)\n@EnableConfigurationProperties({BeanValidationProperties.class})\n@RequiredArgsConstructor\npublic class BeanValidationConfig implements WicketApplicationInitConfiguration {\n\n    private final BeanValidationProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        new BeanValidationConfiguration().configure(webApplication);\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/beanvalidation/BeanValidationProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.beanvalidation;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = BeanValidationProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class BeanValidationProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.external.beanvalidation\";\n\n    /**\n     * Enables or disables the bean validation\n     */\n    private boolean enabled;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/diskstorebrowser/DiskStoreBrowserConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.diskstorebrowser;\r\n\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.DefaultPageManagerProvider;\r\nimport org.apache.wicket.devutils.pagestore.PageStorePage;\r\nimport org.apache.wicket.markup.html.pages.BrowserInfoPage;\r\nimport org.apache.wicket.pageStore.DiskPageStore;\r\nimport org.apache.wicket.pageStore.IPageStore;\r\nimport org.apache.wicket.protocol.http.WebApplication;\r\nimport org.apache.wicket.settings.StoreSettings;\r\nimport org.apache.wicket.util.lang.Bytes;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\r\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\n\r\nimport java.io.File;\r\n\r\n/**\r\n * Mounts the {@link PageStorePage} if the following condition matches\r\n * \r\n * 1. The {@link PageStorePage} is in the classpath\r\n * \r\n * 2. The disk store browser page is enabled in the property (default=false)\r\n * \r\n * @author Marc Giffing\r\n *\r\n */\r\n@ApplicationInitExtension\r\n@ConditionalOnProperty(prefix = DiskStoreBrowserProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\r\n@ConditionalOnClass(value = PageStorePage.class)\r\n@EnableConfigurationProperties({ DiskStoreBrowserProperties.class })\r\n@RequiredArgsConstructor\r\npublic class DiskStoreBrowserConfig implements WicketApplicationInitConfiguration {\r\n\r\n\tprivate final DiskStoreBrowserProperties properties;\r\n\t\r\n\tprivate final WicketEndpointRepository wicketEndpointRepository;\r\n\t\r\n\t@Override\r\n\tpublic void init(WebApplication webApplication) {\r\n\t\twebApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\r\n\t\t\t@Override\r\n\t\t\tprotected IPageStore newPersistentStore() {\r\n\t\t\t\tvar storeSettings = application.getStoreSettings();\r\n\t\t\t\tvar fileStoreFolder = storeSettings.getFileStoreFolder();\r\n\t\t\t\tvar maxSizePerSession = storeSettings.getMaxSizePerSession();\r\n\t\t\t\treturn new DiskPageStore(webApplication.getName(), fileStoreFolder, maxSizePerSession);\r\n\t\t\t}\r\n\t\t});\r\n\t\twebApplication.mountPage(properties.getMountPage(), BrowserInfoPage.class);\r\n\t\t\r\n\t\twicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\r\n\t\t\t\t.withDetail(\"properties\", properties)\r\n\t\t\t\t.build());\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/diskstorebrowser/DiskStoreBrowserProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.diskstorebrowser;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.devutils.pagestore.PageStorePage;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = DiskStoreBrowserProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DiskStoreBrowserProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.external.development.devutils.diskstorebrowser\";\n\n    /**\n     * If enabled the {@link PageStorePage} should be mounted test page.\n     * <p>\n     * It is required that the deployment configuration is set to DEVELOPMENT.\n     */\n    private boolean enabled;\n\n    /**\n     * The default mount page for the disk store browser.\n     */\n    private String mountPage = \"devutils/diskstore/browser\";\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/inspector/InspectorConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.inspector;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.devutils.inspector.LiveSessionsPage;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\n\n/**\n * Mounts pages from the devutils inspector package. Currently only the\n * {@link LiveSessionsPage} is supported and is mounted if the following\n * condition matches.\n * <p>\n * 1. The {@link LiveSessionsPage} is in the classpath.\n * <p>\n * 2. The property enableLiveSessionsPage is enabled\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnClass(value = {org.apache.wicket.devutils.inspector.LiveSessionsPage.class,})\n@EnableConfigurationProperties({InspectorProperties.class})\n@RequiredArgsConstructor\npublic class InspectorConfig implements WicketApplicationInitConfiguration {\n\n    private final InspectorProperties properties;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        if (properties.isEnableLiveSessionsPage()) {\n            webApplication.mountPage(properties.getLiveSessionPageMount(), LiveSessionsPage.class);\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", properties)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/inspector/InspectorProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.inspector;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.devutils.inspector.LiveSessionsPage;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = InspectorProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class InspectorProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.external.development.devutils.interceptor\";\n\n    /**\n     * Enables or disabled the mounting of the {@link LiveSessionsPage}.\n     */\n    private boolean enableLiveSessionsPage;\n\n    /**\n     * The relative address on which the {@link LiveSessionsPage} should be mounted\n     */\n    private String liveSessionPageMount = \"devutils/inspector/live-session-page\";\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/statelesschecker/StatelessCheckerConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.statelesschecker;\r\n\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.devutils.stateless.StatelessChecker;\r\nimport org.apache.wicket.protocol.http.WebApplication;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\r\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\n\r\n/**\r\n * Enables the states checker from the Wicket devutils. Its only enabled if the\r\n * following condition matches\r\n * <p>\r\n * 1. The {@link StatelessChecker} is present in the classpath\r\n * <p>\r\n * 2. the {@link StatelessCheckerProperties}.statelessCheckerEnabled is set to true\r\n * (default=false)\r\n *\r\n * @author Marc Giffing\r\n */\r\n@ApplicationInitExtension\r\n@ConditionalOnProperty(prefix = StatelessCheckerProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = false)\r\n@ConditionalOnClass(value = org.apache.wicket.devutils.stateless.StatelessChecker.class)\r\n@EnableConfigurationProperties({StatelessCheckerProperties.class})\r\n@RequiredArgsConstructor\r\npublic class StatelessCheckerConfig implements WicketApplicationInitConfiguration {\r\n\r\n    private final StatelessCheckerProperties props;\r\n\r\n    private final WicketEndpointRepository wicketEndpointRepository;\r\n\r\n    @Override\r\n    public void init(WebApplication webApplication) {\r\n        webApplication.getComponentPostOnBeforeRenderListeners().add(new StatelessChecker());\r\n\r\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\r\n                .withDetail(\"properties\", props)\r\n                .build());\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/devutils/statelesschecker/StatelessCheckerProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.devutils.statelesschecker;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = StatelessCheckerProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class StatelessCheckerProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.external.development.devutils.statelesschecker\";\n\t\n\tprivate boolean enabled = false;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/SpringDevToolsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools;\r\n\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n@ConfigurationProperties(prefix = SpringDevToolsProperties.PROPERTY_PREFIX)\r\n@Getter\r\n@Setter\r\npublic class SpringDevToolsProperties {\r\n\r\n    public static final String PROPERTY_PREFIX = \"spring.devtools.restart\";\r\n\r\n    private boolean enabled = true;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/SpringDevToolsSerializer.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools;\n\nimport org.apache.wicket.serialize.ISerializer;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.serializer.DefaultDeserializer;\nimport org.springframework.core.serializer.support.DeserializingConverter;\nimport org.springframework.core.serializer.support.SerializingConverter;\n\n/**\n * A custom serializer is needed to support Spring Boot Devtools. Spring Boot Devtools\n * has some limitation with support of serialisation/deserialization support. So we have to\n * provide a custom Wicket {@link ISerializer}.\n *\n * <p>\n * <b>20.2.6 Known limitations</b> <br>\n * Restart functionality does not work well with objects that are deserialized using a\n * standard ObjectInputStream. If you need to deserialize data, you may need to use Spring’s\n * ConfigurableObjectInputStream in combination with Thread.currentThread().getContextClassLoader().\n * Unfortunately, several third-party libraries deserialize without considering the context classloader.\n * If you find such a problem, you will need to request a fix with the original authors.\n * </p>\n *\n * @author Marc Giffing\n * @see <a href=\"https://github.com/spring-projects/spring-boot/issues/3805\">Spring Boot Devtools Serializer Issue</a>\n */\npublic class SpringDevToolsSerializer implements ISerializer {\n\n    private final Converter<Object, byte[]> serializer = new SerializingConverter();\n    private final Converter<byte[], Object> deserializer;\n\n    public SpringDevToolsSerializer() {\n        this.deserializer = new DeserializingConverter(new DefaultDeserializer(Thread.currentThread().getContextClassLoader()));\n    }\n\n    @Override\n    public byte[] serialize(Object object) {\n        return serializer.convert(object);\n    }\n\n    @Override\n    public Object deserialize(byte[] data) {\n        return deserializer.convert(data);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/SpringDevtoolsSerializerConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration;\nimport org.springframework.boot.devtools.restart.ConditionalOnInitializedRestarter;\n\n/**\n * The Wicket serializer does not working with Spring Boot Devtools so we have to provide a custom {@link SpringDevToolsSerializer}.\n * It should be active by default if the following conditions matches.\n * <p>\n * 1. The {@link LocalDevToolsAutoConfiguration} class is in the classpath. This means that the Spring Boot Devtools is available in the classpath.\n * <p>\n * 2. The property \"spring.devtools.restart.enabled\" is set to true. (default is true). There is maybe a better option to check\n * <p>\n * 3. Restarter condition is active {@link ConditionalOnInitializedRestarter}.\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = SpringDevToolsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(LocalDevToolsAutoConfiguration.class)\n@EnableConfigurationProperties({SpringDevToolsProperties.class})\n@ConditionalOnInitializedRestarter\n@RequiredArgsConstructor\npublic class SpringDevtoolsSerializerConfig implements WicketApplicationInitConfiguration {\n\n    private final SpringDevToolsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        webApplication.getFrameworkSettings().setSerializer(new SpringDevToolsSerializer());\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/springboot/devtools/WicketDevToolsPropertyDefaultsPostProcessor.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools;\r\n\r\nimport org.springframework.boot.SpringApplication;\r\nimport org.springframework.boot.devtools.restart.Restarter;\r\nimport org.springframework.boot.env.EnvironmentPostProcessor;\r\nimport org.springframework.core.Ordered;\r\nimport org.springframework.core.annotation.Order;\r\nimport org.springframework.core.env.ConfigurableEnvironment;\r\nimport org.springframework.core.env.Environment;\r\nimport org.springframework.core.env.MapPropertySource;\r\n\r\nimport java.util.Collections;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\n@Order(Ordered.LOWEST_PRECEDENCE)\r\n//TODO add feature request in the Spring Boot project for adding custom development properties \r\npublic class WicketDevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor {\r\n\r\n    private static final Map<String, Object> PROPERTIES;\r\n\r\n    static {\r\n        Map<String, Object> properties = new HashMap<>();\r\n        properties.put(\"wicket.core.settings.general.configuration-type\", \"development\");\r\n        properties.put(\"wicket.core.settings.markup.strip-wicket-tags\", \"false\");\r\n        properties.put(\"wicket.core.settings.debug.component-use-check\", \"true\");\r\n        properties.put(\"wicket.core.settings.debug.development-utilities-enabled\", \"true\");\r\n        properties.put(\"wicket.core.settings.debug.ajax-debug-mode-enabled\", \"true\");\r\n\r\n\r\n        PROPERTIES = Collections.unmodifiableMap(properties);\r\n    }\r\n\r\n    @Override\r\n    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\r\n        if (Boolean.TRUE.equals(isWicketDevToolsEnabled(environment)\r\n                && isLocalApplication(environment))\r\n                && canAddProperties(environment)) {\r\n            var propertySource = new MapPropertySource(\"wicketrefresh\", PROPERTIES);\r\n            environment.getPropertySources().addLast(propertySource);\r\n        }\r\n    }\r\n\r\n    private Boolean isWicketDevToolsEnabled(ConfigurableEnvironment environment) {\r\n        var devToolsEnabled = Boolean.TRUE;\r\n        var devToolsEnabledString = environment.getProperty(\"wicket.\" + SpringDevToolsProperties.PROPERTY_PREFIX + \".enabled\");\r\n        if (devToolsEnabledString != null) {\r\n            devToolsEnabled = devToolsEnabledString.equalsIgnoreCase(\"true\");\r\n        }\r\n        return devToolsEnabled;\r\n    }\r\n\r\n    private boolean isLocalApplication(ConfigurableEnvironment environment) {\r\n        return environment.getPropertySources().get(\"remoteUrl\") == null;\r\n    }\r\n\r\n    private boolean canAddProperties(Environment environment) {\r\n        return isRestarterInitialized() || isRemoteRestartEnabled(environment);\r\n    }\r\n\r\n    private boolean isRestarterInitialized() {\r\n\r\n        try {\r\n            Restarter restarter = Restarter.getInstance();\r\n            return (restarter != null && restarter.getInitialUrls() != null);\r\n        } catch (NoClassDefFoundError | Exception ex) {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    private boolean isRemoteRestartEnabled(Environment environment) {\r\n        return environment.containsProperty(\"spring.devtools.remote.secret\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/wicketsource/WicketSourceConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.wicketsource;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.github.jennybrown8.wicketsource.WicketSource;\n\n/**\n * Enables wicket-source support if the following two condition matches:\n * <p>\n * 1. The WicketSource is in the classpath.\n * <p>\n * 2. The property wicket.wicketsource.enabled is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = WicketSourceProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = com.github.jennybrown8.wicketsource.WicketSource.class)\n@EnableConfigurationProperties({WicketSourceProperties.class})\n@RequiredArgsConstructor\npublic class WicketSourceConfig implements WicketApplicationInitConfiguration {\n\n    private final WicketSourceProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        WicketSource.configure(webApplication);\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/development/wicketsource/WicketSourceProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.wicketsource;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = WicketSourceProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class WicketSourceProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.external.development.wicketsource\";\n\t\n\tprivate boolean enabled = false;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/boot/actuator/WicketEndpoint.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.boot.actuator;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\r\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\n\r\n@ConfigurationProperties(prefix = \"endpoints.wicket\")\r\n@Endpoint(id = \"wicket\")\r\n@RequiredArgsConstructor\r\npublic class WicketEndpoint {\r\n\r\n    private final WicketEndpointRepository repository;\r\n\r\n    @ReadOperation\r\n    public Map<String, Object> wicketExtensions() {\r\n        Map<String, Object> result = new HashMap<>();\r\n        result.put(\"extensions\", repository.getConfigs());\r\n        return result;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/boot/actuator/WicketEndpointConfiguration.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.boot.actuator;\r\n\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\n\r\n@Configuration\r\npublic class WicketEndpointConfiguration {\r\n\r\n    @Bean\r\n    public WicketEndpoint wicketEndpoint() {\r\n        return new WicketEndpoint(wicketEndpointRepositoryDefault());\r\n    }\r\n\r\n    @Bean\r\n    @ConditionalOnMissingBean\r\n    public WicketEndpointRepository wicketEndpointRepositoryDefault() {\r\n        return new WicketEndpointRepositoryDefault();\r\n    }\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/boot/actuator/WicketEndpointRepositoryDefault.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.boot.actuator;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\r\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\r\nimport lombok.Getter;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\n@Getter\r\npublic class WicketEndpointRepositoryDefault implements WicketEndpointRepository {\r\n\r\n    private final List<WicketAutoConfig> configs = new ArrayList<>();\r\n\r\n    public void add(WicketAutoConfig autoconfig) {\r\n        this.configs.add(autoconfig);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/security/SecureWebSession.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security;\r\n\r\nimport java.io.Serializable;\r\n\r\nimport org.apache.wicket.authroles.authentication.AuthenticatedWebSession;\r\nimport org.apache.wicket.authroles.authorization.strategies.role.Roles;\r\nimport org.apache.wicket.injection.Injector;\r\nimport org.apache.wicket.protocol.http.WebSession;\r\nimport org.apache.wicket.request.Request;\r\nimport org.apache.wicket.spring.injection.annot.SpringBean;\r\nimport org.springframework.security.authentication.AuthenticationManager;\r\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\r\nimport org.springframework.security.core.Authentication;\r\nimport org.springframework.security.core.AuthenticationException;\r\nimport org.springframework.security.core.context.SecurityContextHolder;\r\nimport org.springframework.security.web.context.HttpSessionSecurityContextRepository;\r\n\r\n/**\r\n * Spring Security Implementation of Wickets {@link AuthenticatedWebSession}.\r\n *\r\n * @author Marc Giffing\r\n */\r\npublic class SecureWebSession extends AuthenticatedWebSession implements Serializable {\r\n\r\n    private static final String SPRING_SECURITY_CONTEXT_KEY = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;\r\n\r\n    @SpringBean(name = \"authenticationManager\")\r\n    private AuthenticationManager authenticationManager;\r\n\r\n    public SecureWebSession(Request request) {\r\n        super(request);\r\n        Injector.get().inject(this);\r\n    }\r\n\r\n    @Override\r\n    public boolean authenticate(String username, String password) {\r\n        try {\r\n            var auth = authenticationManager\r\n                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));\r\n            if (auth.isAuthenticated()) {\r\n                SecurityContextHolder.getContext().setAuthentication(auth);\r\n                WebSession httpSession = WebSession.get();\r\n                if (httpSession != null) {\r\n                    httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());\r\n                }\r\n                return true;\r\n            }\r\n            return false;\r\n        } catch (AuthenticationException e) {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public Roles getRoles() {\r\n        Roles roles = new Roles();\r\n        if (isSignedIn()) {\r\n            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\r\n            authentication.getAuthorities().forEach(authority -> roles.add(authority.getAuthority()));\r\n        }\r\n        return roles;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/security/SpringSecurityConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.security.AuthenticatedWebSessionConfig;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootSecuredWebApplication;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootWebApplication;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = SpringSecurityProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = {\n        org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession.class,\n        org.springframework.security.core.Authentication.class,\n        org.springframework.security.web.SecurityFilterChain.class\n})\n@EnableConfigurationProperties({SpringSecurityProperties.class})\n@ConditionalOnMissingBean(WicketBootWebApplication.class)\npublic class SpringSecurityConfig {\n\n    @Bean\n    public WicketBootSecuredWebApplication wicketBootWebApplication() {\n        return new WicketBootSecuredWebApplication();\n    }\n\n    @Bean\n    public AuthenticatedWebSessionConfig authenticatedWebSessionConfig() {\n        return () -> SecureWebSession.class;\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/spring/security/SpringSecurityProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = SpringSecurityProperties.PROPERTY_PREFIX)\npublic class SpringSecurityProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.external.spring.security\";\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/webjars/WebjarsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.webjars;\n\nimport jdk.jfr.Registered;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.condition.ConditionalOnWicket;\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\n\nimport de.agilecoders.wicket.webjars.WicketWebjars;\nimport de.agilecoders.wicket.webjars.settings.WebjarsSettings;\n\n/**\n * Enables webjars support if the following two condition matches:\n * <p>\n * 1. The {@link WicketWebjars} is in the classpath.\n * <p>\n * 2. The property wicket.webjars.enabled is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = WebjarsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = de.agilecoders.wicket.webjars.WicketWebjars.class)\n@EnableConfigurationProperties({WebjarsProperties.class})\n@ConditionalOnWicket(value = 10)\n@RequiredArgsConstructor\npublic class WebjarsConfig implements WicketApplicationInitConfiguration {\n\n    private final WebjarsProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var settings = new WebjarsSettings();\n        WicketWebjars.install(webApplication, settings);\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/external/webjars/WebjarsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.external.webjars;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = WebjarsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class WebjarsProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.external.webjars\";\n\n    /**\n     * Enables webjars support\n     */\n    private boolean enabled = true;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/annotationscan/AnnotatedMountScannerConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.annotationscan;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.core.annotation.Order;\nimport org.wicketstuff.annotation.scan.AnnotatedMountScanner;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\n\n/**\n * Auto configuration for the {@link AnnotatedMountScanner}.\n * <p>\n * It uses the user defined {@link WebApplication} as the default package scan\n * root directory.\n * <p>\n * Enables annotate mount scanner if the following two condition matches:\n * <p>\n * 1. The {@link AnnotatedMountScanner} is in the classpath.\n * <p>\n * 2. The property {@link AnnotatedMountScannerProperties#PROPERTY_PREFIX}\n * .enabled is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.wicketstuff.annotation.scan.AnnotatedMountScanner.class)\n@EnableConfigurationProperties({AnnotatedMountScannerProperties.class})\n@Order(ApplicationInitExtension.DEFAULT_PRECEDENCE + 50)\n@RequiredArgsConstructor\npublic class AnnotatedMountScannerConfig implements WicketApplicationInitConfiguration {\n\n    private final AnnotatedMountScannerProperties prop;\n\n    private final WicketClassCandidatesHolder candidates;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        List<String> packagesToScan = new ArrayList<>();\n        var annotatedMountScanner = new AnnotatedMountScanner();\n\n        var packagename = webApplication.getClass().getPackage().getName();\n        if (prop.getPackagename() != null) {\n            packagename = prop.getPackagename();\n        }\n\n        packagesToScan.add(packagename);\n        annotatedMountScanner.scanPackage(packagename).mount(webApplication);\n\n        if (!candidates.getBasePackages().isEmpty()) {\n            packagesToScan.addAll(candidates.getBasePackages());\n            for (String basePackage : candidates.getBasePackages()) {\n                annotatedMountScanner.scanPackage(basePackage).mount(webApplication);\n            }\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", prop)\n                .withDetail(\"packagesToScan\", packagesToScan)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/annotationscan/AnnotatedMountScannerProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.annotationscan;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = AnnotatedMountScannerProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class AnnotatedMountScannerProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.annotationscan\";\n\n    /**\n     * @see AnnotatedMountScannerConfig\n     */\n    private boolean enabled = true;\n\n    /**\n     * An alternative package name for scanning for mount path if the\n     * WicketApplication should not used as the root scan package\n     */\n    private String packagename;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/cassandra/DataStoreCassandraConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.cassandra;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.DefaultPageManagerProvider;\nimport org.apache.wicket.pageStore.IPageStore;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.datastores.cassandra.CassandraDataStore;\nimport org.wicketstuff.datastores.cassandra.CassandraSettings;\nimport org.wicketstuff.datastores.cassandra.ICassandraSettings;\nimport org.wicketstuff.datastores.common.SessionQuotaManagingDataStore;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\n\n/**\n * Data store auto configuration for the cassandra database\n * <p>\n * Enables cassandra data store if the following two condition matches:\n * <p>\n * 1. The \"com.datastax.driver.core.Session\" is in the classpath.\n * <p>\n * 2. The property {@link DataStoreCassandraProperties#PROPERTY_PREFIX}.enabled\n * is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DataStoreCassandraProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(name = \"com.datastax.driver.core.Session\", value = {CassandraDataStore.class})\n@EnableConfigurationProperties({DataStoreCassandraProperties.class})\n@AutoConfigureAfter(CassandraAutoConfiguration.class)\n@RequiredArgsConstructor\npublic class DataStoreCassandraConfig implements WicketApplicationInitConfiguration {\n\n    private final DataStoreCassandraProperties prop;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var settings = new CassandraSettings();\n        settings.getContactPoints().addAll(prop.getContactPoints());\n        settings.setTableName(prop.getTableName());\n        settings.setKeyspaceName(prop.getKeyspaceName());\n        settings.setRecordTtl(TypeParser.parse(prop.getRecordTtl(), prop.getRecordTtlUnit()));\n\n        webApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\n\n            @Override\n            protected IPageStore newPersistentStore() {\n                var delegate = new CassandraDataStore(webApplication.getName(), settings);\n                return new SessionQuotaManagingDataStore(delegate,\n                        TypeParser.parse(prop.getSessionSize(), prop.getSessionUnit()));\n            }\n\n        });\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", prop)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/cassandra/DataStoreCassandraProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.cassandra;\n\nimport com.giffing.wicket.spring.boot.context.extensions.types.DurationUnit;\nimport com.giffing.wicket.spring.boot.context.extensions.types.SessionUnit;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.List;\n\n@ConfigurationProperties(prefix = DataStoreCassandraProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DataStoreCassandraProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.datastore.cassandra\";\n\n    private boolean enabled = true;\n\n    private List<String> contactPoints;\n\n    private String tableName = \"pagestore\";\n\n    private String keyspaceName = \"wicket\";\n\n    private Long recordTtl = 30L;\n\n    private DurationUnit recordTtlUnit = DurationUnit.MINUTES;\n\n    private Long sessionSize = 2L;\n\n    private SessionUnit sessionUnit = SessionUnit.MEGABYTES;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/hazelcast/DataStoreHazelcastConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.hazelcast;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.DefaultPageManagerProvider;\nimport org.apache.wicket.pageStore.IPageStore;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.datastores.common.SessionQuotaManagingDataStore;\nimport org.wicketstuff.datastores.hazelcast.HazelcastDataStore;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\nimport com.hazelcast.core.HazelcastInstance;\n\n/**\n * Data store auto configuration for the hazelcast database\n * <p>\n * Enables hazelcast data store if the following two condition matches:\n * <p>\n * 1. The {@link HazelcastInstance} is in the classpath.\n * <p>\n * 2. The property {@link DataStoreHazelcastProperties#PROPERTY_PREFIX}.enabled\n * is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DataStoreHazelcastProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnBean(HazelcastInstance.class)\n@ConditionalOnClass({HazelcastInstance.class, HazelcastDataStore.class})\n@EnableConfigurationProperties({DataStoreHazelcastProperties.class})\n@AutoConfigureAfter(HazelcastAutoConfiguration.class)\n@RequiredArgsConstructor\npublic class DataStoreHazelcastConfig implements WicketApplicationInitConfiguration {\n\n    private final DataStoreHazelcastProperties prop;\n\n    private final HazelcastInstance hazelcastInstance;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n\n        webApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\n            @Override\n            protected IPageStore newPersistentStore() {\n                var hazelcastDataStore = new HazelcastDataStore(webApplication.getName(), hazelcastInstance);\n                return new SessionQuotaManagingDataStore(hazelcastDataStore, TypeParser.parse(prop.getSessionSize(), prop.getSessionUnit()));\n            }\n        });\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", prop)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/hazelcast/DataStoreHazelcastProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.hazelcast;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.types.SessionUnit;\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n@ConfigurationProperties(prefix = DataStoreHazelcastProperties.PROPERTY_PREFIX)\r\n@Getter\r\n@Setter\r\npublic class DataStoreHazelcastProperties {\r\n\r\n\tpublic static final String PROPERTY_PREFIX = \"wicket.stuff.datastore.hazelcast\";\r\n\r\n\tprivate boolean enabled = true;\r\n\r\n\tprivate Long sessionSize = 2L;\r\n\r\n\tprivate SessionUnit sessionUnit = SessionUnit.MEGABYTES;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/memcached/DataStoreMemcachedConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.memcached;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.DefaultPageManagerProvider;\nimport org.apache.wicket.pageStore.IPageStore;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.datastores.common.SessionQuotaManagingDataStore;\nimport org.wicketstuff.datastores.memcached.IMemcachedSettings;\nimport org.wicketstuff.datastores.memcached.MemcachedDataStore;\nimport org.wicketstuff.datastores.memcached.MemcachedSettings;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.WicketSpringBootException;\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\n\nimport net.spy.memcached.MemcachedClient;\n\n\n/**\n * Data store auto configuration for the memcached database\n * <p>\n * Enables memcached data store if the following two condition matches:\n * <p>\n * 1. The {@link MemcachedClient} is in the classpath.\n * <p>\n * 2. The property {@link DataStoreMemcachedProperties#PROPERTY_PREFIX}.enabled\n * is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DataStoreMemcachedProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass({MemcachedClient.class, MemcachedDataStore.class})\n@EnableConfigurationProperties({DataStoreMemcachedProperties.class})\n@RequiredArgsConstructor\npublic class DataStoreMemcachedConfig implements WicketApplicationInitConfiguration {\n\n    private final DataStoreMemcachedProperties prop;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n\n        webApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\n            @Override\n            protected IPageStore newPersistentStore() {\n                var settings = new MemcachedSettings();\n                settings.setExpirationTime(prop.getExpirationTime());\n                settings.setPort(prop.getPort());\n                settings.setServerNames(prop.getServerNames());\n                settings.setShutdownTimeout(TypeParser.parse(prop.getShutdownTimeout(), prop.getShutdownTimeoutUnit()));\n                try {\n                    var memcachedDataStore = new MemcachedDataStore(webApplication.getName(), settings);\n                    return new SessionQuotaManagingDataStore(memcachedDataStore, TypeParser.parse(prop.getSessionSize(), prop.getSessionUnit()));\n                } catch (Exception e) {\n                    throw new WicketSpringBootException(e);\n                }\n            }\n        });\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", prop)\n                .build());\n\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/memcached/DataStoreMemcachedProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.memcached;\n\nimport com.giffing.wicket.spring.boot.context.extensions.types.DurationUnit;\nimport com.giffing.wicket.spring.boot.context.extensions.types.SessionUnit;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = DataStoreMemcachedProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DataStoreMemcachedProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.stuff.datastore.memcached\";\n\n\tprivate boolean enabled = true;\n\n\tprivate Long sessionSize = 2L;\n\n\tprivate SessionUnit sessionUnit = SessionUnit.MEGABYTES;\n\t\n\tprivate int expirationTime  = 30;\n\t\n\tprivate int port = 11211;\n\t\n\tprivate String serverNames;\n\t\n\tprivate long shutdownTimeout = 30;\n\t\n\tprivate DurationUnit shutdownTimeoutUnit  = DurationUnit.MINUTES;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/redis/DataStoreRedisConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.redis;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.DefaultPageManagerProvider;\nimport org.apache.wicket.pageStore.IPageStore;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.datastores.common.SessionQuotaManagingDataStore;\nimport org.wicketstuff.datastores.redis.IRedisSettings;\nimport org.wicketstuff.datastores.redis.RedisDataStore;\nimport org.wicketstuff.datastores.redis.RedisSettings;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.context.extensions.types.TypeParser;\n\nimport redis.clients.jedis.Jedis;\n\n/**\n * Data store auto configuration for the redis database\n * <p>\n * Enables redis data store if the following two condition matches:\n * <p>\n * 1. The {@link Jedis} is in the classpath.\n * <p>\n * 2. The property {@link DataStoreRedisProperties#PROPERTY_PREFIX}.enabled\n * is true (default = true)\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = DataStoreRedisProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass({Jedis.class, RedisDataStore.class})\n@EnableConfigurationProperties({DataStoreRedisProperties.class})\n@AutoConfigureAfter(RedisAutoConfiguration.class)\n@RequiredArgsConstructor\npublic class DataStoreRedisConfig implements WicketApplicationInitConfiguration {\n\n    private final DataStoreRedisProperties prop;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n\n        webApplication.setPageManagerProvider(new DefaultPageManagerProvider(webApplication) {\n            @Override\n            protected IPageStore newPersistentStore() {\n                var settings = new RedisSettings();\n                settings.setHostname(prop.getHostname());\n                settings.setPort(prop.getPort());\n                settings.setRecordTtl(TypeParser.parse(prop.getRecordTtl(), prop.getRecordTtlUnit()));\n\n                var redisDataStore = new RedisDataStore(webApplication.getName(), settings);\n                return new SessionQuotaManagingDataStore(redisDataStore, TypeParser.parse(prop.getSessionSize(), prop.getSessionUnit()));\n            }\n        });\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", prop)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/datastore/redis/DataStoreRedisProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.datastore.redis;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport com.giffing.wicket.spring.boot.context.extensions.types.DurationUnit;\nimport com.giffing.wicket.spring.boot.context.extensions.types.SessionUnit;\n\n@ConfigurationProperties(prefix = DataStoreRedisProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class DataStoreRedisProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.datastore.redis\";\n\n    private boolean enabled = true;\n\n    private Long sessionSize = 2L;\n\n    private SessionUnit sessionUnit = SessionUnit.MEGABYTES;\n\n    private String hostname = \"127.0.0.1\";\n\n    private int port = 6379;\n\n    private Long recordTtl = 30L;\n\n    private DurationUnit recordTtlUnit = DurationUnit.MINUTES;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/htmlcompressor/HTMLCompressingConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.htmlcompressor;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.googlecode.htmlcompressor.compressor.HtmlCompressor;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.wicketstuff.htmlcompressor.HtmlCompressingMarkupFactory;\n\nimport java.lang.reflect.Method;\n\n/**\n * Enables the HTML markup compression if the following two conditions matches:\n * <p>\n * 1. The {@link HtmlCompressingMarkupFactory} class is present\n * <p>\n * 2. The {@link HTMLCompressingProperties}.compressHTMLEnabled is set to true\n * (default is true).\n *\n * @author Marc Giffing\n */\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = HTMLCompressingProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.wicketstuff.htmlcompressor.HtmlCompressingMarkupFactory.class)\n@EnableConfigurationProperties({HTMLCompressingProperties.class})\n@RequiredArgsConstructor\n@Slf4j\npublic class HTMLCompressingConfig implements WicketApplicationInitConfiguration {\n\n    private final HTMLCompressingProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var compressor = new HtmlCompressor();\n        setFeatureConfiguration(compressor);\n        webApplication.getMarkupSettings().setMarkupFactory(new HtmlCompressingMarkupFactory(compressor));\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n    private void setFeatureConfiguration(HtmlCompressor compressor) {\n        for (var entrySet : props.getFeatures().entrySet()) {\n            Method method = null;\n            var capitalizedKey = StringUtils.capitalize(entrySet.getKey());\n            var methodname = \"set\" + capitalizedKey;\n            try {\n                method = compressor.getClass().getMethod(methodname, boolean.class);\n                method.setAccessible(true);\n                ReflectionUtils.invokeMethod(method, compressor, entrySet.getValue());\n            } catch (Exception e) {\n                log.warn(\"failed to invoke method: {} with value {}. Exception: {}\", methodname, entrySet.getValue(), e.getMessage());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/htmlcompressor/HTMLCompressingProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.htmlcompressor;\n\nimport com.googlecode.htmlcompressor.compressor.HtmlCompressor;\nimport lombok.Getter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@ConfigurationProperties(prefix = HTMLCompressingProperties.PROPERTY_PREFIX)\n@Getter\npublic class HTMLCompressingProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.htmlcompressor\";\n\n    /**\n     * Indicates if the HTML compression should be enabled. It is only enable if a\n     * HTML compression library is present.\n     *\n     * @see HTMLCompressingConfig\n     */\n    private boolean enabled = true;\n\n    /**\n     * Sets additional features of the {@link HtmlCompressor} class. It uses\n     * reflection to set boolean properties on public methods.\n     * <p>\n     * You can for example use compressCSS->true to invoke the public method setCompressCSS(true).\n     * <p>\n     * The main goal is to provide an API independent solution to configure the {@link HtmlCompressor}.\n     * API changes can be handled over configuration changes\n     */\n    private final Map<String, Boolean> features = new HashMap<>();\n\n    public HTMLCompressingProperties() {\n        features.put(\"removeComments\", Boolean.TRUE);\n        features.put(\"removeMultiSpaces\", Boolean.TRUE);\n        features.put(\"removeIntertagSpaces\", Boolean.TRUE);\n        features.put(\"removeQuotes\", Boolean.TRUE);\n        features.put(\"compressJavaScript\", Boolean.TRUE);\n        features.put(\"compressCss\", Boolean.TRUE);\n        features.put(\"simpleDoctype\", Boolean.TRUE);\n        features.put(\"removeScriptAttributes\", Boolean.FALSE);\n        features.put(\"removeStyleAttributes\", Boolean.FALSE);\n        features.put(\"removeLinkAttributes\", Boolean.FALSE);\n        features.put(\"removeFormAttributes\", Boolean.FALSE);\n        features.put(\"removeInputAttributes\", Boolean.FALSE);\n        features.put(\"simpleBooleanAttributes\", Boolean.FALSE);\n        features.put(\"removeJavaScriptProtocol\", Boolean.FALSE);\n        features.put(\"removeHttpProtocol\", Boolean.FALSE);\n        features.put(\"removeHttpsProtocol\", Boolean.FALSE);\n        features.put(\"preserveLineBreaks\", Boolean.FALSE);\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/monitoring/jamon/BootJamonAdminPage.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.monitoring.jamon;\n\nimport org.apache.wicket.markup.head.CssHeaderItem;\nimport org.apache.wicket.markup.head.IHeaderResponse;\nimport org.wicketstuff.jamon.component.JamonAdminPage;\n\npublic class BootJamonAdminPage extends JamonAdminPage {\n\n    @Override\n    public void renderHead(IHeaderResponse response) {\n        super.renderHead(response);\n        response.render(CssHeaderItem.forReference(JamonCssResourceReference.INSTANCE));\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/monitoring/jamon/JamonConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.monitoring.jamon;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.jamon.request.cycle.JamonAwareRequestCycleListener;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = JamonProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = JamonAwareRequestCycleListener.class)\n@EnableConfigurationProperties({JamonProperties.class})\n@RequiredArgsConstructor\npublic class JamonConfig implements WicketApplicationInitConfiguration {\n\n    private final JamonProperties prop;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        webApplication.getRequestCycleListeners().add(new JamonAwareRequestCycleListener(webApplication, prop.isIncludeSourceNameInMonitorLabel()));\n        webApplication.mountPage(prop.getMountPage(), BootJamonAdminPage.class);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/monitoring/jamon/JamonCssResourceReference.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.monitoring.jamon;\n\nimport org.apache.wicket.request.resource.CssResourceReference;\n\n\npublic class JamonCssResourceReference extends CssResourceReference {\n\n    /**\n     * Singleton instance of this reference\n     */\n    public static final JamonCssResourceReference INSTANCE = new JamonCssResourceReference();\n\n    /**\n     * Private constructor.\n     */\n    private JamonCssResourceReference() {\n        super(JamonCssResourceReference.class, \"css/jamon.css\");\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/monitoring/jamon/JamonProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.monitoring.jamon;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = JamonProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class JamonProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.stuff.monitoring.jamon\";\n\t\n\tprivate boolean includeSourceNameInMonitorLabel = true;\n\t\n\tprivate String mountPage = \"/monitoring/jamon\";\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/monitoring/jamon/css/jamon.css",
    "content": ".jamonTable {\n\tbackground-color: #03487f;\n\tborder-width: 2px;\n\tborder-style: solid;\n\tborder-color: white;\n\tfont-weight: bold;\n}\n\n.jamonAdminTable {\n\tbackground-color: #03487f;\n\tborder-width: 2px;\n\tborder-style: solid;\n\tborder-color: white;\n\tfont-weight: bold;\n}\n\n.jamonDetailTable {\n\tbackground-color: #03487f;\n\tborder-width: 2px;\n\tborder-style: solid;\n\tborder-color: white;\n\tfont-weight: bold;\n}\n\n.jamonLinkToDetailPanel {\n\tcolor: white; \n\tfont-weight: bold;\n}\n\n.jamonDetailTitle {\n\tfont-weight: bold;\n\tfont-size: 18px;\n\tcolor: #03487f;\n\ttext-decoration: underline;\n}\n\n.headers a {\n\tcolor: white; \n\tfont-weight: bold;\n}\n.headers {\n\tcolor: white; \n\tfont-weight: bold;\n}\n\n.odd {\n\tbackground-color: #3b6588;\n}\n\n.even {\n\tbackground-color: #c5d4e4;\n}\n\n.selected {\n\tbackground-color: #03487f;\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/restannotations/RestAnnotationsConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.restannotations;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.rest.utils.mounting.PackageScanner;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = RestAnnotationsProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = PackageScanner.class)\n@EnableConfigurationProperties({RestAnnotationsProperties.class})\n@RequiredArgsConstructor\npublic class RestAnnotationsConfig implements WicketApplicationInitConfiguration {\n\n    private final RestAnnotationsProperties prop;\n\n    private final WicketClassCandidatesHolder candidates;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var packagename = webApplication.getClass().getPackage().getName();\n        if (prop.getPackagename() != null) {\n            packagename = prop.getPackagename();\n        }\n\n        PackageScanner.scanPackage(webApplication, packagename);\n        for (String basePackage : candidates.getBasePackages()) {\n            PackageScanner.scanPackage(webApplication, basePackage);\n        }\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/restannotations/RestAnnotationsProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.restannotations;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = RestAnnotationsProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class RestAnnotationsProperties {\n\n\tpublic static final String PROPERTY_PREFIX = \"wicket.stuff.restannotations\";\n\t\n\tprivate boolean enabled = true;\n\n\tprivate String packagename;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/serializer/fast2/WicketSerializerFast2Config.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.serializer.fast2;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.extensions.ExtensionMisconfigurationException;\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools.SpringDevtoolsSerializerConfig;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.serialize.ISerializer;\nimport org.apache.wicket.serialize.java.JavaSerializer;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.pageserializer.fast2.Fast2WicketSerializer;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = WicketSerializerFast2Properties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.wicketstuff.pageserializer.fast2.Fast2WicketSerializer.class)\n@EnableConfigurationProperties({WicketSerializerFast2Properties.class})\n@ConditionalOnMissingBean(SpringDevtoolsSerializerConfig.class)\n@RequiredArgsConstructor\npublic class WicketSerializerFast2Config implements WicketApplicationInitConfiguration {\n\n    private final WicketSerializerFast2Properties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        ISerializer currentSerializer = webApplication.getFrameworkSettings().getSerializer();\n        if (currentSerializer.getClass().equals(JavaSerializer.class)) {\n            webApplication.getFrameworkSettings().setSerializer(new Fast2WicketSerializer());\n        } else {\n            throw new ExtensionMisconfigurationException(\"Fast2Config: There is already another serializer configured \" + currentSerializer);\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/serializer/fast2/WicketSerializerFast2Properties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.serializer.fast2;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = WicketSerializerFast2Properties.PROPERTY_PREFIX)\npublic class WicketSerializerFast2Properties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.serializer.fast2\";\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/serializer/kryo2/WicketSerializerKryo2Config.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.serializer.kryo2;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.extensions.ExtensionMisconfigurationException;\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools.SpringDevtoolsSerializerConfig;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.serialize.java.JavaSerializer;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.pageserializer.kryo2.KryoSerializer;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = WicketSerializerKryo2Properties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = org.wicketstuff.pageserializer.kryo2.KryoSerializer.class)\n@EnableConfigurationProperties({WicketSerializerKryo2Properties.class})\n@ConditionalOnMissingBean(SpringDevtoolsSerializerConfig.class)\n@RequiredArgsConstructor\npublic class WicketSerializerKryo2Config implements WicketApplicationInitConfiguration {\n\n    private final WicketSerializerKryo2Properties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        var currentSerializer = webApplication.getFrameworkSettings().getSerializer();\n        if (currentSerializer.getClass().equals(JavaSerializer.class)) {\n            webApplication.getFrameworkSettings().setSerializer(new KryoSerializer());\n        } else {\n            throw new ExtensionMisconfigurationException(\"Kryo2Config: There is already another serializer configured \" + currentSerializer);\n        }\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/serializer/kryo2/WicketSerializerKryo2Properties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.serializer.kryo2;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = WicketSerializerKryo2Properties.PROPERTY_PREFIX)\npublic class WicketSerializerKryo2Properties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.serializer.kryo2\";\n\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/shiro/ShiroSecurityConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.shiro;\r\n\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.shiro.spring.boot.autoconfigure.ShiroAutoConfiguration;\r\nimport org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;\r\nimport org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;\r\nimport org.apache.wicket.Page;\r\nimport org.apache.wicket.markup.html.WebPage;\r\nimport org.apache.wicket.protocol.http.WebApplication;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\r\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.wicketstuff.shiro.annotation.AnnotationsShiroAuthorizationStrategy;\r\nimport org.wicketstuff.shiro.authz.ShiroUnauthorizedComponentListener;\r\n\r\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\r\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\r\nimport com.giffing.wicket.spring.boot.context.scan.WicketAccessDeniedPage;\r\nimport com.giffing.wicket.spring.boot.context.scan.WicketSignInPage;\r\nimport com.giffing.wicket.spring.boot.starter.app.classscanner.candidates.WicketClassCandidatesHolder;\r\n\r\n//TODO check if property shiro.enabled is true\r\n@ApplicationInitExtension\r\n@ConditionalOnProperty(prefix = ShiroSecurityProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\r\n@ConditionalOnClass(value = {\r\n        AnnotationsShiroAuthorizationStrategy.class,\r\n        ShiroAutoConfiguration.class,\r\n})\r\n@EnableConfigurationProperties({ShiroSecurityProperties.class})\r\n@RequiredArgsConstructor\r\npublic class ShiroSecurityConfig implements WicketApplicationInitConfiguration {\r\n\r\n    private final WicketClassCandidatesHolder classCandidates;\r\n\r\n    @Bean\r\n    ShiroFilterChainDefinition shiroFilterChainDefinition() {\r\n        return new DefaultShiroFilterChainDefinition();\r\n    }\r\n\r\n    @Override\r\n    public void init(WebApplication webApplication) {\r\n        var authz = new AnnotationsShiroAuthorizationStrategy();\r\n        webApplication.getSecuritySettings().setAuthorizationStrategy(authz);\r\n\r\n        if (classCandidates.getSignInPageCandidates().isEmpty()) {\r\n            throw new IllegalStateException(\"Couln't find sign in page - please annotate the sign in page with @\" + WicketSignInPage.class.getName());\r\n        }\r\n        if (classCandidates.getAccessDeniedPageCandidates().isEmpty()) {\r\n            throw new IllegalStateException(\"Couln't find access denied in page - please annotate the sign in page with @\" + WicketAccessDeniedPage.class.getName());\r\n        }\r\n        var signInPage = classCandidates.getSignInPageCandidates().iterator().next().getCandidate();\r\n        var accessDeniedPage = classCandidates.getAccessDeniedPageCandidates().iterator().next().getCandidate();\r\n        webApplication.getSecuritySettings()\r\n                .setUnauthorizedComponentInstantiationListener(new ShiroUnauthorizedComponentListener(signInPage, accessDeniedPage, authz));\r\n\r\n    }\r\n\r\n}"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/shiro/ShiroSecurityProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.shiro;\r\n\r\nimport lombok.Getter;\r\nimport lombok.Setter;\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n@ConfigurationProperties(prefix = ShiroSecurityProperties.PROPERTY_PREFIX)\r\n@Getter\r\n@Setter\r\npublic class ShiroSecurityProperties {\r\n\r\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.restannotations\";\r\n\r\n    private boolean enabled = true;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/springreference/SpringReferenceConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.springreference;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.wicketstuff.springreference.SpringReferenceSupporter;\n\n@ApplicationInitExtension\n@ConditionalOnProperty(prefix = SpringReferenceProperties.PROPERTY_PREFIX, value = \"enabled\", matchIfMissing = true)\n@ConditionalOnClass(value = SpringReferenceSupporter.class)\n@EnableConfigurationProperties({SpringReferenceProperties.class})\n@RequiredArgsConstructor\npublic class SpringReferenceConfig implements WicketApplicationInitConfiguration {\n\n    private final SpringReferenceProperties props;\n\n    private final WicketEndpointRepository wicketEndpointRepository;\n\n    @Override\n    public void init(WebApplication webApplication) {\n        SpringReferenceSupporter.register(webApplication);\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/configuration/extensions/stuff/springreference/SpringReferenceProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.configuration.extensions.stuff.springreference;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = SpringReferenceProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class SpringReferenceProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.stuff.springreference\";\n\n    private boolean enabled = true;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/WicketWebInitializer.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web;\n\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketAutoConfig;\nimport com.giffing.wicket.spring.boot.context.extensions.boot.actuator.WicketEndpointRepository;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootWebApplication;\nimport com.giffing.wicket.spring.boot.starter.web.config.WicketWebInitializerAutoConfig;\nimport com.giffing.wicket.spring.boot.starter.web.config.WicketWebInitializerConfig;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.protocol.http.WicketFilter;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport java.util.EnumSet;\n\n/**\n * Primary container configuration to configure Wicket requests.\n *\n * @author Marc Giffing\n */\n@Configuration\n@Import(value = {WicketWebInitializerAutoConfig.class})\n@EnableConfigurationProperties({WicketWebInitializerProperties.class})\npublic class WicketWebInitializer {\n\n    public static final String WICKET_FILTERNAME = \"wicket-filter\";\n\n    @Bean\n    public FilterRegistrationBean<WicketFilter> wicketFilter(\n            WicketWebInitializerConfig wicketWebInitializerConfig,\n            WicketWebInitializerProperties props,\n            WicketEndpointRepository wicketEndpointRepository,\n            WicketBootWebApplication wicketBootWebApplication\n    ) {\n        var wicketFilter = wicketWebInitializerConfig.createWicketFilter((WebApplication) wicketBootWebApplication);\n\n        var filter = new FilterRegistrationBean<>(wicketFilter);\n        filter.setName(WICKET_FILTERNAME);\n        filter.addUrlPatterns(props.getFilterMappingParam());\n        filter.setDispatcherTypes(EnumSet.copyOf(props.getDispatcherTypes()));\n        filter.setMatchAfter(props.isFilterMatchAfter());\n\n        filter.addInitParameter(WicketFilter.FILTER_MAPPING_PARAM, props.getFilterMappingParam());\n        props.getInitParameters().forEach(filter::addInitParameter);\n\n        wicketEndpointRepository.add(new WicketAutoConfig.Builder(this.getClass())\n                .withDetail(\"wicketFilterName\", WICKET_FILTERNAME)\n                .withDetail(\"wicketFilterClass\", wicketFilter.getClass())\n                .withDetail(\"properties\", props)\n                .build());\n\n        return filter;\n    }\n\n}\n\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/WicketWebInitializerProperties.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web;\n\nimport jakarta.servlet.DispatcherType;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@ConfigurationProperties(prefix = WicketWebInitializerProperties.PROPERTY_PREFIX)\n@Getter\n@Setter\npublic class WicketWebInitializerProperties {\n\n    public static final String PROPERTY_PREFIX = \"wicket.web.servlet\";\n\n    private String filterMappingParam = \"/*\";\n\n    // Adds possibility to add init parameters dynamically\n    private Map<String, String> initParameters = new HashMap<>();\n\n    private List<DispatcherType> dispatcherTypes = List.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.ASYNC);\n\n    private boolean filterMatchAfter;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/config/WicketWebInitializerAutoConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.config;\n\nimport com.giffing.wicket.spring.boot.starter.web.servlet.standard.StandardWicketWebInitializer;\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.*;\nimport org.apache.wicket.Application;\nimport org.apache.wicket.protocol.ws.javax.JavaxWebSocketFilter;\nimport org.apache.wicket.protocol.ws.javax.WicketServerEndpointConfig;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration of the {@link WicketWebInitializerConfig} depending on property\n * conditions and dependency existence.\n *\n * @author Marc Giffing\n */\n@Configuration\npublic class WicketWebInitializerAutoConfig {\n\n    /**\n     * The {@link StandardWicketWebInitializer} should be configured if no other\n     * {@link WicketWebInitializerConfig} is configured. Its quasi the standard\n     * configuration.\n     *\n     * @author Marc Giffing\n     */\n    @Configuration\n    @ConditionalOnMissingBean(WicketWebInitializerConfig.class)\n    @AutoConfigureAfter(WebSocketWicketWebInitializerAutoConfiguration.class)\n    public static class StandardWicketWebInitializerAutoConfiguration {\n\n        @Bean\n        public WicketWebInitializerConfig wicketWebInitializerConfig() {\n            return new StandardWicketWebInitializer();\n        }\n    }\n\n    /**\n     * @author Marc Giffing\n     */\n    @Configuration\n    @ConditionalOnClass({JavaxWebSocketFilter.class})\n    @ConditionalOnProperty(prefix = \"wicket.external.websocket\", value = \"enabled\", matchIfMissing = true)\n    public static class WebSocketWicketWebInitializerAutoConfiguration {\n\n        public static final String REGISTER_SERVER_ENDPOINT = \"wicket.external.websocket.registerServerEndpoint\";\n        public static final String REGISTER_SERVER_ENDPOINT_ENABLED = REGISTER_SERVER_ENDPOINT + \".enabled\";\n\n        @Bean\n        public WicketWebInitializerConfig wicketWebInitializerConfig() {\n            return new WebSocketWicketWebInitializer();\n        }\n\n        /**\n         * @return the wicket server endpoint config register which registers  the {@link WicketServerEndpointConfig}\n         */\n        @Bean\n        @ConditionalOnProperty(prefix = REGISTER_SERVER_ENDPOINT, value = \"enabled\", matchIfMissing = true)\n        public WicketServerEndpointConfigRegister wicketServerEndpointConfigRegister() {\n            return new WicketServerEndpointConfigRegister();\n        }\n\n        @Bean\n        @ConditionalOnMissingBean(WicketSessionResolver.class)\n        public WicketSessionResolver dummyWicketSessionResolver() {\n            return new DummyWicketSessionResolver();\n        }\n\n        @Bean\n        public WebSocketMessageSenderDefault webSocketEventHandler(Application application, WicketSessionResolver wicketSessionResolver) {\n            return new WebSocketMessageSenderDefault(application, wicketSessionResolver);\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/config/WicketWebInitializerConfig.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.config;\n\nimport com.giffing.wicket.spring.boot.starter.web.WicketWebInitializer;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.protocol.http.WicketFilter;\n\n/**\n * Dynamic configuration support which will be used in {@link WicketWebInitializer}.\n * <p>\n * The configuration {@link WicketWebInitializerAutoConfig} is responsible to detect which {@link WicketWebInitializerConfig}\n * should be configured.\n *\n * @author Marc Giffing\n */\npublic interface WicketWebInitializerConfig {\n\n    /**\n     * Returns a {@link WicketFilter} which will be configured in the {@link WicketWebInitializer}\n     */\n    WicketFilter createWicketFilter(WebApplication application);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/standard/StandardWicketWebInitializer.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.standard;\n\nimport com.giffing.wicket.spring.boot.starter.web.config.WicketWebInitializerConfig;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.protocol.http.WicketFilter;\n\n/**\n * The {@link StandardWicketWebInitializer} will be configured when no other\n * {@link WicketWebInitializerConfig} is present. It uses the standard {@link WicketFilter}.\n *\n * @author Marc Giffing\n */\npublic class StandardWicketWebInitializer implements WicketWebInitializerConfig {\n\n    @Override\n    public WicketFilter createWicketFilter(WebApplication application) {\n        return new WicketFilter(application);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/DummyWicketSessionResolver.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\r\n\r\nimport java.util.List;\r\n\r\npublic class DummyWicketSessionResolver implements WicketSessionResolver {\r\n\r\n    @Override\r\n    public List<String> resolve(Object value) {\r\n        return List.of();\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/WebSocketMessageBroadcaster.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\n\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\n\n/**\n * Used to broadcast {@link IWebSocketPushMessage} messages.\n *\n * @author Marc Giffing\n */\npublic interface WebSocketMessageBroadcaster {\n\n    /**\n     * Broadcasts a push message to the Wicket page (and it's components)\n     * associated with all connections. The components can then send messages or\n     * component updates to client by adding them to the target.\n     *\n     * @param event\n     */\n    void sendToAll(IWebSocketPushMessage event);\n\n    /**\n     * Sends a message to a specific identifier. The {@link WicketSessionResolver} is responsible to\n     * the identifier and return the corresponding session list to inform the user.\n     * <p>\n     * The identifier can be an username or a user group. Its up to the user to decide how the session ids will\n     * resolved.\n     */\n    void sendTo(Object identifier, IWebSocketPushMessage event);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/WebSocketMessageSenderDefault.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\n\nimport org.apache.wicket.Application;\nimport org.apache.wicket.protocol.ws.WebSocketSettings;\nimport org.apache.wicket.protocol.ws.api.IWebSocketConnection;\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class WebSocketMessageSenderDefault implements WebSocketMessageBroadcaster {\n\n    private final Logger log = LoggerFactory.getLogger(getClass());\n\n    private Application application;\n\n    private WicketSessionResolver wicketSessionResolver;\n\n    public WebSocketMessageSenderDefault(Application application, WicketSessionResolver wicketSessionResolver) {\n        this.application = application;\n        this.wicketSessionResolver = wicketSessionResolver;\n    }\n\n    @Override\n    public void sendToAll(IWebSocketPushMessage event) {\n        var webSocketSettings = WebSocketSettings.Holder.get(application);\n        var connectionRegistry = webSocketSettings.getConnectionRegistry();\n        var connections = connectionRegistry.getConnections(application);\n        log.trace(\"sending event to {} connections\", connections.size());\n        for (IWebSocketConnection connection : connections) {\n            connection.sendMessage(event);\n        }\n    }\n\n    @Override\n    public void sendTo(Object identifier, IWebSocketPushMessage event) {\n        if (identifier == null) {\n            return;\n        }\n\n        var webSocketSettings = WebSocketSettings.Holder.get(application);\n        var connectionRegistry = webSocketSettings.getConnectionRegistry();\n        wicketSessionResolver.resolve(identifier).forEach(sessionId -> {\n            var connections = connectionRegistry.getConnections(application, sessionId);\n            log.trace(\"sending event to {} connections\", connections.size());\n            for (IWebSocketConnection connection : connections) {\n                connection.sendMessage(event);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/WebSocketWicketWebInitializer.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\n\nimport com.giffing.wicket.spring.boot.starter.web.config.WicketWebInitializerConfig;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.protocol.http.WicketFilter;\nimport org.apache.wicket.protocol.ws.javax.JavaxWebSocketFilter;\n\n/**\n * This initializer will be used if the JSR 356 - Java API for WebSocket is\n * used.\n *\n * @author Marc Giffing\n */\npublic class WebSocketWicketWebInitializer implements WicketWebInitializerConfig {\n\n    @Override\n    public WicketFilter createWicketFilter(WebApplication application) {\n        return new JavaxWebSocketFilter(application);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/WicketServerEndpointConfigRegister.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\n\nimport com.giffing.wicket.spring.boot.context.exceptions.WicketSpringBootException;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.websocket.DeploymentException;\nimport jakarta.websocket.Endpoint;\nimport jakarta.websocket.server.ServerContainer;\nimport org.apache.wicket.protocol.ws.javax.WicketServerEndpointConfig;\n\n/**\n * Automatically registers the {@link WicketServerEndpointConfig} as an {@link Endpoint}\n * in the {@link ServerContainer}\n *\n * @author Marc Giffing\n */\npublic class WicketServerEndpointConfigRegister implements ServletContextListener {\n\n    private static final String SERVER_CONTAINER_ATTRIBUTE = ServerContainer.class.getName();\n\n    @Override\n    public void contextInitialized(ServletContextEvent sce) {\n        var container = sce.getServletContext();\n\n        var serverContainer = (ServerContainer) container.getAttribute(SERVER_CONTAINER_ATTRIBUTE);\n        try {\n            serverContainer.addEndpoint(new WicketServerEndpointConfig());\n        } catch (DeploymentException e) {\n            throw new WicketSpringBootException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/java/com/giffing/wicket/spring/boot/starter/web/servlet/websocket/WicketSessionResolver.java",
    "content": "package com.giffing.wicket.spring.boot.starter.web.servlet.websocket;\r\n\r\nimport java.util.List;\r\n\r\npublic interface WicketSessionResolver {\r\n\r\n\t/**\r\n\t * Retrieve the session id from the principle object.\r\n\t * \r\n\t * @param identifier\r\n\t * @return\r\n\t */\r\n\tList<String> resolve(Object identifier);\r\n\t\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "com.giffing.wicket.spring.boot.starter.WicketAutoConfiguration\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/resources/META-INF/spring-devtools.properties",
    "content": "restart.include.wicket-annotation=/wicketstuff-annotation-[\\\\w-\\.]+\\.jar\r\nrestart.include.wicket-spring=/wicket-spring-[\\\\w-\\.]+\\.jar\r\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.env.EnvironmentPostProcessor=com.giffing.wicket.spring.boot.starter.configuration.extensions.external.development.springboot.devtools.WicketDevToolsPropertyDefaultsPostProcessor\n\norg.springframework.boot.diagnostics.FailureAnalyzer=com.giffing.wicket.spring.boot.starter.app.verifier.WicketDependencyVersionCheckerFailureAnalyzer\n"
  },
  {
    "path": "wicket-spring-boot-starter/src/main/resources/application-development.yml",
    "content": "spring:\n  h2:\n    console:\n      enabled: true\n  devtools:\n    restart:\n      additional-exclude: /**/*.js, /**/*.css, /**/*.html, /**/*.htm\nwicket:\n  core:\n    settings:\n      general:\n        configuration-type: development\n      debug:\n        enabled: true\n        component-use-check: true\n        development-utilities-enabled: true\n      markup:\n        strip-wicket-tags: false\n  stuff:\n    htmlcompressor:\n      enabled: false\n      features:\n        removeComments: false\n        removeMultiSpaces: false\n        removeIntertagSpaces: false\n        removeQuotes: false\n        compressJavaScript: false\n        compressCss: false\n        simpleDoctype: false\n        removeScriptAttributes: false\n        removeStyleAttributes: false\n        removeLinkAttributes: false\n        removeFormAttributes: false\n        removeInputAttributes: false\n        simpleBooleanAttributes: false\n        removeJavaScriptProtocol: false\n        removeHttpProtocol: false\n        removeHttpsProtocol: false\n        preserveLineBreaks: false\n  external:\n    development:\n      devutils:\n        statelesschecker:\n          enabled: true\n        interceptor:\n          enable-live-sessions-page: true\n        diskstorebrowser:\n          enabled: true\n      wicketsource:\n        enabled: true"
  },
  {
    "path": "wicket-spring-boot-starter-example/.gitignore",
    "content": "/target/\n/.settings/\n.classpath\n.project\n.springBeans\n/src/main/resources/public/docs/"
  },
  {
    "path": "wicket-spring-boot-starter-example/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>wicket-spring-boot-starter-example</artifactId>\n\n    <parent>\n        <groupId>com.giffing.wicket.spring.boot.starter</groupId>\n        <artifactId>wicket-spring-boot-starter-parent</artifactId>\n        <version>4.1.1</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <name>Spring boot starter example</name>\n    <description>\n        An example project which uses the wicket-spring-boot-starter autoconfiguration project\n    </description>\n\n    <properties>\n        <maven.deploy.skip>true</maven.deploy.skip>\n        <maven.javadoc.skip>true</maven.javadoc.skip>\n        <wicket-bootstrap.version>7.0.11</wicket-bootstrap.version>\n        <hibernate-processor.version>7.1.0.Final</hibernate-processor.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.giffing.wicket.spring.boot.starter</groupId>\n            <artifactId>wicket-spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-actuator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.session</groupId>\n            <artifactId>spring-session-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.wicketstuff</groupId>\n            <artifactId>wicketstuff-annotation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>de.agilecoders.wicket</groupId>\n            <artifactId>wicket-bootstrap-core</artifactId>\n            <version>${wicket-bootstrap.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>de.agilecoders.wicket</groupId>\n            <artifactId>wicket-bootstrap-extensions</artifactId>\n            <version>${wicket-bootstrap.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>de.agilecoders.wicket</groupId>\n            <artifactId>wicket-bootstrap-sass</artifactId>\n            <version>${wicket-bootstrap.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>de.agilecoders.wicket</groupId>\n            <artifactId>wicket-bootstrap-themes</artifactId>\n            <version>${wicket-bootstrap.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.wicketstuff</groupId>\n            <artifactId>wicketstuff-htmlcompressor</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.yahoo.platform.yui</groupId>\n            <artifactId>yuicompressor</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.wicket</groupId>\n            <artifactId>wicket-extensions</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.wicket</groupId>\n            <artifactId>wicket-bean-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>de.agilecoders.wicket.webjars</groupId>\n            <artifactId>wicket-webjars</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.xml.bind</groupId>\n            <artifactId>jakarta.xml.bind-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.wicketstuff</groupId>\n            <artifactId>wicketstuff-serializer-fast2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>de.agilecoders.wicket</groupId>\n            <artifactId>jquery-selectors</artifactId>\n            <version>4.0.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.liquibase</groupId>\n            <artifactId>liquibase-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.wicketstuff</groupId>\n            <artifactId>wicketstuff-restannotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.wicketstuff</groupId>\n            <artifactId>wicketstuff-restannotations-json</artifactId>\n        </dependency>\n        <!-- Test dependencies -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.wicket</groupId>\n            <artifactId>wicket-tester</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate.orm</groupId>\n            <artifactId>hibernate-processor</artifactId>\n            <version>${hibernate-processor.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.wicket</groupId>\n            <artifactId>wicket-native-websocket-javax</artifactId>\n        </dependency>\n    </dependencies>\n\n    <profiles>\n        <profile>\n            <id>release</id>\n        </profile>\n        <profile>\n            <id>development</id>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n            </activation>\n            <properties>\n                <spring.profiles.active>development</spring.profiles.active>\n            </properties>\n            <dependencies>\n                <dependency>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-devtools</artifactId>\n                </dependency>\n                <dependency>\n                    <groupId>org.apache.wicket</groupId>\n                    <artifactId>wicket-devutils</artifactId>\n                </dependency>\n                <dependency>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-web</artifactId>\n                </dependency>\n                <dependency>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-actuator</artifactId>\n                </dependency>\n            </dependencies>\n        </profile>\n    </profiles>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-release-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>none</phase>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.13.0</version>\n                <configuration>\n                    <source>17</source>\n                    <target>17</target>\n                    <annotationProcessorPaths>\n                        <path>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                            <version>${lombok.version}</version>\n                        </path>\n                        <path>\n                            <groupId>org.hibernate.orm</groupId>\n                            <artifactId>hibernate-processor</artifactId>\n                            <version>${hibernate-processor.version}</version>\n                        </path>\n                    </annotationProcessorPaths>\n                </configuration>\n            </plugin>\n\n            <!-- Assist eclipse in recognizing the classes generated -->\n            <!-- by jpa-modelgen (via maven-processor-plugin) as source files -->\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>add-source</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>add-source</goal>\n                        </goals>\n                        <configuration>\n                            <sources>\n                                <source>target/generated-sources/apt</source>\n                            </sources>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.asciidoctor</groupId>\n                <artifactId>asciidoctor-maven-plugin</artifactId>\n                <version>3.1.0</version>\n                <executions>\n                    <execution>\n                        <id>output-html</id>\n                        <phase>generate-resources</phase>\n                        <goals>\n                            <goal>process-asciidoc</goal>\n                        </goals>\n                        <configuration>\n                            <sourceDirectory>src/main/doc</sourceDirectory>\n                            <outputDirectory>target/docs</outputDirectory>\n                            <backend>html</backend>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>maven-resources-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>copy-asciidoc-resources</id>\n                        <phase>generate-resources</phase>\n                        <goals>\n                            <goal>copy-resources</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${basedir}/src/main/resources/public/docs/</outputDirectory>\n                            <resources>\n                                <resource>\n                                    <directory>target/docs</directory>\n                                    <filtering>true</filtering>\n                                </resource>\n                            </resources>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**</include>\n                </includes>\n                <excludes>\n                    <exclude>**/*.java</exclude>\n                </excludes>\n            </resource>\n        </resources>\n        <pluginManagement>\n            <plugins>\n                <!--This plugin's configuration is used to store Eclipse m2e settings\n                    only. It has no influence on the Maven build itself. -->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>1.0.0</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.asciidoctor\n                                        </groupId>\n                                        <artifactId>\n                                            asciidoctor-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.5.2,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                process-asciidoc\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore/>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.bsc.maven</groupId>\n                                        <artifactId>maven-processor-plugin</artifactId>\n                                        <versionRange>[${maven-processor-plugin.version},)</versionRange>\n                                        <goals>\n                                            <goal>process</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <execute/>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n\n</project>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/doc/index.adoc",
    "content": "= Example Title\n\n== Sub Section 1\n\n== Sub Section 2"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/WicketApplication.java",
    "content": "package com.giffing.wicket.spring.boot.example;\n\nimport com.giffing.wicket.spring.boot.example.repository.services.DefaultRepositoryService;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\n\n@SpringBootApplication\n@EnableJpaRepositories(basePackageClasses = {DefaultRepositoryService.class})\npublic class WicketApplication {\n\n    public static void main(String[] args) {\n        new SpringApplicationBuilder()\n                .sources(WicketApplication.class)\n                .run(args);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/WicketApplication.properties",
    "content": "login.label=Login"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/model/Customer.java",
    "content": "package com.giffing.wicket.spring.boot.example.model;\n\nimport com.giffing.wicket.spring.boot.example.repository.Domain;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.GenerationType;\nimport jakarta.persistence.Id;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.io.Serializable;\n\n@Entity\n@Getter\n@Setter\npublic class Customer implements Domain<Long>, Serializable {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n\n    private String username;\n\n    private String firstname;\n\n    private String lastname;\n\n    private boolean active;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/DefaultFilter.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository;\n\npublic abstract class DefaultFilter implements Filter {\n\n    private Sort sort;\n\n    private boolean ascending;\n\n    @Override\n    public Sort sort() {\n        return sort;\n    }\n\n    @Override\n    public boolean isAscending() {\n        return ascending;\n    }\n\n    @Override\n    public void setSort(Sort sort, boolean ascending) {\n        this.sort = sort;\n        this.ascending = ascending;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/Domain.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository;\n\npublic interface Domain<ID> {\n\n    ID getId();\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/Filter.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository;\n\nimport java.io.Serializable;\n\npublic interface Filter extends Serializable {\n\n    Sort sort();\n\n    boolean isAscending();\n\n    void setSort(Sort sort, boolean ascending);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/FilterService.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository;\n\nimport java.util.List;\n\npublic interface FilterService<MODEL, ID, FILTER_MODEL extends Filter> {\n\n    MODEL findById(ID id);\n\n    List<MODEL> findAll(Long page, Long count, FILTER_MODEL filter);\n\n    long count(FILTER_MODEL filter);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/Sort.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository;\n\npublic interface Sort {\n\n    String getFieldName();\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/DefaultRepositoryService.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services;\n\nimport com.giffing.wicket.spring.boot.example.repository.Filter;\nimport com.giffing.wicket.spring.boot.example.repository.FilterService;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.domain.Sort.Direction;\n\npublic abstract class DefaultRepositoryService<MODEL, ID, FILTER extends Filter> implements FilterService<MODEL, ID, FILTER> {\n\n    public Sort getSort(FILTER filter) {\n        var sort = Sort.unsorted();\n        if (filter.sort() != null) {\n            Direction direction = filter.isAscending() ? Direction.ASC : Direction.DESC;\n            sort = Sort.by(direction, filter.sort().getFieldName());\n        }\n        return sort;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/CustomerRepository.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.repository.ListCrudRepository;\n\npublic interface CustomerRepository extends ListCrudRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {\n\n    int countByUsernameIgnoreCase(String username);\n\n    Customer findByUsernameIgnoreCase(String username);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/CustomerRepositoryService.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer;\r\n\r\nimport com.giffing.wicket.spring.boot.example.model.Customer;\r\nimport com.giffing.wicket.spring.boot.example.repository.FilterService;\r\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerFilter;\r\n\r\nimport java.util.List;\r\n\r\npublic interface CustomerRepositoryService extends FilterService<Customer, Long, CustomerFilter> {\r\n\r\n    void delete(Long id);\r\n\r\n    List<String> findUsernames(int count, String usernamePart);\r\n\r\n    Customer save(Customer customer);\r\n\r\n    Customer findByUsername(String username);\r\n\r\n    /**\r\n     * @param username the username\r\n     * @return true if the username already exists\r\n     */\r\n    boolean usernameExists(String username);\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/CustomerRepositoryServiceImpl.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer;\n\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.model.Customer_;\nimport com.giffing.wicket.spring.boot.example.repository.services.DefaultRepositoryService;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerFilter;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.specs.CustomerSpecs;\nimport jakarta.annotation.Resource;\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.TypedQuery;\nimport jakarta.persistence.criteria.CriteriaBuilder;\nimport jakarta.persistence.criteria.CriteriaQuery;\nimport jakarta.persistence.criteria.Predicate;\nimport jakarta.persistence.criteria.Root;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.jpa.domain.Specification;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n@Repository\npublic class CustomerRepositoryServiceImpl extends DefaultRepositoryService<Customer, Long, CustomerFilter> implements CustomerRepositoryService {\n\n    private CustomerRepository customerRepository;\n\n    @Resource\n    private EntityManager em;\n\n    public CustomerRepositoryServiceImpl(CustomerRepository customerRepository) {\n        this.customerRepository = customerRepository;\n    }\n\n    @Override\n    public List<Customer> findAll(Long page, Long count, CustomerFilter filter) {\n        PageRequest pr = PageRequest.of(page.intValue(), count.intValue(), getSort(filter));\n        return customerRepository.findAll(filter(filter), pr).getContent();\n    }\n\n    @Override\n    public long count(CustomerFilter filter) {\n        return customerRepository.count(filter(filter));\n    }\n\n    private Specification<Customer> filter(CustomerFilter filter) {\n        List<Specification<Customer>> specs = new ArrayList<>();\n\n        if (filter.getId() != null) {\n            specs.add(CustomerSpecs.hasId(filter.getId()));\n        }\n\n        if (isNotEmpty(filter.getUsername())) {\n            specs.add(CustomerSpecs.hasUsername(filter.getUsername()));\n        }\n\n        if (isNotEmpty(filter.getUsernameLike())) {\n            specs.add(CustomerSpecs.hasUsernameLike(filter.getUsernameLike()));\n        }\n\n        if (isNotEmpty(filter.getFirstnameLike())) {\n            specs.add(CustomerSpecs.hasFirstnameLike(filter.getFirstnameLike()));\n        }\n\n        if (isNotEmpty(filter.getLastnameLike())) {\n            specs.add(CustomerSpecs.hasLastnameLike(filter.getLastnameLike()));\n        }\n\n        if (filter.isActive()) {\n            specs.add(CustomerSpecs.hasActive(filter.isActive()));\n        }\n\n        Specification<Customer> spec = null;\n        for (Specification<Customer> specification : specs) {\n            if (spec == null) {\n                spec = Specification.where(specification);\n            } else {\n                spec = spec.and(specification);\n            }\n        }\n\n        return spec;\n    }\n\n    boolean isNotEmpty(String toCheck) {\n        if (toCheck != null && toCheck.length() > 0) {\n            return true;\n        }\n\n        return false;\n    }\n\n\n    @Override\n    public Customer findById(Long id) {\n        Optional<Customer> customer = customerRepository.findById(id);\n        return customer.isPresent() ? customer.get() : null;\n    }\n\n    @Override\n    public void delete(Long id) {\n        customerRepository.deleteById(id);\n    }\n\n    @Override\n    public List<String> findUsernames(int count, String usernamePart) {\n\n        CriteriaBuilder builder = em.getCriteriaBuilder();\n        CriteriaQuery<String> query = builder.createQuery(String.class);\n        Root<Customer> customerRoot = query.from(Customer.class);\n\n        query = query.select(customerRoot.get(Customer_.username));\n\n        Predicate predicate = CustomerSpecs.hasUsernameLike(usernamePart).toPredicate(customerRoot, query, builder);\n        query = query.where(predicate);\n\n        TypedQuery<String> createQuery = em.createQuery(query);\n        createQuery.setMaxResults(count);\n        return createQuery.getResultList();\n    }\n\n    @Override\n    public Customer save(Customer customer) {\n        return customerRepository.save(customer);\n    }\n\n    @Override\n    public boolean usernameExists(String username) {\n        return customerRepository.countByUsernameIgnoreCase(username) >= 1;\n    }\n\n    @Override\n    public Customer findByUsername(String username) {\n        return customerRepository.findByUsernameIgnoreCase(username);\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/filter/CustomerFilter.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer.filter;\n\nimport com.giffing.wicket.spring.boot.example.repository.DefaultFilter;\nimport lombok.Getter;\nimport lombok.Setter;\n\n@Getter\n@Setter\npublic class CustomerFilter extends DefaultFilter {\n\n    private Long id;\n\n    /**\n     * Filtering for the exact user name\n     */\n    private String username;\n\n    /**\n     * Filtering by lowercase username with wildcards at the start and the end.\n     */\n    private String usernameLike;\n\n    private String firstnameLike;\n\n    private String lastnameLike;\n\n    private boolean active;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/filter/CustomerSort.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer.filter;\n\nimport com.giffing.wicket.spring.boot.example.repository.Sort;\n\npublic enum CustomerSort implements Sort {\n    ID(\"id\"),\n    USERNAME(\"username\"),\n    FIRSTNAME(\"firstname\"),\n    LASTNAME(\"lastname\"),\n    ACTIVE(\"active\");\n\n    private final String sortName;\n\n    CustomerSort(String sortName) {\n        this.sortName = sortName;\n    }\n\n    @Override\n    public String getFieldName() {\n        return this.sortName;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/repository/services/customer/specs/CustomerSpecs.java",
    "content": "package com.giffing.wicket.spring.boot.example.repository.services.customer.specs;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.model.Customer_;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.springframework.data.jpa.domain.Specification;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic class CustomerSpecs {\n\n    public static Specification<Customer> hasId(final Long id) {\n        return (root, query, builder) -> builder.equal(root.get(Customer_.id), id);\n    }\n\n    public static Specification<Customer> hasUsername(final String username) {\n        return (root, query, builder) -> builder.equal(builder.lower(root.get(Customer_.username)), username.toLowerCase());\n    }\n\n    public static Specification<Customer> hasUsernameLike(final String username) {\n        return (root, query, builder) -> builder.like(builder.lower(root.get(Customer_.username)), \"%\" + username.toLowerCase() + \"%\");\n    }\n\n    public static Specification<Customer> hasFirstnameLike(final String firstname) {\n        return (root, query, builder) -> builder.like(builder.lower(root.get(Customer_.firstname)), \"%\" + firstname.toLowerCase() + \"%\");\n    }\n\n    public static Specification<Customer> hasLastnameLike(final String lastname) {\n        return (root, query, builder) -> builder.like(builder.lower(root.get(Customer_.lastname)), \"%\" + lastname.toLowerCase() + \"%\");\n    }\n\n    public static Specification<Customer> hasActive(final boolean active) {\n        return (root, query, builder) -> builder.equal(root.get(Customer_.active), active);\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/SpringBootWebPackageIdentifier.java",
    "content": "package com.giffing.wicket.spring.boot.example.web;\n\npublic interface SpringBootWebPackageIdentifier {\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/assets/base/CustomStylesCssRessourceReference.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.assets.base;\n\nimport org.apache.wicket.request.resource.CssResourceReference;\n\npublic class CustomStylesCssRessourceReference extends CssResourceReference {\n\n    public static final CustomStylesCssRessourceReference INSTANCE = new CustomStylesCssRessourceReference();\n\n    public CustomStylesCssRessourceReference() {\n        super(CustomStylesCssRessourceReference.class, \"custom.css\");\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/assets/base/custom.css",
    "content": ".navbar {\n    --bs-navbar-padding-x: 1;\n}\n\n.items {\n    padding-right: 5px;\n}"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/ActionPanel.html",
    "content": "<wicket:panel><span wicket:id=\"items\" class=\"items\"><span wicket:id=\"item\" /></span></wicket:panel>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/ActionPanel.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.action.panel;\n\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.AbstrractActionItem;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.list.BootstrapListView;\nimport org.apache.wicket.markup.html.list.ListItem;\nimport org.apache.wicket.markup.html.panel.Panel;\n\nimport java.util.List;\n\npublic class ActionPanel extends Panel {\n\n    public ActionPanel(String id, List<AbstrractActionItem> items) {\n        super(id);\n        add(new BootstrapListView<>(\"items\", items) {\n\n            @Override\n            protected void populateItem(ListItem<AbstrractActionItem> item) {\n                item.add(item.getModel().getObject());\n            }\n\n        });\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/AbstractActionItemLink.html",
    "content": "<wicket:panel>\n<a wicket:id=\"link\">\n\t<span aria-hidden=\"true\" wicket:id=\"icon\"></span>\n</a>\n</wicket:panel>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/AbstractActionItemLink.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.action.panel.items;\n\nimport de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.ajax.markup.html.AjaxLink;\n\npublic abstract class AbstractActionItemLink<T> extends AbstrractActionItem {\n\n    protected AbstractActionItemLink(IconType iconType) {\n        AjaxLink<T> link = new AjaxLink<T>(\"link\") {\n\n            @Override\n            public void onClick(AjaxRequestTarget target) {\n                AbstractActionItemLink.this.onClick(target);\n\n            }\n        };\n        add(link);\n        link.add(new Icon(\"icon\", iconType));\n    }\n\n    public abstract void onClick(AjaxRequestTarget target);\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/AbstrractActionItem.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.action.panel.items;\n\nimport org.apache.wicket.markup.html.panel.Panel;\n\npublic abstract class AbstrractActionItem extends Panel {\n\n    protected AbstrractActionItem() {\n        super(\"item\");\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/links/ActionItemLink.html",
    "content": "<wicket:panel>\n<a wicket:id=\"link\">\n\t<span aria-hidden=\"true\" wicket:id=\"icon\"></span>\n</a>\n</wicket:panel>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/links/ActionItemLink.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.action.panel.items.links;\n\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.AbstrractActionItem;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;\nimport org.apache.wicket.markup.html.link.AbstractLink;\n\npublic class ActionItemLink extends AbstrractActionItem {\n\n    public ActionItemLink(IconType iconType, AbstractLink link) {\n        add(link);\n        link.add(new Icon(\"icon\", iconType));\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/action/panel/items/yesno/YesNoLink.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.action.panel.items.yesno;\n\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.AbstractActionItemLink;\nimport com.giffing.wicket.spring.boot.example.web.html.modal.YesNoModal;\nimport com.giffing.wicket.spring.boot.example.web.pages.BasePage;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.markup.html.panel.EmptyPanel;\n\npublic abstract class YesNoLink<T> extends AbstractActionItemLink<T> {\n\n    protected YesNoLink(IconType iconType) {\n        super(iconType);\n    }\n\n    @Override\n    public void onClick(AjaxRequestTarget target) {\n        YesNoModal yesNoModal = new YesNoModal(\"defaultModal\") {\n\n            @Override\n            protected void yesClicked(AjaxRequestTarget target) {\n                YesNoLink.this.yesClicked(target);\n                close(target);\n                ((BasePage) getPage()).replaceDefaultModal(new EmptyPanel(\"defaultModal\"), target);\n            }\n        };\n        ((BasePage) getPage()).replaceDefaultModal(yesNoModal, target);\n        yesNoModal.appendShowDialogJavaScript(target);\n    }\n\n    protected abstract void yesClicked(AjaxRequestTarget target);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/notify/NotyJSReference.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.notify;\r\n\r\nimport org.apache.wicket.resource.JQueryPluginResourceReference;\r\n\r\npublic class NotyJSReference extends JQueryPluginResourceReference {\r\n\r\n    public static final NotyJSReference INSTANCE = new NotyJSReference();\r\n\r\n    public NotyJSReference() {\r\n        super(NotyJSReference.class, \"jquery.noty.js\");\r\n    }\r\n\r\n}"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/notify/NotyPackagedJSReference.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.notify;\r\n\r\nimport org.apache.wicket.resource.JQueryPluginResourceReference;\r\n\r\npublic class NotyPackagedJSReference extends JQueryPluginResourceReference {\r\n\r\n    public static final NotyPackagedJSReference INSTANCE = new NotyPackagedJSReference();\r\n\r\n    public NotyPackagedJSReference() {\r\n        super(NotyPackagedJSReference.class, \"jquery.noty.packaged.min.js\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/notify/NotyThemeBootstrapJSReference.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.general.notify;\r\n\r\nimport org.apache.wicket.resource.JQueryPluginResourceReference;\r\n\r\npublic class NotyThemeBootstrapJSReference extends JQueryPluginResourceReference {\r\n\r\n    public static final NotyThemeBootstrapJSReference INSTANCE = new NotyThemeBootstrapJSReference();\r\n\r\n    public NotyThemeBootstrapJSReference() {\r\n        super(NotyThemeBootstrapJSReference.class, \"noty.theme.bootstrap.js\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/notify/jquery.noty.js",
    "content": "/*!\r\n @package noty - jQuery Notification Plugin\r\n @version version: 2.4.1\r\n @contributors https://github.com/needim/noty/graphs/contributors\r\n\r\n @documentation Examples and Documentation - http://needim.github.com/noty/\r\n\r\n @license Licensed under the MIT licenses: http://www.opensource.org/licenses/mit-license.php\r\n */\r\n\r\nif (typeof Object.create !== 'function') {\r\n  Object.create = function (o) {\r\n    function F() {\r\n    }\r\n\r\n    F.prototype = o;\r\n    return new F();\r\n  };\r\n}\r\n\r\nvar NotyObject = {\r\n\r\n  init: function (options) {\r\n\r\n    // Mix in the passed in options with the default options\r\n    this.options = $.extend({}, $.noty.defaults, options);\r\n\r\n    this.options.layout = (this.options.custom) ? $.noty.layouts['inline'] : $.noty.layouts[this.options.layout];\r\n\r\n    if ($.noty.themes[this.options.theme]) {\r\n      this.options.theme = $.noty.themes[this.options.theme];\r\n      if (this.options.theme.template)\r\n        this.options.template = this.options.theme.template;\r\n\r\n      if (this.options.theme.animation)\r\n        this.options.animation = this.options.theme.animation;\r\n    }\r\n    else {\r\n      this.options.themeClassName = this.options.theme;\r\n    }\r\n\r\n    this.options = $.extend({}, this.options, this.options.layout.options);\r\n\r\n    if (this.options.id) {\r\n      if ($.noty.store[this.options.id]) {\r\n        return $.noty.store[this.options.id];\r\n      }\r\n    } else {\r\n      this.options.id = 'noty_' + (new Date().getTime() * Math.floor(Math.random() * 1000000));\r\n    }\r\n\r\n    // Build the noty dom initial structure\r\n    this._build();\r\n\r\n    // return this so we can chain/use the bridge with less code.\r\n    return this;\r\n  }, // end init\r\n\r\n  _build: function () {\r\n\r\n    // Generating noty bar\r\n    var $bar = $('<div class=\"noty_bar noty_type_' + this.options.type + '\"></div>').attr('id', this.options.id);\r\n    $bar.append(this.options.template).find('.noty_text').html(this.options.text);\r\n\r\n    this.$bar = (this.options.layout.parent.object !== null) ? $(this.options.layout.parent.object).css(this.options.layout.parent.css).append($bar) : $bar;\r\n\r\n    if (this.options.themeClassName)\r\n      this.$bar.addClass(this.options.themeClassName).addClass('noty_container_type_' + this.options.type);\r\n\r\n    // Set buttons if available\r\n    if (this.options.buttons) {\r\n\r\n      var $buttons;\r\n      // Try find container for buttons in presented template, and create it if not found\r\n      if (this.$bar.find('.noty_buttons').length > 0) {\r\n        $buttons = this.$bar.find('.noty_buttons');\r\n      } else {\r\n        $buttons = $('<div/>').addClass('noty_buttons');\r\n        (this.options.layout.parent.object !== null) ? this.$bar.find('.noty_bar').append($buttons) : this.$bar.append($buttons);\r\n      }\r\n\r\n      var self = this;\r\n\r\n      $.each(this.options.buttons, function (i, button) {\r\n        var $button = $('<button/>').addClass((button.addClass) ? button.addClass : 'gray').html(button.text).attr('id', button.id ? button.id : 'button-' + i)\r\n            .attr('title', button.title)\r\n            .appendTo($buttons)\r\n            .on('click', function (event) {\r\n              if ($.isFunction(button.onClick)) {\r\n                button.onClick.call($button, self, event);\r\n              }\r\n            });\r\n      });\r\n    } else {\r\n      // If buttons is not available, then remove containers if exist\r\n      this.$bar.find('.noty_buttons').remove();\r\n    }\r\n\r\n    if (this.options.progressBar && this.options.timeout) {\r\n      var $progressBar = $('<div/>').addClass('noty_progress_bar');\r\n      (this.options.layout.parent.object !== null) ? this.$bar.find('.noty_bar').append($progressBar) : this.$bar.append($progressBar);\r\n    }\r\n\r\n    // For easy access\r\n    this.$message     = this.$bar.find('.noty_message');\r\n    this.$closeButton = this.$bar.find('.noty_close');\r\n    this.$buttons     = this.$bar.find('.noty_buttons');\r\n    this.$progressBar = this.$bar.find('.noty_progress_bar');\r\n\r\n    $.noty.store[this.options.id] = this; // store noty for api\r\n\r\n  }, // end _build\r\n\r\n  show: function () {\r\n\r\n    var self = this;\r\n\r\n    (self.options.custom) ? self.options.custom.find(self.options.layout.container.selector).append(self.$bar) : $(self.options.layout.container.selector).append(self.$bar);\r\n\r\n    if (self.options.theme && self.options.theme.style)\r\n      self.options.theme.style.apply(self);\r\n\r\n    ($.type(self.options.layout.css) === 'function') ? this.options.layout.css.apply(self.$bar) : self.$bar.css(this.options.layout.css || {});\r\n\r\n    self.$bar.addClass(self.options.layout.addClass);\r\n\r\n    self.options.layout.container.style.apply($(self.options.layout.container.selector), [self.options.within]);\r\n\r\n    self.showing = true;\r\n\r\n    if (self.options.theme && self.options.theme.style)\r\n      self.options.theme.callback.onShow.apply(this);\r\n\r\n    if ($.inArray('click', self.options.closeWith) > -1)\r\n      self.$bar.css('cursor', 'pointer').on('click', function (evt) {\r\n        self.stopPropagation(evt);\r\n        if (self.options.callback.onCloseClick) {\r\n          self.options.callback.onCloseClick.apply(self);\r\n        }\r\n        self.close();\r\n      });\r\n\r\n    if ($.inArray('hover', self.options.closeWith) > -1)\r\n      self.$bar.one('mouseenter', function () {\r\n        self.close();\r\n      });\r\n\r\n    if ($.inArray('button', self.options.closeWith) > -1)\r\n      self.$closeButton.one('click', function (evt) {\r\n        self.stopPropagation(evt);\r\n        self.close();\r\n      });\r\n\r\n    if ($.inArray('button', self.options.closeWith) == -1)\r\n      self.$closeButton.remove();\r\n\r\n    if (self.options.callback.beforeShow)\r\n      self.options.callback.beforeShow.apply(self);\r\n\r\n    if (typeof self.options.animation.open == 'string') {\r\n      self.animationTypeOpen = 'css';\r\n      self.$bar.css('min-height', self.$bar.innerHeight());\r\n      self.$bar.on('click', function (e) {\r\n        self.wasClicked = true;\r\n      });\r\n      self.$bar.show();\r\n\r\n      if (self.options.callback.onShow)\r\n        self.options.callback.onShow.apply(self);\r\n\r\n      self.$bar.addClass(self.options.animation.open).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {\r\n        if (self.options.callback.afterShow) self.options.callback.afterShow.apply(self);\r\n        self.showing = false;\r\n        self.shown   = true;\r\n        self.bindTimeout();\r\n        if (self.hasOwnProperty('wasClicked')) {\r\n          self.$bar.off('click', function (e) {\r\n            self.wasClicked = true;\r\n          });\r\n          self.close();\r\n        }\r\n      });\r\n\r\n    } else if (typeof self.options.animation.open == 'object' && self.options.animation.open == null) {\r\n      self.animationTypeOpen = 'none';\r\n      self.showing           = false;\r\n      self.shown             = true;\r\n      self.$bar.show();\r\n      self.bindTimeout();\r\n\r\n      if (self.options.callback.onShow)\r\n        self.options.callback.onShow.apply(self);\r\n\r\n      self.$bar.queue(function () {\r\n        if (self.options.callback.afterShow)\r\n          self.options.callback.afterShow.apply(self);\r\n      });\r\n\r\n    } else {\r\n      self.animationTypeOpen = 'anim';\r\n\r\n      if (self.options.callback.onShow)\r\n        self.options.callback.onShow.apply(self);\r\n\r\n      self.$bar.animate(\r\n          self.options.animation.open,\r\n          self.options.animation.speed,\r\n          self.options.animation.easing,\r\n          function () {\r\n            if (self.options.callback.afterShow) self.options.callback.afterShow.apply(self);\r\n            self.showing = false;\r\n            self.shown   = true;\r\n            self.bindTimeout();\r\n          });\r\n    }\r\n\r\n    return this;\r\n\r\n  }, // end show\r\n\r\n  bindTimeout: function () {\r\n    var self = this;\r\n\r\n    // If noty is have a timeout option\r\n    if (self.options.timeout) {\r\n\r\n      if (self.options.progressBar && self.$progressBar) {\r\n        self.$progressBar.css({\r\n          transition: 'all ' + self.options.timeout + 'ms linear',\r\n          width: '0%'\r\n        });\r\n      }\r\n\r\n      self.queueClose(self.options.timeout);\r\n      self.$bar.on('mouseenter', self.dequeueClose.bind(self));\r\n      self.$bar.on('mouseleave', self.queueClose.bind(self, self.options.timeout));\r\n    }\r\n\r\n  },\r\n\r\n  dequeueClose: function () {\r\n    var self = this;\r\n\r\n    if (self.options.progressBar) {\r\n      this.$progressBar.css({\r\n        transition: 'none',\r\n        width: '100%'\r\n      });\r\n    }\r\n\r\n    if (!this.closeTimer) return;\r\n    clearTimeout(this.closeTimer);\r\n    this.closeTimer = null;\r\n  },\r\n\r\n  queueClose: function (timeout) {\r\n    var self = this;\r\n\r\n    if (self.options.progressBar) {\r\n      self.$progressBar.css({\r\n        transition: 'all ' + self.options.timeout + 'ms linear',\r\n        width: '0%'\r\n      });\r\n    }\r\n\r\n    if (this.closeTimer) return;\r\n    self.closeTimer = window.setTimeout(function () {\r\n      self.close();\r\n    }, timeout);\r\n    return self.closeTimer;\r\n  },\r\n\r\n  close: function () {\r\n    if (this.$progressBar) {\r\n      this.$progressBar.remove();\r\n    }\r\n\r\n    if (this.closeTimer) this.dequeueClose();\r\n\r\n    if (this.closed) return;\r\n    if (this.$bar && this.$bar.hasClass('i-am-closing-now')) return;\r\n\r\n    var self = this;\r\n\r\n    if (this.showing && (this.animationTypeOpen == 'anim' || this.animationTypeOpen == 'none')) {\r\n      self.$bar.queue(\r\n          function () {\r\n            self.close.apply(self);\r\n          }\r\n      );\r\n      return;\r\n    } else if (this.showing && this.animationTypeOpen == 'css') {\r\n      self.$bar.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {\r\n        self.close();\r\n      });\r\n    }\r\n\r\n    if (!this.shown && !this.showing) { // If we are still waiting in the queue just delete from queue\r\n      var queue = [];\r\n      $.each($.noty.queue, function (i, n) {\r\n        if (n.options.id != self.options.id) {\r\n          queue.push(n);\r\n        }\r\n      });\r\n      $.noty.queue = queue;\r\n      return;\r\n    }\r\n\r\n    self.$bar.addClass('i-am-closing-now');\r\n\r\n    if (self.options.callback.onClose) {\r\n      self.options.callback.onClose.apply(self);\r\n    }\r\n\r\n    if (typeof self.options.animation.close == 'string') {\r\n      self.$bar.removeClass(self.options.animation.open).addClass(self.options.animation.close).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {\r\n        if (self.options.callback.afterClose) self.options.callback.afterClose.apply(self);\r\n        self.closeCleanUp();\r\n      });\r\n\r\n    } else if (typeof self.options.animation.close == 'object' && self.options.animation.close == null) {\r\n      self.$bar.dequeue().hide(0, function () {\r\n        if (self.options.callback.afterClose) self.options.callback.afterClose.apply(self);\r\n        self.closeCleanUp();\r\n      });\r\n\r\n    } else {\r\n      self.$bar.clearQueue().stop().animate(\r\n          self.options.animation.close,\r\n          self.options.animation.speed,\r\n          self.options.animation.easing,\r\n          function () {\r\n            if (self.options.callback.afterClose) self.options.callback.afterClose.apply(self);\r\n          })\r\n          .promise().done(function () {\r\n        self.closeCleanUp();\r\n      });\r\n    }\r\n\r\n  }, // end close\r\n\r\n  closeCleanUp: function () {\r\n\r\n    var self = this;\r\n\r\n    // Modal Cleaning\r\n    if (self.options.modal) {\r\n      $.notyRenderer.setModalCount(-1);\r\n      if ($.notyRenderer.getModalCount() == 0 && !$.noty.queue.length) $('.noty_modal').fadeOut(self.options.animation.fadeSpeed, function () {\r\n        $(this).remove();\r\n      });\r\n    }\r\n\r\n    // Layout Cleaning\r\n    $.notyRenderer.setLayoutCountFor(self, -1);\r\n    if ($.notyRenderer.getLayoutCountFor(self) == 0) $(self.options.layout.container.selector).remove();\r\n\r\n    // Make sure self.$bar has not been removed before attempting to remove it\r\n    if (typeof self.$bar !== 'undefined' && self.$bar !== null) {\r\n\r\n      if (typeof self.options.animation.close == 'string') {\r\n        self.$bar.css('transition', 'all 10ms ease').css('border', 0).css('margin', 0).height(0);\r\n        self.$bar.one('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {\r\n          self.$bar.remove();\r\n          self.$bar   = null;\r\n          self.closed = true;\r\n\r\n          if (self.options.theme.callback && self.options.theme.callback.onClose) {\r\n            self.options.theme.callback.onClose.apply(self);\r\n          }\r\n\r\n          self.handleNext();\r\n        });\r\n      } else {\r\n        self.$bar.remove();\r\n        self.$bar   = null;\r\n        self.closed = true;\r\n\r\n        self.handleNext();\r\n      }\r\n    } else {\r\n      self.handleNext();\r\n    }\r\n\r\n  }, // end close clean up\r\n\r\n  handleNext: function () {\r\n    var self = this;\r\n\r\n    delete $.noty.store[self.options.id]; // deleting noty from store\r\n\r\n    if (self.options.theme.callback && self.options.theme.callback.onClose) {\r\n      self.options.theme.callback.onClose.apply(self);\r\n    }\r\n\r\n    if (!self.options.dismissQueue) {\r\n      // Queue render\r\n      $.noty.ontap = true;\r\n\r\n      $.notyRenderer.render();\r\n    }\r\n\r\n    if (self.options.maxVisible > 0 && self.options.dismissQueue) {\r\n      $.notyRenderer.render();\r\n    }\r\n  },\r\n\r\n  setText: function (text) {\r\n    if (!this.closed) {\r\n      this.options.text = text;\r\n      this.$bar.find('.noty_text').html(text);\r\n    }\r\n    return this;\r\n  },\r\n\r\n  setType: function (type) {\r\n    if (!this.closed) {\r\n      this.options.type = type;\r\n      this.options.theme.style.apply(this);\r\n      this.options.theme.callback.onShow.apply(this);\r\n    }\r\n    return this;\r\n  },\r\n\r\n  setTimeout: function (time) {\r\n    if (!this.closed) {\r\n      var self             = this;\r\n      this.options.timeout = time;\r\n      self.$bar.delay(self.options.timeout).promise().done(function () {\r\n        self.close();\r\n      });\r\n    }\r\n    return this;\r\n  },\r\n\r\n  stopPropagation: function (evt) {\r\n    evt = evt || window.event;\r\n    if (typeof evt.stopPropagation !== \"undefined\") {\r\n      evt.stopPropagation();\r\n    }\r\n    else {\r\n      evt.cancelBubble = true;\r\n    }\r\n  },\r\n\r\n  closed : false,\r\n  showing: false,\r\n  shown  : false\r\n\r\n}; // end NotyObject\r\n\r\n$.notyRenderer = {};\r\n\r\n$.notyRenderer.init = function (options) {\r\n\r\n  // Renderer creates a new noty\r\n  var notification = Object.create(NotyObject).init(options);\r\n\r\n  if (notification.options.killer)\r\n    $.noty.closeAll();\r\n\r\n  (notification.options.force) ? $.noty.queue.unshift(notification) : $.noty.queue.push(notification);\r\n\r\n  $.notyRenderer.render();\r\n\r\n  return ($.noty.returns == 'object') ? notification : notification.options.id;\r\n};\r\n\r\n$.notyRenderer.render = function () {\r\n\r\n  var instance = $.noty.queue[0];\r\n\r\n  if ($.type(instance) === 'object') {\r\n    if (instance.options.dismissQueue) {\r\n      if (instance.options.maxVisible > 0) {\r\n        if ($(instance.options.layout.container.selector + ' > li').length < instance.options.maxVisible) {\r\n          $.notyRenderer.show($.noty.queue.shift());\r\n        }\r\n        else {\r\n\r\n        }\r\n      }\r\n      else {\r\n        $.notyRenderer.show($.noty.queue.shift());\r\n      }\r\n    }\r\n    else {\r\n      if ($.noty.ontap) {\r\n        $.notyRenderer.show($.noty.queue.shift());\r\n        $.noty.ontap = false;\r\n      }\r\n    }\r\n  }\r\n  else {\r\n    $.noty.ontap = true; // Queue is over\r\n  }\r\n\r\n};\r\n\r\n$.notyRenderer.show = function (notification) {\r\n\r\n  if (notification.options.modal) {\r\n    $.notyRenderer.createModalFor(notification);\r\n    $.notyRenderer.setModalCount(+1);\r\n  }\r\n\r\n  // Where is the container?\r\n  if (notification.options.custom) {\r\n    if (notification.options.custom.find(notification.options.layout.container.selector).length == 0) {\r\n      notification.options.custom.append($(notification.options.layout.container.object).addClass('i-am-new'));\r\n    }\r\n    else {\r\n      notification.options.custom.find(notification.options.layout.container.selector).removeClass('i-am-new');\r\n    }\r\n  }\r\n  else {\r\n    if ($(notification.options.layout.container.selector).length == 0) {\r\n      $('body').append($(notification.options.layout.container.object).addClass('i-am-new'));\r\n    }\r\n    else {\r\n      $(notification.options.layout.container.selector).removeClass('i-am-new');\r\n    }\r\n  }\r\n\r\n  $.notyRenderer.setLayoutCountFor(notification, +1);\r\n\r\n  notification.show();\r\n};\r\n\r\n$.notyRenderer.createModalFor = function (notification) {\r\n  if ($('.noty_modal').length == 0) {\r\n    var modal = $('<div/>').addClass('noty_modal').addClass(notification.options.theme).data('noty_modal_count', 0);\r\n\r\n    if (notification.options.theme.modal && notification.options.theme.modal.css)\r\n      modal.css(notification.options.theme.modal.css);\r\n\r\n    modal.prependTo($('body')).fadeIn(notification.options.animation.fadeSpeed);\r\n\r\n    if ($.inArray('backdrop', notification.options.closeWith) > -1)\r\n      modal.on('click', function () {\r\n        $.noty.closeAll();\r\n      });\r\n  }\r\n};\r\n\r\n$.notyRenderer.getLayoutCountFor = function (notification) {\r\n  return $(notification.options.layout.container.selector).data('noty_layout_count') || 0;\r\n};\r\n\r\n$.notyRenderer.setLayoutCountFor = function (notification, arg) {\r\n  return $(notification.options.layout.container.selector).data('noty_layout_count', $.notyRenderer.getLayoutCountFor(notification) + arg);\r\n};\r\n\r\n$.notyRenderer.getModalCount = function () {\r\n  return $('.noty_modal').data('noty_modal_count') || 0;\r\n};\r\n\r\n$.notyRenderer.setModalCount = function (arg) {\r\n  return $('.noty_modal').data('noty_modal_count', $.notyRenderer.getModalCount() + arg);\r\n};\r\n\r\n// This is for custom container\r\n$.fn.noty = function (options) {\r\n  options.custom = $(this);\r\n  return $.notyRenderer.init(options);\r\n};\r\n\r\n$.noty         = {};\r\n$.noty.queue   = [];\r\n$.noty.ontap   = true;\r\n$.noty.layouts = {};\r\n$.noty.themes  = {};\r\n$.noty.returns = 'object';\r\n$.noty.store   = {};\r\n\r\n$.noty.get = function (id) {\r\n  return $.noty.store.hasOwnProperty(id) ? $.noty.store[id] : false;\r\n};\r\n\r\n$.noty.close = function (id) {\r\n  return $.noty.get(id) ? $.noty.get(id).close() : false;\r\n};\r\n\r\n$.noty.setText = function (id, text) {\r\n  return $.noty.get(id) ? $.noty.get(id).setText(text) : false;\r\n};\r\n\r\n$.noty.setType = function (id, type) {\r\n  return $.noty.get(id) ? $.noty.get(id).setType(type) : false;\r\n};\r\n\r\n$.noty.clearQueue = function () {\r\n  $.noty.queue = [];\r\n};\r\n\r\n$.noty.closeAll = function () {\r\n  $.noty.clearQueue();\r\n  $.each($.noty.store, function (id, noty) {\r\n    noty.close();\r\n  });\r\n};\r\n\r\nvar windowAlert = window.alert;\r\n\r\n$.noty.consumeAlert = function (options) {\r\n  window.alert = function (text) {\r\n    if (options)\r\n      options.text = text;\r\n    else\r\n      options = {text: text};\r\n\r\n    $.notyRenderer.init(options);\r\n  };\r\n};\r\n\r\n$.noty.stopConsumeAlert = function () {\r\n  window.alert = windowAlert;\r\n};\r\n\r\n$.noty.defaults = {\r\n  layout      : 'topRight',\r\n  theme       : 'relax',\r\n  type        : 'alert',\r\n  text        : '',\r\n  progressBar : false,\r\n  dismissQueue: true,\r\n  template    : '<div class=\"noty_message\"><span class=\"noty_text\"></span><div class=\"noty_close\"></div></div>',\r\n  animation   : {\r\n    open     : {height: 'toggle'},\r\n    close    : {height: 'toggle'},\r\n    easing   : 'swing',\r\n    speed    : 500,\r\n    fadeSpeed: 'fast'\r\n  },\r\n  timeout     : false,\r\n  force       : false,\r\n  modal       : false,\r\n  maxVisible  : 5,\r\n  killer      : false,\r\n  closeWith   : ['click'],\r\n  callback    : {\r\n    beforeShow  : function () {\r\n    },\r\n    onShow      : function () {\r\n    },\r\n    afterShow   : function () {\r\n    },\r\n    onClose     : function () {\r\n    },\r\n    afterClose  : function () {\r\n    },\r\n    onCloseClick: function () {\r\n    }\r\n  },\r\n  buttons     : false\r\n};\r\n\r\n$(window).on('resize', function () {\r\n  $.each($.noty.layouts, function (index, layout) {\r\n    layout.container.style.apply($(layout.container.selector));\r\n  });\r\n});\r\n\r\n// Helpers\r\nwindow.noty = function noty(options) {\r\n  return $.notyRenderer.init(options);\r\n};\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/general/notify/noty.theme.bootstrap.js",
    "content": "$.noty.themes.bootstrapTheme = {\r\n  name    : 'bootstrapTheme',\r\n  modal   : {\r\n    css: {\r\n      position       : 'fixed',\r\n      width          : '100%',\r\n      height         : '100%',\r\n      backgroundColor: '#000',\r\n      zIndex         : 10000,\r\n      opacity        : 0.6,\r\n      display        : 'none',\r\n      left           : 0,\r\n      top            : 0,\r\n      wordBreak      : 'break-all'\r\n    }\r\n  },\r\n  style   : function () {\r\n\r\n    var containerSelector = this.options.layout.container.selector;\r\n    $(containerSelector).addClass('list-group');\r\n\r\n    this.$closeButton.append('<span aria-hidden=\"true\">&times;</span><span class=\"sr-only\">Close</span>');\r\n    this.$closeButton.addClass('close');\r\n\r\n    this.$bar.addClass(\"list-group-item\").css('padding', '0px').css('position', 'relative');\r\n\r\n    this.$progressBar.css({\r\n      position       : 'absolute',\r\n      left           : 0,\r\n      bottom         : 0,\r\n      height         : 4,\r\n      width          : '100%',\r\n      backgroundColor: '#000000',\r\n      opacity        : 0.2,\r\n      '-ms-filter'   : 'progid:DXImageTransform.Microsoft.Alpha(Opacity=20)',\r\n      filter         : 'alpha(opacity=20)'\r\n    });\r\n\r\n    switch (this.options.type) {\r\n      case 'alert':\r\n      case 'notification':\r\n        this.$bar.addClass(\"list-group-item-info\");\r\n        break;\r\n      case 'warning':\r\n        this.$bar.addClass(\"list-group-item-warning\");\r\n        break;\r\n      case 'error':\r\n        this.$bar.addClass(\"list-group-item-danger\");\r\n        break;\r\n      case 'information':\r\n        this.$bar.addClass(\"list-group-item-info\");\r\n        break;\r\n      case 'success':\r\n        this.$bar.addClass(\"list-group-item-success\");\r\n        break;\r\n    }\r\n\r\n    this.$message.css({\r\n      textAlign: 'center',\r\n      padding  : '8px 10px 9px',\r\n      width    : 'auto',\r\n      position : 'relative'\r\n    });\r\n  },\r\n  callback: {\r\n    onShow : function () { },\r\n    onClose: function () { }\r\n  }\r\n};\r\n\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/autocomplete/AutoCompleteTextField.css",
    "content": "div.wicket-aa {\n    background-color:white;\n    border:1px solid #2387C4;\n    color:black;\n}\ndiv.wicket-aa ul {\n   list-style-image:none;\n   list-style-position:outside;\n   list-style-type:none;\n   margin:0pt;\n   padding:5px;\n}\ndiv.wicket-aa ul li.selected {\n    background-color:#2387C4;\n}"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/autocomplete/AutoCompleteTextField.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.autocomplete;\n\nimport org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;\nimport org.apache.wicket.markup.head.CssHeaderItem;\nimport org.apache.wicket.markup.head.IHeaderResponse;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.request.resource.CssResourceReference;\n\npublic abstract class AutoCompleteTextField\n        extends org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField<String> {\n\n    protected AutoCompleteTextField(String id, AutoCompleteSettings settings) {\n        super(id, settings);\n    }\n\n    protected AutoCompleteTextField(String id, IModel<String> model, AutoCompleteSettings settings) {\n        super(id, model, settings);\n    }\n\n    @Override\n    public void renderHead(final IHeaderResponse response) {\n        super.renderHead(response);\n\n        response.render(CssHeaderItem.forReference(new CssResourceReference(\n                AutoCompleteTextField.class, \"AutoCompleteTextField.css\")));\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/basic/YesNoLabel.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.basic;\n\nimport org.apache.wicket.markup.ComponentTag;\nimport org.apache.wicket.markup.MarkupStream;\nimport org.apache.wicket.markup.html.basic.Label;\nimport org.apache.wicket.model.IModel;\n\npublic class YesNoLabel extends Label {\n\n    public YesNoLabel(String id, IModel<Boolean> model) {\n        super(id, model);\n    }\n\n    @Override\n    public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {\n        var active = (boolean) getDefaultModelObject();\n        var resourceKey = active ? \"yes\" : \"no\";\n        replaceComponentTagBody(markupStream, openTag, getString(resourceKey));\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/border/behavior/ValidationMsgBehavior.html",
    "content": "<wicket:border>\n\t<div>\n\t\t<wicket:body />\n\t</div>\n</wicket:border>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/border/behavior/ValidationMsgBehavior.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.border.behavior;\n\n\nimport org.apache.wicket.Component;\nimport org.apache.wicket.feedback.FeedbackMessage;\nimport org.apache.wicket.markup.html.border.BorderBehavior;\nimport org.apache.wicket.markup.html.form.FormComponent;\n\npublic class ValidationMsgBehavior extends BorderBehavior {\n\n    private static final long serialVersionUID = 1L;\n\n    @Override\n    public void beforeRender(Component c) {\n        if (c instanceof FormComponent<?> fc && !fc.isValid()) {\n            super.beforeRender(c);\n        }\n    }\n\n    @Override\n    public void afterRender(Component component) {\n        if (component instanceof FormComponent<?> fc && !fc.isValid()) {\n            String error;\n            if (fc.hasFeedbackMessage()) {\n                FeedbackMessage first = fc.getFeedbackMessages().first();\n                first.markRendered();\n                error = first.getMessage().toString();\n\n            } else {\n                error = \"Your input is invalid.\";\n            }\n            fc.getResponse().write(\"*<span class=\\\"invalid-feedback\\\">\" + error + \"</span>\");\n            super.afterRender(component);\n        }\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/form/ValidationForm.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.form;\n\nimport de.agilecoders.wicket.core.markup.html.bootstrap.form.BootstrapForm;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.util.visit.IVisitor;\n\npublic class ValidationForm<T> extends BootstrapForm<T> {\n\n    private static final long serialVersionUID = 1L;\n\n    private IVisitor visitor = new ValidationFormVisitor<>();\n\n    public ValidationForm(String id, IModel<T> model) {\n        super(id, model);\n    }\n\n    @Override\n    protected void onBeforeRender() {\n        super.onBeforeRender();\n        visitChildren(visitor);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/form/ValidationFormVisitor.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.form;\n\nimport com.giffing.wicket.spring.boot.example.web.html.border.behavior.ValidationMsgBehavior;\nimport org.apache.wicket.Component;\nimport org.apache.wicket.markup.html.form.FormComponent;\nimport org.apache.wicket.util.io.IClusterable;\nimport org.apache.wicket.util.visit.IVisit;\nimport org.apache.wicket.util.visit.IVisitor;\n\nimport java.io.Serializable;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class ValidationFormVisitor<R> implements IVisitor<Component, R>, IClusterable, Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private Set<FormComponent<?>> visited = new HashSet<>();\n\n    @Override\n    public void component(Component c, IVisit<R> visit) {\n        if (c instanceof FormComponent<?> fc && !visited.contains(c)) {\n            c.add(new ValidationMsgBehavior());\n            visited.add(fc);\n        }\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/form/focus/FocusBehaviour.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.form.focus;\n\nimport org.apache.wicket.Component;\nimport org.apache.wicket.behavior.Behavior;\nimport org.apache.wicket.markup.head.IHeaderResponse;\nimport org.apache.wicket.markup.head.OnDomReadyHeaderItem;\n\npublic class FocusBehaviour extends Behavior {\n\n    @Override\n    public void renderHead(Component component, IHeaderResponse response) {\n        super.renderHead(component, response);\n        OnDomReadyHeaderItem focusComponentHeaderItem = OnDomReadyHeaderItem\n                .forScript(\"document.getElementById('%s').focus();\".formatted(component.getMarkupId()));\n        response.render(focusComponentHeaderItem);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/modal/YesNoModal.html",
    "content": "<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <title>TextContentModal</title>\n</head>\n<body>\n<wicket:extend>\n    <div wicket:id=\"content\"></div>\n</wicket:extend>\n</body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/modal/YesNoModal.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.modal;\n\nimport de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.markup.html.panel.Panel;\n\npublic abstract class YesNoModal extends Modal<Panel> {\n\n    protected YesNoModal(String id) {\n        super(id);\n        var yesNoPanel = new YesNoPanel(\"content\") {\n\n            @Override\n            protected void yesClicked(AjaxRequestTarget target) {\n                YesNoModal.this.yesClicked(target);\n            }\n\n            @Override\n            protected void noClicked(AjaxRequestTarget target) {\n                YesNoModal.this.noClicked(target);\n            }\n\n        };\n        add(yesNoPanel);\n    }\n\n    protected void noClicked(AjaxRequestTarget target) {\n        close(target);\n    }\n\n    protected abstract void yesClicked(AjaxRequestTarget target);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/modal/YesNoPanel.html",
    "content": "<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n        <title>TextContentModal</title>\n</head>\n<body>\n<wicket:panel>\n        <label>Are you sure?</label>\n        <hr>\n        <a wicket:id=\"yes\" class=\"btn btn-primary\">yes</a>\n        <a wicket:id=\"no\" class=\"btn\">no</a>\n</wicket:panel>\n</body>\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/modal/YesNoPanel.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.modal;\n\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.ajax.markup.html.AjaxLink;\nimport org.apache.wicket.markup.html.panel.Panel;\n\npublic abstract class YesNoPanel extends Panel {\n\n\n    protected YesNoPanel(String id) {\n        super(id);\n\n        add(new AjaxLink<>(\"yes\") {\n            @Override\n            public void onClick(AjaxRequestTarget target) {\n                YesNoPanel.this.yesClicked(target);\n            }\n        });\n\n        add(new AjaxLink<>(\"no\") {\n            @Override\n            public void onClick(AjaxRequestTarget target) {\n                YesNoPanel.this.noClicked(target);\n            }\n        });\n\n    }\n\n    protected abstract void noClicked(AjaxRequestTarget target);\n\n    protected abstract void yesClicked(AjaxRequestTarget target);\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/panel/FeedbackPanel.html",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<body>\n<wicket:panel>\n  <div wicket:id=\"feedbackul\" class=\"feedbackPanel\">\n    <div wicket:id=\"messages\">\n      <p wicket:id=\"message\">A message</p>\n    </div>\n  </div>\n</wicket:panel>\n</body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/panel/FeedbackPanel.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.panel;\n\npublic class FeedbackPanel extends org.apache.wicket.markup.html.panel.FeedbackPanel {\n\n    public FeedbackPanel(String string) {\n        super(string);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/repeater/data/table/filter/AbstractCheckBoxFilter.html",
    "content": "<wicket:panel xmlns:wicket=\"http://wicket.apache.org\"><input type=\"checkbox\" wicket:id=\"filter\"/></wicket:panel>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/repeater/data/table/filter/AbstractCheckBoxFilter.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.repeater.data.table.filter;\n\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.AbstractFilter;\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilterForm;\nimport org.apache.wicket.markup.html.form.CheckBox;\nimport org.apache.wicket.markup.html.form.FormComponentUpdatingBehavior;\nimport org.apache.wicket.markup.html.form.TextField;\nimport org.apache.wicket.model.IModel;\n\npublic class AbstractCheckBoxFilter extends AbstractFilter {\n\n    private final CheckBox filter;\n\n    public AbstractCheckBoxFilter(final String id, final IModel<Boolean> model, final FilterForm<?> form) {\n        super(id, form);\n        filter = createTextFieldComponent(\"filter\", model);\n        enableFocusTracking(filter);\n        add(filter);\n    }\n\n    public CheckBox createTextFieldComponent(String componentId, final IModel<Boolean> model) {\n        CheckBox checkBox = new CheckBox(componentId, model);\n        checkBox.add(new FormComponentUpdatingBehavior());\n        return checkBox;\n    }\n\n    /**\n     * @return underlying {@link TextField} form component that represents this filter\n     */\n    public final CheckBox getFilter() {\n        return filter;\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/repeater/data/table/filter/AbstractTextFieldFilter.html",
    "content": "<wicket:panel xmlns:wicket=\"http://wicket.apache.org\"><input type=\"text\" wicket:id=\"filter\"/></wicket:panel>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/html/repeater/data/table/filter/AbstractTextFieldFilter.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.html.repeater.data.table.filter;\n\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.AbstractFilter;\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilterForm;\nimport org.apache.wicket.markup.html.form.TextField;\nimport org.apache.wicket.model.IModel;\n\npublic class AbstractTextFieldFilter<T> extends AbstractFilter {\n\n    private final TextField<T> filter;\n\n    public AbstractTextFieldFilter(final String id, final IModel<T> model, final FilterForm<?> form) {\n        super(id, form);\n        filter = createTextFieldComponent(\"filter\", model);\n        enableFocusTracking(filter);\n        add(filter);\n    }\n\n    public TextField<T> createTextFieldComponent(String componentId, final IModel<T> model) {\n        return new TextField<>(componentId, model);\n    }\n\n    /**\n     * @return underlying {@link TextField} form component that represents this filter\n     */\n    public final TextField<T> getFilter() {\n        return filter;\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/BaseAuthenticatedPage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <meta charset=\"utf-8\" />\n    <title>Spring Boot - Apache Wicket Quickstart</title>\n\n</head>\n<body>\n<wicket:extend>\n        <header wicket:id=\"navbar\" class=\"bs-docs-nav\"></header>\n        <wicket:child/>\n        <wicket:container wicket:id=\"footer\"></wicket:container>\n</wicket:extend>\n</body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/BaseAuthenticatedPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages;\n\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.footer.Footer;\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.ChatPage;\nimport de.agilecoders.wicket.core.Bootstrap;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapExternalLink;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuBookmarkablePageLink;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuDivider;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.dropdown.MenuHeader;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.navbar.*;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.utilities.BackgroundColorBehavior;\nimport de.agilecoders.wicket.core.settings.ITheme;\nimport de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome6IconType;\nimport org.apache.wicket.Component;\nimport org.apache.wicket.markup.html.WebMarkupContainer;\nimport org.apache.wicket.markup.html.link.AbstractLink;\nimport org.apache.wicket.model.Model;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic abstract class BaseAuthenticatedPage extends BasePage {\n\n    protected BaseAuthenticatedPage(final PageParameters parameters) {\n        super(parameters);\n        add(newNavbar(\"navbar\"));\n        add(newNavigation(\"navigation\"));\n        add(new Footer(\"footer\"));\n    }\n\n    protected Navbar newNavbar(String markupId) {\n        var navbar = new Navbar(markupId)\n                .setPosition(Navbar.Position.TOP)\n                .setInverted(true)\n                .setBackgroundColor(BackgroundColorBehavior.Color.Dark);\n\n        navbar.setBrandName(Model.of(\"Wicket\"));\n        navbar.addComponents(NavbarComponents.transform(\n                Navbar.ComponentPosition.LEFT,\n                new NavbarButton<Void>(CustomerListPage.class, Model.of(\"Customers\")).setIconType(FontAwesome6IconType.person_s),\n                new NavbarButton<Void>(ChatPage.class, Model.of(\"Chat\")).setIconType(FontAwesome6IconType.rocketchat),\n                new NavbarExternalLink(Model.of(\"https://github.com/MarcGiffing/wicket-spring-boot\"))\n                        .setLabel(Model.of(\"Github\"))\n                        .setTarget(BootstrapExternalLink.Target.blank)\n                        .setIconType(FontAwesome6IconType.upload_s))\n        );\n        var dropdown = new NavbarDropDownButton(Model.of(\"Themes\")) {\n\n            @Override\n            public boolean isActive(Component item) {\n                return false;\n            }\n\n            @Override\n            protected List<AbstractLink> newSubMenuButtons(final String buttonMarkupId) {\n                final List<AbstractLink> subMenu = new ArrayList<>();\n                subMenu.add(new MenuHeader(Model.of(\"all available themes:\")));\n                subMenu.add(new MenuDivider());\n\n                var settings = Bootstrap.getSettings(getApplication());\n                var themes = settings.getThemeProvider().available();\n\n                for (final ITheme theme : themes) {\n                    var params = new PageParameters();\n                    params.set(\"theme\", theme.name());\n                    subMenu.add(new MenuBookmarkablePageLink<Void>(getPageClass(), params, Model.of(theme.name())));\n                }\n\n                return subMenu;\n            }\n        }.setIconType(FontAwesome6IconType.book_s);\n\n        navbar.addComponents(new ImmutableNavbarComponent(dropdown, Navbar.ComponentPosition.RIGHT));\n        return navbar;\n    }\n\n    private void configureTheme(PageParameters pageParameters) {\n        var theme = pageParameters.get(\"theme\");\n\n        if (!theme.isEmpty()) {\n            var settings = Bootstrap.getSettings(getApplication());\n            settings.getActiveThemeProvider().setActiveTheme(theme.toString(\"\"));\n        }\n    }\n\n    @Override\n    protected void onConfigure() {\n        super.onConfigure();\n        configureTheme(getPageParameters());\n    }\n\n    protected boolean hasNavigation() {\n        return false;\n    }\n\n    private Component newNavigation(String markupId) {\n        var navigation = new WebMarkupContainer(markupId);\n        navigation.setVisible(hasNavigation());\n        return navigation;\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/BaseAuthenticatedPage.properties",
    "content": "id=Id\nusername=Username\nfirstname=Firstname\nlastname=Lastname\nactive=Active\npassword=Password\nusernameLike=Username\nfirstnameLike=Firstname\nlastnameLike=Lastname\n\nyes=Yes\nno=No\n\nUsernameExistsValidator=Username already exists!\n\nFeedbackMessage.CSS.undefined=bg-primary\nFeedbackMessage.CSS.debug=bg-info\nFeedbackMessage.CSS.info=bg-success\nFeedbackMessage.CSS.success=bg-success\nFeedbackMessage.CSS.warning=bg-warning\nFeedbackMessage.CSS.error=bg-danger\nFeedbackMessage.CSS.fatal=bg-danger\n\nlogin.label=Login"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/BasePage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n    <head>\n        <meta charset=\"utf-8\">\n        <title>Apache Wicket &amp; Spring Bootstrap</title>\n        <meta wicket:id=\"viewport\">\n        <meta wicket:id=\"description\">\n        <meta wicket:id=\"ie-edge\">\n        <wicket:header-items/>\n    </head>\n\n    <body style=\"padding-top: 60px\">\n        <a name=\"top\" style=\"display: none;\"></a>\n        <a class=\"visually-hidden\" href=\"#content\">Skip navigation</a>\n        <div wicket:id=\"defaultModal\"></div>\n        <wicket:child/>\n\n        <pre style=\"display:none\" wicket:id=\"code-internal\"></pre>\n        <wicket:container wicket:id=\"footer-container\"/>\n    </body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/BasePage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages;\n\nimport com.giffing.wicket.spring.boot.example.web.assets.base.CustomStylesCssRessourceReference;\nimport com.giffing.wicket.spring.boot.example.web.general.notify.NotyJSReference;\nimport com.giffing.wicket.spring.boot.example.web.general.notify.NotyPackagedJSReference;\nimport com.giffing.wicket.spring.boot.example.web.general.notify.NotyThemeBootstrapJSReference;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.block.Code;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.form.FormGroup;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.html.IeEdgeMetaTag;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.html.MetaTag;\nimport de.agilecoders.wicket.core.markup.html.bootstrap.html.MobileViewportMetaTag;\nimport de.agilecoders.wicket.core.markup.html.references.BootlintHeaderItem;\nimport de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome6CssReference;\nimport org.apache.wicket.MarkupContainer;\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.markup.head.CssHeaderItem;\nimport org.apache.wicket.markup.head.IHeaderResponse;\nimport org.apache.wicket.markup.head.JavaScriptHeaderItem;\nimport org.apache.wicket.markup.head.filter.HeaderResponseContainer;\nimport org.apache.wicket.markup.html.GenericWebPage;\nimport org.apache.wicket.markup.html.form.FormComponent;\nimport org.apache.wicket.markup.html.panel.EmptyPanel;\nimport org.apache.wicket.model.Model;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\n\npublic class BasePage extends GenericWebPage<Void> {\n\n    private MarkupContainer defaultModal;\n\n    public BasePage(final PageParameters parameters) {\n        super(parameters);\n\n        defaultModal = new EmptyPanel(\"defaultModal\");\n        defaultModal.setMarkupId(\"defaultModal\");\n        defaultModal.setOutputMarkupId(true);\n        queue(defaultModal);\n\n        MobileViewportMetaTag mvt = new MobileViewportMetaTag(\"viewport\");\n        mvt.setWidth(\"device-width\");\n        mvt.setInitialScale(\"1\");\n        add(mvt);\n        add(new IeEdgeMetaTag(\"ie-edge\"));\n        add(new MetaTag(\"description\", Model.of(\"description\"), Model.of(\"Wicket\")));\n\n        add(new Code(\"code-internal\"));\n        add(new HeaderResponseContainer(\"footer-container\", \"footer-container\"));\n    }\n\n    @Override\n    public void renderHead(IHeaderResponse response) {\n        super.renderHead(response);\n\n        response.render(CssHeaderItem.forReference(CustomStylesCssRessourceReference.INSTANCE));\n        response.render(CssHeaderItem.forReference(FontAwesome6CssReference.instance()));\n        response.render(JavaScriptHeaderItem.forReference(NotyJSReference.INSTANCE));\n        response.render(JavaScriptHeaderItem.forReference(NotyPackagedJSReference.INSTANCE));\n        response.render(JavaScriptHeaderItem.forReference(NotyThemeBootstrapJSReference.INSTANCE));\n\n        if (!getRequest().getRequestParameters().getParameterValue(\"bootlint\").isNull()) {\n            response.render(BootlintHeaderItem.INSTANCE);\n        }\n    }\n\n    public void replaceDefaultModal(MarkupContainer newModal, AjaxRequestTarget target) {\n        newModal.setMarkupId(defaultModal.getMarkupId());\n        newModal.setOutputMarkupId(true);\n        defaultModal.replaceWith(newModal);\n        target.add(newModal);\n        defaultModal = newModal;\n    }\n\n    protected void queueFormComponent(FormComponent<?> formComponent) {\n        var formGroup = new FormGroup(formComponent.getId() + \"Border\");\n        formGroup.useFormComponentLabel(true);\n        formGroup.add(formComponent);\n        queue(formGroup);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/WicketBootstrapInitializer.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages;\n\nimport com.giffing.wicket.spring.boot.context.extensions.ApplicationInitExtension;\nimport com.giffing.wicket.spring.boot.context.extensions.WicketApplicationInitConfiguration;\nimport de.agilecoders.wicket.core.Bootstrap;\nimport de.agilecoders.wicket.core.settings.BootstrapSettings;\nimport de.agilecoders.wicket.core.settings.CookieThemeProvider;\nimport de.agilecoders.wicket.sass.BootstrapSass;\nimport de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchTheme;\nimport de.agilecoders.wicket.themes.markup.html.bootswatch.BootswatchThemeProvider;\nimport org.apache.wicket.markup.head.filter.JavaScriptFilteredIntoFooterHeaderResponse;\nimport org.apache.wicket.protocol.http.WebApplication;\n\n@ApplicationInitExtension\npublic class WicketBootstrapInitializer implements WicketApplicationInitConfiguration {\n    @Override\n    public void init(WebApplication webApplication) {\n        var settings = new BootstrapSettings();\n        Bootstrap.builder().withBootstrapSettings(settings).install(webApplication);\n        var themeProvider = new BootswatchThemeProvider(BootswatchTheme.Cerulean);\n\n        settings.setJsResourceFilterName(\"footer-container\")\n                .setThemeProvider(themeProvider)\n                .setActiveThemeProvider(new CookieThemeProvider());\n\n        BootstrapSass.install(webApplication);\n        webApplication.getCspSettings().blocking().disabled();\n        webApplication.getMarkupSettings().setStripWicketTags(true);\n\n        webApplication.getHeaderResponseDecorators().add(response -> new JavaScriptFilteredIntoFooterHeaderResponse(response, \"footer-container\"));\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/CustomerListPage.html",
    "content": "<html xmlns:wicket=\"http://wicket.apache.org\">\n<body>\n<wicket:extend>\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>Customers\n                <a wicket:id=\"create\"></a>\n            </h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        <div wicket:id=\"feedback\"></div>\n\n        <form wicket:id=\"form\">\n            <div class=\"row\">\n                <div class=\"col-xs-4 col-md-4\">\n                    <div wicket:id=\"idBorder\">\n                        <input type=\"text\" wicket:id=\"id\" class=\"form-control\"/>\n                    </div>\n                    <div wicket:id=\"usernameLikeBorder\">\n                        <input type=\"text\" wicket:id=\"usernameLike\" class=\"form-control\"/>\n                    </div>\n                </div>\n                <div class=\"col-xs-4 col-md-4\">\n                    <div wicket:id=\"firstnameLikeBorder\">\n                        <input type=\"text\" wicket:id=\"firstnameLike\" class=\"form-control\"/>\n                    </div>\n                    <div wicket:id=\"lastnameLikeBorder\">\n                        <input type=\"text\" wicket:id=\"lastnameLike\" class=\"form-control\"/>\n                    </div>\n                </div>\n                <div class=\"col-xs-4 col-md-4\">\n                    <div wicket:id=\"activeBorder\">\n                        <input type=\"checkbox\" wicket:id=\"active\" class=\"form-check-input\"/>\n                    </div>\n                </div>\n            </div>\n            <button type=\"submit\" class=\"btn btn-primary\">Search</button>\n            <button type=\"submit\" class=\"btn btn-secondary\" wicket:id=\"cancel\">Cancel</button>\n\n        </form>\n        <hr/>\n        <form wicket:id=\"filterForm\">\n            <table wicket:id=\"table\" class=\"table table-striped table-condensed table-hover\"></table>\n        </form>\n    </div>\n</wicket:extend>\n</body>\n\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/CustomerListPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport com.giffing.wicket.spring.boot.context.scan.WicketHomePage;\r\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.AbstrractActionItem;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.BaseAuthenticatedPage;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.events.CustomerDeletedEvent;\r\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WebSocketMessageBroadcaster;\r\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapBookmarkablePageLink;\r\nimport de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;\r\nimport de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome6IconType;\r\nimport org.apache.wicket.Component;\r\nimport org.apache.wicket.ajax.AjaxRequestTarget;\r\nimport org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;\r\nimport org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilterForm;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilterToolbar;\r\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.FilteredPropertyColumn;\r\nimport org.apache.wicket.markup.html.form.Button;\r\nimport org.apache.wicket.markup.html.form.CheckBox;\r\nimport org.apache.wicket.markup.html.form.TextField;\r\nimport org.apache.wicket.markup.html.link.BookmarkablePageLink;\r\nimport org.apache.wicket.markup.repeater.Item;\r\nimport org.apache.wicket.model.CompoundPropertyModel;\r\nimport org.apache.wicket.model.IModel;\r\nimport org.apache.wicket.model.Model;\r\nimport org.apache.wicket.model.PropertyModel;\r\nimport org.apache.wicket.model.ResourceModel;\r\nimport org.apache.wicket.protocol.ws.api.WebSocketBehavior;\r\nimport org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;\r\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\r\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\r\nimport org.apache.wicket.spring.injection.annot.SpringBean;\r\nimport org.apache.wicket.validation.validator.StringValidator;\r\nimport org.wicketstuff.annotation.mount.MountPath;\r\n\r\nimport com.giffing.wicket.spring.boot.example.model.Customer;\r\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\r\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerFilter;\r\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerSort;\r\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.ActionPanel;\r\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.links.ActionItemLink;\r\nimport com.giffing.wicket.spring.boot.example.web.general.action.panel.items.yesno.YesNoLink;\r\nimport com.giffing.wicket.spring.boot.example.web.html.basic.YesNoLabel;\r\nimport com.giffing.wicket.spring.boot.example.web.html.form.ValidationForm;\r\nimport com.giffing.wicket.spring.boot.example.web.html.panel.FeedbackPanel;\r\nimport com.giffing.wicket.spring.boot.example.web.html.repeater.data.table.filter.AbstractCheckBoxFilter;\r\nimport com.giffing.wicket.spring.boot.example.web.html.repeater.data.table.filter.AbstractTextFieldFilter;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.create.CustomerCreatePage;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.edit.CustomerEditPage;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.events.CustomerChangedEvent;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.model.CustomerDataProvider;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.model.UsernameSearchTextField;\r\n\r\n@WicketHomePage\r\n@MountPath(\"custsomers\")\r\n@AuthorizeInstantiation(\"USER\")\r\npublic class CustomerListPage extends BaseAuthenticatedPage {\r\n\r\n\t@SpringBean\r\n\tprivate CustomerRepositoryService customerRepositoryService;\r\n\r\n\t@SpringBean\r\n\tprivate WebSocketMessageBroadcaster webSocketMessageBroadcaster;\r\n\t\r\n\tprivate IModel<CustomerFilter> customerFilterModel;\r\n\r\n\tprivate FilterForm<CustomerFilter> filterForm;\r\n\r\n\tDataTable<Customer, CustomerSort> dataTable;\r\n\t\r\n\tpublic CustomerListPage() {\r\n\t\tsuper(new PageParameters());\r\n\t\tFeedbackPanel feedbackPanel = new FeedbackPanel(\"feedback\");\r\n\t\tfeedbackPanel.setOutputMarkupId(true);\r\n\t\tadd(feedbackPanel);\r\n\t\t\r\n\t\tadd(getWebSocketBehavior(feedbackPanel));\r\n\t\t\r\n\t\tcustomerFilterModel = new CompoundPropertyModel<>(new CustomerFilter());\r\n\t\tCustomerDataProvider customerDataProvider = new CustomerDataProvider(customerFilterModel);\r\n\t\t\r\n\t\tqueue(new BootstrapBookmarkablePageLink<Customer>(\"create\", CustomerCreatePage.class, Buttons.Type.Link)\r\n\t\t\t\t.setIconType(FontAwesome6IconType.plus_s)\r\n\t\t\t\t.setSize(Buttons.Size.Large));\r\n\t\t\r\n\t\tqueue(new ValidationForm<>(\"form\", customerFilterModel));\r\n\t\tqueueFormComponent(new TextField<>(\"id\"));\r\n\t\tqueueFormComponent(new UsernameSearchTextField(\"usernameLike\"));\r\n\t\tqueueFormComponent(new TextField<String>(\"firstnameLike\").add(StringValidator.minimumLength(3)));\r\n\t\tqueueFormComponent(new TextField<String>(\"lastnameLike\").add(StringValidator.minimumLength(3)));\r\n\t\tqueueFormComponent(new CheckBox(\"active\"));\r\n\t\tqueue(cancelButton());\r\n\t\t\r\n\t\tcustomerDataTable(customerDataProvider);\r\n\r\n\t}\r\n\r\n\tprivate WebSocketBehavior getWebSocketBehavior(FeedbackPanel feedbackPanel) {\r\n\t\treturn new WebSocketBehavior() {\r\n\r\n\t\t\t@Override\r\n\t\t\tprotected void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {\r\n\t\t\t\tif (message instanceof CustomerChangedEvent event) {\r\n\t\t\t\t\tinfo(\"Customer changed \" + event.getCustomer().getFirstname() + \" \" + event.getCustomer().getLastname());\r\n\t\t\t\t\thandler.add(feedbackPanel);\r\n\t\t\t\t}\r\n\t\t\t\tif (message instanceof CustomerDeletedEvent event) {\r\n\t\t\t\t\twarn(\"Customer deleted: \" + event.getCustomer().getFirstname() + \" \" + event.getCustomer().getLastname());\r\n\t\t\t\t\thandler.add(feedbackPanel);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t};\r\n\t}\r\n\r\n\tprivate Button cancelButton() {\r\n\t\tButton cancelButton = new Button(\"cancel\") {\r\n\r\n\t\t\t@Override\r\n\t\t\tpublic void onSubmit() {\r\n\t\t\t\tcustomerFilterModel.setObject(new CustomerFilter());\r\n\t\t\t\tgetForm().clearInput();\r\n\t\t\t\tfilterForm.clearInput();\r\n\t\t\t}\r\n\r\n\t\t};\r\n\t\tcancelButton.setDefaultFormProcessing(false);\r\n\t\treturn cancelButton;\r\n\t}\r\n\r\n\tprivate void customerDataTable(CustomerDataProvider customerDataProvider) {\r\n\r\n\t\tfilterForm = new FilterForm<>(\"filterForm\", customerDataProvider);\r\n\t\tqueue(filterForm);\r\n\r\n\t\tList<IColumn<Customer, CustomerSort>> columns = new ArrayList<>();\r\n\t\tcolumns.add(idColumn());\r\n\t\tcolumns.add(usernameColumn());\r\n\t\tcolumns.add(firstnameColumn());\r\n\t\tcolumns.add(lastnameColumn());\r\n\t\tcolumns.add(activeColumn());\r\n\t\tcolumns.add(actionColumn());\r\n\r\n\t\tdataTable = new AjaxFallbackDefaultDataTable<>(\"table\", columns,\r\n\t\t\t\tcustomerDataProvider, 10);\r\n\t\tdataTable.setOutputMarkupId(true);\r\n\t\tFilterToolbar filterToolbar = new FilterToolbar(dataTable, filterForm);\r\n\r\n\t\tdataTable.addTopToolbar(filterToolbar);\r\n\t\tqueue(dataTable);\r\n\t}\r\n\r\n\tprivate PropertyColumn<Customer, CustomerSort> idColumn() {\r\n\t\treturn new PropertyColumn<>(Model.of(\"Id\"), CustomerSort.ID,\r\n\t\t\t\tCustomerSort.ID.getFieldName());\r\n\t}\r\n\t\r\n\tprivate FilteredPropertyColumn<Customer, CustomerSort> usernameColumn() {\r\n\t\treturn new FilteredPropertyColumn<>(new ResourceModel(\"username\"), CustomerSort.USERNAME,\r\n                CustomerSort.USERNAME.getFieldName()) {\r\n\r\n            @Override\r\n            public Component getFilter(String componentId, FilterForm<?> form) {\r\n                return new AbstractTextFieldFilter<String>(componentId,\r\n                        new PropertyModel<>(form.getModel(), \"usernameLike\"), form) {\r\n\r\n                    @Override\r\n                    public TextField<String> createTextFieldComponent(String componentId, IModel<String> model) {\r\n                        return new UsernameSearchTextField(componentId, model);\r\n                    }\r\n\r\n                };\r\n            }\r\n\r\n        };\r\n\t}\r\n\t\r\n\tprivate FilteredPropertyColumn<Customer, CustomerSort> firstnameColumn() {\r\n\t\treturn new FilteredPropertyColumn<>(new ResourceModel(\"firstname\"),\r\n                CustomerSort.FIRSTNAME, CustomerSort.FIRSTNAME.getFieldName()) {\r\n\r\n            @Override\r\n            public Component getFilter(String componentId, FilterForm<?> form) {\r\n                return new AbstractTextFieldFilter<String>(componentId,\r\n                        new PropertyModel<>(form.getModel(), \"firstnameLike\"), form) {\r\n\r\n                    @Override\r\n                    public TextField<String> createTextFieldComponent(String componentId, IModel<String> model) {\r\n                        return new TextField<>(componentId, model);\r\n                    }\r\n\r\n                };\r\n            }\r\n\r\n        };\r\n\t}\r\n\t\r\n\tprivate FilteredPropertyColumn<Customer, CustomerSort> lastnameColumn() {\r\n\t\treturn new FilteredPropertyColumn<>(new ResourceModel(\"lastname\"), CustomerSort.LASTNAME,\r\n                CustomerSort.LASTNAME.getFieldName()) {\r\n\r\n            @Override\r\n            public Component getFilter(String componentId, FilterForm<?> form) {\r\n                return new AbstractTextFieldFilter<String>(componentId,\r\n                        new PropertyModel<>(form.getModel(), \"lastnameLike\"), form) {\r\n\r\n                    @Override\r\n                    public TextField<String> createTextFieldComponent(String componentId, IModel<String> model) {\r\n                        return new TextField<>(componentId, model);\r\n                    }\r\n\r\n                };\r\n            }\r\n\r\n        };\r\n\t}\r\n\r\n\tprivate FilteredPropertyColumn<Customer, CustomerSort> activeColumn() {\r\n\t\treturn new FilteredPropertyColumn<>(new ResourceModel(\"active\"), CustomerSort.ACTIVE,\r\n                CustomerSort.ACTIVE.getFieldName()) {\r\n\r\n            @Override\r\n            public Component getFilter(String componentId, FilterForm<?> form) {\r\n                return new AbstractCheckBoxFilter(componentId, new PropertyModel<>(form.getModel(), \"active\"), form);\r\n            }\r\n\r\n            @Override\r\n            public void populateItem(Item<ICellPopulator<Customer>> item, String componentId,\r\n                                     IModel<Customer> rowModel) {\r\n                item.add(new YesNoLabel(componentId, (IModel<Boolean>) getDataModel(rowModel)));\r\n            }\r\n\r\n        };\r\n\t}\r\n\t\r\n\tprivate AbstractColumn<Customer, CustomerSort> actionColumn() {\r\n\t\treturn new AbstractColumn<>(Model.of(\"Action\")) {\r\n\r\n            @Override\r\n            public void populateItem(Item<ICellPopulator<Customer>> cellItem, String componentId,\r\n                                     IModel<Customer> rowModel) {\r\n                List<AbstrractActionItem> abstractItems = new ArrayList<>();\r\n                var params = new PageParameters();\r\n                params.add(CustomerEditPage.CUSTOMER_ID_PARAM, rowModel.getObject().getId());\r\n                params.add(CustomerEditPage.PAGE_REFERENCE_ID, getPageId());\r\n\r\n                abstractItems.add(editActionItem(params));\r\n                abstractItems.add(deleteActionItem(rowModel));\r\n                cellItem.add(new ActionPanel(componentId, abstractItems));\r\n            }\r\n\r\n            private static ActionItemLink editActionItem(PageParameters params) {\r\n                return new ActionItemLink(\r\n                        FontAwesome6IconType.pen_s,\r\n                        new BookmarkablePageLink<Customer>(\"link\", CustomerEditPage.class, params)\r\n                );\r\n            }\r\n\r\n            private YesNoLink<Object> deleteActionItem(IModel<Customer> rowModel) {\r\n                return new YesNoLink<>(FontAwesome6IconType.trash_s) {\r\n\r\n                    @Override\r\n                    protected void yesClicked(AjaxRequestTarget target) {\r\n                        customerRepositoryService.delete(rowModel.getObject().getId());\r\n                        webSocketMessageBroadcaster.sendToAll(new CustomerDeletedEvent(rowModel.getObject()));\r\n                        target.add(dataTable);\r\n                    }\r\n                };\r\n            }\r\n        };\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/create/CustomerCreatePage.html",
    "content": "<html xmlns:wicket=\"http://wicket.apache.org\">\n<body>\n<wicket:extend>\n\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>Customer Create</h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        <form wicket:id=\"form\">\n            <div class=\"row col-xs-4 col-md-4\">\n                <div wicket:id=\"usernameBorder\">\n                    <input type=\"text\" class=\"form-control\" wicket:id=\"username\"/>\n                </div>\n            </div>\n            <div class=\"row col-xs-4 col-md-4\">\n                <div wicket:id=\"firstnameBorder\">\n                    <input type=\"text\" class=\"form-control\" wicket:id=\"firstname\"/>\n                </div>\n            </div>\n            <div class=\"row col-xs-4 col-md-4\">\n                <div wicket:id=\"lastnameBorder\">\n                    <input type=\"text\" class=\"form-control\" wicket:id=\"lastname\"/>\n                </div>\n            </div>\n            <div class=\"row col-xs-4 col-md-4\">\n                <div wicket:id=\"activeBorder\">\n                    <input type=\"checkbox\" class=\"form-check-input\" wicket:id=\"active\"/>\n                </div>\n            </div>\n            <div class=\"row col-xs-4 col-md-4\">\n                <hr>\n            </div>\n            <div class=\"row col-xs-1 col-md-1\">\n                <button type=\"submit\" class=\"btn btn-primary\" wicket:id=\"submit\">Save</button>\n                <button type=\"submit\" class=\"btn\" wicket:id=\"cancel\">Cancel</button>\n            </div>\n        </form>\n    </div>\n</wicket:extend>\n</body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/create/CustomerCreatePage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.create;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.web.html.form.ValidationForm;\nimport com.giffing.wicket.spring.boot.example.web.pages.BaseAuthenticatedPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.events.CustomerChangedEvent;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.model.UsernameTextField;\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WebSocketMessageBroadcaster;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.Component;\nimport org.apache.wicket.PageReference;\nimport org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;\nimport org.apache.wicket.markup.html.form.Button;\nimport org.apache.wicket.markup.html.form.CheckBox;\nimport org.apache.wicket.markup.html.form.FormComponent;\nimport org.apache.wicket.markup.html.form.RequiredTextField;\nimport org.apache.wicket.model.CompoundPropertyModel;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.wicketstuff.annotation.mount.MountPath;\n\n@MountPath(\"customers/create\")\n@AuthorizeInstantiation(\"USER\")\npublic class CustomerCreatePage extends BaseAuthenticatedPage {\n\n    @SpringBean\n    private CustomerRepositoryService service;\n\n    @SpringBean\n    private WebSocketMessageBroadcaster webSocketMessageBroadcaster;\n\n    @Getter\n    CompoundPropertyModel<Customer> customerModel;\n\n    @Setter\n    private Integer pageReferenceId;\n\n    public CustomerCreatePage(Integer pageId) {\n        super(new PageParameters());\n        this.pageReferenceId = pageId;\n    }\n\n    public CustomerCreatePage() {\n        super(new PageParameters());\n        customerModel = new CompoundPropertyModel<>(new Customer());\n        queue(new ValidationForm<>(\"form\", customerModel));\n        queueFormComponent(usernameField());\n        queueFormComponent(new RequiredTextField<>(\"firstname\"));\n        queueFormComponent(new RequiredTextField<>(\"lastname\"));\n        queueFormComponent(new CheckBox(\"active\"));\n        queue(submitButton());\n        queue(cancelButton());\n    }\n\n\n    private FormComponent<String> usernameField() {\n        return new UsernameTextField(\"username\") {\n\n            @Override\n            public boolean isEnabled() {\n                return isCreatePage();\n            }\n        };\n    }\n\n    public boolean isCreatePage() {\n        return true;\n    }\n\n    private Component submitButton() {\n        return new Button(\"submit\") {\n            @Override\n            public void onSubmit() {\n                var customer = customerModel.getObject();\n                service.save(customer);\n                webSocketMessageBroadcaster.sendToAll(new CustomerChangedEvent(customer));\n                if (pageReferenceId != null) {\n                    setResponsePage(new PageReference(pageReferenceId).getPage());\n                } else {\n                    setResponsePage(CustomerListPage.class);\n                }\n            }\n        };\n    }\n\n    private Component cancelButton() {\n        Button cancelButton = new Button(\"cancel\") {\n\n            @Override\n            public void onSubmit() {\n                if (pageReferenceId != null) {\n                    setResponsePage(new PageReference(pageReferenceId).getPage());\n                } else {\n                    setResponsePage(CustomerListPage.class);\n                }\n            }\n\n        };\n        cancelButton.setDefaultFormProcessing(false);\n        return cancelButton;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/edit/CustomerEditPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.edit;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.create.CustomerCreatePage;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.apache.wicket.util.string.StringValue;\nimport org.wicketstuff.annotation.mount.MountPath;\n\nimport java.text.MessageFormat;\n\n@MountPath(\"customers/edit/${\" + CustomerEditPage.CUSTOMER_ID_PARAM + \"}\")\n@AuthorizeInstantiation(\"USER\")\npublic class CustomerEditPage extends CustomerCreatePage {\n\n    public static final String CUSTOMER_ID_PARAM = \"id\";\n    public static final String PAGE_REFERENCE_ID = \"referenceId\";\n\n    @SpringBean\n    private CustomerRepositoryService service;\n\n    public CustomerEditPage(PageParameters params) {\n        super();\n        var customerIdParam = params.get(CUSTOMER_ID_PARAM);\n        if (customerIdParam.isEmpty() || !StringUtils.isNumeric(customerIdParam.toString())) {\n            getSession().error(MessageFormat.format(getString(\"param.customer.id.missing\"), customerIdParam));\n//\t\t\t\"Missing customer id \" + stringValue\n            setResponsePage(CustomerListPage.class);\n        }\n        Long customerId = customerIdParam.toLong();\n        var customer = service.findById(customerId);\n        if (customer == null) {\n            getSession().error(MessageFormat.format(getString(\"customer.not-found\"), customerId.toString()));\n            setResponsePage(CustomerListPage.class);\n        }\n\n        var pageReferfenceIdParam = params.get(PAGE_REFERENCE_ID);\n        if (!pageReferfenceIdParam.isEmpty() || StringUtils.isNumeric(pageReferfenceIdParam.toString())) {\n            setPageReferenceId(pageReferfenceIdParam.toInteger());\n        }\n\n        getCustomerModel().setObject(customer);\n    }\n\n    @Override\n    public boolean isCreatePage() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/edit/CustomerEditPage.properties",
    "content": "param.customer.id.missing=Missing customer id {0}\ncustomer.not-found=Customer not found {0}"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/events/CustomerChangedEvent.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.events;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\n\n@Getter\n@RequiredArgsConstructor\npublic class CustomerChangedEvent implements IWebSocketPushMessage {\n\n    private final Customer customer;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/events/CustomerDeletedEvent.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.events;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\n\n@Getter\n@RequiredArgsConstructor\npublic class CustomerDeletedEvent implements IWebSocketPushMessage {\n\n    private final Customer customer;\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/model/CustomerDataProvider.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.model;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerFilter;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerSort;\nimport com.giffing.wicket.spring.boot.example.web.wicket.dataprovider.DefaultDataProvider;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.wicket.injection.Injector;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\n\n@Getter\n@Setter\npublic class CustomerDataProvider extends DefaultDataProvider<Customer, Long, CustomerFilter, CustomerSort, CustomerRepositoryService> {\n\n    @SpringBean\n    private CustomerRepositoryService filterService;\n\n    private IModel<CustomerFilter> customerFilterModel;\n\n    public CustomerDataProvider(IModel<CustomerFilter> customerFilterModel) {\n        this.customerFilterModel = customerFilterModel;\n        Injector.get().inject(this);\n    }\n\n    @Override\n    public CustomerFilter getFilter() {\n        return customerFilterModel.getObject();\n    }\n\n    @Override\n    public void setFilter(CustomerFilter filterModel) {\n        customerFilterModel.setObject(filterModel);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/model/UsernameSearchTextField.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.model;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.apache.wicket.validation.validator.StringValidator;\n\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.web.html.autocomplete.AutoCompleteTextField;\n\npublic class UsernameSearchTextField extends AutoCompleteTextField {\n\n\tprivate static final Integer MINIMUM_INPUT_LENGTH = 3;\n\t\n\t@SpringBean\n\tprivate CustomerRepositoryService service;\n\t\n\tpublic UsernameSearchTextField(String id) {\n\t\tsuper(id, settings());\n\t\tinitComponent();\n\t}\n\n\tpublic UsernameSearchTextField(String componentId, IModel<String> model) {\n\t\tsuper(componentId, model, settings());\n\t\tinitComponent();\n\t}\n\n\tprivate void initComponent() {\n\t\tadd(StringValidator.minimumLength(MINIMUM_INPUT_LENGTH));\n\t}\n\n\t@Override\n\tprotected Iterator<String> getChoices(String username) {\n\t\tList<String> result = new ArrayList<>();\n\t\tif(username != null && username.length() >= MINIMUM_INPUT_LENGTH){\n\t\t\tresult = service.findUsernames(10, username);\n\t\t}\n\t\treturn result.iterator();\n\t}\n\t\n\tprivate static AutoCompleteSettings settings(){\n\t\treturn new AutoCompleteSettings().setMinInputLength(MINIMUM_INPUT_LENGTH);\n\t}\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/customers/model/UsernameTextField.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.model;\n\nimport org.apache.wicket.injection.Injector;\nimport org.apache.wicket.markup.html.form.TextField;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.apache.wicket.validation.IValidatable;\nimport org.apache.wicket.validation.IValidator;\nimport org.apache.wicket.validation.ValidationError;\nimport org.apache.wicket.validation.validator.StringValidator;\n\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\n\npublic class UsernameTextField extends TextField<String>{\n\n\t@SpringBean\n\tprivate CustomerRepositoryService service;\n\t\n\tpublic UsernameTextField(String id) {\n\t\tsuper(id);\n\t\tInjector.get().inject(this);\n\t\tadd(StringValidator.minimumLength(3));\n\t\tsetRequired(true);\n\t\tadd(new UsernameExistsValidator());\n\t}\n\n\tpublic class UsernameExistsValidator implements IValidator<String>{\n\n\t\t@Override\n\t\tpublic void validate(IValidatable<String> validatable) {\n\t\t\tfinal String field = validatable.getValue();\n\t\t\tif(service.usernameExists(field)){\n\t\t\t\tValidationError error = new ValidationError();\n\t\t\t\terror.setMessage(getString(getClass().getSimpleName()));\n\t\t\t\tvalidatable.error(error);\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/AccessDeniedPage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>Access Denied!</title>\n\n</head>\n<body>\n<wicket:extend>\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>Access Denied!</h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        ...\n    </div>\n\n</wicket:extend>\n</body>\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/AccessDeniedPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.errors;\n\nimport com.giffing.wicket.spring.boot.context.scan.WicketAccessDeniedPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.BasePage;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.wicket.request.http.WebResponse;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.wicketstuff.annotation.mount.MountPath;\n\n@MountPath(\"problem\")\n@WicketAccessDeniedPage\npublic class AccessDeniedPage extends BasePage {\n\n    public AccessDeniedPage(PageParameters parameters) {\n        super(parameters);\n    }\n\n    @Override\n    protected void setHeaders(final WebResponse response) {\n        response.setStatus(HttpServletResponse.SC_FORBIDDEN);\n    }\n\n    @Override\n    public boolean isErrorPage() {\n        return true;\n    }\n\n    @Override\n    public boolean isVersioned() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/ExpiredPage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>Expired</title>\n\n</head>\n<body>\n<wicket:extend>\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>Expired!</h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        ...\n    </div>\n</wicket:extend>\n</body>\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/ExpiredPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.errors;\n\nimport com.giffing.wicket.spring.boot.example.web.pages.BasePage;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.apache.wicket.request.http.WebResponse;\n\nimport com.giffing.wicket.spring.boot.context.scan.WicketExpiredPage;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\n\n@WicketExpiredPage\npublic class ExpiredPage extends BasePage {\n\n    public ExpiredPage(PageParameters parameters) {\n        super(parameters);\n    }\n\n    @Override\n    protected void setHeaders(final WebResponse response) {\n        response.setStatus(HttpServletResponse.SC_GONE);\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/InternalErrorPage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>Internal Error</title>\n\n</head>\n<body>\n<wicket:extend>\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>Internal Error!</h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        ...\n    </div>\n\n</wicket:extend>\n</body>\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/errors/InternalErrorPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.errors;\n\nimport com.giffing.wicket.spring.boot.context.scan.WicketInternalErrorPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.BasePage;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\n\n@WicketInternalErrorPage\npublic class InternalErrorPage extends BasePage {\n    public InternalErrorPage(PageParameters parameters) {\n        super(parameters);\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/footer/Footer.html",
    "content": "<html xmlns:wicket=\"http://wicket.apache.org\">\n    <head>\n        <title>Footer</title>\n    </head>\n    <body>\n        <wicket:panel>\n            <footer class=\"footer\">\n                <div class=\"container\">\n                </div>\n            </footer>\n        </wicket:panel>\n    </body>\n</html>\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/footer/Footer.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.footer;\n\nimport org.apache.wicket.markup.html.panel.Panel;\n\npublic class Footer extends Panel {\n    public Footer(String markupId) {\n        super(markupId);\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/login/LoginPage.html",
    "content": "<!DOCTYPE html>\n<html xmlns:wicket=\"http://wicket.apache.org\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>Spring Boot - Apache Wicket Quickstart</title>\n\n</head>\n<body>\n<wicket:extend>\n    <header class=\"jumbotron subhead\" id=\"content\">\n        <div class=\"container\">\n            <h1>\n                <wicket:message key=\"login.label\">login</wicket:message>\n            </h1>\n        </div>\n    </header>\n\n    <div class=\"container\">\n        <form wicket:id=\"loginForm\">\n            <div wicket:id=\"feedback\"></div>\n            <div class=\"input-group mb-4\">\n                <div wicket:id=\"usernameBorder\">\n                    <input type=\"text\" class=\"form-control\" wicket:id=\"username\" placeholder=\"Username:\"/>\n                </div>\n            </div>\n            <div class=\"input-group mb-4\">\n                <div wicket:id=\"passwordBorder\">\n                    <input type=\"password\" class=\"form-control\" wicket:id=\"password\" placeholder=\"Password:\"/>\n                </div>\n            </div>\n            <div class=\"input-group mb-4\">\n                <button type=\"submit\" class=\"btn btn-primary\">Submit</button>\n            </div>\n        </form>\n        <hr>\n        <ul class=\"list-group list-group-horizontal-md\">\n            <li class=\"list-group-item flex-fill\"><b>Username</b></li>\n            <li class=\"list-group-item flex-fill\"><b>Password</b></li>\n        </ul>\n        <ul class=\"list-group list-group-horizontal-md\">\n            <li class=\"list-group-item flex-fill\">admin</li>\n            <li class=\"list-group-item flex-fill\">admin</li>\n        </ul>\n        <ul class=\"list-group list-group-horizontal-md\">\n            <li class=\"list-group-item flex-fill\">customer</li>\n            <li class=\"list-group-item flex-fill\">customer</li>\n        </ul>\n    </div>\n\n\n</wicket:extend>\n</body>\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/login/LoginPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.login;\n\nimport com.giffing.wicket.spring.boot.context.scan.WicketSignInPage;\nimport com.giffing.wicket.spring.boot.example.web.html.form.focus.FocusBehaviour;\nimport com.giffing.wicket.spring.boot.example.web.html.panel.FeedbackPanel;\nimport com.giffing.wicket.spring.boot.example.web.pages.BasePage;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;\nimport org.apache.wicket.authroles.authentication.AuthenticatedWebSession;\nimport org.apache.wicket.markup.html.form.PasswordTextField;\nimport org.apache.wicket.markup.html.form.RequiredTextField;\nimport org.apache.wicket.markup.html.form.StatelessForm;\nimport org.apache.wicket.model.CompoundPropertyModel;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.wicketstuff.annotation.mount.MountPath;\n\n/**\n * Default login page.\n *\n * @author Marc Giffing\n */\n@WicketSignInPage\n@MountPath(\"login\")\npublic class LoginPage extends BasePage {\n\n    public LoginPage(PageParameters parameters) {\n        super(parameters);\n\n        if (((AbstractAuthenticatedWebSession) getSession()).isSignedIn()) {\n            continueToOriginalDestination();\n            setResponsePage(CustomerListPage.class);\n        }\n        add(new LoginForm(\"loginForm\"));\n    }\n\n    private class LoginForm extends StatelessForm<LoginForm> {\n\n        private String username;\n\n        private String password;\n\n        public LoginForm(String id) {\n            super(id);\n            setModel(new CompoundPropertyModel<>(this));\n            add(new FeedbackPanel(\"feedback\"));\n\n            queueFormComponent(usernameField());\n            queueFormComponent(new PasswordTextField(\"password\"));\n        }\n\n        private RequiredTextField<String> usernameField() {\n            var usernameField = new RequiredTextField<String>(\"username\");\n            usernameField.setOutputMarkupId(true);\n            usernameField.add(new FocusBehaviour());\n            return usernameField;\n        }\n\n        @Override\n        protected void onSubmit() {\n            AuthenticatedWebSession session = AuthenticatedWebSession.get();\n            if (session.signIn(username, password)) {\n                setResponsePage(CustomerListPage.class);\n            } else {\n                error(\"Login failed\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatPage.css",
    "content": "ul {\r\n    list-style-type: none;\r\n}"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatPage.html",
    "content": "<!DOCTYPE html>\r\n<html xmlns:wicket=\"http://wicket.apache.org\">\r\n<head>\r\n    <meta charset=\"utf-8\"/>\r\n    <title>Chat</title>\r\n</head>\r\n<body>\r\n<wicket:extend>\r\n    <header class=\"jumbotron subhead\" id=\"content\">\r\n        <div class=\"container\">\r\n            <h1>Chat</h1>\r\n        </div>\r\n    </header>\r\n    <hr/>\r\n    <div class=\"container\">\r\n        <div wicket:id=\"feedback\"></div>\r\n        <form wicket:id=\"form\" class=\"form\">\r\n            <div class=\"row\">\r\n                <div class=\"col-md-10\">\r\n                    <div class=\"panel panel-default\">\r\n                        <div class=\"panel-heading\">\r\n                            <div class=\"input-group\">\r\n\t\t\t\t\t\t\t\t\t<span class=\"input-group-btn\">\r\n\t\t\t\t\t\t\t\t\t\t<button class=\"btn btn-default btn-sm\">\r\n\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa-solid fa-person\" aria-hidden=\"true\"></i>\r\n\t\t\t\t\t\t\t\t\t\t</button>\r\n\t\t\t\t\t\t\t\t\t</span>\r\n                                <select wicket:id=\"participants\" class=\"form-control input-sm\">\r\n                                </select>\r\n                            </div>\r\n                            <div class=\"input-group\">\r\n\t\t\t\t\t\t\t\t\t<span class=\"input-group-btn\">\r\n\t\t\t\t\t\t\t\t\t\t<button class=\"btn btn-default btn-sm\">\r\n\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa-solid fa-fa-solid fa-pen\" aria-hidden=\"true\"></i>\r\n\t\t\t\t\t\t\t\t\t\t</button>\r\n\t\t\t\t\t\t\t\t\t</span>\r\n                                <input wicket:id=\"message\" type=\"text\" class=\"form-control input-sm\"\r\n                                       placeholder=\"Type your message here...\"/>\r\n                                <span class=\"input-group-btn\">\r\n\t\t\t\t\t\t\t\t\t\t<button class=\"btn btn-default btn-sm\" wicket:id=\"submit\">\r\n\t\t\t\t\t\t\t\t\t\t\t<i class=\"fa-solid fa-right-to-bracket\" aria-hidden=\"true\"></i>\r\n\t\t\t\t\t\t\t\t\t\t </button>\r\n\t\t\t\t\t\t\t\t\t</span>\r\n                            </div>\r\n                        </div>\r\n                        <div wicket:id=\"chatMessageContainer\" class=\"justify-content-start\">\r\n                            <div wicket:id=\"messages\">\r\n                                <div class=\"row\">\r\n                                    <p class=\"col-md-10 small p-2 ms-3 mb-1 rounded-3 bg-body-tertiary\">\r\n                                        <span wicket:id=\"from\"></span>: <span wicket:id=\"message\"></span>\r\n                                    </p>\r\n                                </div>\r\n                            </div>\r\n                        </div>\r\n                    </div>\r\n                </div>\r\n            </div>\r\n        </form>\r\n    </div>\r\n</wicket:extend>\r\n</body>\r\n</html>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatPage.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket;\n\nimport com.giffing.wicket.spring.boot.example.web.html.panel.FeedbackPanel;\nimport com.giffing.wicket.spring.boot.example.web.pages.BaseAuthenticatedPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.events.CustomerMessageEvent;\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.events.JoinChatEvent;\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.events.LeftChatEvent;\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WebSocketMessageBroadcaster;\nimport de.agilecoders.wicket.jquery.JQuery;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.wicket.ajax.AjaxRequestTarget;\nimport org.apache.wicket.ajax.markup.html.form.AjaxButton;\nimport org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;\nimport org.apache.wicket.markup.head.CssHeaderItem;\nimport org.apache.wicket.markup.head.IHeaderResponse;\nimport org.apache.wicket.markup.html.WebMarkupContainer;\nimport org.apache.wicket.markup.html.basic.Label;\nimport org.apache.wicket.markup.html.form.DropDownChoice;\nimport org.apache.wicket.markup.html.form.Form;\nimport org.apache.wicket.markup.html.form.RequiredTextField;\nimport org.apache.wicket.markup.html.list.ListItem;\nimport org.apache.wicket.markup.html.list.ListView;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.model.Model;\nimport org.apache.wicket.protocol.ws.api.WebSocketBehavior;\nimport org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;\nimport org.apache.wicket.protocol.ws.api.message.ClosedMessage;\nimport org.apache.wicket.protocol.ws.api.message.ConnectedMessage;\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.apache.wicket.request.resource.PackageResourceReference;\nimport org.apache.wicket.spring.injection.annot.SpringBean;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.wicketstuff.annotation.mount.MountPath;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.UUID;\n\n@MountPath(\"chat\")\n@AuthorizeInstantiation(\"USER\")\npublic class ChatPage extends BaseAuthenticatedPage {\n\n    @SpringBean\n    private WebSocketMessageBroadcaster webSocketMessageBroadcaster;\n\n    @SpringBean\n    private ChatService chatService;\n\n    private WebMarkupContainer chatMessageContainer;\n\n    private ListView<ChatMessage> messages;\n\n    private RequiredTextField<String> messageInput;\n\n    private DropDownChoice<String> participantChoice;\n\n    public ChatPage(PageParameters pageParameters) {\n        super(pageParameters);\n        add(new FeedbackPanel(\"feedback\").setOutputMarkupId(true));\n        addWebsocketBehaviour();\n        addChatForm();\n    }\n\n    private void addChatForm() {\n        IModel<String> to = Model.of(\"\");\n        IModel<String> message = Model.of(\"\");\n\n        var form = new Form<Void>(\"form\");\n\n        participantChoice = new DropDownChoice<>(\"participants\", to, () -> chatService.getParticipants().stream().toList());\n        participantChoice.setOutputMarkupId(true);\n\n        messageInput = new RequiredTextField<>(\"message\", message);\n        messageInput.setOutputMarkupId(true);\n        AjaxButton submitButton = new AjaxButton(\"submit\") {\n\n            @Override\n            protected void onSubmit(AjaxRequestTarget target) {\n                String name = SecurityContextHolder.getContext().getAuthentication().getName();\n                webSocketMessageBroadcaster.sendToAll(new CustomerMessageEvent(name, message.getObject()));\n                messageInput.setModelObject(null);\n                target.add(messageInput);\n            }\n\n        };\n        form.setDefaultButton(submitButton);\n\n\n        messages = new ListView<>(\"messages\", new ArrayList<>()) {\n\n            @Override\n            protected void populateItem(ListItem<ChatMessage> item) {\n                ChatMessage modelObject = item.getModelObject();\n                item.add(new Label(\"from\", modelObject.getFrom()));\n                item.add(new Label(\"message\", modelObject.getMessage()));\n\n            }\n        };\n        messages.setOutputMarkupId(true);\n\n        chatMessageContainer = new WebMarkupContainer(\"chatMessageContainer\");\n        chatMessageContainer.setOutputMarkupId(true);\n        chatMessageContainer.add(messages);\n\n        add(form);\n        form.add(submitButton);\n        form.add(participantChoice);\n        form.add(messageInput);\n        form.add(chatMessageContainer);\n    }\n\n    private void addWebsocketBehaviour() {\n        var currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();\n        var browserTabIdentifier = UUID.randomUUID().toString();\n        var chatParticipant = new ChatParticipant(browserTabIdentifier, currentUsername);\n        add(new WebSocketBehavior() {\n\n            @Override\n            protected void onPush(WebSocketRequestHandler handler, IWebSocketPushMessage message) {\n                if (message instanceof CustomerMessageEvent event) {\n                    messages.getModelObject().add(new ChatMessage(event.getSender(), event.getMessage()));\n                    handler.add(chatMessageContainer);\n                }\n                if (message instanceof JoinChatEvent event) {\n                    var notifyStatus = \"success\";\n                    var notifyMessage = \"%s joined the chat\".formatted(event.getUsername());\n                    addNotifyMessage(handler, notifyStatus, notifyMessage);\n                    handler.add(participantChoice);\n                }\n                if (message instanceof LeftChatEvent event) {\n                    String notifyStatus = \"warning\";\n                    String notifyMessage = \"%s left the chat\".formatted(event.getUsername());\n                    addNotifyMessage(handler, notifyStatus, notifyMessage);\n                    handler.add(participantChoice);\n                }\n            }\n\n            private void addNotifyMessage(WebSocketRequestHandler handler, String notifyStatus, String notifyMessage) {\n                handler.appendJavaScript(JQuery\n                        .plain(\"noty({text: '%s', type: '%s', timeout: '5000', progressbar: true});\"\n                                .formatted(notifyMessage, notifyStatus)));\n            }\n\n            @Override\n            protected void onConnect(ConnectedMessage message) {\n                chatService.join(chatParticipant);\n            }\n\n            @Override\n            protected void onClose(ClosedMessage message) {\n                chatService.leave(chatParticipant);\n            }\n\n        });\n    }\n\n    @Getter\n    @RequiredArgsConstructor\n    private static class ChatMessage implements Serializable {\n        private final String from;\n        private final String message;\n    }\n\n    @Override\n    public void renderHead(IHeaderResponse response) {\n        super.renderHead(response);\n        response.render(CssHeaderItem.forReference(new PackageResourceReference(ChatPage.class, \"ChatPage.css\")));\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatPage.properties",
    "content": "username=Username\r\nmessage=Message"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatParticipant.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket;\r\n\r\nimport lombok.Data;\r\nimport lombok.RequiredArgsConstructor;\r\n\r\nimport java.io.Serializable;\r\n\r\n/**\r\n * The user can login to multiple browsers and tabs.\r\n * This class is used to identify a specific user with an open browser tab\r\n *\r\n * @author Marc Giffing\r\n */\r\n@Data\r\n@RequiredArgsConstructor\r\npublic class ChatParticipant implements Serializable {\r\n\r\n    private final String username;\r\n\r\n    /**\r\n     * The user can login to multiple browsers and tabs\r\n     * This identifier is used to identify a single browser tab.\r\n     */\r\n    private final String browserTabIdentifier;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/ChatService.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket;\r\n\r\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.events.JoinChatEvent;\r\nimport com.giffing.wicket.spring.boot.example.web.pages.websocket.events.LeftChatEvent;\r\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WebSocketMessageBroadcaster;\r\nimport org.springframework.stereotype.Component;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Set;\r\nimport java.util.stream.Collectors;\r\n\r\n@Component\r\npublic class ChatService {\r\n\r\n    private final WebSocketMessageBroadcaster broadcaster;\r\n\r\n\r\n    private List<ChatParticipant> participants = new ArrayList<>();\r\n\r\n    public ChatService(WebSocketMessageBroadcaster broadcaster) {\r\n        this.broadcaster = broadcaster;\r\n    }\r\n\r\n    public Set<String> getParticipants() {\r\n        return participants\r\n                .stream()\r\n                .map(ChatParticipant::getUsername)\r\n                .collect(Collectors.toSet());\r\n    }\r\n\r\n    public void join(ChatParticipant chatParticipant) {\r\n        var username = chatParticipant.getUsername();\r\n        var existingUserSpecificParticipants = participants\r\n                .stream()\r\n                .filter(p -> p.getUsername().equalsIgnoreCase(chatParticipant.getUsername()))\r\n                .toList();\r\n        participants.add(chatParticipant);\r\n        if (existingUserSpecificParticipants.isEmpty()) {\r\n            broadcaster.sendToAll(new JoinChatEvent(username));\r\n        }\r\n    }\r\n\r\n    public void leave(ChatParticipant chatParticipant) {\r\n        var username = chatParticipant.getUsername();\r\n        var chatParticipateToDelete = participants\r\n                .stream()\r\n                .filter(p -> p.getBrowserTabIdentifier().equals(chatParticipant.getBrowserTabIdentifier()))\r\n                .findAny();\r\n        chatParticipateToDelete.ifPresent(participant -> participants.remove(participant));\r\n\r\n        var remainingUserSpecificParticipants = participants\r\n                .stream()\r\n                .filter(p -> p.getUsername().equalsIgnoreCase(chatParticipant.getUsername()))\r\n                .toList();\r\n        if (remainingUserSpecificParticipants.isEmpty()) {\r\n            broadcaster.sendToAll(new LeftChatEvent(username));\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/events/CustomerMessageEvent.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket.events;\r\n\r\nimport lombok.Getter;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\r\n\r\n/**\r\n * Used to send a message to a specific user\r\n */\r\n@Getter\r\n@RequiredArgsConstructor\r\npublic class CustomerMessageEvent implements IWebSocketPushMessage {\r\n\r\n    private final String sender;\r\n\r\n    private final String message;\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/events/JoinChatEvent.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket.events;\r\n\r\nimport lombok.Getter;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\r\n\r\n@Getter\r\n@RequiredArgsConstructor\r\npublic class JoinChatEvent implements IWebSocketPushMessage {\r\n\r\n    private final String username;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/pages/websocket/events/LeftChatEvent.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.websocket.events;\r\n\r\nimport lombok.Getter;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;\r\n\r\n@Getter\r\n@RequiredArgsConstructor\r\npublic class LeftChatEvent implements IWebSocketPushMessage {\r\n\r\n    private final String username;\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/security/SpringSecurityWicketSessionResolver.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.security;\r\n\r\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WicketSessionResolver;\r\nimport lombok.RequiredArgsConstructor;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.session.FindByIndexNameSessionRepository;\r\nimport org.springframework.session.Session;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\n@RequiredArgsConstructor\r\npublic class SpringSecurityWicketSessionResolver implements WicketSessionResolver {\r\n\t\r\n\tprivate final FindByIndexNameSessionRepository<? extends Session> sessions;\r\n\t\r\n\t@Override\r\n\tpublic List<String> resolve(Object identifier) {\r\n\t\tMap<String, ? extends Session> findByPrincipalName = sessions.findByPrincipalName(identifier.toString());\r\n\t\treturn new ArrayList<>(findByPrincipalName.keySet());\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/security/WicketWebSecurityAdapterConfig.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.security;\r\n\r\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.security.authentication.AuthenticationManager;\r\nimport org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;\r\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\r\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\r\nimport org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;\r\nimport org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;\r\nimport org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;\r\nimport org.springframework.security.core.userdetails.User;\r\nimport org.springframework.security.core.userdetails.UserDetailsService;\r\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\r\nimport org.springframework.security.crypto.password.PasswordEncoder;\r\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\r\nimport org.springframework.security.web.SecurityFilterChain;\r\nimport org.springframework.security.web.firewall.HttpFirewall;\r\nimport org.springframework.security.web.firewall.StrictHttpFirewall;\r\n\r\n/**\r\n * Default Spring Boot Wicket security getting started configuration. Its only\r\n * active if there is not other {@link SecurityFilterChain} bean is present.\r\n * <p>\r\n * Holds hard coded users which should only be used to get started\r\n *\r\n * @author Marc Giffing\r\n */\r\n@Configuration\r\n@EnableWebSecurity\r\npublic class WicketWebSecurityAdapterConfig {\r\n\r\n    @ConditionalOnMissingBean\r\n    @Bean\r\n    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {\r\n        return authenticationConfiguration.getAuthenticationManager();\r\n    }\r\n\r\n    @ConditionalOnMissingBean\r\n    @Bean\r\n    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {\r\n        return http\r\n                .securityContext(ctx -> ctx.requireExplicitSave(false))\r\n                .csrf(AbstractHttpConfigurer::disable)\r\n                .authorizeHttpRequests(authorizeHttpRequests ->\r\n                        authorizeHttpRequests.requestMatchers(\"/**\").permitAll())\r\n                .logout(LogoutConfigurer::permitAll)\r\n                .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))\r\n                .build();\r\n    }\r\n\r\n    @Bean\r\n    public static BCryptPasswordEncoder passwordEncoder() {\r\n        return new BCryptPasswordEncoder();\r\n    }\r\n\r\n    @Bean\r\n    //TODO Add Wicket Issue - problem with semicolon in wicket websocket url. Allow semicolon.\r\n    public HttpFirewall allowUrlEncodedSlashHttpFirewall() {\r\n        StrictHttpFirewall fw = new StrictHttpFirewall();\r\n        fw.setAllowSemicolon(true);\r\n        return fw;\r\n    }\r\n\r\n    @ConditionalOnMissingBean\r\n    @Bean\r\n    public UserDetailsService userDetailsService(final PasswordEncoder passwordEncoder) {\r\n        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();\r\n        manager.createUser(\r\n                User.withUsername(\"admin\")\r\n                        .password(passwordEncoder.encode(\"admin\"))\r\n                        .authorities(\"USER\", \"ADMIN\")\r\n                        .build());\r\n        manager.createUser(\r\n                User.withUsername(\"customer\")\r\n                        .password(passwordEncoder.encode(\"customer\"))\r\n                        .authorities(\"USER\", \"ADMIN\")\r\n                        .build());\r\n        return manager;\r\n    }\r\n\r\n    //@Bean\r\n    //public WicketSessionResolver springSecurityWicketSessionResolver() {\r\n    //\treturn new SpringSecurityWicketSessionResolver();\r\n    //}\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/java/com/giffing/wicket/spring/boot/example/web/wicket/dataprovider/DefaultDataProvider.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.wicket.dataprovider;\n\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.apache.wicket.extensions.markup.html.repeater.data.sort.ISortState;\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.filter.IFilterStateLocator;\nimport org.apache.wicket.extensions.markup.html.repeater.util.SingleSortState;\nimport org.apache.wicket.model.CompoundPropertyModel;\nimport org.apache.wicket.model.IModel;\nimport org.apache.wicket.model.LoadableDetachableModel;\n\nimport com.giffing.wicket.spring.boot.example.repository.Domain;\nimport com.giffing.wicket.spring.boot.example.repository.Filter;\nimport com.giffing.wicket.spring.boot.example.repository.FilterService;\nimport com.giffing.wicket.spring.boot.example.repository.Sort;\n\npublic abstract class DefaultDataProvider<MODEL extends Domain<ID>, \n\t\t\t\tID, \n\t\t\t\tFILTER_MODEL extends Filter, \n\t\t\t\tSORT, \n\t\t\t\tSERVICE extends FilterService<MODEL, ID, FILTER_MODEL>> \n\t\timplements \tISortableDataProvider<MODEL, SORT>, \n\t\t\t\t\tIFilterStateLocator<FILTER_MODEL> {\n\t\n\tpublic abstract SERVICE getFilterService();\n\t\n\tpublic abstract FILTER_MODEL getFilter();\n\t\n\tpublic abstract void setFilter(FILTER_MODEL filterModel);\n\t\n\tprivate SingleSortState<SORT> singleSortState = new SingleSortState<>();\n\n    @Override\n\tpublic Iterator<? extends MODEL> iterator(long first, long count) {\n\t\tif(singleSortState.getSort() != null){\n\t\t\tSort property = (Sort) singleSortState.getSort().getProperty();\n\t\t\tboolean ascending = singleSortState.getSort().isAscending();\n\t\t\tgetFilter().setSort(property, ascending);\n\t\t}\n\t\t//TODO quick and dirty check again \n\t\tlong page = first / count;\n\t\treturn getFilterService().findAll(page, count, this.getFilter()).iterator();\n\t}\n\n\t@Override\n\tpublic long size() {\n\t\tlong count = getFilterService().count(this.getFilter());\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic IModel<MODEL> model(MODEL object) {\n\t\tID id = object.getId();\n\t\treturn new CompoundPropertyModel<>(new LoadableDetachableModel<MODEL>(object) {\n\n\t\t\t@Override\n\t\t\tprotected MODEL load() {\n\t\t\t\treturn getFilterService().findById(id);\n\t\t\t}\n\t\t});\n\t}\n\t\n\t@Override\n\tpublic ISortState<SORT> getSortState() {\n\t\treturn singleSortState;\n\t}\n\n\t@Override\n\tpublic FILTER_MODEL getFilterState() {\n\t\treturn getFilter();\n\t}\n\n\t@Override\n\tpublic void setFilterState(FILTER_MODEL state) {\n\t\tsetFilter(state);\n\t}\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/META-INF/spring-devtools.properties",
    "content": "restart.include.wicketx=/wicketstuff-annotation-[\\\\w-\\.]+\\.jar\nrestart.include.wicket-spring-boot-starter=/wicket-spring-boot-starter-[\\\\w-\\.]+\\.jar\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/application.yml",
    "content": "wicket:\n  stuff:\n    datastore:\n      hazelcast:\n        enabled: false\n  core:\n    resourcesettings:\n      packageresourceguard:\n        pattern:\n        - +*.map\n    csrf:\n      enabled: false\n    settings:\n      markup:\n        stripWicketTags: true\n  endpoints:\n    web:\n      exposure:\n        include: \"*\"\nserver:\n  compression:\n    enabled: true\n  port: 8081\nspring:\n  main:\n    allow-bean-definition-overriding: true\n  jpa:\n    hibernate:\n      ddl-auto: none\n  liquibase:\n    change-log: classpath:/db/changelog/db.changelog-master.xml\n  session:\n    store-type: jdbc\n    jdbc:\n      initialize-schema: always\n      schema: classpath:org/springframework/session/jdbc/schema-h2.sql\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/db/changelog/db.changelog-master.xml",
    "content": "<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\txmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd \n   http://www.liquibase.org/xml/ns/dbchangelog \n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd\">\n\n\t<include file=\"init.xml\" relativeToChangelogFile=\"true\"/>\n\t<include file=\"test-data.xml\" relativeToChangelogFile=\"true\" />\n\n</databaseChangeLog>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/db/changelog/init.xml",
    "content": "<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\txmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd \n   http://www.liquibase.org/xml/ns/dbchangelog \n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd\">\n\n\t<include file=\"table_customer.xml\" relativeToChangelogFile=\"true\" />\n\t\n</databaseChangeLog>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/db/changelog/table_customer.xml",
    "content": "<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\txmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd \n   http://www.liquibase.org/xml/ns/dbchangelog \n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd\">\n\n\n\t<changeSet author=\"mgiffing\" id=\"1\">\n\t\t<createTable tableName=\"customer\">\n\t\t\t<column name=\"id\" type=\"bigint\" autoIncrement=\"true\">\n\t\t\t\t<constraints primaryKey=\"true\" nullable=\"false\" />\n\t\t\t</column>\n\n\t\t\t<column name=\"username\" type=\"VARCHAR(255)\">\n\t\t\t\t<constraints nullable=\"false\" />\n\t\t\t</column>\n\n\t\t\t<column name=\"firstname\" type=\"VARCHAR(255)\" />\n\n\t\t\t<column name=\"lastname\" type=\"VARCHAR(255)\" />\n\t\t\t<column name=\"active\" type=\"BOOLEAN\">\n\t\t\t\t<constraints nullable=\"false\" />\n\t\t\t</column>\n\t\t</createTable>\n\n\t</changeSet>\n\n</databaseChangeLog>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/db/changelog/test-data.xml",
    "content": "<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\txmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd \n   http://www.liquibase.org/xml/ns/dbchangelog \n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd\">\n\n\n\t<changeSet id=\"init-testdata\" author=\"mgiffing\">\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">frodo</column>\n\t\t\t<column name=\"firstname\">Frodo</column>\n\t\t\t<column name=\"lastname\">Beutlin</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">bilbo</column>\n\t\t\t<column name=\"firstname\">Bilbo</column>\n\t\t\t<column name=\"lastname\">Beutlin</column>\n\t\t\t<column name=\"active\">false</column>\n\t\t</insert>\n\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">adalgrim</column>\n\t\t\t<column name=\"firstname\">Adalgrim</column>\n\t\t\t<column name=\"lastname\">Tuk</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">bodo</column>\n\t\t\t<column name=\"firstname\">Bodo</column>\n\t\t\t<column name=\"lastname\">Stolzfuß</column>\n\t\t\t<column name=\"active\">false</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">tuk</column>\n\t\t\t<column name=\"firstname\">Ferdibrand</column>\n\t\t\t<column name=\"lastname\">Tuk</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t</changeSet>\n\n</databaseChangeLog>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/main/resources/logback.xml",
    "content": "<configuration>\n    <include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n    <logger name=\"org.hibernate.SQL\" level=\"DEBUG\"/>\n</configuration>"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/WicketBaseIntTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web;\n\nimport com.giffing.wicket.spring.boot.example.WicketApplication;\nimport com.giffing.wicket.spring.boot.example.web.pages.login.LoginPage;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security.SecureWebSession;\nimport com.giffing.wicket.spring.boot.starter.web.servlet.websocket.WebSocketMessageBroadcaster;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.util.tester.FormTester;\nimport org.apache.wicket.util.tester.WicketTester;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.mockito.Mockito;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Test class for initialize Wicket & Spring Boot only in the web package. All\n * external spring beans have to be mocked.\n * \n * @author Marc Giffing\n *\n */\n@SpringBootTest(classes = WicketApplication.class)\npublic abstract class WicketBaseIntTest {\n\n\tprivate static final String USERNAME = \"admin\";\n\tprivate static final String PASSWORD = \"admin\";\n\n\tprivate WicketTester tester;\n\n\t@Autowired\n\tprivate WebApplication wicketApplication;\n\n\t@Configuration\n\tpublic static class TestConfig {\n\t\t@Bean\n\t\t@Primary\n\t\tpublic WebSocketMessageBroadcaster webSocketMessageBroadcaster() {\n\t\t\treturn Mockito.mock(WebSocketMessageBroadcaster.class);\n\t\t}\n\t}\n\n\t@BeforeEach\n\tpublic void setUp() {\n\t\ttester = new WicketTester(wicketApplication, new WicketMockServletContext(wicketApplication, null));\n\t\tlogin(USERNAME, PASSWORD);\n\t}\n\n\tprivate void login(String username, String password) {\n\t\tSecureWebSession session = (SecureWebSession) tester.getSession();\n\t\tsession.signOut();\n\t\ttester.startPage(LoginPage.class);\n\t\tFormTester formTester = tester.newFormTester(\"loginForm\");\n\t\tformTester.setValue(borderPath(\"username\"), username);\n\t\tformTester.setValue(borderPath(\"password\"), password);\n\t\tformTester.submit();\n\t\ttester.assertNoErrorMessage();\n\t\ttester.assertRenderedPage(tester.getApplication().getHomePage());\n\t}\n\n\tpublic WicketTester getTester() {\n\t\treturn tester;\n\t}\n\n\tpublic WebApplication getWicketApplication() {\n\t\treturn wicketApplication;\n\t}\n\n\tprotected String borderPath(String componentName){\n\t\treturn componentName + \"Border:\" + componentName + \"Border_body:\" + componentName;\n\t}\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/WicketBaseTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web;\n\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.login.LoginPage;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security.SecureWebSession;\nimport org.apache.wicket.protocol.http.WebApplication;\nimport org.apache.wicket.util.tester.FormTester;\nimport org.apache.wicket.util.tester.WicketTester;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.TestingAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport test.com.giffing.wicket.spring.boot.example.web.WicketWebApplicationConfig;\n\n/**\n * Test class for initialize Wicket & Spring Boot only in the web package. All\n * external spring beans have to be mocked.\n * \n * @author Marc Giffing\n *\n */\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = WicketWebApplicationConfig.class)\n@Disabled\npublic class WicketBaseTest {\n\n\tprivate static final String USERNAME = \"admin\";\n\tprivate static final String PASSWORD = \"admin\";\n\n\tprivate WicketTester tester;\n\n\t@Autowired\n\tprivate WebApplication wicketApplication;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContextMock;\n\t\n\t@MockitoBean\n\tprivate CustomAuthenticationManager customAuthenticationManager;\n\n\t@BeforeEach\n\tpublic void setUp() {\n\t\tReflectionTestUtils.setField(wicketApplication, \"applicationContext\", applicationContextMock);\n\t\ttester = new WicketTester(wicketApplication, new WicketMockServletContext(wicketApplication, null));\n\t\tlogin(USERNAME, PASSWORD);\n\t}\n\t\n\tpublic static class CustomAuthenticationManager implements AuthenticationManager {\n\n\t\t@Override\n\t\tpublic Authentication authenticate(Authentication arg0) throws AuthenticationException {\n\t\t\treturn new TestingAuthenticationToken(USERNAME, PASSWORD, \"USER\", \"ADMIN\");\n\t\t}\n\t\t\n\t}\n\n\tprivate void login(String username, String password) {\n\t\tSecureWebSession session = (SecureWebSession) tester.getSession();\n\t\tsession.signOut();\n\t\ttester.startPage(LoginPage.class);\n\t\tFormTester formTester = tester.newFormTester(\"loginForm\");\n\t\tformTester.setValue(borderPath(\"username\"), username);\n\t\tformTester.setValue(borderPath(\"password\"), password);\n\t\tformTester.submit();\n\t\ttester.assertNoErrorMessage();\n\t\ttester.assertRenderedPage(CustomerListPage.class);\n\t}\n\n\tpublic WicketTester getTester() {\n\t\treturn tester;\n\t}\n\n\tpublic WebApplication getWicketApplication() {\n\t\treturn wicketApplication;\n\t}\n\n\tprotected String borderPath(String componentName){\n\t\treturn componentName + \"Border:\" + componentName + \"Border_body:\" + componentName;\n\t}\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/WicketMockServletContext.java",
    "content": "package com.giffing.wicket.spring.boot.example.web;\r\n\r\nimport java.util.Set;\r\n\r\nimport jakarta.servlet.SessionTrackingMode;\r\n\r\nimport org.apache.wicket.Application;\r\nimport org.apache.wicket.protocol.http.mock.MockServletContext;\r\n\r\npublic class WicketMockServletContext extends MockServletContext {\r\n\r\n\tpublic WicketMockServletContext(Application application, String path) {\r\n\t\tsuper( application, path );\r\n\t}\r\n\t\r\n\t@Override\r\n\tpublic Set<SessionTrackingMode> getDefaultSessionTrackingModes() {\r\n\t\treturn Set.of(SessionTrackingMode.COOKIE);\r\n\t}\r\n\r\n\t@Override\r\n\tpublic Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {\r\n\t\treturn Set.of(SessionTrackingMode.COOKIE);\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/pages/customers/CustomerListIntTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;\nimport org.apache.wicket.markup.repeater.Item;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.test.annotation.Rollback;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerSort;\nimport com.giffing.wicket.spring.boot.example.web.WicketBaseIntTest;\nimport com.giffing.wicket.spring.boot.example.web.html.modal.YesNoModal;\n\n@Transactional\n@Rollback\npublic class CustomerListIntTest extends WicketBaseIntTest {\n\n    @Test\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n    public void assert_start_customer_list_page() {\n        getTester().startPage(CustomerListPage.class);\n        getTester().assertRenderedPage(CustomerListPage.class);\n        getTester().assertComponent(\"filterForm:table\", DataTable.class);\n\n        DataTable<Customer, CustomerSort> dataTable = (DataTable) getTester().getComponentFromLastRenderedPage(\n                \"filterForm:table\");\n        assertThat(dataTable.getItemCount(), equalTo(5L));\n        //id, username, firstname, lastname, active, actions\n        assertThat(dataTable.getColumns().size(), equalTo(6));\n        //get third row\n        Item<Customer> item3 = (Item) getTester().getComponentFromLastRenderedPage(\"filterForm:table:body:rows:3\");\n        assertThat(item3.getModelObject().getId(), equalTo(3L));\n        assertThat(item3.getModelObject().getUsername(), equalTo(\"adalgrim\"));\n\n        Item<Customer> item5 = (Item) getTester().getComponentFromLastRenderedPage(\"filterForm:table:body:rows:5\");\n        assertThat(item5.getModelObject().getId(), equalTo(5L));\n        assertThat(item5.getModelObject().getUsername(), equalTo(\"tuk\"));\n    }\n\n    @Test\n    public void assert_delete_customer_method_called_once() {\n        getTester().startPage(CustomerListPage.class);\n        getTester().assertRenderedPage(CustomerListPage.class);\n\n        @SuppressWarnings(\"unchecked\")\n        DataTable<Customer, CustomerSort> dataTable = (DataTable) getTester().getComponentFromLastRenderedPage(\n                \"filterForm:table\");\n        assertThat(dataTable.getItemCount(), equalTo(5L));\n\n        getTester().clickLink(getTableCell(5, 6) + \"items:1:item:link\");\n        getTester().assertComponent(\"defaultModal\", YesNoModal.class);\n        getTester().clickLink(\"defaultModal:content:yes\", true);\n\n        assertThat(dataTable.getItemCount(), equalTo(4L));\n\n    }\n\n    private String getTableCell(int row, int cell) {\n        return \"filterForm:table:body:rows:\" + row + \":cells:\" + cell + \":cell:\";\n    }\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/pages/customers/CustomerListPageTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers;\n\nimport static org.hamcrest.CoreMatchers.equalTo;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;\nimport org.apache.wicket.markup.repeater.Item;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerSort;\nimport com.giffing.wicket.spring.boot.example.web.WicketBaseTest;\nimport com.giffing.wicket.spring.boot.example.web.html.modal.YesNoModal;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.create.CustomerCreatePage;\n\npublic class CustomerListPageTest extends WicketBaseTest {\n\n\tprivate static final long CUSTOMERS_COUNT = 5;\n\n\t@MockitoBean\n\tprivate CustomerRepositoryService repository;\n\t\n\t@Override\n\t@BeforeEach\n\tpublic void setUp(){\n\t\tsuper.setUp();\n\t\t\n\t\tMockito.when(repository.findAll(Mockito.anyLong(), Mockito.anyLong(), Mockito.any())).thenReturn(createCustomers(CUSTOMERS_COUNT));\n\t\tMockito.when(repository.count(Mockito.any())).thenReturn(CUSTOMERS_COUNT);\n\t\tfor (long i=1; i <= CUSTOMERS_COUNT; i++) {\n\t\t\tMockito.when(repository.findById(i)).thenReturn(createCustomer(i));\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic void assert_start_customer_list_page(){\n\t\tgetTester().startPage(CustomerListPage.class);\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\tgetTester().assertComponent(\"filterForm:table\", DataTable.class);\n\t\t\n\t\tDataTable<Customer, CustomerSort> dataTable = (DataTable) getTester().getComponentFromLastRenderedPage(\"filterForm:table\");\n\t\tassertThat(dataTable.getItemCount(), equalTo(CUSTOMERS_COUNT));\n\t\t//id, username, firstname, lastname, active, actions\n\t\tassertThat(dataTable.getColumns().size(), equalTo(6));\n\t\t//get third row\n\t\tItem<Customer> item3 = (Item) getTester().getComponentFromLastRenderedPage(\"filterForm:table:body:rows:3\");\n\t\tassertThat(item3.getModelObject().getId(), equalTo(3L));\n\t\tassertThat(item3.getModelObject().getUsername(), equalTo(\"username3\"));\n\t\t\n\t\tItem<Customer> item5 = (Item) getTester().getComponentFromLastRenderedPage(\"filterForm:table:body:rows:5\");\n\t\tassertThat(item5.getModelObject().getId(), equalTo(5L));\n\t\tassertThat(item5.getModelObject().getUsername(), equalTo(\"username5\"));\n\t}\n\t\n\t@Test\n\tpublic void assert_click_customer_edit_page(){\n\t\tgetTester().startPage(CustomerListPage.class);\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\tgetTester().clickLink(getTableCell(5, 6) + \"items:0:item:link\");\n\t\tgetTester().assertRenderedPage(CustomerCreatePage.class);\n\t\t\n\t}\n\t\n\t@Test\n\tpublic void assert_click_customer_create_page(){\n\t\tgetTester().startPage(CustomerListPage.class);\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\tgetTester().clickLink(\"create\");\n\t\tgetTester().assertRenderedPage(CustomerCreatePage.class);\n\t}\n\t\n\t@Test\n\tpublic void assert_delete_customer_method_called_once(){\n\t\tgetTester().startPage(CustomerListPage.class);\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\tgetTester().clickLink(getTableCell(5, 6) + \"items:1:item:link\");\n\t\tgetTester().assertComponent(\"defaultModal\", YesNoModal.class);\n\t\tgetTester().clickLink(\"defaultModal:content:yes\", true);\n\t\t\n\t\tverify(repository, times(1)).delete(Mockito.anyLong());\n\t\tverify(repository, times(1)).delete(5L);\n\t\t\n\t}\n\t\n\tprivate String getTableCell(int row, int cell){\n\t\treturn \"filterForm:table:body:rows:\" + row + \":cells:\" + cell + \":cell:\";\n\t}\n\t\n\tpublic static List<Customer> createCustomers(long count) {\n\t\tList<Customer> customers = new ArrayList<>();\n\t\tfor(long i = 1; i <= count; i++){\n\t\t\tcustomers.add(createCustomer(i));\n\t\t}\n\t\treturn customers;\n\t}\n\n\tpublic static Customer createCustomer(long i) {\n\t\tCustomer customer = new Customer();\n\t\tcustomer.setId(i);\n\t\tcustomer.setUsername(\"username\" + i);\n\t\tcustomer.setFirstname(\"firstname\" + i);\n\t\tcustomer.setLastname(\"lastname\" + i);\n\t\treturn customer;\n\t}\n\t\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/pages/customers/create/CustomerCreatePageIntTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.create;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.filter.CustomerFilter;\nimport com.giffing.wicket.spring.boot.example.web.WicketBaseIntTest;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport org.apache.wicket.util.tester.FormTester;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.Rollback;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.notNullValue;\n\n@Transactional\n@Rollback\npublic class CustomerCreatePageIntTest extends WicketBaseIntTest {\n\n    @Autowired\n    private CustomerRepositoryService service;\n\n    @Test\n    public void assert_new_customer_saved() {\n\n        long initialCustomerCount = service.count(new CustomerFilter());\n\n        getTester().startPage(CustomerCreatePage.class);\n        getTester().assertRenderedPage(CustomerCreatePage.class);\n        FormTester formTester = getTester().newFormTester(\"form\");\n\n        String usernameOfNewCreatedUser = \"newUser\";\n        formTester.setValue(borderPath(\"username\"), usernameOfNewCreatedUser);\n        formTester.setValue(borderPath(\"firstname\"), \"newFirstname\");\n        formTester.setValue(borderPath(\"lastname\"), \"newLastname\");\n        formTester.submit(\"submit\");\n        getTester().assertNoErrorMessage();\n        getTester().assertNoInfoMessage();\n        getTester().assertRenderedPage(CustomerListPage.class);\n\n        long currentCustomerCount = service.count(new CustomerFilter());\n        assertThat(currentCustomerCount, equalTo(initialCustomerCount + 1));\n\n        Customer newUser = service.findByUsername(usernameOfNewCreatedUser);\n        assertThat(newUser, notNullValue());\n        assertThat(newUser.getId(), notNullValue());\n        assertThat(newUser.getUsername(), equalTo(usernameOfNewCreatedUser));\n    }\n\n    @Test\n    public void assert_error_when_create_existing_customer() {\n        getTester().startPage(CustomerCreatePage.class);\n        getTester().assertRenderedPage(CustomerCreatePage.class);\n        getTester().debugComponentTrees();\n        FormTester formTester = getTester().newFormTester(\"form\");\n\n        //user is created via liquibase as initial data\n        String usernameOfExistingUser = \"frodo\";\n        formTester.setValue(borderPath(\"username\"), usernameOfExistingUser);\n        formTester.setValue(borderPath(\"firstname\"), \"newFirstname\");\n        formTester.setValue(borderPath(\"lastname\"), \"newLastname\");\n        formTester.submit(\"submit\");\n\n        getTester().assertErrorMessages(\"Username already exists!\");\n\n    }\n\n    protected String borderPath(String componentName) {\n        return componentName + \"Border:\" + componentName + \"Border_body:\" + componentName;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/pages/customers/create/CustomerCreatePageTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.create;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.web.WicketBaseTest;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport org.apache.wicket.util.tester.FormTester;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.hamcrest.Matchers.nullValue;\nimport static org.mockito.Mockito.*;\n\npublic class CustomerCreatePageTest extends WicketBaseTest {\n\n\t@MockitoBean\n\tprivate CustomerRepositoryService repository;\n\t\n\t@Override\n\t@BeforeEach\n\tpublic void setUp(){\n\t\tsuper.setUp();\n\t}\n\t\n\t@Test\n\tpublic void assert_customer_save_called(){\n\t\tgetTester().startPage(CustomerCreatePage.class);\n\t\tgetTester().assertRenderedPage(CustomerCreatePage.class);\n\n\t\tFormTester formTester = getTester().newFormTester(\"form\");\n\t\tformTester.setValue(borderPath(\"username\"), \"myUsername\");\n\t\tformTester.setValue(borderPath(\"firstname\"), \"myFirstname\");\n\t\tformTester.setValue(borderPath(\"lastname\"), \"myLastname\");\n\t\tformTester.submit(\"submit\");\n\t\tgetTester().assertNoErrorMessage();\n\t\tgetTester().assertNoInfoMessage();\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\tArgumentCaptor<Customer> customerArgument = ArgumentCaptor.forClass(Customer.class);\n\t\t\n\t\t//it should be checked, that the username does not already exists\n\t\tverify(repository, times(1)).usernameExists(\"myUsername\");\n\t\t\n\t\tverify(repository, times(1)).save(Mockito.any());\n\t\tverify(repository, times(1)).save(customerArgument.capture());\n\t\t\n\t\tCustomer value = customerArgument.getValue();\n\t\tassertThat(value.getId(), nullValue());\n\t\tassertThat(value.getUsername(), equalTo(\"myUsername\"));\n\t\tassertThat(value.getFirstname(), equalTo(\"myFirstname\"));\n\t\tassertThat(value.getLastname(), equalTo(\"myLastname\"));\n\t}\n\t\n\t@Test\n\tpublic void assert_customer_not_saved_if_user_already_exist() {\n\t\tgetTester().startPage(CustomerCreatePage.class);\n\t\tgetTester().assertRenderedPage(CustomerCreatePage.class);\n\n\t\tString newUsername = \"newUsername\";\n\n\t\twhen(repository.usernameExists(newUsername)).thenReturn(true);\n\t\t\n\t\tFormTester formTester = getTester().newFormTester(\"form\");\n\t\tformTester.setValue(borderPath(\"username\"), newUsername);\n\t\tformTester.setValue(borderPath(\"firstname\"), \"myFirstname\");\n\t\tformTester.setValue(borderPath(\"lastname\"), \"myLastname\");\n\t\tformTester.submit(\"submit\");\n\t\t\n\t\tgetTester().assertErrorMessages(\"Username already exists!\");\n\t\tgetTester().assertRenderedPage(CustomerCreatePage.class);\n\t\t\n\t\t//it should be checked, that the username does already exists\n\t\tverify(repository, times(1)).usernameExists(newUsername);\n\t\tverify(repository, times(0)).save(Mockito.any());\n\t\n\t\t//verifyNoMoreInteractions(repository);\n\t}\n\t\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/pages/customers/edit/CustomerEditPageTest.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.pages.customers.edit;\n\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport org.apache.wicket.request.mapper.parameter.PageParameters;\nimport org.apache.wicket.util.tester.FormTester;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport com.giffing.wicket.spring.boot.example.model.Customer;\nimport com.giffing.wicket.spring.boot.example.repository.services.customer.CustomerRepositoryService;\nimport com.giffing.wicket.spring.boot.example.web.WicketBaseTest;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPageTest;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.model.UsernameTextField;\n\npublic class CustomerEditPageTest extends WicketBaseTest {\n\n\tprivate static final Long CUSTOMERS_COUNT = 5L;\n\t\n\t@MockitoBean\n\tprivate CustomerRepositoryService repository;\n\t\n\t@Override\n\t@BeforeEach\n\tpublic void setUp(){\n\t\tsuper.setUp();\n\t\tMockito.when(repository.findAll(Mockito.anyLong(), Mockito.anyLong(), Mockito.any())).thenReturn(CustomerListPageTest.createCustomers(CUSTOMERS_COUNT));\n\t\tMockito.when(repository.count(Mockito.any())).thenReturn(CUSTOMERS_COUNT);\n\t\tfor (long i=1; i <= CUSTOMERS_COUNT; i++) {\n\t\t\tMockito.when(repository.findById(i)).thenReturn(CustomerListPageTest.createCustomer(i));\n\t\t}\n\t\t\n\t}\n\t\n\t@Test\n\tpublic void assert_customer_not_exists(){\n\t\tPageParameters params = new PageParameters();\n\t\tparams.add(CustomerEditPage.CUSTOMER_ID_PARAM, \"9548\");\n\t\tgetTester().startPage(CustomerEditPage.class, params);\n\t\tgetTester().assertRenderedPage(CustomerListPage.class);\n\t\t\n\t\t\n\t\tgetTester().assertErrorMessages(\"Customer not found 9548\");\n\t\t//TODO how to get a resource from a page which can't be accessed cause of redirect.\n//\t\tLocalizer localizer = getTester().getApplication().getResourceSettings()\n//                .getLocalizer();\n//\t\t\n//\t\tgetTester().assertErrorMessages(MessageFormat.format(localizer.getString(\"customer.not-found\", getTester().getLastRenderedPage()), \"9548\"));\n\t}\n\t\n\t@Test\n\tpublic void assert_customer_on_load_existing(){\n\t\tPageParameters params = new PageParameters();\n\t\tparams.add(CustomerEditPage.CUSTOMER_ID_PARAM, \"3\");\n\t\tgetTester().startPage(CustomerEditPage.class, params);\n\n\t\tgetTester().assertNoErrorMessage();\n\t\tgetTester().assertNoInfoMessage();\n\t\t\n\t\tgetTester().assertRenderedPage(CustomerEditPage.class);\n\t\t\n\t\tFormTester formTester = getTester().newFormTester(\"form\");\n\t\t\n\t\tString username = formTester.getTextComponentValue(borderPath(\"username\"));\n\t\tString firstname = formTester.getTextComponentValue(borderPath(\"firstname\"));\n\t\tString lastname = formTester.getTextComponentValue(borderPath(\"lastname\"));\n\t\t\n\t\tassertThat(username, equalTo(\"username3\"));\n\t\tassertThat(firstname, equalTo(\"firstname3\"));\n\t\tassertThat(lastname, equalTo(\"lastname3\"));\n\t\t\n\t\tgetTester().debugComponentTrees();\n\t\t\n\t\tString usernameFieldPath = \"form:\" + borderPath(\"username\");\n\t\tgetTester().assertComponent(usernameFieldPath, UsernameTextField.class);\n\t\tgetTester().isDisabled(usernameFieldPath);\n\t}\n\t\n\t@Test\n\tpublic void assert_customer_saved(){\n\t\tPageParameters params = new PageParameters();\n\t\tparams.add(CustomerEditPage.CUSTOMER_ID_PARAM, \"3\");\n\t\tgetTester().startPage(CustomerEditPage.class, params);\n\n\t\tFormTester formTester = getTester().newFormTester(\"form\");\n\t\tformTester.setValue(borderPath(\"firstname\"), \"the-new-firstname\");\n\t\tformTester.submit(\"submit\");\n\t\t\n\t\tArgumentCaptor<Customer> customerArgument = ArgumentCaptor.forClass(Customer.class);\n\t\t\n\t\t//it should be checked, that the username does not already exists\n\t\tverify(repository, times(0)).usernameExists(Mockito.any());\n\t\t\n\t\tverify(repository, times(1)).save(Mockito.any());\n\t\tverify(repository, times(1)).save(customerArgument.capture());\n\t\t\n\t\tCustomer value = customerArgument.getValue();\n\t\tassertThat(value.getId(), equalTo(3L));\n\t\tassertThat(value.getUsername(), equalTo(\"username3\"));\n\t\tassertThat(value.getFirstname(), equalTo(\"the-new-firstname\"));\n\t\tassertThat(value.getLastname(), equalTo(\"lastname3\"));\n\n\t}\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/com/giffing/wicket/spring/boot/example/web/security/WicketWebSecurityAdapterTestConfig.java",
    "content": "package com.giffing.wicket.spring.boot.example.web.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n@Configuration\n@Import(WicketWebSecurityAdapterConfig.class)\npublic class WicketWebSecurityAdapterTestConfig {\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {\n        auth\n                .inMemoryAuthentication()\n                .withUser(\"admin\")\n                .password(passwordEncoder.encode(\"admin\"))\n                .authorities(\"USER\", \"ADMIN\");\n    }\n\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/java/test/com/giffing/wicket/spring/boot/example/web/WicketWebApplicationConfig.java",
    "content": "package test.com.giffing.wicket.spring.boot.example.web;\n\nimport org.apache.wicket.Page;\nimport org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession;\nimport org.apache.wicket.markup.html.WebPage;\nimport org.apache.wicket.resource.loader.ClassStringResourceLoader;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\nimport org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport com.giffing.wicket.spring.boot.example.WicketApplication;\nimport com.giffing.wicket.spring.boot.example.web.SpringBootWebPackageIdentifier;\nimport com.giffing.wicket.spring.boot.example.web.pages.customers.CustomerListPage;\nimport com.giffing.wicket.spring.boot.example.web.pages.login.LoginPage;\nimport com.giffing.wicket.spring.boot.starter.app.WicketBootSecuredWebApplication;\nimport com.giffing.wicket.spring.boot.starter.configuration.extensions.external.spring.security.SecureWebSession;\n\n//TODO move to test\n@SpringBootApplication(exclude = {\n        DataSourceAutoConfiguration.class,\n        JpaRepositoriesAutoConfiguration.class,\n        HibernateJpaAutoConfiguration.class,\n})\n@ComponentScan(basePackageClasses = SpringBootWebPackageIdentifier.class)\n@EnableTransactionManagement\npublic class WicketWebApplicationConfig extends WicketBootSecuredWebApplication {\n\n    @Override\n    protected void init() {\n        super.init();\n        // Add WicketApplication.properties resource file\n        getResourceSettings().getStringResourceLoaders().add(new ClassStringResourceLoader(WicketApplication.class));\n    }\n\n    @Override\n    protected Class<? extends WebPage> getSignInPageClass() {\n        return LoginPage.class;\n    }\n\n    @Override\n    public Class<? extends Page> getHomePage() {\n        return CustomerListPage.class;\n    }\n\n    @Override\n    protected Class<? extends AbstractAuthenticatedWebSession> getWebSessionClass() {\n        return SecureWebSession.class;\n    }\n\n}\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/resources/application.yml",
    "content": "spring:\n  main:\n    allow-bean-definition-overriding: true\n  jpa:\n    hibernate:\n      ddl-auto: none\n  liquibase:\n    change-log: classpath:db/changelog/db.changelog-master-test.xml\nwicket:\n  stuff:\n    serializer:\n      fast2:\n        enabled: false\n  core:\n    csrf:\n      enabled: false\n"
  },
  {
    "path": "wicket-spring-boot-starter-example/src/test/resources/db/changelog/db.changelog-master-test.xml",
    "content": "<databaseChangeLog xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\txmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd \n   http://www.liquibase.org/xml/ns/dbchangelog \n   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd\">\n\n\t<include file=\"/db/changelog/init.xml\"/>\n\n\t<changeSet id=\"init-testdata\" author=\"mgiffing\">\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">frodo</column>\n\t\t\t<column name=\"firstname\">Frodo</column>\n\t\t\t<column name=\"lastname\">Beutlin</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">bilbo</column>\n\t\t\t<column name=\"firstname\">Bilbo</column>\n\t\t\t<column name=\"lastname\">Beutlin</column>\n\t\t\t<column name=\"active\">false</column>\n\t\t</insert>\n\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">adalgrim</column>\n\t\t\t<column name=\"firstname\">Adalgrim</column>\n\t\t\t<column name=\"lastname\">Tuk</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">bodo</column>\n\t\t\t<column name=\"firstname\">Bodo</column>\n\t\t\t<column name=\"lastname\">Stolzfuß</column>\n\t\t\t<column name=\"active\">false</column>\n\t\t</insert>\n\n\t\t<insert tableName=\"customer\">\n\t\t\t<column name=\"username\">tuk</column>\n\t\t\t<column name=\"firstname\">Ferdibrand</column>\n\t\t\t<column name=\"lastname\">Tuk</column>\n\t\t\t<column name=\"active\">true</column>\n\t\t</insert>\n\n\t</changeSet>\n\n</databaseChangeLog>"
  }
]