5454import com .ibm .fhir .operation .bulkdata .model .type .OperationFields ;
5555import com .ibm .fhir .operation .bulkdata .model .type .StorageType ;
5656import com .ibm .fhir .persistence .FHIRPersistence ;
57+ import com .ibm .fhir .persistence .InteractionStatus ;
5758import com .ibm .fhir .persistence .SingleResourceResult ;
5859import com .ibm .fhir .persistence .context .FHIRPersistenceContext ;
5960import com .ibm .fhir .persistence .context .FHIRPersistenceContextFactory ;
6061import com .ibm .fhir .persistence .context .FHIRPersistenceEvent ;
61- import com .ibm .fhir .persistence .exception .FHIRPersistenceException ;
6262import com .ibm .fhir .persistence .helper .FHIRPersistenceHelper ;
6363import com .ibm .fhir .persistence .helper .FHIRTransactionHelper ;
6464import com .ibm .fhir .persistence .payload .PayloadPersistenceHelper ;
@@ -186,7 +186,6 @@ public void writeItems(List<java.lang.Object> arg0) throws Exception {
186186
187187 // Get the Skippable Update status
188188 boolean skip = adapter .enableSkippableUpdates ();
189- Map <String ,SaltHash > localCache = new HashMap <>();
190189 try {
191190 for (Object objResJsonList : arg0 ) {
192191 @ SuppressWarnings ("unchecked" )
@@ -222,13 +221,7 @@ public void writeItems(List<java.lang.Object> arg0) throws Exception {
222221
223222 // Set up the persistence context to include the deleted resources when we read
224223 FHIRPersistenceContext persistenceContext = FHIRPersistenceContextFactory .createPersistenceContext (event , true );
225- long startTime = System .currentTimeMillis ();
226- operationOutcome = conditionalFingerprintUpdate (chunkData , skip , localCache , fhirPersistence , persistenceContext , id , fhirResource );
227- if (auditLogger .shouldLog ()) {
228- long endTime = System .currentTimeMillis ();
229- String location = "@source:" + ctx .getSource () + "/" + ctx .getImportPartitionWorkitem ();
230- auditLogger .logUpdateOnImport (null , fhirResource , new Date (startTime ), new Date (endTime ), Response .Status .OK , location , "BulkDataOperator" );
231- }
224+ operationOutcome = conditionalFingerprintUpdate (chunkData , skip , fhirPersistence , persistenceContext , id , fhirResource , ctx );
232225 }
233226
234227 succeededNum ++;
@@ -293,15 +286,17 @@ public void writeItems(List<java.lang.Object> arg0) throws Exception {
293286 *
294287 * @param chunkData the transient user data used increment the number of skips
295288 * @param skip should skip the resource if it matches
296- * @param localCache map containing the key-saltHash
297289 * @param persistence used to facilitate the calls to the underlying db
298290 * @param context used in db calls
299291 * @param logicalId the logical id of the FHIR resource (e.g. 1-2-3-4)
300292 * @param resource the FHIR Resource
293+ * @param ctx the bulk data context
301294 * @return outcomes including information or warnings
302- * @throws FHIRPersistenceException
295+ * @throws Exception
303296 */
304- public OperationOutcome conditionalFingerprintUpdate (ImportTransientUserData chunkData , boolean skip , Map <String , SaltHash > localCache , FHIRPersistence persistence , FHIRPersistenceContext context , String logicalId , Resource resource ) throws FHIRPersistenceException {
297+ public OperationOutcome conditionalFingerprintUpdate (ImportTransientUserData chunkData , boolean skip , FHIRPersistence persistence , FHIRPersistenceContext context , String logicalId , Resource resource , BulkDataContext ctx ) throws Exception {
298+ long startTime = System .currentTimeMillis ();
299+ Response .Status status = Response .Status .OK ;
305300
306301 // Since issue 1869, we must perform the read at this point in order to obtain the
307302 // latest version id. The persistence layer no longer makes any changes to the
@@ -317,27 +312,29 @@ public OperationOutcome conditionalFingerprintUpdate(ImportTransientUserData chu
317312
318313 // If the resource was previously deleted, we need to treat this as a not to skip, otherwise we end up with really inconsistent data
319314 // when there is a DELETED resource.
315+ boolean skipped = false ;
320316 OperationOutcome oo ;
321- if (skip && !oldResourceResult .isDeleted ()) {
322- // Key is scoped to the ResourceType.
323- String key = resourceType + "/" + logicalId ;
324- SaltHash oldBaseLine = localCache .get (key );
325-
326- ResourceFingerprintVisitor fp = new ResourceFingerprintVisitor ();
327- if (oldBaseLine == null ) {
328- // If the resource exists, then we need to fingerprint.
329- if (oldResource != null ) {
330- ResourceFingerprintVisitor fpOld = new ResourceFingerprintVisitor ();
331- oldResource .accept (fpOld );
332- oldBaseLine = fpOld .getSaltAndHash ();
333- fp = new ResourceFingerprintVisitor (oldBaseLine );
334- }
317+ if (!skip || oldResourceResult .isDeleted () || oldResource == null ) {
318+ SingleResourceResult <? extends Resource > result = persistence .updateWithMeta (context , resource );
319+
320+ if (result .getStatus () == InteractionStatus .MODIFIED ) {
321+ status = Response .Status .CREATED ;
335322 }
323+ oo = result .getOutcome ();
324+ } else {
325+ // Fingerprint old base line
326+ ResourceFingerprintVisitor fpOld = new ResourceFingerprintVisitor ();
327+ oldResource .accept (fpOld );
328+ SaltHash oldBaseLine = fpOld .getSaltAndHash ();
336329
330+ // Fingerprint new base line
331+ ResourceFingerprintVisitor fp = new ResourceFingerprintVisitor (oldBaseLine );
337332 resource .accept (fp );
338333 SaltHash newBaseLine = fp .getSaltAndHash ();
339334
340335 if (oldBaseLine != null && oldBaseLine .equals (newBaseLine )) {
336+ // Outcome is an informational message (no change to datastore)
337+ String key = resource .getClass ().getSimpleName () + "/" + logicalId ;
341338 if (logger .isLoggable (Level .FINE )) {
342339 logger .fine ("Skipping $import - update for '" + key + "'" );
343340 }
@@ -347,22 +344,31 @@ public OperationOutcome conditionalFingerprintUpdate(ImportTransientUserData chu
347344 .severity (IssueSeverity .INFORMATION )
348345 .code (IssueType .INFORMATIONAL )
349346 .details (CodeableConcept .builder ()
350- .text (string ("Update resource matches the existing resource; skipping the update for '" + key + "'" ))
347+ .text (string ("Update to an existing resource matches the stored resource's hash ; skipping the update for '" + key + "'" ))
351348 .build ())
352349 .build ())
353350 .build ();
351+ skipped = true ;
354352 } else {
353+ // Outcome is an Update
355354 // We need to update the db and update the local cache
356- if (oldResource != null ) {
357- // Old Resource is set so we avoid an extra read
358- context .getPersistenceEvent ().setPrevFhirResource (oldResource );
359- }
360- oo = persistence .updateWithMeta (context , resource ).getOutcome ();
361- localCache .put (key , newBaseLine );
355+ // Old Resource is set so we avoid an extra read
356+ context .getPersistenceEvent ().setPrevFhirResource (oldResource );
357+ SingleResourceResult <? extends Resource > result = persistence .updateWithMeta (context , resource );
358+ oo = result .getOutcome ();
359+ }
360+ }
361+
362+ // Audit Logging
363+ if (auditLogger .shouldLog ()) {
364+ long endTime = System .currentTimeMillis ();
365+ String location = "@source:" + ctx .getSource () + "/" + ctx .getImportPartitionWorkitem ();
366+ if (!skipped ) {
367+ auditLogger .logUpdateOnImport (oldResource , resource , new Date (startTime ), new Date (endTime ), status , location , "BulkDataOperator" );
368+ } else {
369+ auditLogger .logUpdateOnImportSkipped (resource , new Date (startTime ), new Date (endTime ), status , location , "BulkDataOperator" );
362370 }
363- } else {
364- oo = persistence .updateWithMeta (context , resource ).getOutcome ();
365371 }
366372 return oo ;
367373 }
368- }
374+ }
0 commit comments