1616 */
1717package org .apache .nifi .processors .box ;
1818
19- import com .box .sdk .BoxEvent ;
20- import com .eclipsesource .json .Json ;
21- import com .eclipsesource .json .JsonObject ;
19+ import com .box .sdkgen .schemas .event .Event ;
20+ import com .box .sdkgen .schemas .eventsource .EventSource ;
21+ import com .box .sdkgen .schemas .eventsourceresource .EventSourceResource ;
22+ import com .box .sdkgen .schemas .file .File ;
23+ import com .box .sdkgen .schemas .folder .Folder ;
24+ import com .box .sdkgen .schemas .foldermini .FolderMini ;
25+ import com .box .sdkgen .schemas .user .User ;
26+ import com .fasterxml .jackson .core .JsonFactory ;
27+ import com .fasterxml .jackson .core .JsonGenerator ;
28+ import com .fasterxml .jackson .databind .ObjectMapper ;
2229
2330import java .io .Closeable ;
2431import java .io .IOException ;
2532import java .io .OutputStream ;
26- import java .io .OutputStreamWriter ;
27- import java .io .Writer ;
28- import java .util .Objects ;
29-
30- import static java .nio .charset .StandardCharsets .UTF_8 ;
33+ import java .util .Map ;
3134
3235/**
33- * A class responsible for writing {@link BoxEvent } objects into a JSON array.
36+ * A class responsible for writing {@link Event } objects into a JSON array.
3437 * Not thread-safe.
3538 */
3639final class BoxEventJsonArrayWriter implements Closeable {
3740
38- private final Writer writer ;
41+ private static final JsonFactory JSON_FACTORY = new JsonFactory ();
42+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
43+ private final JsonGenerator generator ;
3944 private boolean hasBegun ;
40- private boolean hasEntries ;
4145 private boolean closed ;
4246
43- private BoxEventJsonArrayWriter (final Writer writer ) {
44- this .writer = writer ;
47+ private BoxEventJsonArrayWriter (final JsonGenerator generator ) {
48+ this .generator = generator ;
4549 this .hasBegun = false ;
46- this .hasEntries = false ;
4750 this .closed = false ;
4851 }
4952
5053 static BoxEventJsonArrayWriter create (final OutputStream outputStream ) throws IOException {
51- final Writer writer = new OutputStreamWriter (outputStream , UTF_8 );
52- return new BoxEventJsonArrayWriter (writer );
54+ final JsonGenerator generator = JSON_FACTORY . createGenerator (outputStream );
55+ return new BoxEventJsonArrayWriter (generator );
5356 }
5457
55- void write (final BoxEvent event ) throws IOException {
58+ void write (final Event event ) throws IOException {
5659 if (closed ) {
5760 throw new IOException ("The Writer is closed" );
5861 }
5962
6063 if (!hasBegun ) {
61- beginArray ();
64+ generator . writeStartArray ();
6265 hasBegun = true ;
6366 }
6467
65- if (hasEntries ) {
66- writer .write (',' );
68+ writeEvent (event );
69+ }
70+
71+ private void writeEvent (final Event event ) throws IOException {
72+ generator .writeStartObject ();
73+
74+ // Map Event fields to JSON using camelCase to match the original NiFi Box processor format
75+ writeStringField ("createdAt" , event .getCreatedAt () != null ? event .getCreatedAt ().toString () : null );
76+ writeStringField ("recordedAt" , event .getRecordedAt () != null ? event .getRecordedAt ().toString () : null );
77+ writeStringField ("eventType" , event .getEventType () != null ? event .getEventType ().getValue () : null );
78+ writeStringField ("id" , event .getEventId ());
79+ writeStringField ("sessionID" , event .getSessionId ());
80+ writeStringField ("type" , event .getType ());
81+
82+ // Handle createdBy if present (camelCase for field name, but inner fields match Box API)
83+ if (event .getCreatedBy () != null ) {
84+ generator .writeObjectFieldStart ("createdBy" );
85+ writeStringField ("id" , event .getCreatedBy ().getId ());
86+ writeStringField ("type" , event .getCreatedBy ().getType () != null ? event .getCreatedBy ().getType ().getValue () : null );
87+ writeStringField ("name" , event .getCreatedBy ().getName ());
88+ writeStringField ("login" , event .getCreatedBy ().getLogin ());
89+ generator .writeEndObject ();
90+ } else {
91+ generator .writeNullField ("createdBy" );
6792 }
6893
69- final JsonObject json = toRecord (event );
70- json .writeTo (writer );
94+ // Handle source if present - use snake_case for inner fields to match Box API format
95+ writeSource (event .getSource ());
96+
97+ // Handle additionalDetails if present - serialize as proper JSON object
98+ writeAdditionalDetails (event .getAdditionalDetails ());
7199
72- hasEntries = true ;
100+ generator . writeEndObject () ;
73101 }
74102
75- private JsonObject toRecord (final BoxEvent event ) {
76- final JsonObject json = Json .object ();
77-
78- json .add ("accessibleBy" , event .getAccessibleBy () == null ? Json .NULL : Json .parse (event .getAccessibleBy ().getJson ()));
79- json .add ("actionBy" , event .getActionBy () == null ? Json .NULL : Json .parse (event .getActionBy ().getJson ()));
80- json .add ("additionalDetails" , Objects .requireNonNullElse (event .getAdditionalDetails (), Json .NULL ));
81- json .add ("createdAt" , event .getCreatedAt () == null ? Json .NULL : Json .value (event .getCreatedAt ().toString ()));
82- json .add ("createdBy" , event .getCreatedBy () == null ? Json .NULL : Json .parse (event .getCreatedBy ().getJson ()));
83- json .add ("eventType" , event .getEventType () == null ? Json .NULL : Json .value (event .getEventType ().name ()));
84- json .add ("id" , Objects .requireNonNullElse (Json .value (event .getID ()), Json .NULL ));
85- json .add ("ipAddress" , Objects .requireNonNullElse (Json .value (event .getIPAddress ()), Json .NULL ));
86- json .add ("sessionID" , Objects .requireNonNullElse (Json .value (event .getSessionID ()), Json .NULL ));
87- json .add ("source" , Objects .requireNonNullElse (event .getSourceJSON (), Json .NULL ));
88- json .add ("typeName" , Objects .requireNonNullElse (Json .value (event .getTypeName ()), Json .NULL ));
89-
90- return json ;
103+ private void writeSource (final EventSourceResource source ) throws IOException {
104+ if (source == null ) {
105+ generator .writeNullField ("source" );
106+ return ;
107+ }
108+
109+ generator .writeObjectFieldStart ("source" );
110+ try {
111+ // EventSourceResource is a union type (OneOfSix) - check what kind of source we have
112+ if (source .isFile ()) {
113+ // File source - contains file_id, file_name, and parent folder info
114+ File file = source .getFile ();
115+ writeStringField ("item_type" , "file" );
116+ writeStringField ("item_id" , file .getId ());
117+ writeStringField ("item_name" , file .getName ());
118+ // Add file-specific fields for collaboration events
119+ writeStringField ("file_id" , file .getId ());
120+ writeStringField ("file_name" , file .getName ());
121+ // Add parent folder info if available
122+ FolderMini parent = file .getParent ();
123+ if (parent != null ) {
124+ writeStringField ("folder_id" , parent .getId ());
125+ writeStringField ("folder_name" , parent .getName ());
126+ }
127+ } else if (source .isFolder ()) {
128+ // Folder source - contains folder_id, folder_name
129+ Folder folder = source .getFolder ();
130+ writeStringField ("item_type" , "folder" );
131+ writeStringField ("item_id" , folder .getId ());
132+ writeStringField ("item_name" , folder .getName ());
133+ // Add folder-specific fields for collaboration events
134+ writeStringField ("folder_id" , folder .getId ());
135+ writeStringField ("folder_name" , folder .getName ());
136+ } else if (source .isEventSource ()) {
137+ // Generic EventSource - has item_type, item_id, item_name
138+ EventSource eventSource = source .getEventSource ();
139+ String itemType = eventSource .getItemType () != null ? eventSource .getItemType ().getValue () : null ;
140+ writeStringField ("item_type" , itemType );
141+ writeStringField ("item_id" , eventSource .getItemId ());
142+ writeStringField ("item_name" , eventSource .getItemName ());
143+ // For EventSource, also populate file/folder specific fields based on item_type
144+ if ("file" .equals (itemType )) {
145+ writeStringField ("file_id" , eventSource .getItemId ());
146+ writeStringField ("file_name" , eventSource .getItemName ());
147+ } else if ("folder" .equals (itemType )) {
148+ writeStringField ("folder_id" , eventSource .getItemId ());
149+ writeStringField ("folder_name" , eventSource .getItemName ());
150+ }
151+ // Add parent folder info if available
152+ FolderMini parent = eventSource .getParent ();
153+ if (parent != null ) {
154+ writeStringField ("parent_id" , parent .getId ());
155+ writeStringField ("parent_name" , parent .getName ());
156+ }
157+ } else if (source .isUser ()) {
158+ // User source
159+ User user = source .getUser ();
160+ writeStringField ("item_type" , "user" );
161+ writeStringField ("id" , user .getId ());
162+ writeStringField ("name" , user .getName ());
163+ writeStringField ("login" , user .getLogin ());
164+ } else if (source .isMap ()) {
165+ // Generic map - write all entries
166+ Map <String , Object > map = source .getMap ();
167+ for (Map .Entry <String , Object > entry : map .entrySet ()) {
168+ Object value = entry .getValue ();
169+ if (value != null ) {
170+ generator .writeFieldName (entry .getKey ());
171+ generator .writeObject (value );
172+ }
173+ }
174+ } else if (source .isAppItemEventSource ()) {
175+ // AppItemEventSource
176+ writeStringField ("item_type" , "app_item" );
177+ } else {
178+ writeStringField ("item_type" , "unknown" );
179+ }
180+ } catch (Exception e ) {
181+ writeStringField ("error" , "Could not serialize source: " + e .getMessage ());
182+ }
183+ generator .writeEndObject ();
91184 }
92185
93- private void beginArray () throws IOException {
94- writer .write ('[' );
186+ private void writeAdditionalDetails (final Map <String , Object > additionalDetails ) throws IOException {
187+ if (additionalDetails == null ) {
188+ generator .writeNullField ("additionalDetails" );
189+ return ;
190+ }
191+
192+ try {
193+ // Write additionalDetails as a proper JSON object, not a string
194+ generator .writeFieldName ("additionalDetails" );
195+ generator .writeStartObject ();
196+ for (Map .Entry <String , Object > entry : additionalDetails .entrySet ()) {
197+ String key = entry .getKey ();
198+ Object value = entry .getValue ();
199+ if (value == null ) {
200+ generator .writeNullField (key );
201+ } else if (value instanceof String ) {
202+ generator .writeStringField (key , (String ) value );
203+ } else if (value instanceof Number ) {
204+ generator .writeNumberField (key , ((Number ) value ).doubleValue ());
205+ } else if (value instanceof Boolean ) {
206+ generator .writeBooleanField (key , (Boolean ) value );
207+ } else if (value instanceof Map ) {
208+ // Nested map - use ObjectMapper to serialize
209+ generator .writeFieldName (key );
210+ generator .writeRawValue (OBJECT_MAPPER .writeValueAsString (value ));
211+ } else {
212+ // For other types, convert to string
213+ generator .writeStringField (key , value .toString ());
214+ }
215+ }
216+ generator .writeEndObject ();
217+ } catch (Exception e ) {
218+ generator .writeNullField ("additionalDetails" );
219+ }
95220 }
96221
97- private void endArray () throws IOException {
98- writer .write (']' );
222+ private void writeStringField (final String fieldName , final String value ) throws IOException {
223+ if (value != null ) {
224+ generator .writeStringField (fieldName , value );
225+ } else {
226+ generator .writeNullField (fieldName );
227+ }
99228 }
100229
101230 @ Override
@@ -107,10 +236,10 @@ public void close() throws IOException {
107236 closed = true ;
108237
109238 if (!hasBegun ) {
110- beginArray ();
239+ generator . writeStartArray ();
111240 }
112- endArray ();
241+ generator . writeEndArray ();
113242
114- writer .close ();
243+ generator .close ();
115244 }
116245}
0 commit comments