diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 1b6c3611a..df00628c3 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,11 +5,19 @@ updates:
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: gradle
directory: "/android"
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: gradle
directory: "/samples/deviceCodeSample"
schedule:
@@ -25,6 +33,10 @@ updates:
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: github-actions
directory: "/"
schedule:
@@ -36,18 +48,30 @@ updates:
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: gradle
directory: "/android"
target-branch: v3/longTermBranch
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: maven
directory: "/"
target-branch: v3/longTermBranch
schedule:
interval: daily
open-pull-requests-limit: 10
+ groups:
+ kiota-dependencies:
+ patterns:
+ - "*kiota*"
- package-ecosystem: github-actions
directory: "/"
target-branch: v3/longTermBranch
diff --git a/.github/workflows/api-level-lint.yml b/.github/workflows/api-level-lint.yml
index 80dd4d01b..95f2863e6 100644
--- a/.github/workflows/api-level-lint.yml
+++ b/.github/workflows/api-level-lint.yml
@@ -6,22 +6,24 @@ on:
branches:
- dev
- master
+ - v3/longTermBranch
pull_request:
branches:
- dev
- master
+ - v3/longTermBranch
jobs:
lint-api-level:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-java@v3
+ - uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 20
- name: Setup Android SDK
- uses: android-actions/setup-android@v3.0.0
+ uses: android-actions/setup-android@v3.2.0
- name: Add execution right to the script
run: chmod +x gradlew
working-directory: ./android
@@ -31,7 +33,7 @@ jobs:
working-directory: ./android
- name: Upload linting results
if: failure() && steps.lint.outcome == 'failure'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: lint-report
path: ./android/build/reports
diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml
index dbf50d8a0..eb42bbbd1 100644
--- a/.github/workflows/build-and-publish.yml
+++ b/.github/workflows/build-and-publish.yml
@@ -24,7 +24,7 @@ jobs:
- name: Easy detect-secrets
uses: RobertFischer/detect-secrets-action@v2.0.0
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 20
distribution: 'temurin'
@@ -56,7 +56,7 @@ jobs:
- name: Easy detect-secrets
uses: RobertFischer/detect-secrets-action@v2.0.0
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 20
distribution: 'temurin'
@@ -78,7 +78,7 @@ jobs:
- name: Publish
run: ./gradlew $PUBLISH_TASK
- name: Upload Build Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: drop
path: |
@@ -105,11 +105,11 @@ jobs:
run: .\scripts\getLatestVersion.ps1
shell: pwsh
- name: Create tag
- uses: rickstaa/action-create-tag@v1.6.6
+ uses: rickstaa/action-create-tag@v1.7.2
with:
tag: ${{ steps.GetVersion.outputs.tag }}
- name: Queue Git Release
- uses: benc-uk/workflow-dispatch@v1
+ uses: benc-uk/workflow-dispatch@v121
with:
workflow: Git Release
token: ${{ secrets.PERSONAL_TOKEN }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 2d5154690..2af747ed4 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -13,10 +13,10 @@ name: "CodeQL"
on:
push:
- branches: [ "dev", "master" ]
+ branches: ["dev", "master", "v3/longTermBranch"]
pull_request:
# The branches below must be a subset of the branches above
- branches: [ "dev" ]
+ branches: ["dev", "v3/longTermBranch"]
schedule:
- cron: '0 1 * * 4'
workflow_dispatch:
@@ -45,7 +45,7 @@ jobs:
uses: actions/checkout@v4
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 20
distribution: 'temurin'
@@ -53,7 +53,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -81,6 +81,6 @@ jobs:
run: ./gradlew build
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/git-release.yml b/.github/workflows/git-release.yml
index 975198d5a..aa6475c50 100644
--- a/.github/workflows/git-release.yml
+++ b/.github/workflows/git-release.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Download Build Artifact
- uses: dawidd6/action-download-artifact@v2.28.0
+ uses: dawidd6/action-download-artifact@v3.0.0
with:
workflow: build-and-publish.yml
workflow_conclusion: success
@@ -21,7 +21,7 @@ jobs:
name: drop
path: drop
- name: Github Release
- uses: anton-yurchenko/git-release@v5.0
+ uses: anton-yurchenko/git-release@v6.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}}
DRAFT_RELEASE: "false"
diff --git a/.github/workflows/gradle-build.yml b/.github/workflows/gradle-build.yml
index ad7885437..515791a26 100644
--- a/.github/workflows/gradle-build.yml
+++ b/.github/workflows/gradle-build.yml
@@ -2,7 +2,7 @@ name: Java CI with Gradle
on:
pull_request:
- branches: [ dev, master ]
+ branches: [ dev, master, v3/longTermBranch ]
paths-ignore:
- '.gradle/wrapper'
- '.gitignore'
@@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 20
distribution: 'temurin'
@@ -29,7 +29,7 @@ jobs:
- name: Build with Gradle
run: ./gradlew build
- name: Upload a Build Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: drop
path: |
@@ -42,4 +42,4 @@ jobs:
settings.gradle
gradle.properties
**/gradle/**
- Scripts/**
\ No newline at end of file
+ Scripts/**
diff --git a/.github/workflows/sample-build-check.yml b/.github/workflows/sample-build-check.yml
deleted file mode 100644
index 4a2a58f83..000000000
--- a/.github/workflows/sample-build-check.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: "samples build check"
-
-on:
- workflow_dispatch:
- push:
- paths:
- - '**/*.java'
- - '**/*.yml'
-
-jobs:
- samples-build-check-device-code:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v3
- with:
- distribution: 'temurin'
- java-version: 20
- - name: Add execution right to the script
- run: chmod +x gradlew
- working-directory: ./samples/deviceCodeSample
- - name: Build and run type summary project
- run: ./gradlew --no-daemon build
- working-directory: ./samples/deviceCodeSample
- samples-build-check-interactive:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-java@v3
- with:
- distribution: 'temurin'
- java-version: 20
- - name: Add execution right to the script
- run: chmod +x gradlew
- working-directory: ./samples/interactiveBrowserSample
- - name: Build and run type summary project
- run: ./gradlew --no-daemon build
- working-directory: ./samples/interactiveBrowserSample
\ No newline at end of file
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index 02a328912..4f38cc49e 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -33,19 +33,19 @@ jobs:
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 20
distribution: 'temurin'
cache: gradle
- name: Cache SonarCloud packages
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Gradle packages
- uses: actions/cache@v3
+ uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b040e5bcb..50395e115 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,107 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+## [3.1.0] - 2024-02-07
+
+### Changed
+
+- Version bump for Java SDK GA release.
+- Bumps Kiota-Java abstractions, authentication, http, and serialization components for Java SDK 6.1.0 release.
+
+## [3.0.12] - 2023-12-15
+
+### Fixed
+
+- Fixes a bug where a null collection for allowedHosts would result in failure to initialize client. [#1411](https://github.com/microsoftgraph/msgraph-sdk-java-core/pull/1411)
+
+## [3.0.11] - 2023-12-08
+
+### Changed
+
+- Parent namespace for all classes has been changed from com.microsoft.graph.* to com.microsoft.graph.core.* in order to avoid conflicts with the generated service libraries.
+- This change is not backwards compatible and will require changes to your code.
+
+## [3.0.10] - 2023-11-27
+
+### Changed
+
+- Removed the usage of reflection for enum deserialization and reordered RequestAdapter method arguments. [Kiota-Java #840](https://github.com/microsoft/kiota-java/issues/840)
+
+## [3.0.9] - 2023-11-14
+
+### Changed
+
+- Kiota-Java has moved away from Async/Completable futures, thus Async components are no longer utilized and have been removed. Furthermore, requestAdapter methods no longer use the async suffix. [Kiota-Java #175](https://github.com/microsoft/kiota-java/issues/175)
+- ApiException class now extends RuntimeException instead of Exception.
+
+### Removed
+
+- ServiceException class has been removed.
+
+## [3.0.8] - 2023-08-09
+
+### Changed
+
+- Replaces Javax annotations in favor of Jakarta annotations.
+
+### Removed
+
+- Removes 'SuppressFBWarnings' annotations and dependency.
+
+## [3.0.7] - 2023-07-20
+
+### Added
+
+- Adds graph-java-sdk implementation of the `UrlReplaceHandler` middleware including default replacement pairs.
+- Default replacement pair: '/users/TokenToReplace' -> '/me'
+
+## [3.0.6] - 2023-07-11
+
+### Added
+
+- Added the PageIterator functionality for Kiota generated service libraries.
+
+## [3.0.5] - 2023-06-15
+
+### Added
+
+- Added Batch Request and Batch Request Collection functionality for Kiota generated service libraries.
+
+## [3.0.4] - 2023-05-03
+
+### Added
+
+- Added LargeFileUploadTask functionality for kiota generated service libraries.
+
+### Fixed
+
+- Fixes formatting used in the headers added by the telemetry handler to align with the [msGraph sdk spec.](https://github.com/microsoftgraph/msgraph-sdk-design/blob/master/middleware/TelemetryHandler.md)
+
+## [3.0.3] - 2023-04-06
+
+### Changed
+
+- Bumps Kiota-Java abstractions, authentication, http, and serialization components.
+
+## [3.0.2] - 2022-10-10
+
+### Changed
+
+- Bumps Kiota-Java abstractions, authentication, http, and serialization components.
+
+## [3.0.1] - 2022-09-20
+
+### Added
+
+- Uses [Kiota-Java](https://github.com/microsoft/kiota-java) libraries as underlying framework.
+- BaseGraphRequestAdapter for use with v1 and beta service libraries.
+
+### Changed
+
+- Removes Request Builders.
+- GraphClientFactory to handle OkHttp client creation.
+- BaseClient refactored to use Kiota framework.
+
## [2.0.21] - 2023-11-08
### Changed
diff --git a/android/build.gradle b/android/build.gradle
index 4793db785..efbf782e5 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -2,21 +2,19 @@ buildscript {
repositories {
google()
gradlePluginPortal()
- maven {
- url "https://plugins.gradle.org/m2/"
- }
}
dependencies {
- classpath "com.gradle:gradle-enterprise-gradle-plugin:3.15.1"
- classpath "com.android.tools.build:gradle:8.1.3"
- classpath "com.github.ben-manes:gradle-versions-plugin:0.49.0"
+ classpath "com.gradle:gradle-enterprise-gradle-plugin:3.16.2"
+ classpath "com.android.tools.build:gradle:8.2.2"
+ classpath "com.github.ben-manes:gradle-versions-plugin:0.51.0"
}
}
repositories {
google()
gradlePluginPortal()
+ mavenCentral()
}
apply plugin: "com.android.library"
@@ -56,18 +54,18 @@ android {
disable "ResourceType" // Annotation binding
disable "GradleDependency"
disable "NewerVersionAvailable"
- disable "DuplicatePlatformClasses" // xpp3 added by azure-identity
+ disable "DuplicatePlatformClasses" // xpp3 added by azure-identity
+ }
+ sourceSets {
+ main {
+ java.srcDirs = ['../src/main/java']
+ res.srcDirs = ['../src/main/java']
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ androidTest {
+ setRoot '../src/test'
+ }
}
- sourceSets {
- main {
- java.srcDirs = ['../src/main/java']
- res.srcDirs = ['../src/main/java']
- manifest.srcFile 'AndroidManifest.xml'
- }
- androidTest {
- setRoot '../src/test'
- }
- }
}
apply from: "../gradle/dependencies.gradle"
diff --git a/android/gradle.properties b/android/gradle.properties
index 385adb9fa..ad0b12e21 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -25,9 +25,9 @@ org.gradle.caching=true
mavenGroupId = com.microsoft.graph
mavenArtifactId = microsoft-graph-core
-mavenMajorVersion = 2
-mavenMinorVersion = 3
-mavenPatchVersion = 3
+mavenMajorVersion = 3
+mavenMinorVersion = 1
+mavenPatchVersion = 0
mavenArtifactSuffix =
#These values are used to run functional tests
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
index c1962a79e..d64cd4917 100644
Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 37aef8d3f..1af9e0930 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
index aeb74cbb4..1aa94a426 100644
--- a/android/gradlew
+++ b/android/gradlew
@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
diff --git a/build.gradle b/build.gradle
index de29f9202..42041e20f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,11 @@
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
- id 'java'
id 'eclipse'
id 'maven-publish'
id 'signing'
id 'jacoco'
- id 'com.github.spotbugs' version '5.2.3'
+ id 'com.github.spotbugs' version '6.0.7'
id "org.sonarqube" version "4.4.1.3373"
}
@@ -84,11 +83,11 @@ def pomConfig = {
}
sonarqube {
- properties {
- property "sonar.projectKey", "microsoftgraph_msgraph-sdk-java-core"
- property "sonar.organization", "microsoftgraph2"
- property "sonar.host.url", "https://sonarcloud.io"
- }
+ properties {
+ property "sonar.projectKey", "microsoftgraph_msgraph-sdk-java-core"
+ property "sonar.organization", "microsoftgraph2"
+ property "sonar.host.url", "https://sonarcloud.io"
+ }
}
//Publishing tasks-
@@ -132,7 +131,7 @@ publishing {
writeTo(pomFile)
}
}
-
+
mavenCentralRelease(MavenPublication) {
customizePom(pom)
groupId project.property('mavenGroupId')
@@ -145,32 +144,32 @@ publishing {
}
}
}
- repositories {
+ repositories {
maven {
url = 'https://oss.sonatype.org/content/repositories/snapshots'
name = 'sonatypeSnapshot'
-
+
credentials {
- if (project.rootProject.file('local.properties').exists()) {
- Properties properties = new Properties()
- properties.load(project.rootProject.file('local.properties').newDataInputStream())
- username = properties.getProperty('sonatypeUsername')
- password = properties.getProperty('sonatypePassword')
- }
+ if (project.rootProject.file('local.properties').exists()) {
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ username = properties.getProperty('sonatypeUsername')
+ password = properties.getProperty('sonatypePassword')
+ }
}
}
-
+
maven {
url = 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
name = 'sonatype'
credentials {
- if (project.rootProject.file('local.properties').exists()) {
- Properties properties = new Properties()
- properties.load(project.rootProject.file('local.properties').newDataInputStream())
- username = properties.getProperty('sonatypeUsername')
- password = properties.getProperty('sonatypePassword')
- }
+ if (project.rootProject.file('local.properties').exists()) {
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ username = properties.getProperty('sonatypeUsername')
+ password = properties.getProperty('sonatypePassword')
+ }
}
}
}
@@ -181,7 +180,7 @@ signing {
}
tasks.withType(Sign)*.enabled = mavenCentralPublishingEnabled.toBoolean()
-def fixAscNames = { name ->
+def fixAscNames = { name ->
if(name.contains('pom')) {
"${project.property('mavenArtifactId')}-${mavenMajorVersion}.${mavenMinorVersion}.${mavenPatchVersion}.pom.asc"
} else {
@@ -232,8 +231,8 @@ def customizePom(pom) {
licenses {
license {
name "MIT License"
- url "http://opensource.org/licenses/MIT"
- distribution "repo"
+ url "http://opensource.org/licenses/MIT"
+ distribution "repo"
}
}
scm {
diff --git a/gradle.properties b/gradle.properties
index 11030eaf9..20a14fcdd 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -23,10 +23,10 @@ org.gradle.jvmargs=-Xmx2g
mavenGroupId = com.microsoft.graph
mavenArtifactId = microsoft-graph-core
-mavenMajorVersion = 2
-mavenMinorVersion = 0
-mavenPatchVersion = 21
-mavenArtifactSuffix =
+mavenMajorVersion = 3
+mavenMinorVersion = 1
+mavenPatchVersion = 0
+mavenArtifactSuffix =
#These values are used to run functional tests
#If you wish to run the functional tests, edit the gradle.properties
diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle
index ed256e9e5..8507533cf 100644
--- a/gradle/dependencies.gradle
+++ b/gradle/dependencies.gradle
@@ -1,16 +1,26 @@
dependencies {
// Use JUnit test framework
- testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.1'
- testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.1'
- testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.1'
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testImplementation 'org.mockito:mockito-inline:5.2.0'
+ testImplementation 'io.opentelemetry:opentelemetry-api:1.34.1'
+ testImplementation 'io.opentelemetry:opentelemetry-context:1.34.1'
+ testImplementation 'io.opentelemetry.semconv:opentelemetry-semconv:1.23.1-alpha'
+ testImplementation 'io.github.std-uritemplate:std-uritemplate:0.0.50'
- api 'com.squareup.okhttp3:okhttp:4.12.0'
+ implementation 'com.google.code.gson:gson:2.10.1'
- implementation 'com.google.guava:guava:32.1.3-jre'
+ implementation 'jakarta.annotation:jakarta.annotation-api:2.1.1'
- implementation 'com.google.code.gson:gson:2.10.1'
- api 'com.azure:azure-core:1.45.0'
+ api 'com.squareup.okhttp3:okhttp:4.12.0'
+ api 'com.azure:azure-core:1.46.0'
- api 'com.github.spotbugs:spotbugs-annotations:4.8.1'
-}
\ No newline at end of file
+ api 'com.microsoft.kiota:microsoft-kiota-abstractions:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-authentication-azure:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-http-okHttp:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-serialization-json:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-serialization-text:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-serialization-form:1.0.0'
+ implementation 'com.microsoft.kiota:microsoft-kiota-serialization-multipart:1.0.0'
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index c1962a79e..d64cd4917 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 37aef8d3f..1af9e0930 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index aeb74cbb4..1aa94a426 100755
--- a/gradlew
+++ b/gradlew
@@ -83,7 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -198,11 +202,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
diff --git a/pom.xml b/pom.xml
index 1cb75d8a2..fece8e16a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
com.microsoft.graph
microsoft-graph-core
- 2.0.12
+ 3.1.0
pom
@@ -25,7 +25,7 @@
com.google.guava
guava
- 32.1.3-jre
+ 33.0.0-jre
com.squareup.okhttp3
@@ -35,18 +35,18 @@
com.azure
azure-core
- 1.45.0
+ 1.46.0
org.junit.jupiter
junit-jupiter-api
- 5.10.1
+ 5.10.2
test
org.junit.jupiter
junit-jupiter-params
- 5.10.1
+ 5.10.2
test
@@ -58,7 +58,7 @@
com.github.spotbugs
spotbugs-annotations
- 4.8.1
+ 4.8.3
diff --git a/readme.md b/readme.md
index 748e700c6..464339a34 100644
--- a/readme.md
+++ b/readme.md
@@ -22,9 +22,9 @@ repositories {
dependencies {
// Include the sdk as a dependency
- implementation 'com.microsoft.graph:microsoft-graph-core:2.0.20'
+ implementation 'com.microsoft.graph:microsoft-graph-core:3.1.0'
// This dependency is only needed if you are using the TokenCredentialAuthProvider
- implementation 'com.azure:azure-identity:1.10.2'
+ implementation 'com.azure:azure-identity:1.11.0'
}
```
@@ -37,11 +37,11 @@ Add the dependency in `dependencies` in pom.xml
com.microsoft.graph
microsoft-graph-core
- 2.0.20
+ 3.1.0
com.azure
azure-identity
- 1.10.2
+ 1.11.0
```
diff --git a/samples/deviceCodeSample/.gitignore b/samples/deviceCodeSample/.gitignore
deleted file mode 100644
index e34a1d606..000000000
--- a/samples/deviceCodeSample/.gitignore
+++ /dev/null
@@ -1,34 +0,0 @@
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-/.gradle/
-/build/
-/bin/
-
-#Eclipse
-.project
-.classpath
-.settings
-
-# Maven
-/target/
-local.properties
\ No newline at end of file
diff --git a/samples/deviceCodeSample/build.gradle b/samples/deviceCodeSample/build.gradle
deleted file mode 100644
index 5d56bb63b..000000000
--- a/samples/deviceCodeSample/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins {
- id 'java'
-}
-
-group 'org.example'
-version '1.0-SNAPSHOT'
-
-repositories {
- mavenCentral()
-}
-
-dependencies {
- testImplementation group: 'junit', name: 'junit', version: '4.13.2'
- implementation project(':coreLibrary')
- implementation 'com.azure:azure-identity:1.11.0'
-}
diff --git a/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.jar b/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index c1962a79e..000000000
Binary files a/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.properties b/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 37aef8d3f..000000000
--- a/samples/deviceCodeSample/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
-networkTimeout=10000
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/samples/deviceCodeSample/gradlew b/samples/deviceCodeSample/gradlew
deleted file mode 100644
index aeb74cbb4..000000000
--- a/samples/deviceCodeSample/gradlew
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD=$JAVA_HOME/jre/sh/java
- else
- JAVACMD=$JAVA_HOME/bin/java
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
diff --git a/samples/deviceCodeSample/gradlew.bat b/samples/deviceCodeSample/gradlew.bat
deleted file mode 100644
index 93e3f59f1..000000000
--- a/samples/deviceCodeSample/gradlew.bat
+++ /dev/null
@@ -1,92 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/samples/deviceCodeSample/settings.gradle b/samples/deviceCodeSample/settings.gradle
deleted file mode 100644
index 79a5cd38a..000000000
--- a/samples/deviceCodeSample/settings.gradle
+++ /dev/null
@@ -1,4 +0,0 @@
-include 'coreLibrary'
-
-project(':coreLibrary').projectDir = new File("../../")
-
diff --git a/samples/deviceCodeSample/src/main/java/DeviceCodeFlowMain.java b/samples/deviceCodeSample/src/main/java/DeviceCodeFlowMain.java
deleted file mode 100644
index b39fb3ad7..000000000
--- a/samples/deviceCodeSample/src/main/java/DeviceCodeFlowMain.java
+++ /dev/null
@@ -1,45 +0,0 @@
-import com.azure.identity.DeviceCodeCredential;
-import com.azure.identity.DeviceCodeCredentialBuilder;
-import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
-import com.microsoft.graph.httpcore.HttpClients;
-import okhttp3.*;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-
-public class DeviceCodeFlowMain {
-
- //Replace CLIENT_ID with your own client id from an app that is configured according to the requirements below
- //for requirements visit:
- //https://github.com/Azure/azure-sdk-for-java/wiki/Set-up-Your-Environment-for-Authentication#enable-applications-for-device-code-flow
- private final static String CLIENT_ID = "";
-
- //Set the scopes for your ms-graph request
- private final static List SCOPES = Arrays.asList("User.ReadBasic.All", "User.Read");
-
- public static void main(String[] args) throws Exception {
- final DeviceCodeCredential deviceCodeCred = new DeviceCodeCredentialBuilder()
- .clientId(CLIENT_ID)
- .challengeConsumer(challenge -> System.out.println(challenge.getMessage()))
- .build();
-
- final TokenCredentialAuthProvider tokenCredAuthProvider = new TokenCredentialAuthProvider(SCOPES, deviceCodeCred);
- final OkHttpClient httpClient = HttpClients.createDefault(tokenCredAuthProvider);
-
- final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build();
-
- httpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- System.out.println(response.body().string());
- }
-
- @Override
- public void onFailure(Call call, IOException e) {
- e.printStackTrace();
- }
- });
- }
-}
diff --git a/samples/interactiveBrowserSample/.gitignore b/samples/interactiveBrowserSample/.gitignore
deleted file mode 100644
index e34a1d606..000000000
--- a/samples/interactiveBrowserSample/.gitignore
+++ /dev/null
@@ -1,34 +0,0 @@
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-/.gradle/
-/build/
-/bin/
-
-#Eclipse
-.project
-.classpath
-.settings
-
-# Maven
-/target/
-local.properties
\ No newline at end of file
diff --git a/samples/interactiveBrowserSample/build.gradle b/samples/interactiveBrowserSample/build.gradle
deleted file mode 100644
index 5d56bb63b..000000000
--- a/samples/interactiveBrowserSample/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins {
- id 'java'
-}
-
-group 'org.example'
-version '1.0-SNAPSHOT'
-
-repositories {
- mavenCentral()
-}
-
-dependencies {
- testImplementation group: 'junit', name: 'junit', version: '4.13.2'
- implementation project(':coreLibrary')
- implementation 'com.azure:azure-identity:1.11.0'
-}
diff --git a/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.jar b/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index c1962a79e..000000000
Binary files a/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.properties b/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 37aef8d3f..000000000
--- a/samples/interactiveBrowserSample/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
-networkTimeout=10000
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/samples/interactiveBrowserSample/gradlew b/samples/interactiveBrowserSample/gradlew
deleted file mode 100644
index aeb74cbb4..000000000
--- a/samples/interactiveBrowserSample/gradlew
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
- # IBM's JDK on AIX uses strange locations for the executables
- JAVACMD=$JAVA_HOME/jre/sh/java
- else
- JAVACMD=$JAVA_HOME/bin/java
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
diff --git a/samples/interactiveBrowserSample/gradlew.bat b/samples/interactiveBrowserSample/gradlew.bat
deleted file mode 100644
index 93e3f59f1..000000000
--- a/samples/interactiveBrowserSample/gradlew.bat
+++ /dev/null
@@ -1,92 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if %ERRORLEVEL% equ 0 goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-set EXIT_CODE=%ERRORLEVEL%
-if %EXIT_CODE% equ 0 set EXIT_CODE=1
-if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
-exit /b %EXIT_CODE%
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/samples/interactiveBrowserSample/settings.gradle b/samples/interactiveBrowserSample/settings.gradle
deleted file mode 100644
index b6260dfbe..000000000
--- a/samples/interactiveBrowserSample/settings.gradle
+++ /dev/null
@@ -1,5 +0,0 @@
-include 'coreLibrary'
-
-project(':coreLibrary').projectDir = new File("../../")
-
-
diff --git a/samples/interactiveBrowserSample/src/main/java/InteractiveBrowserMain.java b/samples/interactiveBrowserSample/src/main/java/InteractiveBrowserMain.java
deleted file mode 100644
index f9eb5a767..000000000
--- a/samples/interactiveBrowserSample/src/main/java/InteractiveBrowserMain.java
+++ /dev/null
@@ -1,43 +0,0 @@
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import com.azure.identity.InteractiveBrowserCredential;
-import com.azure.identity.InteractiveBrowserCredentialBuilder;
-import com.microsoft.graph.authentication.*;
-import okhttp3.*;
-import com.microsoft.graph.httpcore.HttpClients;
-
-public class InteractiveBrowserMain {
-
- //Replace CLIENT_ID with your own client id from an adequately configured app
- //for requirements visit:
- //https://github.com/Azure/azure-sdk-for-java/wiki/Set-up-Your-Environment-for-Authentication#enable-applications-for-interactive-browser-oauth-2-flow
- private final static String CLIENT_ID = "";
-
- //Set the scopes for your ms-graph request
- private final static List SCOPES = Arrays.asList("User.ReadBasic.All");
-
- public static void main(String args[]) throws Exception {
- final InteractiveBrowserCredential interactiveBrowserCredential = new InteractiveBrowserCredentialBuilder()
- .clientId(CLIENT_ID)
- .redirectUrl("http://localhost:8765")
- .build();
-
- final TokenCredentialAuthProvider tokenCredentialAuthProvider = new TokenCredentialAuthProvider(SCOPES, interactiveBrowserCredential);
- final OkHttpClient httpClient = HttpClients.createDefault(tokenCredentialAuthProvider);
-
- final Request request = new Request.Builder().url("https://graph.microsoft.com/v1.0/me/").build();
-
- httpClient.newCall(request).enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- System.out.println(response.body().string());
- }
-
- @Override
- public void onFailure(Call call, IOException e) {
- e.printStackTrace();
- }
- });
- }
-}
diff --git a/spotBugsExcludeFilter.xml b/spotBugsExcludeFilter.xml
index 26f35d7eb..ffb0ea6f2 100644
--- a/spotBugsExcludeFilter.xml
+++ b/spotBugsExcludeFilter.xml
@@ -3,47 +3,46 @@
xmlns="https://github.com/spotbugs/filter/3.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
@@ -54,4 +53,62 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/microsoft/graph/authentication/BaseAuthenticationProvider.java b/src/main/java/com/microsoft/graph/authentication/BaseAuthenticationProvider.java
deleted file mode 100644
index d2fb35a9f..000000000
--- a/src/main/java/com/microsoft/graph/authentication/BaseAuthenticationProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.microsoft.graph.authentication;
-
-import java.net.URL;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Locale;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-/**
- * Provides basic common methods for all authentication providers
- */
-public abstract class BaseAuthenticationProvider implements IAuthenticationProvider {
- private static final HashSet validGraphHostNames = new HashSet<>(Arrays.asList("graph.microsoft.com", "graph.microsoft.us", "dod-graph.microsoft.us", "graph.microsoft.de", "microsoftgraph.chinacloudapi.cn", "canary.graph.microsoft.com"));
- private HashSet customHosts;
-
- /**
- * Allow the user to add custom hosts by passing in Array
- * @param customHosts custom hosts passed in by user.
- */
- public void setCustomHosts(@Nonnull String[] customHosts) {
- if(this.customHosts == null){
- this.customHosts = new HashSet();
- }
- for(String host: customHosts){
- this.customHosts.add(host.toLowerCase(Locale.ROOT));
- }
- }
- /**
- * Get the custom hosts set by user.
- * @return the custom hosts set by user.
- */
- @Nullable
- public String[] getCustomHosts(){
- return customHosts.toArray(new String[customHosts.size()]);
- }
- /**
- * Determines whether a request should be authenticated or not based on it's url.
- * If you're implementing a custom provider, call that method first before getting the token
- * @param requestUrl request URL that is about to be executed
- * @return whether a token should be attached to this request
- */
- protected boolean shouldAuthenticateRequestWithUrl(@Nonnull final URL requestUrl) {
- if (requestUrl == null || !requestUrl.getProtocol().toLowerCase(Locale.ROOT).equals("https"))
- return false;
- final String hostName = requestUrl.getHost().toLowerCase(Locale.ROOT);
- return customHosts == null ? (validGraphHostNames.contains(hostName)) : (customHosts.contains(hostName));
- }
-}
diff --git a/src/main/java/com/microsoft/graph/authentication/IAuthenticationProvider.java b/src/main/java/com/microsoft/graph/authentication/IAuthenticationProvider.java
deleted file mode 100644
index ae1f478f4..000000000
--- a/src/main/java/com/microsoft/graph/authentication/IAuthenticationProvider.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.microsoft.graph.authentication;
-
-import java.net.URL;
-import java.util.concurrent.CompletableFuture;
-
-import javax.annotation.Nonnull;
-
-/**
- * Authenticates requests to be sent to the API
- */
-public interface IAuthenticationProvider {
- /**
- * Authenticates the request
- *
- * @param requestUrl the outgoing request URL
- * @return a future with the token
- */
- @Nonnull
- CompletableFuture getAuthorizationTokenAsync(@Nonnull final URL requestUrl);
-}
diff --git a/src/main/java/com/microsoft/graph/authentication/TokenCredentialAuthProvider.java b/src/main/java/com/microsoft/graph/authentication/TokenCredentialAuthProvider.java
deleted file mode 100644
index de9a5d9b3..000000000
--- a/src/main/java/com/microsoft/graph/authentication/TokenCredentialAuthProvider.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.microsoft.graph.authentication;
-
-import com.azure.core.credential.AccessToken;
-import com.azure.core.credential.TokenCredential;
-import com.azure.core.credential.TokenRequestContext;
-
-import javax.annotation.Nonnull;
-import java.net.URL;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-
-/**
- * An implementation of the Authentication Provider with Azure-identity
- */
-public class TokenCredentialAuthProvider extends BaseAuthenticationProvider {
- /** TokenCredential expected from user */
- private final TokenCredential tokenCredential;
- /** Context options which can be optionally set by the user */
- private final TokenRequestContext context;
- /** Default scope to use when no scopes are provided */
- private static final String DEFAULT_GRAPH_SCOPE = "https://graph.microsoft.com/.default";
-
- /**
- * Creates an Authentication provider using a passed in TokenCredential
- *
- * @param tokenCredential Credential object inheriting the TokenCredential interface used to instantiate the Auth Provider
- */
- public TokenCredentialAuthProvider(@Nonnull final TokenCredential tokenCredential) {
- this(Collections.singletonList(DEFAULT_GRAPH_SCOPE), tokenCredential);
- }
-
- /**
- * Creates an Authentication provider using a TokenCredential and list of scopes
- *
- * @param tokenCredential Credential object inheriting the TokenCredential interface used to instantiate the Auth Provider
- * @param scopes Specified desired scopes of the Auth Provider
- */
- public TokenCredentialAuthProvider(@Nonnull final List scopes, @Nonnull final TokenCredential tokenCredential) {
- if(scopes == null || scopes.isEmpty()) {
- throw new IllegalArgumentException("scopes parameter cannot be null or empty");
- }
- this.context = new TokenRequestContext();
- this.context.setScopes(scopes);
- this.tokenCredential = Objects.requireNonNull(tokenCredential, "tokenCredential parameter cannot be null.");
- }
-
- /**
- * Returns an AccessToken as a string
- *
- * @return String representing the retrieved AccessToken
- */
- @Nonnull
- public CompletableFuture getAuthorizationTokenAsync(@Nonnull final URL requestUrl) {
- if(shouldAuthenticateRequestWithUrl(Objects.requireNonNull(requestUrl, "requestUrl parameter cannot be null")))
- return this.tokenCredential
- .getToken(this.context)
- .toFuture()
- .thenApply(AccessToken::getToken);
- else
- return CompletableFuture.completedFuture((String)null);
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchRequest.java b/src/main/java/com/microsoft/graph/content/BatchRequest.java
deleted file mode 100644
index ae7b732c4..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchRequest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.microsoft.graph.core.ClientException;
-import com.microsoft.graph.core.IBaseClient;
-import com.microsoft.graph.http.BaseRequest;
-import com.microsoft.graph.http.HttpMethod;
-import com.microsoft.graph.options.Option;
-
-/** Request for batch requests */
-public class BatchRequest extends BaseRequest {
-
- /**
- * Instantiates a new batch request
- *
- * @param requestUrl the URL to send the request to
- * @param client the client to use to execute the request
- * @param options the options to apply to the request
- */
- public BatchRequest(@Nonnull final String requestUrl, @Nonnull final IBaseClient> client, @Nonnull final List extends Option> options) {
- super(requestUrl, client, options, BatchResponseContent.class);
- }
-
- /**
- * Send this request
- *
- * @return the response object
- * @param content content of the batch request to execute
- * @throws ClientException an exception occurs if there was an error while the request was sent
- */
- @Nullable
- public BatchResponseContent post(@Nullable final BatchRequestContent content) throws ClientException {
- this.setHttpMethod(HttpMethod.POST);
- final BatchResponseContent response = this.getClient().getHttpProvider().send(this, BatchResponseContent.class, content);
- setSerializerOnSteps(response);
- return response;
- }
- /**
- * Send this request
- *
- * @return the response object
- * @param content content of the batch request to execute
- * @throws ClientException an exception occurs if there was an error while the request was sent
- */
- @Nullable
- public java.util.concurrent.CompletableFuture postAsync(@Nullable final BatchRequestContent content) throws ClientException {
- this.setHttpMethod(HttpMethod.POST);
- return this.getClient().getHttpProvider().sendAsync(this, BatchResponseContent.class, content).thenApply(response -> {
- setSerializerOnSteps(response);
- return response;
- });
- }
- private void setSerializerOnSteps(final BatchResponseContent response) {
- if(response.responses != null)
- for(final BatchResponseStep> step : response.responses) {
- step.serializer = this.getClient().getSerializer();
- }
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchRequestBuilder.java b/src/main/java/com/microsoft/graph/content/BatchRequestBuilder.java
deleted file mode 100644
index c6ceda75d..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchRequestBuilder.java
+++ /dev/null
@@ -1,66 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.microsoft.graph.core.IBaseClient;
-import com.microsoft.graph.http.BaseRequestBuilder;
-import com.microsoft.graph.options.Option;
-
-/** Request builder for batch requests */
-public class BatchRequestBuilder extends BaseRequestBuilder {
- /**
- * Instantiates a new batch request builder
- * @param requestUrl the URL for the request
- * @param client the client to use to execute the request
- * @param options the request options
- */
- public BatchRequestBuilder(@Nonnull final String requestUrl, @Nonnull final IBaseClient> client, @Nonnull final List extends Option> options) {
- super(requestUrl, client, options);
- }
- /**
- * Creates the request
- *
- * @param requestOptions the options for this request
- * @return the IUserRequest instance
- */
- @Nonnull
- public BatchRequest buildRequest(@Nullable final com.microsoft.graph.options.Option... requestOptions) {
- return buildRequest(getOptions(requestOptions));
- }
-
- /**
- * Creates the request
- *
- * @param requestOptions the options for this request
- * @return the IUserRequest instance
- */
- @Nonnull
- public BatchRequest buildRequest(@Nonnull final java.util.List extends com.microsoft.graph.options.Option> requestOptions) {
- return new BatchRequest(this.getRequestUrl(), getClient(), requestOptions);
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchRequestContent.java b/src/main/java/com/microsoft/graph/content/BatchRequestContent.java
deleted file mode 100644
index 31c0ac766..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchRequestContent.java
+++ /dev/null
@@ -1,186 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-import com.microsoft.graph.http.HttpMethod;
-import com.microsoft.graph.http.IHttpRequest;
-import com.microsoft.graph.options.HeaderOption;
-import com.microsoft.graph.serializer.IJsonBackedObject;
-
-/** Respresents the content of a JSON batch request */
-public class BatchRequestContent {
- /** Steps part of the batch request */
- @Expose
- @Nullable
- @SerializedName("requests")
- public List> requests;
-
- /**
- * Adds a request as a step to the current batch. Defaults to GET if the HTTP method is not set in the request.
- * @param request the request to add as a step
- * @return the id of the step that was just added to the batch
- */
- @Nonnull
- public String addBatchRequestStep(@Nonnull final IHttpRequest request) {
- Objects.requireNonNull(request, "request parameter cannot be null");
- return addBatchRequestStep(request, request.getHttpMethod() == null ? HttpMethod.GET : request.getHttpMethod());
- }
- /**
- * Adds a request as a step to the current batch
- * @param request the request to add as a step
- * @param httpMethod the HttpMethod to execute the request with
- * @return the id of the step that was just added to the batch
- */
- @Nonnull
- public String addBatchRequestStep(@Nonnull final IHttpRequest request, @Nonnull final HttpMethod httpMethod) {
- return addBatchRequestStep(request, httpMethod, null);
- }
- /**
- * Adds a request as a step to the current batch
- * @param request the request to add as a step
- * @param httpMethod the HttpMethod to execute the request with
- * @param the type of the request body
- * @param serializableBody the body of the request to be serialized
- * @return the id of the step that was just added to the batch
- */
- @Nonnull
- public String addBatchRequestStep(@Nonnull final IHttpRequest request, @Nonnull final HttpMethod httpMethod, @Nullable final T serializableBody) {
- return addBatchRequestStep(request, httpMethod, serializableBody, (String[])null);
- }
- /**
- * Adds a request as a step to the current batch
- * @param request the request to add as a step
- * @param httpMethod the HttpMethod to execute the request with
- * @param the type of the request body
- * @param serializableBody the body of the request to be serialized
- * @param dependsOnRequestsIds the ids of steps this request depends on
- * @return the id of the step that was just added to the batch
- */
- @Nonnull
- public String addBatchRequestStep(@Nonnull final IHttpRequest request, @Nonnull final HttpMethod httpMethod, @Nullable final T serializableBody, @Nullable final String ...dependsOnRequestsIds) {
- Objects.requireNonNull(request, "request parameter cannot be null");
- Objects.requireNonNull(httpMethod, "httpMethod parameter cannot be null");
- if(dependsOnRequestsIds != null)
- for(final String id : dependsOnRequestsIds) {
- if(getStepById(id) == null)
- throw new IllegalArgumentException("the current request depends on a inexisting request");
- }
-
- if(requests == null)
- requests = new ArrayList<>();
-
- final Matcher protocolAndHostReplacementMatcher = protocolAndHostReplacementPattern.matcher(request.getRequestUrl().toString());
- final BatchRequestStep step = new BatchRequestStep() {{
- url = protocolAndHostReplacementMatcher.replaceAll("");
- body = serializableBody;
- method = httpMethod.toString().toUpperCase(Locale.getDefault());
- dependsOn = dependsOnRequestsIds != null && dependsOnRequestsIds.length > 0 ? new HashSet<>(Arrays.asList(dependsOnRequestsIds)) : null;
- id = getNextRequestId();
- }};
-
- if(!request.getHeaders().isEmpty()) {
- step.headers = new HashMap<>();
- for(final HeaderOption headerOption : request.getHeaders())
- step.headers.putIfAbsent(headerOption.getName().toLowerCase(Locale.getDefault()), headerOption.getValue().toString());
- }
- if(step.body != null && step.body instanceof IJsonBackedObject &&
- (step.headers == null || !step.headers.containsKey(contentTypeHeaderKey))) {
- if(step.headers == null)
- step.headers = new HashMap<>();
- step.headers.putIfAbsent(contentTypeHeaderKey, "application/json");
- }
- requests.add(step);
- return step.id;
- }
- private static final String contentTypeHeaderKey = "content-type";
- /**
- * Removes requests from the requests to be executed by the batch. Also removes any dependency references that might exist.
- * @param stepIds ids of steps to be removed.
- */
- public void removeBatchRequestStepWithId(@Nonnull final String ...stepIds) {
- if(requests == null) return;
-
- for(final String stepId : stepIds) {
- Objects.requireNonNull(stepId, "parameter stepIds cannot contain null values");
- requests.removeIf(x -> stepId.equals(x.id));
- for(final BatchRequestStep> step : requests) {
- if(step.dependsOn != null) {
- step.dependsOn.removeIf(stepId::equals);
- if(step.dependsOn.isEmpty())
- step.dependsOn = null; // so we don't send dependsOn: [] over the wire
- }
- }
- }
- }
- /**
- * Gets a step by its step id
- * @param the type of the request body
- * @param stepId the request step id returned from the add method
- * @return the request corresponding to the provided id or null
- */
- @Nullable
- @SuppressWarnings("unchecked")
- public BatchRequestStep getStepById(@Nonnull final String stepId) {
- Objects.requireNonNull(stepId, "parameter stepId cannot be null");
- if(requests == null) return null;
-
- for(final BatchRequestStep> step : requests) {
- if(stepId.equals(step.id))
- return (BatchRequestStep)step;
- }
- return null;
- }
- /** pattern to replace the protocol and host part of the request if specified */
- @Nonnull
- protected static final Pattern protocolAndHostReplacementPattern =
- Pattern.compile("(?i)^http[s]?:\\/\\/(?:graph|dod-graph|microsoftgraph)\\.(?:microsoft|chinacloudapi)\\.(?:com|cn|us|de)\\/(?:v1\\.0|beta)"); // (?i) case insensitive
- //https://docs.microsoft.com/en-us/graph/deployments#microsoft-graph-and-graph-explorer-service-root-endpoints
- /**
- * Generates a randomly available request id
- * @return a random request id
- */
- @Nonnull
- protected String getNextRequestId() {
- String requestId;
- do {
- requestId = Integer.toString(ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE));
- } while(getStepById(requestId) != null);
- return requestId;
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchRequestStep.java b/src/main/java/com/microsoft/graph/content/BatchRequestStep.java
deleted file mode 100644
index cb6ae415a..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchRequestStep.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.HashSet;
-
-import javax.annotation.Nullable;
-
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-
-/** the http request for the batch step */
-public class BatchRequestStep extends BatchStep {
- /** The URL to query for the step */
- @Nullable
- @Expose
- @SerializedName("url")
- public String url;
- /** The HTTP method to use to execute the request */
- @Nullable
- @Expose
- @SerializedName("method")
- public String method;
- /** The IDs of the steps this step depends on before being executed */
- @Nullable
- @Expose
- @SerializedName("dependsOn")
- public HashSet dependsOn;
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchResponseContent.java b/src/main/java/com/microsoft/graph/content/BatchResponseContent.java
deleted file mode 100644
index fe8022524..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchResponseContent.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.List;
-import java.util.Objects;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.google.gson.JsonElement;
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-
-/** Respresents the result of a JSON batch request */
-public class BatchResponseContent {
- /** Responses to the steps from the request */
- @Nullable
- @Expose
- @SerializedName("responses")
- public List> responses;
-
- /**
- * Gets a response to a request in the batch by its id
- * @param stepId Id of the request step in the batch request
- * @return The step response corresponding to the ID or null
- */
- @Nullable
- public BatchResponseStep getResponseById(@Nonnull final String stepId) {
- Objects.requireNonNull(stepId, "parameter stepId cannot be null");
- if(responses == null) return null;
-
- for(final BatchResponseStep step : responses) {
- if(stepId.equals(step.id))
- return step;
- }
- return null;
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchResponseStep.java b/src/main/java/com/microsoft/graph/content/BatchResponseStep.java
deleted file mode 100644
index 659761385..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchResponseStep.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-package com.microsoft.graph.content;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import com.google.gson.JsonElement;
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-import com.microsoft.graph.http.GraphErrorResponse;
-import com.microsoft.graph.http.GraphFatalServiceException;
-import com.microsoft.graph.http.GraphServiceException;
-import com.microsoft.graph.logger.ILogger;
-import com.microsoft.graph.logger.LoggerLevel;
-import com.microsoft.graph.serializer.DefaultSerializer;
-import com.microsoft.graph.serializer.ISerializer;
-
-/** Response for the batch step */
-public class BatchResponseStep extends BatchStep {
- /** Http status code of the response */
- @Expose
- @SerializedName("status")
- public int status;
- /** Serializer to use for response deserialization */
- @Nullable
- protected ISerializer serializer;
-
- /**
- * Returned the deserialized response body of the current step
- * @param type of the response body
- * @param resultClass class of the resulting response body
- * @return the deserialized response body
- * @throws GraphServiceException when a bad request was sent
- * @throws GraphFatalServiceException when the service did not complete the operation as expected because of an internal error
- */
- @Nullable
- public T2 getDeserializedBody(@Nonnull final Class resultClass) throws GraphServiceException, GraphFatalServiceException {
- Objects.requireNonNull(resultClass, "parameter resultClass cannot be null");
- if(serializer == null || body == null || !(body instanceof JsonElement)) return null;
-
- final GraphErrorResponse error = serializer.deserializeObject((JsonElement)body, GraphErrorResponse.class);
- if(error == null || error.error == null) {
- return serializer.deserializeObject((JsonElement)body, resultClass);
- } else {
- boolean verboseError = false;
- if(serializer instanceof DefaultSerializer) {
- final ILogger logger = ((DefaultSerializer)serializer).getLogger();
- verboseError = logger != null && logger.getLoggingLevel() == LoggerLevel.DEBUG;
- }
- throw GraphServiceException.createFromResponse("", "", new ArrayList<>(), "", headers, "", status, error, verboseError);
- }
- }
-}
diff --git a/src/main/java/com/microsoft/graph/content/BatchStep.java b/src/main/java/com/microsoft/graph/content/BatchStep.java
deleted file mode 100644
index 89773904e..000000000
--- a/src/main/java/com/microsoft/graph/content/BatchStep.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2021 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.content;
-
-import java.util.HashMap;
-
-import javax.annotation.Nullable;
-
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-
-/** Common abstractions between batch request steps and batch response steps */
-public abstract class BatchStep {
- /** The Id of the step */
- @Expose
- @Nullable
- @SerializedName("id")
- public String id;
- /** The request/response headers for the step */
- @Expose
- @Nullable
- @SerializedName("headers")
- public HashMap headers;
- /** The body of request/response for the step */
- @Nullable
- @Expose
- @SerializedName("body")
- public T body;
-}
diff --git a/src/main/java/com/microsoft/graph/core/BaseClient.java b/src/main/java/com/microsoft/graph/core/BaseClient.java
deleted file mode 100644
index 27382a382..000000000
--- a/src/main/java/com/microsoft/graph/core/BaseClient.java
+++ /dev/null
@@ -1,382 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2017 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.core;
-
-import com.google.gson.JsonElement;
-import com.microsoft.graph.http.CoreHttpProvider;
-import com.microsoft.graph.http.IHttpProvider;
-import com.microsoft.graph.httpcore.HttpClients;
-import com.microsoft.graph.authentication.IAuthenticationProvider;
-import com.microsoft.graph.content.BatchRequestBuilder;
-import com.microsoft.graph.logger.DefaultLogger;
-import com.microsoft.graph.logger.ILogger;
-import com.microsoft.graph.serializer.DefaultSerializer;
-import com.microsoft.graph.serializer.ISerializer;
-
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Objects;
-
-import javax.annotation.Nonnull;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import okhttp3.Call;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-
-/**
- * A client that communications with an OData service
- * @param type of a request for the native http client
- */
-public class BaseClient implements IBaseClient {
- /**
- * Restricted constructor
- */
- protected BaseClient() {
- }
-
- /**
- * The default endpoint for the Microsoft Graph Service
- */
- public static final String DEFAULT_GRAPH_ENDPOINT = "https://graph.microsoft.com/v1.0";
-
- /**
- * The current endpoint
- */
- private String endpoint;
-
- @Override
- @Nonnull
- public String getServiceRoot() {
- if (endpoint == null) {
- endpoint = DEFAULT_GRAPH_ENDPOINT;
- }
- return endpoint;
- }
-
- @Override
- public void setServiceRoot(@Nonnull final String value) {
- Objects.requireNonNull(value, "value parameter cannot be null");
- endpoint = String.valueOf(value);
- }
-
- /**
- * Send a custom request to Graph
- *
- * @param url
- * the full URL to make a request with
- * @param responseType
- * the response class to deserialize the response into
- * @return the instance of this builder
- */
- @Nonnull
- public CustomRequestBuilder customRequest(@Nonnull final String url, @Nonnull final Class responseType) {
- Objects.requireNonNull(url, "url parameter cannot be null");
- Objects.requireNonNull(responseType, "responseType parameter cannot be null");
- return new CustomRequestBuilder<>(getServiceRoot() + url, this, null, responseType);
- }
-
- /**
- * Send a custom request to Graph
- *
- * @param url
- * the full URL to make a request with
- * @return the instance of this builder
- */
- @Nonnull
- public CustomRequestBuilder customRequest(@Nonnull final String url) {
- return this.customRequest(url, JsonElement.class);
- }
-
- /**
- * Get the batch request builder.
- * @return a request builder to execute a batch.
- */
- @Nonnull
- public BatchRequestBuilder batch() {
- return new BatchRequestBuilder(getServiceRoot() + "/$batch", this, Collections.emptyList());
- }
-
- /**
- * Gets the builder to start configuring the client
- *
- * @return builder to start configuring the client
- */
- @Nonnull
- public static Builder builder() {
- return builder(OkHttpClient.class, Request.class);
- }
-
- /**
- * Gets the builder to start configuring the client
- *
- * @param the type of the native http client
- * @param the type of the native http request
- * @param nativeClientClass the class of the native http client
- * @param nativeRequestClass the class of the native http request
- * @return builder to start configuring the client
- */
- @Nonnull
- public static Builder builder(@Nonnull final Class nativeClientClass, @Nonnull final Class nativeRequestClass) {
- return new Builder<>();
- }
-
- /**
- * Builder to help configure the Graph service client
- * @param type of the native http library client
- * @param type of a request for the native http client
- */
- public static class Builder {
- private ISerializer serializer;
- private IHttpProvider httpProvider;
- private ILogger logger;
- private httpClientType httpClient;
- private IAuthenticationProvider auth;
-
- private IAuthenticationProvider getAuthenticationProvider() {
- if(auth == null) {
- throw new NullPointerException("auth");
- } else {
- return auth;
- }
- }
- private ILogger getLogger() {
- if(logger == null) {
- return new DefaultLogger();
- } else {
- return logger;
- }
- }
- private ISerializer getSerializer() {
- if(serializer == null) {
- return new DefaultSerializer(getLogger());
- } else {
- return serializer;
- }
- }
- @SuppressWarnings("unchecked")
- private httpClientType getHttpClient() {
- if(httpClient == null) {
- return (httpClientType)HttpClients.createDefault(getAuthenticationProvider());
- } else {
- return httpClient;
- }
- }
- @SuppressWarnings("unchecked")
- private IHttpProvider getHttpProvider() {
- if(httpProvider == null) {
- return (IHttpProvider)new CoreHttpProvider(getSerializer(), getLogger(), (Call.Factory) getHttpClient());
- } else {
- return httpProvider;
- }
- }
-
- /**
- * Sets the serializer.
- *
- * @param serializer
- * the serializer
- * @return the instance of this builder
- */
- @Nonnull
- public Builder serializer(@Nonnull final ISerializer serializer) {
- Objects.requireNonNull(serializer, "parameter serializer cannot be null");
- this.serializer = serializer;
- return this;
- }
-
- /**
- * Sets the httpProvider
- *
- * @param httpProvider
- * the httpProvider
- * @return the instance of this builder
- */
- @Nonnull
- public Builder httpProvider(@Nonnull final IHttpProvider httpProvider) {
- Objects.requireNonNull(httpProvider, "parameter httpProvider cannot be null");
- this.httpProvider = httpProvider;
- return this;
- }
-
- /**
- * Sets the logger
- *
- * @param logger
- * the logger
- * @return the instance of this builder
- */
- @Nonnull
- @SuppressFBWarnings
- public Builder logger(@Nonnull final ILogger logger) {
- Objects.requireNonNull(logger, "parameter logger cannot be null");
- this.logger = logger;
- return this;
- }
-
- /**
- * Sets the http client
- *
- * @param client the http client
- *
- * @return the instance of this builder
- */
- @Nonnull
- public Builder httpClient(@Nonnull final httpClientType client) {
- Objects.requireNonNull(client, "parameter client cannot be null");
- this.httpClient = client;
- return this;
- }
-
- /**
- * Sets the authentication provider
- *
- * @param auth the authentication provider
- * @return the instance of this builder
- */
- @Nonnull
- public Builder authenticationProvider(@Nonnull final IAuthenticationProvider auth) {
- Objects.requireNonNull(auth, "parameter auth cannot be null");
- this.auth = auth;
- return this;
- }
-
- /**
- * Builds and returns the Graph service client.
- *
- * @param instance the instance to set the information for
- * @param the type of the client to return
- * @return the Graph service client object
- * @throws ClientException if there was an exception creating the client
- */
- @Nonnull
- protected > ClientType buildClient(@Nonnull ClientType instance) throws ClientException {
- Objects.requireNonNull(instance, "The instance cannot be null");
- instance.setHttpProvider(this.getHttpProvider());
- instance.setLogger(this.getLogger());
- instance.setSerializer(this.getSerializer());
- return instance;
- }
-
- /**
- * Builds and returns the Graph service client.
- *
- * @return the Graph service client object
- * @throws ClientException
- * if there was an exception creating the client
- */
- @Nonnull
- public IBaseClient buildClient() throws ClientException {
- return buildClient(new BaseClient<>());
- }
- }
-
- /**
- * The HTTP provider instance
- */
- private IHttpProvider httpProvider;
-
- /**
- * The logger
- */
- private ILogger logger;
-
- /**
- * The serializer instance
- */
- private ISerializer serializer;
-
- /**
- * Gets the HTTP provider
- *
- * @return The HTTP provider
- */
- @Override
- @Nullable
- public IHttpProvider getHttpProvider() {
- return httpProvider;
- }
-
- /**
- * Gets the logger
- *
- * @return The logger
- */
- @Nullable
- @SuppressFBWarnings
- public ILogger getLogger() {
- return logger;
- }
-
- /**
- * Gets the serializer
- *
- * @return The serializer
- */
- @Override
- @Nullable
- public ISerializer getSerializer() {
- return serializer;
- }
-
- /**
- * Sets the logger
- *
- * @param logger The logger
- */
- protected void setLogger(@Nonnull final ILogger logger) {
- Objects.requireNonNull(logger, "parameter logger cannot be null");
- this.logger = logger;
- }
-
- /**
- * Sets the HTTP provider
- *
- * @param httpProvider The HTTP provider
- */
- protected void setHttpProvider(@Nonnull final IHttpProvider httpProvider) {
- Objects.requireNonNull(httpProvider, "parameter httpProvider cannot be null");
- this.httpProvider = httpProvider;
- }
-
- /**
- * Sets the serializer
- *
- * @param serializer The serializer
- */
- public void setSerializer(@Nonnull final ISerializer serializer) {
- Objects.requireNonNull(serializer, "parameter serializer cannot be null");
- this.serializer = serializer;
- }
-
- /**
- * Gets the service SDK version if the service SDK is in use, null otherwise
- * @return the service SDK version if the service SDK is in use, null otherwise
- */
- @Override
- @Nullable
- public String getServiceSDKVersion() {
- return null;
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/ClientException.java b/src/main/java/com/microsoft/graph/core/ClientException.java
deleted file mode 100644
index a5ab34469..000000000
--- a/src/main/java/com/microsoft/graph/core/ClientException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2017 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.core;
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-/**
- * An exception from the client.
- */
-public class ClientException extends RuntimeException {
-
- private static final long serialVersionUID = -1066560879567392559L;
-
- /**
- * Creates the client exception
- *
- * @param message the message to display
- * @param ex the exception from
- */
- public ClientException(@Nonnull final String message, @Nullable final Throwable ex) {
- super(message, ex);
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/CoreConstants.java b/src/main/java/com/microsoft/graph/core/CoreConstants.java
new file mode 100644
index 000000000..b31b20952
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/CoreConstants.java
@@ -0,0 +1,147 @@
+package com.microsoft.graph.core;
+
+import jakarta.annotation.Nonnull;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Core Constants for use in other classes.
+ */
+public final class CoreConstants {
+ private CoreConstants() {}
+
+ private static class VersionValues {
+ private static final int MAJOR = 3;
+ private static final int MINOR = 1;
+ private static final int PATCH = 0;
+ }
+
+ /**
+ * Header Constants
+ */
+ public static class Headers {
+ private Headers(){}
+ /** Bearer string constant. */
+ public static final String BEARER = "Bearer";
+ /** SDK version header constant. */
+ public static final String SDK_VERSION_HEADER_NAME = "SdkVersion";
+ /** Graph version prefix header constant. */
+ public static final String GRAPH_VERSION_PREFIX = "graph-java-core";
+ /** Android version prefix header constant. */
+ public static final String ANDROID_VERSION_PREFIX = "android";
+ /** Java version prefix header constant. */
+ public static final String JAVA_VERSION_PREFIX = "java";
+ /** Version number header. */
+ public static final String VERSION = String.format(Locale.US, "%d.%d.%d", VersionValues.MAJOR, VersionValues.MINOR, VersionValues.PATCH);
+ /** Client Request ID header constant. */
+ public static final String CLIENT_REQUEST_ID = "client-request-id";
+ /** Feature flag header constant. */
+ public static final String FEATURE_FLAG = "FeatureFlag";
+ /** Default version value constant. */
+ public static final String DEFAULT_VERSION_VALUE = "0";
+ }
+
+ /**
+ * Batch Request Constants
+ */
+ public static class BatchRequest {
+ private BatchRequest(){}
+ /** Batch request max requests property */
+ public static final int MAX_REQUESTS = 20;
+ /** Batch request step id property */
+ public static final String ID = "id";
+ /** Batch request step url property */
+ public static final String URL = "url";
+ /** Batch request step body property */
+ public static final String BODY = "body";
+ /** Batch request step dependsOn property */
+ public static final String DEPENDS_ON = "dependsOn";
+ /** Batch request step method property */
+ public static final String METHOD = "method";
+ /** Batch request step requests property */
+ public static final String REQUESTS = "requests";
+ /** Batch request step responses property */
+ public static final String RESPONSES = "responses";
+ /** Batch request step status property */
+ public static final String STATUS = "status";
+ /** Batch request step headers property */
+ public static final String HEADERS = "headers";
+ /** Batch request step error property */
+ public static final String ERROR = "error";
+ }
+
+ /**
+ * MimeTypeNames Constants
+ */
+ public static class MimeTypeNames {
+ private MimeTypeNames(){}
+ /** Content type header constant for application/json */
+ public static final String APPLICATION_JSON = "application/json";
+ /** Content type header constant for application/octet-stream */
+ public static final String APPLICATION_STREAM = "application/octet-stream";
+ }
+
+ /**
+ * Serialization Constants
+ */
+ public static class Serialization {
+ private Serialization(){}
+ /** OData type property */
+ public static final String ODATA_TYPE = "@odata.type";
+ /** OData nextLink property */
+ public static final String ODATA_NEXT_LINK = "@nextLink";
+ }
+
+ /**
+ * Odata Instance Annotation Constants
+ */
+ public static class OdataInstanceAnnotations {
+ private OdataInstanceAnnotations(){}
+ /** NextLink odata instance annotation */
+ public static final String NEXT_LINK = "@odata.nextLink";
+ /** DeltaLink odata instance annotation */
+ public static final String DELTA_LINK = "@odata.deltaLink";
+ }
+
+ /**
+ * Collection Response Method Name Constants
+ */
+ public static class CollectionResponseMethods {
+ private CollectionResponseMethods() {}
+ /** Method name constant for getOdataDeltaLink in collection responses */
+ public static final String GET_ODATA_DELTA_LINK = "getOdataDeltaLink";
+ /** Method name constant for getOdataNextLink in collection responses */
+ public static final String GET_ODATA_NEXT_LINK = "getOdataNextLink";
+ }
+
+ /**
+ * Url Replacement Constants
+ * Example: /users/{id} -> /me
+ */
+ public static class ReplacementConstants {
+ private ReplacementConstants() {
+ }
+ /** Default token to replace the id value in 'user/{id}' */
+ public static final String USER_ID_TOKEN_TO_REPLACE = "TokenToReplace";
+ /** Default endpoint to be replaced by /me
+ * users/TokenToReplace -> /me
+ */
+ public static final String USERS_ENDPOINT_WITH_REPLACE_TOKEN = "/users/" + USER_ID_TOKEN_TO_REPLACE;
+ /** /me endpoint constant */
+ public static final String ME_ENDPOINT = "/me";
+
+ /**
+ * The default replacement pairs for /users/{id} -> /me
+ * @return the default replacement pairs
+ */
+ @Nonnull
+ public static Map getDefaultReplacementPairs() {
+ HashMap defaultReplacementPairs = new HashMap<>();
+ defaultReplacementPairs.put(USERS_ENDPOINT_WITH_REPLACE_TOKEN, ME_ENDPOINT);
+ return defaultReplacementPairs;
+ }
+
+ }
+
+}
diff --git a/src/main/java/com/microsoft/graph/core/CustomRequestBuilder.java b/src/main/java/com/microsoft/graph/core/CustomRequestBuilder.java
deleted file mode 100644
index 468dcdde8..000000000
--- a/src/main/java/com/microsoft/graph/core/CustomRequestBuilder.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.microsoft.graph.core;
-
-import java.util.List;
-import java.util.Objects;
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-import com.microsoft.graph.http.BaseRequestBuilder;
-import com.microsoft.graph.http.CustomRequest;
-import com.microsoft.graph.options.Option;
-
-/**
- * The class for the CustomRequestBuilder
- *
- * If the provided URL is malformed, the ClientException will contain a MalformedURLException
- */
-public class CustomRequestBuilder extends BaseRequestBuilder {
- /** Type to use for response deserialization */
- public final Class responseType;
-
- /**
- * Instanciates a new custom request builder
- *
- * @param requestUrl the URL to send the request to
- * @param client the client to use for the request
- * @param requestOptions options to apply to the request
- * @param responseType type to use for response deserialization
- */
- public CustomRequestBuilder(@Nonnull final String requestUrl, @Nonnull final IBaseClient> client, @Nullable final List extends Option> requestOptions, @Nonnull final Class responseType) {
- super(requestUrl, client, requestOptions);
- this.responseType = Objects.requireNonNull(responseType, "parameter responseType cannot be null");
- }
-
- /**
- * Builds the request to be executed
- *
- * @return the request to be executed
- * @param requestOptions the options to apply to the request
- */
- @Nonnull
- public CustomRequest buildRequest(@Nullable final com.microsoft.graph.options.Option... requestOptions) {
- return buildRequest(getOptions(requestOptions));
- }
-
- /**
- * Builds the request to be executed
- *
- * @return the request to be executed
- * @param requestOptions the options to apply to the request
- */
- @Nonnull
- public CustomRequest buildRequest(@Nullable final List extends Option> requestOptions) {
- return new CustomRequest<>(getRequestUrl(), getClient(), requestOptions, responseType);
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/DateOnly.java b/src/main/java/com/microsoft/graph/core/DateOnly.java
deleted file mode 100644
index e5a805092..000000000
--- a/src/main/java/com/microsoft/graph/core/DateOnly.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.microsoft.graph.core;
-
-
-import java.text.ParseException;
-import java.util.Locale;
-import java.util.Objects;
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-/**
- * A timezone-nonspecific date
- */
-public class DateOnly {
-
- /**
- * The year
- */
- private final int mYear;
-
- /**
- * The month
- */
- private final int mMonth;
-
- /**
- * The day
- */
- private final int mDay;
-
- /**
- * Constructs a timezone-nonspecific DateOnly
- *
- * @param dateStr date string of the form yyyy-mm-dd
- * @return the parsed DateOnly instance
- * @exception ParseException If there was a failure parsing the dateStr
- */
- @Nullable
- public static DateOnly parse(@Nonnull final String dateStr) throws ParseException {
- Objects.requireNonNull(dateStr, "parameter dateStr cannot be null");
- // break the date up into its constituent parts
- final String[] dateInfo = dateStr.split("-");
-
- // validate the split date string
- final int expectedLength = 3;
- if (dateInfo.length != expectedLength) {
- throw new ParseException(
- "Expected datestring format 'yyyy-mm-dd' but found: " + dateStr, 0
- );
- }
-
- // array indices for date parsing
- final int indYear = 0;
- final int indMonth = 1;
- final int indDay = 2;
-
- // unpack this array
- int year = Integer.parseInt(dateInfo[indYear]);
- int month = Integer.parseInt(dateInfo[indMonth]);
- int day = Integer.parseInt(dateInfo[indDay]);
-
- return new DateOnly(year, month, day);
- }
-
- /**
- * Constructs a timezone-nonspecific DateOnly
- *
- * @param year the year
- * @param month 1-indexed month value (Jan == 1)
- * @param day day of the month
- */
- public DateOnly(final int year, final int month, final int day) {
- mYear = year;
- mMonth = month;
- mDay = day;
- }
-
- /**
- * Gets the year
- *
- * @return the year
- */
- public int getYear() {
- return mYear;
- }
-
- /**
- * Gets the month
- *
- * @return the month
- */
- public int getMonth() {
- return mMonth;
- }
-
- /**
- * Gets the day
- *
- * @return the day
- */
- public int getDay() {
- return mDay;
- }
-
- @Override
- public String toString() {
- return String.format(
- Locale.ROOT,
- "%04d-%02d-%02d", mYear, mMonth, mDay
- );
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/ErrorConstants.java b/src/main/java/com/microsoft/graph/core/ErrorConstants.java
new file mode 100644
index 000000000..02adc04da
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/ErrorConstants.java
@@ -0,0 +1,95 @@
+package com.microsoft.graph.core;
+/**
+ * Constants used for exception building
+ */
+public class ErrorConstants {
+ private ErrorConstants() {}
+
+ /**
+ * Exception codes
+ */
+ public static class Codes {
+ private Codes() {}
+ /** General exception code. */
+ public static final String GENERAL_EXCEPTION = "generalException";
+ /** Invalid request exception code. */
+ public static final String INVALID_REQUEST = "invalidRequest";
+ /** Item not found exception code. */
+ public static final String ITEM_NOT_FOUND = "itemNotFound";
+ /** Not allowed exception code. */
+ public static final String NOT_ALLOWED = "notAllowed";
+ /** Timeout exception code.*/
+ public static final String TIMEOUT = "timeout";
+ /** Too many redirects exception code. */
+ public static final String TOO_MANY_REDIRECTS = "tooManyRedirects";
+ /** Too many retries exception code. */
+ public static final String TOO_MANY_RETRIES = "tooManyRetries";
+ /** Maximum value exceeded exception code. */
+ public static final String MAXIMUM_VALUE_EXCEEDED = "MaximumValueExceeded";
+ /** Invalid argument exception code. */
+ public static final String INVALID_ARGUMENT = "invalidArgument";
+ /** Temporarily unavailable exception code. */
+ public static final String TEMPORARILY_UNAVAILABLE = "temporarily_unavailable";
+ /** Invalid range exception code. */
+ public static final String INVALID_RANGE = "invalidRange";
+ }
+
+ /**
+ * Exception messages
+ */
+ public static class Messages {
+ private Messages() {}
+ /** Authentication provider missing error message. */
+ public static final String AUTHENTICATION_PROVIDER_MISSING = "Authentication provider is required before sending a request.";
+ /** Base Url missing error message. */
+ public static final String BASE_URL_MISSING = "Base URL cannot be null or empty.";
+ /** Invalid type for date converter error message. */
+ public static final String INVALID_TYPE_FOR_DATE_CONVERTER = "DateConverter can only serialize objects of type Date.";
+ /** Invalid type for date time offset converter error message. */
+ public static final String INVALID_TYPE_FOR_DATE_TIME_OFFSET_CONVERTER = "DateTimeOffsetConverter can only serialize objects of type DateTimeOffset.";
+ /** Location header not set on redirect error message. */
+ public static final String LOCATION_HEADER_NOT_SET_ON_REDIRECT = "Location header not present in redirection response.";
+ /** Overall timeout cannot be set error message. */
+ public static final String OVERALL_TIMEOUT_CANNOT_BE_SET = "Overall timeout cannot be set after the first request is sent.";
+ /** Request timed out error message. */
+ public static final String REQUEST_TIMED_OUT = "The request timed out.";
+ /** Request Url missing error message. */
+ public static final String REQUEST_URL_MISSING = "Request URL is required to send a request.";
+ /** Too many redirects error message. */
+ public static final String TOO_MANY_REDIRECTS_FORMAT_STRING = "More than %d redirects encountered while sending the request.";
+ /** Too many retries error message. */
+ public static final String TOO_MANY_RETRIES_FORMAT_STRING = "More than %d retries encountered while sending the request.";
+ /** Unable to create instance of type error message. */
+ public static final String UNABLE_TO_CREATE_INSTANCE_OF_TYPE_FORMAT_STRING = "Unable to create an instance of type %s.";
+ /** Unable to deserialize date error message. */
+ public static final String UNABLE_TO_DESERIALIZE_DATE = "Unable to deserialize the returned Date.";
+ /** Unable to deserialize date time offset error message. */
+ public static final String UNABLE_TO_DESERIALIZE_DATE_TIME_OFFSET = "Unable to deserialize the returned DateDateTimeOffset.";
+ /** Unexpected exception on send error message. */
+ public static final String UNEXPECTED_EXCEPTION_ON_SEND = "An error occurred sending the request.";
+ /** Unexpected exception response error message. */
+ public static final String UNEXPECTED_EXCEPTION_RESPONSE = "Unexpected exception returned from the service.";
+ /** Maximum value exceeded error message. */
+ public static final String MAXIMUM_VALUE_EXCEEDED = "%s exceeds the maximum value of %d.";
+ /** Null parameter error message. */
+ public static final String NULL_PARAMETER = "The following parameter cannot be null: ";
+ /** Unable to deserialize content error message. */
+ public static final String UNABLE_TO_DESERIALIZE_CONTENT = "Unable to deserialize content.";
+ /** Invalid depends on request Id error message. */
+ public static final String INVALID_DEPENDS_ON_REQUEST_ID = "Corresponding batch request id not found for the specified dependsOn relation.";
+ /** Expired upload session error message. */
+ public static final String EXPIRED_UPLOAD_SESSION = "Upload session expired. Upload cannot resume";
+ /** No response for upload error message. */
+ public static final String NO_RESPONSE_FOR_UPLOAD = "No Response Received for upload.";
+ /** Null value error message. */
+ public static final String NULL_VALUE = "%s cannot be null.";
+ /** Unexpected msal exception error message. */
+ public static final String UNEXPECTED_MSAL_EXCEPTION = "Unexpected exception returned from MSAL.";
+ /** Unexpected exception error message. */
+ public static final String UNEXPECTED_EXCEPTION = "Unexpected exception occurred while authenticating the request.";
+ /** Missing retry after header error message. */
+ public static final String MISSING_RETRY_AFTER_HEADER = "Missing retry after header.";
+ /** Invalid proxy argument error message. */
+ public static final String INVALID_PROXY_ARGUMENT = "Proxy cannot be set more once. Proxy can only be set on the proxy or defaultHttpHandler argument and not both.";
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/GraphErrorCodes.java b/src/main/java/com/microsoft/graph/core/GraphErrorCodes.java
deleted file mode 100644
index 2ec00b40b..000000000
--- a/src/main/java/com/microsoft/graph/core/GraphErrorCodes.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2017 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.core;
-
-/**
- * The common Graph error codes
- * @see https://docs.microsoft.com/en-us/graph/errors
- */
-public enum GraphErrorCodes {
- // Standard error codes.
- /** The collar doesn't have permission to perform the action */
- ACCESS_DENIED,
- /** The app or user has been throttled */
- ACTIVITY_LIMIT_REACHED,
- /** No description available */
- ASYNC_TASK_FAILED,
- /** No description available */
- ASYNC_TASK_NOT_COMPLETED,
- /** No description available */
- AUTHENTICATION_CANCELLED,
- /** No description available */
- AUTHENTICATION_FAILURE,
- /** An unspecified error has occurred. */
- GENERAL_EXCEPTION,
- /** The resource could not be found, specific to the Exchange workload. */
- ERROR_ITEM_NOT_FOUND,
- /** The specified byte range is invalid or unavailable. */
- INVALID_RANGE,
- /** The request is malformed or incorrect. */
- INVALID_REQUEST,
- /** The resource could not be found. */
- ITEM_NOT_FOUND,
- /** Malware was detected in the requested resource. */
- MALWARE_DETECTED,
- /** The specified item name already exists. */
- NAME_ALREADY_EXISTS,
- /** The action is not allowed by the system. */
- NOT_ALLOWED,
- /** The request is not supported by the system. */
- NOT_SUPPORTED,
- /** The user has reached their quota limit. */
- QUOTA_LIMIT_REACHED,
- /** The resource being updated has changed since the caller last read it, usually an eTag mismatch. */
- RESOURCE_MODIFIED,
- /** The delta token is no longer valid, and the app must reset the sync state. */
- RESYNC_REQUIRED,
- /** The service is not available. Try the request again after a delay. There may be a Retry-After header. */
- SERVICE_NOT_AVAILABLE,
- /** The application is sending too many requests to the service. Try the request again after a delay. There may be a Retry-After header. */
- TOO_MANY_REDIRECTS,
- /** The caller is not authenticated. */
- UNAUTHENTICATED,
-
- // Extend error codes.
- /** No description available */
- ACCESS_RESTRICTED,
- /** Access restricted to the item's owner. */
- AUTHORIZATION_REQUEST_DENIED,
- /** Failed to get a consistent delta snapshot. Try again later. */
- CANNOT_SNAPSHOT_TREE,
- /** Max limit on the number of child items was reached. */
- CHILD_ITEM_COUNT_EXCEEDED,
- /** No description available */
- ERROR_INVALID_ID_MALFORMED,
- /** No description available */
- ERROR_INVALID_USER,
- /** ETag does not match the current item's value. */
- ENTITY_TAG_DOES_NOT_MATCH,
- /** Declared total size for this fragment is different from that of the upload session. */
- FRAGMENT_LENGTH_MISMATCH,
- /** Uploaded fragment is out of order. */
- FRAGMENT_OUT_OF_ORDER,
- /** Uploaded fragment overlaps with existing data. */
- FRAGMENT_OVERLAP,
- /** Invalid accept type. */
- INVALID_ACCEPT_TYPE,
- /** Invalid parameter format. */
- INVALID_PARAMETER_FORMAT,
- /** Name contains invalid characters. */
- INVALID_PATH,
- /** Invalid query option. */
- INVALID_QUERY_OPTION,
- /** Invalid start index. */
- INVALID_START_INDEX,
- /** Lock token does not match existing lock. */
- LOCK_MISMATCH,
- /** There is currently no unexpired lock on the item. */
- LOCK_NOT_FOUND_OR_ALREADY_EXPIRED,
- /** Lock Owner ID does not match provided ID. */
- LOCK_OWNER_MISMATCH,
- /** ETag header is malformed. ETags must be quoted strings. */
- MALFORMED_ENTITY_TAG,
- /** Max limit on number of Documents is reached. */
- MAX_DOCUMENT_COUNT_EXCEEDED,
- /** Max file size exceeded. */
- MAX_FILE_SIZE_EXCEEDED,
- /** Max limit on number of Folders is reached. */
- MAX_FOLDER_COUNT_EXCEEDED,
- /** Max file size exceeded. */
- MAX_FRAGMENT_LENGTH_EXCEEDED,
- /** Max limit on number of Items is reached. */
- MAX_ITEM_COUNT_EXCEEDED,
- /** Max query length exceeded. */
- MAX_QUERY_LENGTH_EXCEEDED,
- /** Maximum stream size exceeded. */
- MAX_STREAM_SIZE_EXCEEDED,
- /** Parameter Exceeds Maximum Length. */
- PARAMETER_IS_TOO_LONG,
- /** Parameter is smaller then minimum value. */
- PARAMETER_IS_TOO_SMALL,
- /** Path exceeds maximum length. */
- PATH_IS_TOO_LONG,
- /** Folder hierarchy depth limit reached. */
- PATH_TOO_DEEP,
- /** Property not updateable. */
- PROPERTY_NOT_UPDATEABLE,
- /** Resync required. Replace any local items with the server's version (including deletes) if you're sure that the service was up to date with your local changes when you last sync'd. Upload any local changes that the server doesn't know about. */
- RESYNC_APPLY_DIFFERENCES,
- /** Resync required. Upload any local items that the service did not return, and upload any files that differ from the server's version (keeping both copies if you're not sure which one is more up-to-date). */
- RESYNC_UPLOAD_DIFFERENCES,
- /** Resource is temporarily read-only. */
- SERVICE_READ_ONLY,
- /** Too many requests. */
- THROTTLED_REQUEST,
- /** Too many results requested. */
- TOO_MANY_RESULTS_REQUESTED,
- /** Too many terms in the query. */
- TOO_MANY_TERMS_IN_QUERY,
- /** Operation is not allowed because the number of affected items exceeds threshold. */
- TOTAL_AFFECTED_ITEM_COUNT_EXCEEDED,
- /** Data truncation is not allowed. */
- TRUNCATION_NOT_ALLOWED,
- /** Upload session failed. */
- UPLOAD_SESSION_FAILED,
- /** Upload session incomplete. */
- UPLOAD_SESSION_INCOMPLETE,
- /** Upload session not found. */
- UPLOAD_SESSION_NOT_FOUND,
- /** This document is suspicious and may have a virus. */
- VIRUS_SUSPICIOUS,
- /** Zero or fewer results requested. */
- ZERO_OR_FEWER_RESULTS_REQUESTED,
-}
diff --git a/src/main/java/com/microsoft/graph/core/IBaseClient.java b/src/main/java/com/microsoft/graph/core/IBaseClient.java
deleted file mode 100644
index b3b0e7d32..000000000
--- a/src/main/java/com/microsoft/graph/core/IBaseClient.java
+++ /dev/null
@@ -1,111 +0,0 @@
-// ------------------------------------------------------------------------------
-// Copyright (c) 2017 Microsoft Corporation
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ------------------------------------------------------------------------------
-
-package com.microsoft.graph.core;
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-import com.google.gson.JsonElement;
-import com.microsoft.graph.content.BatchRequestBuilder;
-import com.microsoft.graph.http.IHttpProvider;
-import com.microsoft.graph.logger.ILogger;
-import com.microsoft.graph.serializer.ISerializer;
-
-/**
- * A client that communications with an OData service
- * @param type of a request for the native http client
- */
-public interface IBaseClient {
- /**
- * Gets the service root
- *
- * @return the service root
- */
- @Nonnull
- String getServiceRoot();
-
- /**
- * Sets the service root
- *
- * @param value the service root
- */
- void setServiceRoot(@Nonnull final String value);
-
- /**
- * Gets the HTTP provider
- *
- * @return the HTTP provider
- */
- @Nullable
- IHttpProvider getHttpProvider();
-
- /**
- * Gets the logger
- *
- * @return the logger
- */
- @Nullable
- ILogger getLogger();
-
- /**
- * Gets the serializer
- *
- * @return the serializer
- */
- @Nullable
- ISerializer getSerializer();
-
- /**
- * Gets a builder to execute a custom request
- *
- * @return the custom request builder
- * @param url the url to send the request to
- * @param responseType the class to deserialize the response to
- * @param the type to deserialize the response to
- */
- @Nonnull
- CustomRequestBuilder customRequest(@Nonnull final String url, @Nonnull final Class responseType);
-
- /**
- * Gets a builder to execute a custom request with a generic JSONObject response
- *
- * @return the custom request builder
- * @param url the url to send the request to
- */
- @Nonnull
- CustomRequestBuilder customRequest(@Nonnull final String url);
-
- /**
- * Get the batch request builder.
- * @return a request builder to execute a batch.
- */
- @Nonnull
- BatchRequestBuilder batch();
-
- /**
- * Gets the service SDK version if the service SDK is in use, null otherwise
- * @return the service SDK version if the service SDK is in use, null otherwise
- */
- @Nullable
- String getServiceSDKVersion();
-}
diff --git a/src/main/java/com/microsoft/graph/core/Multipart.java b/src/main/java/com/microsoft/graph/core/Multipart.java
deleted file mode 100644
index 878f3e84c..000000000
--- a/src/main/java/com/microsoft/graph/core/Multipart.java
+++ /dev/null
@@ -1,268 +0,0 @@
-package com.microsoft.graph.core;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-import java.util.Map;
-import java.util.Objects;
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.microsoft.graph.options.HeaderOption;
-
-/**
- * Helper for submitting multipart data
- *
- * This follows the Network Working Group's RFC
- * on multipart/form-data posting format:
- * https://www.ietf.org/rfc/rfc2388.txt
- */
-public class Multipart {
- private String boundary;
- private static final String RETURN = "\r\n";
- private ByteArrayOutputStream out;
- /** Default encoding for multi-part requests */
- public static final String MULTIPART_ENCODING = "US-ASCII";
- private String contentType = "multipart/form-data";
-
- /**
- * Create a new multipart object
- */
- public Multipart() {
- out = new ByteArrayOutputStream();
- boundary = "part_" + new BigInteger(130, new SecureRandom());
- }
-
- /**
- * Get the multipart boundary for use in the request header
- * @return the multipart boundary
- */
- @Nonnull
- public String getBoundary() {
- return boundary;
- }
-
- /**
- * Set the multipart boundary for use in the request header
- * @param boundary The multipart boundary
- */
- public void setBoundary(@Nonnull final String boundary) {
- this.boundary = Objects.requireNonNull(boundary, "parameter boundary cannot be null");
- }
-
- /**
- * Get the contentType for use in the request header
- * @return the multipart Content-Type
- */
- @Nonnull
- public String getContentType() {
- return contentType;
- }
-
- /**
- * Set the contentType for use in the request header
- * @param contentType The multipart Content-Type
- */
- public void setContentType(@Nonnull final String contentType) {
- this.contentType = Objects.requireNonNull(contentType, "parameter contentType cannot be null");
- }
-
- /**
- * Get the Content-Type header to send the multipart request
- * @return the multipart header option
- */
- @Nonnull
- public HeaderOption header() {
- return new HeaderOption("Content-Type", contentType + "; boundary=\"" + boundary + "\"");
- }
-
- private void writePartData(String partContent, byte[] byteArray) throws IOException{
- out.write(partContent.getBytes(MULTIPART_ENCODING));
- out.write(byteArray);
- String returnContent = RETURN + RETURN;
- out.write(returnContent.getBytes(MULTIPART_ENCODING));
- }
-
- /**
- * Create content headers value and parameter
- * @param name The content header name
- * @param contentType The content header Content-Type
- * @param filename The content header filename
- * @return content header value and parameter string
- */
- @VisibleForTesting
- String createPartHeader(String name, String contentType, String filename) {
- StringBuilder partContent = new StringBuilder(addBoundary());
- partContent.append("Content-Disposition: form-data");
- if(filename != null) {
- if(name != null)
- partContent.append("; name=\"").append(name).append("\"; filename=\"").append(filename).append("\"");
- else
- partContent.append("; filename=\"").append(filename).append("\"");
- }
- else if(name != null)
- partContent.append("; name=\"").append(name).append("\"");
- if(contentType != null)
- partContent.append(RETURN).append("Content-Type: ").append(contentType);
- partContent.append(RETURN).append(RETURN);
- return partContent.toString();
- }
-
- /**
- * Create content headers value and parameter
- * @param contentValue The content header value
- * @param contentDispParameter Map containing content paramter's key and value pair
- * @return content header value and parameter string
- */
- @Nonnull
- public static String createContentHeaderValue(@Nonnull final String contentValue, @Nullable final Map contentDispParameter) {
- final StringBuilder builder = new StringBuilder(contentValue);
-
- if(contentDispParameter != null) {
- for(Map.Entry entry : contentDispParameter.entrySet())
- builder.append(";").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\"");
- }
- return builder.toString();
- }
-
- /**
- * Create content headers header-name, value and parameter string
- * @param headers Map containing Header-name and header-value pair
- */
- private String createPartHeader(Map headers) {
- final StringBuilder builder = new StringBuilder(addBoundary());
- final String defaultPartContent = "Content-Disposition: form-data;" + RETURN + "Content-Type: " + contentType + RETURN + RETURN;
-
- if(headers != null) {
- for(Map.Entry entry : headers.entrySet())
- builder.append(entry.getKey()).append(": ").append(entry.getValue()).append(RETURN);
- builder.append(RETURN);
- } else
- builder.append(defaultPartContent);
- return builder.toString();
- }
-
- /**
- * Add multipart content headers and byte content
- * @param name The multipart content name
- * @param contentType The multipart Content-Type
- * @param filename The multipart content file name
- * @param byteArray The multipart byte content
- * @throws IOException
- */
- private void addData(String name, String contentType, String filename, byte[] byteArray) throws IOException {
- String partContent = createPartHeader(name, contentType, filename);
- writePartData(partContent, byteArray);
- }
-
- /**
- * Add a part to the multipart body
- * @param name The name of the part
- * @param contentType The MIME type (text/html, video/mp4, etc.)
- * @param byteArray The byte[] contents of the resource
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- public void addFormData(@Nonnull final String name, @Nonnull final String contentType, @Nonnull final byte[] byteArray) throws IOException {
- addData(name, contentType, null, byteArray);
- }
-
- /**
- * Add a part to the multipart body
- * @param contentType The MIME type (text/html, video/mp4, etc.)
- * @param byteArray The byte[] contents of the resource
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- public void addPart(@Nonnull final String contentType, @Nonnull final byte[] byteArray) throws IOException {
- addData(null, contentType, null, byteArray);
- }
-
- /**
- * Add a part to the multipart body
- * @param headers Map containing Header's header-name(eg: Content-Disposition, Content-Type, etc..) and header's value-parameter string
- * @param content The byte[] contents of the resource
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- public void addPart(@Nonnull final Map headers, @Nonnull final byte[] content) throws IOException{
- final String partContent = createPartHeader(headers);
- writePartData(partContent, content);
- }
-
- /**
- * Add an HTML part to the multipart body
- * @param name The name of the part
- * @param content The HTML body for the part
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- public void addHtmlPart(@Nonnull final String name, @Nonnull final byte[] content) throws IOException {
- addFormData(name, "text/html", content);
- }
-
- /**
- * Add a file part to the multipart body
- * @param name The name of the part
- * @param contentType The MIME type of the file (application/pdf, video/mp4, etc.)
- * @param file The file
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- public void addFilePart(@Nonnull final String name, @Nonnull final String contentType, @Nonnull final java.io.File file) throws IOException {
- try(final InputStream fileStream = new FileInputStream(file)) {
- final byte[] fileBytes = getByteArray(fileStream);
- addData(name, contentType, file.getName(), fileBytes);
- }
- }
-
- /**
- * Adds a boundary at the beginning of a new part
- * @return The boundary
- */
- private String addBoundary() {
- return "--" + boundary + RETURN;
- }
-
- /**
- * Adds a boundary at the end of the multipart body
- * @return The boundary
- */
- private String addEnding() {
- return "--" + boundary + "--";
- }
-
- /**
- * Returns a full multipart body byte array
- * @return The byte[] representation of the multipart object
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- @Nullable
- public byte[] content() throws IOException {
- ByteArrayOutputStream finalStream = out;
- finalStream.write(addEnding().getBytes(MULTIPART_ENCODING));
- return finalStream.toByteArray();
- }
-
- /**
- * Helper method to convert an InputStream to a byte[]
- * @param in The input stream to convert
- * @return The byte[]
- * @throws IOException Throws an exception if the output stream cannot be written to
- */
- private byte[] getByteArray(final InputStream in) throws IOException {
- try (final ByteArrayOutputStream buffer = new ByteArrayOutputStream()){
- int nRead;
- byte[] data = new byte[16384];
- try {
- while ((nRead = in.read(data, 0, data.length)) != -1) {
- buffer.write(data, 0, nRead);
- }
- } finally {
- in.close();
- }
- buffer.flush();
- return buffer.toByteArray();
- }
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/TimeOfDay.java b/src/main/java/com/microsoft/graph/core/TimeOfDay.java
deleted file mode 100644
index bc87efe02..000000000
--- a/src/main/java/com/microsoft/graph/core/TimeOfDay.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package com.microsoft.graph.core;
-
-
-import javax.annotation.Nullable;
-import javax.annotation.Nonnull;
-
-import java.math.BigDecimal;
-import java.text.ParseException;
-import java.util.Locale;
-import java.util.Objects;
-
-/**
- * The time of day
- */
-public class TimeOfDay {
-
- /**
- * The hour
- */
- private final int mHour;
-
- /**
- * The minute
- */
- private final int mMinute;
-
- /**
- * The second
- */
- private final int mSecond;
-
- /**
- * Constructs a timezone-nonspecific DateOnly
- *
- * @param timeStr time string of the form HH:mm:ss
- * @return the parsed DateOnly instance
- * @exception ParseException If there was a failure parsing the dateStr
- */
- @Nullable
- public static TimeOfDay parse(@Nonnull final String timeStr) throws ParseException {
- Objects.requireNonNull(timeStr, "parameter timeStr cannot be null");
- // break the date up into its constituent parts
- final String[] timeInfo = timeStr.split(":");
-
- // validate the split date string
- final int expectedLength = 3;
- if (timeInfo.length != expectedLength) {
- throw new ParseException(
- "Expected time string format 'HH:mm:ss' but found: " + timeStr, 0
- );
- }
-
- // array indices for date parsing
- final int indHour = 0;
- final int indMinute = 1;
- final int indSecond = 2;
-
- // unpack this array
- final int hour = Integer.parseInt(timeInfo[indHour]);
- final int minute = Integer.parseInt(timeInfo[indMinute]);
- final int second = new BigDecimal(timeInfo[indSecond]).intValue();
-
- return new TimeOfDay(hour, minute, second);
- }
-
- /**
- * Constructs a TimeOfDay object
- *
- * @param hour the hour
- * @param minute the minute
- * @param second the second
- */
- public TimeOfDay(final int hour, final int minute, final int second) {
- mHour = hour;
- mMinute = minute;
- mSecond = second;
- }
-
- /**
- * Gets the hour
- *
- * @return the hour
- */
- public int getHour() {
- return mHour;
- }
-
- /**
- * Gets the minute
- *
- * @return the minute
- */
- public int getMinute() {
- return mMinute;
- }
-
- /**
- * Gets the second
- *
- * @return the second
- */
- public int getSecond() {
- return mSecond;
- }
-
- @Override
- @Nonnull
- public String toString() {
- return String.format(
- Locale.ROOT,
- "%02d:%02d:%02d", mHour, mMinute, mSecond
- );
- }
-}
diff --git a/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAccessTokenProvider.java b/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAccessTokenProvider.java
new file mode 100644
index 000000000..6b559400d
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAccessTokenProvider.java
@@ -0,0 +1,37 @@
+package com.microsoft.graph.core.authentication;
+
+import java.util.HashSet;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import com.azure.core.credential.TokenCredential;
+import com.microsoft.kiota.authentication.ObservabilityOptions;
+
+/** AzureIdentityAccessTokenProvider wrapper from Kiota library with Microsoft Graph defaults. */
+public class AzureIdentityAccessTokenProvider extends com.microsoft.kiota.authentication.AzureIdentityAccessTokenProvider {
+ /**
+ * Creates a new instance of AzureIdentityAccessTokenProvider.
+ * @param tokenCredential The Azure.Identity.TokenCredential implementation to use.
+ */
+ public AzureIdentityAccessTokenProvider(@Nonnull TokenCredential tokenCredential) {
+ this(tokenCredential, new String[] {}, null);
+ }
+ /** {@inheritDoc} */
+ @SuppressWarnings("LambdaLast")
+ public AzureIdentityAccessTokenProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts,
+ @Nullable final ObservabilityOptions observabilityOptions, @Nonnull final String... scopes) {
+ super(tokenCredential, allowedHosts, observabilityOptions, scopes);
+ if (allowedHosts == null || allowedHosts.length == 0) {
+ final HashSet allowedHostsSet = new HashSet();
+ allowedHostsSet.add("graph.microsoft.com");
+ allowedHostsSet.add("graph.microsoft.us");
+ allowedHostsSet.add("dod-graph.microsoft.us");
+ allowedHostsSet.add("graph.microsoft.de");
+ allowedHostsSet.add("microsoftgraph.chinacloudapi.cn");
+ allowedHostsSet.add("canary.graph.microsoft.com");
+ this.getAllowedHostsValidator().setAllowedHosts(allowedHostsSet);
+ }
+ }
+
+}
diff --git a/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAuthenticationProvider.java b/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAuthenticationProvider.java
new file mode 100644
index 000000000..f88d7736d
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/authentication/AzureIdentityAuthenticationProvider.java
@@ -0,0 +1,32 @@
+package com.microsoft.graph.core.authentication;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import com.azure.core.credential.TokenCredential;
+import com.microsoft.kiota.authentication.BaseBearerTokenAuthenticationProvider;
+import com.microsoft.kiota.authentication.ObservabilityOptions;
+/** Implementation of Authentication provider for Azure Identity with Microsoft Graph defaults */
+public class AzureIdentityAuthenticationProvider extends BaseBearerTokenAuthenticationProvider {
+ /**
+ * Creates a new instance of AzureIdentityAuthenticationProvider.
+ * @param tokenCredential The Azure.Identity.TokenCredential implementation to use.
+ * @param allowedHosts The list of allowed hosts for which to request access tokens.
+ * @param scopes The scopes to request access tokens for.
+ */
+ @SuppressWarnings("LambdaLast")
+ public AzureIdentityAuthenticationProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, @Nonnull final String... scopes) {
+ this(tokenCredential, allowedHosts, null, scopes);
+ }
+ /**
+ * Creates a new instance of AzureIdentityAuthenticationProvider.
+ * @param tokenCredential The Azure.Identity.TokenCredential implementation to use.
+ * @param allowedHosts The list of allowed hosts for which to request access tokens.
+ * @param observabilityOptions The observability options to use.
+ * @param scopes The scopes to request access tokens for.
+ */
+ @SuppressWarnings("LambdaLast")
+ public AzureIdentityAuthenticationProvider(@Nonnull final TokenCredential tokenCredential, @Nonnull final String[] allowedHosts, @Nullable final ObservabilityOptions observabilityOptions, @Nonnull final String... scopes) {
+ super(new AzureIdentityAccessTokenProvider(tokenCredential, allowedHosts, observabilityOptions, scopes));
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/content/BatchRequestContent.java b/src/main/java/com/microsoft/graph/core/content/BatchRequestContent.java
new file mode 100644
index 000000000..c382e3581
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/content/BatchRequestContent.java
@@ -0,0 +1,250 @@
+package com.microsoft.graph.core.content;
+
+import com.google.gson.*;
+import com.google.gson.stream.JsonWriter;
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.graph.core.models.BatchRequestStep;
+import com.microsoft.graph.core.requests.IBaseClient;
+import com.microsoft.kiota.Compatibility;
+import com.microsoft.kiota.RequestAdapter;
+import com.microsoft.kiota.RequestInformation;
+
+import okhttp3.*;
+import okio.Buffer;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+/**
+ * A class representing the content of a batch request.
+ */
+public class BatchRequestContent {
+ private HashMap batchRequestSteps;
+ private RequestAdapter requestAdapter;
+ private final String maxStepsExceededMessage = String.format(Locale.US,ErrorConstants.Messages.MAXIMUM_VALUE_EXCEEDED, "Number of request steps", CoreConstants.BatchRequest.MAX_REQUESTS);
+
+ /**
+ * Creates a new BatchRequestContent object.
+ * @param client The IBaseClient for handling requests.
+ */
+ public BatchRequestContent(@Nonnull IBaseClient client) {
+ this(client, new ArrayList<>());
+ }
+ /**
+ * Creates a new BatchRequestContent object.
+ * @param baseClient The IBaseClient for handling requests.
+ * @param batchRequestSteps The list of BatchRequestSteps to add to the batch request.
+ */
+ public BatchRequestContent(@Nonnull IBaseClient baseClient, @Nonnull List batchRequestSteps) {
+ this(baseClient.getRequestAdapter(), batchRequestSteps);
+ }
+ /**
+ * Creates a new BatchRequestContent object.
+ * @param requestAdapter The request adapter to use for requests.
+ * @param batchRequestSteps The list of BatchRequestSteps to add to the batch request.
+ */
+ public BatchRequestContent(@Nonnull RequestAdapter requestAdapter, @Nonnull List batchRequestSteps) {
+ this.requestAdapter = Objects.requireNonNull(requestAdapter, ErrorConstants.Messages.NULL_PARAMETER + "requestAdapter");
+
+ Objects.requireNonNull(batchRequestSteps, ErrorConstants.Messages.NULL_PARAMETER + "batchRequestSteps");
+ if(batchRequestSteps.size() >= CoreConstants.BatchRequest.MAX_REQUESTS) {
+ throw new IllegalArgumentException(maxStepsExceededMessage);
+ }
+
+ this.batchRequestSteps = new HashMap<>();
+ for (BatchRequestStep requestStep : batchRequestSteps) {
+ addBatchRequestStep(requestStep);
+ }
+ }
+ /**
+ * Gets the batch request steps.
+ * @return The batch request steps.
+ */
+ @Nonnull
+ public Map getBatchRequestSteps() {
+
+ return new HashMap<>(batchRequestSteps);
+ }
+ /**
+ * Adds a batch request step to the batch request.
+ * @param requestStep The batch request step to add.
+ * @return True if the batch request step was added, false otherwise.
+ */
+ public boolean addBatchRequestStep(@Nullable BatchRequestStep requestStep)
+ {
+ if( requestStep == null
+ || this.batchRequestSteps.containsKey(requestStep.getRequestId())
+ || this.batchRequestSteps.size() >= CoreConstants.BatchRequest.MAX_REQUESTS) {
+ return false;
+ }
+ if(!containsCorrespondingRequestId(requestStep.getDependsOn())) {
+ throw new IllegalArgumentException(ErrorConstants.Messages.INVALID_DEPENDS_ON_REQUEST_ID);
+ }
+ this.batchRequestSteps.put(requestStep.getRequestId(), requestStep);
+ return true;
+ }
+ /**
+ * Adds a batch request step to the batch request.
+ * @param request The request to add.
+ * @return The request id of the added request.
+ */
+ @Nonnull
+ public String addBatchRequestStep(@Nonnull Request request) {
+ if(this.batchRequestSteps.size() >= CoreConstants.BatchRequest.MAX_REQUESTS) {
+ throw new IllegalArgumentException(maxStepsExceededMessage);
+ }
+ String requestId = java.util.UUID.randomUUID().toString();
+ BatchRequestStep requestStep = new BatchRequestStep(requestId, request);
+ this.batchRequestSteps.put(requestId, requestStep);
+ return requestId;
+ }
+ /**
+ * Adds a batch request step to the batch request.
+ * @param requestInformation The request information to add.
+ * @return The request id of the added request.
+ */
+ @Nonnull
+ public String addBatchRequestStep(@Nonnull RequestInformation requestInformation) {
+ if(this.batchRequestSteps.size() >= CoreConstants.BatchRequest.MAX_REQUESTS) {
+ throw new IllegalArgumentException(maxStepsExceededMessage);
+ }
+ String requestId = java.util.UUID.randomUUID().toString();
+ final Request request = this.requestAdapter.convertToNativeRequest(requestInformation);
+ BatchRequestStep requestStep = new BatchRequestStep(requestId, request);
+ this.batchRequestSteps.put(requestId, requestStep);
+ return requestId;
+ }
+ /**
+ * Removes a batch request step from the batch request.
+ * @param requestId The request id of the request to remove.
+ * @return True if the request was removed, false otherwise.
+ */
+ public boolean removeBatchRequestStepWithId(@Nonnull String requestId) {
+ if(Compatibility.isBlank(requestId)) {
+ throw new IllegalArgumentException("requestId cannot be null or empty.");
+ }
+ boolean isRemoved = false;
+ if(this.batchRequestSteps.containsKey(requestId)) {
+ this.batchRequestSteps.remove(requestId);
+ isRemoved = true;
+ for (BatchRequestStep requestStep : this.batchRequestSteps.values()) {
+ requestStep.removeDependsOnId(requestId);
+ }
+ }
+ return isRemoved;
+ }
+
+ /**
+ * Builds a BatchRequestContent object from failed requests.
+ * @param responseStatusCodes The response status codes of the failed requests.
+ * @return The BatchRequestContent object.
+ */
+ @Nonnull
+ public BatchRequestContent createNewBatchFromFailedRequests (@Nonnull Map responseStatusCodes) {
+ BatchRequestContent request = new BatchRequestContent(this.requestAdapter, new ArrayList<>());
+ responseStatusCodes.forEach((key, value) -> {
+ if(this.batchRequestSteps.containsKey(key) && !BatchResponseContent.isSuccessStatusCode(value)) {
+ request.addBatchRequestStep(this.batchRequestSteps.get(key).getRequest());
+ }
+ });
+ return request;
+ }
+ /**
+ * Builds the json content of the batch request.
+ * @return The json content of the batch request as an InputStream.
+ * @throws IOException if there was an error writing the batch request content.
+ */
+ @Nonnull
+ public InputStream getBatchRequestContent() throws IOException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
+ writer.beginObject();
+ writer.name(CoreConstants.BatchRequest.REQUESTS);
+ writer.beginArray();
+ for (BatchRequestStep requestStep : this.batchRequestSteps.values()) {
+ writeBatchRequestStep(requestStep, writer);
+ }
+ writer.endArray();
+ writer.endObject();
+ writer.flush();
+ PipedInputStream in = new PipedInputStream();
+ try(final PipedOutputStream out = new PipedOutputStream(in)) {
+ outputStream.writeTo(out);
+ return in;
+ }
+ }
+ private void writeBatchRequestStep(BatchRequestStep requestStep, JsonWriter writer) throws IOException {
+ Request request = requestStep.getRequest();
+ writer.beginObject();
+ writer.name(CoreConstants.BatchRequest.ID).value(requestStep.getRequestId());
+ writer.name(CoreConstants.BatchRequest.URL).value(getRelativeUrl(request.url()));
+ writer.name(CoreConstants.BatchRequest.METHOD).value(request.method());
+
+ List dependsOn = requestStep.getDependsOn();
+ if(!dependsOn.isEmpty()) {
+ writer.name(CoreConstants.BatchRequest.DEPENDS_ON);
+ writer.beginArray();
+ for(String id : dependsOn) {
+ writer.value(id);
+ }
+ writer.endArray();
+ }
+ RequestBody requestBody = request.body();
+ Headers headers = request.headers();
+ if(requestBody != null) {
+ String contentType = Objects.requireNonNull(requestBody.contentType()).toString();
+ headers = headers.newBuilder().add("Content-Type", contentType).build();
+ writer.name(CoreConstants.BatchRequest.BODY);
+ if(contentType.toLowerCase(Locale.US).contains(CoreConstants.MimeTypeNames.APPLICATION_JSON)){
+ JsonObject bodyObject = getJsonRequestContent(requestBody);
+ writer.jsonValue(bodyObject.toString());
+ } else {
+ String rawBodyContent = getRawRequestContent(requestBody);
+ writer.value(rawBodyContent);
+ }
+ }
+ if(headers.size() != 0 || requestBody != null) {
+ writer.name(CoreConstants.BatchRequest.HEADERS);
+ writer.beginObject();
+ for(int i = 0; i < headers.size(); i++) {
+ writer.name(headers.name(i)).value(headers.value(i));
+ }
+ writer.endObject();
+ }
+ writer.endObject();
+ }
+ private JsonObject getJsonRequestContent(RequestBody requestBody) throws IOException {
+ try {
+ Buffer buffer = new Buffer();
+ requestBody.writeTo(buffer);
+ return JsonParser.parseString(buffer.readUtf8()).getAsJsonObject();
+ } catch(IOException e) {
+ throw new IOException(ErrorConstants.Messages.UNABLE_TO_DESERIALIZE_CONTENT, e);
+ }
+ }
+ private String getRawRequestContent(RequestBody requestBody) throws IOException {
+ try{
+ Buffer buffer = new Buffer();
+ requestBody.writeTo(buffer);
+ return buffer.readUtf8();
+ } catch(IOException e) {
+ throw new IOException(ErrorConstants.Messages.UNABLE_TO_DESERIALIZE_CONTENT, e);
+ }
+ }
+ private boolean containsCorrespondingRequestId(List dependsOn) {
+ return dependsOn.stream().allMatch(id -> this.batchRequestSteps.containsKey(id));
+ }
+ private String getRelativeUrl(HttpUrl url) {
+ String query = url.encodedQuery(); //Query must be encoded in order for batch requests to work.
+ String path = url.encodedPath().substring(5);
+ if(Compatibility.isBlank(query)) {
+ return path;
+ }
+ return (path + "?" + query); // `v1.0/` and `beta/` are both 5 characters
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/content/BatchRequestContentCollection.java b/src/main/java/com/microsoft/graph/core/content/BatchRequestContentCollection.java
new file mode 100644
index 000000000..6d0d2e45a
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/content/BatchRequestContentCollection.java
@@ -0,0 +1,137 @@
+package com.microsoft.graph.core.content;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.graph.core.models.BatchRequestStep;
+import com.microsoft.graph.core.requests.IBaseClient;
+import com.microsoft.kiota.RequestInformation;
+import okhttp3.Request;
+
+import jakarta.annotation.Nonnull;
+import java.util.*;
+
+/**
+ * A collection of batch requests
+ */
+public class BatchRequestContentCollection {
+ private IBaseClient baseClient;
+ private List batchRequests;
+ private int batchRequestLimit;
+ private BatchRequestContent currentBatchRequest;
+ private boolean readOnly = false;
+ /**
+ * Creates a new batch request collection with the default maximum number of requests.
+ * @param baseClient the base client to use for requests.
+ */
+ public BatchRequestContentCollection(@Nonnull IBaseClient baseClient) {
+ this(baseClient, CoreConstants.BatchRequest.MAX_REQUESTS);
+ }
+ /**
+ * Creates a new batch request collection.
+ * @param baseClient the base client to use for requests.
+ * @param batchRequestLimit the maximum number of requests to batch together.
+ */
+ public BatchRequestContentCollection(@Nonnull IBaseClient baseClient, int batchRequestLimit) {
+ Objects.requireNonNull(baseClient, ErrorConstants.Messages.NULL_PARAMETER + "baseClient");
+ if(batchRequestLimit < 2 || batchRequestLimit > CoreConstants.BatchRequest.MAX_REQUESTS) {
+ throw new IllegalArgumentException("batchRequestLimit must be between 2 and " + CoreConstants.BatchRequest.MAX_REQUESTS);
+ }
+ this.baseClient = baseClient;
+ this.batchRequestLimit = batchRequestLimit;
+ batchRequests = new ArrayList<>();
+ currentBatchRequest = new BatchRequestContent(baseClient);
+ }
+ /**
+ * Adds a request to the current BatchRequestContent object of the collection.
+ * @param request the request to add.
+ * @return the id of the request in the batch.
+ */
+ @Nonnull
+ public String addBatchRequestStep(@Nonnull Request request) {
+ setupCurrentRequest();
+ return currentBatchRequest.addBatchRequestStep(request);
+ }
+ /**
+ * Adds a request to the current BatchRequestContent object of the collection.
+ * @param requestInformation the requestInformation for the request being added.
+ * @return the id of the request in the batch.
+ */
+ @Nonnull
+ public String addBatchRequestStep(@Nonnull RequestInformation requestInformation) {
+ setupCurrentRequest();
+ return currentBatchRequest.addBatchRequestStep(requestInformation);
+ }
+ /**
+ * removes a request from a BatchRequestContent object within the collection.
+ * @param requestId the id of the request to remove.
+ * @return true if the request was removed, false if it was not found.
+ */
+ public boolean removeBatchRequestStepWithId(@Nonnull String requestId) {
+ validateReadOnly();
+ boolean removed = currentBatchRequest.removeBatchRequestStepWithId(requestId);
+ if(!removed && !batchRequests.isEmpty()) {
+ for (BatchRequestContent batchRequest : batchRequests) {
+ removed = batchRequest.removeBatchRequestStepWithId(requestId);
+ if(removed) {
+ return true;
+ }
+ }
+ }
+ return removed;
+ }
+ /**
+ * Get list of BatchRequestContent objects for execution.
+ * @return list of BatchRequestContent objects for execution.
+ */
+ @Nonnull
+ public List getBatchRequestsForExecution() {
+ readOnly = true;
+ if(currentBatchRequest.getBatchRequestSteps().size() > 0) {
+ batchRequests.add(currentBatchRequest);
+ }
+ return new ArrayList<>(batchRequests);
+ }
+ /**
+ * Get all BatchRequestSteps from all BatchRequestContent objects within the collection.
+ * @return HashMap of BatchRequestSteps from all BatchRequestContent objects within the collection.
+ */
+ @Nonnull
+ public Map getBatchRequestSteps() {
+ if (!batchRequests.isEmpty()) {
+ Map result = currentBatchRequest.getBatchRequestSteps();
+ for (BatchRequestContent batchRequestContent : batchRequests) {
+ result.putAll(batchRequestContent.getBatchRequestSteps());
+ }
+ return result;
+ }
+ return currentBatchRequest.getBatchRequestSteps();
+ }
+ /**
+ * Get BatchRequestContentCollection with only failed requests.
+ * @param responseStatusCodes HashMap of response status codes.
+ * @return BatchRequestContentCollection with only failed requests.
+ */
+ @Nonnull
+ public BatchRequestContentCollection newBatchWithFailedRequests(@Nonnull Map responseStatusCodes) {
+ BatchRequestContentCollection newBatch = new BatchRequestContentCollection(this.baseClient, this.batchRequestLimit);
+ Map steps = this.getBatchRequestSteps();
+ responseStatusCodes.forEach((id, statusCode) -> {
+ if(steps.containsKey(id) && !BatchResponseContent.isSuccessStatusCode(statusCode)) {
+ newBatch.addBatchRequestStep(steps.get(id).getRequest());
+ }
+ });
+ return newBatch;
+ }
+ private void validateReadOnly() {
+ if(readOnly) {
+ throw new UnsupportedOperationException("Batch request collection is already executed");
+ }
+ }
+ private void setupCurrentRequest() {
+ validateReadOnly();
+ if(currentBatchRequest.getBatchRequestSteps().size() >= batchRequestLimit) {
+ batchRequests.add(currentBatchRequest);
+ currentBatchRequest = new BatchRequestContent(baseClient);
+ }
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/content/BatchResponseContent.java b/src/main/java/com/microsoft/graph/core/content/BatchResponseContent.java
new file mode 100644
index 000000000..4666c7b3e
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/content/BatchResponseContent.java
@@ -0,0 +1,229 @@
+package com.microsoft.graph.core.content;
+
+import com.google.gson.*;
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.graph.core.requests.ResponseBodyHandler;
+import com.microsoft.kiota.ResponseHandler;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import okhttp3.*;
+
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+
+/**
+ * A class representing the content of a batch request response.
+ */
+public class BatchResponseContent {
+ private Response batchResponse;
+ private JsonObject jsonBatchResponseObject;
+ private HashMap> apiErrorMappings;
+ private Protocol batchResponseProtocol;
+ private Request batchResponseRequest;
+ /**
+ * Creates a new BatchResponseContent instance.
+ * @param batchResponse The response of the batch request.
+ */
+ public BatchResponseContent(@Nonnull Response batchResponse) {
+ this(batchResponse, null);
+ }
+ /**
+ * Creates a new BatchResponseContent instance.
+ * @param batchResponse The response of the batch request.
+ * @param apiErrorMappings The error mappings to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if the specific error code is not present.
+ */
+ public BatchResponseContent(@Nonnull Response batchResponse, @Nullable Map> apiErrorMappings) {
+ this.batchResponse = Objects.requireNonNull(batchResponse, ErrorConstants.Messages.NULL_PARAMETER + "batchResponse");
+ this.batchResponseProtocol = batchResponse.protocol();
+ this.batchResponseRequest = batchResponse.request();
+ this.apiErrorMappings = apiErrorMappings == null ? new HashMap<>() : new HashMap<>(apiErrorMappings);
+ }
+ /**
+ * Gets the responses of the batch request.
+ * @return The responses of the batch request.
+ */
+ @Nonnull
+ public Map getResponses() {
+ HashMap responses = new HashMap<>();
+ jsonBatchResponseObject = jsonBatchResponseObject != null ? jsonBatchResponseObject : getBatchResponseContent();
+ if (jsonBatchResponseObject != null) {
+ JsonElement responsesElement = jsonBatchResponseObject.get(CoreConstants.BatchRequest.RESPONSES);
+ if (responsesElement != null && responsesElement.isJsonArray()) { //ensure "responses" is not null and is an array.
+ JsonArray responsesArray = responsesElement.getAsJsonArray();
+ for (JsonElement responseElement : responsesArray) {
+ responses.put(responseElement.getAsJsonObject().get("id").getAsString(), getResponseFromJsonObject(responseElement));
+ }
+ }
+ }
+ return responses;
+ }
+ /**
+ * Gets the status codes of the responses of the batch request.
+ * @return The status codes of the responses of the batch request.
+ */
+ @Nonnull
+ public Map getResponsesStatusCode() {
+ HashMap statusCodes = new HashMap<>();
+ jsonBatchResponseObject = jsonBatchResponseObject != null ? jsonBatchResponseObject : getBatchResponseContent();
+ if (jsonBatchResponseObject != null) {
+ JsonElement responsesElement = jsonBatchResponseObject.get(CoreConstants.BatchRequest.RESPONSES);
+ if (responsesElement != null && responsesElement.isJsonArray()) { //ensure "responses" is not null and is an array.
+ JsonArray responsesArray = responsesElement.getAsJsonArray();
+ for (JsonElement responseElement : responsesArray) {
+ statusCodes.put(responseElement.getAsJsonObject().get("id").getAsString(), getStatusCodeFromJsonObject(responseElement));
+ }
+ }
+ }
+ return statusCodes;
+ }
+ /**
+ * Gets the response within the batch response via specified id.
+ * @param requestId The id of the request.
+ * @return The response within the batch response via specified id, null if not found.
+ */
+ @Nullable
+ public Response getResponseById(@Nonnull String requestId) {
+ Objects.requireNonNull(requestId);
+ if(!requestId.isEmpty()) {
+ jsonBatchResponseObject = jsonBatchResponseObject != null ? jsonBatchResponseObject : getBatchResponseContent();
+ if (jsonBatchResponseObject != null) {
+ JsonElement responsesElement = jsonBatchResponseObject.get(CoreConstants.BatchRequest.RESPONSES);
+ if (responsesElement != null && responsesElement.isJsonArray()) { //ensure "responses" is not null and is an array.
+ JsonArray responsesArray = responsesElement.getAsJsonArray();
+ for (JsonElement responseElement : responsesArray) {
+ if (responseElement.getAsJsonObject().get("id").getAsString().equals(requestId)) {
+ return getResponseFromJsonObject(responseElement);
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+ /**
+ * Gets the response within the batch response via specified id.
+ * @param requestId The id of the request.
+ * @param responseHandler The response handler to use when deserializing the response body.
+ * @return The response within the batch response via specified id, null if not found.
+ * @param The type of the response body.
+ */
+ @Nullable
+ public T getResponseById(@Nonnull String requestId, @Nonnull ResponseHandler responseHandler) {
+ Response response = getResponseById(requestId);
+ if(response == null) {
+ return null;
+ }
+ return responseHandler.handleResponse(response, apiErrorMappings);
+ }
+ /**
+ * Gets the response within the batch response via specified id.
+ * @param requestId The id of the request.
+ * @param factory The factory to use when deserializing the response body.
+ * @return The response within the batch response via specified id, null if not found.
+ * @param The type of the response body.
+ */
+ @Nullable
+ public T getResponseById(@Nonnull String requestId, @Nonnull ParsableFactory factory) {
+ return this.getResponseById(requestId, new ResponseBodyHandler<>(factory));
+ }
+ /**
+ * Gets the response within the batch response via specified id.
+ * @param requestId The id of the request.
+ * @return The response within the batch response via specified id as an InputStream, null if not found.
+ */
+ @Nullable
+ public InputStream getResponseStreamById(@Nonnull String requestId) {
+ Response response = getResponseById(requestId);
+ if(response != null && response.body() != null) {
+ InputStream in = response.body().byteStream();
+ return in;
+ }
+ return null;
+ }
+ /**
+ * Get the next link of the batch response.
+ * @return The next link of the batch response.
+ */
+ @Nullable
+ public String getNextLink() {
+ jsonBatchResponseObject = jsonBatchResponseObject != null ? jsonBatchResponseObject : getBatchResponseContent();
+ if(jsonBatchResponseObject != null) {
+ JsonElement nextLinkElement = jsonBatchResponseObject.get(CoreConstants.Serialization.ODATA_NEXT_LINK);
+ if (nextLinkElement != null && nextLinkElement.isJsonPrimitive()) {
+ return nextLinkElement.getAsString();
+ }
+ }
+ return null;
+ }
+ private JsonObject getBatchResponseContent() {
+ if (this.batchResponse.body() != null && this.batchResponse.body().contentType() != null) {
+ InputStream in = this.batchResponse.body().byteStream();
+ try(InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
+ return JsonParser.parseReader(reader).getAsJsonObject();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+ private Response getResponseFromJsonObject(JsonElement responseElement) {
+ Response.Builder response = new Response.Builder();
+ JsonObject responseObject = responseElement.getAsJsonObject();
+ String message = null;
+ if(responseObject.has(CoreConstants.BatchRequest.STATUS)) {
+ response.code(responseObject.get("status").getAsInt());
+ }
+ String contentType = null;
+ if(responseObject.has(CoreConstants.BatchRequest.HEADERS)) {
+ JsonObject headers = responseObject.get(CoreConstants.BatchRequest.HEADERS).getAsJsonObject();
+ for(Map.Entry header : headers.entrySet()) {
+ String key = header.getKey();
+ String value = header.getValue().getAsString();
+ if(key.equalsIgnoreCase("Content-Type")) {
+ contentType = value;
+ }
+ response.addHeader(key, value);
+ }
+ }
+ if(responseObject.has(CoreConstants.BatchRequest.BODY)) {
+ String body = responseObject.get(CoreConstants.BatchRequest.BODY).toString();
+ if(responseObject.get("body").isJsonObject()) {
+ JsonObject bodyObject = responseObject.get("body").getAsJsonObject();
+ if(bodyObject.has(CoreConstants.BatchRequest.ERROR)) {
+ JsonObject errorObject = bodyObject.get(CoreConstants.BatchRequest.ERROR).getAsJsonObject();
+ message = errorObject.get("message").getAsString();
+ }
+ }
+ ResponseBody responseBody = ResponseBody.create(body, MediaType.parse(contentType != null ? contentType : CoreConstants.MimeTypeNames.APPLICATION_JSON));
+ response.body(responseBody);
+ responseBody.close();
+ }
+ response.protocol(this.batchResponseProtocol);
+ response.message(message == null ? "See status code for details" : message);
+ response.request(this.batchResponseRequest);
+ return response.build();
+ }
+
+ private int getStatusCodeFromJsonObject(JsonElement responseElement) {
+ JsonObject responseObject = responseElement.getAsJsonObject();
+ if(responseObject.has(CoreConstants.BatchRequest.STATUS)) {
+ return responseObject.get(CoreConstants.BatchRequest.STATUS).getAsInt();
+ } else {
+ throw new IllegalArgumentException("Response object does not contain status code");
+ }
+ }
+ /**
+ * Checks if the status code is a success status code.
+ * @param statusCode The status code to check.
+ * @return True if the status code is a success status code, false otherwise.
+ */
+ public static boolean isSuccessStatusCode(int statusCode) {
+ return (statusCode >= 200 && statusCode < 300);
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/content/BatchResponseContentCollection.java b/src/main/java/com/microsoft/graph/core/content/BatchResponseContentCollection.java
new file mode 100644
index 000000000..08333d242
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/content/BatchResponseContentCollection.java
@@ -0,0 +1,108 @@
+package com.microsoft.graph.core.content;
+
+import com.microsoft.kiota.ResponseHandler;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import okhttp3.Response;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.io.InputStream;
+import java.util.*;
+
+/**
+ * A collection of BatchResponseContent objects.
+ */
+public class BatchResponseContentCollection {
+
+ private List batchResponses;
+
+ /**
+ * Instantiates a new Batch response content collection.
+ */
+ public BatchResponseContentCollection() {
+ batchResponses = new ArrayList<>();
+ }
+ /**
+ * Add BatchResponseContent object to the collection.
+ * @param keys the keys of the requests that were batched together.
+ * @param content the BatchResponseContent object to add to the collection.
+ */
+ public void addBatchResponse(@Nonnull Collection keys, @Nonnull BatchResponseContent content) {
+ batchResponses.add(new KeyedBatchResponseContent(new HashSet<>(keys), content));
+ }
+ /**
+ * Gets the BatchResponseContent object containing the response for the request with the given id.
+ * @param requestId the id of the request to get the response for.
+ * @return the BatchResponseContent object containing the response for the request with the given id, null if no response was found.
+ */
+ private BatchResponseContent getBatchResponseContaining(@Nonnull String requestId) {
+ Objects.requireNonNull(requestId);
+ for(KeyedBatchResponseContent keyedResponse : batchResponses) {
+ if(keyedResponse.keys.contains(requestId)) {
+ return keyedResponse.response;
+ }
+ }
+ return null;
+ }
+ /**
+ * Gets the response for the request with the given id.
+ * @param requestId the id of the request to get the response for.
+ * @return the response for the request with the given id, null if no response was found.
+ */
+ @Nullable
+ public Response getResponseById(@Nonnull String requestId) {
+ Objects.requireNonNull(requestId);
+ BatchResponseContent response = getBatchResponseContaining(requestId);
+ return response == null ? null : response.getResponseById(requestId);
+ }
+ /**
+ * Gets the response for the request with the given id.
+ * @param requestId the id of the request to get the response for.
+ * @param handler the handler to use when deserializing the response.
+ * @return the response for the request with the given id, null if no response was found.
+ * @param the type of the response.
+ */
+ @Nullable
+ public T getResponseById(@Nonnull String requestId, @Nonnull ResponseHandler handler) {
+ Objects.requireNonNull(requestId);
+ BatchResponseContent response = getBatchResponseContaining(requestId);
+ return response == null ? null : response.getResponseById(requestId, handler);
+ }
+ /**
+ * Gets the response for the request with the given id.
+ * @param requestId the id of the request to get the response for.
+ * @param factory the factory to use when deserializing the response.
+ * @return the response for the request with the given id, null if no response was found.
+ * @param the type of the response.
+ */
+ @Nullable
+ public T getResponseById(@Nonnull String requestId, @Nonnull ParsableFactory factory) {
+ Objects.requireNonNull(requestId);
+ BatchResponseContent response = getBatchResponseContaining(requestId);
+ return response == null ? null : response.getResponseById(requestId, factory);
+ }
+ /**
+ * Gets the response for the request with the given id as a stream.
+ * @param requestId the id of the request to get the response for.
+ * @return the response for the request with the given id, null if no response was found.
+ */
+ @Nullable
+ public InputStream getResponseStreamById(@Nonnull String requestId) {
+ BatchResponseContent response = getBatchResponseContaining(requestId);
+ return response == null ? null : response.getResponseStreamById(requestId);
+ }
+ /**
+ * Gets the response codes for all the requests in the batch.
+ * @return the response codes for all the requests in the batch.
+ */
+ @Nonnull
+ public Map getResponsesStatusCodes() {
+ HashMap statusCodes = new HashMap<>();
+ for(KeyedBatchResponseContent keyedResponse : batchResponses) {
+ Map responseStatusCodes = keyedResponse.response.getResponsesStatusCode();
+ statusCodes.putAll(responseStatusCodes);
+ }
+ return statusCodes;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/content/KeyedBatchResponseContent.java b/src/main/java/com/microsoft/graph/core/content/KeyedBatchResponseContent.java
new file mode 100644
index 000000000..15fd137ac
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/content/KeyedBatchResponseContent.java
@@ -0,0 +1,30 @@
+package com.microsoft.graph.core.content;
+
+import jakarta.annotation.Nonnull;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A model to map id Keys to requests within a BatchResponseContent object.
+ */
+public class KeyedBatchResponseContent {
+ /**
+ * The ids of the requests that were batched together.
+ */
+ @Nonnull
+ protected HashSet keys;
+ /**
+ * The BatchResponseContent object paired to the keys.
+ */
+ @Nonnull
+ protected BatchResponseContent response;
+ /**
+ * Instantiates a new Keyed batch response content.
+ * @param keys the ids of the requests that were batched together.
+ * @param response the BatchResponseContent object to add to the collection.
+ */
+ public KeyedBatchResponseContent(@Nonnull Set keys, @Nonnull BatchResponseContent response) {
+ this.keys = new HashSet<>(keys);
+ this.response = response;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/exceptions/ClientException.java b/src/main/java/com/microsoft/graph/core/exceptions/ClientException.java
new file mode 100644
index 000000000..fd22df2c1
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/exceptions/ClientException.java
@@ -0,0 +1,24 @@
+package com.microsoft.graph.core.exceptions;
+
+import jakarta.annotation.Nonnull;
+
+/**
+ * Graph client exception wrapper.
+ */
+public class ClientException extends Exception {
+ /**
+ * Constructor for a ClientException
+ * @param message The exception message.
+ * @param cause The possible inner exception causing this exception.
+ */
+ public ClientException(@Nonnull String message, @Nonnull Throwable cause) {
+ super(message, cause);
+ }
+ /***
+ * Constructor for a ClientException
+ * @param message The exception message.
+ */
+ public ClientException(@Nonnull String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/models/BatchRequestStep.java b/src/main/java/com/microsoft/graph/core/models/BatchRequestStep.java
new file mode 100644
index 000000000..72ea06ff9
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/models/BatchRequestStep.java
@@ -0,0 +1,107 @@
+package com.microsoft.graph.core.models;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.kiota.Compatibility;
+import com.microsoft.kiota.http.middleware.UrlReplaceHandler;
+import okhttp3.Request;
+
+import jakarta.annotation.Nonnull;
+import java.util.*;
+
+/**
+ * Represents a single request in a batch request
+ */
+public class BatchRequestStep {
+
+ private final String requestId;
+ private final Request request;
+ private List dependsOn;
+ /**
+ * Creates a new BatchRequestStep
+ * @param requestId The id of the request
+ * @param request The request
+ */
+ public BatchRequestStep(@Nonnull String requestId, @Nonnull Request request) {
+ Objects.requireNonNull(request, ErrorConstants.Messages.NULL_PARAMETER + "request");
+ if(Compatibility.isBlank(requestId)) {
+ throw new IllegalArgumentException("requestId cannot be null or empty.");
+ }
+ this.requestId = requestId;
+ this.request = UrlReplaceHandler.replaceRequestUrl(request, CoreConstants.ReplacementConstants.getDefaultReplacementPairs());
+ }
+ /**
+ * Creates a new BatchRequestStep
+ * @param requestId The id of the request
+ * @param request The request
+ * @param dependsOn The ids of the requests that this request depends on
+ */
+ public BatchRequestStep(@Nonnull String requestId, @Nonnull Request request, @Nonnull List dependsOn) {
+ this(requestId, request);
+ this.dependsOn = new ArrayList<>(dependsOn);
+ }
+ /**
+ * Gets the request
+ * @return The request
+ */
+ @Nonnull
+ public Request getRequest() {
+ return this.request;
+ }
+ /**
+ * Gets the id of the request
+ * @return The id of the request
+ */
+ @Nonnull
+ public String getRequestId() {
+ return this.requestId;
+ }
+ /**
+ * Gets the ids of the requests that this request depends on
+ * @return The ids of the requests that this request depends on
+ */
+ @Nonnull
+ public List getDependsOn() {
+ if(dependsOn == null) {
+ return new ArrayList<>();
+ }
+ return new ArrayList<>(dependsOn);
+ }
+ /**
+ * Sets the ids of the requests that this request depends on
+ * @param dependsOn The ids of the requests that this request depends on
+ */
+ public void setDependsOn(@Nonnull List dependsOn) {
+ this.dependsOn = new ArrayList<>(dependsOn);
+ }
+ /**
+ * Adds a request id to the dependsOn list.
+ * @param id The id of the request to add to the dependsOn list.
+ */
+ public void addDependsOnId(@Nonnull String id) {
+ if(Compatibility.isBlank(id)) {
+ throw new IllegalArgumentException("id cannot be null or empty");
+ }
+ if(dependsOn == null) {
+ dependsOn = new ArrayList<>();
+ }
+ dependsOn.add(id);
+ }
+ /**
+ * Removes a request id from the dependsOn list.
+ *
+ * @param id The id of the request to remove.
+ * @return true if the request id is no longer present in the dependsOn collection, false if dependsOn is null.
+ */
+ public boolean removeDependsOnId(@Nonnull String id) {
+ Objects.requireNonNull(id);
+ if(dependsOn != null) {
+ if(!dependsOn.contains(id) || id.isEmpty()) {
+ throw new IllegalArgumentException("id is not present in the dependsOn collection or is empty");
+ }
+ dependsOn.removeAll(Collections.singleton(id));
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/models/IProgressCallback.java b/src/main/java/com/microsoft/graph/core/models/IProgressCallback.java
new file mode 100644
index 000000000..038a336af
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/models/IProgressCallback.java
@@ -0,0 +1,16 @@
+package com.microsoft.graph.core.models;
+
+/**
+ * Defines how to return progress status from a request.
+ */
+@FunctionalInterface
+public interface IProgressCallback {
+
+ /**
+ * How progress updates are handled for this callback
+ *
+ * @param current the current amount of progress
+ * @param max the max amount of progress
+ */
+ void report(final long current, final long max);
+}
diff --git a/src/main/java/com/microsoft/graph/core/models/IUploadSession.java b/src/main/java/com/microsoft/graph/core/models/IUploadSession.java
new file mode 100644
index 000000000..072d24d02
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/models/IUploadSession.java
@@ -0,0 +1,50 @@
+package com.microsoft.graph.core.models;
+
+import com.microsoft.kiota.serialization.AdditionalDataHolder;
+import com.microsoft.kiota.serialization.Parsable;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.time.OffsetDateTime;
+import java.util.List;
+
+/**
+ * Interface defining and UploadSession
+ */
+public interface IUploadSession extends Parsable, AdditionalDataHolder {
+ /**
+ * Gets the Upload Url.
+ * The URL endpoint that accepts PUT requests for byte ranges of the file.
+ * @return the upload Url
+ */
+ @Nonnull
+ String getUploadUrl();
+ /**
+ * Sets the Upload Url
+ * @param url the upload Url for the session
+ */
+ void setUploadUrl(@Nonnull String url);
+ /**
+ * Gets the Next Expected Ranges.
+ * A collection of byte ranges that the server is missing for the file. These ranges are zero indexed and of the format 'start-end' (e.g. '0-26' to indicate the first 27 bytes of the file). When uploading files as Outlook attachments, instead of a collection of ranges, this property always indicates a single value '{start}', the location in the file where the next upload should begin.
+ * @return the Next Expected Ranges.
+ */
+ @Nonnull
+ List getNextExpectedRanges();
+ /**
+ * Sets the ranges that are yet to be uploaded.
+ * @param nextExpectedRanges the byte ranges yet to be uploaded.
+ */
+ void setNextExpectedRanges(@Nonnull List nextExpectedRanges);
+ /**
+ * Expiration date of the upload session
+ * @return the expiration date.
+ */
+ @Nullable
+ OffsetDateTime getExpirationDateTime();
+ /**
+ * Set the expiration date of the UploadSession
+ * @param dateTime the expiration date of the UploadSession.
+ */
+ void setExpirationDateTime(@Nonnull OffsetDateTime dateTime);
+}
diff --git a/src/main/java/com/microsoft/graph/core/models/UploadResult.java b/src/main/java/com/microsoft/graph/core/models/UploadResult.java
new file mode 100644
index 000000000..6f99e3eac
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/models/UploadResult.java
@@ -0,0 +1,34 @@
+package com.microsoft.graph.core.models;
+
+import jakarta.annotation.Nullable;
+
+import java.net.URI;
+
+/**
+ * Model containing the information from an upload response.
+ * @param The type of item contained in the response.
+ */
+public class UploadResult {
+ /**
+ * Default constructor.
+ */
+ public UploadResult() {
+ //Default constructor
+ }
+ /** The UploadSession containing information about the created upload session. */
+ @Nullable
+ public IUploadSession uploadSession;
+ /** The uploaded item, once upload has completed. */
+ @Nullable
+ public T itemResponse;
+ /** The uploaded item location, once upload has completed. */
+ @Nullable
+ public URI location;
+ /**
+ * Status of the request.
+ * @return A boolean dictating whether the upload has been fully completed.
+ */
+ public boolean isUploadSuccessful() {
+ return (this.itemResponse != null) || (this.location != null);
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/models/UploadSession.java b/src/main/java/com/microsoft/graph/core/models/UploadSession.java
new file mode 100644
index 000000000..18bb54d9c
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/models/UploadSession.java
@@ -0,0 +1,142 @@
+package com.microsoft.graph.core.models;
+
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.kiota.Compatibility;
+import com.microsoft.kiota.serialization.ParseNode;
+import com.microsoft.kiota.serialization.SerializationWriter;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.time.OffsetDateTime;
+import java.util.*;
+import java.util.function.Consumer;
+
+/**
+ * Concrete implementation of the IUploadSession interface.
+ */
+public class UploadSession implements IUploadSession {
+ /** The URL for upload. */
+ private String uploadUrl ="";
+ /** The ranges yet to be uploaded to the server. */
+ private List nextExpectedRanges;
+ /** Expiration date of the upload session. */
+ private OffsetDateTime expirationDateTime;
+ /** Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. */
+ private Map additionalData = new HashMap<>();
+ private static final String UPLOAD_URL = "uploadUrl";
+ private static final String NEXT_EXPECTED_RANGES = "nextExpectedRanges";
+ private static final String EXPIRATION_DATE_TIME = "expirationDateTime";
+ /**
+ * Instantiates a new uploadSession and sets the default values.
+ */
+ @Nullable
+ public UploadSession() {
+ this.setAdditionalData(new HashMap<>());
+ }
+ /**
+ * Get the upload url of the upload session.
+ * @return The upload Url.
+ */
+ @Nonnull
+ @Override
+ public String getUploadUrl() {
+ return this.uploadUrl;
+ }
+ /**
+ * Set the upload url of the upload session.
+ * @param uploadUrl The upload url for the session.
+ */
+ public void setUploadUrl(@Nonnull final String uploadUrl) {
+ if(Compatibility.isBlank(uploadUrl))
+ throw new IllegalArgumentException("uploadUrl cannot be null or empty");
+ this.uploadUrl = uploadUrl;
+ }
+ /**
+ * Get the next upload byte ranges to be uploaded.
+ * @return The byte ranges to be uploaded.
+ */
+ @Nonnull
+ @Override
+ public List getNextExpectedRanges() {
+ return new ArrayList<>(nextExpectedRanges);
+ }
+ /**
+ * Set the byte ranges yet to be uploaded.
+ * @param nextExpectedRanges The byte ranges yet to be uploaded.
+ */
+ @Override
+ public void setNextExpectedRanges(@Nonnull final List nextExpectedRanges) {
+ Objects.requireNonNull(nextExpectedRanges, ErrorConstants.Messages.NULL_PARAMETER + NEXT_EXPECTED_RANGES);
+ this.nextExpectedRanges = new ArrayList<>(nextExpectedRanges);
+ }
+ /**
+ * Get the time at which the session expires.
+ * @return The session expiration time.
+ */
+ @Nullable
+ @Override
+ public OffsetDateTime getExpirationDateTime() {
+ return this.expirationDateTime;
+ }
+ /**
+ * Set the time at which the session expires.
+ * @param expirationDateTime The session expiration time.
+ */
+ @Override
+ public void setExpirationDateTime(@Nullable final OffsetDateTime expirationDateTime) {
+ this.expirationDateTime = expirationDateTime;
+ }
+ /**
+ * Get the additional data found.
+ * @return The additional data.
+ */
+ @Nonnull
+ @Override
+ public Map getAdditionalData() {
+ return new HashMap<>(this.additionalData);
+ }
+ /**
+ * Sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
+ * @param additionalData The AdditionalData to set.
+ */
+ public void setAdditionalData(@Nonnull final Map additionalData) {
+ Objects.requireNonNull(additionalData, ErrorConstants.Messages.NULL_PARAMETER + "additionalData");
+ this.additionalData = new HashMap<>(additionalData);
+ }
+ /**
+ * The deserialization information for the current model.
+ * @return A hash map describing how to deserialize the current model fields.
+ */
+ @Nonnull
+ @Override
+ public Map> getFieldDeserializers() {
+ final UploadSession currentObj = this;
+ HashMap> deserializers = new HashMap<>(3);
+ deserializers.put(EXPIRATION_DATE_TIME, n -> currentObj.setExpirationDateTime(n.getOffsetDateTimeValue()));
+ deserializers.put(NEXT_EXPECTED_RANGES, n -> currentObj.setNextExpectedRanges(n.getCollectionOfPrimitiveValues(String.class)));
+ deserializers.put(UPLOAD_URL, n -> currentObj.setUploadUrl(n.getStringValue()));
+ return deserializers;
+ }
+ /**
+ * Serializes information the current object.
+ * @param writer Serialization writer to use to serialize this model.
+ */
+ @Override
+ public void serialize(@Nonnull final SerializationWriter writer) {
+ Objects.requireNonNull(writer, ErrorConstants.Messages.NULL_PARAMETER + "writer");
+ writer.writeOffsetDateTimeValue(EXPIRATION_DATE_TIME, getExpirationDateTime());
+ writer.writeCollectionOfPrimitiveValues(NEXT_EXPECTED_RANGES, getNextExpectedRanges());
+ writer.writeStringValue(UPLOAD_URL, getUploadUrl());
+ writer.writeAdditionalData(getAdditionalData());
+ }
+ /**
+ * Creates a new instance of the current model based on discriminator value.
+ * @param parseNode The parse node to use to read the discriminator value and create the object.
+ * @return an uploadSession
+ */
+ @Nonnull
+ public static UploadSession createFromDiscriminatorValue(@Nonnull final ParseNode parseNode){
+ Objects.requireNonNull(parseNode);
+ return new UploadSession();
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/BaseGraphRequestAdapter.java b/src/main/java/com/microsoft/graph/core/requests/BaseGraphRequestAdapter.java
new file mode 100644
index 000000000..fb7091cb6
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/BaseGraphRequestAdapter.java
@@ -0,0 +1,166 @@
+package com.microsoft.graph.core.requests;
+
+import com.microsoft.graph.core.requests.options.GraphClientOption;
+import com.microsoft.kiota.Compatibility;
+import com.microsoft.kiota.authentication.AuthenticationProvider;
+import com.microsoft.kiota.http.OkHttpRequestAdapter;
+import com.microsoft.kiota.serialization.ParseNodeFactory;
+import com.microsoft.kiota.serialization.SerializationWriterFactory;
+
+import okhttp3.OkHttpClient;
+
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import java.util.EnumMap;
+
+/**
+ * Extension of the OkHttpRequestAdapter which is used as the default for Graph Requests.
+ */
+public class BaseGraphRequestAdapter extends OkHttpRequestAdapter {
+
+ /**
+ * Enum list of Keys which can be used to access the cloudList map.
+ */
+ public enum Clouds {
+ /** Key for Global Cloud URL */
+ GLOBAL_CLOUD,
+ /** Key for US GOV Cloud URL */
+ USGOV_CLOUD,
+ /** Key for China Cloud URL */
+ CHINA_CLOUD,
+ /** Key for Germany Cloud URL */
+ GERMANY_CLOUD,
+ /** Key for US DOD Cloud URL */
+ USGOV_DOD_CLOUD
+ }
+
+ /**
+ * Map of valid cloud urls for use in Graph requests.
+ * Accessible using a Clouds enum value.
+ */
+ private static EnumMap getCloudList() {
+ EnumMap cloudList = new EnumMap<>(Clouds.class);
+ cloudList.put( Clouds.GLOBAL_CLOUD, "https://graph.microsoft.com" );
+ cloudList.put( Clouds.USGOV_CLOUD, "https://graph.microsoft.us");
+ cloudList.put( Clouds.CHINA_CLOUD, "https://microsoftgraph.chinacloudapi.cn");
+ cloudList.put( Clouds.GERMANY_CLOUD, "https://graph.microsoft.de");
+ cloudList.put( Clouds.USGOV_DOD_CLOUD, "https://dod-graph.microsoft.us");
+ return cloudList;
+ }
+
+ /**
+ * The default BaseGraphRequestAdapter constructor, includes all configurable properties.
+ * Note: GraphClientOption will be ignored if you also choose to include an OKHttpClient.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param parseNodeFactory the ParseNodeFactory for use in requests.
+ * @param serializationWriterFactory the SerializationWriterFactory for use in requests.
+ * @param client the OkHttpClient for use in requests.
+ * @param graphClientOption the GraphClientOption for use in requests.
+ * @param baseUrl the base URL for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull final AuthenticationProvider authenticationProvider, @Nullable final ParseNodeFactory parseNodeFactory, @Nullable final SerializationWriterFactory serializationWriterFactory, @Nullable final OkHttpClient client, @Nullable final GraphClientOption graphClientOption, @Nullable String baseUrl) {
+ super(authenticationProvider, parseNodeFactory, serializationWriterFactory, client != null ? client : GraphClientFactory.create(graphClientOption).build());
+ if (!Compatibility.isBlank(baseUrl)) {
+ setBaseUrl(baseUrl);
+ } else {
+ setBaseUrl(determineBaseAddress(null, null));
+ }
+ }
+
+ /**
+ * Constructor requiring only an AuthenticationProvider
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ */
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider) {
+ this(authenticationProvider, determineBaseAddress(null, null));
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider and a base URL.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param baseUrl the base URL for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nonnull String baseUrl) {
+ this(authenticationProvider, baseUrl, new GraphClientOption());
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider, base URL, and an OkHttpClient.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param baseUrl the base URL for use in requests.
+ * @param client the OkHttpClient for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nonnull String baseUrl, @Nonnull OkHttpClient client) {
+ this(authenticationProvider, null, null, client, null, baseUrl);
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider, base URL, and GraphClientOption.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param baseUrl the base URL for use in requests.
+ * @param graphClientOption the GraphClientOption for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nonnull String baseUrl, @Nonnull GraphClientOption graphClientOption) {
+ this(authenticationProvider, null, null, null, graphClientOption, baseUrl);
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider, optional National Cloud, and optional Version.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param cloud the National Cloud for use in requests.
+ * @param version the Graph version for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nullable Clouds cloud, @Nullable String version) {
+ this(authenticationProvider, determineBaseAddress(cloud, version));
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider, optional National Cloud, optional Version, and required OkHttpClient.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param cloud the National Cloud for use in requests.
+ * @param version the Graph version for use in requests.
+ * @param client the OkHttpClient for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nullable Clouds cloud, @Nullable String version, @Nonnull OkHttpClient client) {
+ this(authenticationProvider, determineBaseAddress(cloud, version), client);
+ }
+
+ /**
+ * Constructor requiring an AuthenticationProvider, optional National Cloud, optional Version, and required GraphClientOption.
+ *
+ * @param authenticationProvider the AuthenticationProvider for use in requests.
+ * @param cloud the National Cloud for use in requests.
+ * @param version the Graph version for use in requests.
+ * @param graphClientOption the GraphClientOption for use in requests.
+ */
+ @SuppressWarnings("LambdaLast")
+ public BaseGraphRequestAdapter(@Nonnull AuthenticationProvider authenticationProvider, @Nullable Clouds cloud, @Nullable String version, @Nonnull GraphClientOption graphClientOption) {
+ this(authenticationProvider, determineBaseAddress(cloud, version), graphClientOption);
+ }
+
+ private static String determineBaseAddress(@Nullable final Clouds nationalCloud, @Nullable final String version) {
+ final String cloud = nationalCloud == null ? getCloudList().get(Clouds.GLOBAL_CLOUD) : getCloudList().get(nationalCloud);
+ if(cloud == null) {
+ throw new IllegalArgumentException(nationalCloud+" is an unexpected national cloud.");
+ }
+ return version == null ? (cloud+"/v1.0") : (cloud+"/"+version);
+ }
+ protected final void finalize() throws Throwable{
+ // to avoid finalizer attacks on the constructors defensive programming
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/BatchRequestBuilder.java b/src/main/java/com/microsoft/graph/core/requests/BatchRequestBuilder.java
new file mode 100644
index 000000000..aabd553e1
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/BatchRequestBuilder.java
@@ -0,0 +1,96 @@
+package com.microsoft.graph.core.requests;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.content.BatchRequestContent;
+import com.microsoft.graph.core.content.BatchRequestContentCollection;
+import com.microsoft.graph.core.content.BatchResponseContent;
+import com.microsoft.graph.core.content.BatchResponseContentCollection;
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.kiota.HttpMethod;
+import com.microsoft.kiota.NativeResponseHandler;
+import com.microsoft.kiota.RequestAdapter;
+import com.microsoft.kiota.RequestInformation;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import okhttp3.Response;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A request builder for creating batch requests.
+ */
+public class BatchRequestBuilder {
+ private final RequestAdapter requestAdapter;
+ /**
+ * Instantiates a new BatchRequestBuilder.
+ * @param requestAdapter the adapter to use to build requests.
+ */
+ public BatchRequestBuilder(@Nonnull RequestAdapter requestAdapter) {
+ this.requestAdapter = Objects.requireNonNull(requestAdapter, ErrorConstants.Messages.NULL_PARAMETER + "requestAdapter");
+ }
+ /**
+ * Posts a batch request.
+ * @param requestContent the batch request content.
+ * @param errorMappings the error mappings to use when parsing the response.
+ * @return the batch response content.
+ * @throws IOException if there was an error writing the request content.
+ */
+ @Nonnull
+ public BatchResponseContent post(@Nonnull BatchRequestContent requestContent, @Nullable Map> errorMappings) throws IOException {
+ Objects.requireNonNull(requestContent, ErrorConstants.Messages.NULL_PARAMETER + "requestContent");
+ RequestInformation requestInfo = toPostRequestInformation(requestContent);
+ NativeResponseHandler nativeResponseHandler = new NativeResponseHandler();
+ requestInfo.setResponseHandler(nativeResponseHandler);
+ requestAdapter.sendPrimitive(requestInfo, errorMappings == null ? null : new HashMap<>(errorMappings) ,InputStream.class);
+ return new BatchResponseContent((Response) nativeResponseHandler.getValue(), errorMappings);
+ }
+ /**
+ * Posts a BatchRequestContentCollection.
+ * @param batchRequestContentCollection the BatchRequestContentCollection to post.
+ * @param errorMappings the error mappings to use when parsing the response.
+ * @return the BatchResponseContentCollection.
+ * @throws IOException if there was an error writing the request content.
+ */
+ @Nonnull
+ public BatchResponseContentCollection post(@Nonnull BatchRequestContentCollection batchRequestContentCollection, @Nullable Map> errorMappings) throws IOException {
+ BatchResponseContentCollection collection = new BatchResponseContentCollection();
+ List requests = batchRequestContentCollection.getBatchRequestsForExecution();
+ for (BatchRequestContent request : requests) {
+ BatchResponseContent responseContent = post(request, errorMappings);
+ collection.addBatchResponse(request.getBatchRequestSteps().keySet(), responseContent);
+ }
+ return collection;
+ }
+ /**
+ * Creates the request information for a batch request.
+ * @param requestContent the batch request content.
+ * @return the request information.
+ * @throws IOException if there was an error writing the request content.
+ */
+ @Nonnull
+ public RequestInformation toPostRequestInformation(@Nonnull BatchRequestContent requestContent) throws IOException {
+ Objects.requireNonNull(requestContent, ErrorConstants.Messages.NULL_PARAMETER + "requestContent");
+ RequestInformation requestInfo = new RequestInformation();
+ requestInfo.httpMethod = HttpMethod.POST;
+ requestInfo.urlTemplate = "{+baseurl}/$batch";
+ requestInfo.content = requestContent.getBatchRequestContent();
+ requestInfo.headers.add("Content-Type", CoreConstants.MimeTypeNames.APPLICATION_JSON);
+ return requestInfo;
+ }
+ /**
+ * Gets the request adapter.
+ * @return the request adapter.
+ */
+ @Nonnull
+ public RequestAdapter getRequestAdapter() {
+ return requestAdapter;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/FeatureFlag.java b/src/main/java/com/microsoft/graph/core/requests/FeatureFlag.java
new file mode 100644
index 000000000..dc6ec00b5
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/FeatureFlag.java
@@ -0,0 +1,37 @@
+package com.microsoft.graph.core.requests;
+
+/**
+ * The class which holds the values of each feature flag.
+ * Values are set such that they translate seamlessly to base 2.
+ */
+public final class FeatureFlag {
+ private FeatureFlag(){}
+ /** The value of the None flag, 0.*/
+ public static final int NONE_FLAG = 0;
+ /** The value of the Redirect Handler flag, 1. */
+ public static final int REDIRECT_HANDLER_FLAG = 1;
+ /** The value of the Retry Handler flag, 10. */
+ public static final int RETRY_HANDLER_FLAG = 2;
+ /** The value of the Auth Handler flag, 100. */
+ public static final int AUTH_HANDLER_FLAG = 4;
+ /** The value of the Default Http flag, 1000. */
+ public static final int DEFAULT_HTTP_FLAG = 8;
+ /** The value of the Logging Handler flag, 10000. */
+ public static final int LOGGING_HANDLER_FLAG = 16;
+ /** The value of the Service Discovery flag, 100000. */
+ public static final int SERVICE_DISCOVERY_FLAG = 32;
+ /** The value of the Compression Handler flag, 1000000. */
+ public static final int COMPRESSION_HANDLER_FLAG = 64;
+ /** The value of the Connection Pool flag, 10000000. */
+ public static final int CONNECTION_POOL_FLAG = 128;
+ /** The value of the Long Running Operation flag, 100000000. */
+ public static final int LONG_RUNNING_OP_FLAG = 256;
+ /** The value of the Batch Request flag, 1000000000. */
+ public static final int BATCH_REQUEST_FLAG = 512;
+ /** The value of the Page Iterator flag, 10000000000. */
+ public static final int PAGE_ITERATOR_FLAG = 1024;
+ /** The value of the File Upload flag, 100000000000. */
+ public static final int FILE_UPLOAD_FLAG = 2048;
+ /** The value of the UrlReplacement flag, 1000000000000. */
+ public static final int URL_REPLACEMENT_FLAG = 4096;
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/FeatureTracker.java b/src/main/java/com/microsoft/graph/core/requests/FeatureTracker.java
new file mode 100644
index 000000000..fb43a736b
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/FeatureTracker.java
@@ -0,0 +1,42 @@
+package com.microsoft.graph.core.requests;
+
+
+import jakarta.annotation.Nonnull;
+
+/**
+ * Manages and tracks the flags for tasks and handlers.
+ */
+public class FeatureTracker {
+ /**
+ * Default constructor
+ */
+ public FeatureTracker() {
+ //Default constructor
+ }
+
+ private int featureUsage = FeatureFlag.NONE_FLAG;
+ /**
+ * Sets a numeric representation of the SDK feature usage
+ * @param flag a numeric representation of the SDK feature usage
+ */
+ public void setFeatureUsage(@Nonnull int flag) {
+
+ featureUsage = featureUsage | flag;
+ }
+ /**
+ * Gets a numeric representation of the SDK feature usage
+ * @return a numeric representation of the SDK feature usage
+ */
+ public int getFeatureUsage() {
+ return featureUsage;
+ }
+
+ /**
+ * Gets a serialized representation of the SDK feature usage.
+ * @return a serialized representation of the SDK feature usage
+ */
+ @Nonnull
+ public String getSerializedFeatureUsage() {
+ return Integer.toHexString(featureUsage);
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java b/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java
new file mode 100644
index 000000000..7833952a3
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/GraphClientFactory.java
@@ -0,0 +1,97 @@
+package com.microsoft.graph.core.requests;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.requests.middleware.GraphTelemetryHandler;
+import com.microsoft.graph.core.requests.options.GraphClientOption;
+import com.microsoft.kiota.http.KiotaClientFactory;
+import com.microsoft.kiota.http.middleware.UrlReplaceHandler;
+import com.microsoft.kiota.http.middleware.options.UrlReplaceHandlerOption;
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.util.*;
+
+/**
+ * The GraphClientFactory used to create the OkHttpClient.
+ */
+public class GraphClientFactory {
+ private GraphClientFactory() { }
+ /**
+ * The default OkHttpClient Builder for Graph.
+ *
+ * @return an OkHttpClient Builder instance.
+ */
+ @Nonnull
+ public static OkHttpClient.Builder create() {
+ return create(new GraphClientOption());
+ }
+ /**
+ * OkHttpClient Builder for Graph with specified Interceptors.
+ *
+ * @param interceptors desired interceptors for use in requests.
+ * @return an OkHttpClient Builder instance.
+ */
+ @Nonnull
+ public static OkHttpClient.Builder create(@Nonnull Interceptor... interceptors) {
+ return create(new GraphClientOption(), interceptors);
+ }
+ /**
+ * OkHttpClient Builder for Graph with specified Interceptors and GraphClientOption.
+ *
+ * @param interceptors desired interceptors for use in requests.
+ * @param graphClientOption the GraphClientOption for use in requests.
+ * @return an OkHttpClient Builder instance.
+ */
+ @Nonnull
+ public static OkHttpClient.Builder create(@Nonnull GraphClientOption graphClientOption, @Nonnull Interceptor... interceptors) {
+ final OkHttpClient.Builder builder = create(graphClientOption);
+ //Skip adding interceptor if that class of interceptor already exist.
+ final List appliedInterceptors = new ArrayList<>();
+ for(Interceptor interceptor: builder.interceptors()) {
+ appliedInterceptors.add(interceptor.getClass().toString());
+ }
+ for (Interceptor interceptor:interceptors){
+ if(appliedInterceptors.contains(interceptor.getClass().toString())) {
+ continue;
+ }
+ builder.addInterceptor(interceptor);
+ }
+ return builder;
+ }
+ /**
+ * The OkHttpClient Builder with optional GraphClientOption
+ *
+ * @param graphClientOption the GraphClientOption for use in requests.
+ * @return an OkHttpClient Builder instance.
+ */
+ @Nonnull
+ public static OkHttpClient.Builder create(@Nullable GraphClientOption graphClientOption) {
+ GraphClientOption options = graphClientOption != null ? graphClientOption : new GraphClientOption();
+ return KiotaClientFactory.create(createDefaultGraphInterceptors(options));
+ }
+ /**
+ * Creates the default Interceptors for use with Graph.
+ *
+ * @param graphClientOption the GraphClientOption used to create the GraphTelemetryHandler with.
+ * @return an array of interceptors.
+ */
+ @Nonnull
+ public static Interceptor[] createDefaultGraphInterceptors(@Nonnull GraphClientOption graphClientOption) {
+ List handlers = new ArrayList<>();
+ addDefaultFeatureUsages(graphClientOption);
+
+ handlers.add(new UrlReplaceHandler(new UrlReplaceHandlerOption(CoreConstants.ReplacementConstants.getDefaultReplacementPairs())));
+ handlers.add(new GraphTelemetryHandler(graphClientOption));
+ handlers.addAll(Arrays.asList(KiotaClientFactory.createDefaultInterceptors()));
+ return handlers.toArray(new Interceptor[0]);
+ }
+ //These are the default features used by the Graph Client
+ private static void addDefaultFeatureUsages(GraphClientOption graphClientOption) {
+ graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.RETRY_HANDLER_FLAG);
+ graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.REDIRECT_HANDLER_FLAG);
+ graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.URL_REPLACEMENT_FLAG);
+ graphClientOption.featureTracker.setFeatureUsage(FeatureFlag.BATCH_REQUEST_FLAG);
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/IBaseClient.java b/src/main/java/com/microsoft/graph/core/requests/IBaseClient.java
new file mode 100644
index 000000000..ac54024a0
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/IBaseClient.java
@@ -0,0 +1,28 @@
+package com.microsoft.graph.core.requests;
+
+import com.microsoft.kiota.RequestAdapter;
+
+import jakarta.annotation.Nonnull;
+
+/**
+ * The default client interface
+ */
+public interface IBaseClient {
+ /**
+ * Method to set the RequestAdapter property
+ * @param requestAdapter specifies the desired RequestAdapter
+ */
+ void setRequestAdapter(@Nonnull RequestAdapter requestAdapter);
+ /**
+ * Returns the current RequestAdapter for sending requests
+ * @return the RequestAdapter currently in use
+ */
+ @Nonnull
+ RequestAdapter getRequestAdapter();
+ /**
+ * Gets the BatchRequestBuilder
+ * @return the BatchRequestBuilder instance
+ */
+ @Nonnull
+ BatchRequestBuilder getBatchRequestBuilder();
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/ResponseBodyHandler.java b/src/main/java/com/microsoft/graph/core/requests/ResponseBodyHandler.java
new file mode 100644
index 000000000..c66a99d0d
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/ResponseBodyHandler.java
@@ -0,0 +1,92 @@
+package com.microsoft.graph.core.requests;
+
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.kiota.ApiException;
+import com.microsoft.kiota.ApiExceptionBuilder;
+import com.microsoft.kiota.http.HeadersCompatibility;
+import com.microsoft.kiota.serialization.*;
+
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.io.*;
+import java.util.HashMap;
+
+/**
+ * A response handler for deserializing responses to a ModelType. Particularly for Batch requests.
+ * @param the ModelType of the response body.
+ */
+public class ResponseBodyHandler implements com.microsoft.kiota.ResponseHandler {
+ private final ParseNodeFactory parseNodeFactory;
+ private final ParsableFactory factory;
+ /**
+ * Instantiates a new response handler.
+ * @param parseNodeFactory the parse node factory to use when deserializing the response.
+ * @param factory the factory to use when deserializing the response to a ModelType.
+ */
+ public ResponseBodyHandler(@Nullable ParseNodeFactory parseNodeFactory, @Nonnull ParsableFactory factory) {
+ this.parseNodeFactory = (parseNodeFactory == null) ? ParseNodeFactoryRegistry.defaultInstance : parseNodeFactory;
+ this.factory = factory;
+ }
+ /**
+ * Instantiates a new response handler.
+ * @param factory the factory to use when deserializing the response to a ModelType.
+ */
+ public ResponseBodyHandler(@Nonnull ParsableFactory factory) {
+ this(null, factory);
+ }
+ /**
+ * Handles the response and returns the deserialized response body as a ModelType.
+ * @param response The native response object.
+ * @param errorMappings the error mappings for the response to use when deserializing failed responses bodies. Where an error code like 401 applies specifically to that status code, a class code like 4XX applies to all status codes within the range if an the specific error code is not present.
+ * @return the deserialized response.
+ * @param The type of the native response object.
+ * @param The type of the response model object.
+ */
+ @Nullable
+ @Override
+ public ModelType handleResponse(@Nonnull NativeResponseType response, @Nullable HashMap> errorMappings) {
+ if(response instanceof Response && ((Response) response).body()!=null) {
+ Response nativeResponse = (Response) response;
+ ResponseBody body = nativeResponse.body();
+ try(final InputStream in = body.byteStream()) {
+ ParseNode parseNode = this.parseNodeFactory.getParseNode(body.contentType().type() + "/" + body.contentType().subtype(), in);
+ body.close();
+ if(nativeResponse.isSuccessful()) {
+ final ModelType result = (ModelType) parseNode.getObjectValue(this.factory); //We can be sure this is the correct type since return of this method is based on the type of the factory.
+ return result;
+ } else {
+ handleFailedResponse(nativeResponse, errorMappings, parseNode);
+ }
+ }
+ catch(IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ } else {
+ throw new IllegalArgumentException("The provided response type is not supported by this response handler.");
+ }
+ return null;
+ }
+
+ private void handleFailedResponse(Response nativeResponse, HashMap> errorMappings, ParseNode parseNode) {
+ int statusCode = nativeResponse.code();
+ String statusCodeString = String.valueOf(statusCode);
+ if (errorMappings == null ||
+ !errorMappings.containsKey(statusCodeString) ||
+ !(statusCode >= 400 && statusCode <= 499 && errorMappings.containsKey("4XX")) &&
+ !(statusCode >= 500 && statusCode <= 599 && errorMappings.containsKey("5XX"))) {
+ throw new ApiExceptionBuilder()
+ .withMessage(ErrorConstants.Codes.GENERAL_EXCEPTION)
+ .withResponseStatusCode(statusCode)
+ .withResponseHeaders(HeadersCompatibility.getResponseHeaders(nativeResponse.headers()))
+ .build();
+ } else {
+ Parsable result = parseNode.getObjectValue(errorMappings.get(statusCodeString));
+ if (!(result instanceof Exception)) {
+ throw new ApiException("The server returned an unexpected status code and the error registered for this code failed to deserialize: " + statusCodeString);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandler.java b/src/main/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandler.java
new file mode 100644
index 000000000..46bbe0a97
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/middleware/GraphTelemetryHandler.java
@@ -0,0 +1,99 @@
+package com.microsoft.graph.core.requests.middleware;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Objects;
+
+import com.microsoft.graph.core.requests.options.GraphClientOption;
+import jakarta.annotation.Nonnull;
+
+import com.microsoft.graph.core.CoreConstants;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+/**
+ * Middleware responsible for adding telemetry information on SDK usage
+ * Note: the telemetry only collects anonymous information on SDK version and usage. No personal information is collected.
+ */
+public class GraphTelemetryHandler implements Interceptor{
+
+ private GraphClientOption mGraphClientOption;
+
+ /**
+ * Instantiate a GraphTelemetryHandler with default GraphClientOption.
+ */
+ public GraphTelemetryHandler(){
+ this(new GraphClientOption());
+ }
+ /**
+ * Instantiate a GraphTelemetryHandler with specified GraphClientOption
+ * @param graphClientOption the specified GraphClientOption for the GraphTelemetryHandler.
+ */
+ public GraphTelemetryHandler(@Nonnull final GraphClientOption graphClientOption){
+ this.mGraphClientOption = Objects.requireNonNull(graphClientOption);
+ }
+
+ @Override
+ @Nonnull
+ public Response intercept(@Nonnull final Chain chain) throws IOException {
+ final Request request = chain.request();
+ final Request.Builder telemetryAddedBuilder = request.newBuilder();
+
+ final String clientLibraryUsed = "graph-java" + (mGraphClientOption.getGraphServiceTargetVersion().equals("v1.0") ? "" : "-"+mGraphClientOption.getGraphServiceTargetVersion()); //graph-java | graph-java-beta
+ final String sdkVersion = (mGraphClientOption.getClientLibraryVersion() == null ? "" : "/"+ mGraphClientOption.getClientLibraryVersion()); //SDK version value
+
+ final String coreVersionHeader = CoreConstants.Headers.GRAPH_VERSION_PREFIX + "/" + mGraphClientOption.getCoreLibraryVersion(); //"graph-java-core/3.0.0"
+
+ final String featureUsage = "(featureUsage=" + mGraphClientOption.featureTracker.getSerializedFeatureUsage(); // (featureUsage=
+
+ final String jreVersion = System.getProperty("java.version");
+ final String jreVersionHeader = (CoreConstants.Headers.DEFAULT_VERSION_VALUE.equals(jreVersion) ? "" : ("; runtimeEnvironment=JRE/"+jreVersion)); //runtimeEnvironment=JRE/
+
+ final String androidVersion = getAndroidAPILevel(); // android/
+ final String androidVersionHeader = (CoreConstants.Headers.DEFAULT_VERSION_VALUE.equals(androidVersion) ? "" : ("; " + CoreConstants.Headers.ANDROID_VERSION_PREFIX + "/" + androidVersion));
+
+ final String sdkTelemetry = clientLibraryUsed + sdkVersion + ", " + coreVersionHeader + " " + featureUsage + jreVersionHeader + androidVersionHeader+")";
+
+ telemetryAddedBuilder.addHeader(CoreConstants.Headers.SDK_VERSION_HEADER_NAME, sdkTelemetry);
+ if(request.header(CoreConstants.Headers.CLIENT_REQUEST_ID) == null) {
+ telemetryAddedBuilder.addHeader(CoreConstants.Headers.CLIENT_REQUEST_ID, mGraphClientOption.getClientRequestId());
+ }
+
+ return chain.proceed(telemetryAddedBuilder.build());
+ }
+
+ private String androidAPILevel;
+ private String getAndroidAPILevel() {
+ if(androidAPILevel == null) {
+ androidAPILevel = getAndroidAPILevelInternal();
+ }
+ return androidAPILevel;
+ }
+
+ private String getAndroidAPILevelInternal() {
+ try {
+ final Class> buildClass = Class.forName("android.os.Build");
+ final Class>[] subclasses = buildClass.getDeclaredClasses();
+ Class> versionClass = null;
+ for(final Class> subclass : subclasses) {
+ if(subclass.getName().endsWith("VERSION")) {
+ versionClass = subclass;
+ break;
+ }
+ }
+ if(versionClass == null)
+ return CoreConstants.Headers.DEFAULT_VERSION_VALUE;
+ else {
+ final Field sdkVersionField = versionClass.getField("SDK_INT");
+ final Object value = sdkVersionField.get(null);
+ final String valueStr = String.valueOf(value);
+ return valueStr == null || valueStr.equals("") ? CoreConstants.Headers.DEFAULT_VERSION_VALUE : valueStr;
+ }
+ } catch (IllegalAccessException | ClassNotFoundException | NoSuchFieldException ex) {
+ // we're not on android and return "0" to align with java version which returns "0" when running on android
+ return CoreConstants.Headers.DEFAULT_VERSION_VALUE;
+ }
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/options/GraphClientOption.java b/src/main/java/com/microsoft/graph/core/requests/options/GraphClientOption.java
new file mode 100644
index 000000000..e3aa39968
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/options/GraphClientOption.java
@@ -0,0 +1,120 @@
+package com.microsoft.graph.core.requests.options;
+
+import java.util.UUID;
+
+import com.microsoft.graph.core.requests.FeatureTracker;
+import com.microsoft.kiota.Compatibility;
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.kiota.RequestOption;
+
+/**
+ * Options to be passed to the telemetry middleware.
+ */
+public class GraphClientOption implements RequestOption {
+
+ private String clientRequestId;
+ private String clientLibraryVersion;
+ private String coreLibraryVersion;
+ private String graphServiceTargetVersion;
+ /**
+ * Default constructor
+ */
+ public GraphClientOption() {
+ //Default constructor
+ }
+
+ /**
+ * Feature Tracker instance
+ */
+ public final FeatureTracker featureTracker = new FeatureTracker();
+ /**
+ * Sets the client request id
+ * @param clientRequestId the client request id to set, preferably the string representation of a GUID
+ */
+ public void setClientRequestId(@Nonnull final String clientRequestId) {
+ if(Compatibility.isBlank(clientRequestId)) {
+ throw new IllegalArgumentException("clientRequestId cannot be null or empty");
+ }
+ this.clientRequestId = clientRequestId;
+ }
+ /**
+ * Gets the client request id
+ * @return the client request id
+ */
+ @Nonnull
+ public String getClientRequestId() {
+ if(clientRequestId == null) {
+ clientRequestId = UUID.randomUUID().toString();
+ }
+ return clientRequestId;
+ }
+ /**
+ * Sets a string representation of the client library
+ * @param clientLibraryVersion client library version specified by user.
+ */
+ public void setClientLibraryVersion(@Nonnull final String clientLibraryVersion) {
+ if(Compatibility.isBlank(clientLibraryVersion))
+ {
+ throw new IllegalArgumentException("clientLibraryVersion cannot be null or empty");
+ }
+ this.clientLibraryVersion = clientLibraryVersion;
+ }
+ /**
+ * Get the client library version as a string
+ * If null return null;
+ * @return client library version.
+ */
+ @Nullable
+ public String getClientLibraryVersion() {
+ return this.clientLibraryVersion == null ? null : this.clientLibraryVersion;
+ }
+ /**
+ * Set the core library version as a String, in this format 'x.x.x'
+ * @param coreLibraryVersion core library version specified by user.
+ */
+ public void setCoreLibraryVersion(@Nonnull final String coreLibraryVersion) {
+ if(Compatibility.isBlank(coreLibraryVersion))
+ {
+ throw new IllegalArgumentException("coreLibraryVersion cannot be null or empty");
+ }
+ this.coreLibraryVersion = coreLibraryVersion;
+ }
+ /**
+ * Get the core library version as a String, in this format 'x.x.x'
+ * If null return the value in CoreConstants.
+ * @return core library version.
+ */
+ @Nonnull
+ public String getCoreLibraryVersion() {
+ return this.coreLibraryVersion == null ? CoreConstants.Headers.VERSION : this.coreLibraryVersion;
+ }
+ /**
+ * Set the target version of the api endpoint we are targeting (v1 or beta)
+ * @param graphServiceVersion the version of the Api endpoint we are targeting
+ */
+ public void setGraphServiceTargetVersion(@Nonnull final String graphServiceVersion) {
+ if(Compatibility.isBlank(graphServiceVersion))
+ {
+ throw new IllegalArgumentException("graphServiceVersion cannot be null or empty");
+ }
+ this.graphServiceTargetVersion = graphServiceVersion;
+ }
+ /**
+ * Get the target version of the api endpoint we are targeting (v1 or beta)
+ * return 'v1' if not specified.
+ * @return the version of the Api endpoint we are targeting.
+ */
+ @Nonnull
+ public String getGraphServiceTargetVersion() {
+ return this.graphServiceTargetVersion == null ? "v1.0" : this.graphServiceTargetVersion;
+ }
+
+ @Override
+ @Nonnull
+ public Class getType() {
+ return (Class) GraphClientOption.class;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/upload/UploadResponseHandler.java b/src/main/java/com/microsoft/graph/core/requests/upload/UploadResponseHandler.java
new file mode 100644
index 000000000..6d4a2acec
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/upload/UploadResponseHandler.java
@@ -0,0 +1,94 @@
+package com.microsoft.graph.core.requests.upload;
+
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.graph.core.models.UploadResult;
+import com.microsoft.graph.core.models.UploadSession;
+import com.microsoft.kiota.ApiException;
+import com.microsoft.kiota.ApiExceptionBuilder;
+import com.microsoft.kiota.http.HeadersCompatibility;
+import com.microsoft.kiota.serialization.*;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Objects;
+
+/**
+ * The request handler for upload requests.
+ */
+public class UploadResponseHandler {
+
+ private final ParseNodeFactory parseNodeFactory;
+ /**
+ * UploadResponseHandler constructor.
+ */
+ public UploadResponseHandler() {
+ this(null);
+ }
+ /**
+ * UploadResponseHandler constructor.
+ * @param parseNodeFactory The ParseNodeFactory to use for response parsing.
+ */
+ public UploadResponseHandler(@Nullable ParseNodeFactory parseNodeFactory) {
+ this.parseNodeFactory = (parseNodeFactory == null) ? ParseNodeFactoryRegistry.defaultInstance : parseNodeFactory;
+ }
+ /**
+ * Process the raw HTTP response from an upload request.
+ * @param response The HTTP response returned from the upload request.
+ * @param factory The ParsableFactory defining the instantiation of the object being uploaded.
+ * @param The type of the object being uploaded.
+ * @return An UploadResult model containing the information from the server resulting from the upload request.
+ */
+ @Nonnull
+ public UploadResult handleResponse(@Nonnull final Response response, @Nonnull final ParsableFactory factory) {
+ Objects.requireNonNull(response);
+ Objects.requireNonNull(factory);
+ try (final ResponseBody body = response.body()) {
+ if (Objects.isNull(body)) {
+ throw new ApiException(ErrorConstants.Messages.NO_RESPONSE_FOR_UPLOAD);
+ }
+ try(final InputStream in = body.byteStream()){
+ final String contentType = body.contentType().toString().split(";")[0]; //contentType.toString() returns in format ;, we only want the mediaType.
+ if(!response.isSuccessful()) {
+ throw new ApiExceptionBuilder()
+ .withMessage(ErrorConstants.Codes.GENERAL_EXCEPTION)
+ .withResponseStatusCode(response.code())
+ .withResponseHeaders(HeadersCompatibility.getResponseHeaders(response.headers()))
+ .build();
+ }
+ UploadResult uploadResult = new UploadResult<>();
+ if (response.code() == HttpURLConnection.HTTP_CREATED) {
+ if (body.contentLength() > 0) {
+ final ParseNode uploadTypeParseNode = parseNodeFactory.getParseNode(contentType, in);
+ uploadResult.itemResponse = uploadTypeParseNode.getObjectValue(factory);
+ }
+ final String location = response.headers().get("location");
+ if(!Objects.isNull(location) && !location.isEmpty()) {
+ uploadResult.location = new URI(location);
+ }
+ } else {
+ final ParseNode parseNode = parseNodeFactory.getParseNode(contentType, in);
+ final UploadSession uploadSession = parseNode.getObjectValue(UploadSession::createFromDiscriminatorValue);
+ if (!uploadSession.getNextExpectedRanges().isEmpty()) {
+ uploadResult.uploadSession = uploadSession;
+ } else {
+ uploadResult.itemResponse = parseNode.getObjectValue(factory);
+ }
+ }
+ return uploadResult;
+ }
+ }
+ catch(IOException | URISyntaxException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
+
+
diff --git a/src/main/java/com/microsoft/graph/core/requests/upload/UploadSessionRequestBuilder.java b/src/main/java/com/microsoft/graph/core/requests/upload/UploadSessionRequestBuilder.java
new file mode 100644
index 000000000..b9ca15537
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/upload/UploadSessionRequestBuilder.java
@@ -0,0 +1,74 @@
+package com.microsoft.graph.core.requests.upload;
+
+import com.microsoft.graph.core.models.IUploadSession;
+import com.microsoft.graph.core.models.UploadResult;
+import com.microsoft.kiota.*;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import okhttp3.Response;
+
+import jakarta.annotation.Nonnull;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * UploadSessionRequestBuilder class to get and delete an UploadSession.
+ * @param The type of object being uploaded.
+ */
+public class UploadSessionRequestBuilder {
+
+ private final UploadResponseHandler responseHandler;
+ private final RequestAdapter requestAdapter;
+ private final String urlTemplate;
+ private final ParsableFactory factory;
+ /**
+ * Create a new UploadSessionRequest.
+ * @param sessionUrl The uploadSession url to use in the request.
+ * @param requestAdapter The RequestAdapted to execute the request.
+ * @param factory The ParsableFactory defining the instantiation of the object being uploaded.
+ */
+ public UploadSessionRequestBuilder(@Nonnull String sessionUrl,
+ @Nonnull final RequestAdapter requestAdapter,
+ @Nonnull final ParsableFactory factory) {
+ this.responseHandler = new UploadResponseHandler();
+ this.requestAdapter = Objects.requireNonNull(requestAdapter);
+ if(Compatibility.isBlank(sessionUrl))
+ {
+ throw new IllegalArgumentException("sessionUrl cannot be null or empty");
+ }
+ this.urlTemplate = sessionUrl;
+ this.factory = Objects.requireNonNull(factory);
+ }
+ /**
+ * Gets the specified UploadSession.
+ * @return the IUploadSession
+ */
+ @Nonnull
+ public IUploadSession get() {
+ RequestInformation requestInformation = toGetRequestInformation();
+ NativeResponseHandler nativeResponseHandler = new NativeResponseHandler();
+ requestInformation.setResponseHandler(nativeResponseHandler);
+ requestAdapter.sendPrimitive(requestInformation, null, InputStream.class);
+ UploadResult result = responseHandler.handleResponse((Response) nativeResponseHandler.getValue(), factory);
+ return result.uploadSession;
+ }
+ private RequestInformation toGetRequestInformation() {
+ RequestInformation requestInformation = new RequestInformation();
+ requestInformation.httpMethod = HttpMethod.GET;
+ requestInformation.urlTemplate = this.urlTemplate;
+ return requestInformation;
+ }
+ /**
+ * Deletes the specified UploadSession.
+ */
+ public void delete() {
+ RequestInformation requestInfo = this.toDeleteRequestInformation();
+ this.requestAdapter.sendPrimitive(requestInfo, null, Void.class);
+ }
+ private RequestInformation toDeleteRequestInformation() {
+ RequestInformation requestInformation = new RequestInformation();
+ requestInformation.httpMethod = HttpMethod.DELETE;
+ requestInformation.urlTemplate = this.urlTemplate;
+ return requestInformation;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/requests/upload/UploadSliceRequestBuilder.java b/src/main/java/com/microsoft/graph/core/requests/upload/UploadSliceRequestBuilder.java
new file mode 100644
index 000000000..718697d06
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/requests/upload/UploadSliceRequestBuilder.java
@@ -0,0 +1,109 @@
+package com.microsoft.graph.core.requests.upload;
+
+import com.microsoft.graph.core.models.UploadResult;
+import com.microsoft.kiota.*;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import okhttp3.Response;
+
+import jakarta.annotation.Nonnull;
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Request for uploading a slice of a large file.
+ * @param The type of the object being uploaded.
+ */
+public class UploadSliceRequestBuilder {
+
+ private final UploadResponseHandler responseHandler;
+ private final RequestAdapter requestAdapter;
+ private final String urlTemplate;
+ private final long rangeBegin;
+ private final long rangeEnd;
+ private final long totalSessionLength;
+ private final long rangeLength;
+ private final ParsableFactory factory;
+
+ /**
+ * Request for uploading one slice of a session.
+ * @param sessionUrl URL to upload the slice.
+ * @param requestAdapter Request adapted used for uploading the slice.
+ * @param rangeBegin Beginning of the range for this slice.
+ * @param rangeEnd End of the range for this slice.
+ * @param totalSessionLength Total session length. This MUST be consistent.
+ * @param factory The ParsableFactory defining the instantiation of the object being uploaded.
+ */
+ public UploadSliceRequestBuilder(@Nonnull String sessionUrl,
+ @Nonnull final RequestAdapter requestAdapter,
+ long rangeBegin,
+ long rangeEnd,
+ long totalSessionLength,
+ @Nonnull ParsableFactory factory) {
+ if(Compatibility.isBlank(sessionUrl))
+ {
+ throw new IllegalArgumentException("sessionUrl cannot be null or empty");
+ }
+ this.urlTemplate = sessionUrl;
+ this.requestAdapter = Objects.requireNonNull(requestAdapter);
+ this.factory = factory;
+ this.rangeBegin = rangeBegin;
+ this.rangeEnd = rangeEnd;
+ this.rangeLength = (rangeEnd-rangeBegin+1);
+ this.totalSessionLength = totalSessionLength;
+ this.responseHandler = new UploadResponseHandler();
+ }
+ /**
+ * Uploads the slice using PUT.
+ * @param stream The stream of data to be uploaded.
+ * @return The model containing the Upload information retrieved from the response.
+ */
+ @Nonnull
+ public UploadResult put(@Nonnull InputStream stream) {
+ Objects.requireNonNull(stream);
+ RequestInformation requestInformation = this.toPutRequestInformation(stream);
+ NativeResponseHandler nativeResponseHandler = new NativeResponseHandler();
+ requestInformation.setResponseHandler(nativeResponseHandler);
+ requestAdapter.sendPrimitive(requestInformation,null, InputStream.class);
+ return responseHandler.handleResponse((Response) nativeResponseHandler.getValue(), factory);
+ }
+ private RequestInformation toPutRequestInformation(InputStream stream) {
+ Objects.requireNonNull(stream);
+ RequestInformation requestInfo = new RequestInformation();
+ requestInfo.httpMethod = HttpMethod.PUT;
+ requestInfo.urlTemplate = this.urlTemplate;
+ requestInfo.setStreamContent(stream,"application/octet-stream");
+ requestInfo.headers.add("Content-Range", String.format(Locale.US, "bytes %d-%d/%d", this.rangeBegin, this.rangeEnd, this.totalSessionLength));
+ requestInfo.headers.add("Content-Length", ""+this.rangeLength);
+ return requestInfo;
+ }
+ /**
+ * Get the range of bytes for this slice.
+ * @return the range of bytes in this slice.
+ */
+ public long getRangeLength() {
+ return rangeLength;
+ }
+ /**
+ * Get the starting byte position for this upload slice.
+ * @return The byte position where this upload slice begins.
+ */
+ public long getRangeBegin() {
+ return rangeBegin;
+ }
+ /**
+ * Get the ending byte position for this upload slice.
+ * @return the position where this upload slice ends.
+ */
+ public long getRangeEnd() {
+ return rangeEnd;
+ }
+ /**
+ * Get the total number of bytes being uploaded in the session.
+ * @return The total number of bytes in this upload session.
+ */
+ public long getTotalSessionLength() {
+ return totalSessionLength;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/tasks/LargeFileUploadTask.java b/src/main/java/com/microsoft/graph/core/tasks/LargeFileUploadTask.java
new file mode 100644
index 000000000..9f02dfe27
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/tasks/LargeFileUploadTask.java
@@ -0,0 +1,284 @@
+package com.microsoft.graph.core.tasks;
+
+import com.microsoft.graph.core.ErrorConstants;
+import com.microsoft.graph.core.exceptions.ClientException;
+import com.microsoft.graph.core.models.IProgressCallback;
+import com.microsoft.graph.core.models.IUploadSession;
+import com.microsoft.graph.core.models.UploadResult;
+import com.microsoft.graph.core.models.UploadSession;
+import com.microsoft.graph.core.requests.BaseGraphRequestAdapter;
+import com.microsoft.graph.core.requests.FeatureFlag;
+import com.microsoft.graph.core.requests.GraphClientFactory;
+import com.microsoft.graph.core.requests.options.GraphClientOption;
+import com.microsoft.graph.core.requests.upload.UploadSessionRequestBuilder;
+import com.microsoft.graph.core.requests.upload.UploadSliceRequestBuilder;
+import com.microsoft.kiota.ApiException;
+import com.microsoft.kiota.RequestAdapter;
+import com.microsoft.kiota.authentication.AnonymousAuthenticationProvider;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+import com.microsoft.kiota.serialization.ParseNode;
+import okhttp3.OkHttpClient;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.time.OffsetDateTime;
+import java.util.*;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Task for uploading large files including pausing and resuming.
+ * @param They type of Item that we will be uploading
+ */
+public class LargeFileUploadTask {
+
+ private static final long DEFAULT_MAX_SLICE_SIZE = (long) 5*1024*1024;
+ private IUploadSession uploadSession;
+ private final RequestAdapter requestAdapter;
+ private final InputStream uploadStream;
+ private final long maxSliceSize;
+ private ArrayList> rangesRemaining;
+ private final long totalUploadLength;
+ private final ParsableFactory factory;
+ private long amountUploaded;
+ /**
+ * LargeFileUploadTask instance constructor.
+ * @param requestAdapter The request adapter for this upload task.
+ * @param uploadSession Parsable containing upload session information.
+ * @param uploadStream Readable stream of information to be uploaded.
+ * @param streamSize The size of the information stream to be uploaded.
+ * @param factory The ParsableFactory defining the instantiation of the object being uploaded.
+ * @throws IllegalAccessException thrown when attempting to extract uploadSession information.
+ * @throws IOException thrown when attempting to extract uploadSession information.
+ * @throws InvocationTargetException thrown when attempting to extract uploadSession information.
+ * @throws NoSuchMethodException thrown when attempting to extract uploadSession information.
+ */
+ public LargeFileUploadTask(@Nullable final RequestAdapter requestAdapter,
+ @Nonnull Parsable uploadSession,
+ @Nonnull InputStream uploadStream,
+ long streamSize,
+ @Nonnull ParsableFactory factory) throws IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
+ this(requestAdapter, uploadSession,uploadStream, streamSize,DEFAULT_MAX_SLICE_SIZE, factory);
+ }
+ /**
+ * LargeFileUploadTask instance constructor.
+ * @param requestAdapter The request adapter for this upload task.
+ * @param uploadSession Parsable containing upload session information.
+ * @param uploadStream Readable stream of information to be uploaded.
+ * @param streamSize The size of the information stream to be uploaded.
+ * @param maxSliceSize Max size(in bytes) of each slice to be uploaded. Defaults to 5 MB. When uploading to OneDrive or SharePoint, this value needs to be a multiple of 320 KiB (327,680 bytes).
+ * @param factory The ParsableFactory defining the instantiation of the object being uploaded.
+ * @throws IllegalAccessException thrown when attempting to extract uploadSession information.
+ * @throws IOException thrown when attempting to extract uploadSession information.
+ * @throws InvocationTargetException thrown when attempting to extract uploadSession information.
+ * @throws NoSuchMethodException thrown when attempting to extract uploadSession information.
+ */
+ public LargeFileUploadTask(@Nullable final RequestAdapter requestAdapter,
+ @Nonnull Parsable uploadSession,
+ @Nonnull InputStream uploadStream,
+ long streamSize,
+ long maxSliceSize,
+ @Nonnull ParsableFactory factory) throws IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
+ Objects.requireNonNull(uploadSession);
+ Objects.requireNonNull(uploadStream);
+ Objects.requireNonNull(factory);
+ if(uploadStream.available() <=0) {
+ throw new IllegalArgumentException("Must provide a stream that is not empty.");
+ }
+ this.uploadSession = extractSessionFromParsable(uploadSession);
+ this.requestAdapter = Objects.isNull(requestAdapter) ? initializeAdapter(this.uploadSession.getUploadUrl()):requestAdapter;
+ this.totalUploadLength = streamSize;
+ this.rangesRemaining = getRangesRemaining(this.uploadSession);
+ this.uploadStream = uploadStream;
+ this.maxSliceSize = maxSliceSize;
+ this.factory = factory;
+ }
+ /**
+ * Perform the upload task.
+ * @return An UploadResult model containing the information from the server resulting from the upload request.
+ * May also occur if interruption occurs in .sleep() call.
+ * @throws IOException if there was an error reading the chunk input stream.
+ * @throws InterruptedException if the thread is interrupted while sleeping.
+ */
+ @Nonnull
+ public UploadResult upload() throws IOException, InterruptedException{
+ return this.upload(3, null);
+ }
+ /**
+ * Perform the upload task.
+ * @param maxTries Number of times to retry the task before giving up.
+ * @param progress IProgress interface describing how to report progress.
+ * @return An UploadResult model containing the information from the server resulting from the upload request.
+ * May also occur if interruption occurs in .sleep() call.
+ * @throws IOException if there was an error reading the chunk input stream.
+ * @throws InterruptedException if the thread is interrupted while sleeping.
+ */
+ @Nonnull
+ public UploadResult upload(int maxTries, @Nullable IProgressCallback progress) throws IOException, InterruptedException {
+ int uploadTries = 0;
+ ArrayList exceptionsList = new ArrayList<>();
+ while (uploadTries < maxTries) {
+
+ List> uploadSliceRequestBuilders = getUploadSliceRequests();
+ for (UploadSliceRequestBuilder request : uploadSliceRequestBuilders) {
+ UploadResult result;
+ result = uploadSlice(request, exceptionsList);
+ amountUploaded += request.getRangeLength();
+ if(progress != null) {
+ progress.report(amountUploaded, this.totalUploadLength);
+ }
+ if (result.isUploadSuccessful()) {
+ return result;
+ }
+ }
+ updateSessionStatus();
+ uploadTries += 1;
+ if (uploadTries < maxTries) {
+ TimeUnit.SECONDS.sleep((long) 2 * uploadTries * uploadTries);
+ }
+ }
+ throw new CancellationException("The upload task was retried the maximum number of times without success and has been cancelled.");
+ }
+ /**
+ * Resume the upload task.
+ * @return An UploadResult model containing the information from the server resulting from the upload request.
+ * @throws ClientException if the upload session has expired.
+ * @throws IOException if there was an error reading the chunk input stream.
+ * @throws InterruptedException if the thread is interrupted while sleeping.
+ */
+ @Nonnull
+ public UploadResult resume() throws ClientException, IOException , InterruptedException{
+ return this.resume(3, null);
+ }
+ /**
+ * Resume the upload task.
+ * @param maxTries Number of times to retry the task before giving up.
+ * @param progress IProgress interface describing how to report progress.
+ * @return An UploadResult model containing the information from the server resulting from the upload request.
+ * @throws ClientException if the upload session has expired.
+ * @throws IOException if there was an error reading the chunk input stream.
+ * @throws InterruptedException if the thread is interrupted while sleeping.
+ */
+ @Nonnull
+ public UploadResult resume(int maxTries, @Nullable IProgressCallback progress) throws ClientException, IOException , InterruptedException{
+ IUploadSession session;
+ session = updateSessionStatus();
+ OffsetDateTime expirationDateTime = Objects.isNull(session.getExpirationDateTime()) ? OffsetDateTime.now() : session.getExpirationDateTime();
+ if(expirationDateTime.isBefore(OffsetDateTime.now()) || expirationDateTime.isEqual(OffsetDateTime.now())) {
+ throw new ClientException(ErrorConstants.Messages.EXPIRED_UPLOAD_SESSION);
+ }
+ return this.upload(maxTries, progress);
+ }
+ /**
+ * Delete the upload session.
+ * @throws ClientException if the upload session has expired.
+ */
+ public void deleteSession() throws ClientException {
+ OffsetDateTime expirationDateTime = Objects.isNull(this.uploadSession.getExpirationDateTime()) ? OffsetDateTime.now() : this.uploadSession.getExpirationDateTime();
+ if(expirationDateTime.isBefore(OffsetDateTime.now()) || expirationDateTime.isEqual(OffsetDateTime.now())) {
+ throw new ClientException(ErrorConstants.Messages.EXPIRED_UPLOAD_SESSION);
+ }
+ UploadSessionRequestBuilder builder = new UploadSessionRequestBuilder<>(this.uploadSession.getUploadUrl(), this.requestAdapter, this.factory);
+ builder.delete();
+ }
+ /**
+ * Get the session information from the server, and update the internally held session with the updated information.
+ * @return the updated UploadSession model.
+ */
+ @Nonnull
+ public IUploadSession updateSessionStatus() {
+ UploadSessionRequestBuilder sessionRequestBuilder = new UploadSessionRequestBuilder<>(this.uploadSession.getUploadUrl(), this.requestAdapter, this.factory);
+ IUploadSession session = sessionRequestBuilder.get();
+ this.rangesRemaining = getRangesRemaining(session);
+ session.setUploadUrl(this.uploadSession.getUploadUrl());
+ this.uploadSession = session;
+ return session;
+ }
+ private UploadResult uploadSlice(UploadSliceRequestBuilder uploadSliceRequestBuilder, ArrayList exceptionsList) throws IOException {
+ byte[] buffer = chunkInputStream(uploadStream,(int) uploadSliceRequestBuilder.getRangeBegin(), (int)uploadSliceRequestBuilder.getRangeLength());
+ ByteArrayInputStream chunkStream = new ByteArrayInputStream(buffer);
+ try {
+ return uploadSliceRequestBuilder.put(chunkStream);
+ } catch (ApiException apiException) {
+ return handleApiException(apiException, exceptionsList);
+ }
+ }
+ private UploadResult handleApiException(ApiException apiException, ArrayList exceptionsList) {
+ if(apiException.getMessage().toLowerCase(Locale.ROOT).contains(ErrorConstants.Codes.GENERAL_EXCEPTION.toLowerCase(Locale.ROOT))
+ || apiException.getMessage().toLowerCase(Locale.ROOT).contains(ErrorConstants.Codes.TIMEOUT.toLowerCase(Locale.ROOT))) {
+ exceptionsList.add(apiException);
+ } else if (apiException.getMessage().toLowerCase(Locale.ROOT).contains(ErrorConstants.Codes.INVALID_RANGE.toLowerCase(Locale.ROOT))) {
+ return new UploadResult<>();
+ }
+ throw apiException;
+ }
+ /**
+ * Creates the UploadSliceRequestBuilders for the upload task based on the upload session information.
+ * @return The list of UploadSliceRequestsBuilders, each describing a slice to be uploaded.
+ */
+ @Nonnull
+ protected List> getUploadSliceRequests() {
+ ArrayList> builders = new ArrayList<>();
+ for (Map.Entry entry: rangesRemaining) {
+ long currentRangeBegin = entry.getKey();
+ long currentEnd = entry.getValue();
+ while(currentRangeBegin < currentEnd) {
+ long nextSliceSize = nextSliceSize(currentRangeBegin, currentEnd);
+ UploadSliceRequestBuilder sliceRequestBuilder =
+ new UploadSliceRequestBuilder<>(this.uploadSession.getUploadUrl(), this.requestAdapter,
+ currentRangeBegin, currentRangeBegin + nextSliceSize -1, this.totalUploadLength, this.factory);
+ builders.add(sliceRequestBuilder);
+ currentRangeBegin += nextSliceSize;
+ }
+ }
+ return builders;
+ }
+ private ArrayList> getRangesRemaining(IUploadSession uploadSession) {
+ ArrayList> remaining = new ArrayList<>();
+ for (String range:uploadSession.getNextExpectedRanges()) {
+ String[] specifiers = range.split("-");
+ remaining.add(new AbstractMap.SimpleEntry<>(Long.valueOf(specifiers[0]),
+ specifiers.length == 2 ? Long.parseLong(specifiers[1]) : this.totalUploadLength -1));
+ }
+ return remaining;
+ }
+ private RequestAdapter initializeAdapter(String uploadUrl) {
+ GraphClientOption options = new GraphClientOption();
+ options.featureTracker.setFeatureUsage(FeatureFlag.FILE_UPLOAD_FLAG);
+ OkHttpClient client = GraphClientFactory.create(options).build();
+ return new BaseGraphRequestAdapter(new AnonymousAuthenticationProvider(), uploadUrl, client);
+ }
+ /** Extract the upload session information from parsable and return in a new UploadSession model. */
+ @Nonnull
+ private IUploadSession extractSessionFromParsable(@Nonnull Parsable uploadSession) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+ Map> deserializers = uploadSession.getFieldDeserializers();
+ if (!deserializers.containsKey("expirationDateTime"))
+ throw new IllegalArgumentException("The Parsable does not contain the 'expirationDateTime' property");
+ if (!deserializers.containsKey("nextExpectedRanges"))
+ throw new IllegalArgumentException("The Parsable does not contain the 'nextExpectedRanges' property");
+ if (!deserializers.containsKey("uploadUrl"))
+ throw new IllegalArgumentException("The Parsable does not contain the 'uploadUrl' property");
+
+ UploadSession session = new UploadSession();
+ session.setExpirationDateTime((OffsetDateTime) uploadSession.getClass().getDeclaredMethod("getExpirationDateTime").invoke(uploadSession));
+ session.setUploadUrl((String) uploadSession.getClass().getDeclaredMethod("getUploadUrl").invoke(uploadSession));
+ session.setNextExpectedRanges((List) uploadSession.getClass().getDeclaredMethod("getNextExpectedRanges").invoke(uploadSession));
+ return session;
+ }
+ private long nextSliceSize(long rangeBegin, long rangeEnd) {
+ long size = rangeEnd - rangeBegin + 1;
+ return Math.min(size, this.maxSliceSize);
+ }
+ private byte[] chunkInputStream(InputStream stream, int begin, int length) throws IOException {
+ byte[] buffer = new byte[length];
+ int lengthAssert = stream.read(buffer, begin, length);
+ assert lengthAssert == length;
+ return buffer;
+ }
+}
diff --git a/src/main/java/com/microsoft/graph/core/tasks/PageIterator.java b/src/main/java/com/microsoft/graph/core/tasks/PageIterator.java
new file mode 100644
index 000000000..f64df44ca
--- /dev/null
+++ b/src/main/java/com/microsoft/graph/core/tasks/PageIterator.java
@@ -0,0 +1,338 @@
+package com.microsoft.graph.core.tasks;
+
+import com.microsoft.graph.core.CoreConstants;
+import com.microsoft.graph.core.requests.IBaseClient;
+import com.microsoft.kiota.*;
+import com.microsoft.kiota.serialization.AdditionalDataHolder;
+import com.microsoft.kiota.serialization.Parsable;
+import com.microsoft.kiota.serialization.ParsableFactory;
+
+import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+/**
+ * A class for iterating through pages of a collection
+ * Uses to automatically pages through result sets across multiple calls and process each item in the result set.
+ * @param The type of the entity returned in the collection. This type must implement {@link Parsable}
+ * @param The Microsoft Graph collection response type returned in the collection response. This type must implement {@link Parsable} and {@link AdditionalDataHolder}
+ */
+public class PageIterator {
+ /**
+ * Creates a new instance of the PageIterator class
+ */
+ protected PageIterator() {
+ // default constructor
+ }
+ private static final String NO_COLLECTION_PROPERTY_ERROR = "The Parsable does not contain a collection property.";
+ private RequestAdapter requestAdapter;
+ private TCollectionPage currentPage;
+ private ParsableFactory collectionPageFactory;
+ private Queue pageItemQueue;
+ private Function processPageItemCallback;
+ private UnaryOperator requestConfigurator;
+
+
+ private String deltaLink;
+
+ /**
+ * The deltaLink returned from a delta query.
+ * @return the deltaLink from the delta query
+ */
+ @Nullable
+ public String getDeltaLink() {
+ return deltaLink;
+ }
+ private String nextLink;
+ /**
+ * The nextLink returned from a collection query.
+ * @return the nextLink from the collection query
+ */
+ @Nullable
+ public String getNextLink() {
+ return nextLink;
+ }
+ private PageIteratorState state = PageIteratorState.NOT_STARTED;
+ /**
+ * The state of the page iterator
+ * @return the state of the page iterator
+ */
+ @Nonnull
+ public PageIteratorState getPageIteratorState() {
+ return state;
+ }
+ /**
+ * Sets the request adapter to use for requests in the page iterator.
+ * @param requestAdapter the request adapter to use for requests.
+ */
+ protected void setRequestAdapter(@Nonnull RequestAdapter requestAdapter) {
+ this.requestAdapter = Objects.requireNonNull(requestAdapter);
+ }
+ /**
+ * The factory to use for creating the collection page instance.
+ * @param collectionPageFactory the factory to use for creating the collection page.
+ */
+ protected void setCollectionPageFactory(@Nonnull ParsableFactory collectionPageFactory) {
+ this.collectionPageFactory = Objects.requireNonNull(collectionPageFactory);
+ }
+ /**
+ * The request configurator to use for requests in the page iterator.
+ * @param requestConfigurator the request configurator to use when modifying requests.
+ */
+ protected void setRequestConfigurator(@Nullable UnaryOperator requestConfigurator) {
+ this.requestConfigurator = requestConfigurator;
+ }
+ /**
+ * The current page of the collection.
+ * @param currentPage the current page of the collection.
+ */
+ protected void setCurrentPage(@Nonnull TCollectionPage currentPage) {
+ this.currentPage = Objects.requireNonNull(currentPage);
+ }
+ /**
+ * The processPageItemCallback to use for processing each item in the collection.
+ * @param processPageItemCallback the processPageItemCallback to use for processing each item in the collection.
+ */
+ protected void setProcessPageItemCallback(@Nonnull Function processPageItemCallback) {
+ this.processPageItemCallback = Objects.requireNonNull(processPageItemCallback);
+ }
+ /**
+ * The queue of items in the current page.
+ * @param pageItemQueue the queue of items in the current page.
+ */
+ protected void setPageItemQueue(@Nonnull Queue pageItemQueue) {
+ this.pageItemQueue = Objects.requireNonNull(pageItemQueue);
+ }
+ /**
+ * A builder class for building a PageIterator.
+ * @param The type of the entity returned in the collection. This type must implement {@link Parsable}
+ * @param The Microsoft Graph collection response type returned in the collection response. This type must implement {@link Parsable} and {@link AdditionalDataHolder}
+ */
+ public static class Builder implements PageIteratorBuilder{
+ /**
+ * Constructor for the Builder class of a PageIterator.
+ */
+ public Builder() {
+ // Default constructor
+ }
+ private RequestAdapter requestAdapter;
+ private TCollectionPage currentPage;
+ private ParsableFactory collectionPageFactory;
+ private UnaryOperator requestConfigurator;
+ private Function processPageItemCallback;
+ private RequestAdapter getRequestAdapter() {
+ return this.requestAdapter;
+ }
+ private TCollectionPage getCollectionPage() {
+ return this.currentPage;
+ }
+ private ParsableFactory getCollectionPageFactory() {
+ return this.collectionPageFactory;
+ }
+
+ private UnaryOperator getRequestConfigurator() {
+ return this.requestConfigurator;
+ }
+ private Function getProcessPageItemCallback() {
+ return this.processPageItemCallback;
+ }
+
+ @Override
+ @Nonnull
+ public Builder client(@Nonnull IBaseClient client) {
+ Objects.requireNonNull(client);
+ return this.requestAdapter(client.getRequestAdapter());
+ }
+ @Override
+ @Nonnull
+ public Builder requestAdapter(@Nonnull RequestAdapter requestAdapter) {
+ this.requestAdapter = Objects.requireNonNull(requestAdapter);
+ return this;
+ }
+ @Override
+ @Nonnull
+ public Builder collectionPage(@Nonnull TCollectionPage collectionPage) {
+ this.currentPage = Objects.requireNonNull(collectionPage);
+ return this;
+ }
+ @Override
+ @Nonnull
+ public Builder collectionPageFactory(@Nonnull ParsableFactory collectionPageFactory) {
+ this.collectionPageFactory = Objects.requireNonNull(collectionPageFactory);
+ return this;
+ }
+ @Override
+ @Nonnull
+ public Builder requestConfigurator(@Nonnull UnaryOperator requestConfigurator) {
+ this.requestConfigurator = Objects.requireNonNull(requestConfigurator);
+ return this;
+ }
+ /**
+ * Sets the callback to be called for each item in the collection.
+ * @param processPageItemCallback the callback to be called for each item in the collection.
+ * @return the builder object itself
+ */
+ @Nonnull
+ public Builder processPageItemCallback(@Nonnull Function