[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Question\n    url: https://github.com/graphql-java-kickstart/graphql-java-servlet/discussions\n    about: Anything you are not sure about? Ask the community in Discussions!\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/add-javax-suffix.sh",
    "content": "#!/bin/bash\n\naddSuffix() {\n  local result\n  result=$(grep include settings.gradle | awk '{print $2}' | tr -d \"'\" | tr -d ':')\n  readarray -t <<<\"$result\"\n  modules=(\"${MAPFILE[@]}\")\n\n  updateLocalDependencies\n}\n\nupdateLocalDependencies() {\n  for module in \"${modules[@]}\"; do\n    cp -rf \"$module\" \"$module\"-javax\n    rm -rf \"$module\"\n\n    for dependency in \"${modules[@]}\"; do\n      sed -i -E \"s/project\\(('|\\\"):${dependency}('|\\\")\\)/project\\(':${dependency}-javax'\\)/\" \"$module\"-\"javax\"/build.gradle\n    done\n  done\n\n  updateGradleSettings\n}\n\nupdateGradleSettings() {\n  for module in \"${modules[@]}\"; do\n    echo \"Replace ${module} with ${module}-javax in settings.gradle\"\n    sed -i -E \"s/('|\\\"):${module}('|\\\")/':${module}-javax'/\" settings.gradle\n  done\n\n  cat settings.gradle\n}\n\necho \"Add suffix -javax to modules\"\naddSuffix\n\nls -lh"
  },
  {
    "path": ".github/release.sh",
    "content": "#!/bin/bash\nset -ev\n\nFLAVOUR=\"${1}\"\n\nremoveSnapshots() {\n  sed -i 's/-SNAPSHOT//' gradle.properties\n}\n\necho \"Publishing release to Maven Central\"\nremoveSnapshots\n\nif [ \"${FLAVOUR}\" == 'javax' ]; then\n  .github/add-javax-suffix.sh\nfi\n\n./gradlew clean build publishToSonatype closeAndReleaseSonatypeStagingRepository\n"
  },
  {
    "path": ".github/replaceJakartaWithJavax.sh",
    "content": "#!/bin/bash\n\n# Set jdk11 as source and target\nsed -i 's/SOURCE_COMPATIBILITY=.*/SOURCE_COMPATIBILITY=11/' gradle.properties\nsed -i 's/TARGET_COMPATIBILITY=.*/TARGET_COMPATIBILITY=11/' gradle.properties\n\n# Replace jakarta imports and dependencies with javax\ngrep -rl 'import jakarta' ./graphql-java-servlet | xargs sed -i 's/import jakarta/import javax/g'\nsed -i 's/.*jakarta.websocket:jakarta.websocket-client-api.*//' graphql-java-servlet/build.gradle\nsed -i \\\n  's/jakarta.servlet:jakarta.servlet-api.*/javax.servlet:javax.servlet-api:$LIB_JAVAX_SERVLET\"/' \\\n  graphql-java-servlet/build.gradle\nsed -i \\\n  's/jakarta.websocket.*/javax.websocket:javax.websocket-api:$LIB_JAVAX_WEBSOCKET\"/' \\\n  graphql-java-servlet/build.gradle\n\n# Final check if there are something else to replace\ngrep -rl 'jakarta' ./graphql-java-servlet | xargs sed -i 's/jakarta/javax/g'\n\n# Set the version 5 for spring framework\nsed -i \\\n  's/org.springframework:spring-test.*/org.springframework:spring-test:$LIB_SPRINGFRAMEWORK_5\"/' \\\n  graphql-java-servlet/build.gradle\nsed -i \\\n  's/org.springframework:spring-web.*/org.springframework:spring-web:$LIB_SPRINGFRAMEWORK_5\"/' \\\n  graphql-java-servlet/build.gradle\n\necho \"Replaced jakarta occurrences with javax\""
  },
  {
    "path": ".github/tag-release.sh",
    "content": "#!/bin/bash\nset -ev\n\ngetVersion() {\n  ./gradlew properties -q | grep -E \"^version\" | awk '{print $2}' | tr -d '[:space:]'\n}\n\nremoveSnapshots() {\n  sed -i 's/-SNAPSHOT//' gradle.properties\n}\n\ncommitRelease() {\n  local APP_VERSION\n  APP_VERSION=$(getVersion)\n  git commit -a -m \"Update version for release\"\n  git tag -a \"v${APP_VERSION}\" -m \"Tag release version\"\n}\n\nbumpVersion() {\n  echo \"Bump version number\"\n  local APP_VERSION\n  APP_VERSION=$(getVersion | xargs)\n  local SEMANTIC_REGEX='^([0-9]+)\\.([0-9]+)(\\.([0-9]+))?$'\n  if [[ ${APP_VERSION} =~ ${SEMANTIC_REGEX} ]]; then\n    if [[ ${BASH_REMATCH[4]} ]]; then\n      nextVersion=$((BASH_REMATCH[4] + 1))\n      nextVersion=\"${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${nextVersion}-SNAPSHOT\"\n    else\n      nextVersion=$((BASH_REMATCH[2] + 1))\n      nextVersion=\"${BASH_REMATCH[1]}.${nextVersion}-SNAPSHOT\"\n    fi\n\n    echo \"Next version: ${nextVersion}\"\n    sed -i -E \"s/^version(\\s)?=.*/version=${nextVersion}/\" gradle.properties\n    git commit -a -m \"Bumped version for next release\"\n  else\n    echo \"No semantic version and therefore cannot publish to maven repository: '${APP_VERSION}'\"\n  fi\n}\n\ngit config --global user.email \"actions@github.com\"\ngit config --global user.name \"GitHub Actions\"\n\necho \"Deploying release to Maven Central\"\nremoveSnapshots\ncommitRelease\nbumpVersion\ngit push --follow-tags"
  },
  {
    "path": ".github/workflows/pull-request.yml",
    "content": "name: \"Pull request\"\non:\n  pull_request:\n    types: [ opened, synchronize, reopened ]\n\njobs:\n  validation:\n    name: Gradle Wrapper Validation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: gradle/wrapper-validation-action@v3\n\n  test:\n    name: Test run\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ ubuntu-latest, macos-latest, windows-latest ]\n        java: [ 17, 19 ]\n    needs: validation\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.java }}\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: ${{ matrix.java }}\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable (non-Windows only)\n        if: matrix.os != 'windows-latest'\n        run: chmod +x ./gradlew\n      - name: Gradle Check (non-Windows)\n        if: matrix.os != 'windows-latest'\n        run: ./gradlew --info check\n      - name: Gradle Check (Windows)\n        if: matrix.os == 'windows-latest'\n        shell: cmd\n        run: gradlew --info check\n\n  build:\n    name: Sonar analysis\n    needs: validation\n    runs-on: ubuntu-latest\n    env:\n      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n    steps:\n      - uses: actions/checkout@v4\n        if: env.SONAR_TOKEN != null\n        with:\n          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis\n      - name: Set up JDK 17\n        if: env.SONAR_TOKEN != null\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache SonarCloud packages\n        if: env.SONAR_TOKEN != null\n        uses: actions/cache@v4\n        with:\n          path: ~/.sonar/cache\n          key: ${{ runner.os }}-sonar\n          restore-keys: ${{ runner.os }}-sonar\n      - name: Cache Gradle packages\n        if: env.SONAR_TOKEN != null\n        uses: actions/cache@v4\n        with:\n          path: ~/.gradle/caches\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}\n          restore-keys: ${{ runner.os }}-gradle\n      - name: Build and analyze\n        if: env.SONAR_TOKEN != null\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n        run: ./gradlew build jacocoTestReport sonarqube --info\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: \"Publish release\"\non: [ workflow_dispatch ]\n\njobs:\n  validation:\n    name: Gradle Wrapper Validation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: gradle/wrapper-validation-action@v3\n\n  test-jakarta:\n    name: Test run jakarta\n    needs: validation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 17\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Gradle Check\n        run: ./gradlew --info check\n\n  build-jakarta:\n    name: Publish release jakarta\n    needs: test-jakarta\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 17\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Prepare environment\n        env:\n          GPG_KEY_CONTENTS: ${{ secrets.GPG_KEY_CONTENTS }}\n          SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.GPG_SIGNING_SECRET_KEY_RING_FILE }}\n        run: sudo bash -c \"echo '$GPG_KEY_CONTENTS' | base64 -d > '$SIGNING_SECRET_KEY_RING_FILE'\"\n      - name: Publish release\n        env:\n          SIGNING_KEY_ID: ${{ secrets.GPG_SIGNING_KEY_ID }}\n          SIGNING_PASSWORD: ${{ secrets.GPG_SIGNING_PASSWORD }}\n          SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.GPG_SIGNING_SECRET_KEY_RING_FILE }}\n          OSS_USER_TOKEN_KEY: ${{ secrets.OSS_USER_TOKEN_KEY }}\n          OSS_USER_TOKEN_PASS: ${{ secrets.OSS_USER_TOKEN_PASS }}\n        run: .github/release.sh\n\n  test-javax:\n    name: Test run javax\n    needs: validation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 11\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 11\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Replace jakarta with javax\n        run: .github/replaceJakartaWithJavax.sh\n      - name: Gradle Check\n        run: ./gradlew --info check\n\n  build-javax:\n    name: Publish release javax\n    needs: test-javax\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 11\n\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 11\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Prepare environment\n        env:\n          GPG_KEY_CONTENTS: ${{ secrets.GPG_KEY_CONTENTS }}\n          SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.GPG_SIGNING_SECRET_KEY_RING_FILE }}\n        run: sudo bash -c \"echo '$GPG_KEY_CONTENTS' | base64 -d > '$SIGNING_SECRET_KEY_RING_FILE'\"\n      - name: Replace jakarta with javax\n        run: .github/replaceJakartaWithJavax.sh\n      - name: Publish release\n        env:\n          SIGNING_KEY_ID: ${{ secrets.GPG_SIGNING_KEY_ID }}\n          SIGNING_PASSWORD: ${{ secrets.GPG_SIGNING_PASSWORD }}\n          SIGNING_SECRET_KEY_RING_FILE: ${{ secrets.GPG_SIGNING_SECRET_KEY_RING_FILE }}\n          OSS_USER_TOKEN_KEY: ${{ secrets.OSS_USER_TOKEN_KEY }}\n          OSS_USER_TOKEN_PASS: ${{ secrets.OSS_USER_TOKEN_PASS }}\n        run: .github/release.sh javax\n  tag:\n    name: Tag release\n    needs: [ build-jakarta, build-javax ]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 17\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Tag release\n        run: .github/tag-release.sh\n"
  },
  {
    "path": ".github/workflows/snapshot.yml",
    "content": "name: \"Publish snapshot\"\non:\n  push:\n    branches:\n      - master\n\njobs:\n  validation:\n    name: Gradle Wrapper Validation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: gradle/wrapper-validation-action@v3\n\n  test-jakarta:\n    name: Test run jakarta\n    needs: validation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 17\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Gradle Check\n        run: ./gradlew --info check\n\n  build-jakarta:\n    name: Publish snapshot jakarta\n    needs: test-jakarta\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 17\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Gradle Publish Snapshot\n        if: env.OSS_USER_TOKEN_KEY != null\n        env:\n          OSS_USER_TOKEN_KEY: ${{ secrets.OSS_USER_TOKEN_KEY }}\n          OSS_USER_TOKEN_PASS: ${{ secrets.OSS_USER_TOKEN_PASS }}\n        run: ./gradlew clean build publish -x test\n\n  test-javax:\n    name: Test run javax\n    needs: validation\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 11\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 11\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Replace jakarta with javax\n        run: .github/replaceJakartaWithJavax.sh\n      - name: Gradle Check\n        run: ./gradlew --info check\n\n  build-javax:\n    name: Publish snapshot javax\n    needs: test-javax\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 11\n      - name: Cache Gradle\n        uses: actions/cache@v4\n        env:\n          java-version: 11\n        with:\n          path: |\n            ~/.gradle/caches\n            ~/.gradle/wrapper\n          key: ${{ runner.os }}-${{ env.java-version }}-gradle-${{ hashFiles('**/*.gradle*') }}\n          restore-keys: |\n            ${{ runner.os }}-${{ env.java-version }}-gradle-\n      - name: Make gradlew executable\n        run: chmod +x ./gradlew\n      - name: Replace jakarta with javax\n        run: .github/replaceJakartaWithJavax.sh\n      - name: Add suffix to modules\n        run: .github/add-javax-suffix.sh\n      - name: Gradle Publish Snapshot\n        if: env.OSS_USER_TOKEN_KEY != null\n        env:\n          OSS_USER_TOKEN_KEY: ${{ secrets.OSS_USER_TOKEN_KEY }}\n          OSS_USER_TOKEN_PASS: ${{ secrets.OSS_USER_TOKEN_PASS }}\n        run: ./gradlew clean build publish -x test\n\n  sonar:\n    name: Sonar analysis\n    needs: validation\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis\n      - name: Set up JDK 17\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: 17\n      - name: Cache SonarCloud packages\n        uses: actions/cache@v4\n        with:\n          path: ~/.sonar/cache\n          key: ${{ runner.os }}-sonar\n          restore-keys: ${{ runner.os }}-sonar\n      - name: Cache Gradle packages\n        uses: actions/cache@v4\n        with:\n          path: ~/.gradle/caches\n          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}\n          restore-keys: ${{ runner.os }}-gradle\n      - name: Build and analyze\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n        if: env.SONAR_TOKEN != null\n        run: ./gradlew build jacocoTestReport sonarqube --info\n"
  },
  {
    "path": ".gitignore",
    "content": ".gradle/\nbuild/\n*.iml\n*.ipr\n*.iws\n.idea/*\n!.idea/codeStyles/\ntarget/\n/out/\n.classpath\n.project\n.settings\nbin\n.DS_Store\n/**/out/\n/projectFilesBackup/.idea/workspace.xml\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nWe're really glad you're reading this, because we need more volunteer developers\nto help with this project!\n\nWe can use all the help we can get on all our [GraphQL Java Kickstart](https://github.com/graphql-java-kickstart)\nprojects. This work ranges from adding new features, fixing bugs, and answering questions to writing documentation. \n\n## Answering questions and writing documentation\n\nA lot of the questions asked on Spectrum or Github are caused by a lack of documentation.\nWe should strive from now on to answer questions by adding content to \nour [documentation](https://github.com/graphql-java-kickstart/documentation) and referring\nthem to the newly created content.\n\nContinuous integration will make sure that the changes are automatically deployed to \nhttps://www.graphql-java-kickstart.com.\n\n## Submitting changes\n\nPlease send a Pull Request with a clear list of what you've done using the\n[Github flow](https://guides.github.com/introduction/flow/). We can always use more\ntest coverage, so we'd love to see that in the pull requests too. And make sure to\nfollow our coding conventions (below) and make sure all your commits are atomic \n(one feature per commit).\n\n## Coding conventions\n\nWe use Google Style guides for our projects. See the \n[Java Style Guide](https://google.github.io/styleguide/javaguide.html) for a detailed\ndescription. You can download the \n[IntelliJ Java Google Style](https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml)\nto import in these settings in IntelliJ.\n\nThese conventions are checked during the build phase. If the build fails because\nthe code is not using the correct style you can fix this easily by running a gradle task\n```bash\n./gradlew googleJavaFormat\n```\n\n### SonarLint\n\nIt would also be very helpful to install the SonarLint plugin in your IDE and fix any\nrelevant SonarLint issues before pushing a PR. We're aware that the current state\nof the code raises a lot of SonarLint issues out of the box, but any help in reducing\nthat is appreciated. More importantly we don't increase that technical debt.\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright 2016 Yurii Rashkovskii and Contributors\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\n"
  },
  {
    "path": "README.md",
    "content": "# GraphQL Java Servlet\n[![Maven Central](https://img.shields.io/maven-central/v/com.graphql-java-kickstart/graphql-java-servlet.svg)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java-kickstart/graphql-java-servlet)\n[![Build Status](https://github.com/graphql-java-kickstart/graphql-java-servlet/workflows/Publish%20snapshot/badge.svg)](https://github.com/graphql-java-kickstart/graphql-java-servlet/actions?query=workflow%3A%22Publish+snapshot%22)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=graphql-java-kickstart_graphql-java-servlet&metric=alert_status)](https://sonarcloud.io/dashboard?id=graphql-java-kickstart_graphql-java-servlet)\n[![GitHub contributors](https://img.shields.io/github/contributors/graphql-java-kickstart/graphql-java-servlet)](https://github.com/graphql-java-kickstart/graphql-java-servlet/graphs/contributors)\n[![Discuss on GitHub](https://img.shields.io/badge/GitHub-discuss-orange)](https://github.com/graphql-java-kickstart/graphql-java-servlet/discussions)\n\n\n## We are looking for contributors!\nAre you interested in improving our documentation, working on the codebase, reviewing PRs?\n\n[Reach out to us on Discussions](https://github.com/graphql-java-kickstart/graphql-java-servlet/discussions) and join the team!\n\nWe hope you'll get involved! Read our [Contributors' Guide](CONTRIBUTING.md) for more details.\n\n## Overview\nImplementation of GraphQL Java Servlet including support for Relay.js, Apollo and OSGi out of the box.\nThis project wraps the Java implementation of GraphQL provided by [GraphQL Java](https://www.graphql-java.com).\nSee [GraphQL Java documentation](https://www.graphql-java.com/documentation/latest/) for more in depth details\nregarding GraphQL Java itself. \n\nWe try to stay up to date with GraphQL Java as much as possible maintaining the retro-compatibility\nwith javax and Springframework 5.\n\nOn each release we publish three flavours of this project:\n - [latest jakarta](#jakarta-and-springframework-6)\n - [jakarta5](#jakarta5)\n - [javax](#javax-and-springframework-5)\n \nAll of them also supports legacy projects that can compile with older JDK versions: the minimum JDK\nversion supported is the `11`.\n\n## Jakarta and Springframework 6.*\nThis is the main flavour using the latest version of `Jakarta` (currently the `6.*`) and the latest\nversion of `Springframework` (currently the `6.*`). All the codebase can be found in the branch: \n`master`\n\n```xml\n<dependency>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <artifactId>graphql-java-servlet</artifactId>\n    <version>${graphql-java-servlet.version}</version>\n</dependency>\n```\n\n## Jakarta5\nThis flavour use the `jakarta` version `5.*` and it is meant to be used for all the projects that \nare already migrated to jakarta, but they are waiting that `jakarta6` will become more broadly used.\nAll the codebase can be found in the branch: `jakarta5`\n\n```xml\n<dependency>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <artifactId>graphql-java-servlet-jakarta5</artifactId>\n    <version>${graphql-java-servlet-jakarta5.version}</version>\n</dependency>\n```\n\n## Javax and Springframework 5.*\nThis is the legacy flavour using the `javax` dependency and the version `5.*` of `Springframework` \n(since it is still broadly used by a lot of projects). All the codebase can be found in the branch: \n`master` \n\n```xml\n<dependency>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <artifactId>graphql-java-servlet-javax</artifactId>\n    <version>${graphql-java-servlet.version}</version>\n</dependency>\n```\n\n\n## Installation and getting started\n\nSee [Getting started](https://graphql-java-kickstart.github.io/servlet/getting-started/) for more\ndetailed instructions.\n"
  },
  {
    "path": "build.gradle",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2016 oEmbedler Inc. and Contributors\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n *  documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the\n *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit\n *  persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING\n * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nbuildscript {\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        maven { url \"https://plugins.gradle.org/m2/\" }\n        maven { url 'https://repo.spring.io/plugins-release' }\n    }\n}\n\nplugins {\n    id \"biz.aQute.bnd.builder\" version \"6.4.0\" apply false\n    id \"org.sonarqube\" version \"5.1.0.4882\"\n    id \"jacoco\"\n    id \"io.github.gradle-nexus.publish-plugin\" version '2.0.0'\n}\n\nsonarqube {\n    properties {\n        property \"sonar.projectKey\", \"graphql-java-kickstart_graphql-java-servlet\"\n        property \"sonar.organization\", \"graphql-java-kickstart\"\n        property \"sonar.host.url\", \"https://sonarcloud.io\"\n    }\n}\n\nsubprojects {\n    apply plugin: 'idea'\n    apply plugin: 'jacoco'\n    apply plugin: 'org.sonarqube'\n    apply plugin: 'java'\n    apply plugin: 'maven-publish'\n    apply plugin: 'signing'\n\n    repositories {\n        mavenLocal()\n        mavenCentral()\n        maven { url \"https://oss.sonatype.org/content/repositories/snapshots\" }\n        maven { url \"https://repo.spring.io/libs-milestone\" }\n    }\n\n    dependencies {\n        compileOnly \"org.projectlombok:lombok:$LIB_LOMBOK_VER\"\n        annotationProcessor \"org.projectlombok:lombok:$LIB_LOMBOK_VER\"\n\n        testCompileOnly \"org.projectlombok:lombok:$LIB_LOMBOK_VER\"\n        testAnnotationProcessor \"org.projectlombok:lombok:$LIB_LOMBOK_VER\"\n    }\n\n    idea {\n        module {\n            downloadJavadoc = true\n            downloadSources = true\n        }\n    }\n\n    compileJava {\n        sourceCompatibility = SOURCE_COMPATIBILITY\n        targetCompatibility = TARGET_COMPATIBILITY\n    }\n\n    compileTestJava {\n        sourceCompatibility = SOURCE_COMPATIBILITY_TEST\n        targetCompatibility = TARGET_COMPATIBILITY_TEST\n    }\n\n    compileJava.dependsOn(processResources)\n\n    test {\n        useJUnitPlatform()\n\n        afterSuite { desc, result ->\n            if (!desc.parent) {\n                if (result.testCount == 0) {\n                    throw new IllegalStateException(\"No tests were found. Failing the build\")\n                }\n            }\n        }\n    }\n\n    jacocoTestReport {\n        reports {\n            xml.required = true\n            html.required = false\n            csv.required = false\n        }\n    }\n\n    if (!it.name.startsWith('example')) {\n        jar {\n            from \"LICENSE.md\"\n        }\n\n        java {\n            withSourcesJar()\n            withJavadocJar()\n        }\n\n        if (!version.toString().endsWith('-SNAPSHOT')) {\n            ext[\"signing.keyId\"] = System.env.SIGNING_KEY_ID\n            ext[\"signing.password\"] = System.env.SIGNING_PASSWORD\n            ext[\"signing.secretKeyRingFile\"] = System.env.SIGNING_SECRET_KEY_RING_FILE\n\n            signing {\n                sign publishing.publications\n            }\n        }\n\n        publishing {\n            publications {\n                mavenJava(MavenPublication) {\n                    version version\n                    from components.java\n\n                    versionMapping {\n                        usage('java-api') {\n                            fromResolutionOf('runtimeClasspath')\n                        }\n                        usage('java-runtime') {\n                            fromResolutionResult()\n                        }\n                    }\n\n                    pom {\n                        name = PROJECT_NAME\n                        description = 'relay.js-compatible GraphQL servlet'\n                        url = 'https://github.com/graphql-java-kickstart/graphql-java-servlet'\n                        inceptionYear = '2016'\n\n                        scm {\n                            url = 'https://github.com/graphql-java-kickstart/graphql-java-servlet'\n                            connection = 'scm:https://github.com/graphql-java-kickstart/graphql-java-servlet.git'\n                            developerConnection = 'scm:git://github.com/graphql-java-kickstart/graphql-java-servlet.git'\n                        }\n\n                        licenses {\n                            license {\n                                name = 'The Apache Software License, Version 2.0'\n                                url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'\n                                distribution = 'repo'\n                            }\n                        }\n\n                        developers {\n                            developer {\n                                id = 'oliemansm'\n                                name = 'Michiel Oliemans'\n                            }\n                            developer {\n                                id = 'yrashk'\n                                name = 'Yurii Rashkovskii'\n                                email = 'yrashk@gmail.com'\n                            }\n                            developer {\n                                id = 'apottere'\n                                name = 'Andrew Potter'\n                                email = 'apottere@gmail.com'\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nnexusPublishing {\n    repositories {\n        sonatype {\n            username = System.env.OSS_USER_TOKEN_KEY ?: project.findProperty('OSS_USER_TOKEN_KEY') ?: ''\n            password = System.env.OSS_USER_TOKEN_PASS ?: project.findProperty('OSS_USER_TOKEN_PASS') ?: ''\n        }\n    }\n}\n\nwrapper {\n    distributionType = Wrapper.DistributionType.ALL\n}\n"
  },
  {
    "path": "examples/osgi/apache-karaf-feature/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xmlns=\"http://maven.apache.org/POM/4.0.0\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <artifactId>graphql-java-servlet-osgi-examples-karaf-feature</artifactId>\n  <build>\n    <plugins>\n      <plugin>\n        <artifactId>karaf-maven-plugin</artifactId>\n        <configuration>\n          <addTransitiveFeatures>true</addTransitiveFeatures>\n          <includeTransitiveDependency>true</includeTransitiveDependency>\n          <startLevel>80</startLevel>\n        </configuration>\n        <extensions>true</extensions>\n        <groupId>org.apache.karaf.tooling</groupId>\n        <version>4.2.10</version>\n      </plugin>\n\n      <plugin>\n        <artifactId>maven-install-plugin</artifactId>\n        <groupId>org.apache.maven.plugins</groupId>\n        <version>2.5.2</version>\n      </plugin>\n      <plugin>\n        <artifactId>maven-deploy-plugin</artifactId>\n        <groupId>org.apache.maven.plugins</groupId>\n        <version>2.8.2</version>\n      </plugin>\n    </plugins>\n\n  </build>\n\n  <dependencies>\n    <dependency>\n      <artifactId>jackson-core</artifactId>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <version>${jackson.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>jackson-annotations</artifactId>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <version>${jackson.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>jackson-databind</artifactId>\n      <groupId>com.fasterxml.jackson.core</groupId>\n      <version>${jackson.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>jackson-datatype-jdk8</artifactId>\n      <groupId>com.fasterxml.jackson.datatype</groupId>\n      <version>${jackson.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>guava</artifactId>\n      <groupId>com.google.guava</groupId>\n      <version>[24.1.1,)</version>\n    </dependency>\n    <dependency>\n      <artifactId>commons-fileupload</artifactId>\n      <groupId>commons-fileupload</groupId>\n      <version>[1.3.3,)</version>\n    </dependency>\n    <dependency>\n      <artifactId>antlr4-runtime</artifactId>\n      <groupId>org.antlr</groupId>\n      <version>4.7.1</version>\n    </dependency>\n\n    <dependency>\n      <artifactId>graphql-java-servlet</artifactId>\n      <groupId>com.graphql-java-kickstart</groupId>\n      <version>${graphql.java.servlet.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>graphql-java</artifactId>\n      <groupId>com.graphql-java</groupId>\n      <version>${graphql.java.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>graphql-java-annotations</artifactId>\n      <groupId>com.graphql-java</groupId>\n      <version>0.13.1</version>\n    </dependency>\n\n    <dependency>\n      <artifactId>graphql-java-servlet-osgi-examples-providers</artifactId>\n      <groupId>com.graphql-java-kickstart</groupId>\n      <version>${project.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>slf4j-api</artifactId>\n      <groupId>org.slf4j</groupId>\n      <version>1.7.25</version>\n    </dependency>\n    <dependency>\n      <artifactId>slf4j-log4j12</artifactId>\n      <groupId>org.slf4j</groupId>\n      <version>1.7.25</version>\n    </dependency>\n  </dependencies>\n  <modelVersion>4.0.0</modelVersion>\n\n  <packaging>feature</packaging>\n\n\n  <parent>\n    <artifactId>graphql-java-servlet-osgi-examples</artifactId>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <version>10.1.0</version>\n  </parent>\n\n  <properties>\n    <jackson.version>2.13.4.2</jackson.version>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "examples/osgi/apache-karaf-feature/src/main/feature/feature.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<features name=\"graphql-java-servlet-osgi-examples-karaf-feature\"\n  xmlns=\"http://karaf.apache.org/xmlns/features/v1.4.0\">\n  <feature description=\"graphql-java-servlet-osgi-examples-karaf-feature\"\n    name=\"graphql-java-servlet-osgi-examples-karaf-feature\">\n    <feature dependency=\"false\" prerequisite=\"true\">scr</feature>\n    <feature dependency=\"false\" prerequisite=\"true\">war</feature>\n    <feature dependency=\"false\" prerequisite=\"true\">http</feature>\n  </feature>\n</features>\n"
  },
  {
    "path": "examples/osgi/apache-karaf-package/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xmlns=\"http://maven.apache.org/POM/4.0.0\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <artifactId>graphql-java-servlet-osgi-examples-apache-karaf-package</artifactId>\n  <build>\n    <!-- if you want to include resources in the distribution -->\n    <plugins>\n      <!-- if you want to include resources in the distribution -->\n      <plugin>\n        <artifactId>maven-resources-plugin</artifactId>\n        <executions>\n          <execution>\n            <goals>\n              <goal>resources</goal>\n            </goals>\n            <id>process-resources</id>\n          </execution>\n        </executions>\n        <groupId>org.apache.maven.plugins</groupId>\n        <version>2.6</version>\n      </plugin>\n      <plugin>\n        <artifactId>karaf-maven-plugin</artifactId>\n        <configuration>\n          <!-- no startupFeatures -->\n          <bootFeatures>\n            <feature>minimal</feature>\n            <feature>wrapper</feature>\n            <feature>graphql-java-servlet-osgi-examples-karaf-feature</feature>\n          </bootFeatures>\n          <installedFeatures>\n          </installedFeatures>\n        </configuration>\n        <extensions>true</extensions>\n        <groupId>org.apache.karaf.tooling</groupId>\n        <version>${karaf.version}</version>\n      </plugin>\n\n      <plugin>\n        <artifactId>maven-install-plugin</artifactId>\n        <groupId>org.apache.maven.plugins</groupId>\n        <version>2.5.2</version>\n      </plugin>\n      <plugin>\n        <artifactId>maven-deploy-plugin</artifactId>\n        <groupId>org.apache.maven.plugins</groupId>\n        <version>2.8.2</version>\n      </plugin>\n    </plugins>\n\n    <resources>\n      <resource>\n        <directory>src/main/resources</directory>\n        <filtering>false</filtering>\n        <includes>\n          <include>**/*</include>\n        </includes>\n      </resource>\n      <resource>\n        <directory>src/main/filtered-resources</directory>\n        <filtering>true</filtering>\n        <includes>\n          <include>**/*</include>\n        </includes>\n      </resource>\n    </resources>\n  </build>\n\n  <dependencies>\n    <dependency>\n      <!-- scope is compile so all features (there is only one) are installed into startup.properties and the feature repo itself is not added in etc/org.apache.karaf.features.cfg file -->\n      <artifactId>framework</artifactId>\n      <groupId>org.apache.karaf.features</groupId>\n      <type>kar</type>\n      <version>${karaf.version}</version>\n    </dependency>\n    <dependency>\n      <!-- scope is runtime so the feature repo is listed in etc/org.apache.karaf.features.cfg file, and features will installed into the system directory if specify in the plugin configuration -->\n      <artifactId>standard</artifactId>\n      <classifier>features</classifier>\n      <groupId>org.apache.karaf.features</groupId>\n      <scope>runtime</scope>\n      <type>xml</type>\n      <version>${karaf.version}</version>\n    </dependency>\n    <dependency>\n      <!-- scope is runtime so the feature repo is listed in etc/org.apache.karaf.features.cfg file, and features will installed into the system directory if specify in the plugin configuration -->\n      <artifactId>enterprise</artifactId>\n      <classifier>features</classifier>\n      <groupId>org.apache.karaf.features</groupId>\n      <scope>runtime</scope>\n      <type>xml</type>\n      <version>${karaf.version}</version>\n    </dependency>\n\n    <dependency>\n      <artifactId>graphql-java-servlet-osgi-examples-karaf-feature</artifactId>\n      <classifier>features</classifier>\n      <groupId>com.graphql-java-kickstart</groupId>\n      <scope>runtime</scope>\n      <type>xml</type>\n      <version>${project.version}</version>\n    </dependency>\n  </dependencies>\n  <modelVersion>4.0.0</modelVersion>\n\n  <packaging>karaf-assembly</packaging>\n\n  <parent>\n    <artifactId>graphql-java-servlet-osgi-examples</artifactId>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <version>10.1.0</version>\n  </parent>\n</project>\n"
  },
  {
    "path": "examples/osgi/buildAndRun.sh",
    "content": "#!/usr/bin/env bash\nmvn clean install\npushd apache-karaf-package/target || exit 1\ntar zxvf graphql-java-servlet-osgi-examples-apache-karaf-package-10.1.0.tar.gz\ncd graphql-java-servlet-osgi-examples-apache-karaf-package-10.1.0/bin || exit 1\n./karaf debug\npopd || exit 1\n"
  },
  {
    "path": "examples/osgi/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xmlns=\"http://maven.apache.org/POM/4.0.0\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <artifactId>graphql-java-servlet-osgi-examples</artifactId>\n\n  <groupId>com.graphql-java-kickstart</groupId>\n  <modelVersion>4.0.0</modelVersion>\n  <modules>\n    <module>providers</module>\n    <module>apache-karaf-feature</module>\n    <module>apache-karaf-package</module>\n  </modules>\n  <packaging>pom</packaging>\n\n  <properties>\n    <graphql.java.servlet.version>11.0.0-SNAPSHOT</graphql.java.servlet.version>\n    <graphql.java.version>16.1</graphql.java.version>\n    <karaf.version>4.2.10</karaf.version>\n    <maven.compiler.source>11</maven.compiler.source>\n    <maven.compiler.target>11</maven.compiler.target>\n  </properties>\n\n  <version>10.1.0</version>\n\n</project>\n"
  },
  {
    "path": "examples/osgi/providers/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xmlns=\"http://maven.apache.org/POM/4.0.0\"\n  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <artifactId>graphql-java-servlet-osgi-examples-providers</artifactId>\n  <build>\n    <plugins>\n      <plugin>\n        <artifactId>maven-bundle-plugin</artifactId>\n        <configuration>\n        </configuration>\n        <extensions>true</extensions>\n        <groupId>org.apache.felix</groupId>\n        <version>3.3.0</version>\n      </plugin>\n    </plugins>\n  </build>\n\n  <dependencies>\n    <dependency>\n      <artifactId>graphql-java-servlet</artifactId>\n      <groupId>com.graphql-java-kickstart</groupId>\n      <scope>provided</scope>\n      <version>${graphql.java.servlet.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>graphql-java</artifactId>\n      <groupId>com.graphql-java</groupId>\n      <scope>provided</scope>\n      <version>${graphql.java.version}</version>\n    </dependency>\n    <dependency>\n      <artifactId>osgi.enterprise</artifactId>\n      <groupId>org.osgi</groupId>\n      <scope>provided</scope>\n      <version>6.0.0</version>\n    </dependency>\n    <dependency>\n      <artifactId>org.apache.felix.scr.ds-annotations</artifactId>\n      <groupId>org.apache.felix</groupId>\n      <scope>provided</scope>\n      <version>1.2.4</version>\n    </dependency>\n  </dependencies>\n  <modelVersion>4.0.0</modelVersion>\n\n  <packaging>bundle</packaging>\n\n  <parent>\n    <artifactId>graphql-java-servlet-osgi-examples</artifactId>\n    <groupId>com.graphql-java-kickstart</groupId>\n    <version>10.1.0</version>\n  </parent>\n\n</project>\n"
  },
  {
    "path": "examples/osgi/providers/src/main/java/graphql/servlet/examples/osgi/ExampleGraphQLProvider.java",
    "content": "package graphql.servlet.examples.osgi;\n\nimport graphql.schema.GraphQLFieldDefinition;\nimport graphql.schema.GraphQLType;\nimport graphql.kickstart.servlet.osgi.GraphQLMutationProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLQueryProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLTypesProvider;\nimport org.osgi.service.component.annotations.Component;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport static graphql.Scalars.GraphQLString;\nimport static graphql.schema.GraphQLFieldDefinition.*;\n\n@Component(\n    name = \"ExampleGraphQLProvider\",\n    immediate = true\n)\npublic class ExampleGraphQLProvider implements GraphQLQueryProvider, GraphQLMutationProvider,\n    GraphQLTypesProvider {\n\n  public Collection<GraphQLFieldDefinition> getQueries() {\n    List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<GraphQLFieldDefinition>();\n    fieldDefinitions.add(newFieldDefinition()\n        .type(GraphQLString)\n        .name(\"hello\")\n        .description(\n            \"Basic example of a GraphQL Java Servlet provider using the Apache Karaf OSGi Runtime\")\n        .staticValue(\"world\")\n        .build());\n    return fieldDefinitions;\n  }\n\n  public Collection<GraphQLFieldDefinition> getMutations() {\n    return new ArrayList<GraphQLFieldDefinition>();\n  }\n\n  public Collection<GraphQLType> getTypes() {\n    return new ArrayList<GraphQLType>();\n  }\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.10.2-all.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "version=16.0.0\ngroup=com.graphql-java-kickstart\nPROJECT_NAME=graphql-java-servlet\nPROJECT_DESC=GraphQL Java Kickstart\nPROJECT_GIT_REPO_URL=https://github.com/graphql-java-kickstart/graphql-java-servlet\nPROJECT_LICENSE=MIT\nPROJECT_LICENSE_URL=https://github.com/graphql-java-kickstart/spring-java-servlet/blob/master/LICENSE.md\nPROJECT_DEV_ID=oliemansm\nPROJECT_DEV_NAME=Michiel Oliemans\nLIB_GRAPHQL_JAVA_VER=22.3\nLIB_JACKSON_VER=2.17.2\nLIB_SLF4J_VER=2.0.16\nLIB_LOMBOK_VER=1.18.34\n# These constants are necessary to the automatic release of javax flavour\nLIB_JAVAX_SERVLET=4.0.1\nLIB_JAVAX_WEBSOCKET=1.1\nLIB_SPRINGFRAMEWORK_5=5.3.25\nSOURCE_COMPATIBILITY=11\nTARGET_COMPATIBILITY=11\nSOURCE_COMPATIBILITY_TEST=17\nTARGET_COMPATIBILITY_TEST=17\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        org.gradle.wrapper.GradleWrapperMain \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "graphql-java-kickstart/bnd.bnd",
    "content": "Export-Package: graphql.kickstart.*\nImport-Package: !lombok,*\n"
  },
  {
    "path": "graphql-java-kickstart/build.gradle",
    "content": "apply plugin: 'biz.aQute.bnd.builder'\n\njar {\n    bndfile = 'bnd.bnd'\n}\n\napply plugin: 'java-library-distribution'\n\ndependencies {\n    // GraphQL\n    api \"com.graphql-java:graphql-java:$LIB_GRAPHQL_JAVA_VER\"\n    implementation \"org.slf4j:slf4j-api:$LIB_SLF4J_VER\"\n\n    // JSON\n    api \"com.fasterxml.jackson.core:jackson-core:$LIB_JACKSON_VER\"\n    api \"com.fasterxml.jackson.core:jackson-annotations:$LIB_JACKSON_VER\"\n    api \"com.fasterxml.jackson.core:jackson-databind:2.17.2\"\n    api \"com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$LIB_JACKSON_VER\"\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/BatchedDataLoaderGraphQLBuilder.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.GraphQL;\nimport graphql.kickstart.execution.config.GraphQLBuilder;\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\n\npublic class BatchedDataLoaderGraphQLBuilder {\n\n  GraphQL newGraphQL(GraphQLBatchedInvocationInput invocationInput, GraphQLBuilder graphQLBuilder) {\n    return invocationInput.getInvocationInputs().stream()\n        .findFirst()\n        .map(GraphQLSingleInvocationInput::getSchema)\n        .map(schema -> graphQLBuilder.build(schema, graphQLBuilder.getInstrumentationSupplier()))\n        .orElseThrow(\n            () ->\n                new IllegalArgumentException(\n                    \"Batched invocation input must contain at least one query\"));\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/DecoratedExecutionResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionResult;\nimport graphql.GraphQLError;\nimport java.util.List;\nimport java.util.Map;\nimport lombok.RequiredArgsConstructor;\nimport org.reactivestreams.Publisher;\n\n@RequiredArgsConstructor\nclass DecoratedExecutionResult implements ExecutionResult {\n\n  private final ExecutionResult result;\n\n  boolean isAsynchronous() {\n    return result.getData() instanceof Publisher;\n  }\n\n  @Override\n  public List<GraphQLError> getErrors() {\n    return result.getErrors();\n  }\n\n  @Override\n  public <T> T getData() {\n    return result.getData();\n  }\n\n  @Override\n  public boolean isDataPresent() {\n    return result.isDataPresent();\n  }\n\n  @Override\n  public Map<Object, Object> getExtensions() {\n    return result.getExtensions();\n  }\n\n  @Override\n  public Map<String, Object> toSpecification() {\n    return result.toSpecification();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/DefaultGraphQLRootObjectBuilder.java",
    "content": "package graphql.kickstart.execution;\n\npublic class DefaultGraphQLRootObjectBuilder extends StaticGraphQLRootObjectBuilder {\n\n  public DefaultGraphQLRootObjectBuilder() {\n    super(new Object());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/ExtensionsDeserializer.java",
    "content": "package graphql.kickstart.execution;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport java.io.IOException;\nimport java.util.Map;\n\npublic class ExtensionsDeserializer extends JsonDeserializer<Map<String, Object>> {\n\n  public static Map<String, Object> deserializeExtensionsObject(\n      Object extensions, ObjectCodec codec) {\n    return ObjectMapDeserializeHelper.deserializeObjectMapObject(extensions, codec, \"extensions\");\n  }\n\n  @Override\n  public Map<String, Object> deserialize(JsonParser p, DeserializationContext ctxt)\n      throws IOException {\n    return ExtensionsDeserializer.deserializeExtensionsObject(\n        p.readValueAs(Object.class), p.getCodec());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/FutureBatchedExecutionResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass FutureBatchedExecutionResult implements FutureExecutionResult {\n\n  @Getter\n  private final GraphQLInvocationInput invocationInput;\n  private final CompletableFuture<List<ExecutionResult>> batched;\n\n  @Override\n  public CompletableFuture<GraphQLQueryResult> thenApplyQueryResult() {\n    return batched.thenApply(GraphQLQueryResult::create);\n  }\n\n  @Override\n  public void cancel() {\n    batched.cancel(true);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/FutureErrorExecutionResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass FutureErrorExecutionResult implements FutureExecutionResult {\n\n  private final GraphQLErrorQueryResult errorQueryResult;\n\n  @Override\n  public CompletableFuture<GraphQLQueryResult> thenApplyQueryResult() {\n    return CompletableFuture.completedFuture(errorQueryResult);\n  }\n\n  @Override\n  public GraphQLInvocationInput getInvocationInput() {\n    return null;\n  }\n\n  @Override\n  public void cancel() {\n    // nothing to do\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/FutureExecutionResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface FutureExecutionResult {\n\n  static FutureExecutionResult single(\n      GraphQLInvocationInput invocationInput, CompletableFuture<ExecutionResult> single) {\n    return new FutureSingleExecutionResult(invocationInput, single);\n  }\n\n  static FutureExecutionResult batched(\n      GraphQLInvocationInput invocationInput, CompletableFuture<List<ExecutionResult>> batched) {\n    return new FutureBatchedExecutionResult(invocationInput, batched);\n  }\n\n  static FutureExecutionResult error(GraphQLErrorQueryResult result) {\n    return new FutureErrorExecutionResult(result);\n  }\n\n  CompletableFuture<GraphQLQueryResult> thenApplyQueryResult();\n\n  GraphQLInvocationInput getInvocationInput();\n\n  void cancel();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/FutureSingleExecutionResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass FutureSingleExecutionResult implements FutureExecutionResult {\n\n  @Getter\n  private final GraphQLInvocationInput invocationInput;\n  private final CompletableFuture<ExecutionResult> single;\n\n  @Override\n  public CompletableFuture<GraphQLQueryResult> thenApplyQueryResult() {\n    return single.thenApply(GraphQLQueryResult::create);\n  }\n\n  @Override\n  public void cancel() {\n    single.cancel(true);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLBatchedQueryResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionResult;\nimport java.util.List;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass GraphQLBatchedQueryResult implements GraphQLQueryResult {\n\n  @Getter private final List<ExecutionResult> results;\n\n  @Override\n  public boolean isBatched() {\n    return true;\n  }\n\n  @Override\n  public boolean isAsynchronous() {\n    return false;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLErrorQueryResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n@Getter\n@RequiredArgsConstructor\nclass GraphQLErrorQueryResult implements GraphQLQueryResult {\n\n  private final int statusCode;\n  private final String message;\n\n  @Override\n  public boolean isBatched() {\n    return false;\n  }\n\n  @Override\n  public boolean isAsynchronous() {\n    return false;\n  }\n\n  @Override\n  public boolean isError() {\n    return true;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLInvoker.java",
    "content": "package graphql.kickstart.execution;\n\nimport static java.util.stream.Collectors.toList;\n\nimport graphql.ExecutionResult;\nimport graphql.GraphQL;\nimport graphql.kickstart.execution.config.GraphQLBuilder;\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class GraphQLInvoker {\n\n  private final GraphQLBuilder graphQLBuilder;\n  private final BatchedDataLoaderGraphQLBuilder batchedDataLoaderGraphQLBuilder;\n  private final GraphQLInvokerProxy proxy = GraphQL::executeAsync;\n\n  public FutureExecutionResult execute(GraphQLInvocationInput invocationInput) {\n    if (invocationInput instanceof GraphQLSingleInvocationInput) {\n      return FutureExecutionResult.single(\n          invocationInput, executeAsync((GraphQLSingleInvocationInput) invocationInput));\n    }\n    return FutureExecutionResult.batched(\n        invocationInput, executeAsync((GraphQLBatchedInvocationInput) invocationInput));\n  }\n\n  public CompletableFuture<ExecutionResult> executeAsync(\n      GraphQLSingleInvocationInput invocationInput) {\n    GraphQL graphQL = graphQLBuilder.build(invocationInput.getSchema());\n    return proxy.executeAsync(graphQL, invocationInput.getExecutionInput());\n  }\n\n  public GraphQLQueryResult query(GraphQLInvocationInput invocationInput) {\n    return queryAsync(invocationInput).join();\n  }\n\n  public CompletableFuture<GraphQLQueryResult> queryAsync(GraphQLInvocationInput invocationInput) {\n    if (invocationInput instanceof GraphQLSingleInvocationInput) {\n      return executeAsync((GraphQLSingleInvocationInput) invocationInput)\n          .thenApply(GraphQLQueryResult::create);\n    }\n    GraphQLBatchedInvocationInput batchedInvocationInput =\n        (GraphQLBatchedInvocationInput) invocationInput;\n    return executeAsync(batchedInvocationInput).thenApply(GraphQLQueryResult::create);\n  }\n\n  private CompletableFuture<List<ExecutionResult>> executeAsync(\n      GraphQLBatchedInvocationInput batchedInvocationInput) {\n    GraphQL graphQL =\n        batchedDataLoaderGraphQLBuilder.newGraphQL(batchedInvocationInput, graphQLBuilder);\n    return sequence(\n        batchedInvocationInput.getExecutionInputs().stream()\n            .map(executionInput -> proxy.executeAsync(graphQL, executionInput))\n            .collect(toList()));\n  }\n\n  @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n  private <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {\n    CompletableFuture[] futuresArray = futures.toArray(new CompletableFuture[0]);\n    return CompletableFuture.allOf(futuresArray)\n        .thenApply(\n            aVoid -> {\n              List<T> result = new ArrayList<>(futures.size());\n              for (CompletableFuture future : futuresArray) {\n                assert future.isDone(); // per the API contract of allOf()\n                result.add((T) future.join());\n              }\n              return result;\n            });\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLInvokerProxy.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.ExecutionInput;\nimport graphql.ExecutionResult;\nimport graphql.GraphQL;\nimport java.util.concurrent.CompletableFuture;\n\npublic interface GraphQLInvokerProxy {\n\n  CompletableFuture<ExecutionResult> executeAsync(GraphQL graphQL, ExecutionInput executionInput);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLObjectMapper.java",
    "content": "package graphql.kickstart.execution;\n\nimport static java.util.stream.Collectors.toList;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.MappingIterator;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.ObjectReader;\nimport graphql.ExecutionResult;\nimport graphql.ExecutionResultImpl;\nimport graphql.GraphQLError;\nimport graphql.kickstart.execution.config.ConfiguringObjectMapperProvider;\nimport graphql.kickstart.execution.config.GraphQLServletObjectMapperConfigurer;\nimport graphql.kickstart.execution.config.ObjectMapperProvider;\nimport graphql.kickstart.execution.error.DefaultGraphQLErrorHandler;\nimport graphql.kickstart.execution.error.GraphQLErrorHandler;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\nimport lombok.SneakyThrows;\n\n/** @author Andrew Potter */\npublic class GraphQLObjectMapper {\n\n  private static final TypeReference<Map<String, List<String>>> MULTIPART_MAP_TYPE_REFERENCE =\n      new TypeReference<Map<String, List<String>>>() {};\n  private final ObjectMapperProvider objectMapperProvider;\n  private final Supplier<GraphQLErrorHandler> graphQLErrorHandlerSupplier;\n\n  private ObjectMapper mapper;\n\n  protected GraphQLObjectMapper(\n      ObjectMapperProvider objectMapperProvider,\n      Supplier<GraphQLErrorHandler> graphQLErrorHandlerSupplier) {\n    this.objectMapperProvider = objectMapperProvider;\n    this.graphQLErrorHandlerSupplier = graphQLErrorHandlerSupplier;\n  }\n\n  public static Builder newBuilder() {\n    return new Builder();\n  }\n\n  // Double-check idiom for lazy initialization of instance fields.\n  public ObjectMapper getJacksonMapper() {\n    ObjectMapper result = mapper;\n    if (result == null) { // First check (no locking)\n      synchronized (this) {\n        result = mapper;\n        if (result == null) { // Second check (with locking)\n          mapper = result = objectMapperProvider.provide();\n        }\n      }\n    }\n\n    return result;\n  }\n\n  /** @return an {@link ObjectReader} for deserializing {@link GraphQLRequest} */\n  public ObjectReader getGraphQLRequestMapper() {\n    return getJacksonMapper().reader().forType(GraphQLRequest.class);\n  }\n\n  public GraphQLRequest readGraphQLRequest(InputStream inputStream) throws IOException {\n    return getGraphQLRequestMapper().readValue(inputStream);\n  }\n\n  public GraphQLRequest readGraphQLRequest(String text) throws IOException {\n    return getGraphQLRequestMapper().readValue(text);\n  }\n\n  public List<GraphQLRequest> readBatchedGraphQLRequest(InputStream inputStream)\n      throws IOException {\n    MappingIterator<GraphQLRequest> iterator = getGraphQLRequestMapper().readValues(inputStream);\n    List<GraphQLRequest> requests = new ArrayList<>();\n\n    while (iterator.hasNext()) {\n      requests.add(iterator.next());\n    }\n\n    return requests;\n  }\n\n  public List<GraphQLRequest> readBatchedGraphQLRequest(String query) throws IOException {\n    MappingIterator<GraphQLRequest> iterator = getGraphQLRequestMapper().readValues(query);\n    List<GraphQLRequest> requests = new ArrayList<>();\n\n    while (iterator.hasNext()) {\n      requests.add(iterator.next());\n    }\n\n    return requests;\n  }\n\n  @SneakyThrows\n  public String serializeResultAsJson(ExecutionResult executionResult) {\n    return getJacksonMapper().writeValueAsString(createResultFromExecutionResult(executionResult));\n  }\n\n  public void serializeResultAsJson(Writer writer, ExecutionResult executionResult)\n      throws IOException {\n    getJacksonMapper().writeValue(writer, createResultFromExecutionResult(executionResult));\n  }\n\n  /**\n   * Serializes result as bytes in UTF-8 encoding instead of string.\n   *\n   * @param executionResult query execution result to serialize.\n   * @return result serialized into Json representation in UTF-8 encoding, converted into {@code\n   *     byte[]}.\n   */\n  @SneakyThrows\n  public byte[] serializeResultAsBytes(ExecutionResult executionResult) {\n    return getJacksonMapper().writeValueAsBytes(createResultFromExecutionResult(executionResult));\n  }\n\n  public boolean areErrorsPresent(ExecutionResult executionResult) {\n    return graphQLErrorHandlerSupplier.get().errorsPresent(executionResult.getErrors());\n  }\n\n  public ExecutionResult sanitizeErrors(ExecutionResult executionResult) {\n    Object data = executionResult.getData();\n    Map<Object, Object> extensions = executionResult.getExtensions();\n    List<GraphQLError> errors = executionResult.getErrors();\n\n    GraphQLErrorHandler errorHandler = graphQLErrorHandlerSupplier.get();\n    if (errorHandler.errorsPresent(errors)) {\n      errors = errorHandler.processErrors(errors);\n    } else {\n      errors = null;\n    }\n    return new ExecutionResultImpl(data, errors, extensions);\n  }\n\n  public Map<String, Object> createResultFromExecutionResult(ExecutionResult executionResult) {\n    ExecutionResult sanitizedExecutionResult = sanitizeErrors(executionResult);\n    return convertSanitizedExecutionResult(sanitizedExecutionResult);\n  }\n\n  public Map<String, Object> convertSanitizedExecutionResult(ExecutionResult executionResult) {\n    return convertSanitizedExecutionResult(executionResult, true);\n  }\n\n  public Map<String, Object> convertSanitizedExecutionResult(\n      ExecutionResult executionResult, boolean includeData) {\n    final Map<String, Object> result = new LinkedHashMap<>();\n\n    if (areErrorsPresent(executionResult)) {\n      result.put(\n          \"errors\",\n          executionResult.getErrors().stream()\n              .map(GraphQLError::toSpecification)\n              .collect(toList()));\n    }\n\n    if (executionResult.getExtensions() != null && !executionResult.getExtensions().isEmpty()) {\n      result.put(\"extensions\", executionResult.getExtensions());\n    }\n\n    if (includeData) {\n      result.put(\"data\", executionResult.getData());\n    }\n\n    return result;\n  }\n\n  @SneakyThrows\n  public Map<String, Object> deserializeVariables(String variables) {\n    return VariablesDeserializer.deserializeVariablesObject(\n        getJacksonMapper().readValue(variables, Object.class), getJacksonMapper());\n  }\n\n  @SneakyThrows\n  public Map<String, Object> deserializeExtensions(String extensions) {\n    return ExtensionsDeserializer.deserializeExtensionsObject(\n        getJacksonMapper().readValue(extensions, Object.class), getJacksonMapper());\n  }\n\n  @SneakyThrows\n  public Map<String, List<String>> deserializeMultipartMap(InputStream inputStream) {\n    return getJacksonMapper().readValue(inputStream, MULTIPART_MAP_TYPE_REFERENCE);\n  }\n\n  public static class Builder {\n\n    private ObjectMapperProvider objectMapperProvider = new ConfiguringObjectMapperProvider();\n    private Supplier<GraphQLErrorHandler> graphQLErrorHandler = DefaultGraphQLErrorHandler::new;\n\n    public Builder withObjectMapperConfigurer(\n        GraphQLServletObjectMapperConfigurer objectMapperConfigurer) {\n      return withObjectMapperConfigurer(() -> objectMapperConfigurer);\n    }\n\n    public Builder withObjectMapperConfigurer(\n        Supplier<GraphQLServletObjectMapperConfigurer> objectMapperConfigurer) {\n      this.objectMapperProvider = new ConfiguringObjectMapperProvider(objectMapperConfigurer.get());\n      return this;\n    }\n\n    public Builder withObjectMapperProvider(ObjectMapperProvider objectMapperProvider) {\n      this.objectMapperProvider = objectMapperProvider;\n      return this;\n    }\n\n    public Builder withGraphQLErrorHandler(GraphQLErrorHandler graphQLErrorHandler) {\n      return withGraphQLErrorHandler(() -> graphQLErrorHandler);\n    }\n\n    public Builder withGraphQLErrorHandler(Supplier<GraphQLErrorHandler> graphQLErrorHandler) {\n      this.graphQLErrorHandler = graphQLErrorHandler;\n      return this;\n    }\n\n    public GraphQLObjectMapper build() {\n      return new GraphQLObjectMapper(objectMapperProvider, graphQLErrorHandler);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLQueryInvoker.java",
    "content": "package graphql.kickstart.execution;\n\nimport graphql.execution.instrumentation.ChainedInstrumentation;\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.execution.instrumentation.SimplePerformantInstrumentation;\nimport graphql.execution.preparsed.NoOpPreparsedDocumentProvider;\nimport graphql.execution.preparsed.PreparsedDocumentProvider;\nimport graphql.kickstart.execution.config.DefaultExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.ExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.GraphQLBuilder;\nimport java.util.List;\nimport java.util.function.Supplier;\n\n/**\n * @author Andrew Potter\n */\npublic class GraphQLQueryInvoker {\n\n  private final Supplier<ExecutionStrategyProvider> getExecutionStrategyProvider;\n  private final Supplier<Instrumentation> getInstrumentation;\n  private final Supplier<PreparsedDocumentProvider> getPreparsedDocumentProvider;\n\n  protected GraphQLQueryInvoker(\n      Supplier<ExecutionStrategyProvider> getExecutionStrategyProvider,\n      Supplier<Instrumentation> getInstrumentation,\n      Supplier<PreparsedDocumentProvider> getPreparsedDocumentProvider) {\n    this.getExecutionStrategyProvider = getExecutionStrategyProvider;\n    this.getInstrumentation = getInstrumentation;\n    this.getPreparsedDocumentProvider = getPreparsedDocumentProvider;\n  }\n\n  public static Builder newBuilder() {\n    return new Builder();\n  }\n\n  public GraphQLInvoker toGraphQLInvoker() {\n    GraphQLBuilder graphQLBuilder =\n        new GraphQLBuilder()\n            .executionStrategyProvider(getExecutionStrategyProvider)\n            .instrumentation(getInstrumentation)\n            .preparsedDocumentProvider(getPreparsedDocumentProvider);\n    return new GraphQLInvoker(graphQLBuilder, new BatchedDataLoaderGraphQLBuilder());\n  }\n\n  public static class Builder {\n\n    private Supplier<ExecutionStrategyProvider> getExecutionStrategyProvider =\n        DefaultExecutionStrategyProvider::new;\n    private Supplier<Instrumentation> getInstrumentation =\n        () -> SimplePerformantInstrumentation.INSTANCE;\n    private Supplier<PreparsedDocumentProvider> getPreparsedDocumentProvider =\n        () -> NoOpPreparsedDocumentProvider.INSTANCE;\n\n    public Builder withExecutionStrategyProvider(ExecutionStrategyProvider provider) {\n      return withExecutionStrategyProvider(() -> provider);\n    }\n\n    public Builder withExecutionStrategyProvider(Supplier<ExecutionStrategyProvider> supplier) {\n      this.getExecutionStrategyProvider = supplier;\n      return this;\n    }\n\n    public Builder withInstrumentation(Instrumentation instrumentation) {\n      return withInstrumentation(() -> instrumentation);\n    }\n\n    public Builder withInstrumentation(Supplier<Instrumentation> supplier) {\n      this.getInstrumentation = supplier;\n      return this;\n    }\n\n    public Builder with(List<Instrumentation> instrumentations) {\n      if (instrumentations.isEmpty()) {\n        return this;\n      }\n      if (instrumentations.size() == 1) {\n        withInstrumentation(instrumentations.get(0));\n      } else {\n        withInstrumentation(new ChainedInstrumentation(instrumentations));\n      }\n      return this;\n    }\n\n    public Builder withPreparsedDocumentProvider(PreparsedDocumentProvider provider) {\n      return withPreparsedDocumentProvider(() -> provider);\n    }\n\n    public Builder withPreparsedDocumentProvider(Supplier<PreparsedDocumentProvider> supplier) {\n      this.getPreparsedDocumentProvider = supplier;\n      return this;\n    }\n\n    public GraphQLQueryInvoker build() {\n      return new GraphQLQueryInvoker(\n          getExecutionStrategyProvider,\n          getInstrumentation,\n          getPreparsedDocumentProvider);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLQueryResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport static java.util.Collections.emptyList;\n\nimport graphql.ExecutionResult;\nimport java.util.List;\n\npublic interface GraphQLQueryResult {\n\n  static GraphQLSingleQueryResult create(ExecutionResult result) {\n    return new GraphQLSingleQueryResult(new DecoratedExecutionResult(result));\n  }\n\n  static GraphQLBatchedQueryResult create(List<ExecutionResult> results) {\n    return new GraphQLBatchedQueryResult(results);\n  }\n\n  static GraphQLErrorQueryResult createError(int statusCode, String message) {\n    return new GraphQLErrorQueryResult(statusCode, message);\n  }\n\n  boolean isBatched();\n\n  boolean isAsynchronous();\n\n  default DecoratedExecutionResult getResult() {\n    return null;\n  }\n\n  default List<ExecutionResult> getResults() {\n    return emptyList();\n  }\n\n  default boolean isError() {\n    return false;\n  }\n\n  default int getStatusCode() {\n    return 200;\n  }\n\n  default String getMessage() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLRequest.java",
    "content": "package graphql.kickstart.execution;\n\nimport static graphql.kickstart.execution.OperationNameExtractor.extractOperationName;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport graphql.introspection.IntrospectionQuery;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/** @author Andrew Potter */\n@JsonIgnoreProperties(ignoreUnknown = true)\npublic class GraphQLRequest {\n\n  private String query;\n\n  @JsonDeserialize(using = VariablesDeserializer.class)\n  private Map<String, Object> variables = new HashMap<>();\n\n  @JsonDeserialize(using = ExtensionsDeserializer.class)\n  private Map<String, Object> extensions = new HashMap<>();\n\n  private String operationName;\n\n  public GraphQLRequest() {}\n\n  public GraphQLRequest(\n      String query,\n      Map<String, Object> variables,\n      Map<String, Object> extensions,\n      String operationName) {\n    this.query = query;\n    this.operationName = operationName;\n    if (extensions != null) {\n      this.extensions = extensions;\n    }\n    if (variables != null) {\n      this.variables = variables;\n    }\n  }\n\n  public static GraphQLRequest createIntrospectionRequest() {\n    return new GraphQLRequest(\n        IntrospectionQuery.INTROSPECTION_QUERY,\n        new HashMap<>(),\n        new HashMap<>(),\n        \"IntrospectionQuery\");\n  }\n\n  public static GraphQLRequest createQueryOnlyRequest(String query) {\n    return new GraphQLRequest(query, new HashMap<>(), new HashMap<>(), null);\n  }\n\n  public String getQuery() {\n    return query;\n  }\n\n  public void setQuery(String query) {\n    this.query = query;\n  }\n\n  public Map<String, Object> getVariables() {\n    return variables;\n  }\n\n  public void setVariables(Map<String, Object> variables) {\n    if (variables != null) {\n      this.variables = variables;\n    }\n  }\n\n  public Map<String, Object> getExtensions() {\n    return extensions;\n  }\n\n  public void setExtensions(Map<String, Object> extensions) {\n    if (extensions != null) {\n      this.extensions = extensions;\n    }\n  }\n\n  public String getOperationName() {\n    return extractOperationName(query, operationName, null);\n  }\n\n  public void setOperationName(String operationName) {\n    this.operationName = operationName;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLRootObjectBuilder.java",
    "content": "package graphql.kickstart.execution;\n\npublic interface GraphQLRootObjectBuilder {\n\n  /** @return the graphql root object */\n  Object build();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/GraphQLSingleQueryResult.java",
    "content": "package graphql.kickstart.execution;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass GraphQLSingleQueryResult implements GraphQLQueryResult {\n\n  @Getter private final DecoratedExecutionResult result;\n\n  @Override\n  public boolean isBatched() {\n    return false;\n  }\n\n  @Override\n  public boolean isAsynchronous() {\n    return result.isAsynchronous();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/ObjectMapDeserializationException.java",
    "content": "package graphql.kickstart.execution;\n\npublic class ObjectMapDeserializationException extends RuntimeException {\n\n  ObjectMapDeserializationException(String message) {\n    super(message);\n  }\n\n  ObjectMapDeserializationException(String message, Throwable cause) {\n    super(message, cause);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/ObjectMapDeserializeHelper.java",
    "content": "package graphql.kickstart.execution;\n\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport java.io.IOException;\nimport java.util.Map;\n\npublic class ObjectMapDeserializeHelper {\n\n  public static Map<String, Object> deserializeObjectMapObject(\n      Object object, ObjectCodec codec, String fieldName) {\n    if (object instanceof Map) {\n      @SuppressWarnings(\"unchecked\")\n      Map<String, Object> genericObjectMap = (Map<String, Object>) object;\n      return genericObjectMap;\n    } else if (object instanceof String) {\n      try {\n        return codec.readValue(\n            codec.getFactory().createParser((String) object),\n            new TypeReference<Map<String, Object>>() {});\n      } catch (IOException e) {\n        throw new ObjectMapDeserializationException(\n            String.format(\"Cannot deserialize field '%s'\", fieldName), e);\n      }\n    } else {\n      throw new ObjectMapDeserializationException(\n          String.format(\"Field '%s' should be either an object or a string\", fieldName));\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/OperationNameExtractor.java",
    "content": "package graphql.kickstart.execution;\n\nimport static graphql.kickstart.execution.StringUtils.isNotEmpty;\n\nimport graphql.language.Document;\nimport graphql.language.OperationDefinition;\nimport graphql.parser.InvalidSyntaxException;\nimport graphql.parser.Parser;\nimport java.util.List;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\nclass OperationNameExtractor {\n\n  static String extractOperationName(\n      String gqlQuery, String requestedOperationName, String defaultIfNotFound) {\n    if (isNotEmpty(requestedOperationName)) {\n      return requestedOperationName;\n    }\n    if (isNotEmpty(gqlQuery)) {\n      return parseForOperationName(gqlQuery, defaultIfNotFound);\n    }\n    return defaultIfNotFound;\n  }\n\n  private static String parseForOperationName(String gqlQuery, String defaultIfNotFound) {\n    try {\n      Document document = new Parser().parseDocument(gqlQuery);\n      List<OperationDefinition> operations =\n          document.getDefinitionsOfType(OperationDefinition.class);\n      if (operations.size() == 1) {\n        String name = operations.get(0).getName();\n        if (isNotEmpty(name)) {\n          return name;\n        }\n      }\n    } catch (InvalidSyntaxException ignored) {\n      // ignored\n    }\n    return defaultIfNotFound;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/StaticGraphQLRootObjectBuilder.java",
    "content": "package graphql.kickstart.execution;\n\npublic class StaticGraphQLRootObjectBuilder implements GraphQLRootObjectBuilder {\n\n  private final Object rootObject;\n\n  public StaticGraphQLRootObjectBuilder(Object rootObject) {\n    this.rootObject = rootObject;\n  }\n\n  @Override\n  public Object build() {\n    return rootObject;\n  }\n\n  protected Object getRootObject() {\n    return rootObject;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/StringUtils.java",
    "content": "package graphql.kickstart.execution;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\nclass StringUtils {\n\n  static boolean isNotEmpty(CharSequence cs) {\n    return !isEmpty(cs);\n  }\n\n  static boolean isEmpty(final CharSequence cs) {\n    return cs == null || cs.length() == 0;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/VariablesDeserializer.java",
    "content": "package graphql.kickstart.execution;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport java.io.IOException;\nimport java.util.Map;\n\n/** @author Andrew Potter */\npublic class VariablesDeserializer extends JsonDeserializer<Map<String, Object>> {\n\n  public static Map<String, Object> deserializeVariablesObject(\n      Object variables, ObjectCodec codec) {\n    return ObjectMapDeserializeHelper.deserializeObjectMapObject(variables, codec, \"variables\");\n  }\n\n  @Override\n  public Map<String, Object> deserialize(JsonParser p, DeserializationContext ctxt)\n      throws IOException {\n    return deserializeVariablesObject(p.readValueAs(Object.class), p.getCodec());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/ConfiguringObjectMapperProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport graphql.kickstart.execution.error.DefaultGraphQLServletObjectMapperConfigurer;\n\npublic class ConfiguringObjectMapperProvider implements ObjectMapperProvider {\n\n  private final ObjectMapper objectMapperTemplate;\n\n  private final GraphQLServletObjectMapperConfigurer objectMapperConfigurer;\n\n  public ConfiguringObjectMapperProvider(\n      ObjectMapper objectMapperTemplate,\n      GraphQLServletObjectMapperConfigurer objectMapperConfigurer) {\n    this.objectMapperTemplate =\n        objectMapperTemplate == null ? new ObjectMapper() : objectMapperTemplate;\n    this.objectMapperConfigurer =\n        objectMapperConfigurer == null\n            ? new DefaultGraphQLServletObjectMapperConfigurer()\n            : objectMapperConfigurer;\n  }\n\n  public ConfiguringObjectMapperProvider(ObjectMapper objectMapperTemplate) {\n    this(objectMapperTemplate, null);\n  }\n\n  public ConfiguringObjectMapperProvider(\n      GraphQLServletObjectMapperConfigurer objectMapperConfigurer) {\n    this(null, objectMapperConfigurer);\n  }\n\n  public ConfiguringObjectMapperProvider() {\n    this(null, null);\n  }\n\n  @Override\n  public ObjectMapper provide() {\n    ObjectMapper mapper = this.objectMapperTemplate.copy();\n    this.objectMapperConfigurer.configure(mapper);\n    return mapper;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/DefaultExecutionStrategyProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.execution.ExecutionStrategy;\n\n/** @author Andrew Potter */\npublic class DefaultExecutionStrategyProvider implements ExecutionStrategyProvider {\n\n  private final ExecutionStrategy queryExecutionStrategy;\n  private final ExecutionStrategy mutationExecutionStrategy;\n  private final ExecutionStrategy subscriptionExecutionStrategy;\n\n  public DefaultExecutionStrategyProvider() {\n    this(null);\n  }\n\n  public DefaultExecutionStrategyProvider(ExecutionStrategy executionStrategy) {\n    this(executionStrategy, executionStrategy, null);\n  }\n\n  public DefaultExecutionStrategyProvider(\n      ExecutionStrategy queryExecutionStrategy,\n      ExecutionStrategy mutationExecutionStrategy,\n      ExecutionStrategy subscriptionExecutionStrategy) {\n    this.queryExecutionStrategy = queryExecutionStrategy;\n    this.mutationExecutionStrategy = mutationExecutionStrategy;\n    this.subscriptionExecutionStrategy = subscriptionExecutionStrategy;\n  }\n\n  @Override\n  public ExecutionStrategy getQueryExecutionStrategy() {\n    return queryExecutionStrategy;\n  }\n\n  @Override\n  public ExecutionStrategy getMutationExecutionStrategy() {\n    return mutationExecutionStrategy;\n  }\n\n  @Override\n  public ExecutionStrategy getSubscriptionExecutionStrategy() {\n    return subscriptionExecutionStrategy;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/DefaultGraphQLSchemaProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.schema.GraphQLSchema;\n\n/** @author Andrew Potter */\npublic class DefaultGraphQLSchemaProvider implements GraphQLSchemaProvider {\n\n  private final GraphQLSchema schema;\n  private final GraphQLSchema readOnlySchema;\n\n  public DefaultGraphQLSchemaProvider(GraphQLSchema schema) {\n    this(schema, GraphQLSchemaProvider.copyReadOnly(schema));\n  }\n\n  public DefaultGraphQLSchemaProvider(GraphQLSchema schema, GraphQLSchema readOnlySchema) {\n    this.schema = schema;\n    this.readOnlySchema = readOnlySchema;\n  }\n\n  @Override\n  public GraphQLSchema getSchema() {\n    return schema;\n  }\n\n  @Override\n  public GraphQLSchema getReadOnlySchema() {\n    return readOnlySchema;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/ExecutionStrategyProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.execution.ExecutionStrategy;\n\npublic interface ExecutionStrategyProvider {\n\n  ExecutionStrategy getQueryExecutionStrategy();\n\n  ExecutionStrategy getMutationExecutionStrategy();\n\n  ExecutionStrategy getSubscriptionExecutionStrategy();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/GraphQLBuilder.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.GraphQL;\nimport graphql.execution.ExecutionStrategy;\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.execution.instrumentation.SimplePerformantInstrumentation;\nimport graphql.execution.preparsed.NoOpPreparsedDocumentProvider;\nimport graphql.execution.preparsed.PreparsedDocumentProvider;\nimport graphql.schema.GraphQLSchema;\nimport java.util.function.Supplier;\nimport lombok.Getter;\n\npublic class GraphQLBuilder {\n\n  private Supplier<ExecutionStrategyProvider> executionStrategyProviderSupplier =\n      DefaultExecutionStrategyProvider::new;\n  private Supplier<PreparsedDocumentProvider> preparsedDocumentProviderSupplier =\n      () -> NoOpPreparsedDocumentProvider.INSTANCE;\n\n  @Getter\n  private Supplier<Instrumentation> instrumentationSupplier =\n      () -> SimplePerformantInstrumentation.INSTANCE;\n\n  private Supplier<GraphQLBuilderConfigurer> graphQLBuilderConfigurerSupplier = () -> builder -> {};\n\n  public GraphQLBuilder executionStrategyProvider(Supplier<ExecutionStrategyProvider> supplier) {\n    if (supplier != null) {\n      executionStrategyProviderSupplier = supplier;\n    }\n    return this;\n  }\n\n  public GraphQLBuilder preparsedDocumentProvider(Supplier<PreparsedDocumentProvider> supplier) {\n    if (supplier != null) {\n      preparsedDocumentProviderSupplier = supplier;\n    }\n    return this;\n  }\n\n  public GraphQLBuilder instrumentation(Supplier<Instrumentation> supplier) {\n    if (supplier != null) {\n      instrumentationSupplier = supplier;\n    }\n    return this;\n  }\n\n  public GraphQLBuilder graphQLBuilderConfigurer(Supplier<GraphQLBuilderConfigurer> supplier) {\n    if (supplier != null) {\n      graphQLBuilderConfigurerSupplier = supplier;\n    }\n    return this;\n  }\n\n  public GraphQL build(GraphQLSchemaProvider schemaProvider) {\n    return build(schemaProvider.getSchema());\n  }\n\n  public GraphQL build(GraphQLSchema schema) {\n    return build(schema, instrumentationSupplier);\n  }\n\n  public GraphQL build(\n      GraphQLSchema schema, Supplier<Instrumentation> configuredInstrumentationSupplier) {\n    ExecutionStrategyProvider executionStrategyProvider = executionStrategyProviderSupplier.get();\n    ExecutionStrategy queryExecutionStrategy =\n        executionStrategyProvider.getQueryExecutionStrategy();\n    ExecutionStrategy mutationExecutionStrategy =\n        executionStrategyProvider.getMutationExecutionStrategy();\n    ExecutionStrategy subscriptionExecutionStrategy =\n        executionStrategyProvider.getSubscriptionExecutionStrategy();\n\n    GraphQL.Builder builder =\n        GraphQL.newGraphQL(schema)\n            .preparsedDocumentProvider(preparsedDocumentProviderSupplier.get());\n\n    if (queryExecutionStrategy != null) {\n      builder.queryExecutionStrategy(queryExecutionStrategy);\n    }\n\n    if (mutationExecutionStrategy != null) {\n      builder.mutationExecutionStrategy(mutationExecutionStrategy);\n    }\n\n    if (subscriptionExecutionStrategy != null) {\n      builder.subscriptionExecutionStrategy(subscriptionExecutionStrategy);\n    }\n\n    Instrumentation instrumentation = configuredInstrumentationSupplier.get();\n    builder.instrumentation(instrumentation);\n    graphQLBuilderConfigurerSupplier.get().configure(builder);\n    return builder.build();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/GraphQLBuilderConfigurer.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.GraphQL;\n\npublic interface GraphQLBuilderConfigurer {\n\n  void configure(GraphQL.Builder builder);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/GraphQLSchemaProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.schema.GraphQLObjectType;\nimport graphql.schema.GraphQLSchema;\n\npublic interface GraphQLSchemaProvider {\n\n  static GraphQLSchema copyReadOnly(GraphQLSchema schema) {\n    return GraphQLSchema.newSchema(schema).mutation((GraphQLObjectType) null).build();\n  }\n\n  /** @return a schema for handling mbean calls. */\n  GraphQLSchema getSchema();\n\n  GraphQLSchema getReadOnlySchema();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/GraphQLServletObjectMapperConfigurer.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n/** @author Andrew Potter */\npublic interface GraphQLServletObjectMapperConfigurer {\n\n  void configure(ObjectMapper mapper);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/InstrumentationProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport graphql.execution.instrumentation.Instrumentation;\n\npublic interface InstrumentationProvider {\n\n  Instrumentation getInstrumentation();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/config/ObjectMapperProvider.java",
    "content": "package graphql.kickstart.execution.config;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\npublic interface ObjectMapperProvider {\n\n  ObjectMapper provide();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/ContextSetting.java",
    "content": "package graphql.kickstart.execution.context;\n\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.execution.input.PerQueryBatchedInvocationInput;\nimport graphql.kickstart.execution.input.PerRequestBatchedInvocationInput;\nimport graphql.schema.GraphQLSchema;\nimport java.util.List;\nimport java.util.function.Supplier;\n\n/**\n * An enum representing possible context settings. These are modeled after Apollo's link settings.\n */\npublic enum ContextSetting {\n\n  /**\n   * A context object, and therefor dataloader registry and subject, should be shared between all\n   * GraphQL executions in a http request.\n   */\n  PER_REQUEST,\n  /** Each GraphQL execution should always have its own context. */\n  PER_QUERY;\n\n  /**\n   * Creates a set of inputs with the correct context based on the setting.\n   *\n   * @param requests the GraphQL requests to execute.\n   * @param schema the GraphQL schema to execute the requests against.\n   * @param contextSupplier method that returns the context to use for each execution or for the\n   *     request as a whole.\n   * @param root the root object to use for each execution.\n   * @return a configured batch input.\n   */\n  public GraphQLBatchedInvocationInput getBatch(\n      List<GraphQLRequest> requests,\n      GraphQLSchema schema,\n      Supplier<GraphQLKickstartContext> contextSupplier,\n      Object root) {\n    switch (this) {\n      case PER_QUERY:\n        return new PerQueryBatchedInvocationInput(requests, schema, contextSupplier, root, this);\n      case PER_REQUEST:\n        return new PerRequestBatchedInvocationInput(requests, schema, contextSupplier, root, this);\n      default:\n        throw new ContextSettingNotConfiguredException();\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/ContextSettingNotConfiguredException.java",
    "content": "package graphql.kickstart.execution.context;\n\npublic class ContextSettingNotConfiguredException extends RuntimeException {\n\n  ContextSettingNotConfiguredException() {\n    super(\"Unconfigured context setting type\");\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/DefaultGraphQLContext.java",
    "content": "package graphql.kickstart.execution.context;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport org.dataloader.DataLoaderRegistry;\n\n/**\n * An object for the DefaultGraphQLContextBuilder to return. Can be extended to include more\n * context.\n */\npublic class DefaultGraphQLContext implements GraphQLKickstartContext {\n\n  private final DataLoaderRegistry dataLoaderRegistry;\n  private final Map<Object, Object> map;\n\n  public DefaultGraphQLContext(DataLoaderRegistry dataLoaderRegistry, Map<Object, Object> map) {\n    this.dataLoaderRegistry =\n        Objects.requireNonNull(dataLoaderRegistry, \"dataLoaderRegistry is required\");\n    this.map = Objects.requireNonNull(map, \"map is required\");\n  }\n\n  public DefaultGraphQLContext(Map<Object, Object> map) {\n    this(new DataLoaderRegistry(), map);\n  }\n\n  public DefaultGraphQLContext(DataLoaderRegistry dataLoaderRegistry) {\n    this(dataLoaderRegistry, new HashMap<>());\n  }\n\n  public DefaultGraphQLContext() {\n    this(new DataLoaderRegistry());\n  }\n\n  public void put(Object key, Object value) {\n    map.put(key, value);\n  }\n\n  @Override\n  public DataLoaderRegistry getDataLoaderRegistry() {\n    return dataLoaderRegistry;\n  }\n\n  @Override\n  public Map<Object, Object> getMapOfContext() {\n    return map;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/DefaultGraphQLContextBuilder.java",
    "content": "package graphql.kickstart.execution.context;\n\n/** Returns an empty context. */\npublic class DefaultGraphQLContextBuilder implements GraphQLContextBuilder {\n\n  @Override\n  public GraphQLKickstartContext build() {\n    return new DefaultGraphQLContext();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/GraphQLContextBuilder.java",
    "content": "package graphql.kickstart.execution.context;\n\npublic interface GraphQLContextBuilder {\n\n  /** @return the graphql context */\n  GraphQLKickstartContext build();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/context/GraphQLKickstartContext.java",
    "content": "package graphql.kickstart.execution.context;\n\nimport java.util.Map;\nimport lombok.NonNull;\nimport org.dataloader.DataLoaderRegistry;\n\n/** Represents the context required by the servlet to execute a GraphQL request. */\npublic interface GraphQLKickstartContext {\n\n  static GraphQLKickstartContext of(Map<Object, Object> map) {\n    return new DefaultGraphQLContext(map);\n  }\n\n  static GraphQLKickstartContext of(DataLoaderRegistry dataLoaderRegistry) {\n    return new DefaultGraphQLContext(dataLoaderRegistry);\n  }\n\n  static GraphQLKickstartContext of(\n      DataLoaderRegistry dataLoaderRegistry, Map<Object, Object> map) {\n    return new DefaultGraphQLContext(dataLoaderRegistry, map);\n  }\n\n  /** @return the Dataloader registry to use for the execution. Must not return <code>null</code> */\n  @NonNull\n  DataLoaderRegistry getDataLoaderRegistry();\n\n  Map<Object, Object> getMapOfContext();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/error/DefaultGraphQLErrorHandler.java",
    "content": "package graphql.kickstart.execution.error;\n\nimport graphql.ExceptionWhileDataFetching;\nimport graphql.GraphQLError;\nimport graphql.execution.NonNullableFieldWasNullError;\nimport java.util.List;\nimport java.util.stream.Collectors;\nimport lombok.extern.slf4j.Slf4j;\n\n/** @author Andrew Potter */\n@Slf4j\npublic class DefaultGraphQLErrorHandler implements GraphQLErrorHandler {\n\n  @Override\n  public List<GraphQLError> processErrors(List<GraphQLError> errors) {\n    final List<GraphQLError> clientErrors = filterGraphQLErrors(errors);\n    if (clientErrors.size() < errors.size()) {\n\n      // Some errors were filtered out to hide implementation - put a generic error in place.\n      clientErrors.add(new GenericGraphQLError(\"Internal Server Error(s) while executing query\"));\n\n      errors.stream().filter(error -> !isClientError(error)).forEach(this::logError);\n    }\n\n    return clientErrors;\n  }\n\n  protected void logError(GraphQLError error) {\n    if (error instanceof Throwable) {\n      log.error(\"Error executing query!\", (Throwable) error);\n    } else if (error instanceof ExceptionWhileDataFetching) {\n      log.error(\n          \"Error executing query {}\",\n          error.getMessage(),\n          ((ExceptionWhileDataFetching) error).getException());\n    } else {\n      log.error(\n          \"Error executing query ({}): {}\", error.getClass().getSimpleName(), error.getMessage());\n    }\n  }\n\n  protected List<GraphQLError> filterGraphQLErrors(List<GraphQLError> errors) {\n    return errors.stream()\n        .filter(this::isClientError)\n        .map(this::replaceNonNullableFieldWasNullError)\n        .collect(Collectors.toList());\n  }\n\n  protected boolean isClientError(GraphQLError error) {\n    if (error instanceof ExceptionWhileDataFetching) {\n      return ((ExceptionWhileDataFetching) error).getException() instanceof GraphQLError;\n    }\n    return true;\n  }\n\n  private GraphQLError replaceNonNullableFieldWasNullError(GraphQLError error) {\n    if (error instanceof NonNullableFieldWasNullError) {\n      return new RenderableNonNullableFieldWasNullError((NonNullableFieldWasNullError) error);\n    } else {\n      return error;\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/error/DefaultGraphQLServletObjectMapperConfigurer.java",
    "content": "package graphql.kickstart.execution.error;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport graphql.kickstart.execution.config.GraphQLServletObjectMapperConfigurer;\n\n/** @author Andrew Potter */\npublic class DefaultGraphQLServletObjectMapperConfigurer\n    implements GraphQLServletObjectMapperConfigurer {\n\n  @Override\n  public void configure(ObjectMapper mapper) {\n    mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);\n    mapper.setDefaultPropertyInclusion(JsonInclude.Include.ALWAYS);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/error/GenericGraphQLError.java",
    "content": "package graphql.kickstart.execution.error;\n\nimport static java.util.Collections.emptyList;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport graphql.ErrorType;\nimport graphql.GraphQLError;\nimport graphql.language.SourceLocation;\nimport java.util.List;\n\n/** @author Andrew Potter */\npublic class GenericGraphQLError implements GraphQLError {\n\n  private final String message;\n\n  public GenericGraphQLError(String message) {\n    this.message = message;\n  }\n\n  @Override\n  public String getMessage() {\n    return message;\n  }\n\n  @Override\n  @JsonIgnore\n  public List<SourceLocation> getLocations() {\n    return emptyList();\n  }\n\n  @Override\n  @JsonIgnore\n  public ErrorType getErrorType() {\n    return null;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/error/GraphQLErrorHandler.java",
    "content": "package graphql.kickstart.execution.error;\n\nimport graphql.GraphQLError;\nimport java.util.List;\n\n/** @author Andrew Potter */\npublic interface GraphQLErrorHandler {\n\n  default boolean errorsPresent(List<GraphQLError> errors) {\n    return errors != null && !errors.isEmpty();\n  }\n\n  List<GraphQLError> processErrors(List<GraphQLError> errors);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/error/RenderableNonNullableFieldWasNullError.java",
    "content": "package graphql.kickstart.execution.error;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport graphql.ErrorType;\nimport graphql.GraphQLError;\nimport graphql.execution.NonNullableFieldWasNullError;\nimport graphql.language.SourceLocation;\nimport java.util.List;\nimport java.util.Map;\n\nclass RenderableNonNullableFieldWasNullError implements GraphQLError {\n\n  private final NonNullableFieldWasNullError delegate;\n\n  public RenderableNonNullableFieldWasNullError(\n      NonNullableFieldWasNullError nonNullableFieldWasNullError) {\n    this.delegate = nonNullableFieldWasNullError;\n  }\n\n  @Override\n  public String getMessage() {\n    return delegate.getMessage();\n  }\n\n  @Override\n  @JsonInclude(JsonInclude.Include.NON_NULL)\n  public List<SourceLocation> getLocations() {\n    return delegate.getLocations();\n  }\n\n  @Override\n  public ErrorType getErrorType() {\n    return delegate.getErrorType();\n  }\n\n  @Override\n  public List<Object> getPath() {\n    return delegate.getPath();\n  }\n\n  @Override\n  public Map<String, Object> toSpecification() {\n    return delegate.toSpecification();\n  }\n\n  @Override\n  @JsonInclude(JsonInclude.Include.NON_NULL)\n  public Map<String, Object> getExtensions() {\n    return delegate.getExtensions();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/input/GraphQLBatchedInvocationInput.java",
    "content": "package graphql.kickstart.execution.input;\n\nimport static java.util.stream.Collectors.toList;\n\nimport graphql.ExecutionInput;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport java.util.List;\n\n/** Interface representing a batched input. */\npublic interface GraphQLBatchedInvocationInput extends GraphQLInvocationInput {\n\n  /** @return each individual input in the batch, configured with a context. */\n  List<GraphQLSingleInvocationInput> getInvocationInputs();\n\n  default List<ExecutionInput> getExecutionInputs() {\n    return getInvocationInputs().stream()\n        .map(GraphQLSingleInvocationInput::getExecutionInput)\n        .collect(toList());\n  }\n\n  ContextSetting getContextSetting();\n\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/input/GraphQLInvocationInput.java",
    "content": "package graphql.kickstart.execution.input;\n\nimport java.util.List;\n\npublic interface GraphQLInvocationInput {\n  List<String> getQueries();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/input/GraphQLSingleInvocationInput.java",
    "content": "package graphql.kickstart.execution.input;\n\nimport static java.util.Collections.singletonList;\n\nimport graphql.ExecutionInput;\nimport graphql.execution.ExecutionId;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport graphql.schema.GraphQLSchema;\nimport java.util.List;\n\n/** Represents a single GraphQL execution. */\npublic class GraphQLSingleInvocationInput implements GraphQLInvocationInput {\n\n  private final GraphQLSchema schema;\n\n  private final ExecutionInput executionInput;\n\n  public GraphQLSingleInvocationInput(\n      GraphQLRequest request, GraphQLSchema schema, GraphQLKickstartContext context, Object root) {\n    this.schema = schema;\n    this.executionInput = createExecutionInput(request, context, root);\n  }\n\n  /** @return the schema to use to execute this query. */\n  public GraphQLSchema getSchema() {\n    return schema;\n  }\n\n  private ExecutionInput createExecutionInput(\n      GraphQLRequest graphQLRequest, GraphQLKickstartContext context, Object root) {\n    return ExecutionInput.newExecutionInput()\n        .query(graphQLRequest.getQuery())\n        .operationName(graphQLRequest.getOperationName())\n        .context(context)\n        .graphQLContext(context.getMapOfContext())\n        .root(root)\n        .variables(graphQLRequest.getVariables())\n        .extensions(graphQLRequest.getExtensions())\n        .dataLoaderRegistry(context.getDataLoaderRegistry())\n        .executionId(ExecutionId.generate())\n        .build();\n  }\n\n  public ExecutionInput getExecutionInput() {\n    return executionInput;\n  }\n\n  @Override\n  public List<String> getQueries() {\n    return singletonList(executionInput.getQuery());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/input/PerQueryBatchedInvocationInput.java",
    "content": "package graphql.kickstart.execution.input;\n\nimport static java.util.stream.Collectors.toList;\n\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport graphql.schema.GraphQLSchema;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport lombok.Getter;\n\n/** A Collection of GraphQLSingleInvocationInput that each have a unique context object. */\n@Getter\npublic class PerQueryBatchedInvocationInput implements GraphQLBatchedInvocationInput {\n\n  private final List<GraphQLSingleInvocationInput> invocationInputs;\n  private final ContextSetting contextSetting;\n\n  public PerQueryBatchedInvocationInput(\n      List<GraphQLRequest> requests,\n      GraphQLSchema schema,\n      Supplier<GraphQLKickstartContext> contextSupplier,\n      Object root,\n      ContextSetting contextSetting) {\n    invocationInputs =\n        requests.stream()\n            .map(\n                request ->\n                    new GraphQLSingleInvocationInput(request, schema, contextSupplier.get(), root))\n            .collect(Collectors.toList());\n    this.contextSetting = contextSetting;\n  }\n\n  @Override\n  public List<String> getQueries() {\n    return invocationInputs.stream()\n        .map(GraphQLSingleInvocationInput::getQueries)\n        .flatMap(List::stream)\n        .collect(toList());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/input/PerRequestBatchedInvocationInput.java",
    "content": "package graphql.kickstart.execution.input;\n\nimport static java.util.stream.Collectors.toList;\n\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport graphql.schema.GraphQLSchema;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport lombok.Getter;\n\n/** A collection of GraphQLSingleInvocationInputs that share a context object. */\n@Getter\npublic class PerRequestBatchedInvocationInput implements GraphQLBatchedInvocationInput {\n\n  private final List<GraphQLSingleInvocationInput> invocationInputs;\n  private final ContextSetting contextSetting;\n\n  public PerRequestBatchedInvocationInput(\n      List<GraphQLRequest> requests,\n      GraphQLSchema schema,\n      Supplier<GraphQLKickstartContext> contextSupplier,\n      Object root,\n      ContextSetting contextSetting) {\n    GraphQLKickstartContext context = contextSupplier.get();\n    invocationInputs =\n        requests.stream()\n            .map(request -> new GraphQLSingleInvocationInput(request, schema, context, root))\n            .collect(toList());\n    this.contextSetting = contextSetting;\n  }\n\n  @Override\n  public List<String> getQueries() {\n    return invocationInputs.stream()\n        .map(GraphQLSingleInvocationInput::getQueries)\n        .flatMap(List::stream)\n        .collect(toList());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/AbstractTrackingApproach.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.ExecutionResult;\nimport graphql.execution.ExecutionId;\nimport graphql.execution.FieldValueInfo;\nimport graphql.execution.ResultPath;\nimport graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext;\nimport graphql.execution.instrumentation.InstrumentationContext;\nimport graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;\nimport graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.extern.slf4j.Slf4j;\nimport org.dataloader.DataLoaderRegistry;\n\n/** Handles logic common to tracking approaches. */\n@Slf4j\npublic abstract class AbstractTrackingApproach implements TrackingApproach {\n\n  private final DataLoaderRegistry dataLoaderRegistry;\n\n  private final RequestStack stack = new RequestStack();\n\n  protected AbstractTrackingApproach(DataLoaderRegistry dataLoaderRegistry) {\n    this.dataLoaderRegistry = dataLoaderRegistry;\n  }\n\n  /** @return allows extending classes to modify the stack. */\n  protected RequestStack getStack() {\n    return stack;\n  }\n\n  @Override\n  public ExecutionStrategyInstrumentationContext beginExecutionStrategy(\n      InstrumentationExecutionStrategyParameters parameters) {\n    ExecutionId executionId = parameters.getExecutionContext().getExecutionId();\n    ResultPath path = parameters.getExecutionStrategyParameters().getPath();\n    int parentLevel = path.getLevel();\n    int curLevel = parentLevel + 1;\n    int fieldCount = parameters.getExecutionStrategyParameters().getFields().size();\n    synchronized (stack) {\n      stack.increaseExpectedFetchCount(executionId, curLevel, fieldCount);\n      stack.increaseHappenedStrategyCalls(executionId, curLevel);\n    }\n\n    return new ExecutionStrategyInstrumentationContext() {\n      @Override\n      public void onDispatched() {\n        // default empty implementation\n      }\n\n      @Override\n      public void onCompleted(ExecutionResult result, Throwable t) {\n        // default empty implementation\n      }\n\n      @Override\n      public void onFieldValuesInfo(List<FieldValueInfo> fieldValueInfoList) {\n        synchronized (stack) {\n          stack.setStatus(\n              executionId,\n              handleOnFieldValuesInfo(fieldValueInfoList, stack, executionId, curLevel));\n          if (stack.allReady()) {\n            dispatchWithoutLocking();\n          }\n        }\n      }\n    };\n  }\n\n  //\n  // thread safety : called with synchronised(stack)\n  //\n  private boolean handleOnFieldValuesInfo(\n      List<FieldValueInfo> fieldValueInfoList,\n      RequestStack stack,\n      ExecutionId executionId,\n      int curLevel) {\n    stack.increaseHappenedOnFieldValueCalls(executionId, curLevel);\n    int expectedStrategyCalls = 0;\n    for (FieldValueInfo fieldValueInfo : fieldValueInfoList) {\n      if (fieldValueInfo.getCompleteValueType() == FieldValueInfo.CompleteValueType.OBJECT) {\n        expectedStrategyCalls++;\n      } else if (fieldValueInfo.getCompleteValueType() == FieldValueInfo.CompleteValueType.LIST) {\n        expectedStrategyCalls += getCountForList(fieldValueInfo);\n      }\n    }\n    stack.increaseExpectedStrategyCalls(executionId, curLevel + 1, expectedStrategyCalls);\n    return dispatchIfNeeded(stack, executionId, curLevel + 1);\n  }\n\n  private int getCountForList(FieldValueInfo fieldValueInfo) {\n    int result = 0;\n    for (FieldValueInfo cvi : fieldValueInfo.getFieldValueInfos()) {\n      if (cvi.getCompleteValueType() == FieldValueInfo.CompleteValueType.OBJECT) {\n        result++;\n      } else if (cvi.getCompleteValueType() == FieldValueInfo.CompleteValueType.LIST) {\n        result += getCountForList(cvi);\n      }\n    }\n    return result;\n  }\n\n  @Override\n  public InstrumentationContext<Object> beginFieldFetch(\n      InstrumentationFieldFetchParameters parameters) {\n    ExecutionId executionId = parameters.getExecutionContext().getExecutionId();\n    ResultPath path = parameters.getEnvironment().getExecutionStepInfo().getPath();\n    int level = path.getLevel();\n    return new InstrumentationContext<Object>() {\n\n      @Override\n      public void onDispatched() {\n        synchronized (stack) {\n          stack.increaseFetchCount(executionId, level);\n          stack.setStatus(executionId, dispatchIfNeeded(stack, executionId, level));\n\n          if (stack.allReady()) {\n            dispatchWithoutLocking();\n          }\n        }\n      }\n\n      @Override\n      public void onCompleted(Object result, Throwable t) {\n        // default empty implementation\n      }\n    };\n  }\n\n  @Override\n  public void removeTracking(ExecutionId executionId) {\n    synchronized (stack) {\n      stack.removeExecution(executionId);\n      if (stack.allReady()) {\n        dispatchWithoutLocking();\n      }\n    }\n  }\n\n  //\n  // thread safety : called with synchronised(stack)\n  //\n  private boolean dispatchIfNeeded(RequestStack stack, ExecutionId executionId, int level) {\n    if (levelReady(stack, executionId, level)) {\n      return stack.dispatchIfNotDispatchedBefore(executionId, level);\n    }\n    return false;\n  }\n\n  //\n  // thread safety : called with synchronised(stack)\n  //\n  private boolean levelReady(RequestStack stack, ExecutionId executionId, int level) {\n    if (level == 1) {\n      // level 1 is special: there is only one strategy call and that's it\n      return stack.allFetchesHappened(executionId, 1);\n    }\n    return (levelReady(stack, executionId, level - 1)\n        && stack.allOnFieldCallsHappened(executionId, level - 1)\n        && stack.allStrategyCallsHappened(executionId, level)\n        && stack.allFetchesHappened(executionId, level));\n  }\n\n  @Override\n  public void dispatch() {\n    synchronized (stack) {\n      dispatchWithoutLocking();\n    }\n  }\n\n  private void dispatchWithoutLocking() {\n    log.debug(\"Dispatching data loaders ({})\", dataLoaderRegistry.getKeys());\n    dataLoaderRegistry.dispatchAll();\n    stack.allReset();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/DataLoaderDispatcherInstrumentationState.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.execution.ExecutionId;\nimport graphql.execution.instrumentation.InstrumentationState;\nimport org.dataloader.DataLoaderRegistry;\n\n/** A base class that keeps track of whether aggressive batching can be used */\npublic class DataLoaderDispatcherInstrumentationState implements InstrumentationState {\n\n  private final TrackingApproach approach;\n  private final DataLoaderRegistry dataLoaderRegistry;\n  private final boolean hasNoDataLoaders;\n  private boolean aggressivelyBatching = true;\n\n  public DataLoaderDispatcherInstrumentationState(\n      DataLoaderRegistry dataLoaderRegistry, TrackingApproach approach, ExecutionId executionId) {\n\n    this.dataLoaderRegistry = dataLoaderRegistry;\n    this.approach = approach;\n    approach.createState(executionId);\n    hasNoDataLoaders = dataLoaderRegistry.getKeys().isEmpty();\n  }\n\n  boolean isAggressivelyBatching() {\n    return aggressivelyBatching;\n  }\n\n  void setAggressivelyBatching(boolean aggressivelyBatching) {\n    this.aggressivelyBatching = aggressivelyBatching;\n  }\n\n  TrackingApproach getApproach() {\n    return approach;\n  }\n\n  DataLoaderRegistry getDataLoaderRegistry() {\n    return dataLoaderRegistry;\n  }\n\n  boolean hasNoDataLoaders() {\n    return hasNoDataLoaders;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/FieldLevelTrackingApproach.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.Internal;\nimport graphql.execution.ExecutionId;\nimport graphql.execution.instrumentation.InstrumentationState;\nimport org.dataloader.DataLoaderRegistry;\n\n/**\n * This approach uses field level tracking to achieve its aims of making the data loader more\n * efficient. Can handle new/concurrent executions using the same sets of dataloaders, attempting to\n * batch load calls together.\n */\n@Internal\npublic class FieldLevelTrackingApproach extends AbstractTrackingApproach {\n\n  public FieldLevelTrackingApproach(DataLoaderRegistry dataLoaderRegistry) {\n    super(dataLoaderRegistry);\n  }\n\n  public InstrumentationState createState(ExecutionId executionId) {\n    synchronized (getStack()) {\n      if (getStack().contains(executionId)) {\n        throw new TrackingApproachException(\n            String.format(\"Execution id %s already in active execution\", executionId));\n      }\n      getStack().addExecution(executionId);\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/NoOpInstrumentationProvider.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.execution.instrumentation.SimplePerformantInstrumentation;\nimport graphql.kickstart.execution.config.InstrumentationProvider;\n\npublic class NoOpInstrumentationProvider implements InstrumentationProvider {\n\n  @Override\n  public Instrumentation getInstrumentation() {\n    return SimplePerformantInstrumentation.INSTANCE;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/RequestLevelTrackingApproach.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.execution.ExecutionId;\nimport graphql.execution.instrumentation.InstrumentationState;\nimport java.util.List;\nimport org.dataloader.DataLoaderRegistry;\n\n/** Dispatching approach that expects to know about all executions before execution starts. */\npublic class RequestLevelTrackingApproach extends AbstractTrackingApproach {\n\n  public RequestLevelTrackingApproach(\n      List<ExecutionId> executionIds, DataLoaderRegistry dataLoaderRegistry) {\n    super(dataLoaderRegistry);\n    RequestStack requestStack = getStack();\n    executionIds.forEach(requestStack::addExecution);\n  }\n\n  @Override\n  public InstrumentationState createState(ExecutionId executionId) {\n    if (!getStack().contains(executionId)) {\n      throw new TrackingApproachException(\n          String.format(\"Request tracking not set up with execution id %s\", executionId));\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/RequestStack.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.Assert;\nimport graphql.execution.ExecutionId;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\n/** Manages sets of call stack state for ongoing executions. */\npublic class RequestStack {\n\n  private final Map<ExecutionId, CallStack> activeRequests = new LinkedHashMap<>();\n\n  private final Map<ExecutionId, Boolean> status = new LinkedHashMap<>();\n\n  /**\n   * Sets the status indicating if a specific execution is ready for dispatching.\n   *\n   * @param executionId must be an active execution\n   * @param toState if ready to dispatch\n   */\n  public void setStatus(ExecutionId executionId, boolean toState) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Can not set status for execution %s, it is not managed by this request stack\",\n              executionId));\n    }\n    if (toState) {\n      status.put(executionId, true);\n    }\n  }\n\n  /** @return if all managed executions are ready to be dispatched. */\n  public boolean allReady() {\n    return status.values().stream().noneMatch(Boolean.FALSE::equals)\n        && activeRequests.values().stream().map(CallStack::getDispatchedLevels).distinct().count()\n            <= 1;\n  }\n\n  /** Removes all dispatch status. Should be used after a call to dispatch. */\n  public void allReset() {\n    status.keySet().forEach(key -> status.put(key, false));\n  }\n\n  /**\n   * Returns if this RequestStack is managing an execution for the supplied id.\n   *\n   * @param executionId no restrictions\n   * @return if an active execution\n   */\n  public boolean contains(ExecutionId executionId) {\n    return activeRequests.containsKey(executionId);\n  }\n\n  /**\n   * Removes any state associated with an id.\n   *\n   * @param executionId no restrictions\n   */\n  public void removeExecution(ExecutionId executionId) {\n    activeRequests.remove(executionId);\n    status.remove(executionId);\n  }\n\n  /**\n   * Creates a call stack for an associated id.\n   *\n   * @param executionId can not already be managed by this RequestStack\n   */\n  public void addExecution(ExecutionId executionId) {\n    if (activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\"An execution already exists for %s, can not create one\", executionId));\n    }\n    CallStack callStack = new CallStack();\n    status.put(executionId, false);\n    activeRequests.put(executionId, callStack);\n  }\n\n  /**\n   * Increases the expected fetch count for an execution.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param curLevel the level to increase the expected count\n   * @param fieldCount the amount to increase the expected amount\n   */\n  public void increaseExpectedFetchCount(ExecutionId executionId, int curLevel, int fieldCount) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not increase expected fetch count\",\n              executionId));\n    }\n    activeRequests.get(executionId).increaseExpectedFetchCount(curLevel, fieldCount);\n  }\n\n  /**\n   * Increments happened strategy calls for an execution at specified level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param curLevel level to increment\n   */\n  public void increaseHappenedStrategyCalls(ExecutionId executionId, int curLevel) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not increase happened happened strategy calls\",\n              executionId));\n    }\n    activeRequests.get(executionId).increaseHappenedStrategyCalls(curLevel);\n  }\n\n  /**\n   * Increments happened on field value calls for an execution at a specified level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param curLevel level to increment\n   */\n  public void increaseHappenedOnFieldValueCalls(ExecutionId executionId, int curLevel) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not increase happened on field calls\",\n              executionId));\n    }\n    activeRequests.get(executionId).increaseHappenedOnFieldValueCalls(curLevel);\n  }\n\n  /**\n   * Increases expected strategy calls for an execution at a specified level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param curLevel level to increase\n   * @param expectedStrategyCalls number to increment by\n   */\n  public void increaseExpectedStrategyCalls(\n      ExecutionId executionId, int curLevel, int expectedStrategyCalls) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not increase expected strategy calls\",\n              executionId));\n    }\n    activeRequests.get(executionId).increaseExpectedStrategyCalls(curLevel, expectedStrategyCalls);\n  }\n\n  /**\n   * Get the all fetches happened value for an execution at a specific level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to get the value of\n   * @return allFetchesHappened\n   */\n  public boolean allFetchesHappened(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not get all fetches happened value\",\n              executionId));\n    }\n    return activeRequests.get(executionId).allFetchesHappened(level);\n  }\n\n  /**\n   * Get the all on field calls happened for an exectuion at a specific level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to get the value of\n   * @return allOnFieldCallsHappened\n   */\n  public boolean allOnFieldCallsHappened(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not get all on field calls happened value\",\n              executionId));\n    }\n    return activeRequests.get(executionId).allOnFieldCallsHappened(level);\n  }\n\n  /**\n   * Get the all strategy calls happened value for an exectuion at a specific level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to get the value of\n   * @return allStrategyCallsHappened\n   */\n  public boolean allStrategyCallsHappened(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not get all strategy calls happened value\",\n              executionId));\n    }\n    return activeRequests.get(executionId).allStrategyCallsHappened(level);\n  }\n\n  /**\n   * Get the dispatch if not dispatched before value of a specific level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to get the value of\n   * @return dispatchIfNotDispattchedBefore\n   */\n  public boolean dispatchIfNotDispatchedBefore(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not get dispatch if not dispatched before value\",\n              executionId));\n    }\n    return activeRequests.get(executionId).dispatchIfNotDispatchedBefore(level);\n  }\n\n  /**\n   * Increment the fetch count for an execution at a specific level.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to increment\n   */\n  public void increaseFetchCount(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not increase fetch count\",\n              executionId));\n    }\n    activeRequests.get(executionId).increaseFetchCount(level);\n  }\n\n  /**\n   * Clear and mark current level as ready for an execution.\n   *\n   * @param executionId must be managed by this RequestStack\n   * @param level the level to clear and mark\n   */\n  public void clearAndMarkCurrentLevelAsReady(ExecutionId executionId, int level) {\n    if (!activeRequests.containsKey(executionId)) {\n      throw new IllegalStateException(\n          String.format(\n              \"Execution %s not managed by this RequestStack, can not clea and mark current level as ready\",\n              executionId));\n    }\n    activeRequests.get(executionId).clearAndMarkCurrentLevelAsReady(level);\n  }\n\n  private static class CallStack {\n\n    private final Map<Integer, Integer> expectedFetchCountPerLevel = new LinkedHashMap<>();\n    private final Map<Integer, Integer> fetchCountPerLevel = new LinkedHashMap<>();\n    private final Map<Integer, Integer> expectedStrategyCallsPerLevel = new LinkedHashMap<>();\n    private final Map<Integer, Integer> happenedStrategyCallsPerLevel = new LinkedHashMap<>();\n    private final Map<Integer, Integer> happenedOnFieldValueCallsPerLevel = new LinkedHashMap<>();\n\n    private final List<Integer> dispatchedLevels = new ArrayList<>();\n\n    private CallStack() {\n      expectedStrategyCallsPerLevel.put(1, 1);\n    }\n\n    private void increaseExpectedFetchCount(int level, int count) {\n      expectedFetchCountPerLevel.put(\n          level, expectedFetchCountPerLevel.getOrDefault(level, 0) + count);\n    }\n\n    private void increaseFetchCount(int level) {\n      fetchCountPerLevel.put(level, fetchCountPerLevel.getOrDefault(level, 0) + 1);\n    }\n\n    private void increaseExpectedStrategyCalls(int level, int count) {\n      expectedStrategyCallsPerLevel.put(\n          level, expectedStrategyCallsPerLevel.getOrDefault(level, 0) + count);\n    }\n\n    private void increaseHappenedStrategyCalls(int level) {\n      happenedStrategyCallsPerLevel.put(\n          level, happenedStrategyCallsPerLevel.getOrDefault(level, 0) + 1);\n    }\n\n    private void increaseHappenedOnFieldValueCalls(int level) {\n      happenedOnFieldValueCallsPerLevel.put(\n          level, happenedOnFieldValueCallsPerLevel.getOrDefault(level, 0) + 1);\n    }\n\n    private boolean allStrategyCallsHappened(int level) {\n      return Objects.equals(\n          happenedStrategyCallsPerLevel.get(level), expectedStrategyCallsPerLevel.get(level));\n    }\n\n    private boolean allOnFieldCallsHappened(int level) {\n      return Objects.equals(\n          happenedOnFieldValueCallsPerLevel.get(level), expectedStrategyCallsPerLevel.get(level));\n    }\n\n    private boolean allFetchesHappened(int level) {\n      return Objects.equals(fetchCountPerLevel.get(level), expectedFetchCountPerLevel.get(level));\n    }\n\n    private List<Integer> getDispatchedLevels() {\n      return dispatchedLevels;\n    }\n\n    @Override\n    public String toString() {\n      return \"CallStack{\"\n          + \"expectedFetchCountPerLevel=\"\n          + expectedFetchCountPerLevel\n          + \", fetchCountPerLevel=\"\n          + fetchCountPerLevel\n          + \", expectedStrategyCallsPerLevel=\"\n          + expectedStrategyCallsPerLevel\n          + \", happenedStrategyCallsPerLevel=\"\n          + happenedStrategyCallsPerLevel\n          + \", happenedOnFieldValueCallsPerLevel=\"\n          + happenedOnFieldValueCallsPerLevel\n          + \", dispatchedLevels\"\n          + dispatchedLevels\n          + '}';\n    }\n\n    private boolean dispatchIfNotDispatchedBefore(int level) {\n      if (dispatchedLevels.contains(level)) {\n        Assert.assertShouldNeverHappen(\"level \" + level + \" already dispatched\");\n        return false;\n      }\n      dispatchedLevels.add(level);\n      return true;\n    }\n\n    private void clearAndMarkCurrentLevelAsReady(int level) {\n      expectedFetchCountPerLevel.clear();\n      fetchCountPerLevel.clear();\n      expectedStrategyCallsPerLevel.clear();\n      happenedStrategyCallsPerLevel.clear();\n      happenedOnFieldValueCallsPerLevel.clear();\n      dispatchedLevels.clear();\n\n      // make sure the level is ready\n      expectedFetchCountPerLevel.put(level, 1);\n      expectedStrategyCallsPerLevel.put(level, 1);\n      happenedStrategyCallsPerLevel.put(level, 1);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/TrackingApproach.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\nimport graphql.execution.ExecutionId;\nimport graphql.execution.instrumentation.ExecutionStrategyInstrumentationContext;\nimport graphql.execution.instrumentation.InstrumentationContext;\nimport graphql.execution.instrumentation.InstrumentationState;\nimport graphql.execution.instrumentation.parameters.InstrumentationExecutionStrategyParameters;\nimport graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters;\n\npublic interface TrackingApproach extends InstrumentationState {\n\n  /**\n   * Handles creating any state for DataLoaderDispatcherInstrumentation\n   *\n   * @param executionId the execution to create state for.\n   * @return individual state, if any for the execution.\n   */\n  InstrumentationState createState(ExecutionId executionId);\n\n  /** Dispatch dataloaders and clean up state. */\n  void dispatch();\n\n  /**\n   * Handles approach specific logic for DataLoaderDispatcherInstrumentation.\n   *\n   * @param parameters parameters supplied to DataLoaderDispatcherInstrumentation\n   * @return the instrumented context\n   */\n  ExecutionStrategyInstrumentationContext beginExecutionStrategy(\n      InstrumentationExecutionStrategyParameters parameters);\n\n  /**\n   * Handles approach specific logic for DataLoaderDispatcherInstrumentation.\n   *\n   * @param parameters parameters supplied to DataLoaderDispatcherInstrumentation\n   * @return the instrumented context\n   */\n  InstrumentationContext<Object> beginFieldFetch(InstrumentationFieldFetchParameters parameters);\n\n  /**\n   * Removes tracking state for an execution.\n   *\n   * @param executionId the execution to remove state for\n   */\n  void removeTracking(ExecutionId executionId);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/instrumentation/TrackingApproachException.java",
    "content": "package graphql.kickstart.execution.instrumentation;\n\npublic class TrackingApproachException extends RuntimeException {\n\n  TrackingApproachException(String message) {\n    super(message);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/AtomicSubscriptionSubscription.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport java.util.concurrent.atomic.AtomicReference;\nimport org.reactivestreams.Subscription;\n\npublic class AtomicSubscriptionSubscription {\n\n  private final AtomicReference<Subscription> reference = new AtomicReference<>(null);\n\n  public void set(Subscription subscription) {\n    if (reference.get() != null) {\n      throw new IllegalStateException(\"Cannot overwrite subscription!\");\n    }\n\n    reference.set(subscription);\n  }\n\n  public Subscription get() {\n    Subscription subscription = reference.get();\n    if (subscription == null) {\n      throw new IllegalStateException(\"Subscription has not been initialized yet!\");\n    }\n\n    return subscription;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/DefaultSubscriptionSession.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport graphql.ExecutionResult;\nimport graphql.execution.reactive.SingleSubscriberPublisher;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.reactivestreams.Publisher;\nimport org.reactivestreams.Subscription;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class DefaultSubscriptionSession implements SubscriptionSession {\n\n  @Getter private final GraphQLSubscriptionMapper mapper;\n  private SingleSubscriberPublisher<String> publisher = new SingleSubscriberPublisher<>();\n  private SessionSubscriptions subscriptions = new SessionSubscriptions();\n\n  @Override\n  public void send(String message) {\n    Objects.requireNonNull(message, \"message is required\");\n    publisher.offer(message);\n  }\n\n  @Override\n  public void sendMessage(Object payload) {\n    Objects.requireNonNull(payload, \"payload is required\");\n    send(mapper.serialize(payload));\n  }\n\n  @Override\n  public void subscribe(String id, Publisher<ExecutionResult> dataPublisher) {\n    dataPublisher.subscribe(new SessionSubscriber(this, id));\n  }\n\n  @Override\n  public void add(String id, Subscription subscription) {\n    subscriptions.add(id, subscription);\n  }\n\n  @Override\n  public void unsubscribe(String id) {\n    subscriptions.cancel(id);\n  }\n\n  @Override\n  public void sendDataMessage(String id, Object payload) {\n    send(mapper.serialize(payload));\n  }\n\n  @Override\n  public void sendErrorMessage(String id, Object payload) {\n    send(mapper.serialize(payload));\n  }\n\n  @Override\n  public void sendCompleteMessage(String id) {\n    // default empty implementation\n  }\n\n  @Override\n  public void close(String reason) {\n    log.debug(\"Closing subscription session {}\", getId());\n    subscriptions.close();\n    publisher.noMoreData();\n  }\n\n  @Override\n  public Map<String, Object> getUserProperties() {\n    return new HashMap<>();\n  }\n\n  @Override\n  public boolean isOpen() {\n    return true;\n  }\n\n  @Override\n  public String getId() {\n    return null;\n  }\n\n  @Override\n  public SessionSubscriptions getSubscriptions() {\n    return subscriptions;\n  }\n\n  @Override\n  public Object unwrap() {\n    throw new UnsupportedOperationException();\n  }\n\n  @Override\n  public Publisher<String> getPublisher() {\n    return publisher;\n  }\n\n  @Override\n  public String toString() {\n    return getId();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/GraphQLSubscriptionInvocationInputFactory.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\n\npublic interface GraphQLSubscriptionInvocationInputFactory {\n\n  GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest, SubscriptionSession session);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/GraphQLSubscriptionMapper.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport graphql.ExecutionResult;\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport java.util.Map;\nimport java.util.Objects;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\npublic class GraphQLSubscriptionMapper {\n\n  private final GraphQLObjectMapper graphQLObjectMapper;\n\n  public GraphQLRequest readGraphQLRequest(String payload) {\n    Objects.requireNonNull(payload, \"Payload is required\");\n    try {\n      return graphQLObjectMapper.getJacksonMapper().readValue(payload, GraphQLRequest.class);\n    } catch (JsonProcessingException e) {\n      throw new GraphQLException(\"Cannot read GraphQL request from payload '\" + payload + \"'\", e);\n    }\n  }\n\n  public GraphQLRequest convertGraphQLRequest(Object payload) {\n    Objects.requireNonNull(payload, \"Payload is required\");\n    return graphQLObjectMapper.getJacksonMapper().convertValue(payload, GraphQLRequest.class);\n  }\n\n  public ExecutionResult sanitizeErrors(ExecutionResult executionResult) {\n    return graphQLObjectMapper.sanitizeErrors(executionResult);\n  }\n\n  public boolean hasNoErrors(ExecutionResult executionResult) {\n    return !graphQLObjectMapper.areErrorsPresent(executionResult);\n  }\n\n  public Map<String, Object> convertSanitizedExecutionResult(ExecutionResult executionResult) {\n    return graphQLObjectMapper.convertSanitizedExecutionResult(executionResult, false);\n  }\n\n  public String serialize(Object payload) {\n    try {\n      return graphQLObjectMapper.getJacksonMapper().writeValueAsString(payload);\n    } catch (JsonProcessingException e) {\n      return e.getMessage();\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SessionSubscriber.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport static java.util.Collections.singletonList;\n\nimport graphql.ExecutionResult;\nimport graphql.GraphqlErrorBuilder;\nimport graphql.execution.NonNullableFieldWasNullException;\nimport graphql.kickstart.execution.error.GenericGraphQLError;\nimport java.util.HashMap;\nimport java.util.Map;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\n@Slf4j\n@RequiredArgsConstructor\nclass SessionSubscriber implements Subscriber<ExecutionResult> {\n\n  private final SubscriptionSession session;\n  private final String id;\n  private AtomicSubscriptionSubscription subscriptionReference =\n      new AtomicSubscriptionSubscription();\n\n  @Override\n  public void onSubscribe(Subscription subscription) {\n    log.debug(\"Subscribe to execution result: {}\", subscription);\n    subscriptionReference.set(subscription);\n    subscriptionReference.get().request(1);\n\n    session.add(id, subscriptionReference.get());\n  }\n\n  @Override\n  public void onNext(ExecutionResult executionResult) {\n    Map<String, Object> result = new HashMap<>();\n    result.put(\"data\", executionResult.getData());\n\n    session.sendDataMessage(id, result);\n    subscriptionReference.get().request(1);\n  }\n\n  @Override\n  public void onError(Throwable throwable) {\n    log.error(\"Subscription error\", throwable);\n    Map<String, Object> payload = new HashMap<>();\n    if (throwable.getCause() instanceof NonNullableFieldWasNullException) {\n      NonNullableFieldWasNullException e = (NonNullableFieldWasNullException) throwable.getCause();\n      payload.put(\n          \"errors\",\n          singletonList(\n              GraphqlErrorBuilder.newError().message(e.getMessage()).path(e.getPath()).build()));\n    } else {\n      payload.put(\"errors\", singletonList(new GenericGraphQLError(throwable.getMessage())));\n    }\n\n    session.unsubscribe(id);\n    session.sendErrorMessage(id, payload);\n  }\n\n  @Override\n  public void onComplete() {\n    session.unsubscribe(id);\n    session.sendCompleteMessage(id);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SessionSubscriptions.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport org.reactivestreams.Subscription;\n\n/** @author Andrew Potter */\npublic class SessionSubscriptions {\n\n  private final Object lock = new Object();\n\n  private boolean closed = false;\n  private Map<String, Subscription> subscriptions = new ConcurrentHashMap<>();\n\n  public void add(Subscription subscription) {\n    add(getImplicitId(subscription), subscription);\n  }\n\n  public void add(String id, Subscription subscription) {\n    synchronized (lock) {\n      if (closed) {\n        throw new IllegalStateException(\"Websocket was already closed!\");\n      }\n      subscriptions.put(id, subscription);\n    }\n  }\n\n  public void cancel(Subscription subscription) {\n    cancel(getImplicitId(subscription));\n  }\n\n  public void cancel(String id) {\n    Subscription subscription = subscriptions.remove(id);\n    if (subscription != null) {\n      subscription.cancel();\n    }\n  }\n\n  public void close() {\n    synchronized (lock) {\n      closed = true;\n      subscriptions.forEach((k, v) -> v.cancel());\n      subscriptions.clear();\n    }\n  }\n\n  private String getImplicitId(Subscription subscription) {\n    return String.valueOf(subscription.hashCode());\n  }\n\n  public int getSubscriptionCount() {\n    return subscriptions.size();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SubscriptionConnectionListener.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\n/** Marker interface */\npublic interface SubscriptionConnectionListener {}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SubscriptionException.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\npublic class SubscriptionException extends Exception {\n\n  private final transient Object payload;\n\n  public SubscriptionException() {\n    this(null);\n  }\n\n  public SubscriptionException(Object payload) {\n    this.payload = payload;\n  }\n\n  public Object getPayload() {\n    return payload;\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SubscriptionProtocolFactory.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport java.util.function.Consumer;\n\n/** @author Andrew Potter */\npublic abstract class SubscriptionProtocolFactory {\n\n  private final String protocol;\n\n  protected SubscriptionProtocolFactory(String protocol) {\n    this.protocol = protocol;\n  }\n\n  public String getProtocol() {\n    return protocol;\n  }\n\n  public abstract Consumer<String> createConsumer(SubscriptionSession session);\n\n  public void shutdown() {\n    // do nothing\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/SubscriptionSession.java",
    "content": "package graphql.kickstart.execution.subscriptions;\n\nimport graphql.ExecutionResult;\nimport java.util.Map;\nimport org.reactivestreams.Publisher;\nimport org.reactivestreams.Subscription;\n\npublic interface SubscriptionSession {\n\n  void subscribe(String id, Publisher<ExecutionResult> data);\n\n  void add(String id, Subscription subscription);\n\n  void unsubscribe(String id);\n\n  void send(String message);\n\n  void sendMessage(Object payload);\n\n  void sendDataMessage(String id, Object payload);\n\n  void sendErrorMessage(String id, Object payload);\n\n  void sendCompleteMessage(String id);\n\n  void close(String reason);\n\n  /**\n   * While the session is open, this method returns a Map that the developer may use to store\n   * application specific information relating to this session instance. The developer may retrieve\n   * information from this Map at any time between the opening of the session and during the\n   * onClose() method. But outside that time, any information stored using this Map may no longer be\n   * kept by the container. Web socket applications running on distributed implementations of the\n   * web container should make any application specific objects stored here java.io.Serializable, or\n   * the object may not be recreated after a failover.\n   *\n   * @return an editable Map of application data.\n   */\n  Map<String, Object> getUserProperties();\n\n  boolean isOpen();\n\n  String getId();\n\n  SessionSubscriptions getSubscriptions();\n\n  Object unwrap();\n\n  Publisher<String> getPublisher();\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloCommandProvider.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type;\nimport java.util.Collection;\nimport java.util.EnumMap;\n\npublic class ApolloCommandProvider {\n\n  private final EnumMap<Type, SubscriptionCommand> commands = new EnumMap<>(Type.class);\n\n  public ApolloCommandProvider(\n      GraphQLSubscriptionMapper mapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Collection<ApolloSubscriptionConnectionListener> connectionListeners) {\n    commands.put(\n        Type.GQL_CONNECTION_INIT, new SubscriptionConnectionInitCommand(connectionListeners));\n    commands.put(\n        Type.GQL_START,\n        new SubscriptionStartCommand(\n            mapper, invocationInputFactory, graphQLInvoker, connectionListeners));\n    commands.put(Type.GQL_STOP, new SubscriptionStopCommand(connectionListeners));\n    commands.put(\n        Type.GQL_CONNECTION_TERMINATE,\n        new SubscriptionConnectionTerminateCommand(connectionListeners));\n  }\n\n  public SubscriptionCommand getByType(Type type) {\n    if (commands.containsKey(type)) {\n      return commands.get(type);\n    }\n    throw new IllegalStateException(\"No command found for type \" + type);\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionConnectionListener.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionConnectionListener;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\n\npublic interface ApolloSubscriptionConnectionListener extends SubscriptionConnectionListener {\n\n  default void onConnect(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  default void onStart(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  default void onStop(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  default void onTerminate(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  default void shutdown() {\n    // do nothing\n  }\n}"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionConsumer.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type;\nimport java.util.function.Consumer;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class ApolloSubscriptionConsumer implements Consumer<String> {\n\n  private final SubscriptionSession session;\n  private final GraphQLObjectMapper objectMapper;\n  private final ApolloCommandProvider commandProvider;\n\n  @Override\n  public void accept(String request) {\n    try {\n      OperationMessage message =\n          objectMapper.getJacksonMapper().readValue(request, OperationMessage.class);\n      SubscriptionCommand command = commandProvider.getByType(message.getType());\n      command.apply(session, message);\n    } catch (JsonProcessingException e) {\n      log.error(\"Cannot read subscription command '{}'\", request, e);\n      session.sendMessage(new OperationMessage(Type.GQL_CONNECTION_ERROR, null, e.getMessage()));\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionKeepAliveRunner.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\nclass ApolloSubscriptionKeepAliveRunner {\n\n  private static final int EXECUTOR_POOL_SIZE = 10;\n\n  private final ScheduledExecutorService executor;\n  private final OperationMessage keepAliveMessage;\n  private final Map<SubscriptionSession, Future<?>> futures;\n  private final long keepAliveIntervalSeconds;\n\n  ApolloSubscriptionKeepAliveRunner(Duration keepAliveInterval) {\n    this.keepAliveMessage = OperationMessage.newKeepAliveMessage();\n    this.executor = Executors.newScheduledThreadPool(EXECUTOR_POOL_SIZE);\n    this.futures = new ConcurrentHashMap<>();\n    this.keepAliveIntervalSeconds = keepAliveInterval.getSeconds();\n  }\n\n  void keepAlive(SubscriptionSession session) {\n    futures.computeIfAbsent(session, this::startKeepAlive);\n  }\n\n  private ScheduledFuture<?> startKeepAlive(SubscriptionSession session) {\n    return executor.scheduleAtFixedRate(\n        () -> {\n          try {\n            if (session.isOpen()) {\n              session.sendMessage(keepAliveMessage);\n            } else {\n              log.debug(\"Session {} appears to be closed. Aborting keep alive\", session.getId());\n              abort(session);\n            }\n          } catch (Exception t) {\n            log.error(\n                \"Cannot send keep alive message to session {}. Aborting keep alive\",\n                session.getId(),\n                t);\n            abort(session);\n          }\n        },\n        0,\n        keepAliveIntervalSeconds,\n        TimeUnit.SECONDS);\n  }\n\n  void abort(SubscriptionSession session) {\n    Future<?> future = futures.remove(session);\n    if (future != null) {\n      future.cancel(true);\n    }\n  }\n\n  void shutdown() {\n    this.executor.shutdown();\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionProtocolFactory.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionProtocolFactory;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport lombok.Getter;\n\n/** @author Andrew Potter */\npublic class ApolloSubscriptionProtocolFactory extends SubscriptionProtocolFactory {\n\n  public static final int KEEP_ALIVE_INTERVAL = 15;\n  @Getter private final GraphQLObjectMapper objectMapper;\n  private final ApolloCommandProvider commandProvider;\n  private KeepAliveSubscriptionConnectionListener keepAlive;\n\n  public ApolloSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker) {\n    this(\n        objectMapper,\n        invocationInputFactory,\n        graphQLInvoker,\n        Duration.ofSeconds(KEEP_ALIVE_INTERVAL));\n  }\n\n  public ApolloSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Duration keepAliveInterval) {\n    this(objectMapper, invocationInputFactory, graphQLInvoker, null, keepAliveInterval);\n  }\n\n  public ApolloSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Collection<ApolloSubscriptionConnectionListener> connectionListeners) {\n    this(\n        objectMapper,\n        invocationInputFactory,\n        graphQLInvoker,\n        connectionListeners,\n        Duration.ofSeconds(KEEP_ALIVE_INTERVAL));\n  }\n\n  public ApolloSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Collection<ApolloSubscriptionConnectionListener> connectionListeners,\n      Duration keepAliveInterval) {\n    super(\"graphql-ws\");\n    this.objectMapper = objectMapper;\n    Set<ApolloSubscriptionConnectionListener> listeners = new HashSet<>();\n    if (connectionListeners != null) {\n      listeners.addAll(connectionListeners);\n    }\n    if (keepAliveInterval != null\n        && listeners.stream()\n            .noneMatch(KeepAliveSubscriptionConnectionListener.class::isInstance)) {\n      keepAlive = new KeepAliveSubscriptionConnectionListener(keepAliveInterval);\n      listeners.add(keepAlive);\n    }\n    commandProvider =\n        new ApolloCommandProvider(\n            new GraphQLSubscriptionMapper(objectMapper),\n            invocationInputFactory,\n            graphQLInvoker,\n            listeners);\n  }\n\n  @Override\n  public Consumer<String> createConsumer(SubscriptionSession session) {\n    return new ApolloSubscriptionConsumer(session, objectMapper, commandProvider);\n  }\n\n  @Override\n  public void shutdown() {\n    if (keepAlive != null) {\n      keepAlive.shutdown();\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/ApolloSubscriptionSession.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.DefaultSubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class ApolloSubscriptionSession extends DefaultSubscriptionSession {\n\n  public ApolloSubscriptionSession(GraphQLSubscriptionMapper mapper) {\n    super(mapper);\n  }\n\n  @Override\n  public void sendDataMessage(String id, Object payload) {\n    sendMessage(new OperationMessage(Type.GQL_DATA, id, payload));\n  }\n\n  @Override\n  public void sendErrorMessage(String id, Object payload) {\n    sendMessage(new OperationMessage(Type.GQL_ERROR, id, payload));\n  }\n\n  @Override\n  public void sendCompleteMessage(String id) {\n    sendMessage(new OperationMessage(Type.GQL_COMPLETE, id, null));\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/KeepAliveSubscriptionConnectionListener.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.time.Duration;\n\npublic class KeepAliveSubscriptionConnectionListener\n    implements ApolloSubscriptionConnectionListener {\n\n  protected final ApolloSubscriptionKeepAliveRunner keepAliveRunner;\n\n  public KeepAliveSubscriptionConnectionListener() {\n    this(Duration.ofSeconds(15));\n  }\n\n  public KeepAliveSubscriptionConnectionListener(Duration keepAliveInterval) {\n    keepAliveRunner = new ApolloSubscriptionKeepAliveRunner(keepAliveInterval);\n  }\n\n  @Override\n  public void onConnect(SubscriptionSession session, OperationMessage message) {\n    keepAliveRunner.keepAlive(session);\n  }\n\n  @Override\n  public void onStart(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  @Override\n  public void onStop(SubscriptionSession session, OperationMessage message) {\n    // do nothing\n  }\n\n  @Override\n  public void onTerminate(SubscriptionSession session, OperationMessage message) {\n    keepAliveRunner.abort(session);\n  }\n\n  @Override\n  public void shutdown() {\n    keepAliveRunner.shutdown();\n  }\n\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/OperationMessage.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonValue;\nimport java.util.HashMap;\nimport java.util.Map;\nimport lombok.AllArgsConstructor;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor\n@AllArgsConstructor\n@JsonInclude(JsonInclude.Include.NON_NULL)\npublic class OperationMessage {\n\n  private Type type;\n  private String id;\n  private Object payload;\n\n  public static OperationMessage newKeepAliveMessage() {\n    return new OperationMessage(Type.GQL_CONNECTION_KEEP_ALIVE, null, null);\n  }\n\n  public Type getType() {\n    return type;\n  }\n\n  public String getId() {\n    return id;\n  }\n\n  public Object getPayload() {\n    return payload;\n  }\n\n  public enum Type {\n\n    // Server Messages\n    GQL_CONNECTION_ACK(\"connection_ack\"),\n    GQL_CONNECTION_ERROR(\"connection_error\"),\n    GQL_CONNECTION_KEEP_ALIVE(\"ka\"),\n    GQL_DATA(\"data\"),\n    GQL_ERROR(\"error\"),\n    GQL_COMPLETE(\"complete\"),\n\n    // Client Messages\n    GQL_CONNECTION_INIT(\"connection_init\"),\n    GQL_CONNECTION_TERMINATE(\"connection_terminate\"),\n    GQL_START(\"start\"),\n    GQL_STOP(\"stop\");\n\n    private static final Map<String, Type> reverseLookup = new HashMap<>();\n\n    static {\n      for (Type type : Type.values()) {\n        reverseLookup.put(type.getValue(), type);\n      }\n    }\n\n    private final String value;\n\n    Type(String value) {\n      this.value = value;\n    }\n\n    @JsonCreator\n    public static Type findType(String value) {\n      return reverseLookup.get(value);\n    }\n\n    @JsonValue\n    public String getValue() {\n      return value;\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/SubscriptionCommand.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\n\ninterface SubscriptionCommand {\n\n  void apply(SubscriptionSession session, OperationMessage message);\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/SubscriptionConnectionInitCommand.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type;\nimport java.util.Collection;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\nclass SubscriptionConnectionInitCommand implements SubscriptionCommand {\n\n  private final Collection<ApolloSubscriptionConnectionListener> connectionListeners;\n\n  @Override\n  public void apply(SubscriptionSession session, OperationMessage message) {\n    log.debug(\"Apollo subscription connection init: {}\", session);\n    try {\n      connectionListeners.forEach(it -> it.onConnect(session, message));\n      session.sendMessage(new OperationMessage(Type.GQL_CONNECTION_ACK, message.getId(), null));\n    } catch (Exception t) {\n      log.error(\"Cannot initialize subscription command '{}'\", message, t);\n      session.sendMessage(\n          new OperationMessage(Type.GQL_CONNECTION_ERROR, message.getId(), t.getMessage()));\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/SubscriptionConnectionTerminateCommand.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport static graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type.GQL_CONNECTION_TERMINATE;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.Collection;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\nclass SubscriptionConnectionTerminateCommand implements SubscriptionCommand {\n\n  private final Collection<ApolloSubscriptionConnectionListener> connectionListeners;\n\n  @Override\n  public void apply(SubscriptionSession session, OperationMessage message) {\n    connectionListeners.forEach(it -> it.onTerminate(session, message));\n    session.close(\"client requested \" + GQL_CONNECTION_TERMINATE.getValue());\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/SubscriptionStartCommand.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport static graphql.kickstart.execution.subscriptions.apollo.OperationMessage.Type.GQL_ERROR;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.Collection;\nimport java.util.Objects;\nimport java.util.concurrent.CompletableFuture;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\nclass SubscriptionStartCommand implements SubscriptionCommand {\n\n  private final GraphQLSubscriptionMapper mapper;\n  private final GraphQLSubscriptionInvocationInputFactory invocationInputFactory;\n  private final GraphQLInvoker graphQLInvoker;\n  private final Collection<ApolloSubscriptionConnectionListener> connectionListeners;\n\n  @Override\n  public void apply(SubscriptionSession session, OperationMessage message) {\n    log.debug(\"Apollo subscription start: {} --> {}\", session, message.getPayload());\n    connectionListeners.forEach(it -> it.onStart(session, message));\n    CompletableFuture<ExecutionResult> executionResult =\n        executeAsync(message.getPayload(), session);\n    executionResult.thenAccept(result -> handleSubscriptionStart(session, message.getId(), result));\n  }\n\n  private CompletableFuture<ExecutionResult> executeAsync(\n      Object payload, SubscriptionSession session) {\n    Objects.requireNonNull(payload, \"Payload is required\");\n    GraphQLRequest graphQLRequest = mapper.convertGraphQLRequest(payload);\n\n    GraphQLSingleInvocationInput invocationInput =\n        invocationInputFactory.create(graphQLRequest, session);\n    return graphQLInvoker.executeAsync(invocationInput);\n  }\n\n  private void handleSubscriptionStart(\n      SubscriptionSession session, String id, ExecutionResult executionResult) {\n    ExecutionResult sanitizedExecutionResult = mapper.sanitizeErrors(executionResult);\n    if (mapper.hasNoErrors(sanitizedExecutionResult)) {\n      session.subscribe(id, sanitizedExecutionResult.getData());\n    } else {\n      Object payload = mapper.convertSanitizedExecutionResult(sanitizedExecutionResult);\n      session.sendMessage(new OperationMessage(GQL_ERROR, id, payload));\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-kickstart/src/main/java/graphql/kickstart/execution/subscriptions/apollo/SubscriptionStopCommand.java",
    "content": "package graphql.kickstart.execution.subscriptions.apollo;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.Collection;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass SubscriptionStopCommand implements SubscriptionCommand {\n\n  private final Collection<ApolloSubscriptionConnectionListener> connectionListeners;\n\n  @Override\n  public void apply(SubscriptionSession session, OperationMessage message) {\n    connectionListeners.forEach(it -> it.onStop(session, message));\n    session.unsubscribe(message.getId());\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/bnd.bnd",
    "content": "Export-Package: graphql.kickstart.servlet.*\nImport-Package: !lombok,*\nRequire-Capability: osgi.extender;\n  filter:=\"(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))\"\n"
  },
  {
    "path": "graphql-java-servlet/build.gradle",
    "content": "buildscript {\n    repositories {\n        mavenCentral()\n    }\n}\n\napply plugin: 'groovy'\napply plugin: 'java-library-distribution'\napply plugin: 'biz.aQute.bnd.builder'\n\njar {\n    bndfile = 'bnd.bnd'\n}\n\ndependencies {\n    api(project(':graphql-java-kickstart'))\n\n    // Servlet\n    compileOnly \"jakarta.servlet:jakarta.servlet-api:6.1.0\"\n    compileOnly \"jakarta.websocket:jakarta.websocket-api:2.2.0\"\n    compileOnly \"jakarta.websocket:jakarta.websocket-client-api:2.2.0\"\n    implementation \"org.slf4j:slf4j-api:$LIB_SLF4J_VER\"\n\n    // OSGi\n    compileOnly 'org.osgi:org.osgi.core:6.0.0'\n    compileOnly 'org.osgi:org.osgi.service.cm:1.6.1'\n    compileOnly 'org.osgi:org.osgi.service.component:1.5.1'\n    compileOnly 'org.osgi:org.osgi.service.component.annotations:1.5.1'\n    compileOnly 'org.osgi:org.osgi.service.metatype.annotations:1.4.1'\n    compileOnly 'org.osgi:org.osgi.annotation:6.0.0'\n\n    testImplementation 'io.github.graphql-java:graphql-java-annotations:9.1'\n\n    // Unit testing\n    testImplementation \"org.apache.groovy:groovy-all:4.0.23\"\n    testImplementation \"org.spockframework:spock-core:2.3-groovy-4.0\"\n    testRuntimeOnly \"net.bytebuddy:byte-buddy:1.15.2\"\n    testRuntimeOnly \"org.objenesis:objenesis:3.4\"\n    testImplementation \"org.slf4j:slf4j-simple:$LIB_SLF4J_VER\"\n    testImplementation \"org.springframework:spring-test:6.1.13\"\n    testRuntimeOnly \"org.springframework:spring-web:6.1.13\"\n    testImplementation 'com.google.guava:guava:33.3.1-jre'\n    testImplementation \"jakarta.servlet:jakarta.servlet-api:6.1.0\"\n    testImplementation \"jakarta.websocket:jakarta.websocket-api:2.2.0\"\n    testImplementation \"jakarta.websocket:jakarta.websocket-client-api:2.2.0\"\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AbstractGraphQLHttpServlet.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static graphql.kickstart.execution.GraphQLRequest.createQueryOnlyRequest;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport graphql.kickstart.servlet.core.GraphQLMBean;\nimport graphql.kickstart.servlet.core.GraphQLServletListener;\nimport graphql.schema.GraphQLFieldDefinition;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\n\n/** @author Andrew Potter */\n@Slf4j\npublic abstract class AbstractGraphQLHttpServlet extends HttpServlet\n    implements Servlet, GraphQLMBean {\n\n  protected abstract GraphQLConfiguration getConfiguration();\n\n  public void addListener(GraphQLServletListener servletListener) {\n    getConfiguration().add(servletListener);\n  }\n\n  public void removeListener(GraphQLServletListener servletListener) {\n    getConfiguration().remove(servletListener);\n  }\n\n  @Override\n  public String[] getQueries() {\n    return getConfiguration()\n        .getInvocationInputFactory()\n        .getSchemaProvider()\n        .getSchema()\n        .getQueryType()\n        .getFieldDefinitions()\n        .stream()\n        .map(GraphQLFieldDefinition::getName)\n        .toArray(String[]::new);\n  }\n\n  @Override\n  public String[] getMutations() {\n    return getConfiguration()\n        .getInvocationInputFactory()\n        .getSchemaProvider()\n        .getSchema()\n        .getMutationType()\n        .getFieldDefinitions()\n        .stream()\n        .map(GraphQLFieldDefinition::getName)\n        .toArray(String[]::new);\n  }\n\n  @Override\n  public String executeQuery(String query) {\n    try {\n      GraphQLRequest graphQLRequest = createQueryOnlyRequest(query);\n      GraphQLSingleInvocationInput invocationInput =\n          getConfiguration().getInvocationInputFactory().create(graphQLRequest);\n      ExecutionResult result =\n          getConfiguration().getGraphQLInvoker().query(invocationInput).getResult();\n      return getConfiguration().getObjectMapper().serializeResultAsJson(result);\n    } catch (Exception e) {\n      return e.getMessage();\n    }\n  }\n\n  @Override\n  protected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n    doRequest(req, resp);\n  }\n\n  @Override\n  protected void doPost(HttpServletRequest req, HttpServletResponse resp) {\n    doRequest(req, resp);\n  }\n\n  private void doRequest(HttpServletRequest request, HttpServletResponse response) {\n    try {\n      getConfiguration().getHttpRequestHandler().handle(request, response);\n    } catch (Exception t) {\n      log.error(\"Error executing GraphQL request!\", t);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AbstractGraphQLInvocationInputParser.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nabstract class AbstractGraphQLInvocationInputParser implements GraphQLInvocationInputParser {\n\n  final GraphQLInvocationInputFactory invocationInputFactory;\n  final GraphQLObjectMapper graphQLObjectMapper;\n  final ContextSetting contextSetting;\n\n  boolean isSingleQuery(String query) {\n    return query != null && !query.trim().isEmpty() && !query.trim().startsWith(\"[\");\n  }\n\n  boolean isBatchedQuery(String query) {\n    return query != null && query.trim().startsWith(\"[\");\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskDecorator.java",
    "content": "package graphql.kickstart.servlet;\n\npublic interface AsyncTaskDecorator {\n\n  Runnable decorate(Runnable runnable);\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTaskExecutor.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.util.concurrent.Executor;\nimport lombok.NonNull;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass AsyncTaskExecutor implements Executor {\n\n  private final Executor executor;\n  private final AsyncTaskDecorator taskDecorator;\n\n  @Override\n  public void execute(@NonNull Runnable command) {\n    if (taskDecorator != null) {\n      Runnable decorated = taskDecorator.decorate(command);\n      executor.execute(decorated);\n    } else {\n      executor.execute(command);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/AsyncTimeoutListener.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.io.IOException;\nimport jakarta.servlet.AsyncEvent;\nimport jakarta.servlet.AsyncListener;\n\ninterface AsyncTimeoutListener extends AsyncListener {\n\n  default void onComplete(AsyncEvent event) throws IOException {}\n\n  default void onError(AsyncEvent event) throws IOException {}\n\n  default void onStartAsync(AsyncEvent event) throws IOException {}\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/BatchedQueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\nclass BatchedQueryResponseWriter implements QueryResponseWriter {\n  private final List<ExecutionResult> results;\n  private final GraphQLObjectMapper graphQLObjectMapper;\n\n  @Override\n  public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    response.setCharacterEncoding(StandardCharsets.UTF_8.name());\n    response.setContentType(HttpRequestHandler.APPLICATION_JSON_UTF8);\n    response.setStatus(HttpRequestHandler.STATUS_OK);\n\n    // Use direct serialization to byte arrays and avoid any string concatenation to save multiple\n    // GiB of memory allocation during large response processing.\n    List<byte[]> serializedResults = new ArrayList<>(2 * results.size() + 1);\n\n    if (!results.isEmpty()) {\n      serializedResults.add(\"[\".getBytes(StandardCharsets.UTF_8));\n    } else {\n      serializedResults.add(\"[]\".getBytes(StandardCharsets.UTF_8));\n    }\n    long totalLength = serializedResults.get(0).length;\n\n    // '[', ',' and ']' are all 1 byte in UTF-8.\n    for (int i = 0; i < results.size(); i++) {\n      byte[] currentResult = graphQLObjectMapper.serializeResultAsBytes(results.get(i));\n      serializedResults.add(currentResult);\n\n      if (i != results.size() - 1) {\n        serializedResults.add(\",\".getBytes(StandardCharsets.UTF_8));\n      } else {\n        serializedResults.add(\"]\".getBytes(StandardCharsets.UTF_8));\n      }\n      totalLength += currentResult.length + 1; // result.length + ',' or ']'\n    }\n\n    if (totalLength > Integer.MAX_VALUE) {\n      throw new IllegalStateException(\n          \"Response size exceed 2GiB. Query will fail. Seen size: \" + totalLength);\n    }\n    response.setContentLength((int) totalLength);\n\n    for (byte[] result : serializedResults) {\n      response.getOutputStream().write(result);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/ConfiguredGraphQLHttpServlet.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.util.Objects;\n\nclass ConfiguredGraphQLHttpServlet extends GraphQLHttpServlet {\n\n  private final GraphQLConfiguration configuration;\n\n  ConfiguredGraphQLHttpServlet(GraphQLConfiguration configuration) {\n    this.configuration = Objects.requireNonNull(configuration, \"configuration is required\");\n  }\n\n  @Override\n  protected GraphQLConfiguration getConfiguration() {\n    return configuration;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/ErrorQueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.io.IOException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass ErrorQueryResponseWriter implements QueryResponseWriter {\n\n  private final int statusCode;\n  private final String message;\n\n  @Override\n  public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    response.sendError(statusCode, message);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/ExecutionResultSubscriber.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jakarta.servlet.AsyncContext;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\nclass ExecutionResultSubscriber implements Subscriber<ExecutionResult> {\n\n  private final AtomicReference<Subscription> subscriptionRef;\n  private final AsyncContext asyncContext;\n  private final GraphQLObjectMapper graphQLObjectMapper;\n  private final CountDownLatch completedLatch = new CountDownLatch(1);\n\n  ExecutionResultSubscriber(\n      AtomicReference<Subscription> subscriptionRef,\n      AsyncContext asyncContext,\n      GraphQLObjectMapper graphQLObjectMapper) {\n    this.subscriptionRef = subscriptionRef;\n    this.asyncContext = asyncContext;\n    this.graphQLObjectMapper = graphQLObjectMapper;\n  }\n\n  @Override\n  public void onSubscribe(Subscription subscription) {\n    subscriptionRef.set(subscription);\n    subscriptionRef.get().request(1);\n  }\n\n  @Override\n  public void onNext(ExecutionResult executionResult) {\n    try {\n      Writer writer = asyncContext.getResponse().getWriter();\n      writer.write(\"data: \");\n      writer.write(graphQLObjectMapper.serializeResultAsJson(executionResult));\n      writer.write(\"\\n\\n\");\n      writer.flush();\n      subscriptionRef.get().request(1);\n    } catch (IOException ignored) {\n      // ignore\n    }\n  }\n\n  @Override\n  public void onError(Throwable t) {\n    asyncContext.complete();\n    completedLatch.countDown();\n  }\n\n  @Override\n  public void onComplete() {\n    asyncContext.complete();\n    completedLatch.countDown();\n  }\n\n  void await() throws InterruptedException {\n    completedLatch.await();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLConfiguration.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLQueryInvoker;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.servlet.cache.CachingHttpRequestInvoker;\nimport graphql.kickstart.servlet.cache.GraphQLResponseCacheManager;\nimport graphql.kickstart.servlet.config.DefaultGraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.config.GraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.core.GraphQLServletListener;\nimport graphql.kickstart.servlet.core.GraphQLServletRootObjectBuilder;\nimport graphql.kickstart.servlet.input.BatchInputPreProcessor;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport graphql.kickstart.servlet.input.NoOpBatchInputPreProcessor;\nimport graphql.schema.GraphQLSchema;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\nimport lombok.Getter;\n\npublic class GraphQLConfiguration {\n\n  private final GraphQLInvocationInputFactory invocationInputFactory;\n  private final Supplier<BatchInputPreProcessor> batchInputPreProcessor;\n  private final GraphQLInvoker graphQLInvoker;\n  private final GraphQLObjectMapper objectMapper;\n  private final List<GraphQLServletListener> listeners;\n  private final long subscriptionTimeout;\n  @Getter private final long asyncTimeout;\n  private final ContextSetting contextSetting;\n  private final GraphQLResponseCacheManager responseCacheManager;\n  @Getter private final Executor asyncExecutor;\n  private HttpRequestHandler requestHandler;\n\n  private GraphQLConfiguration(\n      GraphQLInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      GraphQLQueryInvoker queryInvoker,\n      GraphQLObjectMapper objectMapper,\n      List<GraphQLServletListener> listeners,\n      long subscriptionTimeout,\n      long asyncTimeout,\n      ContextSetting contextSetting,\n      Supplier<BatchInputPreProcessor> batchInputPreProcessor,\n      GraphQLResponseCacheManager responseCacheManager,\n      Executor asyncExecutor) {\n    this.invocationInputFactory = invocationInputFactory;\n    this.asyncExecutor = asyncExecutor;\n    this.graphQLInvoker = graphQLInvoker != null ? graphQLInvoker : queryInvoker.toGraphQLInvoker();\n    this.objectMapper = objectMapper;\n    this.listeners = listeners;\n    this.subscriptionTimeout = subscriptionTimeout;\n    this.asyncTimeout = asyncTimeout;\n    this.contextSetting = contextSetting;\n    this.batchInputPreProcessor = batchInputPreProcessor;\n    this.responseCacheManager = responseCacheManager;\n  }\n\n  public static GraphQLConfiguration.Builder with(GraphQLSchema schema) {\n    return with(new DefaultGraphQLSchemaServletProvider(schema));\n  }\n\n  public static GraphQLConfiguration.Builder with(GraphQLSchemaServletProvider schemaProvider) {\n    return new Builder(GraphQLInvocationInputFactory.newBuilder(schemaProvider));\n  }\n\n  public static GraphQLConfiguration.Builder with(\n      GraphQLInvocationInputFactory invocationInputFactory) {\n    return new Builder(invocationInputFactory);\n  }\n\n  public GraphQLInvocationInputFactory getInvocationInputFactory() {\n    return invocationInputFactory;\n  }\n\n  public GraphQLInvoker getGraphQLInvoker() {\n    return graphQLInvoker;\n  }\n\n  public GraphQLObjectMapper getObjectMapper() {\n    return objectMapper;\n  }\n\n  public List<GraphQLServletListener> getListeners() {\n    return new ArrayList<>(listeners);\n  }\n\n  public void add(GraphQLServletListener listener) {\n    listeners.add(listener);\n  }\n\n  public boolean remove(GraphQLServletListener listener) {\n    return listeners.remove(listener);\n  }\n\n  public long getSubscriptionTimeout() {\n    return subscriptionTimeout;\n  }\n\n  public ContextSetting getContextSetting() {\n    return contextSetting;\n  }\n\n  public BatchInputPreProcessor getBatchInputPreProcessor() {\n    return batchInputPreProcessor.get();\n  }\n\n  public GraphQLResponseCacheManager getResponseCacheManager() {\n    return responseCacheManager;\n  }\n\n  public HttpRequestHandler getHttpRequestHandler() {\n    if (requestHandler == null) {\n      requestHandler = createHttpRequestHandler();\n    }\n    return requestHandler;\n  }\n\n  private HttpRequestHandler createHttpRequestHandler() {\n    if (responseCacheManager == null) {\n      return new HttpRequestHandlerImpl(this);\n    } else {\n      return new HttpRequestHandlerImpl(this, new CachingHttpRequestInvoker(this));\n    }\n  }\n\n  public static class Builder {\n\n    private GraphQLInvocationInputFactory.Builder invocationInputFactoryBuilder;\n    private GraphQLInvocationInputFactory invocationInputFactory;\n    private GraphQLInvoker graphQLInvoker;\n    private GraphQLQueryInvoker queryInvoker = GraphQLQueryInvoker.newBuilder().build();\n    private GraphQLObjectMapper objectMapper = GraphQLObjectMapper.newBuilder().build();\n    private List<GraphQLServletListener> listeners = new ArrayList<>();\n    private long subscriptionTimeout = 0;\n    private long asyncTimeout = 30000;\n    private ContextSetting contextSetting = ContextSetting.PER_QUERY;\n    private Supplier<BatchInputPreProcessor> batchInputPreProcessorSupplier =\n        NoOpBatchInputPreProcessor::new;\n    private GraphQLResponseCacheManager responseCacheManager;\n    private int asyncCorePoolSize = 10;\n    private int asyncMaxPoolSize = 200;\n    private Executor asyncExecutor;\n    private AsyncTaskDecorator asyncTaskDecorator;\n\n    private Builder(GraphQLInvocationInputFactory.Builder invocationInputFactoryBuilder) {\n      this.invocationInputFactoryBuilder = invocationInputFactoryBuilder;\n    }\n\n    private Builder(GraphQLInvocationInputFactory invocationInputFactory) {\n      this.invocationInputFactory = invocationInputFactory;\n    }\n\n    public Builder with(GraphQLInvoker graphQLInvoker) {\n      this.graphQLInvoker = graphQLInvoker;\n      return this;\n    }\n\n    public Builder with(GraphQLQueryInvoker queryInvoker) {\n      if (queryInvoker != null) {\n        this.queryInvoker = queryInvoker;\n      }\n      return this;\n    }\n\n    public Builder with(GraphQLObjectMapper objectMapper) {\n      if (objectMapper != null) {\n        this.objectMapper = objectMapper;\n      }\n      return this;\n    }\n\n    public Builder with(List<GraphQLServletListener> listeners) {\n      if (listeners != null) {\n        this.listeners = listeners;\n      }\n      return this;\n    }\n\n    public Builder with(GraphQLServletContextBuilder contextBuilder) {\n      this.invocationInputFactoryBuilder.withGraphQLContextBuilder(contextBuilder);\n      return this;\n    }\n\n    public Builder with(GraphQLServletRootObjectBuilder rootObjectBuilder) {\n      this.invocationInputFactoryBuilder.withGraphQLRootObjectBuilder(rootObjectBuilder);\n      return this;\n    }\n\n    public Builder with(long subscriptionTimeout) {\n      this.subscriptionTimeout = subscriptionTimeout;\n      return this;\n    }\n\n    public Builder asyncTimeout(long asyncTimeout) {\n      this.asyncTimeout = asyncTimeout;\n      return this;\n    }\n\n    public Builder with(Executor asyncExecutor) {\n      this.asyncExecutor = asyncExecutor;\n      return this;\n    }\n\n    public Builder asyncCorePoolSize(int asyncCorePoolSize) {\n      this.asyncCorePoolSize = asyncCorePoolSize;\n      return this;\n    }\n\n    public Builder asyncMaxPoolSize(int asyncMaxPoolSize) {\n      this.asyncMaxPoolSize = asyncMaxPoolSize;\n      return this;\n    }\n\n    public Builder with(ContextSetting contextSetting) {\n      if (contextSetting != null) {\n        this.contextSetting = contextSetting;\n      }\n      return this;\n    }\n\n    public Builder with(BatchInputPreProcessor batchInputPreProcessor) {\n      if (batchInputPreProcessor != null) {\n        this.batchInputPreProcessorSupplier = () -> batchInputPreProcessor;\n      }\n      return this;\n    }\n\n    public Builder with(Supplier<BatchInputPreProcessor> batchInputPreProcessor) {\n      if (batchInputPreProcessor != null) {\n        this.batchInputPreProcessorSupplier = batchInputPreProcessor;\n      }\n      return this;\n    }\n\n    public Builder with(GraphQLResponseCacheManager responseCache) {\n      this.responseCacheManager = responseCache;\n      return this;\n    }\n\n    public Builder with(AsyncTaskDecorator asyncTaskDecorator) {\n      this.asyncTaskDecorator = asyncTaskDecorator;\n      return this;\n    }\n\n    private Executor getAsyncExecutor() {\n      if (asyncExecutor != null) {\n        return asyncExecutor;\n      }\n      return new ThreadPoolExecutor(\n          asyncCorePoolSize,\n          asyncMaxPoolSize,\n          60,\n          TimeUnit.SECONDS,\n          new LinkedBlockingQueue<>(Integer.MAX_VALUE));\n    }\n\n    private Executor getAsyncTaskExecutor() {\n      return new AsyncTaskExecutor(getAsyncExecutor(), asyncTaskDecorator);\n    }\n\n    public GraphQLConfiguration build() {\n      return new GraphQLConfiguration(\n          this.invocationInputFactory != null\n              ? this.invocationInputFactory\n              : invocationInputFactoryBuilder.build(),\n          graphQLInvoker,\n          queryInvoker,\n          objectMapper,\n          listeners,\n          subscriptionTimeout,\n          asyncTimeout,\n          contextSetting,\n          batchInputPreProcessorSupplier,\n          responseCacheManager,\n          getAsyncTaskExecutor());\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLGetInvocationInputParser.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\nclass GraphQLGetInvocationInputParser extends AbstractGraphQLInvocationInputParser {\n\n  GraphQLGetInvocationInputParser(\n      GraphQLInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper,\n      ContextSetting contextSetting) {\n    super(invocationInputFactory, graphQLObjectMapper, contextSetting);\n  }\n\n  public GraphQLInvocationInput getGraphQLInvocationInput(\n      HttpServletRequest request, HttpServletResponse response) throws IOException {\n    if (isIntrospectionQuery(request)) {\n      GraphQLRequest graphqlRequest = GraphQLRequest.createIntrospectionRequest();\n      return invocationInputFactory.create(graphqlRequest, request, response);\n    }\n\n    String query = request.getParameter(\"query\");\n    if (query == null) {\n      throw new GraphQLException(\"Query parameter not found in GET request\");\n    }\n\n    if (isSingleQuery(query)) {\n      Map<String, Object> variables = getVariables(request);\n      Map<String, Object> extensions = getExtensions(request);\n      String operationName = request.getParameter(\"operationName\");\n      GraphQLRequest graphqlRequest =\n          new GraphQLRequest(query, variables, extensions, operationName);\n      return invocationInputFactory.createReadOnly(graphqlRequest, request, response);\n    }\n\n    List<GraphQLRequest> graphqlRequests = graphQLObjectMapper.readBatchedGraphQLRequest(query);\n    return invocationInputFactory.createReadOnly(\n        contextSetting, graphqlRequests, request, response);\n  }\n\n  private boolean isIntrospectionQuery(HttpServletRequest request) {\n    String path =\n        Optional.ofNullable(request.getPathInfo()).orElseGet(request::getServletPath).toLowerCase();\n    return path.contentEquals(\"/schema.json\");\n  }\n\n  private Map<String, Object> getVariables(HttpServletRequest request) {\n    return Optional.ofNullable(request.getParameter(\"variables\"))\n        .map(graphQLObjectMapper::deserializeVariables)\n        .map(HashMap::new)\n        .orElseGet(HashMap::new);\n  }\n\n  private Map<String, Object> getExtensions(HttpServletRequest request) {\n    return Optional.ofNullable(request.getParameter(\"extensions\"))\n        .map(graphQLObjectMapper::deserializeExtensions)\n        .map(HashMap::new)\n        .orElseGet(HashMap::new);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLHttpServlet.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.schema.GraphQLSchema;\n\n/** @author Michiel Oliemans */\npublic abstract class GraphQLHttpServlet extends AbstractGraphQLHttpServlet {\n\n  public static GraphQLHttpServlet with(GraphQLSchema schema) {\n    return new ConfiguredGraphQLHttpServlet(GraphQLConfiguration.with(schema).build());\n  }\n\n  public static GraphQLHttpServlet with(GraphQLConfiguration configuration) {\n    return new ConfiguredGraphQLHttpServlet(configuration);\n  }\n\n  @Override\n  protected abstract GraphQLConfiguration getConfiguration();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLInvocationInputParser.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport java.io.IOException;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\ninterface GraphQLInvocationInputParser {\n\n  static GraphQLInvocationInputParser create(\n      HttpServletRequest request,\n      GraphQLInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper,\n      ContextSetting contextSetting)\n      throws IOException {\n    if (\"GET\".equalsIgnoreCase(request.getMethod())) {\n      return new GraphQLGetInvocationInputParser(\n          invocationInputFactory, graphQLObjectMapper, contextSetting);\n    }\n\n    try {\n      boolean notMultipartRequest =\n          request.getContentType() == null\n              || !request.getContentType().startsWith(\"multipart/form-data\")\n              || request.getParts().isEmpty();\n      if (notMultipartRequest) {\n        return new GraphQLPostInvocationInputParser(\n            invocationInputFactory, graphQLObjectMapper, contextSetting);\n      }\n      return new GraphQLMultipartInvocationInputParser(\n          invocationInputFactory, graphQLObjectMapper, contextSetting);\n    } catch (ServletException e) {\n      throw new IOException(\"Cannot get parts of request\", e);\n    }\n  }\n\n  GraphQLInvocationInput getGraphQLInvocationInput(\n      HttpServletRequest request, HttpServletResponse response) throws IOException;\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLMultipartInvocationInputParser.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static java.util.stream.Collectors.joining;\n\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.core.internal.VariableMapper;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.Part;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\nclass GraphQLMultipartInvocationInputParser extends AbstractGraphQLInvocationInputParser {\n\n  private static final String[] MULTIPART_KEYS = new String[] {\"operations\", \"graphql\", \"query\"};\n\n  GraphQLMultipartInvocationInputParser(\n      GraphQLInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper,\n      ContextSetting contextSetting) {\n    super(invocationInputFactory, graphQLObjectMapper, contextSetting);\n  }\n\n  @Override\n  public GraphQLInvocationInput getGraphQLInvocationInput(\n      HttpServletRequest request, HttpServletResponse response) throws IOException {\n    try {\n      final Map<String, List<Part>> parts =\n          request.getParts().stream().collect(Collectors.groupingBy(Part::getName));\n\n      for (String key : MULTIPART_KEYS) {\n        // Check to see if there is a part under the key we seek\n        if (!parts.containsKey(key)) {\n          continue;\n        }\n\n        final Optional<Part> queryItem = findPart(parts);\n        if (!queryItem.isPresent()) {\n          log.info(\"Bad POST multipart request: no part named {}\", Arrays.toString(MULTIPART_KEYS));\n          throw new GraphQLException(\n              \"Bad POST multipart request: no part named \" + Arrays.toString(MULTIPART_KEYS));\n        }\n\n        return getGraphQLInvocationInput(request, response, parts, key, queryItem.get());\n      }\n\n      log.info(\"Bad POST multipart request: no part named {}\", Arrays.toString(MULTIPART_KEYS));\n      throw new GraphQLException(\n          \"Bad POST multipart request: no part named \" + Arrays.toString(MULTIPART_KEYS));\n    } catch (ServletException e) {\n      throw new IOException(\"Cannot get parts from request\", e);\n    }\n  }\n\n  private GraphQLInvocationInput getGraphQLInvocationInput(\n      HttpServletRequest request,\n      HttpServletResponse response,\n      Map<String, List<Part>> parts,\n      String key,\n      Part queryItem)\n      throws IOException {\n    InputStream inputStream = queryItem.getInputStream();\n\n    final Optional<Map<String, List<String>>> variablesMap =\n        getPart(parts, \"map\")\n            .map(\n                part -> {\n                  try (InputStream is = part.getInputStream()) {\n                    return graphQLObjectMapper.deserializeMultipartMap(is);\n                  } catch (IOException e) {\n                    throw new PartIOException(\"Unable to read input stream from part\", e);\n                  }\n                });\n\n    String query = read(inputStream, request.getCharacterEncoding());\n    if (\"query\".equals(key) && isSingleQuery(query)) {\n      GraphQLRequest graphqlRequest =\n          buildRequestFromQuery(query, graphQLObjectMapper, parts, request.getCharacterEncoding());\n      variablesMap.ifPresent(m -> mapMultipartVariables(graphqlRequest, m, parts));\n      return invocationInputFactory.create(graphqlRequest, request, response);\n    } else if (isSingleQuery(query)) {\n      GraphQLRequest graphqlRequest = graphQLObjectMapper.readGraphQLRequest(query);\n      variablesMap.ifPresent(m -> mapMultipartVariables(graphqlRequest, m, parts));\n      return invocationInputFactory.create(graphqlRequest, request, response);\n    } else {\n      List<GraphQLRequest> graphqlRequests = graphQLObjectMapper.readBatchedGraphQLRequest(query);\n      variablesMap.ifPresent(\n          map -> graphqlRequests.forEach(r -> mapMultipartVariables(r, map, parts)));\n      return invocationInputFactory.create(contextSetting, graphqlRequests, request, response);\n    }\n  }\n\n  private Optional<Part> findPart(Map<String, List<Part>> parts) {\n    return Arrays.stream(MULTIPART_KEYS)\n        .filter(parts::containsKey)\n        .map(key -> getPart(parts, key))\n        .findFirst()\n        .filter(Optional::isPresent)\n        .map(Optional::get);\n  }\n\n  private Optional<Part> getPart(Map<String, List<Part>> parts, String name) {\n    return Optional.ofNullable(parts.get(name))\n        .filter(list -> !list.isEmpty())\n        .map(list -> list.get(0));\n  }\n\n  private void mapMultipartVariables(\n      GraphQLRequest request,\n      Map<String, List<String>> variablesMap,\n      Map<String, List<Part>> fileItems) {\n    Map<String, Object> variables = request.getVariables();\n\n    variablesMap.forEach(\n        (partName, objectPaths) -> {\n          Part part =\n              getPart(fileItems, partName)\n                  .orElseThrow(\n                      () ->\n                          new RuntimeException(\n                              \"unable to find part name \"\n                                  + partName\n                                  + \" as referenced in the variables map\"));\n\n          objectPaths.forEach(\n              objectPath -> VariableMapper.mapVariable(objectPath, variables, part));\n        });\n  }\n\n  private GraphQLRequest buildRequestFromQuery(\n      String query,\n      GraphQLObjectMapper graphQLObjectMapper,\n      Map<String, List<Part>> parts,\n      String charset)\n      throws IOException {\n    Map<String, Object> variables = null;\n    final Optional<Part> variablesItem = getPart(parts, \"variables\");\n    if (variablesItem.isPresent()) {\n      variables =\n          graphQLObjectMapper.deserializeVariables(\n              read(variablesItem.get().getInputStream(), charset));\n    }\n\n    Map<String, Object> extensions = null;\n    final Optional<Part> extensionsItem = getPart(parts, \"extensions\");\n    if (extensionsItem.isPresent()) {\n      extensions =\n          graphQLObjectMapper.deserializeExtensions(\n              read(extensionsItem.get().getInputStream(), charset));\n    }\n\n    String operationName = null;\n    final Optional<Part> operationNameItem = getPart(parts, \"operationName\");\n    if (operationNameItem.isPresent()) {\n      operationName = read(operationNameItem.get().getInputStream(), charset).trim();\n    }\n\n    return new GraphQLRequest(query, variables, extensions, operationName);\n  }\n\n  private String read(InputStream inputStream, String charset) throws IOException {\n    try (InputStreamReader streamReader = new InputStreamReader(inputStream, charset);\n        BufferedReader reader = new BufferedReader(streamReader)) {\n      return reader.lines().collect(joining());\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLPostInvocationInputParser.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static java.util.stream.Collectors.joining;\n\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport java.io.IOException;\nimport java.util.List;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nclass GraphQLPostInvocationInputParser extends AbstractGraphQLInvocationInputParser {\n\n  private static final String APPLICATION_GRAPHQL = \"application/graphql\";\n\n  GraphQLPostInvocationInputParser(\n      GraphQLInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper,\n      ContextSetting contextSetting) {\n    super(invocationInputFactory, graphQLObjectMapper, contextSetting);\n  }\n\n  public GraphQLInvocationInput getGraphQLInvocationInput(\n      HttpServletRequest request, HttpServletResponse response) throws IOException {\n    String contentType = request.getContentType();\n    if (contentType != null && APPLICATION_GRAPHQL.equals(contentType.split(\";\")[0].trim())) {\n      String query = request.getReader().lines().collect(joining(\" \"));\n      GraphQLRequest graphqlRequest = GraphQLRequest.createQueryOnlyRequest(query);\n      return invocationInputFactory.create(graphqlRequest, request, response);\n    }\n\n    String body = request.getReader().lines().collect(joining(\" \"));\n    if (isSingleQuery(body)) {\n      GraphQLRequest graphqlRequest = graphQLObjectMapper.readGraphQLRequest(body);\n      return invocationInputFactory.create(graphqlRequest, request, response);\n    }\n\n    if (isBatchedQuery(body)) {\n      List<GraphQLRequest> requests = graphQLObjectMapper.readBatchedGraphQLRequest(body);\n      return invocationInputFactory.create(contextSetting, requests, request, response);\n    }\n\n    throw new GraphQLException(\"No valid query found in request\");\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/GraphQLWebsocketServlet.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static java.util.Arrays.asList;\nimport static java.util.Collections.singletonList;\nimport static java.util.stream.Collectors.toList;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SessionSubscriptions;\nimport graphql.kickstart.execution.subscriptions.SubscriptionConnectionListener;\nimport graphql.kickstart.execution.subscriptions.SubscriptionProtocolFactory;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.apollo.ApolloSubscriptionConnectionListener;\nimport graphql.kickstart.servlet.apollo.ApolloWebSocketSubscriptionProtocolFactory;\nimport graphql.kickstart.servlet.subscriptions.FallbackSubscriptionProtocolFactory;\nimport graphql.kickstart.servlet.subscriptions.WebSocketSendSubscriber;\nimport graphql.kickstart.servlet.subscriptions.WebSocketSubscriptionProtocolFactory;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\nimport jakarta.websocket.CloseReason;\nimport jakarta.websocket.Endpoint;\nimport jakarta.websocket.EndpointConfig;\nimport jakarta.websocket.HandshakeResponse;\nimport jakarta.websocket.MessageHandler;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\nimport jakarta.websocket.server.ServerEndpointConfig;\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * Must be used with {@link #modifyHandshake(ServerEndpointConfig, HandshakeRequest,\n * HandshakeResponse)}\n *\n * @author Andrew Potter\n */\n@Slf4j\npublic class GraphQLWebsocketServlet extends Endpoint {\n\n  private static final String HANDSHAKE_REQUEST_KEY = HandshakeRequest.class.getName();\n  private static final String PROTOCOL_FACTORY_REQUEST_KEY =\n      SubscriptionProtocolFactory.class.getName();\n  private static final CloseReason ERROR_CLOSE_REASON =\n      new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, \"Internal Server Error\");\n  private static final CloseReason SHUTDOWN_CLOSE_REASON =\n      new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, \"Server Shut Down\");\n\n  private final List<SubscriptionProtocolFactory> subscriptionProtocolFactories;\n  private final SubscriptionProtocolFactory fallbackSubscriptionProtocolFactory;\n  private final List<String> allSubscriptionProtocols;\n\n  private final Map<Session, SessionSubscriptions> sessionSubscriptionCache =\n      new ConcurrentHashMap<>();\n  private final AtomicBoolean isShuttingDown = new AtomicBoolean(false);\n  private final AtomicBoolean isShutDown = new AtomicBoolean(false);\n  private final Object cacheLock = new Object();\n\n  public GraphQLWebsocketServlet(GraphQLConfiguration configuration) {\n    this(configuration, null);\n  }\n\n  public GraphQLWebsocketServlet(\n      GraphQLConfiguration configuration,\n      Collection<SubscriptionConnectionListener> connectionListeners) {\n    this(\n        configuration.getGraphQLInvoker(),\n        configuration.getInvocationInputFactory(),\n        configuration.getObjectMapper(),\n        connectionListeners);\n  }\n\n  public GraphQLWebsocketServlet(\n      GraphQLInvoker graphQLInvoker,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper) {\n    this(graphQLInvoker, invocationInputFactory, graphQLObjectMapper, null);\n  }\n\n  public GraphQLWebsocketServlet(\n      GraphQLInvoker graphQLInvoker,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLObjectMapper graphQLObjectMapper,\n      Collection<SubscriptionConnectionListener> connectionListeners) {\n    List<ApolloSubscriptionConnectionListener> listeners = new ArrayList<>();\n    if (connectionListeners != null) {\n      connectionListeners.stream()\n          .filter(ApolloSubscriptionConnectionListener.class::isInstance)\n          .map(ApolloSubscriptionConnectionListener.class::cast)\n          .forEach(listeners::add);\n    }\n    subscriptionProtocolFactories =\n        singletonList(\n            new ApolloWebSocketSubscriptionProtocolFactory(\n                graphQLObjectMapper, invocationInputFactory, graphQLInvoker, listeners));\n    fallbackSubscriptionProtocolFactory =\n        new FallbackSubscriptionProtocolFactory(\n            new GraphQLSubscriptionMapper(graphQLObjectMapper),\n            invocationInputFactory,\n            graphQLInvoker);\n    allSubscriptionProtocols =\n        Stream.concat(\n                subscriptionProtocolFactories.stream(),\n                Stream.of(fallbackSubscriptionProtocolFactory))\n            .map(SubscriptionProtocolFactory::getProtocol)\n            .collect(toList());\n  }\n\n  public GraphQLWebsocketServlet(\n      List<SubscriptionProtocolFactory> subscriptionProtocolFactory,\n      SubscriptionProtocolFactory fallbackSubscriptionProtocolFactory) {\n\n    this.subscriptionProtocolFactories = subscriptionProtocolFactory;\n    this.fallbackSubscriptionProtocolFactory = fallbackSubscriptionProtocolFactory;\n\n    allSubscriptionProtocols =\n        Stream.concat(\n                subscriptionProtocolFactories.stream(),\n                Stream.of(fallbackSubscriptionProtocolFactory))\n            .map(SubscriptionProtocolFactory::getProtocol)\n            .collect(toList());\n  }\n\n  @Override\n  public void onOpen(Session session, EndpointConfig endpointConfig) {\n    final WebSocketSubscriptionProtocolFactory subscriptionProtocolFactory =\n        (WebSocketSubscriptionProtocolFactory)\n            endpointConfig.getUserProperties().get(PROTOCOL_FACTORY_REQUEST_KEY);\n\n    SubscriptionSession subscriptionSession = subscriptionProtocolFactory.createSession(session);\n    synchronized (cacheLock) {\n      if (isShuttingDown.get()) {\n        throw new IllegalStateException(\"Server is shutting down!\");\n      }\n\n      sessionSubscriptionCache.put(session, subscriptionSession.getSubscriptions());\n    }\n\n    subscriptionSession.getPublisher().subscribe(new WebSocketSendSubscriber(session));\n\n    log.debug(\"Session opened: {}, {}\", session.getId(), endpointConfig);\n    Consumer<String> consumer = subscriptionProtocolFactory.createConsumer(subscriptionSession);\n\n    // This *cannot* be a lambda because of the way undertow checks the class...\n    session.addMessageHandler(\n        new MessageHandler.Whole<String>() {\n          @Override\n          public void onMessage(String text) {\n            try {\n              consumer.accept(text);\n            } catch (Exception t) {\n              log.error(\"Error executing websocket query for session: {}\", session.getId(), t);\n              closeUnexpectedly(session, t);\n            }\n          }\n        });\n  }\n\n  @Override\n  public void onClose(Session session, CloseReason closeReason) {\n    log.debug(\"Session closed: {}, {}\", session.getId(), closeReason);\n    SessionSubscriptions subscriptions;\n    synchronized (cacheLock) {\n      subscriptions = sessionSubscriptionCache.remove(session);\n    }\n    if (subscriptions != null) {\n      subscriptions.close();\n    }\n  }\n\n  @Override\n  public void onError(Session session, Throwable thr) {\n    if (thr instanceof EOFException) {\n      log.warn(\n          \"Session {} was killed abruptly without calling onClose. Cleaning up session\",\n          session.getId());\n      onClose(session, ERROR_CLOSE_REASON);\n    } else {\n      log.error(\"Error in websocket session: {}\", session.getId(), thr);\n      closeUnexpectedly(session, thr);\n    }\n  }\n\n  private void closeUnexpectedly(Session session, Throwable t) {\n    try {\n      session.close(ERROR_CLOSE_REASON);\n    } catch (IOException e) {\n      log.error(\"Error closing websocket session for session: {}\", session.getId(), t);\n    }\n  }\n\n  public void modifyHandshake(\n      ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {\n    sec.getUserProperties().put(HANDSHAKE_REQUEST_KEY, request);\n\n    List<String> protocol = request.getHeaders().get(HandshakeRequest.SEC_WEBSOCKET_PROTOCOL);\n    if (protocol == null) {\n      protocol = Collections.emptyList();\n    }\n\n    SubscriptionProtocolFactory subscriptionProtocolFactory =\n        getSubscriptionProtocolFactory(protocol);\n    sec.getUserProperties().put(PROTOCOL_FACTORY_REQUEST_KEY, subscriptionProtocolFactory);\n\n    if (request.getHeaders().get(HandshakeResponse.SEC_WEBSOCKET_ACCEPT) != null) {\n      response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, allSubscriptionProtocols);\n    }\n    if (!protocol.isEmpty()) {\n      //noinspection ArraysAsListWithZeroOrOneArgument\n      response\n          .getHeaders()\n          .put(\n              HandshakeRequest.SEC_WEBSOCKET_PROTOCOL,\n              new ArrayList<>(asList(subscriptionProtocolFactory.getProtocol())));\n    }\n  }\n\n  /** Stops accepting connections and closes all existing connections */\n  public void beginShutDown() {\n    synchronized (cacheLock) {\n      isShuttingDown.set(true);\n      Map<Session, SessionSubscriptions> copy = new HashMap<>(sessionSubscriptionCache);\n\n      // Prevent comodification exception since #onClose() is called during session.close(), but we\n      // can't necessarily rely on that happening so we close subscriptions here anyway.\n      copy.forEach(\n          (session, wsSessionSubscriptions) -> {\n            wsSessionSubscriptions.close();\n            try {\n              session.close(SHUTDOWN_CLOSE_REASON);\n            } catch (IOException e) {\n              log.error(\"Error closing websocket session!\", e);\n            }\n          });\n\n      copy.clear();\n\n      if (!sessionSubscriptionCache.isEmpty()) {\n        log.error(\"GraphQLWebsocketServlet did not shut down cleanly!\");\n        sessionSubscriptionCache.clear();\n      }\n\n      for (SubscriptionProtocolFactory protocolFactory : subscriptionProtocolFactories) {\n        protocolFactory.shutdown();\n      }\n\n      fallbackSubscriptionProtocolFactory.shutdown();\n    }\n\n    isShutDown.set(true);\n  }\n\n  /** @return true when shutdown is complete */\n  public boolean isShutDown() {\n    return isShutDown.get();\n  }\n\n  private SubscriptionProtocolFactory getSubscriptionProtocolFactory(List<String> accept) {\n    for (String protocol : accept) {\n      for (SubscriptionProtocolFactory subscriptionProtocolFactory :\n          subscriptionProtocolFactories) {\n        if (subscriptionProtocolFactory.getProtocol().equals(protocol)) {\n          return subscriptionProtocolFactory;\n        }\n      }\n    }\n\n    return fallbackSubscriptionProtocolFactory;\n  }\n\n  public int getSessionCount() {\n    return sessionSubscriptionCache.size();\n  }\n\n  public int getSubscriptionCount() {\n    return sessionSubscriptionCache.values().stream()\n        .mapToInt(SessionSubscriptions::getSubscriptionCount)\n        .sum();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestHandler.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.io.IOException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic interface HttpRequestHandler {\n\n  String APPLICATION_JSON_UTF8 = \"application/json;charset=UTF-8\";\n  String APPLICATION_EVENT_STREAM_UTF8 = \"text/event-stream;charset=UTF-8\";\n\n  int STATUS_OK = 200;\n  int STATUS_BAD_REQUEST = 400;\n  int STATUS_INTERNAL_SERVER_ERROR = 500;\n\n  void handle(HttpServletRequest request, HttpServletResponse response) throws IOException;\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestHandlerImpl.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\nclass HttpRequestHandlerImpl implements HttpRequestHandler {\n\n  private final GraphQLConfiguration configuration;\n  private final HttpRequestInvoker requestInvoker;\n\n  HttpRequestHandlerImpl(GraphQLConfiguration configuration) {\n    this(\n        configuration,\n        new HttpRequestInvokerImpl(\n            configuration,\n            configuration.getGraphQLInvoker(),\n            new QueryResponseWriterFactoryImpl()));\n  }\n\n  HttpRequestHandlerImpl(\n      GraphQLConfiguration configuration, HttpRequestInvoker requestInvoker) {\n    this.configuration = configuration;\n    this.requestInvoker = requestInvoker;\n  }\n\n  @Override\n  public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    if (request.getCharacterEncoding() == null) {\n      request.setCharacterEncoding(StandardCharsets.UTF_8.name());\n    }\n\n    ListenerHandler listenerHandler =\n      ListenerHandler.start(request, response, configuration.getListeners());\n\n    try {\n      GraphQLInvocationInput invocationInput = parseInvocationInput(request, response);\n      requestInvoker.execute(invocationInput, request, response, listenerHandler);\n    } catch (InvocationInputParseException e) {\n      response.setStatus(STATUS_BAD_REQUEST);\n      log.info(\"Bad request: cannot parse http request\", e);\n      listenerHandler.onParseError(e);\n      throw e;\n    } catch (GraphQLException e) {\n      response.setStatus(STATUS_BAD_REQUEST);\n      log.info(\"Bad request: cannot handle http request\", e);\n      throw e;\n    } catch (Exception t) {\n      response.setStatus(STATUS_INTERNAL_SERVER_ERROR);\n      log.error(\"Cannot handle http request\", t);\n      throw t;\n    }\n  }\n\n  private GraphQLInvocationInput parseInvocationInput(\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    try {\n      GraphQLInvocationInputParser invocationInputParser =\n        GraphQLInvocationInputParser.create(\n          request,\n          configuration.getInvocationInputFactory(),\n          configuration.getObjectMapper(),\n          configuration.getContextSetting());\n      return invocationInputParser.getGraphQLInvocationInput(request, response);\n    } catch (Exception e) {\n      throw new InvocationInputParseException(e);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvoker.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic interface HttpRequestInvoker {\n\n  void execute(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/HttpRequestInvokerImpl.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static graphql.kickstart.servlet.HttpRequestHandler.STATUS_BAD_REQUEST;\nimport static graphql.kickstart.servlet.HttpRequestHandler.STATUS_INTERNAL_SERVER_ERROR;\n\nimport graphql.ExecutionResult;\nimport graphql.ExecutionResultImpl;\nimport graphql.GraphQLException;\nimport graphql.kickstart.execution.FutureExecutionResult;\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLQueryResult;\nimport graphql.kickstart.execution.error.GenericGraphQLError;\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport graphql.kickstart.servlet.input.BatchInputPreProcessResult;\nimport graphql.kickstart.servlet.input.BatchInputPreProcessor;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.util.concurrent.CancellationException;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CompletionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jakarta.servlet.AsyncContext;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class HttpRequestInvokerImpl implements HttpRequestInvoker {\n\n  private final GraphQLConfiguration configuration;\n  private final GraphQLInvoker graphQLInvoker;\n  private final QueryResponseWriterFactory queryResponseWriterFactory;\n\n  @Override\n  public void execute(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler) {\n    if (request.isAsyncSupported()) {\n      invokeAndHandleAsync(invocationInput, request, response, listenerHandler);\n    } else {\n      handle(invocationInput, request, response, listenerHandler);\n    }\n  }\n\n  private void invokeAndHandleAsync(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler) {\n    AsyncContext asyncContext =\n        request.isAsyncStarted()\n            ? request.getAsyncContext()\n            : request.startAsync(request, response);\n    asyncContext.setTimeout(configuration.getAsyncTimeout());\n    AtomicReference<FutureExecutionResult> futureHolder = new AtomicReference<>();\n    AsyncTimeoutListener timeoutListener =\n        event -> {\n          log.warn(\n              \"GraphQL execution canceled because timeout of \"\n                  + configuration.getAsyncTimeout()\n                  + \" millis was reached. The following query was being executed when this happened:\\n{}\",\n              String.join(\"\\n\", invocationInput.getQueries()));\n          FutureExecutionResult futureResult = futureHolder.get();\n          if (futureResult != null) {\n            futureResult.cancel();\n          } else {\n            writeErrorResponse(\n                invocationInput, request, response, listenerHandler, new CancellationException());\n          }\n        };\n    asyncContext.addListener(timeoutListener);\n    configuration\n        .getAsyncExecutor()\n        .execute(\n            () -> {\n              try {\n                FutureExecutionResult futureResult = invoke(invocationInput, request, response);\n                futureHolder.set(futureResult);\n                handleInternal(futureResult, request, response, listenerHandler)\n                    .thenAccept(it -> asyncContext.complete());\n              } catch (GraphQLException e) {\n                response.setStatus(STATUS_BAD_REQUEST);\n                log.info(\"Bad request: cannot handle http request\", e);\n                listenerHandler.onError(e);\n                asyncContext.complete();\n              } catch (Exception e) {\n                response.setStatus(STATUS_INTERNAL_SERVER_ERROR);\n                log.error(\"Cannot handle http request\", e);\n                listenerHandler.onError(e);\n                asyncContext.complete();\n              }\n            });\n  }\n\n  private void handle(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler) {\n    try {\n      FutureExecutionResult futureResult = invoke(invocationInput, request, response);\n      handleInternal(futureResult, request, response, listenerHandler)\n          .get(configuration.getAsyncTimeout(), TimeUnit.MILLISECONDS);\n    } catch (GraphQLException e) {\n      response.setStatus(STATUS_BAD_REQUEST);\n      log.info(\"Bad request: cannot handle http request\", e);\n      listenerHandler.onError(e);\n    } catch (Exception e) {\n      response.setStatus(STATUS_INTERNAL_SERVER_ERROR);\n      log.error(\"Cannot handle http request\", e);\n      listenerHandler.onError(e);\n      if (e instanceof InterruptedException) {\n        Thread.currentThread().interrupt();\n      }\n    }\n  }\n\n  private CompletableFuture<Void> handleInternal(\n      FutureExecutionResult futureResult,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler) {\n    return futureResult\n        .thenApplyQueryResult()\n        .thenAccept(\n            it -> {\n              listenerHandler.beforeFlush();\n              writeResultResponse(futureResult.getInvocationInput(), it, request, response);\n            })\n        .thenAccept(it -> listenerHandler.onSuccess())\n        .exceptionally(\n            t ->\n                writeErrorResponse(\n                    futureResult.getInvocationInput(), request, response, listenerHandler, t))\n        .thenAccept(it -> listenerHandler.onFinally());\n  }\n\n  private void writeResultResponse(\n      GraphQLInvocationInput invocationInput,\n      GraphQLQueryResult queryResult,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    QueryResponseWriter queryResponseWriter = createWriter(invocationInput, queryResult);\n    try {\n      queryResponseWriter.write(request, response);\n    } catch (IOException e) {\n      throw new UncheckedIOException(e);\n    }\n  }\n\n  private Void writeErrorResponse(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler,\n      Throwable t) {\n    Throwable cause = getCause(t);\n    if (!response.isCommitted()) {\n      writeResultResponse(\n          invocationInput, GraphQLQueryResult.create(toErrorResult(cause)), request, response);\n      listenerHandler.onError(cause);\n    } else {\n      log.warn(\n          \"Cannot write GraphQL response, because the HTTP response is already committed. It most likely timed out.\");\n    }\n    return null;\n  }\n\n  private Throwable getCause(Throwable t) {\n    return t instanceof CompletionException && t.getCause() != null ? t.getCause() : t;\n  }\n\n  private ExecutionResult toErrorResult(Throwable t) {\n    String message =\n        t instanceof CancellationException\n            ? \"Execution canceled because timeout of \"\n                + configuration.getAsyncTimeout()\n                + \" millis was reached\"\n            : t.getMessage();\n    if (message == null) {\n      message = \"Unexpected error occurred\";\n    }\n    return new ExecutionResultImpl(new GenericGraphQLError(message));\n  }\n\n  protected QueryResponseWriter createWriter(\n      GraphQLInvocationInput invocationInput, GraphQLQueryResult queryResult) {\n    return queryResponseWriterFactory.createWriter(invocationInput, queryResult, configuration);\n  }\n\n  private FutureExecutionResult invoke(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    if (invocationInput instanceof GraphQLSingleInvocationInput) {\n      return graphQLInvoker.execute(invocationInput);\n    }\n    return invokeBatched((GraphQLBatchedInvocationInput) invocationInput, request, response);\n  }\n\n  private FutureExecutionResult invokeBatched(\n      GraphQLBatchedInvocationInput batchedInvocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    BatchInputPreProcessor preprocessor = configuration.getBatchInputPreProcessor();\n    BatchInputPreProcessResult result =\n        preprocessor.preProcessBatch(batchedInvocationInput, request, response);\n    if (result.isExecutable()) {\n      return graphQLInvoker.execute(result.getBatchedInvocationInput());\n    }\n\n    return FutureExecutionResult.error(\n        GraphQLQueryResult.createError(result.getStatusCode(), result.getStatusMessage()));\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/InvocationInputParseException.java",
    "content": "package graphql.kickstart.servlet;\n\npublic class InvocationInputParseException extends RuntimeException {\n\n  public InvocationInputParseException(Throwable t) {\n    super(\"Request parsing failed\", t);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/ListenerHandler.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static java.util.Collections.emptyList;\n\nimport graphql.kickstart.servlet.core.GraphQLServletListener;\nimport graphql.kickstart.servlet.core.GraphQLServletListener.RequestCallback;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class ListenerHandler {\n\n  private final List<RequestCallback> callbacks;\n  private final HttpServletRequest request;\n  private final HttpServletResponse response;\n\n  static ListenerHandler start(\n      HttpServletRequest request,\n      HttpServletResponse response,\n      List<GraphQLServletListener> listeners) {\n    if (listeners != null) {\n      return new ListenerHandler(\n          runListeners(listeners, it -> it.onRequest(request, response)), request, response);\n    }\n    return new ListenerHandler(emptyList(), request, response);\n  }\n\n  private static <R> List<R> runListeners(\n      List<GraphQLServletListener> listeners, Function<? super GraphQLServletListener, R> action) {\n    return listeners.stream()\n        .map(\n            listener -> {\n              try {\n                return action.apply(listener);\n              } catch (Exception t) {\n                log.error(\"Error running listener: {}\", listener, t);\n                return null;\n              }\n            })\n        .filter(Objects::nonNull)\n        .collect(Collectors.toList());\n  }\n\n  void runCallbacks(Consumer<RequestCallback> action) {\n    callbacks.forEach(\n        callback -> {\n          try {\n            action.accept(callback);\n          } catch (Exception t) {\n            log.error(\"Error running callback: {}\", callback, t);\n          }\n        });\n  }\n\n  void onParseError(Throwable throwable) {\n    runCallbacks(it -> it.onParseError(request, response, throwable));\n  }\n\n  void beforeFlush() {\n    runCallbacks(it -> it.beforeFlush(request, response));\n  }\n\n  void onSuccess() {\n    runCallbacks(it -> it.onSuccess(request, response));\n  }\n\n  void onError(Throwable throwable) {\n    runCallbacks(it -> it.onError(request, response, throwable));\n  }\n\n  void onFinally() {\n    runCallbacks(it -> it.onFinally(request, response));\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/OsgiGraphQLHttpServlet.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.execution.preparsed.NoOpPreparsedDocumentProvider;\nimport graphql.execution.preparsed.PreparsedDocumentProvider;\nimport graphql.kickstart.execution.GraphQLRootObjectBuilder;\nimport graphql.kickstart.execution.config.DefaultExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.ExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.InstrumentationProvider;\nimport graphql.kickstart.execution.error.DefaultGraphQLErrorHandler;\nimport graphql.kickstart.execution.error.GraphQLErrorHandler;\nimport graphql.kickstart.execution.instrumentation.NoOpInstrumentationProvider;\nimport graphql.kickstart.servlet.context.DefaultGraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.core.DefaultGraphQLRootObjectBuilder;\nimport graphql.kickstart.servlet.core.GraphQLServletListener;\nimport graphql.kickstart.servlet.core.GraphQLServletRootObjectBuilder;\nimport graphql.kickstart.servlet.osgi.GraphQLCodeRegistryProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLDirectiveProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLMutationProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLQueryProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLSubscriptionProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLTypesProvider;\nimport graphql.schema.GraphQLCodeRegistry;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.osgi.service.component.annotations.ReferencePolicyOption;\nimport org.osgi.service.metatype.annotations.Designate;\n\n@Component(\n    service = {jakarta.servlet.http.HttpServlet.class, jakarta.servlet.Servlet.class},\n    property = {\"service.description=GraphQL HTTP Servlet\"})\n@Designate(ocd = OsgiGraphQLHttpServletConfiguration.class, factory = true)\npublic class OsgiGraphQLHttpServlet extends AbstractGraphQLHttpServlet {\n\n  private final OsgiSchemaBuilder schemaBuilder = new OsgiSchemaBuilder();\n\n  public OsgiGraphQLHttpServlet() {\n    schemaBuilder.updateSchema();\n  }\n\n  @Activate\n  public void activate(Config config) {\n    schemaBuilder.activate(config.schema_update_delay());\n  }\n\n  @Deactivate\n  public void deactivate() {\n    schemaBuilder.deactivate();\n  }\n\n  @Override\n  protected GraphQLConfiguration getConfiguration() {\n    return schemaBuilder.buildConfiguration();\n  }\n\n  protected void updateSchema() {\n    schemaBuilder.updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindProvider(GraphQLProvider provider) {\n    if (provider instanceof GraphQLQueryProvider) {\n      schemaBuilder.add((GraphQLQueryProvider) provider);\n    }\n    if (provider instanceof GraphQLMutationProvider) {\n      schemaBuilder.add((GraphQLMutationProvider) provider);\n    }\n    if (provider instanceof GraphQLSubscriptionProvider) {\n      schemaBuilder.add((GraphQLSubscriptionProvider) provider);\n    }\n    if (provider instanceof GraphQLTypesProvider) {\n      schemaBuilder.add((GraphQLTypesProvider) provider);\n    }\n    if (provider instanceof GraphQLDirectiveProvider) {\n      schemaBuilder.add((GraphQLDirectiveProvider) provider);\n    }\n    if (provider instanceof GraphQLCodeRegistryProvider) {\n      schemaBuilder.setCodeRegistryProvider((GraphQLCodeRegistryProvider) provider);\n    }\n    updateSchema();\n  }\n\n  public void unbindProvider(GraphQLProvider provider) {\n    if (provider instanceof GraphQLQueryProvider) {\n      schemaBuilder.remove((GraphQLQueryProvider) provider);\n    }\n    if (provider instanceof GraphQLMutationProvider) {\n      schemaBuilder.remove((GraphQLMutationProvider) provider);\n    }\n    if (provider instanceof GraphQLSubscriptionProvider) {\n      schemaBuilder.remove((GraphQLSubscriptionProvider) provider);\n    }\n    if (provider instanceof GraphQLTypesProvider) {\n      schemaBuilder.remove((GraphQLTypesProvider) provider);\n    }\n    if (provider instanceof GraphQLDirectiveProvider) {\n      schemaBuilder.remove((GraphQLDirectiveProvider) provider);\n    }\n    if (provider instanceof GraphQLCodeRegistryProvider) {\n      schemaBuilder.setCodeRegistryProvider(() -> GraphQLCodeRegistry.newCodeRegistry().build());\n    }\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindQueryProvider(GraphQLQueryProvider queryProvider) {\n    schemaBuilder.add(queryProvider);\n    updateSchema();\n  }\n\n  public void unbindQueryProvider(GraphQLQueryProvider queryProvider) {\n    schemaBuilder.remove(queryProvider);\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindMutationProvider(GraphQLMutationProvider mutationProvider) {\n    schemaBuilder.add(mutationProvider);\n    updateSchema();\n  }\n\n  public void unbindMutationProvider(GraphQLMutationProvider mutationProvider) {\n    schemaBuilder.remove(mutationProvider);\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindSubscriptionProvider(GraphQLSubscriptionProvider subscriptionProvider) {\n    schemaBuilder.add(subscriptionProvider);\n    updateSchema();\n  }\n\n  public void unbindSubscriptionProvider(GraphQLSubscriptionProvider subscriptionProvider) {\n    schemaBuilder.remove(subscriptionProvider);\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindTypesProvider(GraphQLTypesProvider typesProvider) {\n    schemaBuilder.add(typesProvider);\n    updateSchema();\n  }\n\n  public void unbindTypesProvider(GraphQLTypesProvider typesProvider) {\n    schemaBuilder.remove(typesProvider);\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindDirectivesProvider(GraphQLDirectiveProvider directiveProvider) {\n    schemaBuilder.add(directiveProvider);\n    updateSchema();\n  }\n\n  public void unbindDirectivesProvider(GraphQLDirectiveProvider directiveProvider) {\n    schemaBuilder.remove(directiveProvider);\n    updateSchema();\n  }\n\n  @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n  public void bindServletListener(GraphQLServletListener listener) {\n    schemaBuilder.add(listener);\n  }\n\n  public void unbindServletListener(GraphQLServletListener listener) {\n    schemaBuilder.remove(listener);\n  }\n\n  @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)\n  public void setContextBuilder(GraphQLServletContextBuilder contextBuilder) {\n    schemaBuilder.setContextBuilder(contextBuilder);\n  }\n\n  public void unsetContextBuilder(GraphQLServletContextBuilder contextBuilder) {\n    schemaBuilder.setContextBuilder(new DefaultGraphQLServletContextBuilder());\n  }\n\n  @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)\n  public void setRootObjectBuilder(GraphQLServletRootObjectBuilder rootObjectBuilder) {\n    schemaBuilder.setRootObjectBuilder(rootObjectBuilder);\n  }\n\n  public void unsetRootObjectBuilder(GraphQLRootObjectBuilder rootObjectBuilder) {\n    schemaBuilder.setRootObjectBuilder(new DefaultGraphQLRootObjectBuilder());\n  }\n\n  @Reference(\n      cardinality = ReferenceCardinality.OPTIONAL,\n      policy = ReferencePolicy.DYNAMIC,\n      policyOption = ReferencePolicyOption.GREEDY)\n  public void setExecutionStrategyProvider(ExecutionStrategyProvider provider) {\n    schemaBuilder.setExecutionStrategyProvider(provider);\n  }\n\n  public void unsetExecutionStrategyProvider(ExecutionStrategyProvider provider) {\n    schemaBuilder.setExecutionStrategyProvider(new DefaultExecutionStrategyProvider());\n  }\n\n  @Reference(\n      cardinality = ReferenceCardinality.OPTIONAL,\n      policy = ReferencePolicy.DYNAMIC,\n      policyOption = ReferencePolicyOption.GREEDY)\n  public void setInstrumentationProvider(InstrumentationProvider provider) {\n    schemaBuilder.setInstrumentationProvider(provider);\n  }\n\n  public void unsetInstrumentationProvider(InstrumentationProvider provider) {\n    schemaBuilder.setInstrumentationProvider(new NoOpInstrumentationProvider());\n  }\n\n  @Reference(\n      cardinality = ReferenceCardinality.OPTIONAL,\n      policy = ReferencePolicy.DYNAMIC,\n      policyOption = ReferencePolicyOption.GREEDY)\n  public void setErrorHandler(GraphQLErrorHandler errorHandler) {\n    schemaBuilder.setErrorHandler(errorHandler);\n  }\n\n  public void unsetErrorHandler(GraphQLErrorHandler errorHandler) {\n    schemaBuilder.setErrorHandler(new DefaultGraphQLErrorHandler());\n  }\n\n  @Reference(\n      cardinality = ReferenceCardinality.OPTIONAL,\n      policy = ReferencePolicy.DYNAMIC,\n      policyOption = ReferencePolicyOption.GREEDY)\n  public void setPreparsedDocumentProvider(PreparsedDocumentProvider preparsedDocumentProvider) {\n    schemaBuilder.setPreparsedDocumentProvider(preparsedDocumentProvider);\n  }\n\n  public void unsetPreparsedDocumentProvider(PreparsedDocumentProvider preparsedDocumentProvider) {\n    schemaBuilder.setPreparsedDocumentProvider(NoOpPreparsedDocumentProvider.INSTANCE);\n  }\n\n  @Reference(\n      cardinality = ReferenceCardinality.OPTIONAL,\n      policy = ReferencePolicy.DYNAMIC,\n      policyOption = ReferencePolicyOption.GREEDY)\n  public void bindCodeRegistryProvider(GraphQLCodeRegistryProvider graphQLCodeRegistryProvider) {\n    schemaBuilder.setCodeRegistryProvider(graphQLCodeRegistryProvider);\n    updateSchema();\n  }\n\n  public void unbindCodeRegistryProvider(GraphQLCodeRegistryProvider graphQLCodeRegistryProvider) {\n    schemaBuilder.setCodeRegistryProvider(() -> GraphQLCodeRegistry.newCodeRegistry().build());\n    updateSchema();\n  }\n\n  @interface Config {\n\n    int schema_update_delay() default 0;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/OsgiGraphQLHttpServletConfiguration.java",
    "content": "package graphql.kickstart.servlet;\n\nimport org.osgi.service.metatype.annotations.AttributeDefinition;\nimport org.osgi.service.metatype.annotations.ObjectClassDefinition;\n\n@ObjectClassDefinition(\n    name = \"GraphQL HTTP Servlet\",\n    description = \"GraphQL HTTP Servlet Configuration\")\n@interface OsgiGraphQLHttpServletConfiguration {\n\n  @AttributeDefinition(name = \"alias\", description = \"Servlet alias\")\n  String alias() default \"/graphql\";\n\n  @AttributeDefinition(name = \"jmx.objectname\", description = \"JMX object name\")\n  String jmx_objectname() default \"graphql.servlet:type=graphql\";\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/OsgiSchemaBuilder.java",
    "content": "package graphql.kickstart.servlet;\n\nimport static graphql.schema.GraphQLObjectType.newObject;\nimport static graphql.schema.GraphQLSchema.newSchema;\nimport static java.util.stream.Collectors.toSet;\n\nimport graphql.Scalars;\nimport graphql.execution.preparsed.NoOpPreparsedDocumentProvider;\nimport graphql.execution.preparsed.PreparsedDocumentProvider;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.GraphQLQueryInvoker;\nimport graphql.kickstart.execution.config.DefaultExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.ExecutionStrategyProvider;\nimport graphql.kickstart.execution.config.InstrumentationProvider;\nimport graphql.kickstart.execution.error.DefaultGraphQLErrorHandler;\nimport graphql.kickstart.execution.error.GraphQLErrorHandler;\nimport graphql.kickstart.execution.instrumentation.NoOpInstrumentationProvider;\nimport graphql.kickstart.servlet.config.DefaultGraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.config.GraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.context.DefaultGraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.core.DefaultGraphQLRootObjectBuilder;\nimport graphql.kickstart.servlet.core.GraphQLServletListener;\nimport graphql.kickstart.servlet.core.GraphQLServletRootObjectBuilder;\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory;\nimport graphql.kickstart.servlet.osgi.GraphQLCodeRegistryProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLFieldProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLDirectiveProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLMutationProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLQueryProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLSubscriptionProvider;\nimport graphql.kickstart.servlet.osgi.GraphQLTypesProvider;\nimport graphql.schema.GraphQLCodeRegistry;\nimport graphql.schema.GraphQLDirective;\nimport graphql.schema.GraphQLFieldDefinition;\nimport graphql.schema.GraphQLObjectType;\nimport graphql.schema.GraphQLType;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport lombok.Setter;\n\n@Setter\nclass OsgiSchemaBuilder {\n\n  private final List<GraphQLQueryProvider> queryProviders = new ArrayList<>();\n  private final List<GraphQLMutationProvider> mutationProviders = new ArrayList<>();\n  private final List<GraphQLSubscriptionProvider> subscriptionProviders = new ArrayList<>();\n  private final List<GraphQLTypesProvider> typesProviders = new ArrayList<>();\n  private final List<GraphQLDirectiveProvider> directiveProviders = new ArrayList<>();\n  private final List<GraphQLServletListener> listeners = new ArrayList<>();\n\n  private GraphQLServletContextBuilder contextBuilder = new DefaultGraphQLServletContextBuilder();\n  private GraphQLServletRootObjectBuilder rootObjectBuilder = new DefaultGraphQLRootObjectBuilder();\n  private ExecutionStrategyProvider executionStrategyProvider =\n      new DefaultExecutionStrategyProvider();\n  private InstrumentationProvider instrumentationProvider = new NoOpInstrumentationProvider();\n  private GraphQLErrorHandler errorHandler = new DefaultGraphQLErrorHandler();\n  private PreparsedDocumentProvider preparsedDocumentProvider =\n      NoOpPreparsedDocumentProvider.INSTANCE;\n  private GraphQLCodeRegistryProvider codeRegistryProvider =\n      () -> GraphQLCodeRegistry.newCodeRegistry().build();\n\n  private GraphQLSchemaServletProvider schemaProvider;\n\n  private ScheduledExecutorService executor;\n  private ScheduledFuture<?> updateFuture;\n  private int schemaUpdateDelay;\n\n  void activate(int schemaUpdateDelay) {\n    this.schemaUpdateDelay = schemaUpdateDelay;\n    if (schemaUpdateDelay != 0) {\n      executor = Executors.newSingleThreadScheduledExecutor();\n    }\n  }\n\n  void deactivate() {\n    if (executor != null) {\n      executor.shutdown();\n    }\n  }\n\n  void updateSchema() {\n    if (schemaUpdateDelay == 0) {\n      doUpdateSchema();\n    } else {\n      if (updateFuture != null) {\n        updateFuture.cancel(true);\n      }\n\n      updateFuture =\n          executor.schedule(this::doUpdateSchema, schemaUpdateDelay, TimeUnit.MILLISECONDS);\n    }\n  }\n\n  private void doUpdateSchema() {\n    this.schemaProvider =\n        new DefaultGraphQLSchemaServletProvider(\n            newSchema()\n                .query(buildQueryType())\n                .mutation(buildMutationType())\n                .subscription(buildSubscriptionType())\n                .additionalTypes(buildTypes())\n                .additionalDirectives(buildDirectives())\n                .codeRegistry(codeRegistryProvider.getCodeRegistry())\n                .build());\n  }\n\n  private GraphQLObjectType buildQueryType() {\n    final GraphQLObjectType.Builder queryTypeBuilder =\n        newObject().name(\"Query\").description(\"Root query type\");\n\n    if (!queryProviders.isEmpty()) {\n      for (GraphQLQueryProvider provider : queryProviders) {\n        if (provider.getQueries() != null && !provider.getQueries().isEmpty()) {\n          provider.getQueries().forEach(queryTypeBuilder::field);\n        }\n      }\n    } else {\n      // graphql-java enforces Query type to be there with at least some field.\n      queryTypeBuilder.field(\n          GraphQLFieldDefinition.newFieldDefinition()\n              .name(\"_empty\")\n              .type(Scalars.GraphQLBoolean)\n              .build());\n    }\n    return queryTypeBuilder.build();\n  }\n\n  private Set<GraphQLType> buildTypes() {\n    return typesProviders.stream()\n        .map(GraphQLTypesProvider::getTypes)\n        .flatMap(Collection::stream)\n        .collect(toSet());\n  }\n\n  private GraphQLObjectType buildMutationType() {\n    return buildObjectType(\"Mutation\", new ArrayList<>(mutationProviders));\n  }\n\n  private GraphQLObjectType buildSubscriptionType() {\n    return buildObjectType(\"Subscription\", new ArrayList<>(subscriptionProviders));\n  }\n\n  private GraphQLObjectType buildObjectType(String name, List<GraphQLFieldProvider> providers) {\n    if (!providers.isEmpty()) {\n      final GraphQLObjectType.Builder typeBuilder =\n          newObject().name(name).description(\"Root \" + name.toLowerCase() + \" type\");\n\n      for (GraphQLFieldProvider provider : providers) {\n        provider.getFields().forEach(typeBuilder::field);\n      }\n\n      if (!typeBuilder.build().getFieldDefinitions().isEmpty()) {\n        return typeBuilder.build();\n      }\n    }\n    return null;\n  }\n\n  private Set<GraphQLDirective> buildDirectives() {\n    return directiveProviders.stream()\n        .map(GraphQLDirectiveProvider::getDirectives)\n        .flatMap(Collection::stream)\n        .collect(toSet());\n  }\n\n  void add(GraphQLQueryProvider provider) {\n    queryProviders.add(provider);\n  }\n\n  void add(GraphQLMutationProvider provider) {\n    mutationProviders.add(provider);\n  }\n\n  void add(GraphQLSubscriptionProvider provider) {\n    subscriptionProviders.add(provider);\n  }\n\n  void add(GraphQLTypesProvider provider) {\n    typesProviders.add(provider);\n  }\n\n  void add(GraphQLDirectiveProvider provider) {\n    directiveProviders.add(provider);\n  }\n\n  void remove(GraphQLQueryProvider provider) {\n    queryProviders.remove(provider);\n  }\n\n  void remove(GraphQLMutationProvider provider) {\n    mutationProviders.remove(provider);\n  }\n\n  void remove(GraphQLSubscriptionProvider provider) {\n    subscriptionProviders.remove(provider);\n  }\n\n  void remove(GraphQLTypesProvider provider) {\n    typesProviders.remove(provider);\n  }\n\n  void remove(GraphQLDirectiveProvider provider) {\n    directiveProviders.remove(provider);\n  }\n\n  GraphQLSchemaServletProvider getSchemaProvider() {\n    return schemaProvider;\n  }\n\n  GraphQLConfiguration buildConfiguration() {\n    return GraphQLConfiguration.with(buildInvocationInputFactory())\n        .with(buildQueryInvoker())\n        .with(buildObjectMapper())\n        .with(listeners)\n        .build();\n  }\n\n  private GraphQLInvocationInputFactory buildInvocationInputFactory() {\n    return GraphQLInvocationInputFactory.newBuilder(this::getSchemaProvider)\n        .withGraphQLContextBuilder(contextBuilder)\n        .withGraphQLRootObjectBuilder(rootObjectBuilder)\n        .build();\n  }\n\n  private GraphQLQueryInvoker buildQueryInvoker() {\n    return GraphQLQueryInvoker.newBuilder()\n        .withPreparsedDocumentProvider(preparsedDocumentProvider)\n        .withInstrumentation(() -> instrumentationProvider.getInstrumentation())\n        .withExecutionStrategyProvider(executionStrategyProvider)\n        .build();\n  }\n\n  private GraphQLObjectMapper buildObjectMapper() {\n    return GraphQLObjectMapper.newBuilder().withGraphQLErrorHandler(errorHandler).build();\n  }\n\n  void add(GraphQLServletListener listener) {\n    listeners.add(listener);\n  }\n\n  void remove(GraphQLServletListener listener) {\n    listeners.remove(listener);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/PartIOException.java",
    "content": "package graphql.kickstart.servlet;\n\npublic class PartIOException extends RuntimeException {\n\n  public PartIOException(String message, Throwable cause) {\n    super(message, cause);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/QueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.io.IOException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic interface QueryResponseWriter {\n\n  void write(HttpServletRequest request, HttpServletResponse response) throws IOException;\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/QueryResponseWriterFactory.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.GraphQLQueryResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\n\npublic interface QueryResponseWriterFactory {\n\n  QueryResponseWriter createWriter(\n      GraphQLInvocationInput invocationInput,\n      GraphQLQueryResult queryResult,\n      GraphQLConfiguration configuration);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/QueryResponseWriterFactoryImpl.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.GraphQLQueryResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.Objects;\n\npublic class QueryResponseWriterFactoryImpl implements QueryResponseWriterFactory {\n\n  @Override\n  public QueryResponseWriter createWriter(\n      GraphQLInvocationInput invocationInput,\n      GraphQLQueryResult queryResult,\n      GraphQLConfiguration configuration) {\n    Objects.requireNonNull(queryResult, \"GraphQL query result cannot be null\");\n\n    if (queryResult.isBatched()) {\n      return new BatchedQueryResponseWriter(\n          queryResult.getResults(), configuration.getObjectMapper());\n    }\n    if (queryResult.isAsynchronous()) {\n      return new SingleAsynchronousQueryResponseWriter(\n          queryResult.getResult(),\n          configuration.getObjectMapper(),\n          configuration.getSubscriptionTimeout());\n    }\n    if (queryResult.isError()) {\n      return new ErrorQueryResponseWriter(queryResult.getStatusCode(), queryResult.getMessage());\n    }\n    return new SingleQueryResponseWriter(queryResult.getResult(), configuration.getObjectMapper());\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/SingleAsynchronousQueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jakarta.servlet.AsyncContext;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.reactivestreams.Publisher;\nimport org.reactivestreams.Subscription;\n\n@RequiredArgsConstructor\nclass SingleAsynchronousQueryResponseWriter implements QueryResponseWriter {\n\n  @Getter private final ExecutionResult result;\n  private final GraphQLObjectMapper graphQLObjectMapper;\n  private final long subscriptionTimeout;\n\n  @Override\n  public void write(HttpServletRequest request, HttpServletResponse response) {\n    Objects.requireNonNull(request, \"Http servlet request cannot be null\");\n    response.setContentType(HttpRequestHandler.APPLICATION_EVENT_STREAM_UTF8);\n    response.setStatus(HttpRequestHandler.STATUS_OK);\n\n    boolean isInAsyncThread = request.isAsyncStarted();\n    AsyncContext asyncContext =\n        isInAsyncThread ? request.getAsyncContext() : request.startAsync(request, response);\n    asyncContext.setTimeout(subscriptionTimeout);\n    AtomicReference<Subscription> subscriptionRef = new AtomicReference<>();\n    asyncContext.addListener(new SubscriptionAsyncListener(subscriptionRef));\n    ExecutionResultSubscriber subscriber =\n        new ExecutionResultSubscriber(subscriptionRef, asyncContext, graphQLObjectMapper);\n    List<Publisher<ExecutionResult>> publishers = new ArrayList<>();\n    if (result.getData() instanceof Publisher) {\n      publishers.add(result.getData());\n    } else {\n      publishers.add(new StaticDataPublisher<>(result));\n    }\n    publishers.forEach(it -> it.subscribe(subscriber));\n\n    if (isInAsyncThread) {\n      // We need to delay the completion of async context until after the subscription has\n      // terminated, otherwise the AsyncContext is prematurely closed.\n      try {\n        subscriber.await();\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/SingleQueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.RequiredArgsConstructor;\n\n@RequiredArgsConstructor\nclass SingleQueryResponseWriter implements QueryResponseWriter {\n\n  private final ExecutionResult result;\n  private final GraphQLObjectMapper graphQLObjectMapper;\n\n  @Override\n  public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    response.setContentType(HttpRequestHandler.APPLICATION_JSON_UTF8);\n    response.setStatus(HttpRequestHandler.STATUS_OK);\n    response.setCharacterEncoding(StandardCharsets.UTF_8.name());\n\n    byte[] contentBytes = graphQLObjectMapper.serializeResultAsBytes(result);\n    response.setContentLength(contentBytes.length);\n    response.getOutputStream().write(contentBytes);\n    response.getOutputStream().flush();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/StaticDataPublisher.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.execution.reactive.SingleSubscriberPublisher;\nimport org.reactivestreams.Publisher;\n\nclass StaticDataPublisher<T> extends SingleSubscriberPublisher<T> implements Publisher<T> {\n\n  StaticDataPublisher(T data) {\n    super();\n    offer(data);\n    noMoreData();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/SubscriptionAsyncListener.java",
    "content": "package graphql.kickstart.servlet;\n\nimport java.util.concurrent.atomic.AtomicReference;\nimport jakarta.servlet.AsyncEvent;\nimport jakarta.servlet.AsyncListener;\nimport lombok.RequiredArgsConstructor;\nimport org.reactivestreams.Subscription;\n\n@RequiredArgsConstructor\nclass SubscriptionAsyncListener implements AsyncListener {\n\n  private final AtomicReference<Subscription> subscriptionRef;\n\n  @Override\n  public void onComplete(AsyncEvent event) {\n    subscriptionRef.get().cancel();\n  }\n\n  @Override\n  public void onTimeout(AsyncEvent event) {\n    subscriptionRef.get().cancel();\n  }\n\n  @Override\n  public void onError(AsyncEvent event) {\n    subscriptionRef.get().cancel();\n  }\n\n  @Override\n  public void onStartAsync(AsyncEvent event) {\n    // default empty implementation\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/apollo/ApolloScalars.java",
    "content": "package graphql.kickstart.servlet.apollo;\n\nimport graphql.schema.Coercing;\nimport graphql.schema.CoercingParseLiteralException;\nimport graphql.schema.CoercingParseValueException;\nimport graphql.schema.CoercingSerializeException;\nimport graphql.schema.GraphQLScalarType;\nimport jakarta.servlet.http.Part;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic class ApolloScalars {\n\n  public static final GraphQLScalarType Upload =\n      GraphQLScalarType.newScalar()\n          .name(\"Upload\")\n          .description(\"A file part in a multipart request\")\n          .coercing(\n              new Coercing<Part, Void>() {\n                @Override\n                public Void serialize(Object dataFetcherResult) {\n                  throw new CoercingSerializeException(\"Upload is an input-only type\");\n                }\n\n                @Override\n                public Part parseValue(Object input) {\n                  if (input instanceof Part) {\n                    return (Part) input;\n                  } else if (null == input) {\n                    return null;\n                  } else {\n                    throw new CoercingParseValueException(\n                        \"Expected type \"\n                            + Part.class.getName()\n                            + \" but was \"\n                            + input.getClass().getName());\n                  }\n                }\n\n                @Override\n                public Part parseLiteral(Object input) {\n                  throw new CoercingParseLiteralException(\n                      \"Must use variables to specify Upload values\");\n                }\n              })\n          .build();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/apollo/ApolloWebSocketSubscriptionProtocolFactory.java",
    "content": "package graphql.kickstart.servlet.apollo;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLObjectMapper;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.apollo.ApolloSubscriptionConnectionListener;\nimport graphql.kickstart.execution.subscriptions.apollo.ApolloSubscriptionProtocolFactory;\nimport graphql.kickstart.servlet.subscriptions.WebSocketSubscriptionProtocolFactory;\nimport java.time.Duration;\nimport java.util.Collection;\nimport jakarta.websocket.Session;\n\npublic class ApolloWebSocketSubscriptionProtocolFactory extends ApolloSubscriptionProtocolFactory\n    implements WebSocketSubscriptionProtocolFactory {\n\n  public ApolloWebSocketSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker) {\n    super(objectMapper, invocationInputFactory, graphQLInvoker);\n  }\n\n  public ApolloWebSocketSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Duration keepAliveInterval) {\n    super(objectMapper, invocationInputFactory, graphQLInvoker, keepAliveInterval);\n  }\n\n  public ApolloWebSocketSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Collection<ApolloSubscriptionConnectionListener> connectionListeners) {\n    super(objectMapper, invocationInputFactory, graphQLInvoker, connectionListeners);\n  }\n\n  public ApolloWebSocketSubscriptionProtocolFactory(\n      GraphQLObjectMapper objectMapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker,\n      Collection<ApolloSubscriptionConnectionListener> connectionListeners,\n      Duration keepAliveInterval) {\n    super(\n        objectMapper,\n        invocationInputFactory,\n        graphQLInvoker,\n        connectionListeners,\n        keepAliveInterval);\n  }\n\n  @Override\n  public SubscriptionSession createSession(Session session) {\n    return new ApolloWebSocketSubscriptionSession(\n        new GraphQLSubscriptionMapper(getObjectMapper()), session);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/apollo/ApolloWebSocketSubscriptionSession.java",
    "content": "package graphql.kickstart.servlet.apollo;\n\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.apollo.ApolloSubscriptionSession;\nimport graphql.kickstart.servlet.subscriptions.WebSocketSubscriptionSession;\nimport java.util.Map;\nimport jakarta.websocket.Session;\n\npublic class ApolloWebSocketSubscriptionSession extends ApolloSubscriptionSession {\n\n  private final WebSocketSubscriptionSession webSocketSubscriptionSession;\n\n  public ApolloWebSocketSubscriptionSession(GraphQLSubscriptionMapper mapper, Session session) {\n    super(mapper);\n    webSocketSubscriptionSession = new WebSocketSubscriptionSession(mapper, session);\n  }\n\n  @Override\n  public boolean isOpen() {\n    return webSocketSubscriptionSession.isOpen();\n  }\n\n  @Override\n  public Map<String, Object> getUserProperties() {\n    return webSocketSubscriptionSession.getUserProperties();\n  }\n\n  @Override\n  public String getId() {\n    return webSocketSubscriptionSession.getId();\n  }\n\n  @Override\n  public Session unwrap() {\n    return webSocketSubscriptionSession.unwrap();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/BufferedHttpServletResponse.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport jakarta.servlet.ServletOutputStream;\nimport jakarta.servlet.WriteListener;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpServletResponseWrapper;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class BufferedHttpServletResponse extends HttpServletResponseWrapper {\n\n  private BufferedOutputStream copier;\n  private ServletOutputStream outputStream;\n  private PrintWriter writer;\n  private String errorMessage;\n\n  public BufferedHttpServletResponse(HttpServletResponse response) {\n    super(response);\n  }\n\n  @Override\n  public void sendError(int sc, String msg) throws IOException {\n    errorMessage = msg;\n    super.sendError(sc, msg);\n  }\n\n  @Override\n  public void sendError(int sc) throws IOException {\n    sendError(sc, null);\n  }\n\n  @Override\n  public ServletOutputStream getOutputStream() throws IOException {\n    if (writer != null) {\n      throw new IllegalStateException(\"getWriter() has already been called on this response.\");\n    }\n\n    if (outputStream == null) {\n      outputStream = getResponse().getOutputStream();\n      copier = new BufferedOutputStream(outputStream);\n    }\n\n    return copier;\n  }\n\n  @Override\n  public PrintWriter getWriter() throws IOException {\n    if (outputStream != null) {\n      throw new IllegalStateException(\n          \"getOutputStream() has already been called on this response.\");\n    }\n\n    if (writer == null) {\n      copier = new BufferedOutputStream(getResponse().getOutputStream());\n      writer =\n          new PrintWriter(\n              new OutputStreamWriter(copier, getResponse().getCharacterEncoding()), true);\n    }\n\n    return writer;\n  }\n\n  @Override\n  public void flushBuffer() throws IOException {\n    if (writer != null) {\n      writer.flush();\n    } else if (copier != null) {\n      copier.flush();\n    }\n  }\n\n  @Override\n  public boolean isCommitted() {\n    return false;\n  }\n\n  public void close() throws IOException {\n    if (writer != null) {\n      writer.close();\n    } else if (copier != null) {\n      copier.close();\n    }\n  }\n\n  public String getErrorMessage() {\n    return errorMessage;\n  }\n\n  public byte[] getContentAsByteArray() {\n    if (copier != null) {\n      return copier.toByteArray();\n    } else {\n      return new byte[0];\n    }\n  }\n\n  private static final class BufferedOutputStream extends ServletOutputStream {\n\n    private final OutputStream delegate;\n    private final ByteArrayOutputStream buf = new ByteArrayOutputStream();\n\n    public BufferedOutputStream(OutputStream delegate) {\n      this.delegate = delegate;\n    }\n\n    public void write(int b) throws IOException {\n      buf.write(b);\n      delegate.write(b);\n    }\n\n    @Override\n    public void flush() throws IOException {\n      buf.flush();\n      delegate.flush();\n    }\n\n    @Override\n    public void close() throws IOException {\n      buf.close();\n      delegate.close();\n    }\n\n    @Override\n    public boolean isReady() {\n      return true;\n    }\n\n    @Override\n    public void setWriteListener(WriteListener writeListener) {\n      // write listener not supported\n    }\n\n    public byte[] toByteArray() {\n      return buf.toByteArray();\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/CacheReader.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.HttpRequestHandler;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class CacheReader {\n\n  /**\n   * Response from cache if possible, if nothing in cache will not produce any response\n   *\n   * @return {@literal true} if response was fulfilled from cache, {@literal false} is cache not\n   *     found or an error occurred while reading value from cache\n   * @throws IOException if can not read value from the cache\n   */\n  public boolean responseFromCache(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      GraphQLResponseCacheManager cacheManager)\n      throws IOException {\n    try {\n      CachedResponse cachedResponse = cacheManager.get(request, invocationInput);\n      if (cachedResponse != null) {\n        write(response, cachedResponse);\n        return true;\n      }\n    } catch (Exception t) {\n      log.warn(\"Ignore read from cache, unexpected error happened\", t);\n    }\n\n    return false;\n  }\n\n  private void write(HttpServletResponse response, CachedResponse cachedResponse)\n      throws IOException {\n    if (cachedResponse.isError()) {\n      response.sendError(cachedResponse.getErrorStatusCode(), cachedResponse.getErrorMessage());\n    } else {\n      response.setContentType(HttpRequestHandler.APPLICATION_JSON_UTF8);\n      response.setStatus(HttpRequestHandler.STATUS_OK);\n      response.setCharacterEncoding(StandardCharsets.UTF_8.name());\n      response.setContentLength(cachedResponse.getContentBytes().length);\n      response.getOutputStream().write(cachedResponse.getContentBytes());\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/CachedResponse.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\npublic class CachedResponse implements Serializable {\n\n  private static final long serialVersionUID = 5894555791705575139L;\n\n  private final byte[] contentBytes;\n\n  private final boolean error;\n  private final Integer errorStatusCode;\n  private final String errorMessage;\n\n  private CachedResponse(\n      byte[] contentBytes, boolean error, Integer errorStatusCode, String errorMessage) {\n    this.contentBytes = contentBytes;\n    this.error = error;\n    this.errorStatusCode = errorStatusCode;\n    this.errorMessage = errorMessage;\n  }\n\n  /**\n   * Constructor for success response\n   *\n   * @param contentBytes bytes array of graphql json response\n   */\n  public static CachedResponse ofContent(byte[] contentBytes) {\n    Objects.requireNonNull(contentBytes, \"contentBytes can not be null\");\n\n    return new CachedResponse(contentBytes, false, null, null);\n  }\n\n  /**\n   * Constructor for error response\n   *\n   * @param errorStatusCode the status code for the error response\n   * @param errorMessage the error message for the error response\n   */\n  public static CachedResponse ofError(int errorStatusCode, String errorMessage) {\n    return new CachedResponse(null, true, errorStatusCode, errorMessage);\n  }\n\n  /** @return {@literal true} when this request was failed */\n  public boolean isError() {\n    return error;\n  }\n\n  /**\n   * @return the response body for success requests, {@literal null} when {@link #isError()} is\n   *     {@literal true}\n   */\n  public byte[] getContentBytes() {\n    return contentBytes;\n  }\n\n  /** @return the response error code */\n  public Integer getErrorStatusCode() {\n    return errorStatusCode;\n  }\n\n  /** @return the response error message */\n  public String getErrorMessage() {\n    return errorMessage;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/CachingHttpRequestInvoker.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport static graphql.kickstart.servlet.HttpRequestHandler.STATUS_BAD_REQUEST;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.GraphQLConfiguration;\nimport graphql.kickstart.servlet.HttpRequestInvoker;\nimport graphql.kickstart.servlet.HttpRequestInvokerImpl;\nimport graphql.kickstart.servlet.ListenerHandler;\nimport java.io.IOException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.AccessLevel;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@RequiredArgsConstructor(access = AccessLevel.PROTECTED)\npublic class CachingHttpRequestInvoker implements HttpRequestInvoker {\n\n  private final GraphQLConfiguration configuration;\n  private final HttpRequestInvoker requestInvoker;\n  private final CacheReader cacheReader;\n\n  public CachingHttpRequestInvoker(GraphQLConfiguration configuration) {\n    this(\n        configuration,\n        new HttpRequestInvokerImpl(\n            configuration,\n            configuration.getGraphQLInvoker(),\n            new CachingQueryResponseWriterFactory()),\n        new CacheReader());\n  }\n\n  /** Try to return value from cache if cache exists, otherwise process the query normally */\n  @Override\n  public void execute(\n      GraphQLInvocationInput invocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      ListenerHandler listenerHandler) {\n    try {\n      if (!cacheReader.responseFromCache(\n          invocationInput, request, response, configuration.getResponseCacheManager())) {\n        requestInvoker.execute(invocationInput, request, response, listenerHandler);\n      }\n    } catch (IOException e) {\n      response.setStatus(STATUS_BAD_REQUEST);\n      log.warn(\"Unexpected error happened during response from cache\", e);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/CachingQueryResponseWriter.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.QueryResponseWriter;\nimport java.io.IOException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class CachingQueryResponseWriter implements QueryResponseWriter {\n\n  private final QueryResponseWriter delegate;\n  private final GraphQLResponseCacheManager responseCache;\n  private final GraphQLInvocationInput invocationInput;\n  private final boolean error;\n\n  public CachingQueryResponseWriter(\n      QueryResponseWriter delegate,\n      GraphQLResponseCacheManager responseCache,\n      GraphQLInvocationInput invocationInput,\n      boolean error) {\n    this.delegate = delegate;\n    this.responseCache = responseCache;\n    this.invocationInput = invocationInput;\n    this.error = error;\n  }\n\n  @Override\n  public void write(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    if (responseCache.isCacheable(request, invocationInput)) {\n      BufferedHttpServletResponse cachingResponseWrapper =\n          new BufferedHttpServletResponse(response);\n\n      delegate.write(request, cachingResponseWrapper);\n\n      try {\n        if (error) {\n          int errorStatusCode = cachingResponseWrapper.getStatus();\n          String errorMessage = cachingResponseWrapper.getErrorMessage();\n\n          responseCache.put(\n              request, invocationInput, CachedResponse.ofError(errorStatusCode, errorMessage));\n        } else {\n          byte[] contentBytes = cachingResponseWrapper.getContentAsByteArray();\n\n          responseCache.put(request, invocationInput, CachedResponse.ofContent(contentBytes));\n        }\n      } catch (Exception t) {\n        log.warn(\"Ignore read from cache, unexpected error happened\", t);\n      }\n\n      cachingResponseWrapper.flushBuffer();\n      cachingResponseWrapper.close();\n    } else {\n      delegate.write(request, response);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/CachingQueryResponseWriterFactory.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport graphql.kickstart.execution.GraphQLQueryResult;\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport graphql.kickstart.servlet.GraphQLConfiguration;\nimport graphql.kickstart.servlet.QueryResponseWriter;\nimport graphql.kickstart.servlet.QueryResponseWriterFactory;\nimport graphql.kickstart.servlet.QueryResponseWriterFactoryImpl;\n\npublic class CachingQueryResponseWriterFactory implements QueryResponseWriterFactory {\n\n  private final QueryResponseWriterFactory queryResponseWriterFactory =\n      new QueryResponseWriterFactoryImpl();\n\n  @Override\n  public QueryResponseWriter createWriter(\n      GraphQLInvocationInput invocationInput,\n      GraphQLQueryResult queryResult,\n      GraphQLConfiguration configuration) {\n    QueryResponseWriter writer =\n        queryResponseWriterFactory.createWriter(invocationInput, queryResult, configuration);\n    if (configuration.getResponseCacheManager() != null) {\n      return new CachingQueryResponseWriter(\n          writer, configuration.getResponseCacheManager(), invocationInput, queryResult.isError());\n    }\n    return writer;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/cache/GraphQLResponseCacheManager.java",
    "content": "package graphql.kickstart.servlet.cache;\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput;\nimport java.util.Optional;\nimport jakarta.servlet.http.HttpServletRequest;\n\npublic interface GraphQLResponseCacheManager {\n\n  /**\n   * Retrieve the cache by input data. If this query was not cached before, will return empty {@link\n   * Optional}.\n   *\n   * @param request the http request\n   * @param invocationInput input data\n   * @return cached response if something available in cache or {@literal null} if nothing cached\n   */\n  CachedResponse get(HttpServletRequest request, GraphQLInvocationInput invocationInput);\n\n  /**\n   * Decide to cache or not this response. It depends on the implementation.\n   *\n   * @param request the http request\n   * @param invocationInput input data\n   */\n  boolean isCacheable(HttpServletRequest request, GraphQLInvocationInput invocationInput);\n\n  /**\n   * Cache this response. It depends on the implementation.\n   *\n   * @param request the http request\n   * @param invocationInput input data\n   * @param cachedResponse response to cache\n   */\n  void put(\n      HttpServletRequest request,\n      GraphQLInvocationInput invocationInput,\n      CachedResponse cachedResponse);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/config/DefaultGraphQLSchemaServletProvider.java",
    "content": "package graphql.kickstart.servlet.config;\n\nimport graphql.kickstart.execution.config.DefaultGraphQLSchemaProvider;\nimport graphql.schema.GraphQLSchema;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.websocket.server.HandshakeRequest;\n\n/** @author Andrew Potter */\npublic class DefaultGraphQLSchemaServletProvider extends DefaultGraphQLSchemaProvider\n    implements GraphQLSchemaServletProvider {\n\n  public DefaultGraphQLSchemaServletProvider(GraphQLSchema schema) {\n    super(schema);\n  }\n\n  @Override\n  public GraphQLSchema getSchema(HttpServletRequest request) {\n    return getSchema();\n  }\n\n  @Override\n  public GraphQLSchema getSchema(HandshakeRequest request) {\n    return getSchema();\n  }\n\n  @Override\n  public GraphQLSchema getReadOnlySchema(HttpServletRequest request) {\n    return getReadOnlySchema();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/config/GraphQLSchemaServletProvider.java",
    "content": "package graphql.kickstart.servlet.config;\n\nimport graphql.kickstart.execution.config.GraphQLSchemaProvider;\nimport graphql.schema.GraphQLSchema;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.websocket.server.HandshakeRequest;\n\npublic interface GraphQLSchemaServletProvider extends GraphQLSchemaProvider {\n\n  /**\n   * @param request the http request\n   * @return a schema based on the request (auth, etc).\n   */\n  GraphQLSchema getSchema(HttpServletRequest request);\n\n  /**\n   * @param request the http request used to create a websocket\n   * @return a schema based on the request (auth, etc).\n   */\n  GraphQLSchema getSchema(HandshakeRequest request);\n\n  /**\n   * @param request the http request\n   * @return a read-only schema based on the request (auth, etc). Should return the same schema\n   *     (query/subscription-only version) as {@link #getSchema(HttpServletRequest)} for a given\n   *     request.\n   */\n  GraphQLSchema getReadOnlySchema(HttpServletRequest request);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/DefaultGraphQLServletContext.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.DefaultGraphQLContext;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.Part;\nimport lombok.SneakyThrows;\nimport org.dataloader.DataLoaderRegistry;\n\n/** @deprecated Use {@link graphql.kickstart.execution.context.GraphQLKickstartContext} instead */\npublic class DefaultGraphQLServletContext extends DefaultGraphQLContext\n    implements GraphQLServletContext {\n\n  protected DefaultGraphQLServletContext(\n      DataLoaderRegistry dataLoaderRegistry,\n      HttpServletRequest httpServletRequest,\n      HttpServletResponse httpServletResponse) {\n    super(dataLoaderRegistry);\n    put(HttpServletRequest.class, httpServletRequest);\n    put(HttpServletResponse.class, httpServletResponse);\n  }\n\n  public static Builder createServletContext(DataLoaderRegistry registry) {\n    return new Builder(registry);\n  }\n\n  public static Builder createServletContext() {\n    return new Builder(new DataLoaderRegistry());\n  }\n\n  /**\n   * @deprecated Use {@code\n   *     dataFetchingEnvironment.getGraphQlContext().get(HttpServletRequest.class)} instead. Since\n   *     13.0.0\n   */\n  @Override\n  @Deprecated\n  public HttpServletRequest getHttpServletRequest() {\n    return (HttpServletRequest) getMapOfContext().get(HttpServletRequest.class);\n  }\n\n  /**\n   * @deprecated Use {@code\n   *     dataFetchingEnvironment.getGraphQlContext().get(HttpServletResponse.class)} instead. Since\n   *     13.0.0\n   */\n  @Override\n  @Deprecated\n  public HttpServletResponse getHttpServletResponse() {\n    return (HttpServletResponse) getMapOfContext().get(HttpServletResponse.class);\n  }\n\n  /**\n   * @deprecated Use {@code\n   *     dataFetchingEnvironment.getGraphQlContext().get(HttpServletRequest.class)} instead to get\n   *     the request and retrieve the file parts yourself. Since 13.0.0\n   */\n  @Override\n  @Deprecated\n  @SneakyThrows\n  public List<Part> getFileParts() {\n    return getHttpServletRequest().getParts().stream()\n        .filter(part -> part.getContentType() != null)\n        .collect(Collectors.toList());\n  }\n\n  /**\n   * @deprecated Use {@code\n   *     dataFetchingEnvironment.getGraphQlContext().get(HttpServletRequest.class)} instead to get\n   *     the request and retrieve the parts yourself. Since 13.0.0\n   */\n  @Override\n  @Deprecated\n  @SneakyThrows\n  public Map<String, List<Part>> getParts() {\n    return getHttpServletRequest().getParts().stream()\n        .collect(Collectors.groupingBy(Part::getName));\n  }\n\n  public static class Builder {\n\n    private HttpServletRequest httpServletRequest;\n    private HttpServletResponse httpServletResponse;\n    private DataLoaderRegistry dataLoaderRegistry;\n\n    private Builder(DataLoaderRegistry dataLoaderRegistry) {\n      this.dataLoaderRegistry = dataLoaderRegistry;\n    }\n\n    public DefaultGraphQLServletContext build() {\n      return new DefaultGraphQLServletContext(\n          dataLoaderRegistry, httpServletRequest, httpServletResponse);\n    }\n\n    public Builder with(HttpServletRequest httpServletRequest) {\n      this.httpServletRequest = httpServletRequest;\n      return this;\n    }\n\n    public Builder with(DataLoaderRegistry dataLoaderRegistry) {\n      this.dataLoaderRegistry = dataLoaderRegistry;\n      return this;\n    }\n\n    public Builder with(HttpServletResponse httpServletResponse) {\n      this.httpServletResponse = httpServletResponse;\n      return this;\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/DefaultGraphQLServletContextBuilder.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.DefaultGraphQLContextBuilder;\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport java.util.HashMap;\nimport java.util.Map;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\n\n/** Returns an empty context. */\npublic class DefaultGraphQLServletContextBuilder extends DefaultGraphQLContextBuilder\n    implements GraphQLServletContextBuilder {\n\n  @Override\n  public GraphQLKickstartContext build(HttpServletRequest request, HttpServletResponse response) {\n    Map<Object, Object> map = new HashMap<>();\n    map.put(HttpServletRequest.class, request);\n    map.put(HttpServletResponse.class, response);\n    return GraphQLKickstartContext.of(map);\n  }\n\n  @Override\n  public GraphQLKickstartContext build(Session session, HandshakeRequest handshakeRequest) {\n    Map<Object, Object> map = new HashMap<>();\n    map.put(Session.class, session);\n    map.put(HandshakeRequest.class, handshakeRequest);\n    return GraphQLKickstartContext.of(map);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/DefaultGraphQLWebSocketContext.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.DefaultGraphQLContext;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\nimport org.dataloader.DataLoaderRegistry;\n\n/** @deprecated Use {@link graphql.kickstart.execution.context.GraphQLKickstartContext} instead */\n@Deprecated\npublic class DefaultGraphQLWebSocketContext extends DefaultGraphQLContext\n    implements GraphQLWebSocketContext {\n\n  private DefaultGraphQLWebSocketContext(\n      DataLoaderRegistry dataLoaderRegistry, Session session, HandshakeRequest handshakeRequest) {\n    super(dataLoaderRegistry);\n    put(Session.class, session);\n    put(HandshakeRequest.class, handshakeRequest);\n  }\n\n  public static Builder createWebSocketContext(DataLoaderRegistry registry) {\n    return new Builder(registry);\n  }\n\n  public static Builder createWebSocketContext() {\n    return new Builder(new DataLoaderRegistry());\n  }\n\n  /**\n   * @deprecated Use {@code dataFetchingEnvironment.getGraphQlContext().get(Session.class)} instead.\n   *     Since 13.0.0\n   */\n  @Override\n  @Deprecated\n  public Session getSession() {\n    return (Session) getMapOfContext().get(Session.class);\n  }\n\n  /**\n   * @deprecated Use {@code dataFetchingEnvironment.getGraphQlContext().get(HandshakeRequest.class)}\n   *     instead. Since 13.0.0\n   */\n  @Override\n  @Deprecated\n  public HandshakeRequest getHandshakeRequest() {\n    return (HandshakeRequest) getMapOfContext().get(HandshakeRequest.class);\n  }\n\n  public static class Builder {\n\n    private Session session;\n    private HandshakeRequest handshakeRequest;\n    private DataLoaderRegistry dataLoaderRegistry;\n\n    private Builder(DataLoaderRegistry dataLoaderRegistry) {\n      this.dataLoaderRegistry = dataLoaderRegistry;\n    }\n\n    public DefaultGraphQLWebSocketContext build() {\n      return new DefaultGraphQLWebSocketContext(dataLoaderRegistry, session, handshakeRequest);\n    }\n\n    public Builder with(Session session) {\n      this.session = session;\n      return this;\n    }\n\n    public Builder with(HandshakeRequest handshakeRequest) {\n      this.handshakeRequest = handshakeRequest;\n      return this;\n    }\n\n    public Builder with(DataLoaderRegistry dataLoaderRegistry) {\n      this.dataLoaderRegistry = dataLoaderRegistry;\n      return this;\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/GraphQLServletContext.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport java.util.List;\nimport java.util.Map;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.Part;\n\n/** @deprecated Use {@link graphql.kickstart.execution.context.GraphQLKickstartContext} instead */\npublic interface GraphQLServletContext extends GraphQLKickstartContext {\n\n  List<Part> getFileParts();\n\n  Map<String, List<Part>> getParts();\n\n  HttpServletRequest getHttpServletRequest();\n\n  HttpServletResponse getHttpServletResponse();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/GraphQLServletContextBuilder.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport graphql.kickstart.execution.context.GraphQLContextBuilder;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\n\npublic interface GraphQLServletContextBuilder extends GraphQLContextBuilder {\n\n  GraphQLKickstartContext build(\n      HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse);\n\n  GraphQLKickstartContext build(Session session, HandshakeRequest handshakeRequest);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/context/GraphQLWebSocketContext.java",
    "content": "package graphql.kickstart.servlet.context;\n\nimport graphql.kickstart.execution.context.GraphQLKickstartContext;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\n\n/** @deprecated Use {@link graphql.kickstart.execution.context.GraphQLKickstartContext} instead */\npublic interface GraphQLWebSocketContext extends GraphQLKickstartContext {\n\n  Session getSession();\n\n  HandshakeRequest getHandshakeRequest();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/DefaultGraphQLRootObjectBuilder.java",
    "content": "package graphql.kickstart.servlet.core;\n\nimport graphql.kickstart.execution.StaticGraphQLRootObjectBuilder;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.websocket.server.HandshakeRequest;\n\npublic class DefaultGraphQLRootObjectBuilder extends StaticGraphQLRootObjectBuilder\n    implements GraphQLServletRootObjectBuilder {\n\n  public DefaultGraphQLRootObjectBuilder() {\n    super(new Object());\n  }\n\n  @Override\n  public Object build(HttpServletRequest req) {\n    return getRootObject();\n  }\n\n  @Override\n  public Object build(HandshakeRequest req) {\n    return getRootObject();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/GraphQLMBean.java",
    "content": "package graphql.kickstart.servlet.core;\n\npublic interface GraphQLMBean {\n\n  String[] getQueries();\n\n  String[] getMutations();\n\n  String executeQuery(String query);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/GraphQLServletListener.java",
    "content": "package graphql.kickstart.servlet.core;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\n/** @author Andrew Potter */\npublic interface GraphQLServletListener {\n\n  /**\n   * Called this method when the request started processing.\n   * @param request http request\n   * @param response http response\n   * @return request callback or {@literal null}\n   */\n  default RequestCallback onRequest(HttpServletRequest request, HttpServletResponse response) {\n    return null;\n  }\n\n  /**\n   * The callback which used to add additional listeners for GraphQL request execution.\n   */\n  interface RequestCallback {\n\n    /**\n     * Called when failed to parse InvocationInput and the response was not written.\n     * @param request http request\n     * @param response http response\n     */\n    default void onParseError(\n        HttpServletRequest request, HttpServletResponse response, Throwable throwable) {}\n\n    /**\n     * Called right before the response will be written and flushed. Can be used for applying some\n     * changes to the response object, like adding response headers.\n     * @param request http request\n     * @param response http response\n     */\n    default void beforeFlush(HttpServletRequest request, HttpServletResponse response) {}\n\n    /**\n     * Called when GraphQL invoked successfully and the response was written already.\n     * @param request http request\n     * @param response http response\n     */\n    default void onSuccess(HttpServletRequest request, HttpServletResponse response) {}\n\n    /**\n     * Called when GraphQL was failed and the response was written already.\n     * @param request http request\n     * @param response http response\n     */\n    default void onError(\n        HttpServletRequest request, HttpServletResponse response, Throwable throwable) {}\n\n    /**\n     * Called finally once on both success and failed GraphQL invocation. The response is also\n     * already written.\n     * @param request http request\n     * @param response http response\n     */\n    default void onFinally(HttpServletRequest request, HttpServletResponse response) {}\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/GraphQLServletRootObjectBuilder.java",
    "content": "package graphql.kickstart.servlet.core;\n\nimport graphql.kickstart.execution.GraphQLRootObjectBuilder;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.websocket.server.HandshakeRequest;\n\npublic interface GraphQLServletRootObjectBuilder extends GraphQLRootObjectBuilder {\n\n  Object build(HttpServletRequest req);\n\n  Object build(HandshakeRequest req);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/internal/GraphQLThreadFactory.java",
    "content": "package graphql.kickstart.servlet.core.internal;\n\nimport graphql.kickstart.servlet.AbstractGraphQLHttpServlet;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * {@link ThreadFactory} implementation for {@link AbstractGraphQLHttpServlet} async operations\n *\n * @author John Nutting\n */\npublic class GraphQLThreadFactory implements ThreadFactory {\n\n  static final String NAME_PREFIX = \"GraphQLServlet-\";\n  final AtomicInteger threadNumber = new AtomicInteger(1);\n\n  @Override\n  public Thread newThread(final Runnable r) {\n    Thread t = new Thread(r, NAME_PREFIX + threadNumber.getAndIncrement());\n    t.setDaemon(false);\n    t.setPriority(Thread.NORM_PRIORITY);\n    return t;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/internal/VariableMapException.java",
    "content": "package graphql.kickstart.servlet.core.internal;\n\npublic class VariableMapException extends RuntimeException {\n\n  VariableMapException(String message) {\n    super(message);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/core/internal/VariableMapper.java",
    "content": "package graphql.kickstart.servlet.core.internal;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\nimport jakarta.servlet.http.Part;\n\npublic class VariableMapper {\n\n  private static final Pattern PERIOD = Pattern.compile(\"\\\\.\");\n\n  private static final Mapper<Map<String, Object>> MAP_MAPPER =\n      new Mapper<Map<String, Object>>() {\n        @Override\n        public Object set(Map<String, Object> location, String target, Part value) {\n          return location.put(target, value);\n        }\n\n        @Override\n        public Object recurse(Map<String, Object> location, String target) {\n          return location.get(target);\n        }\n      };\n  private static final Mapper<List<Object>> LIST_MAPPER =\n      new Mapper<List<Object>>() {\n        @Override\n        public Object set(List<Object> location, String target, Part value) {\n          return location.set(Integer.parseInt(target), value);\n        }\n\n        @Override\n        public Object recurse(List<Object> location, String target) {\n          return location.get(Integer.parseInt(target));\n        }\n      };\n\n  @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n  public static void mapVariable(String objectPath, Map<String, Object> variables, Part part) {\n    String[] segments = PERIOD.split(objectPath);\n\n    if (segments.length < 2) {\n      throw new VariableMapException(\"object-path in map must have at least two segments\");\n    } else if (!\"variables\".equals(segments[0])) {\n      throw new VariableMapException(\"can only map into variables\");\n    }\n\n    Object currentLocation = variables;\n    for (int i = 1; i < segments.length; i++) {\n      String segmentName = segments[i];\n      Mapper mapper = determineMapper(currentLocation, objectPath, segmentName);\n\n      if (i == segments.length - 1) {\n        if (null != mapper.set(currentLocation, segmentName, part)) {\n          throw new VariableMapException(\"expected null value when mapping \" + objectPath);\n        }\n      } else {\n        currentLocation = mapper.recurse(currentLocation, segmentName);\n        if (null == currentLocation) {\n          throw new VariableMapException(\n              \"found null intermediate value when trying to map \" + objectPath);\n        }\n      }\n    }\n  }\n\n  private static Mapper<?> determineMapper(\n      Object currentLocation, String objectPath, String segmentName) {\n    if (currentLocation instanceof Map) {\n      return MAP_MAPPER;\n    } else if (currentLocation instanceof List) {\n      return LIST_MAPPER;\n    }\n\n    throw new VariableMapException(\n        \"expected a map or list at \" + segmentName + \" when trying to map \" + objectPath);\n  }\n\n  interface Mapper<T> {\n\n    Object set(T location, String target, Part value);\n\n    Object recurse(T location, String target);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/input/BatchInputPreProcessResult.java",
    "content": "package graphql.kickstart.servlet.input;\n\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\n\n/**\n * Wraps the result of pre processing a batch. Allows customization of the response code and message\n * if the batch isn't to be executed.\n */\npublic class BatchInputPreProcessResult {\n\n  private final GraphQLBatchedInvocationInput batchedInvocationInput;\n\n  private final int statusCode;\n\n  private final boolean executable;\n\n  private final String messsage;\n\n  public BatchInputPreProcessResult(GraphQLBatchedInvocationInput graphQLBatchedInvocationInput) {\n    this.batchedInvocationInput = graphQLBatchedInvocationInput;\n    this.executable = true;\n    this.statusCode = 200;\n    this.messsage = null;\n  }\n\n  public BatchInputPreProcessResult(int statusCode, String messsage) {\n    this.batchedInvocationInput = null;\n    this.executable = false;\n    this.statusCode = statusCode;\n    this.messsage = messsage;\n  }\n\n  /** @return If the servlet should try executing this batched input */\n  public boolean isExecutable() {\n    return executable;\n  }\n\n  /** @return the batched input the servlet will try to execute. */\n  public GraphQLBatchedInvocationInput getBatchedInvocationInput() {\n    return batchedInvocationInput;\n  }\n\n  /** @return status message the servlet will use if isExecutable is false. */\n  public String getStatusMessage() {\n    return messsage;\n  }\n\n  /** @return status code the servlet will use if if isExecutable is false. */\n  public int getStatusCode() {\n    return statusCode;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/input/BatchInputPreProcessor.java",
    "content": "package graphql.kickstart.servlet.input;\n\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic interface BatchInputPreProcessor {\n\n  /**\n   * An injectable object that allows clients to manipulate a batch before executing, or abort\n   * altogether.\n   *\n   * @param batchedInvocationInput the input to process\n   * @param request the servlet request\n   * @param response the servlet response\n   * @return wrapped batch to possibly process.\n   */\n  BatchInputPreProcessResult preProcessBatch(\n      GraphQLBatchedInvocationInput batchedInvocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/input/GraphQLInvocationInputFactory.java",
    "content": "package graphql.kickstart.servlet.input;\n\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.config.GraphQLSchemaProvider;\nimport graphql.kickstart.execution.context.ContextSetting;\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport graphql.kickstart.servlet.config.DefaultGraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.config.GraphQLSchemaServletProvider;\nimport graphql.kickstart.servlet.context.DefaultGraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder;\nimport graphql.kickstart.servlet.core.DefaultGraphQLRootObjectBuilder;\nimport graphql.kickstart.servlet.core.GraphQLServletRootObjectBuilder;\nimport graphql.schema.GraphQLSchema;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.HandshakeRequest;\n\n/** @author Andrew Potter */\npublic class GraphQLInvocationInputFactory implements GraphQLSubscriptionInvocationInputFactory {\n\n  private final Supplier<GraphQLSchemaServletProvider> schemaProviderSupplier;\n  private final Supplier<GraphQLServletContextBuilder> contextBuilderSupplier;\n  private final Supplier<GraphQLServletRootObjectBuilder> rootObjectBuilderSupplier;\n\n  protected GraphQLInvocationInputFactory(\n      Supplier<GraphQLSchemaServletProvider> schemaProviderSupplier,\n      Supplier<GraphQLServletContextBuilder> contextBuilderSupplier,\n      Supplier<GraphQLServletRootObjectBuilder> rootObjectBuilderSupplier) {\n    this.schemaProviderSupplier = schemaProviderSupplier;\n    this.contextBuilderSupplier = contextBuilderSupplier;\n    this.rootObjectBuilderSupplier = rootObjectBuilderSupplier;\n  }\n\n  public static Builder newBuilder(GraphQLSchema schema) {\n    return new Builder(new DefaultGraphQLSchemaServletProvider(schema));\n  }\n\n  public static Builder newBuilder(GraphQLSchemaServletProvider schemaProvider) {\n    return new Builder(schemaProvider);\n  }\n\n  public static Builder newBuilder(Supplier<GraphQLSchemaServletProvider> schemaProviderSupplier) {\n    return new Builder(schemaProviderSupplier);\n  }\n\n  public GraphQLSchemaProvider getSchemaProvider() {\n    return schemaProviderSupplier.get();\n  }\n\n  public GraphQLSingleInvocationInput create(\n      GraphQLRequest graphQLRequest, HttpServletRequest request, HttpServletResponse response) {\n    return create(graphQLRequest, request, response, false);\n  }\n\n  public GraphQLBatchedInvocationInput create(\n      ContextSetting contextSetting,\n      List<GraphQLRequest> graphQLRequests,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    return create(contextSetting, graphQLRequests, request, response, false);\n  }\n\n  public GraphQLSingleInvocationInput createReadOnly(\n      GraphQLRequest graphQLRequest, HttpServletRequest request, HttpServletResponse response) {\n    return create(graphQLRequest, request, response, true);\n  }\n\n  public GraphQLBatchedInvocationInput createReadOnly(\n      ContextSetting contextSetting,\n      List<GraphQLRequest> graphQLRequests,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    return create(contextSetting, graphQLRequests, request, response, true);\n  }\n\n  public GraphQLSingleInvocationInput create(GraphQLRequest graphQLRequest) {\n    return new GraphQLSingleInvocationInput(\n        graphQLRequest,\n        schemaProviderSupplier.get().getSchema(),\n        contextBuilderSupplier.get().build(),\n        rootObjectBuilderSupplier.get().build());\n  }\n\n  private GraphQLSingleInvocationInput create(\n      GraphQLRequest graphQLRequest,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      boolean readOnly) {\n    return new GraphQLSingleInvocationInput(\n        graphQLRequest,\n        readOnly\n            ? schemaProviderSupplier.get().getReadOnlySchema(request)\n            : schemaProviderSupplier.get().getSchema(request),\n        contextBuilderSupplier.get().build(request, response),\n        rootObjectBuilderSupplier.get().build(request));\n  }\n\n  private GraphQLBatchedInvocationInput create(\n      ContextSetting contextSetting,\n      List<GraphQLRequest> graphQLRequests,\n      HttpServletRequest request,\n      HttpServletResponse response,\n      boolean readOnly) {\n    return contextSetting.getBatch(\n        graphQLRequests,\n        readOnly\n            ? schemaProviderSupplier.get().getReadOnlySchema(request)\n            : schemaProviderSupplier.get().getSchema(request),\n        () -> contextBuilderSupplier.get().build(request, response),\n        rootObjectBuilderSupplier.get().build(request));\n  }\n\n  @Override\n  public GraphQLSingleInvocationInput create(\n      GraphQLRequest graphQLRequest, SubscriptionSession session) {\n    HandshakeRequest request =\n        (HandshakeRequest) session.getUserProperties().get(HandshakeRequest.class.getName());\n    return new GraphQLSingleInvocationInput(\n        graphQLRequest,\n        schemaProviderSupplier.get().getSchema(request),\n        contextBuilderSupplier.get().build((Session) session.unwrap(), request),\n        rootObjectBuilderSupplier.get().build(request));\n  }\n\n  public GraphQLBatchedInvocationInput create(\n      ContextSetting contextSetting, List<GraphQLRequest> graphQLRequest, Session session) {\n    HandshakeRequest request =\n        (HandshakeRequest) session.getUserProperties().get(HandshakeRequest.class.getName());\n    return contextSetting.getBatch(\n        graphQLRequest,\n        schemaProviderSupplier.get().getSchema(request),\n        () -> contextBuilderSupplier.get().build(session, request),\n        rootObjectBuilderSupplier.get().build(request));\n  }\n\n  public static class Builder {\n\n    private final Supplier<GraphQLSchemaServletProvider> schemaProviderSupplier;\n    private Supplier<GraphQLServletContextBuilder> contextBuilderSupplier =\n        DefaultGraphQLServletContextBuilder::new;\n    private Supplier<GraphQLServletRootObjectBuilder> rootObjectBuilderSupplier =\n        DefaultGraphQLRootObjectBuilder::new;\n\n    public Builder(GraphQLSchemaServletProvider schemaProvider) {\n      this(() -> schemaProvider);\n    }\n\n    public Builder(Supplier<GraphQLSchemaServletProvider> schemaProviderSupplier) {\n      this.schemaProviderSupplier = schemaProviderSupplier;\n    }\n\n    public Builder withGraphQLContextBuilder(GraphQLServletContextBuilder contextBuilder) {\n      return withGraphQLContextBuilder(() -> contextBuilder);\n    }\n\n    public Builder withGraphQLContextBuilder(\n        Supplier<GraphQLServletContextBuilder> contextBuilderSupplier) {\n      this.contextBuilderSupplier = contextBuilderSupplier;\n      return this;\n    }\n\n    public Builder withGraphQLRootObjectBuilder(GraphQLServletRootObjectBuilder rootObjectBuilder) {\n      return withGraphQLRootObjectBuilder(() -> rootObjectBuilder);\n    }\n\n    public Builder withGraphQLRootObjectBuilder(\n        Supplier<GraphQLServletRootObjectBuilder> rootObjectBuilderSupplier) {\n      this.rootObjectBuilderSupplier = rootObjectBuilderSupplier;\n      return this;\n    }\n\n    public GraphQLInvocationInputFactory build() {\n      return new GraphQLInvocationInputFactory(\n          schemaProviderSupplier, contextBuilderSupplier, rootObjectBuilderSupplier);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/input/NoOpBatchInputPreProcessor.java",
    "content": "package graphql.kickstart.servlet.input;\n\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\n/** A default BatchInputPreProcessor that returns the input. */\npublic class NoOpBatchInputPreProcessor implements BatchInputPreProcessor {\n\n  @Override\n  public BatchInputPreProcessResult preProcessBatch(\n      GraphQLBatchedInvocationInput batchedInvocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    return new BatchInputPreProcessResult(batchedInvocationInput);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLCodeRegistryProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLCodeRegistry;\n\npublic interface GraphQLCodeRegistryProvider extends GraphQLProvider {\n\n  GraphQLCodeRegistry getCodeRegistry();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLDirectiveProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLDirective;\nimport java.util.Collection;\n\n\npublic interface GraphQLDirectiveProvider extends GraphQLProvider {\n\n    /** @return A collection of directive definitions that will be added to the schema. */\n    Collection<GraphQLDirective> getDirectives();\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLFieldProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLFieldDefinition;\nimport java.util.Collection;\n\npublic interface GraphQLFieldProvider extends GraphQLProvider {\n\n  Collection<GraphQLFieldDefinition> getFields();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLMutationProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLFieldDefinition;\nimport java.util.Collection;\n\npublic interface GraphQLMutationProvider extends GraphQLFieldProvider {\n\n  Collection<GraphQLFieldDefinition> getMutations();\n\n  default Collection<GraphQLFieldDefinition> getFields() {\n    return getMutations();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\npublic interface GraphQLProvider {}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLQueryProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLFieldDefinition;\nimport java.util.Collection;\n\n/** This interface is used by OSGi bundles to plugin new field into the root query type */\npublic interface GraphQLQueryProvider extends GraphQLProvider {\n\n  /** @return a collection of field definitions that will be added to the root query type. */\n  Collection<GraphQLFieldDefinition> getQueries();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLSubscriptionProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLFieldDefinition;\nimport java.util.Collection;\n\npublic interface GraphQLSubscriptionProvider extends GraphQLFieldProvider {\n\n  Collection<GraphQLFieldDefinition> getSubscriptions();\n\n  default Collection<GraphQLFieldDefinition> getFields() {\n    return getSubscriptions();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/osgi/GraphQLTypesProvider.java",
    "content": "package graphql.kickstart.servlet.osgi;\n\nimport graphql.schema.GraphQLType;\nimport java.util.Collection;\n\npublic interface GraphQLTypesProvider extends GraphQLProvider {\n\n  Collection<GraphQLType> getTypes();\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/subscriptions/FallbackSubscriptionConsumer.java",
    "content": "package graphql.kickstart.servlet.subscriptions;\n\nimport graphql.ExecutionResult;\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.GraphQLRequest;\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.Objects;\nimport java.util.UUID;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\nimport lombok.RequiredArgsConstructor;\n\n/** @author Andrew Potter */\n@RequiredArgsConstructor\npublic class FallbackSubscriptionConsumer implements Consumer<String> {\n\n  private final SubscriptionSession session;\n  private final GraphQLSubscriptionMapper mapper;\n  private final GraphQLSubscriptionInvocationInputFactory invocationInputFactory;\n  private final GraphQLInvoker graphQLInvoker;\n\n  @Override\n  public void accept(String text) {\n    CompletableFuture<ExecutionResult> executionResult = executeAsync(text, session);\n    executionResult.thenAccept(\n        result -> handleSubscriptionStart(session, UUID.randomUUID().toString(), result));\n  }\n\n  private CompletableFuture<ExecutionResult> executeAsync(\n      String payload, SubscriptionSession session) {\n    Objects.requireNonNull(payload, \"Payload is required\");\n    GraphQLRequest graphQLRequest = mapper.readGraphQLRequest(payload);\n\n    GraphQLSingleInvocationInput invocationInput =\n        invocationInputFactory.create(graphQLRequest, session);\n    return graphQLInvoker.executeAsync(invocationInput);\n  }\n\n  private void handleSubscriptionStart(\n      SubscriptionSession session, String id, ExecutionResult executionResult) {\n    ExecutionResult sanitizedExecutionResult = mapper.sanitizeErrors(executionResult);\n    if (mapper.hasNoErrors(sanitizedExecutionResult)) {\n      session.subscribe(id, sanitizedExecutionResult.getData());\n    } else {\n      Object payload = mapper.convertSanitizedExecutionResult(sanitizedExecutionResult);\n      session.sendDataMessage(id, payload);\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/subscriptions/FallbackSubscriptionProtocolFactory.java",
    "content": "package graphql.kickstart.servlet.subscriptions;\n\nimport graphql.kickstart.execution.GraphQLInvoker;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionInvocationInputFactory;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport graphql.kickstart.execution.subscriptions.SubscriptionProtocolFactory;\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.function.Consumer;\nimport jakarta.websocket.Session;\n\n/** @author Andrew Potter */\npublic class FallbackSubscriptionProtocolFactory extends SubscriptionProtocolFactory\n    implements WebSocketSubscriptionProtocolFactory {\n\n  private final GraphQLSubscriptionMapper mapper;\n  private final GraphQLSubscriptionInvocationInputFactory invocationInputFactory;\n  private final GraphQLInvoker graphQLInvoker;\n\n  public FallbackSubscriptionProtocolFactory(\n      GraphQLSubscriptionMapper mapper,\n      GraphQLSubscriptionInvocationInputFactory invocationInputFactory,\n      GraphQLInvoker graphQLInvoker) {\n    super(\"\");\n    this.mapper = mapper;\n    this.invocationInputFactory = invocationInputFactory;\n    this.graphQLInvoker = graphQLInvoker;\n  }\n\n  @Override\n  public Consumer<String> createConsumer(SubscriptionSession session) {\n    return new FallbackSubscriptionConsumer(\n        session, mapper, invocationInputFactory, graphQLInvoker);\n  }\n\n  @Override\n  public SubscriptionSession createSession(Session session) {\n    return new WebSocketSubscriptionSession(mapper, session);\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/subscriptions/WebSocketSendSubscriber.java",
    "content": "package graphql.kickstart.servlet.subscriptions;\n\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicReference;\nimport jakarta.websocket.Session;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\n@Slf4j\n@RequiredArgsConstructor\npublic class WebSocketSendSubscriber implements Subscriber<String> {\n\n  private final Session session;\n  private AtomicReference<Subscription> subscriptionRef = new AtomicReference<>();\n\n  @Override\n  public void onSubscribe(Subscription subscription) {\n    subscriptionRef.set(subscription);\n    subscriptionRef.get().request(1);\n  }\n\n  @Override\n  public void onNext(String message) {\n    subscriptionRef.get().request(1);\n    if (session.isOpen()) {\n      try {\n        session.getBasicRemote().sendText(message);\n      } catch (IOException e) {\n        log.error(\"Cannot send message {}\", message, e);\n      }\n    }\n  }\n\n  @Override\n  public void onError(Throwable t) {\n    log.error(\"WebSocket error\", t);\n  }\n\n  @Override\n  public void onComplete() {\n    subscriptionRef.get().request(1);\n    if (session.isOpen()) {\n      try {\n        log.debug(\"Closing session\");\n        session.close();\n      } catch (IOException e) {\n        log.error(\"Cannot close session\", e);\n      }\n    }\n    subscriptionRef.get().cancel();\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/subscriptions/WebSocketSubscriptionProtocolFactory.java",
    "content": "package graphql.kickstart.servlet.subscriptions;\n\nimport graphql.kickstart.execution.subscriptions.SubscriptionSession;\nimport java.util.function.Consumer;\nimport jakarta.websocket.Session;\n\npublic interface WebSocketSubscriptionProtocolFactory {\n\n  Consumer<String> createConsumer(SubscriptionSession session);\n\n  SubscriptionSession createSession(Session session);\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/main/java/graphql/kickstart/servlet/subscriptions/WebSocketSubscriptionSession.java",
    "content": "package graphql.kickstart.servlet.subscriptions;\n\nimport graphql.kickstart.execution.subscriptions.DefaultSubscriptionSession;\nimport graphql.kickstart.execution.subscriptions.GraphQLSubscriptionMapper;\nimport java.util.Map;\nimport jakarta.websocket.Session;\n\npublic class WebSocketSubscriptionSession extends DefaultSubscriptionSession {\n\n  private final Session session;\n\n  public WebSocketSubscriptionSession(GraphQLSubscriptionMapper mapper, Session session) {\n    super(mapper);\n    this.session = session;\n  }\n\n  @Override\n  public boolean isOpen() {\n    return session.isOpen();\n  }\n\n  @Override\n  public Map<String, Object> getUserProperties() {\n    return session.getUserProperties();\n  }\n\n  @Override\n  public String getId() {\n    return session.getId();\n  }\n\n  @Override\n  public Session unwrap() {\n    return session;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/AbstractGraphQLHttpServletSpec.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.Scalars\nimport graphql.execution.ExecutionStepInfo\nimport graphql.execution.MergedField\nimport graphql.execution.reactive.SingleSubscriberPublisher\nimport graphql.kickstart.servlet.input.GraphQLInvocationInputFactory\nimport graphql.language.Field\nimport graphql.schema.GraphQLNonNull\nimport org.springframework.mock.web.MockHttpServletRequest\nimport org.springframework.mock.web.MockHttpServletResponse\nimport spock.lang.Shared\nimport spock.lang.Specification\n\nimport java.nio.charset.StandardCharsets\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicReference\n\n/**\n * @author Andrew Potter\n */\nclass AbstractGraphQLHttpServletSpec extends Specification {\n\n  public static final int STATUS_OK = 200\n  public static final int STATUS_BAD_REQUEST = 400\n  public static final int STATUS_ERROR = 500\n  public static final String CONTENT_TYPE_JSON_UTF8 = 'application/json;charset=UTF-8'\n  public static final String CONTENT_TYPE_SERVER_SENT_EVENTS = 'text/event-stream;charset=UTF-8'\n\n  @Shared\n  ObjectMapper mapper = new ObjectMapper()\n\n  AbstractGraphQLHttpServlet servlet\n  MockHttpServletRequest request\n  MockHttpServletResponse response\n  CountDownLatch subscriptionLatch\n\n  def setup() {\n    subscriptionLatch = new CountDownLatch(1)\n    servlet = TestUtils.createDefaultServlet({ env -> env.arguments.arg }, { env -> env.arguments.arg }, { env ->\n      AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n      publisherRef.set(new SingleSubscriberPublisher<String>({\n        SingleSubscriberPublisher<String> publisher = publisherRef.get()\n        publisher.offer(\"First\\n\\n\" + env.arguments.arg)\n        publisher.offer(\"Second\\n\\n\" + env.arguments.arg)\n        publisher.noMoreData()\n        subscriptionLatch.countDown()\n      }))\n      return publisherRef.get()\n    })\n\n    request = new MockHttpServletRequest()\n    request.setAsyncSupported(true)\n    request.asyncSupported = true\n    request.setMethod(\"GET\")\n    response = new MockHttpServletResponse()\n  }\n\n\n  Map<String, Object> getResponseContent() {\n    mapper.readValue(response.getContentAsByteArray(), Map)\n  }\n\n  List<Map<String, Object>> getSubscriptionResponseContent() {\n    String[] data = response.getContentAsString().split(\"\\n\\n\")\n    return data.collect { dataLine ->\n      if (dataLine.startsWith(\"data: \")) {\n        return mapper.readValue(dataLine.substring(5), Map)\n      } else {\n        throw new IllegalStateException(\"Could not read event stream\")\n      }\n    }\n  }\n\n  List<Map<String, Object>> getBatchedResponseContent() {\n    mapper.readValue(response.getContentAsByteArray(), List)\n  }\n\n  def \"HTTP GET without info returns bad request\"() {\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_BAD_REQUEST\n  }\n\n  def \"HTTP GET to /schema.json returns introspection query\"() {\n    setup:\n    request.setPathInfo('/schema.json')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.__schema != null\n  }\n\n  def \"query over HTTP GET returns data\"() {\n    setup:\n    request.addParameter('query', 'query { echo(arg:\"test\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    response.getContentLength() == mapper.writeValueAsString([\"data\": [\"echo\": \"test\"]]).getBytes(StandardCharsets.UTF_8).length\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP GET returns data with correct contentLength\"() {\n    setup:\n    request.addParameter('query', 'query { echo(arg:\"special char á\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    response.getContentLength() == mapper.writeValueAsString([\"data\": [\"echo\": \"special char á\"]]).getBytes(StandardCharsets.UTF_8).length\n    getResponseContent().data.echo == \"special char á\"\n  }\n\n  def \"disabling async support on request over HTTP GET does not start async request\"() {\n    setup:\n    servlet = TestUtils.createDefaultServlet({ env -> env.arguments.arg }, { env -> env.arguments.arg }, { env ->\n      AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n      publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n        publisherRef.get().offer((String) env.arguments.arg)\n        publisherRef.get().noMoreData()\n      }))\n      return publisherRef.get()\n    })\n    request.addParameter('query', 'query { echo(arg:\"test\") }')\n    request.setAsyncSupported(false)\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    request.asyncContext == null\n  }\n\n  def \"query over HTTP GET with variables returns data\"() {\n    setup:\n    request.addParameter('query', 'query Echo($arg: String) { echo(arg:$arg) }')\n    request.addParameter('variables', '{\"arg\": \"test\"}')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP GET with variables as string returns data\"() {\n    setup:\n    request.addParameter('query', 'query Echo($arg: String) { echo(arg:$arg) }')\n    request.addParameter('variables', '\"{\\\\\"arg\\\\\": \\\\\"test\\\\\"}\"')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP GET with operationName returns data\"() {\n    when:\n    response = new MockHttpServletResponse()\n    request.addParameter('query', 'query one{ echoOne: echo(arg:\"test-one\") } query two{ echoTwo: echo(arg:\"test-two\") }')\n    request.addParameter('operationName', 'two')\n    servlet.doGet(request, response)\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoOne == null\n    getResponseContent().data.echoTwo == \"test-two\"\n\n  }\n\n  def \"query over HTTP GET with empty non-null operationName returns data\"() {\n    when:\n    response = new MockHttpServletResponse()\n    request.addParameter('query', 'query echo{ echo: echo(arg:\"test\") }')\n    request.addParameter('operationName', '')\n    servlet.doGet(request, response)\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP GET with unknown property 'test' returns data\"() {\n    setup:\n    request.addParameter('query', 'query { echo(arg:\"test\") }')\n    request.addParameter('test', 'test')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET returns data\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET returns data with correct contentLength\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"special char á\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    response.getContentLength() == mapper.writeValueAsString([[\"data\": [\"echo\": \"special char á\"]], [\"data\": [\"echo\": \"test\"]]]).getBytes(StandardCharsets.UTF_8).length\n    getBatchedResponseContent()[0].data.echo == \"special char á\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET with variables returns data\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": { \"arg\": \"test\" } }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": { \"arg\": \"test\" } }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET with variables as string returns data\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": \"{ \\\\\"arg\\\\\": \\\\\"test\\\\\" }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": \"{ \\\\\"arg\\\\\": \\\\\"test\\\\\" }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET with operationName returns data\"() {\n    when:\n    response = new MockHttpServletResponse()\n    request.addParameter('query', '[{ \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"one\" }, { \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"two\" }]')\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echoOne == \"test-one\"\n    getBatchedResponseContent()[0].data.echoTwo == null\n    getBatchedResponseContent()[1].data.echoOne == null\n    getBatchedResponseContent()[1].data.echoTwo == \"test-two\"\n  }\n\n  def \"batched query over HTTP GET with empty non-null operationName returns data\"() {\n    when:\n    response = new MockHttpServletResponse()\n    request.addParameter('query', '[{ \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }, { \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }]')\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP GET with unknown property 'test' returns data\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"Batch Execution Handler allows limiting batches and sending error messages.\"() {\n    setup:\n    servlet = TestUtils.createBatchCustomizedServlet({ env -> env.arguments.arg }, { env -> env.arguments.arg }, { env ->\n      AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n      publisherRef.set(new SingleSubscriberPublisher<String>({\n        SingleSubscriberPublisher<String> publisher = publisherRef.get()\n        publisher.offer(\"First\\n\\n\" + env.arguments.arg)\n        publisher.offer(\"Second\\n\\n\" + env.arguments.arg)\n        publisher.noMoreData()\n        subscriptionLatch.countDown()\n      }))\n      return publisherRef.get()\n    })\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_BAD_REQUEST\n    response.getErrorMessage() == TestBatchInputPreProcessor.BATCH_ERROR_MESSAGE\n  }\n\n  def \"Default Execution Result Handler does not limit number of queries\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent().size() == 3\n  }\n\n  def \"mutation over HTTP GET returns errors\"() {\n    setup:\n    request.addParameter('query', 'mutation { echo(arg:\"test\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().errors.size() == 1\n  }\n\n  def \"batched mutation over HTTP GET returns errors\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"mutation { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"mutation {echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].errors.size() == 1\n    getBatchedResponseContent()[1].errors.size() == 1\n  }\n\n  def \"subscription query over HTTP GET with variables as string returns data\"() {\n    setup:\n    request.addParameter('query', 'subscription Subscription($arg: String!) { echo(arg: $arg) }')\n    request.addParameter('operationName', 'Subscription')\n    request.addParameter('variables', '{\"arg\": \"test\"}')\n    request.setAsyncSupported(true)\n\n    when:\n    servlet.doGet(request, response)\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_SERVER_SENT_EVENTS\n\n    when:\n    subscriptionLatch.await(1, TimeUnit.SECONDS)\n    then:\n    getSubscriptionResponseContent()[0].data.echo == \"First\\n\\ntest\"\n    getSubscriptionResponseContent()[1].data.echo == \"Second\\n\\ntest\"\n  }\n\n  def \"query over HTTP POST without part or body returns bad request\"() {\n    when:\n    request.setMethod(\"POST\")\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_BAD_REQUEST\n  }\n\n  def \"query over HTTP POST body returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query: 'query { echo(arg:\"test\") }'\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multiline body returns data\"() {\n    setup:\n    request.setContent(\"\"\"\n        query { object {\na\nb\n        } }\"\"\".bytes)\n    request.setMethod(\"POST\")\n    request.contentType = \"application/graphql\"\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.object.b == null\n  }\n\n  def \"disabling async support on request over HTTP POST does not start async request\"() {\n    setup:\n    servlet = TestUtils.createDefaultServlet({ env -> env.arguments.arg }, { env -> env.arguments.arg }, { env ->\n      AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n      publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n        publisherRef.get().offer((String) env.arguments.arg)\n        publisherRef.get().noMoreData()\n      }))\n      return publisherRef.get()\n    })\n    request.setContent(mapper.writeValueAsBytes([\n        query: 'query { echo(arg:\"test\") }'\n    ]))\n    request.setAsyncSupported(false)\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    request.asyncContext == null\n  }\n\n  def \"query over HTTP POST body with graphql contentType returns data\"() {\n    setup:\n    request.addHeader(\"Content-Type\", \"application/graphql\")\n    request.setContent('query { echo(arg:\"test\") }'.getBytes(\"UTF-8\"))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST body with variables returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query    : 'query Echo($arg: String) { echo(arg:$arg) }',\n        variables: '{\"arg\": \"test\"}'\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST body with operationName returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query        : 'query one{ echoOne: echo(arg:\"test-one\") } query two{ echoTwo: echo(arg:\"test-two\") }',\n        operationName: 'two'\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoOne == null\n    getResponseContent().data.echoTwo == \"test-two\"\n  }\n\n  def \"query over HTTP POST body with empty non-null operationName returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query        : 'query echo{ echo: echo(arg:\"test\") }',\n        operationName: ''\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST body with unknown property 'test' returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query: 'query { echo(arg:\"test\") }',\n        test : 'test'\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'graphql' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=---test\")\n    request.setMethod(\"POST\")\n\n    request.addPart(TestMultipartContentBuilder.createPart('graphql', mapper.writeValueAsString([query: 'query { echo(arg:\"test\") }'])))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'query' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', 'query { echo(arg:\"test\") }'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'query' with operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', 'query one{ echoOne: echo(arg:\"test-one\") } query two{ echoTwo: echo(arg:\"test-two\") }'))\n    request.addPart(TestMultipartContentBuilder.createPart('operationName', 'two'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoOne == null\n    getResponseContent().data.echoTwo == \"test-two\"\n  }\n\n  def \"query over HTTP POST multipart named 'query' with empty non-null operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', 'query echo{ echo: echo(arg:\"test\") }'))\n    request.addPart(TestMultipartContentBuilder.createPart('operationName', ''))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'query' with variables returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', 'query Echo($arg: String) { echo(arg:$arg) }'))\n    request.addPart(TestMultipartContentBuilder.createPart('variables', '{\"arg\": \"test\"}'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'query' with unknown property 'test' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', 'query { echo(arg:\"test\") }'))\n    request.addPart(TestMultipartContentBuilder.createPart('test', 'test'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"query { echo(arg:\\\\\"test\\\\\") }\"}'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' with operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"two\"}'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoOne == null\n    getResponseContent().data.echoTwo == \"test-two\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' with empty non-null operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' with variables returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"query Echo($arg: String) { echo(arg:$arg) }\", \"variables\": {\"arg\": \"test\"} }'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' with unknown property 'test' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\\\"query\\\": \\\"query { echo(arg:\\\\\"test\\\\\") }\\\"}'))\n    request.addPart(TestMultipartContentBuilder.createPart('test', 'test'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' will interpolate variables from map\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"mutation test($file: Upload!) { echoFile(file: $file) }\", \"variables\": { \"file\": null }}'))\n    request.addPart(TestMultipartContentBuilder.createPart('map', '{\"0\": [\"variables.file\"]}'))\n    request.addPart(TestMultipartContentBuilder.createPart('0', 'test'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoFile == \"test\"\n  }\n\n  def \"query over HTTP POST multipart named 'operations' will interpolate variable list from map\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '{\"query\": \"mutation test($files: [Upload!]!) { echoFiles(files: $files) }\", \"variables\": { \"files\": [null, null] }}'))\n    request.addPart(TestMultipartContentBuilder.createPart('map', '{\"0\": [\"variables.files.0\"], \"1\": [\"variables.files.1\"]}'))\n    request.addPart(TestMultipartContentBuilder.createPart('0', 'test'))\n    request.addPart(TestMultipartContentBuilder.createPart('1', 'test again'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echoFiles == [\"test\", \"test again\"]\n  }\n\n  def \"errors while accessing file from the request\"() {\n    setup:\n    request = Spy(MockHttpServletRequest)\n    request.setMethod(\"POST\")\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    // See https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/connector/Request.java#L2775...L2791\n    request.getParts() >> { throw new IllegalStateException() }\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_BAD_REQUEST\n    response.getContentLength() == 0\n  }\n\n  def \"batched query over HTTP POST body returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    response.getContentLength() == mapper.writeValueAsString([[\"data\": [\"echo\": \"test\"]], [\"data\": [\"echo\": \"test\"]]]).length()\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST body with variables returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": { \"arg\": \"test\" } }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"variables\": { \"arg\": \"test\" } }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST body with operationName returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"one\" }, { \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"two\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echoOne == \"test-one\"\n    getBatchedResponseContent()[0].data.echoTwo == null\n    getBatchedResponseContent()[1].data.echoOne == null\n    getBatchedResponseContent()[1].data.echoTwo == \"test-two\"\n  }\n\n  def \"batched query over HTTP POST body with empty non-null operationName returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }, { \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST body with unknown property 'test' returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'graphql' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n\n    request.addPart(TestMultipartContentBuilder.createPart('graphql', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'graphql' with unknown property 'test' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n\n    request.addPart(TestMultipartContentBuilder.createPart('graphql', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'query' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'query' with operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', '[{ \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"one\" }, { \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"two\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echoOne == \"test-one\"\n    getBatchedResponseContent()[0].data.echoTwo == null\n    getBatchedResponseContent()[1].data.echoOne == null\n    getBatchedResponseContent()[1].data.echoTwo == \"test-two\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'query' with empty non-null operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', '[{ \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }, { \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'query' with variables returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', '[{ \"query\": \"query echo($arg: String) { echo(arg:$arg) }\", \"variables\": { \"arg\": \"test\" } }, { \"query\": \"query echo($arg: String) { echo(arg:$arg) }\", \"variables\": { \"arg\": \"test\" } }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'query' with unknown property 'test' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'operations' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'operations' with unknown property 'test' returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'operations' with operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '[{ \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"one\" }, { \"query\": \"query one{ echoOne: echo(arg:\\\\\"test-one\\\\\") } query two{ echoTwo: echo(arg:\\\\\"test-two\\\\\") }\", \"operationName\": \"two\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echoOne == \"test-one\"\n    getBatchedResponseContent()[0].data.echoTwo == null\n    getBatchedResponseContent()[1].data.echoOne == null\n    getBatchedResponseContent()[1].data.echoTwo == \"test-two\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'operations' with empty non-null operationName returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '[{ \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }, { \"query\": \"query echo{ echo: echo(arg:\\\\\"test\\\\\") }\", \"operationName\": \"\" }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched query over HTTP POST multipart named 'operations' with variables returns data\"() {\n    setup:\n    request.setContentType(\"multipart/form-data, boundary=test\")\n    request.setMethod(\"POST\")\n    request.addPart(TestMultipartContentBuilder.createPart('operations', '[{ \"query\": \"query echo($arg: String) { echo(arg:$arg) }\", \"variables\": { \"arg\": \"test\" } }, { \"query\": \"query echo($arg: String) { echo(arg:$arg) }\", \"variables\": { \"arg\": \"test\" } }]'))\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"mutation over HTTP POST body returns data\"() {\n    setup:\n    request.setContent(mapper.writeValueAsBytes([\n        query: 'mutation { echo(arg:\"test\") }'\n    ]))\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getResponseContent().data.echo == \"test\"\n  }\n\n  def \"batched mutation over HTTP POST body returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"mutation { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"mutation { echo(arg:\\\\\"test\\\\\") }\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"batched mutation over HTTP POST body with unknown property 'test' returns data\"() {\n    setup:\n    request.setContent('[{ \"query\": \"mutation { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }, { \"query\": \"mutation { echo(arg:\\\\\"test\\\\\") }\", \"test\": \"test\" }]'.bytes)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.echo == \"test\"\n    getBatchedResponseContent()[1].data.echo == \"test\"\n  }\n\n  def \"subscription query over HTTP POST with variables as string returns data\"() {\n    setup:\n    request.setContent('{\"query\": \"subscription Subscription($arg: String!) { echo(arg: $arg) }\", \"operationName\": \"Subscription\", \"variables\": {\"arg\": \"test\"}}'.bytes)\n    request.setAsyncSupported(true)\n    request.setMethod(\"POST\")\n\n    when:\n    servlet.doPost(request, response)\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_SERVER_SENT_EVENTS\n\n    when:\n    subscriptionLatch.await(1, TimeUnit.SECONDS)\n    then:\n    getSubscriptionResponseContent()[0].data.echo == \"First\\n\\ntest\"\n    getSubscriptionResponseContent()[1].data.echo == \"Second\\n\\ntest\"\n  }\n\n  def \"errors before graphql schema execution return internal server error\"() {\n    setup:\n    GraphQLConfiguration configuration = GraphQLConfiguration.with(GraphQLInvocationInputFactory.newBuilder {\n      throw new TestException()\n    }.build()).build()\n    servlet = GraphQLHttpServlet.with(configuration)\n    servlet.init()\n\n    request.setPathInfo('/schema.json')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_BAD_REQUEST\n  }\n\n  def \"errors while data fetching are masked in the response\"() {\n    setup:\n    servlet = TestUtils.createDefaultServlet({ throw new TestException() })\n    request.addParameter('query', 'query { echo(arg:\"test\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    def errors = getResponseContent().errors\n    errors.size() == 1\n    errors.first().message.startsWith(\"Internal Server Error(s)\")\n  }\n\n  def \"errors that also implement GraphQLError thrown while data fetching are passed to caller\"() {\n    setup:\n    servlet = TestUtils.createDefaultServlet({ throw new TestGraphQLErrorException(\"This is a test message\") })\n    request.addParameter('query', 'query { echo(arg:\"test\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    def errors = getResponseContent().errors\n    errors.size() == 1\n    errors.first().extensions.foo == \"bar\"\n    errors.first().message.startsWith(\"Exception while fetching data (/echo) : This is a test message\")\n  }\n\n  def \"batched errors while data fetching are masked in the response\"() {\n    setup:\n    servlet = TestUtils.createDefaultServlet({ throw new TestException() })\n    request.addParameter('query', '[{ \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { echo(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    def errors = getBatchedResponseContent().errors\n    errors[0].size() == 1\n    errors[0].first().message.startsWith(\"Internal Server Error(s)\")\n    errors[1].size() == 1\n    errors[1].first().message.startsWith(\"Internal Server Error(s)\")\n  }\n\n  def \"data field is present and null if no data can be returned\"() {\n    setup:\n    request.addParameter('query', 'query { not-a-field(arg:\"test\") }')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    def resp = getResponseContent()\n    resp.containsKey(\"data\")\n    resp.data == null\n    resp.errors != null\n  }\n\n  def \"batched data field is present and null if no data can be returned\"() {\n    setup:\n    request.addParameter('query', '[{ \"query\": \"query { not-a-field(arg:\\\\\"test\\\\\") }\" }, { \"query\": \"query { not-a-field(arg:\\\\\"test\\\\\") }\" }]')\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    def resp = getBatchedResponseContent()\n    resp[0].containsKey(\"data\")\n    resp[0].data == null\n    resp[0].errors != null\n    resp[1].containsKey(\"data\")\n    resp[1].data == null\n    resp[1].errors != null\n  }\n\n  def \"typeInfo is serialized correctly\"() {\n    setup:\n    MergedField field = MergedField.newMergedField().addField(new Field(\"test\")).build()\n    ExecutionStepInfo stepInfo = ExecutionStepInfo.newExecutionStepInfo().field(field).type(new GraphQLNonNull(Scalars.GraphQLString)).build()\n\n    expect:\n    servlet.getConfiguration().getObjectMapper().getJacksonMapper().writeValueAsString(stepInfo) != \"{}\"\n  }\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/BatchedQueryResponseWriterTest.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.ExecutionResultImpl\nimport graphql.kickstart.execution.GraphQLObjectMapper\nimport spock.lang.Specification\nimport spock.lang.Unroll\n\nimport jakarta.servlet.ServletOutputStream\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\nimport java.nio.charset.StandardCharsets\n\nclass BatchedQueryResponseWriterTest extends Specification {\n\n  @Unroll\n  def \"should write utf8 results into the response with content #result\"() {\n    given:\n    def byteArrayOutputStream = new ByteArrayOutputStream()\n    def graphQLObjectMapperMock = GraphQLObjectMapper.newBuilder().withObjectMapperProvider({ new ObjectMapper() }).build()\n    graphQLObjectMapperMock.getJacksonMapper() >> new ObjectMapper()\n\n    def requestMock = Mock(HttpServletRequest)\n    def responseMock = Mock(HttpServletResponse)\n    def servletOutputStreamMock = Mock(ServletOutputStream)\n\n    responseMock.getOutputStream() >> servletOutputStreamMock\n\n    1 * responseMock.setContentLength(expectedContentLengh)\n    1 * responseMock.setCharacterEncoding(StandardCharsets.UTF_8.name())\n    (1.._) * servletOutputStreamMock.write(_) >> { value ->\n      byteArrayOutputStream.write((byte[]) (value[0]))\n    }\n\n    def executionResultList = new ArrayList()\n    for (LinkedHashMap<Object, Object> value : result) {\n      executionResultList.add(new ExecutionResultImpl(value, []))\n    }\n\n    def writer = new BatchedQueryResponseWriter(executionResultList, graphQLObjectMapperMock)\n\n    when:\n    writer.write(requestMock, responseMock)\n\n    then:\n    byteArrayOutputStream.toString(StandardCharsets.UTF_8.name()) == expectedResponseContent\n\n    where:\n    result                      || expectedContentLengh | expectedResponseContent\n    [[testValue: \"abcde\"]]      || 32                   | \"\"\"[{\"data\":{\"testValue\":\"abcde\"}}]\"\"\"\n    [[testValue: \"äöüüöß\"]]     || 39                   | \"\"\"[{\"data\":{\"testValue\":\"äöüüöß\"}}]\"\"\"\n    []                          || 2                    | \"\"\"[]\"\"\"\n    [[k1: \"äöüüöß\"], [k2: \"a\"]] || 52                   | \"\"\"[{\"data\":{\"k1\":\"äöüüöß\"}},{\"data\":{\"k2\":\"a\"}}]\"\"\"\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/DataLoaderDispatchingSpec.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.execution.instrumentation.ChainedInstrumentation\nimport graphql.execution.instrumentation.Instrumentation\nimport graphql.execution.instrumentation.SimplePerformantInstrumentation\nimport graphql.kickstart.execution.context.ContextSetting\nimport graphql.kickstart.execution.context.DefaultGraphQLContext\nimport graphql.kickstart.execution.context.GraphQLKickstartContext\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder\nimport graphql.schema.DataFetcher\nimport graphql.schema.DataFetchingEnvironment\nimport org.dataloader.BatchLoader\nimport org.dataloader.DataLoaderFactory\nimport org.dataloader.DataLoaderRegistry\nimport org.springframework.mock.web.MockHttpServletRequest\nimport org.springframework.mock.web.MockHttpServletResponse\nimport spock.lang.Shared\nimport spock.lang.Specification\n\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\nimport jakarta.websocket.Session\nimport jakarta.websocket.server.HandshakeRequest\nimport java.util.concurrent.CompletableFuture\nimport java.util.concurrent.CompletionStage\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass DataLoaderDispatchingSpec extends Specification {\n\n  public static final int STATUS_OK = 200\n  public static final String CONTENT_TYPE_JSON_UTF8 = 'application/json;charset=UTF-8'\n\n  @Shared\n  ObjectMapper mapper = new ObjectMapper()\n\n  AbstractGraphQLHttpServlet servlet\n  MockHttpServletRequest request\n  MockHttpServletResponse response\n  AtomicInteger fetchCounterA = new AtomicInteger()\n  AtomicInteger loadCounterA = new AtomicInteger()\n  AtomicInteger fetchCounterB = new AtomicInteger()\n  AtomicInteger loadCounterB = new AtomicInteger()\n  AtomicInteger fetchCounterC = new AtomicInteger()\n  AtomicInteger loadCounterC = new AtomicInteger()\n\n  BatchLoader<String, String> batchLoaderWithCounter(AtomicInteger fetchCounter) {\n    return new BatchLoader<String, String>() {\n      @Override\n      CompletionStage<List<String>> load(List<String> keys) {\n        fetchCounter.incrementAndGet()\n        CompletableFuture.completedFuture(keys)\n      }\n    }\n  }\n\n  def registry() {\n    DataLoaderRegistry registry = new DataLoaderRegistry()\n    registry.register(\"A\", DataLoaderFactory.newDataLoader(batchLoaderWithCounter(fetchCounterA)))\n    registry.register(\"B\", DataLoaderFactory.newDataLoader(batchLoaderWithCounter(fetchCounterB)))\n    registry.register(\"C\", DataLoaderFactory.newDataLoader(batchLoaderWithCounter(fetchCounterC)))\n    registry\n  }\n\n  def setup() {\n    request = new MockHttpServletRequest()\n    request.setAsyncSupported(true)\n    request.asyncSupported = true\n    response = new MockHttpServletResponse()\n  }\n\n  def queryDataFetcher(String dataLoaderName, AtomicInteger loadCounter) {\n    return new DataFetcher() {\n      @Override\n      Object get(DataFetchingEnvironment environment) {\n        String id = environment.arguments.arg\n        loadCounter.incrementAndGet()\n        environment.getDataLoader(dataLoaderName).load(id)\n      }\n    }\n  }\n\n  def contextBuilder() {\n    return new GraphQLServletContextBuilder() {\n      @Override\n      GraphQLKickstartContext build(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {\n        new DefaultGraphQLContext(registry())\n      }\n\n      @Override\n      GraphQLKickstartContext build(Session session, HandshakeRequest handshakeRequest) {\n        new DefaultGraphQLContext(registry())\n      }\n\n      @Override\n      GraphQLKickstartContext build() {\n        new DefaultGraphQLContext(registry())\n      }\n    }\n  }\n\n  def configureServlet(ContextSetting contextSetting) {\n    servlet = TestUtils.createDataLoadingServlet(queryDataFetcher(\"A\", loadCounterA),\n        queryDataFetcher(\"B\", loadCounterB), queryDataFetcher(\"C\", loadCounterC)\n        , contextSetting,\n        contextBuilder())\n  }\n\n  def resetCounters() {\n    fetchCounterA.set(0)\n    fetchCounterB.set(0)\n    loadCounterA.set(0)\n    loadCounterB.set(0)\n  }\n\n  List<Map<String, Object>> getBatchedResponseContent() {\n    mapper.readValue(response.getContentAsByteArray(), List)\n  }\n\n  def \"batched query with per query context does not batch loads together\"() {\n    setup:\n    configureServlet(ContextSetting.PER_QUERY)\n    request.addParameter('query', '[{ \"query\": \"query { query(arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\") } }}\" }, { \"query\": \"query{query(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\")} }}\" },' +\n        ' { \"query\": \"query{queryTwo(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\")}}\" }, { \"query\": \"query{queryTwo(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\")}}\" }]')\n    resetCounters()\n    request.setMethod(\"GET\")\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.query.echo.echo == \"test\"\n    getBatchedResponseContent()[1].data.query.echo.echo == \"test\"\n    getBatchedResponseContent()[2].data.queryTwo.echo == \"test\"\n    getBatchedResponseContent()[3].data.queryTwo.echo == \"test\"\n    fetchCounterA.get() == 2\n    loadCounterA.get() == 2\n    fetchCounterB.get() == 2\n    loadCounterB.get() == 2\n    fetchCounterC.get() == 2\n    loadCounterC.get() == 2\n  }\n\n  def \"batched query with per request context batches all queries within the request\"() {\n    setup:\n    servlet = configureServlet(ContextSetting.PER_REQUEST)\n    request.addParameter('query', '[{ \"query\": \"query { query(arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\") } }}\" }, { \"query\": \"query{query(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\") { echo(arg:\\\\\"test\\\\\")} }}\" },' +\n        ' { \"query\": \"query{queryTwo(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\")}}\" }, { \"query\": \"query{queryTwo(arg:\\\\\"test\\\\\") { echo (arg:\\\\\"test\\\\\")}}\" }]')\n    resetCounters()\n    request.setMethod(\"GET\")\n\n    when:\n    servlet.doGet(request, response)\n\n    then:\n    response.getStatus() == STATUS_OK\n    response.getContentType() == CONTENT_TYPE_JSON_UTF8\n    getBatchedResponseContent()[0].data.query.echo.echo == \"test\"\n    getBatchedResponseContent()[1].data.query.echo.echo == \"test\"\n    getBatchedResponseContent()[2].data.queryTwo.echo == \"test\"\n    getBatchedResponseContent()[3].data.queryTwo.echo == \"test\"\n    fetchCounterA.get() == 1\n    loadCounterA.get() == 2\n    fetchCounterB.get() == 1\n    loadCounterB.get() == 2\n    fetchCounterC.get() == 1\n    loadCounterC.get() == 2\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/GraphQLServletListenerSpec.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport graphql.kickstart.servlet.core.GraphQLServletListener\nimport spock.lang.Specification\n\nclass GraphQLServletListenerSpec extends Specification {\n\n  def listener = Mock(GraphQLServletListener)\n  def requestCallback = Mock(GraphQLServletListener.RequestCallback)\n  def tester = new RequestTester(listener)\n\n  def \"query over HTTP GET calls onRequest listener\"() {\n    given: \"a valid graphql query request\"\n    tester.addParameter('query', 'query { echo(arg:\"test\") }')\n\n    and: \"a listener that always returns request callback\"\n    listener.onRequest(tester.request, tester.response) >> requestCallback\n\n    when: \"we execute a GET request\"\n    tester.doGet()\n\n    then:\n    tester.assertThatResponseIsOk()\n    tester.assertThatContentTypeIsJson()\n    1 * listener.onRequest(tester.request, tester.response)\n  }\n\n  def \"query over HTTP GET calls onSuccess callback\"() {\n    given: \"a valid graphql query request\"\n    tester.addParameter('query', 'query { echo(arg:\"test\") }')\n\n    and: \"a listener that always returns request callback\"\n    listener.onRequest(tester.request, tester.response) >> requestCallback\n\n    when: \"we execute a GET request\"\n    tester.doGet()\n\n    then:\n    tester.assertThatResponseIsOk()\n    tester.assertThatContentTypeIsJson()\n    1 * requestCallback.onSuccess(tester.request, tester.response)\n  }\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/OsgiGraphQLHttpServletSpec.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport graphql.AssertException\nimport graphql.annotations.annotationTypes.GraphQLField\nimport graphql.annotations.annotationTypes.GraphQLName\nimport graphql.annotations.processor.GraphQLAnnotations\nimport graphql.execution.instrumentation.InstrumentationState\nimport graphql.execution.instrumentation.SimplePerformantInstrumentation\nimport graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters\nimport graphql.introspection.Introspection\nimport graphql.kickstart.execution.GraphQLRequest\nimport graphql.kickstart.execution.config.ExecutionStrategyProvider\nimport graphql.kickstart.execution.config.InstrumentationProvider\nimport graphql.kickstart.execution.context.DefaultGraphQLContext\nimport graphql.kickstart.execution.context.GraphQLKickstartContext\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder\nimport graphql.kickstart.servlet.core.GraphQLServletListener\nimport graphql.kickstart.servlet.core.GraphQLServletRootObjectBuilder\nimport graphql.kickstart.servlet.osgi.*\nimport graphql.schema.*\nimport org.dataloader.DataLoaderRegistry\nimport spock.lang.Specification\n\nimport static graphql.Scalars.GraphQLInt\nimport static graphql.schema.GraphQLFieldDefinition.newFieldDefinition\n\nclass OsgiGraphQLHttpServletSpec extends Specification {\n\n  static class TestQueryProvider implements GraphQLQueryProvider {\n\n    @Override\n    Collection<GraphQLFieldDefinition> getQueries() {\n      List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<>()\n      fieldDefinitions.add(newFieldDefinition()\n          .name(\"query\")\n          .type(new GraphQLAnnotations().object(Query.class))\n          .staticValue(new Query())\n          .build())\n      return fieldDefinitions\n    }\n\n    @GraphQLName(\"query\")\n    static class Query {\n      @GraphQLField\n      public String field\n    }\n\n  }\n\n  def \"query provider adds query objects\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    TestQueryProvider queryProvider = new TestQueryProvider()\n    servlet.bindQueryProvider(queryProvider)\n    GraphQLFieldDefinition query\n\n    when:\n    query = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getQueryType().getFieldDefinition(\"query\")\n    then:\n    query.getType().name == \"query\"\n\n    when:\n    query = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getQueryType().getFieldDefinition(\"query\")\n    then:\n    query.getType().name == \"query\"\n\n    when:\n    servlet.unbindQueryProvider(queryProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getQueryType().getFieldDefinitions().get(0).name == \"_empty\"\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getQueryType().getFieldDefinitions().get(0).name == \"_empty\"\n  }\n\n  static class TestMutationProvider implements GraphQLMutationProvider {\n    @Override\n    Collection<GraphQLFieldDefinition> getMutations() {\n      return Collections.singletonList(newFieldDefinition().name(\"int\").type(GraphQLInt).staticValue(1).build())\n    }\n  }\n\n  def \"mutation provider adds mutation objects\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    TestMutationProvider mutationProvider = new TestMutationProvider()\n\n    when:\n    servlet.bindMutationProvider(mutationProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getMutationType().getFieldDefinition(\"int\").getType() == GraphQLInt\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getMutationType() == null\n\n    when:\n    servlet.unbindMutationProvider(mutationProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getMutationType() == null\n\n    when:\n    servlet.bindProvider(mutationProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getMutationType().getFieldDefinition(\"int\").getType() == GraphQLInt\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getMutationType() == null\n\n    when:\n    servlet.unbindProvider(mutationProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getMutationType() == null\n  }\n\n  static class TestSubscriptionProvider implements GraphQLSubscriptionProvider {\n    @Override\n    Collection<GraphQLFieldDefinition> getSubscriptions() {\n      return Collections.singletonList(newFieldDefinition().name(\"subscription\").type(new GraphQLAnnotations().object(Subscription.class)).build())\n    }\n\n    @GraphQLName(\"subscription\")\n    static class Subscription {\n      @GraphQLField\n      public String field\n    }\n  }\n\n  def \"subscription provider adds subscription objects\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    TestSubscriptionProvider subscriptionProvider = new TestSubscriptionProvider()\n    servlet.bindSubscriptionProvider(subscriptionProvider)\n    GraphQLFieldDefinition subscription\n\n    when:\n    subscription = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getSubscriptionType().getFieldDefinition(\"subscription\")\n    then:\n    subscription.getType().getName() == \"subscription\"\n\n    when:\n    subscription = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getSubscriptionType().getFieldDefinition(\"subscription\")\n    then:\n    subscription.getType().getName() == \"subscription\"\n\n    when:\n    servlet.unbindSubscriptionProvider(subscriptionProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getSubscriptionType() == null\n\n    when:\n    servlet.bindProvider(subscriptionProvider)\n    then:\n    def subscription2 = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getSubscriptionType().getFieldDefinition(\"subscription\")\n    subscription2.getType().getName() == \"subscription\"\n\n    when:\n    servlet.unbindProvider(subscriptionProvider)\n    then:\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getSubscriptionType() == null\n  }\n\n  static class TestCodeRegistryProvider implements GraphQLCodeRegistryProvider {\n    @Override\n    GraphQLCodeRegistry getCodeRegistry() {\n      return GraphQLCodeRegistry.newCodeRegistry().typeResolver(\"Type\", { env -> null }).build()\n    }\n  }\n\n  def \"code registry provider adds type resolver\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    TestCodeRegistryProvider codeRegistryProvider = new TestCodeRegistryProvider()\n\n    when:\n    servlet.bindCodeRegistryProvider(codeRegistryProvider)\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getCodeRegistry().getTypeResolver(GraphQLInterfaceType.newInterface().name(\"Type\").build())\n    then:\n    notThrown AssertException\n\n    when:\n    servlet.unbindCodeRegistryProvider(codeRegistryProvider)\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getCodeRegistry().getTypeResolver(GraphQLInterfaceType.newInterface().name(\"Type\").build())\n    then:\n    thrown AssertException\n\n    when:\n    servlet.bindProvider(codeRegistryProvider)\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getCodeRegistry().getTypeResolver(GraphQLInterfaceType.newInterface().name(\"Type\").build())\n    then:\n    notThrown AssertException\n\n    when:\n    servlet.unbindProvider(codeRegistryProvider)\n    servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getCodeRegistry().getTypeResolver(GraphQLInterfaceType.newInterface().name(\"Type\").build())\n    then:\n    thrown AssertException\n  }\n\n  def \"schema update delay throws no exception\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    def config = Mock(OsgiGraphQLHttpServlet.Config)\n\n    when:\n    config.schema_update_delay() >> 1\n    servlet.activate(config)\n    servlet.updateSchema()\n    servlet.updateSchema()\n    servlet.deactivate()\n\n    then:\n    noExceptionThrown()\n  }\n\n  def \"bind query provider adds query objects\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def queryProvider = new TestQueryProvider()\n    def query\n\n    when:\n    servlet.bindProvider(queryProvider)\n    query = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getQueryType().getFieldDefinition(\"query\")\n\n    then:\n    query.getType().name == \"query\"\n\n    when:\n    query = servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getReadOnlySchema().getQueryType().getFieldDefinition(\"query\")\n\n    then:\n    query.getType().name == \"query\"\n\n    when:\n    servlet.unbindProvider(queryProvider)\n    then:\n    null != servlet.getConfiguration().getInvocationInputFactory().getSchemaProvider().getSchema().getQueryType().getFieldDefinition(\"_empty\")\n  }\n\n  def \"type provider adds types\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def typesProvider = Mock(GraphQLTypesProvider)\n    def coercing = Mock(Coercing)\n    typesProvider.types >> [GraphQLScalarType.newScalar().name(\"Upload\").coercing(coercing).build()]\n\n    when:\n    servlet.bindTypesProvider(typesProvider)\n\n    then:\n    def type = servlet.configuration.invocationInputFactory.schemaProvider.schema.getType(\"Upload\")\n    type != null\n    type.name == \"Upload\"\n    type instanceof GraphQLScalarType\n    def scalarType = (GraphQLScalarType) type\n    scalarType.coercing == coercing\n\n    when:\n    servlet.unbindTypesProvider(typesProvider)\n\n    then:\n    null == servlet.configuration.invocationInputFactory.schemaProvider.schema.getType(\"Upload\")\n\n    when:\n    servlet.bindProvider(typesProvider)\n    then:\n    servlet.configuration.invocationInputFactory.schemaProvider.schema.getType(\"Upload\").name == \"Upload\"\n\n    when:\n    servlet.unbindProvider(typesProvider)\n    then:\n    null == servlet.configuration.invocationInputFactory.schemaProvider.schema.getType(\"Upload\")\n  }\n\n  static class TestDirectiveProvider implements GraphQLDirectiveProvider {\n    @Override\n    Set<GraphQLDirective> getDirectives() {\n      return new HashSet<>(Arrays.asList(GraphQLDirective.newDirective().name(\"myDirective\").validLocation(Introspection.DirectiveLocation.FIELD).build()));\n    }\n  }\n\n  def \"directive provider adds directives\"() {\n    setup:\n    OsgiGraphQLHttpServlet servlet = new OsgiGraphQLHttpServlet()\n    TestDirectiveProvider directiveProvider = new TestDirectiveProvider()\n\n    when:\n    servlet.bindDirectivesProvider(directiveProvider)\n\n    then:\n    def directive = servlet.configuration.invocationInputFactory.schemaProvider.schema.getDirective(\"myDirective\")\n    directive != null\n    directive.name == \"myDirective\"\n\n    when:\n    servlet.unbindDirectivesProvider(directiveProvider)\n\n    then:\n    null == servlet.configuration.invocationInputFactory.schemaProvider.schema.getDirective(\"myDirective\")\n\n    when:\n    servlet.bindProvider(directiveProvider)\n    then:\n    servlet.configuration.invocationInputFactory.schemaProvider.schema.getDirective(\"myDirective\").name == \"myDirective\"\n\n    when:\n    servlet.unbindProvider(directiveProvider)\n    then:\n    null == servlet.configuration.invocationInputFactory.schemaProvider.schema.getType(\"myDirective\")\n  }\n\n  def \"servlet listener is bound and unbound\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def listener = Mock(GraphQLServletListener)\n\n    when:\n    servlet.bindServletListener(listener)\n    then:\n    servlet.configuration.listeners.contains(listener)\n\n    when:\n    servlet.unbindServletListener(listener)\n    then:\n    !servlet.configuration.listeners.contains(listener)\n  }\n\n  def \"context builder is bound and unbound\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def context = Mock(GraphQLKickstartContext)\n    context.getDataLoaderRegistry() >> new DataLoaderRegistry()\n    context.getMapOfContext() >> new HashMap<Object, Object>()\n    def contextBuilder = Mock(GraphQLServletContextBuilder)\n    contextBuilder.build() >> context\n    def request = GraphQLRequest.createIntrospectionRequest()\n\n    when:\n    servlet.setContextBuilder(contextBuilder)\n    then:\n    def invocationInput = servlet.configuration.invocationInputFactory.create(request)\n    invocationInput.executionInput.context == context\n\n    when:\n    servlet.unsetContextBuilder(contextBuilder)\n    then:\n    servlet.configuration.invocationInputFactory.create(request).executionInput.context instanceof DefaultGraphQLContext\n  }\n\n  def \"root object builder is bound and unbound\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def rootObject = Mock(Object)\n    def rootObjectBuilder = Mock(GraphQLServletRootObjectBuilder)\n    rootObjectBuilder.build() >> rootObject\n    def request = GraphQLRequest.createIntrospectionRequest()\n\n    when:\n    servlet.setRootObjectBuilder(rootObjectBuilder)\n    then:\n    def invocationInput = servlet.configuration.invocationInputFactory.create(request)\n    invocationInput.executionInput.root == rootObject\n\n    when:\n    servlet.unsetRootObjectBuilder(rootObjectBuilder)\n    then:\n    servlet.configuration.invocationInputFactory.create(request).executionInput.root != rootObject\n  }\n\n  def \"execution strategy is bound and unbound\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def executionStrategy = Mock(ExecutionStrategyProvider)\n    def request = GraphQLRequest.createIntrospectionRequest()\n\n    when:\n    servlet.setExecutionStrategyProvider(executionStrategy)\n    def invocationInput = servlet.configuration.invocationInputFactory.create(request)\n    servlet.configuration.graphQLInvoker.query(invocationInput)\n\n    then:\n    1 * executionStrategy.getQueryExecutionStrategy()\n\n    when:\n    servlet.unsetExecutionStrategyProvider(executionStrategy)\n    def invocationInput2 = servlet.configuration.invocationInputFactory.create(request)\n    servlet.configuration.graphQLInvoker.query(invocationInput2)\n\n    then:\n    0 * executionStrategy.getQueryExecutionStrategy()\n  }\n\n  def \"instrumentation provider is bound and unbound\"() {\n    setup:\n    def servlet = new OsgiGraphQLHttpServlet()\n    def instrumentation = new SimplePerformantInstrumentation()\n    def instrumentationProvider = Mock(InstrumentationProvider)\n    instrumentationProvider.getInstrumentation() >> instrumentation\n    def request = GraphQLRequest.createIntrospectionRequest()\n    instrumentation.createState(_ as InstrumentationCreateStateParameters) >> Mock(InstrumentationState)\n\n    when:\n    servlet.setInstrumentationProvider(instrumentationProvider)\n    def invocationInput = servlet.configuration.invocationInputFactory.create(request)\n    servlet.configuration.graphQLInvoker.query(invocationInput)\n\n    then:\n    noExceptionThrown()\n\n    when:\n    servlet.unsetInstrumentationProvider(instrumentationProvider)\n    then:\n    noExceptionThrown()\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/PartIOExceptionTest.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport spock.lang.Specification\n\nclass PartIOExceptionTest extends Specification {\n\n  def \"constructs\"() {\n    when:\n    def e = new PartIOException(\"some message\", new IOException())\n    then:\n    e instanceof RuntimeException\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/RequestTester.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.execution.reactive.SingleSubscriberPublisher\nimport graphql.kickstart.servlet.core.GraphQLServletListener\nimport org.springframework.mock.web.MockHttpServletRequest\nimport org.springframework.mock.web.MockHttpServletResponse\nimport spock.lang.Shared\n\nimport java.util.concurrent.CountDownLatch\nimport java.util.concurrent.atomic.AtomicReference\n\nclass RequestTester {\n\n  public static final int STATUS_OK = 200\n  public static final int STATUS_BAD_REQUEST = 400\n  public static final int STATUS_ERROR = 500\n  public static final String CONTENT_TYPE_JSON_UTF8 = 'application/json;charset=UTF-8'\n  public static final String CONTENT_TYPE_SERVER_SENT_EVENTS = 'text/event-stream;charset=UTF-8'\n\n  @Shared\n  ObjectMapper mapper = new ObjectMapper()\n\n  AbstractGraphQLHttpServlet servlet\n  MockHttpServletRequest request\n  MockHttpServletResponse response\n  CountDownLatch subscriptionLatch\n\n  RequestTester(GraphQLServletListener... listeners) {\n    subscriptionLatch = new CountDownLatch(1)\n    servlet = TestUtils.createDefaultServlet(\n        { env -> env.arguments.arg },\n        { env -> env.arguments.arg },\n        { env ->\n          AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n          publisherRef.set(new SingleSubscriberPublisher<String>({\n            SingleSubscriberPublisher<String> publisher = publisherRef.get()\n            publisher.offer(\"First\\n\\n\" + env.arguments.arg)\n            publisher.offer(\"Second\\n\\n\" + env.arguments.arg)\n            publisher.noMoreData()\n            subscriptionLatch.countDown()\n          }))\n          return publisherRef.get()\n        },\n        listeners)\n\n    request = new MockHttpServletRequest()\n    request.asyncSupported = true\n    request.method = \"GET\"\n    response = new MockHttpServletResponse()\n  }\n\n  Map<String, Object> getResponseContent() {\n    mapper.readValue(response.getContentAsByteArray(), Map)\n  }\n\n  def addParameter(String name, String value) {\n    request.addParameter(name, value)\n  }\n\n  def doGet() {\n    servlet.doGet(request, response)\n  }\n\n  def assertThatResponseIsOk() {\n    return response.getStatus() == STATUS_OK\n  }\n\n  def assertThatContentTypeIsJson() {\n    return response.getContentType() == CONTENT_TYPE_JSON_UTF8\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/SingleAsynchronousQueryResponseWriterTest.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport graphql.ExecutionResult\nimport graphql.kickstart.execution.GraphQLObjectMapper\nimport org.springframework.mock.web.MockAsyncContext\nimport spock.lang.Specification\n\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\n\nclass SingleAsynchronousQueryResponseWriterTest extends Specification {\n\n  def \"result data is no publisher should\"() {\n    given:\n    def result = Mock(ExecutionResult)\n    def objectMapper = Mock(GraphQLObjectMapper)\n    def writer = new SingleAsynchronousQueryResponseWriter(result, objectMapper, 100)\n    def request = Mock(HttpServletRequest)\n    def responseWriter = new PrintWriter(new StringWriter())\n    def response = Mock(HttpServletResponse)\n    response.getWriter() >> responseWriter\n    def asyncContext = new MockAsyncContext(request, response)\n    request.getAsyncContext() >> asyncContext\n    request.isAsyncStarted() >> true\n    objectMapper.serializeResultAsJson(result) >> \"{ }\"\n\n    when:\n    writer.write(request, response)\n\n    then:\n    noExceptionThrown()\n  }\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/SingleQueryResponseWriterTest.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport graphql.ExecutionResultImpl\nimport graphql.kickstart.execution.GraphQLObjectMapper\nimport spock.lang.Specification\nimport spock.lang.Unroll\n\nimport jakarta.servlet.ServletOutputStream\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\nimport java.nio.charset.StandardCharsets\n\nclass SingleQueryResponseWriterTest extends Specification {\n\n  @Unroll\n  def \"should write utf8 results into the response with content #result\"() {\n    given:\n    def graphQLObjectMapperMock = GraphQLObjectMapper.newBuilder().withObjectMapperProvider({ new ObjectMapper() }).build()\n    graphQLObjectMapperMock.getJacksonMapper() >> new ObjectMapper()\n\n    def requestMock = Mock(HttpServletRequest)\n    def responseMock = Mock(HttpServletResponse)\n    responseMock.getOutputStream() >> Mock(ServletOutputStream)\n\n    1 * responseMock.setContentLength(expectedContentLenght)\n    1 * responseMock.setCharacterEncoding(StandardCharsets.UTF_8.name())\n    1 * responseMock.getOutputStream().write(expectedResponseContent.getBytes(StandardCharsets.UTF_8))\n\n    expect:\n    def writer = new SingleQueryResponseWriter(new ExecutionResultImpl(result, []), graphQLObjectMapperMock)\n    writer.write(requestMock, responseMock)\n\n    where:\n    result                || expectedContentLenght | expectedResponseContent\n    [testValue: \"abcde\"]  || 30                    | \"\"\"{\"data\":{\"testValue\":\"abcde\"}}\"\"\"\n    [testValue: \"äöüüöß\"] || 37                    | \"\"\"{\"data\":{\"testValue\":\"äöüüöß\"}}\"\"\"\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestBatchInputPreProcessor.java",
    "content": "package graphql.kickstart.servlet;\n\nimport graphql.kickstart.execution.input.GraphQLBatchedInvocationInput;\nimport graphql.kickstart.servlet.input.BatchInputPreProcessResult;\nimport graphql.kickstart.servlet.input.BatchInputPreProcessor;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic class TestBatchInputPreProcessor implements BatchInputPreProcessor {\n\n  public static String BATCH_ERROR_MESSAGE = \"Batch limit exceeded\";\n\n  @Override\n  public BatchInputPreProcessResult preProcessBatch(\n      GraphQLBatchedInvocationInput batchedInvocationInput,\n      HttpServletRequest request,\n      HttpServletResponse response) {\n    BatchInputPreProcessResult preProcessResult;\n    if (batchedInvocationInput.getExecutionInputs().size() > 2) {\n      preProcessResult = new BatchInputPreProcessResult(400, BATCH_ERROR_MESSAGE);\n    } else {\n      preProcessResult = new BatchInputPreProcessResult(batchedInvocationInput);\n    }\n    return preProcessResult;\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestException.groovy",
    "content": "package graphql.kickstart.servlet\n\n/**\n * @author Andrew Potter\n */\nclass TestException extends RuntimeException {\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestGraphQLErrorException.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport graphql.ErrorType\nimport graphql.GraphQLError\nimport graphql.language.SourceLocation\n\n/**\n * @author Andrew Potter\n */\nclass TestGraphQLErrorException extends RuntimeException implements GraphQLError {\n\n  TestGraphQLErrorException(String message) {\n    super(message)\n  }\n\n  @Override\n  Map<String, Object> getExtensions() {\n    Map<String, Object> customAttributes = new LinkedHashMap<>()\n    customAttributes.put(\"foo\", \"bar\")\n    return customAttributes\n  }\n\n  @Override\n  List<SourceLocation> getLocations() {\n    return null\n  }\n\n  @Override\n  ErrorType getErrorType() {\n    return ErrorType.ValidationError\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestMultipartPart.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport jakarta.servlet.http.Part\n\n/**\n * @author Andrew Potter\n */\nclass TestMultipartContentBuilder {\n\n  static Part createPart(String name, String part) {\n    return new MockPart(name, part)\n  }\n\n  static class MockPart implements Part {\n    final String name\n    final String content\n\n    MockPart(String name, String content) {\n      this.name = name\n      this.content = content\n    }\n\n    @Override\n    InputStream getInputStream() throws IOException {\n      return new ByteArrayInputStream(content.getBytes())\n    }\n\n    @Override\n    String getContentType() {\n      return null\n    }\n\n    @Override\n    String getName() {\n      return name\n    }\n\n    @Override\n    String getSubmittedFileName() {\n      return name\n    }\n\n    @Override\n    long getSize() {\n      return content.getBytes().length\n    }\n\n    @Override\n    void write(String fileName) throws IOException {\n      throw new IllegalArgumentException(\"Not supported\")\n    }\n\n    @Override\n    void delete() throws IOException {\n      throw new IllegalArgumentException(\"Not supported\")\n    }\n\n    @Override\n    String getHeader(String name) {\n      return null\n    }\n\n    @Override\n    Collection<String> getHeaders(String name) {\n      return Collections.emptyList()\n    }\n\n    @Override\n    Collection<String> getHeaderNames() {\n      return Collections.emptyList()\n    }\n  }\n\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/TestUtils.groovy",
    "content": "package graphql.kickstart.servlet\n\nimport com.google.common.io.ByteStreams\nimport graphql.Scalars\nimport graphql.execution.reactive.SingleSubscriberPublisher\nimport graphql.kickstart.execution.context.ContextSetting\nimport graphql.kickstart.servlet.apollo.ApolloScalars\nimport graphql.kickstart.servlet.context.GraphQLServletContextBuilder\nimport graphql.kickstart.servlet.core.GraphQLServletListener\nimport graphql.kickstart.servlet.input.BatchInputPreProcessor\nimport graphql.schema.*\nimport graphql.schema.idl.RuntimeWiring\nimport graphql.schema.idl.SchemaGenerator\nimport graphql.schema.idl.SchemaParser\nimport graphql.schema.idl.TypeRuntimeWiring\nimport graphql.schema.idl.errors.SchemaProblem\nimport lombok.NonNull\n\nimport java.util.concurrent.Executor\nimport java.util.concurrent.atomic.AtomicReference\n\nclass TestUtils {\n\n  static def createDefaultServlet(\n      DataFetcher queryDataFetcher = { env -> env.arguments.arg },\n      DataFetcher mutationDataFetcher = { env -> env.arguments.arg },\n      DataFetcher subscriptionDataFetcher = { env ->\n        AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n        publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n          publisherRef.get().offer(env.arguments.arg)\n          publisherRef.get().noMoreData()\n        }))\n        return publisherRef.get()\n      },\n      GraphQLServletListener... listeners) {\n    createServlet(queryDataFetcher, mutationDataFetcher, subscriptionDataFetcher, null, listeners)\n  }\n\n  static def createBatchCustomizedServlet(\n      DataFetcher queryDataFetcher = { env -> env.arguments.arg },\n      DataFetcher mutationDataFetcher = { env -> env.arguments.arg },\n      DataFetcher subscriptionDataFetcher = { env ->\n        AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n        publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n          publisherRef.get().offer(env.arguments.arg)\n          publisherRef.get().noMoreData()\n        }))\n        return publisherRef.get()\n      }) {\n    createServlet(queryDataFetcher, mutationDataFetcher, subscriptionDataFetcher, createBatchExecutionHandler())\n  }\n\n  static def createDataLoadingServlet(\n      DataFetcher queryDataFetcher = { env -> env.arguments.arg },\n      DataFetcher fieldDataFetcher = { env -> env.arguments.arg },\n      DataFetcher otherDataFetcher,\n      ContextSetting contextSetting, GraphQLServletContextBuilder contextBuilder) {\n    GraphQLSchema schema = createGraphQlSchemaWithTwoLevels(queryDataFetcher, fieldDataFetcher, otherDataFetcher)\n    GraphQLHttpServlet servlet = GraphQLHttpServlet.with(GraphQLConfiguration\n        .with(schema)\n        .with(contextSetting)\n        .with(contextBuilder)\n        .with(executor())\n        .build())\n    servlet.init()\n    return servlet\n  }\n\n  private static def createServlet(\n      DataFetcher queryDataFetcher = { env -> env.arguments.arg },\n      DataFetcher mutationDataFetcher = { env -> env.arguments.arg },\n      DataFetcher subscriptionDataFetcher = { env ->\n        AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n        publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n          publisherRef.get().offer(env.arguments.arg)\n          publisherRef.get().noMoreData()\n        }))\n        return publisherRef.get()\n      },\n      BatchInputPreProcessor batchHandler,\n      GraphQLServletListener... listeners) {\n    GraphQLHttpServlet servlet = GraphQLHttpServlet.with(\n        graphQLConfiguration(\n            createGraphQlSchema(queryDataFetcher, mutationDataFetcher, subscriptionDataFetcher),\n            batchHandler,\n            listeners\n        )\n    )\n    servlet.init()\n    return servlet\n  }\n\n  static def graphQLConfiguration(GraphQLSchema schema, BatchInputPreProcessor batchInputPreProcessor, GraphQLServletListener... listeners) {\n    def configBuilder = GraphQLConfiguration.with(schema)\n    if (batchInputPreProcessor != null) {\n      configBuilder.with(batchInputPreProcessor)\n    }\n    if (listeners != null) {\n      configBuilder.with(Arrays.asList(listeners))\n    }\n    configBuilder.with(executor());\n    configBuilder.build()\n  }\n\n  private static Executor executor() {\n    new Executor() {\n      @Override\n      void execute(@NonNull Runnable command) {\n        command.run()\n      }\n    }\n  }\n\n  static def createBatchExecutionHandler() {\n    new TestBatchInputPreProcessor()\n  }\n\n  static def createGraphQlSchema(\n      DataFetcher queryDataFetcher = { env -> env.arguments.arg },\n      DataFetcher mutationDataFetcher = { env -> env.arguments.arg },\n      DataFetcher subscriptionDataFetcher = { env ->\n        AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()\n        publisherRef.set(new SingleSubscriberPublisher<>({ subscription ->\n          publisherRef.get().offer(env.arguments.arg)\n          publisherRef.get().noMoreData()\n        }))\n        return publisherRef.get()\n      }) {\n    GraphQLObjectType query = GraphQLObjectType.newObject()\n        .name(\"Query\")\n        .field { GraphQLFieldDefinition.Builder field ->\n          field.name(\"echo\")\n          field.type(Scalars.GraphQLString)\n          field.argument { argument ->\n            argument.name(\"arg\")\n            argument.type(Scalars.GraphQLString)\n          }\n          field.dataFetcher(queryDataFetcher)\n        }\n        .field { GraphQLFieldDefinition.Builder field ->\n          field.name(\"object\")\n          field.type(\n              GraphQLObjectType.newObject()\n                  .name(\"NestedObject\")\n                  .field { nested ->\n                    nested.name(\"a\")\n                    nested.type(Scalars.GraphQLString)\n                    nested.argument { argument ->\n                      argument.name(\"arg\")\n                      argument.type(Scalars.GraphQLString)\n                    }\n                    nested.dataFetcher(queryDataFetcher)\n                  }\n                  .field { nested ->\n                    nested.name(\"b\")\n                    nested.type(Scalars.GraphQLString)\n                    nested.argument { argument ->\n                      argument.name(\"arg\")\n                      argument.type(Scalars.GraphQLString)\n                    }\n                    nested.dataFetcher(queryDataFetcher)\n                  }\n          )\n          field.dataFetcher(new StaticDataFetcher([:]))\n        }\n        .field { GraphQLFieldDefinition.Builder field ->\n          field.name(\"returnsNullIncorrectly\")\n          field.type(new GraphQLNonNull(Scalars.GraphQLString))\n          field.dataFetcher({ env -> null })\n        }\n        .build()\n\n    GraphQLObjectType mutation = GraphQLObjectType.newObject()\n        .name(\"Mutation\")\n        .field { field ->\n          field.name(\"echo\")\n          field.type(Scalars.GraphQLString)\n          field.argument { argument ->\n            argument.name(\"arg\")\n            argument.type(Scalars.GraphQLString)\n          }\n          field.dataFetcher(mutationDataFetcher)\n        }\n        .field { field ->\n          field.name(\"echoFile\")\n          field.type(Scalars.GraphQLString)\n          field.argument { argument ->\n            argument.name(\"file\")\n            argument.type(ApolloScalars.Upload)\n          }\n          field.dataFetcher({ env -> new String(ByteStreams.toByteArray(env.arguments.file.getInputStream())) })\n        }\n        .field { field ->\n          field.name(\"echoFiles\")\n          field.type(GraphQLList.list(Scalars.GraphQLString))\n          field.argument { argument ->\n            argument.name(\"files\")\n            argument.type(GraphQLList.list(GraphQLNonNull.nonNull(ApolloScalars.Upload)))\n          }\n          field.dataFetcher({ env ->\n            env.arguments.files.collect {\n              new String(ByteStreams.toByteArray(it.getInputStream()))\n            }\n          })\n        }\n        .build()\n\n    GraphQLObjectType subscription = GraphQLObjectType.newObject()\n        .name(\"Subscription\")\n        .field { field ->\n          field.name(\"echo\")\n          field.type(Scalars.GraphQLString)\n          field.argument { argument ->\n            argument.name(\"arg\")\n            argument.type(Scalars.GraphQLString)\n          }\n          field.dataFetcher(subscriptionDataFetcher)\n        }\n        .build()\n\n\n    return GraphQLSchema.newSchema()\n        .query(query)\n        .mutation(mutation)\n        .subscription(subscription)\n        .additionalType(ApolloScalars.Upload)\n        .build()\n  }\n\n  static def createGraphQlSchemaWithTwoLevels(DataFetcher queryDataFetcher, DataFetcher fieldDataFetcher, DataFetcher otherQueryFetcher) {\n    String sdl = \"\"\"schema {\n                        query: Query\n                    }\n\n                    type Query{\n                            query(arg : String): QueryEcho\n                            queryTwo(arg: String): OtherQueryEcho\n                    }\n                        \n                    type QueryEcho {\n                        echo(arg: String): FieldEcho\n                    }\n                    \n                    type OtherQueryEcho {\n                        echo(arg: String): String\n                    }\n                    \n                    type FieldEcho {\n                        echo(arg:String): String\n                    }\n                    \"\"\"\n\n    def wiring = RuntimeWiring.newRuntimeWiring()\n        .type(TypeRuntimeWiring.newTypeWiring(\"Query\").dataFetcher(\"query\", { env -> env.arguments.arg })\n            .dataFetcher(\"queryTwo\", { env -> env.arguments.arg }))\n        .type(TypeRuntimeWiring.newTypeWiring(\"QueryEcho\").dataFetcher(\"echo\", queryDataFetcher))\n        .type(TypeRuntimeWiring.newTypeWiring(\"FieldEcho\").dataFetcher(\"echo\", fieldDataFetcher))\n        .type(TypeRuntimeWiring.newTypeWiring(\"OtherQueryEcho\").dataFetcher(\"echo\", otherQueryFetcher))\n        .build()\n\n\n    try {\n      def registry = new SchemaParser().parse(new StringReader(sdl))\n      def options = SchemaGenerator.Options.defaultOptions()\n      return new SchemaGenerator().makeExecutableSchema(options, registry, wiring)\n    } catch (SchemaProblem e) {\n      assert false: \"The schema could not be compiled : ${e}\"\n      return null\n    }\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/cache/CacheReaderTest.groovy",
    "content": "package graphql.kickstart.servlet.cache\n\nimport graphql.kickstart.execution.input.GraphQLInvocationInput\nimport spock.lang.Specification\n\nimport jakarta.servlet.ServletOutputStream\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\n\nclass CacheReaderTest extends Specification {\n\n  def cacheManager\n  def invocationInput\n  def request\n  def response\n  def cacheReader\n  def cachedResponse\n\n  def setup() {\n    cacheManager = Mock(GraphQLResponseCacheManager)\n    invocationInput = Mock(GraphQLInvocationInput)\n    request = Mock(HttpServletRequest)\n    response = Mock(HttpServletResponse)\n    cacheReader = new CacheReader()\n    cachedResponse = Mock(CachedResponse)\n  }\n\n  def \"should return false if no cached response\"() {\n    given:\n    cacheManager.get(request, invocationInput) >> null\n\n    when:\n    def result = cacheReader.responseFromCache(invocationInput, request, response, cacheManager)\n\n    then:\n    !result\n  }\n\n  def \"should send error response if cached response is error\"() {\n    given:\n    cachedResponse.isError() >> true\n    cachedResponse.getErrorStatusCode() >> 10\n    cachedResponse.getErrorMessage() >> \"some error\"\n    cacheManager.get(request, invocationInput) >> cachedResponse\n\n    when:\n    def result = cacheReader.responseFromCache(invocationInput, request, response, cacheManager)\n\n    then:\n    result\n    1 * response.sendError(10, \"some error\")\n  }\n\n  def \"should send success response if cached response is ok\"() {\n    given:\n    def outputStream = Mock(ServletOutputStream)\n    cachedResponse.isError() >> false\n    cachedResponse.getContentBytes() >> [00, 01, 02]\n    response.getOutputStream() >> outputStream\n    cacheManager.get(request, invocationInput) >> cachedResponse\n\n    when:\n    def result = cacheReader.responseFromCache(invocationInput, request, response, cacheManager)\n\n    then:\n    result\n    1 * response.setContentType(\"application/json;charset=UTF-8\")\n    1 * response.setStatus(200)\n    1 * response.setCharacterEncoding(\"UTF-8\")\n    1 * response.setContentLength(3)\n    1 * outputStream.write([00, 01, 02])\n  }\n\n  def \"should return false if exception is thrown\"() {\n    given:\n    cacheManager.get(request, invocationInput) >> { throw new RuntimeException() }\n\n    when:\n    def result = cacheReader.responseFromCache(invocationInput, request, response, cacheManager)\n\n    then:\n    !result\n  }\n}\n"
  },
  {
    "path": "graphql-java-servlet/src/test/groovy/graphql/kickstart/servlet/cache/CachingHttpRequestInvokerTest.groovy",
    "content": "package graphql.kickstart.servlet.cache\n\nimport graphql.ExecutionResult\nimport graphql.kickstart.execution.FutureExecutionResult\nimport graphql.kickstart.execution.GraphQLInvoker\nimport graphql.kickstart.execution.GraphQLObjectMapper\nimport graphql.kickstart.execution.GraphQLQueryResult\nimport graphql.kickstart.execution.input.GraphQLSingleInvocationInput\nimport graphql.kickstart.servlet.GraphQLConfiguration\nimport graphql.kickstart.servlet.HttpRequestInvoker\nimport graphql.kickstart.servlet.ListenerHandler\nimport spock.lang.Specification\n\nimport jakarta.servlet.ServletOutputStream\nimport jakarta.servlet.http.HttpServletRequest\nimport jakarta.servlet.http.HttpServletResponse\nimport java.util.concurrent.CompletableFuture\n\nclass CachingHttpRequestInvokerTest extends Specification {\n\n  def cacheReaderMock\n  def cachingInvoker\n  def invocationInputMock\n  def requestMock\n  def responseMock\n  def responseCacheManagerMock\n  def httpRequestInvokerMock\n  def graphqlInvoker\n  def configuration\n  def graphqlObjectMapper\n  def outputStreamMock\n  def listenerHandlerMock\n\n  def setup() {\n    cacheReaderMock = Mock(CacheReader)\n    invocationInputMock = Mock(GraphQLSingleInvocationInput)\n    requestMock = Mock(HttpServletRequest)\n    responseMock = Mock(HttpServletResponse)\n    responseCacheManagerMock = Mock(GraphQLResponseCacheManager)\n    configuration = Mock(GraphQLConfiguration)\n    httpRequestInvokerMock = Mock(HttpRequestInvoker)\n    graphqlInvoker = Mock(GraphQLInvoker)\n    graphqlObjectMapper = Mock(GraphQLObjectMapper)\n    outputStreamMock = Mock(ServletOutputStream)\n    graphqlInvoker.execute(invocationInputMock) >> FutureExecutionResult.single(invocationInputMock, CompletableFuture.completedFuture(Mock(GraphQLQueryResult)))\n    cachingInvoker = new CachingHttpRequestInvoker(configuration, httpRequestInvokerMock, cacheReaderMock)\n    listenerHandlerMock = Mock(ListenerHandler)\n\n    configuration.getResponseCacheManager() >> responseCacheManagerMock\n    configuration.getGraphQLInvoker() >> graphqlInvoker\n    configuration.getObjectMapper() >> graphqlObjectMapper\n    graphqlObjectMapper.serializeResultAsBytes(_ as ExecutionResult) >> new byte[0]\n    graphqlInvoker.queryAsync(invocationInputMock) >> CompletableFuture.completedFuture(Mock(GraphQLQueryResult))\n\n    responseMock.getOutputStream() >> outputStreamMock\n  }\n\n  def \"should execute regular invoker if cache not exists\"() {\n    given:\n    cacheReaderMock.responseFromCache(invocationInputMock, requestMock, responseMock, responseCacheManagerMock) >> false\n\n    when:\n    cachingInvoker.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n\n    then:\n    1 * httpRequestInvokerMock.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n  }\n\n  def \"should not execute regular invoker if cache exists\"() {\n    given:\n    cacheReaderMock.responseFromCache(invocationInputMock, requestMock, responseMock, responseCacheManagerMock) >> true\n\n    when:\n    cachingInvoker.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n\n    then:\n    0 * httpRequestInvokerMock.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n  }\n\n  def \"should return bad request response when ioexception\"() {\n    given:\n    cacheReaderMock.responseFromCache(invocationInputMock, requestMock, responseMock, responseCacheManagerMock) >> { throw new IOException() }\n\n    when:\n    cachingInvoker.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n\n    then:\n    1 * responseMock.setStatus(400)\n  }\n\n  def \"should initialize completely when using single param constructor\"() {\n    given:\n    def invoker = new CachingHttpRequestInvoker(configuration)\n\n    when:\n    invoker.execute(invocationInputMock, requestMock, responseMock, listenerHandlerMock)\n\n    then:\n    noExceptionThrown()\n  }\n\n}\n"
  },
  {
    "path": "lombok.config",
    "content": "lombok.addLombokGeneratedAnnotation = true\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"extends\": [\n    \"github>graphql-java-kickstart/renovate-config\"\n  ]\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'graphql-java-servlet'\n\ninclude ':graphql-java-kickstart'\ninclude ':graphql-java-servlet'\n"
  }
]