77
77
import com .ibm .fhir .model .type .code .IssueSeverity ;
78
78
import com .ibm .fhir .model .type .code .IssueType ;
79
79
import com .ibm .fhir .model .type .code .SearchEntryMode ;
80
+ import com .ibm .fhir .model .util .CollectingVisitor ;
80
81
import com .ibm .fhir .model .util .FHIRUtil ;
81
82
import com .ibm .fhir .model .util .ModelSupport ;
82
83
import com .ibm .fhir .model .util .ReferenceMappingVisitor ;
@@ -1734,11 +1735,11 @@ private List<Entry> processEntriesByMethod(Bundle requestBundle, Map<Integer, En
1734
1735
} else if (request .getMethod ().equals (HTTPVerb .POST )) {
1735
1736
Entry validationResponseEntry = validationResponseEntries .get (entryIndex );
1736
1737
responseEntries [entryIndex ] = processEntryForPost (requestEntry , validationResponseEntry , responseIndexAndEntries ,
1737
- entryIndex , localRefMap , requestURL , absoluteUri , requestDescription .toString (), initialTime );
1738
+ entryIndex , localRefMap , requestURL , absoluteUri , requestDescription .toString (), initialTime , ( bundleType == BundleType . Value . TRANSACTION ) );
1738
1739
} else if (request .getMethod ().equals (HTTPVerb .PUT )) {
1739
1740
Entry validationResponseEntry = validationResponseEntries .get (entryIndex );
1740
1741
responseEntries [entryIndex ] = processEntryForPut (requestEntry , validationResponseEntry , responseIndexAndEntries ,
1741
- entryIndex , localRefMap , requestURL , absoluteUri , requestDescription .toString (), initialTime , skippableUpdates );
1742
+ entryIndex , localRefMap , requestURL , absoluteUri , requestDescription .toString (), initialTime , skippableUpdates , ( bundleType == BundleType . Value . TRANSACTION ) );
1742
1743
} else if (request .getMethod ().equals (HTTPVerb .PATCH )) {
1743
1744
responseEntries [entryIndex ] = processEntryforPatch (requestEntry , requestURL ,entryIndex ,
1744
1745
requestDescription .toString (), initialTime , skippableUpdates );
@@ -2006,7 +2007,7 @@ private void updateOperationContext(FHIROperationContext operationContext, Strin
2006
2007
* @throws Exception
2007
2008
*/
2008
2009
private Entry processEntryForPost (Entry requestEntry , Entry validationResponseEntry , Map <Integer , Entry > responseIndexAndEntries ,
2009
- Integer entryIndex , Map <String , String > localRefMap , FHIRUrlParser requestURL , String absoluteUri , String requestDescription , long initialTime )
2010
+ Integer entryIndex , Map <String , String > localRefMap , FHIRUrlParser requestURL , String absoluteUri , String requestDescription , long initialTime , boolean transaction )
2010
2011
throws Exception {
2011
2012
2012
2013
String [] pathTokens = requestURL .getPathTokens ();
@@ -2081,6 +2082,10 @@ private Entry processEntryForPost(Entry requestEntry, Entry validationResponseEn
2081
2082
throw buildRestException (msg , IssueType .NOT_FOUND );
2082
2083
}
2083
2084
2085
+ if (transaction ) {
2086
+ resolveConditionalReferences (resource , localRefMap );
2087
+ }
2088
+
2084
2089
// Convert any local references found within the resource to their corresponding external reference.
2085
2090
ReferenceMappingVisitor <Resource > visitor = new ReferenceMappingVisitor <Resource >(localRefMap );
2086
2091
resource .accept (visitor );
@@ -2121,6 +2126,62 @@ private Entry processEntryForPost(Entry requestEntry, Entry validationResponseEn
2121
2126
}
2122
2127
}
2123
2128
2129
+ private void resolveConditionalReferences (Resource resource , Map <String , String > localRefMap ) throws Exception {
2130
+ for (String conditionalReference : getConditionalReferences (resource )) {
2131
+ if (localRefMap .containsKey (conditionalReference )) {
2132
+ continue ;
2133
+ }
2134
+
2135
+ FHIRUrlParser parser = new FHIRUrlParser (conditionalReference );
2136
+ String type = parser .getPathTokens ()[0 ];
2137
+
2138
+ MultivaluedMap <String , String > queryParameters = parser .getQueryParameters ();
2139
+ if (queryParameters .isEmpty ()) {
2140
+ throw buildRestException ("Invalid conditional reference: no query parameters found" , IssueType .INVALID );
2141
+ }
2142
+
2143
+ if (queryParameters .keySet ().stream ().anyMatch (key -> SearchConstants .SEARCH_RESULT_PARAMETER_NAMES .contains (key ))) {
2144
+ throw buildRestException ("Invalid conditional reference: only filtering parameters are allowed" , IssueType .INVALID );
2145
+ }
2146
+
2147
+ queryParameters .add ("_summary" , "true" );
2148
+ queryParameters .add ("_count" , "1" );
2149
+
2150
+ Bundle bundle = doSearch (type , null , null , queryParameters , null , resource , false );
2151
+
2152
+ int total = bundle .getTotal ().getValue ();
2153
+
2154
+ if (total == 0 ) {
2155
+ throw buildRestException ("Error resolving conditional reference: search returned no results" , IssueType .NOT_FOUND );
2156
+ }
2157
+
2158
+ if (total > 1 ) {
2159
+ throw buildRestException ("Error resolving conditional reference: search returned multiple results" , IssueType .MULTIPLE_MATCHES );
2160
+ }
2161
+
2162
+ localRefMap .put (conditionalReference , type + "/" + bundle .getEntry ().get (0 ).getResource ().getId ());
2163
+ }
2164
+ }
2165
+
2166
+ private Set <String > getConditionalReferences (Resource resource ) {
2167
+ Set <String > conditionalReferences = new HashSet <>();
2168
+ CollectingVisitor <Reference > visitor = new CollectingVisitor <>(Reference .class );
2169
+ resource .accept (visitor );
2170
+ for (Reference reference : visitor .getResult ()) {
2171
+ if (reference .getReference () != null && reference .getReference ().getValue () != null ) {
2172
+ String value = reference .getReference ().getValue ();
2173
+ if (!value .startsWith ("#" ) &&
2174
+ !value .startsWith ("urn:" ) &&
2175
+ !value .startsWith ("http:" ) &&
2176
+ !value .startsWith ("https:" ) &&
2177
+ value .contains ("?" )) {
2178
+ conditionalReferences .add (value );
2179
+ }
2180
+ }
2181
+ }
2182
+ return conditionalReferences ;
2183
+ }
2184
+
2124
2185
/**
2125
2186
* Processes a request entry with a request method of PUT.
2126
2187
*
@@ -2150,7 +2211,7 @@ private Entry processEntryForPost(Entry requestEntry, Entry validationResponseEn
2150
2211
*/
2151
2212
private Entry processEntryForPut (Entry requestEntry , Entry validationResponseEntry , Map <Integer , Entry > responseIndexAndEntries ,
2152
2213
Integer entryIndex , Map <String , String > localRefMap , FHIRUrlParser requestURL , String absoluteUri , String requestDescription ,
2153
- long initialTime , boolean skippableUpdate ) throws Exception {
2214
+ long initialTime , boolean skippableUpdate , boolean transaction ) throws Exception {
2154
2215
2155
2216
String [] pathTokens = requestURL .getPathTokens ();
2156
2217
String type = null ;
@@ -2177,6 +2238,10 @@ private Entry processEntryForPut(Entry requestEntry, Entry validationResponseEnt
2177
2238
// Retrieve the resource from the request entry.
2178
2239
Resource resource = requestEntry .getResource ();
2179
2240
2241
+ if (transaction ) {
2242
+ resolveConditionalReferences (resource , localRefMap );
2243
+ }
2244
+
2180
2245
// Convert any local references found within the resource to their corresponding external reference.
2181
2246
ReferenceMappingVisitor <Resource > visitor = new ReferenceMappingVisitor <Resource >(localRefMap );
2182
2247
resource .accept (visitor );
@@ -2341,9 +2406,9 @@ private MultivaluedMap<String, String> getQueryParameterMap(String queryString)
2341
2406
* @return local reference map
2342
2407
*/
2343
2408
private Map <String , String > buildLocalRefMap (Bundle requestBundle , Map <Integer , Entry > validationResponseEntries ) throws Exception {
2344
- Map <String , String > localRefMap = new HashMap <>();
2409
+ Map <String , String > localRefMap = new HashMap <>();
2345
2410
2346
- for (int entryIndex = 0 ; entryIndex < requestBundle .getEntry ().size (); ++ entryIndex ) {
2411
+ for (int entryIndex = 0 ; entryIndex < requestBundle .getEntry ().size (); entryIndex ++ ) {
2347
2412
Entry requestEntry = requestBundle .getEntry ().get (entryIndex );
2348
2413
Entry .Request request = requestEntry .getRequest ();
2349
2414
Entry validationResponseEntry = validationResponseEntries .get (entryIndex );
0 commit comments