A Java SDK to access OneDrive drives and files.
Maven Project Info
-
Javadoc
Report Bug
-
Request Feature
Table of Contents
A configurable and extensible SDK for Java programmatic access to a user's OneDrive account via the Microsoft Graph API. This SDK is still in active development, but most documented APIs are implemented.
- OAuth user authentication out-of-the-box for use by client-side desktop applications
- Or you can roll your own OAuth solution to obtain the auth code and persist tokens for server-to-server use-cases
- Automatic credential token refresh support
- Synchronous and asynchronous file transfer operations with a customizable transfer progress callback interface for extensibility
- Business account support to access group resources as well as SharePoint document libraries
- Note: This is currently untested with a real business account. Please file a bug report if any issues are encountered.
- Upload sessions for uploading larges files in segments
- Remote uploads from URL (in preview)
- Obtaining content for a Thumbnail
Per the App Registration documentation, your application needs to be registered via the Azure Apps Registration Page.
Key configuration to note:
- The following delegated API permissions are recommended:
Files.ReadWrite.All
User.Read
offline_access
- The following delegated API permission are recommended for business accounts in order to access SharePoint sites:
Sites.ReadWrite.All
Sites.Manage.All
Sites.FullControl.All
- The following delegated API permission are recommended for business accounts in order to access SharePoint sites:
- If using the default OAuth receiver to handle the redirect for auth code grants, then set the redirect URL to
http://localhost:8890/Callback
- Generate your own client secret, and record your application's client ID and client secret value.
-
You can save this as a JAR bundled resource within your project named
/ms-onedrive-credentials.json
and should be formatted as:{ "clientId" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "clientSecret" : "xxxxxxxxxxxxxxxxxxxxxxxxxxx" }
-
The primary classes used to interact with a OneDrive account is modeled as a tree structure and is as follows:
- OneDrive (javadoc) to obtain user accessible drives
- BusinessOneDrive (javadoc) to obtain business-related user accessible drives and sites
- Drive (javadoc) to access folders
- DriveFolder (javadoc) to manage folders, access subfolders, and upload new files
- DrivePackage (javadoc) to manage folders, access subfolders, and upload new files for packages (OneNote)
- DriveFile (javadoc) to manage, upload (as a new version), and download a file
// Used to initiate the OAuth flow, persist refreshed tokens, or use persisted refresh tokens.
OneDriveFactoryStateManager factoryStateManager = OneDriveFactoryStateManager.builder()
.stateFile(Paths.get("./OneDriveUserState.json")) // Path to save/read user auth tokens
.build();
try {
OneDrive oneDrive = factoryStateManager.getInstance();
// Access drives, folders, and files
} finally {
// Updates persisted auth tokens if refreshed during usage
factoryStateManager.saveState();
}
For more information, please refer to javadoc or source.
AuthInfoStore example
The AuthInfoStore interface provides the ability to implement custom logic to manage user auth token state persistence (e.g., database, remote service, etc.). The default implementation is SingleUserFileBasedAuthInfoStore that saves the auth state to the file system. It also serves as an example on how to implement your own AuthInfoStore implementation.
public class MyAuthInfoStore implements AuthInfoStore {
private DependentDestinationStore myStore;
@Override
public void store(String id, AuthInfo authInfo) throws IOException {
myStore.save(id, authInfo);
}
@Override
public AuthInfo retrieve(String id) throws IOException {
myStore.get(id);
}
}
OneDriveFactoryStateManager factoryStateManager = OneDriveFactoryStateManager.builder()
.authInfoStore(new MyAuthInfoStore()))
.build();
try {
OneDrive oneDrive = factoryStateManager.getInstance();
// Access drives, folders, and files
} finally {
// Updates persisted auth tokens if refreshed during usage to your custom store
factoryStateManager.saveState();
}
SingleUserEncryptedFileBasedAuthInfoStore example
This SDK also provides a SingleUserEncryptedFileBasedAuthInfoStore implementation that encrypts and saves the auth state to the file system. A specified keystore file path along with associated passwords must be specified. If the key store file does not exist, a new one will be created along with a newly generated crypto key that is used to encrypt and decrypt the AuthInfo.
Path myOneDriveUserState = Paths.get("./MyOneDriveUserState.json")
Path myKeyStorePath = Paths.get("./MyKeyStoreFile");
char[] myKeyStorePassword = System.getProperty("MyKeyStorePassword").toCharArray();
char[] myAuthStateCryptoKeyPassword = System.getProperty("MyCryptoKeyPassword").toCharArray();
// Helper to manage storage of the crypto key
KeyStoreHelper keyStoreHelper = new KeyStoreHelper(myKeyStorePath, myKeyStorePassword);
// Helper to encrypt/decrypt AuthInfo contents
CryptoHelper cryptoHelper =
new CryptoHelperFactory(keyStoreHelper, myAuthStateCryptoKeyPassword).newInstance();
// The AuthInfoStore implementation that encrypts + saves and reads + decrypts
// from the filesystem.
SingleUserEncryptedFileBasedAuthInfoStore authInfoStore =
new SingleUserEncryptedFileBasedAuthInfoStore(myOneDriveUserState, cryptoHelper);
OneDriveFactoryStateManager factoryStateManager = OneDriveFactoryStateManager.builder()
.authInfoStore(authInfoStore)
.build();
OkHttpClientBuilder example
If your use-case requires configuring the underlying OkHttpClient
instance (e.g., configuring your own
SSL cert verification, proxy, and/or connection timeouts), you can configure the client with the provided
OkHttpClientBuilder,
or alternatively with OkHttp's builder.
OkHttpClient httpClient = OkHttpClientBuilder.builder()
// Custom trust manager for self/internally signed SSL/TLS certs
.trustManager(myX509TrustManager)
// Custom hostname verification for SSL/TLS endpoints
.hostnameVerifier(myHostnameVerifier)
.proxy(myProxy, myProxyUsername, myProxyPassword) // Proxy config
.connectTimeout(8000L) // connection timeout in milliseconds
.readTimeout(5000L) // read timeout in milliseconds
.writeTimeout(5000L) // write timeout in milliseconds
.build();
OneDriveFactoryStateManager factoryStateManager = OneDriveFactoryStateManager.builder()
.httpClient(httpClient)
.stateFile(Paths.get("./OneDriveUserState.json")) // Path to save/read user auth tokens
.build();
try {
OneDrive oneDrive = factoryStateManager.getInstance();
// Access drives, folders, and files
} finally {
// Updates persisted auth tokens if refreshed during usage
factoryStateManager.saveState();
}
Custom OAuth flow
Once you obtain the authCode
, you can initialize a new OneDrive
directly via:
OneDrive oneDrive = new OneDrive(OneDriveConnectionBuilder.newInstance()
.clientId(clientId) // Your application's client identifier
.clientSecret(clientSecret) // Your application's client secret
.redirectUrl(redirectUrl) // Your custom redirect URL that was used to obtain the authCode
.build(authCode));
While token refresh is automated during the runtime lifecycle of the OneDrive
object, persisting
the user AuthInfo
is required for subsequent initialization(s) to prevent the user from granting
authorization each time an instance is created until the user explicitly revokes the grant or when it expires. Example of subsequent initialization with AuthInfo
AuthInfo authInfo = getAuthInfo(); // Obtain the persisted AuthInfo from your application
OneDrive oneDrive = new OneDrive(OneDriveConnectionBuilder.newInstance()
.clientId(clientId) // Your application's client identifier
.clientSecret(clientSecret) // Your application's client secret
// Your custom redirect URL that was used to obtain the authCode
.redirectUrl(redirectUrl)
.build(authInfo));
authInfo = oneDrive.getAuthInfo(); // Gets the updated tokens after refresh
BusinessOneDrive initialization
OkHttpClient httpClient = new OkHttpClientBuilder().build();
BusinessAccountAuthManager authManager = BusinessAccountAuthManager.builderWithAuthCode()
.authCode(myAuthCode) // Auth code from your OAuth handshake
.clientId(myClientId) // Your application's client identifier
.clientSecret(myClientSecret) // Your application's client secret
.httpClient(httpClient)
.redirectUrl(myRedirectUrl) // The redirect URL associated with your OAuth flow
.buildWithAuthCode();
// Discover and authenticate with a registered service
List<Service> services = authManager.getServices();
authManager.authenticateService(services.get(0));
// Create a new BusinessOneDrive instance
BusinessOneDrive oneDrive = new BusinessOneDrive(
OneDriveConnectionBuilder.newInstance()
.httpClient(httpClient)
.authManager(authManager)
.build(authManager.getAuthInfo()));
// Access business related resources
Site rootSite = oneDrive.getRootSite();
DriveFolder rootFolder = oneDrive.getUserDrive().getRootFolder();
// All children containing either DriveFile or DriveFolder types
List<? extends DriveItemType> allContents = rootFolder.getChildren();
// All child folders with the root folder as parent
List<DriveFolder> driveFolders = rootFolder.getChildFolders();
// All child files with the root folder as parent
List<DriveFile> driveFiles = rootFolder.getChildFiles()
DriveFolder documentsFolder = documentsFolder = root.search("Documents").stream()
.filter(DriveItemType::isFolder)
.findFirst()
.map(DriveFolder.class::cast)
.orElseThrow(() -> new IllegalStateException("Documents not found"));
DriveFile myDrivefile = documentsFolder.upload(new File("./MyFile.zip"));
DriveFileUploadExecution uploadedExec = documentsFolder.uploadAsync(new File("./MyFile.zip"));
// Block on upload completion
DriveFile myDrivefile = uploadedExec.get();
DriveFile myDriveFile = root.search("MyFile.zip").stream()
.filter(DriveItemType::isFile)
.findFirst()
.map(DriveFile.class::cast)
.orElseThrow(() -> new IllegalStateException("MyFile.zip not found"));
myDriveFile.download(Path.of("./"));
DriveFileDownloadExecution downloadExec = myDriveFile.downloadAsync(Paths.get("./"));
// Block on download completion
long downloadedBytes = downloadExec.get();
The TransferProgressCallback interface provides the ability to implement custom logic on update, completion, or failure scenarios (e.g., GUI updates) during file transfers. The default implementation is LogProgressCallback that logs transfer updates to the configured log via SLF4J. It also serves as an example on how to implement your own TransferProgressCallback implementation.
public class MyProgressCallback implements TransferProgressCallback {
@Override
public void onUpdate(long currentBytes, long totalBytes) { ... }
@Override
public void onFailure(Throwable cause) { ... }
@Override
public void onComplete(long bytesTransferred) { ... }
}
// Upload
DriveFile myDrivefile = myFolder.upload(new File("./MyFile.zip"), new MyProgressCallback());
DriveFileUploadExecution uploadedExec =
myFolder.uploadAsync(new File("./MyFile.zip"), new MyProgressCallback());
// Download
myFile.download(Path.of("./"), new MyProgressCallback());
DriveFileDownloadExecution downloadExec =
myFile.downloadAsync(Paths.get("./"), new MyProgressCallback());
-
Add functional test coverage (use of a MockWebServer) - Add integration test coverage
-
Group and Site based access for non-personal accounts -
Add an interface to access and persist tokens for the OneDriveFactoryStateManager (e.g., tokens stored via a database or service)(v0.1.1) -
Obtaining embeddable file previews(v0.1.2) - Remote uploads from URL (in preview)
- Obtaining content for a Thumbnail
- Add configuration of a retry policy + strategy to support automatic retries for retriable errors
See the open issues for a full list of proposed features and known issues.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the GPLv3 license. See LICENSE for more information.
Andy Miles - andy.miles (at) amilesend.com
Project Link: https://github.com/andy-miles/onedrive-java-sdk