11package org .prebid .server .auction ;
22
3- import com .fasterxml .jackson .core .type . TypeReference ;
3+ import com .fasterxml .jackson .core .JsonProcessingException ;
44import com .fasterxml .jackson .databind .JsonNode ;
5- import com .fasterxml .jackson .databind .node .ArrayNode ;
5+ import com .fasterxml .jackson .databind .ObjectMapper ;
6+ import com .fasterxml .jackson .databind .node .NullNode ;
67import com .fasterxml .jackson .databind .node .ObjectNode ;
78import com .iab .openrtb .request .App ;
8- import com .iab .openrtb .request .Data ;
99import com .iab .openrtb .request .Dooh ;
1010import com .iab .openrtb .request .Site ;
1111import com .iab .openrtb .request .User ;
12- import org .apache . commons . lang3 . ObjectUtils ;
12+ import org .prebid . server . exception . InvalidRequestException ;
1313import org .prebid .server .json .JacksonMapper ;
1414import org .prebid .server .json .JsonMerger ;
15- import org .prebid .server .proto .openrtb .ext .request .ExtApp ;
16- import org .prebid .server .proto .openrtb .ext .request .ExtDooh ;
17- import org .prebid .server .proto .openrtb .ext .request .ExtSite ;
18- import org .prebid .server .proto .openrtb .ext .request .ExtUser ;
1915
20- import java .util .Collections ;
21- import java .util .List ;
2216import java .util .Objects ;
2317import java .util .Set ;
24- import java .util .function .Function ;
25- import java .util .function .Predicate ;
26- import java .util .stream .StreamSupport ;
2718
2819public class FpdResolver {
2920
@@ -33,17 +24,8 @@ public class FpdResolver {
3324 private static final String APP = "app" ;
3425 private static final String DOOH = "dooh" ;
3526 private static final Set <String > KNOWN_FPD_ATTRIBUTES = Set .of (USER , SITE , APP , DOOH , BIDDERS );
36- private static final String EXT = "ext" ;
3727 private static final String CONTEXT = "context" ;
3828 private static final String DATA = "data" ;
39- private static final Set <String > USER_DATA_ATTR = Collections .singleton ("geo" );
40- private static final Set <String > APP_DATA_ATTR = Set .of ("id" , "content" , "publisher" , "privacypolicy" );
41- private static final Set <String > SITE_DATA_ATTR = Set .of ("id" , "content" , "publisher" , "privacypolicy" , "mobile" );
42- private static final Set <String > DOOH_DATA_ATTR = Set .of ("id" , "content" , "publisher" , "privacypolicy" );
43-
44- private static final TypeReference <List <Data >> USER_DATA_TYPE_REFERENCE =
45- new TypeReference <>() {
46- };
4729
4830 private final JacksonMapper jacksonMapper ;
4931 private final JsonMerger jsonMerger ;
@@ -54,146 +36,37 @@ public FpdResolver(JacksonMapper jacksonMapper, JsonMerger jsonMerger) {
5436 }
5537
5638 public User resolveUser (User originUser , ObjectNode fpdUser ) {
57- if (fpdUser == null ) {
58- return originUser ;
59- }
60- final User resultUser = originUser == null ? User .builder ().build () : originUser ;
61- final ExtUser resolvedExtUser = resolveUserExt (fpdUser , resultUser );
62- return resultUser .toBuilder ()
63- .keywords (ObjectUtils .defaultIfNull (getString (fpdUser , "keywords" ), resultUser .getKeywords ()))
64- .gender (ObjectUtils .defaultIfNull (getString (fpdUser , "gender" ), resultUser .getGender ()))
65- .yob (ObjectUtils .defaultIfNull (getInteger (fpdUser , "yob" ), resultUser .getYob ()))
66- .data (ObjectUtils .defaultIfNull (getFpdUserData (fpdUser ), resultUser .getData ()))
67- .ext (resolvedExtUser )
68- .build ();
69- }
70-
71- private ExtUser resolveUserExt (ObjectNode fpdUser , User originUser ) {
72- final ExtUser originExtUser = originUser .getExt ();
73- final ObjectNode resolvedData =
74- mergeExtData (fpdUser .path (EXT ).path (DATA ), originExtUser != null ? originExtUser .getData () : null );
75-
76- return updateUserExtDataWithFpdAttr (fpdUser , originExtUser , resolvedData );
77- }
78-
79- private ExtUser updateUserExtDataWithFpdAttr (ObjectNode fpdUser , ExtUser originExtUser , ObjectNode extData ) {
80- final ObjectNode resultData = extData != null ? extData : jacksonMapper .mapper ().createObjectNode ();
81- USER_DATA_ATTR .forEach (attribute -> setAttr (fpdUser , resultData , attribute ));
82- return originExtUser != null
83- ? originExtUser .toBuilder ().data (resultData .isEmpty () ? null : resultData ).build ()
84- : resultData .isEmpty () ? null : ExtUser .builder ().data (resultData ).build ();
85- }
86-
87- private List <Data > getFpdUserData (ObjectNode fpdUser ) {
88- final ArrayNode fpdUserDataNode = getValueFromJsonNode (
89- fpdUser , DATA , node -> (ArrayNode ) node , JsonNode ::isArray );
90-
91- return toList (fpdUserDataNode , USER_DATA_TYPE_REFERENCE );
39+ return mergeFpd (originUser , fpdUser , User .class );
9240 }
9341
9442 public App resolveApp (App originApp , ObjectNode fpdApp ) {
95- if (fpdApp == null ) {
96- return originApp ;
97- }
98- final App resultApp = originApp == null ? App .builder ().build () : originApp ;
99- final ExtApp resolvedExtApp = resolveAppExt (fpdApp , resultApp );
100- return resultApp .toBuilder ()
101- .name (ObjectUtils .defaultIfNull (getString (fpdApp , "name" ), resultApp .getName ()))
102- .bundle (ObjectUtils .defaultIfNull (getString (fpdApp , "bundle" ), resultApp .getBundle ()))
103- .storeurl (ObjectUtils .defaultIfNull (getString (fpdApp , "storeurl" ), resultApp .getStoreurl ()))
104- .domain (ObjectUtils .defaultIfNull (getString (fpdApp , "domain" ), resultApp .getDomain ()))
105- .cat (ObjectUtils .defaultIfNull (getStrings (fpdApp , "cat" ), resultApp .getCat ()))
106- .sectioncat (ObjectUtils .defaultIfNull (getStrings (fpdApp , "sectioncat" ), resultApp .getSectioncat ()))
107- .pagecat (ObjectUtils .defaultIfNull (getStrings (fpdApp , "pagecat" ), resultApp .getPagecat ()))
108- .keywords (ObjectUtils .defaultIfNull (getString (fpdApp , "keywords" ), resultApp .getKeywords ()))
109- .ext (resolvedExtApp )
110- .build ();
111- }
112-
113- private ExtApp resolveAppExt (ObjectNode fpdApp , App originApp ) {
114- final ExtApp originExtApp = originApp .getExt ();
115- final ObjectNode resolvedData =
116- mergeExtData (fpdApp .path (EXT ).path (DATA ), originExtApp != null ? originExtApp .getData () : null );
117-
118- return updateAppExtDataWithFpdAttr (fpdApp , originExtApp , resolvedData );
119- }
120-
121- private ExtApp updateAppExtDataWithFpdAttr (ObjectNode fpdApp , ExtApp originExtApp , ObjectNode extData ) {
122- final ObjectNode resultData = extData != null ? extData : jacksonMapper .mapper ().createObjectNode ();
123- APP_DATA_ATTR .forEach (attribute -> setAttr (fpdApp , resultData , attribute ));
124- return originExtApp != null
125- ? ExtApp .of (originExtApp .getPrebid (), resultData .isEmpty () ? null : resultData )
126- : resultData .isEmpty () ? null : ExtApp .of (null , resultData );
43+ return mergeFpd (originApp , fpdApp , App .class );
12744 }
12845
12946 public Site resolveSite (Site originSite , ObjectNode fpdSite ) {
130- if (fpdSite == null ) {
131- return originSite ;
132- }
133- final Site resultSite = originSite == null ? Site .builder ().build () : originSite ;
134- final ExtSite resolvedExtSite = resolveSiteExt (fpdSite , resultSite );
135- return resultSite .toBuilder ()
136- .name (ObjectUtils .defaultIfNull (getString (fpdSite , "name" ), resultSite .getName ()))
137- .domain (ObjectUtils .defaultIfNull (getString (fpdSite , "domain" ), resultSite .getDomain ()))
138- .cat (ObjectUtils .defaultIfNull (getStrings (fpdSite , "cat" ), resultSite .getCat ()))
139- .sectioncat (ObjectUtils .defaultIfNull (getStrings (fpdSite , "sectioncat" ), resultSite .getSectioncat ()))
140- .pagecat (ObjectUtils .defaultIfNull (getStrings (fpdSite , "pagecat" ), resultSite .getPagecat ()))
141- .page (ObjectUtils .defaultIfNull (getString (fpdSite , "page" ), resultSite .getPage ()))
142- .keywords (ObjectUtils .defaultIfNull (getString (fpdSite , "keywords" ), resultSite .getKeywords ()))
143- .ref (ObjectUtils .defaultIfNull (getString (fpdSite , "ref" ), resultSite .getRef ()))
144- .search (ObjectUtils .defaultIfNull (getString (fpdSite , "search" ), resultSite .getSearch ()))
145- .ext (resolvedExtSite )
146- .build ();
147- }
148-
149- private ExtSite resolveSiteExt (ObjectNode fpdSite , Site originSite ) {
150- final ExtSite originExtSite = originSite .getExt ();
151- final ObjectNode resolvedData =
152- mergeExtData (fpdSite .path (EXT ).path (DATA ), originExtSite != null ? originExtSite .getData () : null );
153-
154- return updateSiteExtDataWithFpdAttr (fpdSite , originExtSite , resolvedData );
155- }
156-
157- private ExtSite updateSiteExtDataWithFpdAttr (ObjectNode fpdSite , ExtSite originExtSite , ObjectNode extData ) {
158- final ObjectNode resultData = extData != null ? extData : jacksonMapper .mapper ().createObjectNode ();
159- SITE_DATA_ATTR .forEach (attribute -> setAttr (fpdSite , resultData , attribute ));
160- return originExtSite != null
161- ? ExtSite .of (originExtSite .getAmp (), resultData .isEmpty () ? null : resultData )
162- : resultData .isEmpty () ? null : ExtSite .of (null , resultData );
47+ return mergeFpd (originSite , fpdSite , Site .class );
16348 }
16449
16550 public Dooh resolveDooh (Dooh originDooh , ObjectNode fpdDooh ) {
166- if (fpdDooh == null ) {
167- return originDooh ;
168- }
169- final Dooh resultDooh = originDooh == null ? Dooh .builder ().build () : originDooh ;
170- final ExtDooh resolvedExtDooh = resolveDoohExt (fpdDooh , resultDooh );
171- return resultDooh .toBuilder ()
172- .name (ObjectUtils .defaultIfNull (getString (fpdDooh , "name" ), resultDooh .getName ()))
173- .venuetype (ObjectUtils .defaultIfNull (getStrings (fpdDooh , "venuetype" ), resultDooh .getVenuetype ()))
174- .venuetypetax (ObjectUtils .defaultIfNull (
175- getInteger (fpdDooh , "venuetypetax" ),
176- resultDooh .getVenuetypetax ()))
177- .domain (ObjectUtils .defaultIfNull (getString (fpdDooh , "domain" ), resultDooh .getDomain ()))
178- .keywords (ObjectUtils .defaultIfNull (getString (fpdDooh , "keywords" ), resultDooh .getKeywords ()))
179- .ext (resolvedExtDooh )
180- .build ();
51+ return mergeFpd (originDooh , fpdDooh , Dooh .class );
18152 }
18253
183- private ExtDooh resolveDoohExt ( ObjectNode fpdDooh , Dooh originDooh ) {
184- final ExtDooh originExtDooh = originDooh . getExt ();
185- final ObjectNode resolvedData =
186- mergeExtData ( fpdDooh . path ( EXT ). path ( DATA ), originExtDooh != null ? originExtDooh . getData () : null );
54+ private < T > T mergeFpd ( T original , ObjectNode fpd , Class < T > tClass ) {
55+ if ( fpd == null || fpd . isNull () || fpd . isMissingNode ()) {
56+ return original ;
57+ }
18758
188- return updateDoohExtDataWithFpdAttr (fpdDooh , originExtDooh , resolvedData );
189- }
59+ final ObjectMapper mapper = jacksonMapper .mapper ();
19060
191- private ExtDooh updateDoohExtDataWithFpdAttr (ObjectNode fpdDooh , ExtDooh originExtDooh , ObjectNode extData ) {
192- final ObjectNode resultData = extData != null ? extData : jacksonMapper .mapper ().createObjectNode ();
193- DOOH_DATA_ATTR .forEach (attribute -> setAttr (fpdDooh , resultData , attribute ));
194- return originExtDooh != null
195- ? ExtDooh .of (resultData .isEmpty () ? null : resultData )
196- : resultData .isEmpty () ? null : ExtDooh .of (resultData );
61+ final JsonNode originalAsJsonNode = original != null
62+ ? mapper .valueToTree (original )
63+ : NullNode .getInstance ();
64+ final JsonNode merged = jsonMerger .merge (fpd , originalAsJsonNode );
65+ try {
66+ return mapper .treeToValue (merged , tClass );
67+ } catch (JsonProcessingException e ) {
68+ throw new InvalidRequestException ("Can't convert merging result class " + tClass .getName ());
69+ }
19770 }
19871
19972 public ObjectNode resolveImpExt (ObjectNode impExt , ObjectNode targeting ) {
@@ -277,62 +150,4 @@ private void removeOrReplace(ObjectNode impExt, String field, JsonNode jsonNode)
277150 impExt .set (field , jsonNode );
278151 }
279152 }
280-
281- private ObjectNode mergeExtData (JsonNode fpdData , JsonNode originData ) {
282- if (fpdData .isMissingNode () || !fpdData .isObject ()) {
283- return originData != null && originData .isObject () ? ((ObjectNode ) originData ).deepCopy () : null ;
284- }
285-
286- if (originData != null && originData .isObject ()) {
287- return (ObjectNode ) jsonMerger .merge (fpdData , originData );
288- }
289- return fpdData .isObject () ? (ObjectNode ) fpdData : null ;
290- }
291-
292- private static void setAttr (ObjectNode source , ObjectNode dest , String fieldName ) {
293- final JsonNode field = source .get (fieldName );
294- if (field != null ) {
295- dest .set (fieldName , field );
296- }
297- }
298-
299- private static List <String > getStrings (JsonNode firstItem , String fieldName ) {
300- final JsonNode valueNode = firstItem .get (fieldName );
301- final ArrayNode arrayNode = valueNode != null && valueNode .isArray () ? (ArrayNode ) valueNode : null ;
302- return arrayNode != null && isTextualArray (arrayNode )
303- ? StreamSupport .stream (arrayNode .spliterator (), false )
304- .map (JsonNode ::asText )
305- .toList ()
306- : null ;
307- }
308-
309- private static boolean isTextualArray (ArrayNode arrayNode ) {
310- return StreamSupport .stream (arrayNode .spliterator (), false ).allMatch (JsonNode ::isTextual );
311- }
312-
313- private static String getString (ObjectNode firstItem , String fieldName ) {
314- return getValueFromJsonNode (firstItem , fieldName , JsonNode ::asText , JsonNode ::isTextual );
315- }
316-
317- private static Integer getInteger (ObjectNode firstItem , String fieldName ) {
318- return getValueFromJsonNode (firstItem , fieldName , JsonNode ::asInt , JsonNode ::isInt );
319- }
320-
321- private <T > List <T > toList (JsonNode node , TypeReference <List <T >> listTypeReference ) {
322- try {
323- return jacksonMapper .mapper ().convertValue (node , listTypeReference );
324- } catch (IllegalArgumentException e ) {
325- return null ;
326- }
327- }
328-
329- private static <T > T getValueFromJsonNode (ObjectNode firstItem , String fieldName ,
330- Function <JsonNode , T > nodeConverter ,
331- Predicate <JsonNode > isCorrectType ) {
332- final JsonNode valueNode = firstItem .get (fieldName );
333- return valueNode != null && isCorrectType .test (valueNode )
334- ? nodeConverter .apply (valueNode )
335- : null ;
336- }
337-
338153}
0 commit comments