-
Notifications
You must be signed in to change notification settings - Fork 77
Phase I: Bulk Operation Support #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| /* | ||
| * Copyright 2026 Ping Identity Corporation | ||
| * | ||
| * 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 | ||
| * | ||
| * http://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. | ||
| */ | ||
| /* | ||
| * Copyright 2026 Ping Identity Corporation | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License (GPLv2 only) | ||
| * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this program; if not, see <http://www.gnu.org/licenses>. | ||
| */ | ||
|
|
||
| package com.unboundid.scim2.client.requests; | ||
|
|
||
| import com.unboundid.scim2.common.annotations.NotNull; | ||
| import com.unboundid.scim2.common.annotations.Nullable; | ||
| import com.unboundid.scim2.common.exceptions.ScimException; | ||
| import com.unboundid.scim2.common.bulk.BulkOperation; | ||
| import com.unboundid.scim2.common.bulk.BulkRequest; | ||
| import com.unboundid.scim2.common.bulk.BulkResponse; | ||
| import jakarta.ws.rs.HttpMethod; | ||
| import jakarta.ws.rs.client.Entity; | ||
| import jakarta.ws.rs.client.WebTarget; | ||
| import jakarta.ws.rs.core.Response; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| import static jakarta.ws.rs.core.Response.Status.Family.SUCCESSFUL; | ||
|
|
||
|
|
||
| /** | ||
| * This class provides a builder for SCIM 2 bulk requests. Bulk requests provide | ||
| * a way for clients to send multiple write operations in a single API call. | ||
| * <br><br> | ||
| * | ||
| * For more information, see the documentation in {@link BulkRequest}. | ||
| */ | ||
| public class BulkRequestBuilder | ||
| extends ResourceReturningRequestBuilder<BulkRequestBuilder> | ||
| { | ||
| @NotNull | ||
| private final List<BulkOperation> operations = new ArrayList<>(); | ||
|
|
||
| /** | ||
| * Create a new bulk request builder that will be used to apply a list of | ||
| * write operations to the given web target. | ||
| * | ||
| * @param target The WebTarget that will receive the bulk request. | ||
| */ | ||
| public BulkRequestBuilder(@NotNull final WebTarget target) | ||
| { | ||
| super(target); | ||
| } | ||
|
|
||
| /** | ||
| * Append a list of bulk operations to this bulk request. Any {@code null} | ||
| * values will be ignored. | ||
| * | ||
| * @param ops The list of bulk operations to add. | ||
| * | ||
| * @return This bulk request builder. | ||
| */ | ||
| @NotNull | ||
| public BulkRequestBuilder append(@Nullable final List<BulkOperation> ops) | ||
| { | ||
| List<BulkOperation> operationList = (ops == null) ? List.of() : ops; | ||
|
|
||
| // Null fields are handled when the bulk request is constructed. | ||
| operations.addAll(operationList); | ||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Append one or more bulk operations to this bulk request. Any {@code null} | ||
| * values will be ignored. | ||
| * | ||
| * @param operations The bulk operation(s) to add. | ||
| * | ||
| * @return This bulk request builder. | ||
| */ | ||
| @NotNull | ||
| public BulkRequestBuilder append(@Nullable final BulkOperation... operations) | ||
| { | ||
| if (operations != null) | ||
| { | ||
| append(Arrays.asList(operations)); | ||
| } | ||
|
|
||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Invoke the SCIM bulk request and return the response. | ||
| * | ||
| * @return The bulk response representing the summary of the write requests | ||
| * that were attempted and whether they were successful. | ||
| * @throws ScimException If the SCIM service responded with an error. | ||
| */ | ||
| @NotNull | ||
| public BulkResponse invoke() throws ScimException | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The layout of this class largely follows the other builders. However, the invoke() method is somewhat unique because any SCIM resources will be included within the BulkResponse, so the returned object is never typed. This is why we'll need to have the mapper class in Phase 2. |
||
| { | ||
| return invoke(BulkResponse.class); | ||
| } | ||
|
|
||
| /** | ||
| * Invoke the SCIM bulk request. | ||
| * | ||
| * @param <C> The Java type to return. This should be a {@link BulkResponse}. | ||
| * @param cls The Java type to return. This should be a {@link BulkResponse}. | ||
| * | ||
| * @return The bulk response. | ||
| * @throws ScimException If the SCIM service responded with an error, such | ||
| * as if the JSON body was too large. | ||
| */ | ||
| @NotNull | ||
| protected <C> C invoke(@NotNull final Class<C> cls) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you wanted this
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I set this as protected because there's virtually no reason I can think of that a caller would want anything other than a BulkResponse object returned. However, if they really need it, they could extend this class and achieve that result this way. Making it |
||
| throws ScimException | ||
| { | ||
| BulkRequest request = new BulkRequest(operations); | ||
| var entity = Entity.entity(generify(request), getContentType()); | ||
|
|
||
| try (Response response = buildRequest().method(HttpMethod.POST, entity)) | ||
| { | ||
| if (response.getStatusInfo().getFamily() == SUCCESSFUL) | ||
| { | ||
| return response.readEntity(cls); | ||
| } | ||
| else | ||
| { | ||
| throw toScimException(response); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| * Copyright 2026 Ping Identity Corporation | ||
| * | ||
| * 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 | ||
| * | ||
| * http://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. | ||
| */ | ||
| /* | ||
| * Copyright 2026 Ping Identity Corporation | ||
| * | ||
| * This program is free software; you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License (GPLv2 only) | ||
| * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) | ||
| * as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this program; if not, see <http://www.gnu.org/licenses>. | ||
| */ | ||
|
|
||
| package com.unboundid.scim2.common.bulk; | ||
|
|
||
| import com.unboundid.scim2.common.annotations.NotNull; | ||
|
|
||
|
|
||
| /** | ||
| * An enum representing possible bulk operation types. | ||
| */ | ||
| public enum BulkOpType | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this phase 2? It does not seem to be used, at least internally. If you just want the constants there is Jakarta, but I understand that enums are helpful, and indicate a specific set of allowed value. In any case, if we need this it seems it could be simplified, pretty much: public enum BulkOpType {
POST, PUT, PATCH, DELETE
}But I'm probably missing something.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great question, yes, this is needed for Phase 2. Also, it's worth noting that the majority of these changes are placed in scim2-sdk-common since entities like bulk operations are model objects. The only dependency that common has is Jackson, so Jakarta utilities are not available to us in the common module anyway. |
||
| { | ||
| /** | ||
| * The "POST" bulk operation type used to create a resource. | ||
| */ | ||
| POST("POST"), | ||
|
|
||
| /** | ||
| * The "PUT" bulk operation type used to overwrite a resource. | ||
| */ | ||
| PUT("PUT"), | ||
|
|
||
| /** | ||
| * The "PATCH" bulk operation type used to update part of a resource. | ||
| */ | ||
| PATCH("PATCH"), | ||
|
|
||
| /** | ||
| * The "DELETE" bulk operation type used to delete a resource. | ||
| */ | ||
| DELETE("DELETE"), | ||
|
|
||
| // GET is not available, since bulk operations are for writes. | ||
| ; | ||
|
|
||
| @NotNull | ||
| private final String stringValue; | ||
|
|
||
| BulkOpType(@NotNull final String stringValue) | ||
| { | ||
| this.stringValue = stringValue; | ||
| } | ||
|
|
||
| @Override | ||
| @NotNull | ||
| public String toString() | ||
| { | ||
| return stringValue; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other builders have
addOperation. WouldaddOperationsbe a good name for this method?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered this, but the term "operation" felt like it was getting overloaded between "patch operation" and "bulk operation". This will become more noticeable in Phase 2, where there is a bulk operation type for patch requests, so the nomenclature has the potential to become confusing. So I decided to name this as "append" just to avoid confusion. What do you think?