3434import java .util .logging .Level ;
3535import java .util .regex .Matcher ;
3636import java .util .regex .Pattern ;
37+ import java .util .stream .Collectors ;
38+ import java .util .stream .Stream ;
3739
3840import javax .json .JsonArray ;
3941import javax .json .JsonObject ;
7072import com .esri .geoportal .service .stac .Collection ;
7173import com .esri .geoportal .service .stac .GeometryServiceClient ;
7274import com .esri .geoportal .service .stac .StacContext ;
75+ import com .jayway .jsonpath .Configuration ;
7376import com .jayway .jsonpath .DocumentContext ;
7477import com .jayway .jsonpath .JsonPath ;
78+ import com .jayway .jsonpath .Option ;
7579
7680import net .minidev .json .JSONArray ;
7781import net .minidev .json .JSONObject ;
@@ -495,7 +499,8 @@ public Response getItems(@Context HttpServletRequest hsr,
495499 else
496500 response = client .sendGet (url );
497501
498- responseJSON = this .prepareResponse (response , hsr , bbox , limit , datetime , null , null , "metadataItems" , collectionId ,null );
502+ responseJSON = this .prepareResponse (response , hsr , bbox , limit , datetime , null , null , "metadataItems" , collectionId ,null ,
503+ null ,null ,outCRS , null , null );
499504
500505 // if reprojecting STAC geometries is supported and a
501506 // geometry service has been configured, try projecting
@@ -835,7 +840,7 @@ public Response search(@Context HttpServletRequest hsr, @QueryParam("limit") int
835840 {
836841 responseJSON = this .prepareResponse (response , hsr , bbox , limit , datetime ,
837842 idList , intersects , "search" ,
838- listOfCollections ,null );
843+ listOfCollections ,null , updated , created , outCRS , itemStatus , filter );
839844
840845 // if re-projecting STAC geometries is supported and a
841846 // geometry service has been configured, try projecting from internal CRS (4326) to requested outCRS
@@ -884,7 +889,8 @@ public Response search(@Context HttpServletRequest hsr, @RequestBody String body
884889 JsonArray bboxJsonArr = (requestPayload .containsKey ("bbox" ) ? requestPayload .getJsonArray ("bbox" ) : null );
885890 JsonArray idArr = (requestPayload .containsKey ("ids" ) ? requestPayload .getJsonArray ("ids" ) : null );
886891 String outCRS = (requestPayload .containsKey ("outCRS" ) ? requestPayload .getString ("outCRS" ) : null );
887-
892+ search_after = (requestPayload .containsKey ("search_after" ) ? requestPayload .getString ("search_after" ) : search_after );
893+
888894 JsonArray collectionArr = (requestPayload .containsKey ("collections" )
889895 ? requestPayload .getJsonArray ("collections" )
890896 : null );
@@ -971,14 +977,15 @@ public Response search(@Context HttpServletRequest hsr, @RequestBody String body
971977 queryMap .put ("filterClause" , filterClause ); //filterQry);
972978 }
973979
974- //Search request with outCRS is valid, if only one collection in collections param, otherwise 400
975- if ((outCRS != null ) && collectionArr !=null && collectionArr .size ()>1 )
976- {
980+ //Search request with outCRS is valid, if only one collection in collections param, otherwise 400
981+ if ((outCRS != null ) && collectionArr !=null && collectionArr .size ()>1 )
982+ {
977983 status = Response .Status .BAD_REQUEST ;
978984 responseJSON = this .generateResponse ("400" , "Only one collection can be included in search param if search param includes outCRS " ,null );
979985 return Response .status (status ).header ("Content-Type" , "application/geo+json" ).entity (responseJSON ).build ();
980986
981- }
987+ }
988+
982989 //Adding one extra so that next page can be figured out
983990 url = url + "/_search?size=" + (limit +1 );
984991 query = StacHelper .prepareSearchQuery (queryMap , search_after );
@@ -1000,15 +1007,15 @@ public Response search(@Context HttpServletRequest hsr, @RequestBody String body
10001007 // if re-projecting STAC geometries is supported and a
10011008 // geometry service has been configured, try projecting
10021009 // from internal CRS (4326) to requested outCRS
1003- if ((outCRS != null ) && ("true" .equals (sc .isCanStacGeomTransform ())) && (!gc .getGeometryService ().isEmpty ())) {
1004- LOGGER .debug ("outCRS = " + outCRS + " - " + gc .getGeometryService ());
1005-
1006- JSONObject projectedResponseObj = projectSearchResults (responseJSON , "4326" , outCRS );
1007- responseJSON = projectedResponseObj .toString ();
1008-
1009- // done
1010- LOGGER .debug ("Project response -> " + responseJSON );
1011- }
1010+ if ((outCRS != null ) && ("true" .equals (sc .isCanStacGeomTransform ())) && (!gc .getGeometryService ().isEmpty ())) {
1011+ LOGGER .debug ("outCRS = " + outCRS + " - " + gc .getGeometryService ());
1012+
1013+ JSONObject projectedResponseObj = projectSearchResults (responseJSON , "4326" , outCRS );
1014+ responseJSON = projectedResponseObj .toString ();
1015+
1016+ // done
1017+ LOGGER .debug ("Project response -> " + responseJSON );
1018+ }
10121019 }
10131020
10141021 } catch (InvalidParameterException e ) {
@@ -1819,9 +1826,16 @@ private String prepareResponseSingleItem(String searchRes, String itemFileString
18191826 finalResponse = finalResponse .replaceAll ("\\ {collectionId\\ }" , collectionId );
18201827 return finalResponse ;
18211828 }
1829+
1830+ private String prepareResponse (String searchRes , HttpServletRequest hsr , String bbox , int limit , String datetime ,
1831+ String ids , String intersects , String requestType , String collectionId , String body ) {
1832+ return this .prepareResponse (searchRes , hsr , bbox , limit , datetime , ids , intersects , requestType , collectionId , body ,
1833+ null , null , null , null , null );
1834+ }
18221835
18231836 private String prepareResponse (String searchRes , HttpServletRequest hsr , String bbox , int limit , String datetime ,
1824- String ids , String intersects , String requestType , String collectionId , String body ) {
1837+ String ids , String intersects , String requestType , String collectionId , String body ,
1838+ String updated ,String created ,String outCrs ,String status ,String filter ) {
18251839
18261840 int numberMatched ;
18271841 net .minidev .json .JSONArray items ;
@@ -1898,18 +1912,15 @@ private String prepareResponse(String searchRes, HttpServletRequest hsr, String
18981912 }
18991913 String urlparam = "" ;
19001914 if (requestType .equalsIgnoreCase ("searchPost" )) {
1901- JSONObject bodyObj =new JSONObject ();
1902- // In post request, search_after will be part of request body
1903- if (body != null )
1904- {
1905- bodyObj = (JSONObject ) JSONValue .parse (body );
1906- if (search_after != null && search_after .length ()>0 )
1907- bodyObj .appendField ("search_after" , search_after );
1908- }
1915+ // Add search_after in urlparam
1916+ urlparam = (search_after != null ? "?search_after=" + search_after : "" );
1917+
1918+ JSONObject bodyObj =new JSONObject ();
19091919 if (nextLink )
19101920 linksContext .set ("$.searchItem.links[1].body" ,(body != null ? bodyObj : "" ));
19111921
19121922 } else {
1923+ // GET request, set everything as request parameters
19131924 if (nextLink )
19141925 {
19151926 linksContext .delete ("$.searchItem.links[1].body" );
@@ -1922,6 +1933,11 @@ private String prepareResponse(String searchRes, HttpServletRequest hsr, String
19221933 + (search_after != null ? "&search_after=" + search_after : "" )
19231934 + (encodedIntersect != null ? "&intersects=" + encodedIntersect : "" )
19241935 + (ids != null ? "&ids=" + ids : "" )
1936+ + (updated != null ? "&updated=" + updated : "" )
1937+ + (created != null ? "&created=" + created : "" )
1938+ + (outCrs != null ? "&outCRS=" + outCrs : "" )
1939+ + (status != null ? "&status=" + status : "" )
1940+ + (filter != null ? "&filter=" + filter : "" )
19251941 +((requestType .startsWith ("search" )) && collectionId != null ? "&collections=" + collectionId : "" );
19261942 }
19271943 if (requestType .startsWith ("metadataItems" ))
@@ -1963,7 +1979,8 @@ private boolean populateFeature(DocumentContext featureContext, DocumentContext
19631979 featureContext .set ("$.featurePropPath.id" , searchItemCtx .read (val ));
19641980
19651981 val = featureContext .read ("$.featurePropPath.collection" );
1966- featureContext .set ("$.featurePropPath.collection" , searchItemCtx .read (val ));
1982+ String collectionId = searchItemCtx .read (val ).toString ();
1983+ featureContext .set ("$.featurePropPath.collection" , collectionId );
19671984
19681985 // add bbox, geometry
19691986 this .setBbox (searchItemCtx , featureContext );
@@ -2027,26 +2044,69 @@ private boolean populateFeature(DocumentContext featureContext, DocumentContext
20272044 LOGGER .trace ("No assets ($._source.assets) in this Stac record with id: " + recordId );
20282045
20292046 }
2030-
2031- // Iterate properties, skip property if it is not available
2047+
2048+ //#680
2049+ //fill item with collection properties when not available in item, item property overrides default set in collection
2050+ Set <String > collectionPropKeySet = null ;
2051+ JSONObject collectionPropObj = null ;
2052+ ArrayList <String > propToBeAddedFromCollectionList = new ArrayList <String >();
2053+
2054+ Collection collection = new Collection (collectionId );
2055+ if (collection .getProperties () != null )
2056+ {
2057+ collectionPropObj = collection .getProperties ();
2058+ if (collectionPropObj != null ) {
2059+ collectionPropKeySet = collectionPropObj .keySet ();
2060+ //Create a combined set of property keys from item and collection
2061+ Set <String > combinedPropSet = Stream .concat (propObjKeys .stream (), collectionPropKeySet .stream ())
2062+ .collect (Collectors .toSet ());
2063+ propObjKeys = combinedPropSet ;
2064+ }
2065+ }
2066+
2067+ // Iterate properties, skip property if it is not available in item and collection
20322068 for (String propKey : propObjKeys ) {
20332069 try {
2034- propKeyVal = String .valueOf (propObj .get (propKey ));
2035- // If it is a json path, set values from search result
2036- if (propKeyVal .startsWith ("$" )) {
2037- if (searchItemCtx .read (propKeyVal ) != null ) {
2038- featureContext .set ("$.featurePropPath.properties." + propKey ,
2039- searchItemCtx .read (propKeyVal ));
2070+ //it is item prop, try to fill from searched item
2071+ if (propObj .containsKey (propKey ))
2072+ {
2073+ propKeyVal = String .valueOf (propObj .get (propKey ));
2074+ // If it is a json path, set values from search result
2075+ if (propKeyVal .startsWith ("$" )) {
2076+ if (searchItemCtx .read (propKeyVal ) != null ) {
2077+ featureContext .set ("$.featurePropPath.properties." + propKey ,
2078+ searchItemCtx .read (propKeyVal ));
2079+ }
20402080 }
20412081 }
2082+ //Not an Item prop, Collection prop
2083+ else
2084+ {
2085+ propToBeAddedFromCollectionList .add (propKey );
2086+ }
2087+
20422088 } catch (Exception e ) {
2043- // If json path not found or error in any property, remove this property in the
2044- // end.
2045- // if removed here, concurrentModificationException
2046- propToBeRemovedList .add ("$.featurePropPath.properties." + propKey );
2047- LOGGER .trace ("key: " + propKey + " could not be added. Reason : " + e .getMessage ());
2089+ //item did not have this data, so check if it is available in collection prop. This will be added later from collection
2090+ if (collectionPropObj != null && collectionPropObj .containsKey (propKey ))
2091+ {
2092+ propToBeAddedFromCollectionList .add (propKey );
2093+ }
2094+ // If json path not found in searchItemCtx.read(propKeyVal) or error in any property, remove this property in the
2095+ // end. if removed here, concurrentModificationException
2096+ else
2097+ {
2098+ propToBeRemovedList .add ("$.featurePropPath.properties." + propKey );
2099+ LOGGER .trace ("key: " + propKey + " could not be added. Reason : " + e .getMessage ());
2100+ }
20482101 }
20492102 }
2103+ //Read updated item property object again and add keys from collection
2104+ HashMap <String , String > updatedPropObj = featureContext .read ("$.featurePropPath.properties" );
2105+ for (String prop : propToBeAddedFromCollectionList )
2106+ {
2107+ updatedPropObj .put (prop , collectionPropObj .getAsString (prop ));
2108+ }
2109+ featureContext .set ("$.featurePropPath.properties" ,updatedPropObj );
20502110
20512111 String linkSelfHref = featureContext .read ("$.featurePropPath.links[0].href" );
20522112 linkSelfHref = linkSelfHref .replaceAll ("\\ {itemId\\ }" , featureContext .read ("$.featurePropPath.id" ).toString ());
0 commit comments