-
Notifications
You must be signed in to change notification settings - Fork 1
Document Transfer Message Processing
In the Document Transfer scenario, Vault Spark allows developers to use the Vault Java SDK to send and receive messages from one vault (the source) to another (the target), whilst transferring a document, and it's source file, renditions, attachments and versions.
Note: Whilst this example copies documents between Vaults, it is also possible to copy documents within the same Vault, using a Connection that points back to the same Vault.
This page covers how to receive the messages in the target vault and process then using SDK Document Transfer support.
The Vault Java SDK QueueService
, RecordService
, HttpService
, 'DocumentServiceand
QueryService` interfaces are used to implement this functionality.
For full details on the interfaces and methods used, please review the Javadocs.
Details of how to create the Spark Messages in the source vault are covered in the page Document Transfer Source Messages.
Once the vSDKDocCopyDocumentAction action adds a Message
to the outbound queue, Spark sends the Message
to the target vault's inbound queue where it is processed by a MessageProcessor
Vault Java SDK class.
The MessageProcessor
then processes the messages by retrieving the Document details, making an HttpService
callouts to the source vault to query for more information and then creating a document in the target vault.
In this example, vSDKDocCopyMessageProcessor contains the processCopyDocuments
method to process the inbound queue messages.
- There are 3 classes, the processor class and two User Defined Classes (UDC):
- The vSDKDocCopyMessageProcessor - processes
Message
records received in the inbound queue -vsdk_doc_copy_in_queue__c
. - The vSDKSparkHelper provides helper methods to process objects from the Integration Transaction object on the Source Vault.
- The vSDKDocCopy process the document transfer.
- The vSDKDocCopyMessageProcessor - processes
- As a
Message
comes in, if an existing Document exists in the target vault it will be updated, otherwise a new record will be created.- Run a
QueryService
query to check for unprocessed records in the Integration Transaction object on the Source Vault. - Use the
DocumentService
to get and copy the document(s) from the- Create a map of incoming messages
- Check to make sure none of the document(s) already exist in the Target Vault
- The source document IDs are added to the query
- Use the
HttpService
to get the document details (e.g. DocFields) - Use the
DocumentService
to copy the document from the source vault to the target vault-
DocumentSourceFileReference
used to establish a connection to the source vaults file and version files to be copied -
DocumentRenditionFileReference
used to establish a connection to the source vaults viewable renditions to be copied -
DocumentService.createDocuments
to copy the document including the source and renditions -
DocumentService.migrateDocumentVersions
to copy the document versions -
DocumentService.createAttachments
used to copy any document attachments
-
- Run a
The messages received from the queue have to be identified and processed according to custom logic. In this sample project, we only want to process messages that are not empty and have an document type
of vSDK Spark Copy Document.
If the document has the vSDK Spark Copy Document document type on the source vault the Approve Document user action will be available. If the Approve Document user action is used the message is pushed to the target vault inbound queue and the processCopyDocuments
method that processes the document and performs custom logic that is specific to a new vsdk_doc_copy_in_queue__c
message.
@MessageProcessorInfo()
public class vSDKDocCopyMessageProcessor implements MessageProcessor {
/**
* Main Spark v2v MessaageProcessor. It determines the Integration Point
* related to the message and call the appropriate Processing code
* to copy documents between two Vaults
*/
Public void execute(MessageContext context) {
//Processes a message from the queue which aren't blank
Message incomingMessage = context.getMessage();
// Here we want to process messages specific to the different integration
// points. These message attributes are set in the document action
// "vSdkDocCopyDocumentAction" in the source Vault
String integrationPointApiName =
incomingMessage.getAttribute("integration_point",
MessageAttributeValueType.STRING);
switch(integrationPointApiName) {
case "receive_copy_document__c":
// Here we want to process the messages associated with the inbound
// Integration Point "Receive Copy Document". This is done in the method
// "processCopyDocuments"
processCopyDocuments(incomingMessage, context);
break;
// Add further case statements here if you wish to handle further
// integration points
}
}
Once the code has entered into the processCopyDocuments
method, the message items are parsed through and then the source document IDs are used to find existing Documents in the target vault.
The code uses the vSDKSparkHelper.getUnprocessedObjects()
method to get all unprocessed items from the Source Vault Integration Transaction object using a query against the records in that object. The query uses the Status field in the Integration Transaction records to get all pending_c
records.
- If records are found, add them to a
List<String> copyDocsList
that is used to update the target.
public static void processCopyDocuments(Message message,
MessageContext context) {
LogService logService = ServiceLocator.locate(LogService.class);
List<String> copyDocsList = VaultCollections.newList();
String sourceVaultId = context.getRemoteVaultId();
String connectionId = context.getConnectionId();
String integrationPointApiName =
message.getAttribute("integration_point", MessageAttributeValueType.STRING);
StringBuilder logMessage = new StringBuilder();
logMessage.append("Processing integrationPointApiName: ");
logMessage.append(integrationPointApiName);
logService.info(logMessage.toString());
String connectionName = "vsdk_doc_copy_connection";
// Check for documents which haven't been copied
// This uses a callback to the source vault for the document
// then add them to the incoming message list for processing
List<String> unprocessedDocIdsList = vSDKSparkHelper.getUnprocessedObjects(
connectionName,
"documents",
integrationPointApiName,
true);
copyDocsList.addAll(unprocessedDocIdsList);
// Copy the documents from the Source Vault
vSDKDocCopy.process(connectionName,
integrationPointApiName,
unprocessedDocIdsList,
true,
true,
true);
}
...
}
The vSDKSparkHelper.getUnprocessedObjects()
method returns a list of objects which haven't been migrated to the target vault yet. This uses a callback to the source vault to check for records in the integration_transaction__c object for the object/integration point, which have a processed status of pending and a last modified date greater than 10 seconds before. This wait is to allow for the job already being processed on a separate thread.
StringBuilder logMessage = new StringBuilder();
logMessage.append("Unprocessed Callback query: ").append(query.toString());
logService.info(logMessage.toString());
//This is a vault to vault Http Request to the source connection
//The configured connection provides the full DNS name.
//For the path, you only need to append the API endpoint after the DNS.
//The query endpoint takes a POST where the BODY is the query itself.
HttpService httpService = ServiceLocator.locate(HttpService.class);
FormHttpRequest request = httpService.newHttpRequestBuilder()
.withConnectionName(connectionName)
.withMethod(HttpMethod.POST)
.withPath("/api/v24.2/query")
.withHeader("Content-Type", "application/x-www-form-urlencoded")
.withBodyParam("q", query.toString())
.build();
//Send the request to the source vault via a callback. The response received back should be a JSON response.
//First, the response is parsed into a `JsonData` object
//From the response, the `getJsonObject()` will get the response as a parseable `JsonObject`
// * Here the `getValue` method can be used to retrieve `responseStatus`, `responseDetails`, and `data`
//The `data` element is an array of JSON data. This is parsed into a `JsonArray` object.
// * Each queried record is returned as an element of the array and must be parsed into a `JsonObject`.
// * Individual fields can then be retrieved from each `JsonObject` that is in the `JsonArray`.
httpService.sendRequest(request, HttpResponseBodyValueType.JSONDATA)
.onSuccess(httpResponse -> {
JsonData response = httpResponse.getResponseBody();
if (response.isValidJson()) {
String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
if (responseStatus.equals("SUCCESS")) {
JsonArray data = response.getJsonObject().getValue("data", JsonValueType.ARRAY);
logService.info("HTTP Query Request: SUCCESS");
//Retrieve each record returned from the VQL query.
//Each element of the returned `data` JsonArray is a record with it's queried fields.
for (int i = 0; i < data.getSize();i++) {
JsonObject queryRecord = data.getValue(i, JsonValueType.OBJECT);
String sourceId = queryRecord.getValue("source_key__c", JsonValueType.STRING);
unprocessedObjectsList.add(sourceId);
}
data = null;
}
response = null;
} else {
logService.info("getUnprocessedObjects error: Received a non-JSON response.");
}
})
.onError(httpOperationError -> {
logService.info("getUnprocessedObjects error: httpOperationError.");
}).execute();
request = null;
return unprocessedObjectsList;
}
The callback to the source vault queries the Integration Transaction
object to see what items are 'Pending' processing on the target vault. The query is built to get all pending document approval transactions for the sample integration point on the target system. That means, that only documents that are approved using the Approve Document
user action on the vSDK Document
document type.
public static List<String> getUnprocessedObjects(String connectionName, // e.g. vsdk_connection_to_warranties
String objectName, // e.g. vsdk_warranty__c
String targetIntegrationPoint, // e.g. send_to_claims_pending__c
Boolean runImmediately) {
String reprocessBeforeDate = java.time.Clock.systemUTC().instant().minusSeconds(10).toString();
LogService logService = ServiceLocator.locate(LogService.class);
List<String> unprocessedObjectsList = VaultCollections.newList();
StringBuilder query = new StringBuilder();
query.append("SELECT source_key__c ");
query.append("FROM integration_transaction__c ");
query.append("WHERE transaction_status__c = 'pending__c' ");
query.append("AND source_object__c = '").append(objectName).append("' ");
query.append("AND target_integration_point__c = '").append(targetIntegrationPoint).append("' ");
if (!runImmediately) {
query.append("AND modified_date__v < '").append(reprocessBeforeDate).append("' ");
}
...
Once the query is established the HTTP callout is defined to send the query to the \query
API endpoint. The query result is put into the List<String> unprocessedObjectsList
list and returned to the vSDKDocCopyMessageProcessor.processCopyDocuments()
method which then calls the vSDKDocCopy.process()
method to finalize and copy the document(s) from the source vault.
...
//This is a vault to vault Http Request to the source connection
//The configured connection provides the full DNS name.
//For the path, you only need to append the API endpoint after the DNS.
//The query endpoint takes a POST where the BODY is the query itself.
HttpService httpService = ServiceLocator.locate(HttpService.class);
FormHttpRequest request = httpService.newHttpRequestBuilder()
.withConnectionName(connectionName)
.withMethod(HttpMethod.POST)
.withPath("/api/v24.2/query")
.withHeader("Content-Type", "application/x-www-form-urlencoded")
.withBodyParam("q", query.toString())
.build();
//Send the request to the source vault via a callback. The response received back should be a JSON response.
//First, the response is parsed into a `JsonData` object
//From the response, the `getJsonObject()` will get the response as a parseable `JsonObject`
// * Here the `getValue` method can be used to retrieve `responseStatus`, `responseDetails`, and `data`
//The `data` element is an array of JSON data. This is parsed into a `JsonArray` object.
// * Each queried record is returned as an element of the array and must be parsed into a `JsonObject`.
// * Individual fields can then be retrieved from each `JsonObject` that is in the `JsonArray`.
httpService.sendRequest(request, HttpResponseBodyValueType.JSONDATA)
.onSuccess(httpResponse -> {
JsonData response = httpResponse.getResponseBody();
if (response.isValidJson()) {
String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
if (responseStatus.equals("SUCCESS")) {
JsonArray data = response.getJsonObject().getValue("data", JsonValueType.ARRAY);
logService.info("HTTP Query Request: SUCCESS");
//Retrieve each record returned from the VQL query.
//Each element of the returned `data` JsonArray is a record with it's queried fields.
for (int i = 0; i < data.getSize();i++) {
JsonObject queryRecord = data.getValue(i, JsonValueType.OBJECT);
String sourceId = queryRecord.getValue("source_key__c", JsonValueType.STRING);
unprocessedObjectsList.add(sourceId);
}
data = null;
}
response = null;
} else {
logService.info("getUnprocessedObjects error: Received a non-JSON response.");
}
}).onError(httpOperationError -> {
logService.info("getUnprocessedObjects error: httpOperationError.");
}).execute();
request = null;
return unprocessedObjectsList;
...
The vSDKDocCopy.process()
method is used to copy documents and document metadata from the source vault and handle errors. It uses a query and HTTP callout to get the relevant information from the source vault.
We establish a successful and failed list to house the successfully copied or failed to copy documents so the status on the source vault can be established later for later retry if necessary.
public static void process(String connectionName,
String integrationPointApiName,
List<String> docGlobalIds,
Boolean includeVersions,
Boolean includeViewableRendition,
Boolean includeAttachments) {
ConnectionService connectionService = ServiceLocator.locate(ConnectionService.class);
ConnectionContext connectionContext = connectionService.newConnectionContext(connectionName,
ConnectionUser.CONNECTION_AUTHORIZED_USER); // Use Connection API name and user
DocumentService documentService = ServiceLocator.locate(DocumentService.class);
LogService logService = ServiceLocator.locate(LogService.class);
List<String> successfulIdList = VaultCollections.newList();
List<String> failedIdList = VaultCollections.newList();
...
The query is built against the document
object on the source vault. It grabs the relevant document fields that need to be copied to the target system. It also uses the ALLVERSIONS
operator in the FROM
clause when versions of the document are to be included. It appends in an IN
statement each of the document IDs established in from the Integration Transaction
source vault query. The records are also sorted to ensure they come back in the correct order with the latest version being last, as this will be needed later to know when to save all the version records for the document.
...
String queryObject = "documents";
StringBuilder query = new StringBuilder();
query.append("SELECT id, global_id__sys, global_version_id__sys, latest_version__v,");
query.append(" version_id, lifecycle__v, status__v, type__v, name__v ");
if (includeVersions) {
query.append("FROM ALLVERSIONS ").append(queryObject).append(" ");
} else {
query.append("FROM ").append(queryObject).append(" ");
}
query.append("WHERE global_id__sys CONTAINS ('" + String.join("','", docGlobalIds) + "')");
query.append("ORDER BY global_version_id__sys ASC");
...
Once the query is established the HTTP callout is defined to send the query to the \query
API endpoint. The query results are written to local variables and the version information is split into 2 local variables housing the major and minor versions of the document. Those split values are later used when creating the document on the target vault.
...
//This is a vault to vault Http Request to the source connection
//The configured connection provides the full DNS name.
//For the path, you only need to append the API endpoint after the DNS.
//The query endpoint takes a POST where the BODY is the query itself.
HttpService httpService = ServiceLocator.locate(HttpService.class);
FormHttpRequest request = httpService.newHttpRequestBuilder()
.withConnectionName(connectionName)
.withMethod(HttpMethod.POST)
.withPath("/api/v24.2/query")
.withHeader("Content-Type", "application/x-www-form-urlencoded")
.withBodyParam("q", query.toString())
.build();
//Send the request the source vault via a callback. The response received back should be a JSON response.
//First, the response is parsed into a `JsonData` object
//From the response, the `getJsonObject()` will get the response as a parseable `JsonObject`
// * Here the `getValue` method can be used to retrieve `responseStatus`, `responseDetails`, and `data`
//The `data` element is an array of JSON data. This is parsed into a `JsonArray` object.
// * Each queried record is returned as an element of the array and must be parsed into a `JsonObject`.
// * Individual fields can then be retrieved from each `JsonObject` that is in the `JsonArray`.
httpService.sendRequest(request, HttpResponseBodyValueType.JSONDATA)
.onSuccess(httpResponse -> {
JsonData response = httpResponse.getResponseBody();
String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
if (responseStatus.equals("SUCCESS")) {
JsonArray data = response.getJsonObject().getValue("data", JsonValueType.ARRAY);
logService.info("HTTP Query Request: SUCCESS");
String latestGlobalId = "";
List<DocumentVersion> newVersions = VaultCollections.newList();
String latestNewDocId = "";
//Retrieve each record returned from the VQL query, which corresponds to a document.
//Each element of the returned `data` JsonArray is a record with it's queried fields.
for (int i = 0; i < data.getSize(); i++) {
JsonObject queryRecord = data.getValue(i, JsonValueType.OBJECT);
String globalId = queryRecord.getValue("global_id__sys", JsonValueType.STRING);
String globalVersionId = queryRecord.getValue("global_version_id__sys", JsonValueType.STRING);
Boolean latestVersion = queryRecord.getValue("latest_version__v", JsonValueType.BOOLEAN);
BigDecimal id = queryRecord.getValue("id", JsonValueType.NUMBER);
// Retrieve the desired document metadata fields from the VQL query data
String versionId = queryRecord.getValue("version_id", JsonValueType.STRING);
String docName = queryRecord.getValue("name__v", JsonValueType.STRING);
String type = queryRecord.getValue("type__v", JsonValueType.STRING);
String lifecycle = queryRecord.getValue("lifecycle__v", JsonValueType.STRING);
String status = queryRecord.getValue("status__v", JsonValueType.STRING);
// Workout the major and minor versions to match the source
String[] parts = StringUtils.split(versionId, "_");
BigDecimal majorVersion = BigDecimal.valueOf(Integer.valueOf(parts[1]));
BigDecimal minorVersion = BigDecimal.valueOf(Integer.valueOf(parts[2]));
...
Creating a new document and creating a new document version need to be done independently, so the code has if/else statement for each.
In the case of a new document the DocumentService.newDocument()
method is first called create the document if if doesn't already exist in the target. The information returned from the query is then used to assign all of the desired metadata fields with a .setValue()
.
Note: It's important to make sure that all the metadata fields returned in the query match those configured in the target vault, otherwise the subsequent save may fail. This includes populating mandatory values and ensuring values are valid.
Then a reference to the source file which needs to be copied is created using the DocumentService.newDocumentSourceFileReference()
. This method that accepts connection information and the id of the document to copy from the source vault.
Additionally, renditions are suppressed using documentVersion.suppressRendition()
and then the viewable rendition is manually copied from the source document using the documentService.newDocumentRenditionFileReference()
method. Should other rendition types be needed further rendition file references should be added, replacing viewable_rendition__v with the desired rendition type.
Note: If these rendition steps were omitted, renditions will instead be regenerated in the target vault, rather than being copied from the source vault.
The documents are then saved to the target vault using the documentService.createDocuments
method.
The latestNewDocId
of the document created is then obtained, as this will be needed later on in order to create any subsequent document versions.
Lastly, any attachments to the document are created using the DocumentService.createAttachments()
method. This example only creates an attachment against the latest document version.
Note: If multiple versions of attachments are needed, the new attachment version should also be passed to
DocumentService.createAttachments()
for each required version.
...
// Create a new document if different from the previous version
if (!globalId.equals(latestGlobalId)) {
String newDocId = getDocumentIdForVersion(globalVersionId);
// Create the doc if it doesn't already exist in the target vault
if (!docVersionExists(globalVersionId)) {
// Create a new document in the target, setting the metadata to match the
// values from the source
DocumentVersion documentVersion = documentService.newDocument();
documentVersion.setValue("name__v", docName);
documentVersion.setValue("type__v", VaultCollections.asList(type));
documentVersion.setValue("lifecycle__v", VaultCollections.asList(lifecycle));
documentVersion.setValue("status__v", VaultCollections.asList(status));
documentVersion.setValue("link__sys", globalId);
documentVersion.setValue("version_link__sys", globalVersionId);
documentVersion.setValue("major_version_number__v", majorVersion);
documentVersion.setValue("minor_version_number__v", minorVersion);
// Copy the source file reference
DocumentSourceFileReference documentSourceFileReference =
documentService.newDocumentSourceFileReference(connectionContext, versionId);
documentVersion.setSourceFile(documentSourceFileReference);
// Suppress the rendition so it can be copied in from the source vault,
// rather than being regenerated
if (includeViewableRendition) {
documentVersion.suppressRendition();
}
// Save the newly created document copy in the target vault
SaveDocumentVersionsResponse documents =
documentService.createDocuments(VaultCollections.asList(documentVersion));
List<PositionalDocumentVersionId> docversion = documents.getSuccesses();
newDocId = docversion.get(0).getDocumentVersionId();
docversion.stream().forEach(newdoc ->
logService.info("Document Created is : " + newdoc.getDocumentVersionId()));
// Create viewable rendition (if required)
//
// Note: similar logic can be used for other rendition types if so desired
if (includeViewableRendition) {
DocumentRenditionFileReference documentRenditionFileReference =
documentService.newDocumentRenditionFileReference(connectionContext,
versionId,
"viewable_rendition__v");
DocumentRendition viewableRendition =
documentService.newDocumentRendition(documentRenditionFileReference,
newDocId,
"viewable_rendition__v");
// Add the rendition
SaveDocumentVersionsResponse docRendition =
documentService.createRenditions(VaultCollections.asList(viewableRendition));
//Logging
List<PositionalDocumentVersionId> docRenditionsList = docRendition.getSuccesses();
docRenditionsList.stream().forEach(renditionId ->
logService.info("Document Rendition created is : "
+ renditionId.getDocumentVersionId()));
}
}
//Get new doc id, for subsequent versions
String[] parts2 = StringUtils.split(newDocId, "_");
latestNewDocId = parts2[0];
// Create document attachments if required
if (includeAttachments) {
List<String> docAttachmentIds = getAttachmentIds(connectionName,id.toString());
List<DocumentAttachment> documentAttachments = VaultCollections.newList();
for (String docAttachmentId : docAttachmentIds) {
DocumentAttachmentFileReference documentAttachmentFileReference =
documentService.newDocumentAttachmentFileReference(connectionContext,
docAttachmentId);
DocumentAttachment documentAttachment =
documentService.newDocumentAttachment(documentAttachmentFileReference,
latestNewDocId);
documentAttachments.add(documentAttachment);
documentService.createAttachments(VaultCollections.asList(documentAttachment));
}
// Document Attachments are only created where they don't already exist
documentService.createAttachments(documentAttachments);
}
// Log the successfully updated records
successfulIdList.add(globalId);
...
When processing an existing document, if there is a new version that doesn't already appear in the target Vault we copy the new version and save it. For this the method documentService.newVersion(latestNewDocId)
is used, using the existing documents id, before setting the values and adding the source file using .setSourceFile()
in the same way as when creating new source documents. It's important to note that when creating new document versions, you must set the major and minor version numbers.
After each new version is created it should be added to an array, and they should all be created together using the documentService.migrateDocumentVersions(newVersions)
method.
Note: If the vSDKDocCopyDocumentAction action is rerun in the source Vault after creating a new document version and subsequently approving it, this code will copy these new version to the target Vault. It doesn't however edit any of the previously copied version where the metadata might have changed. For example the previous steady state version of the document will have changed from approved to superceded. If this is required if will be necessary to delete and re-add the previous versions.
...
// Otherwise create a new version
} else {
// Create the doc if it doesn't already exist in the target vault
if (!docVersionExists(globalVersionId)) {
logService.info("Target document id =" );
logService.info("Document version to be created against docId " + latestNewDocId
+ " with version_link__sys=" + globalVersionId);
// Create a new document version in the target, setting the metadata to match the
// values from the source
DocumentSourceFileReference versionSourceFileReference =
documentService.newDocumentSourceFileReference(connectionContext, versionId);
// Pass Doc Id to create the version from
DocumentVersion newVersion = documentService.newVersion(latestNewDocId);
newVersion.setValue("name__v", docName);
newVersion.setValue("type__v", VaultCollections.asList(type));
newVersion.setValue("lifecycle__v", VaultCollections.asList(lifecycle));
newVersion.setValue("status__v", VaultCollections.asList(status));
newVersion.setValue("link__sys", globalId);
newVersion.setValue("version_link__sys", globalVersionId);
newVersion.setValue("major_version_number__v", majorVersion);
newVersion.setValue("minor_version_number__v", minorVersion);
// Copy the version's source file reference
newVersion.setSourceFile(versionSourceFileReference);
// Add the version to a list to be created once all versions form the document
// have been processed
newVersions.add(newVersion);
}
// If this is the final version for the document, migrate all the versions
if (latestVersion) {
documentService.migrateDocumentVersions(newVersions);
latestNewDocId = "";
newVersions.clear();
}
}
latestGlobalId = globalId;
}
// If the response is unsuccessful the transfer of the integration records
// should be marked as having failed
} else {
for (String docGlobalId : docGlobalIds) {
failedIdList.add(docGlobalId);
}
}
response = null;
})
...
The last step in processing the documents is to set the processing status on the source vault in the Integration Transaction object. There is a list of documents for:
- Those processed successfully
- Those processed unsuccessfully
The two lists mentioned earlier are use to house the documents processed successfully and unsuccessfully, respectively, using the vSDKSparkHelper.setIntTransProcessedStatuses()
method.
The HttpService
is used to update the values on the source side.
...
// Update the source system to say whether the documents have been copied or not,
// by making a callback to the source vault and updating the integration transaction
// record associated with the source record.
vSDKSparkHelper.setIntTransProcessedStatuses(
successfulIdList,
connectionName,
queryObject,
integrationPointApiName,
true);
vSDKSparkHelper.setIntTransProcessedStatuses(
failedIdList,
connectionName,
queryObject,
integrationPointApiName,
false);
...
//The recordsUpdate list parameter contains the affected source Ids.
//The source Ids are used to build a batch of vsdk_bike_store__c updates for the source system.
//The Update Record API takes JSON data as the body of the HttpRequest, so we can
//build a Json request with the `JsonObjectBuilder` and `JsonArrayBuilder`
public static void setIntTransProcessedStatuses(List<String> recordsUpdateSourceRecordIds,
String connectionName, // i.e. vsdk_connection_to_warranties
String objectName, // i.e. vsdk_warranty__c
String targetIntegrationPoint,
Boolean processSuccess) { // i.e. receive_warranties__c
HttpService httpService = ServiceLocator.locate(HttpService.class);
LogService logService = ServiceLocator.locate(LogService.class);
String processValue = "process_success__c";
if (!processSuccess) {
processValue = "process_failure__c";
}
// Get a list of Integration Transaction Record Ids, associated with the given
// composite key which consists of source_record_id, source_object, target_integration_point
// and processed_status of pending
List<String> recordUpdateIds = getIntTransIds(connectionName,
recordsUpdateSourceRecordIds,
objectName,
targetIntegrationPoint);
FormHttpRequest.Builder requestBuilder = httpService.newHttpRequestBuilder()
.withConnectionName(connectionName);
JsonService jsonService = ServiceLocator.locate(JsonService.class);
JsonObjectBuilder jsonObjectBuilder = jsonService.newJsonObjectBuilder();
JsonArrayBuilder jsonArrayBuilder = jsonService.newJsonArrayBuilder();
//The Update Object Record API takes JSON data as input.
//The input format is an array of Json objects.
//Use the `JsonObjectBuilder` to build the individual Json Objects with the necessary updates.
//Then add the resulting `JsonObject` objects to the `JsonArrayBuilder`
for (String value : recordUpdateIds) {
JsonObject inputJsonObject = jsonObjectBuilder.setValue("id", value)
.setValue("transaction_status__c", processValue)
.build();
jsonArrayBuilder.add(inputJsonObject);
}
//Once all the Json objects are added to the `JsonArray`, use the `build` method to generate the array.
JsonArray inputJsonArray = jsonArrayBuilder.build();
if (inputJsonArray.getSize() > 0) {
FormHttpRequest request = requestBuilder
.withMethod(HttpMethod.PUT)
.withPath("/api/v24.2/vobjects/integration_transaction__c")
.withHeader("Content-Type", "application/json")
.withBody(inputJsonArray)
.build();
httpService.sendRequest(request, HttpResponseBodyValueType.JSONDATA)
.onSuccess(httpResponse -> {
JsonData response = httpResponse.getResponseBody();
if (response.isValidJson()) {
String responseStatus = response.getJsonObject().getValue("responseStatus", JsonValueType.STRING);
if (responseStatus.equals("SUCCESS")) {
JsonArray data = response.getJsonObject().getValue("data", JsonValueType.ARRAY);
//Retrieve the results for each record that was updated.
//Each element of the returned `data` JsonArray is the results of a single updated record.
for (int i = 0; i <= data.getSize()-1;i++) {
JsonObject recordResponse = data.getValue(i, JsonValueType.OBJECT);
String recordStatus = recordResponse.getValue("responseStatus", JsonValueType.STRING);
JsonObject recordData = recordResponse.getValue("data", JsonValueType.OBJECT);
String recordId = recordData.getValue("id", JsonValueType.STRING);
StringBuilder logMessage = new StringBuilder();
logMessage.append("HTTP Update Request ").append(recordStatus)
.append(": ").append(recordId);
logService.info(logMessage.toString());
}
data = null;
}
response = null;
} else {
logService.info("v2vHttpUpdate error: Received a non-JSON response.");
}
}).onError(httpOperationError -> {
logService.info(httpOperationError.getMessage());
logService.info(httpOperationError.getHttpResponse().getResponseBody());
}).execute();
request = null;
inputJsonArray = null;
}
}