2 * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include "StandardMetaDataJsonEventListener.h"
10 #define KEY_CREATE_TIMESTAMP "createTimestamp"
11 #define KEY_DATA_MODIFIED_TIMESTAMP "dataModifiedTimestamp"
14 class SmdStackedEventListener
: public BJsonEventListener
{
16 SmdStackedEventListener(
17 StandardMetaDataJsonEventListener
*
19 SmdStackedEventListener
* parent
);
20 ~SmdStackedEventListener();
22 void HandleError(status_t status
, int32 line
,
26 status_t
ErrorStatus();
28 SmdStackedEventListener
*
34 void SetStackedListenerMainListener(
35 SmdStackedEventListener
* stackedListener
);
37 StandardMetaDataJsonEventListener
*
39 SmdStackedEventListener
*
44 class SmdStackedArrayEventListener
: public SmdStackedEventListener
{
46 SmdStackedArrayEventListener(
47 StandardMetaDataJsonEventListener
*
49 SmdStackedEventListener
* parent
);
50 ~SmdStackedArrayEventListener();
52 bool Handle(const BJsonEvent
& event
);
57 class SmdStackedObjectMessageEventListener
: public SmdStackedEventListener
{
59 SmdStackedObjectMessageEventListener(
60 BStringList
* jsonPathObjectNames
,
61 StandardMetaDataJsonEventListener
*
63 SmdStackedEventListener
* parent
);
64 ~SmdStackedObjectMessageEventListener();
66 bool Handle(const BJsonEvent
& event
);
69 BStringList
* fJsonPathObjectNames
;
70 BString fNextItemName
;
74 // #pragma mark - SmdStackedEventListener
76 SmdStackedEventListener::SmdStackedEventListener(
77 StandardMetaDataJsonEventListener
* mainListener
,
78 SmdStackedEventListener
* parent
)
80 fMainListener
= mainListener
;
85 SmdStackedEventListener::~SmdStackedEventListener()
91 SmdStackedEventListener::HandleError(status_t status
, int32 line
,
94 fMainListener
->HandleError(status
, line
, message
);
99 SmdStackedEventListener::Complete()
101 fMainListener
->Complete();
106 SmdStackedEventListener::ErrorStatus()
108 return fMainListener
->ErrorStatus();
113 SmdStackedEventListener::MetaData()
115 return fMainListener
->MetaData();
119 SmdStackedEventListener
*
120 SmdStackedEventListener::Parent()
127 SmdStackedEventListener::SetStackedListenerMainListener(
128 SmdStackedEventListener
* stackedListener
)
130 fMainListener
->SetStackedListener(stackedListener
);
134 // #pragma mark - SmdStackedArrayEventListener
137 SmdStackedArrayEventListener::SmdStackedArrayEventListener(
138 StandardMetaDataJsonEventListener
* mainListener
,
139 SmdStackedEventListener
* parent
)
141 SmdStackedEventListener(mainListener
, parent
)
146 SmdStackedArrayEventListener::~SmdStackedArrayEventListener()
152 SmdStackedArrayEventListener::Handle(const BJsonEvent
& event
)
154 if (ErrorStatus() != B_OK
)
157 switch (event
.EventType()) {
164 // ignore these atomic types in an array.
167 case B_JSON_OBJECT_START
:
168 SetStackedListenerMainListener(
169 new SmdStackedObjectMessageEventListener(NULL
, fMainListener
,
173 case B_JSON_ARRAY_START
:
174 SetStackedListenerMainListener(new SmdStackedArrayEventListener(
175 fMainListener
, this));
178 case B_JSON_ARRAY_END
:
179 SetStackedListenerMainListener(fParent
);
183 case B_JSON_OBJECT_END
:
184 case B_JSON_OBJECT_NAME
:
185 HandleError(B_NOT_ALLOWED
, JSON_EVENT_LISTENER_ANY_LINE
,
186 "illegal state when processing events in an array");
194 // #pragma mark - SmdStackedObjectMessageEventListener
196 SmdStackedObjectMessageEventListener::SmdStackedObjectMessageEventListener(
197 BStringList
* jsonPathObjectNames
,
198 StandardMetaDataJsonEventListener
* mainListener
,
199 SmdStackedEventListener
* parent
)
201 SmdStackedEventListener(mainListener
, parent
)
203 fJsonPathObjectNames
= jsonPathObjectNames
;
207 SmdStackedObjectMessageEventListener::~SmdStackedObjectMessageEventListener()
209 if (fJsonPathObjectNames
!= NULL
)
210 delete fJsonPathObjectNames
;
215 SmdStackedObjectMessageEventListener::Handle(const BJsonEvent
& event
)
217 if (ErrorStatus() != B_OK
)
220 switch (event
.EventType()) {
222 case B_JSON_OBJECT_NAME
:
223 fNextItemName
= event
.Content();
227 if (fJsonPathObjectNames
!= NULL
228 && fJsonPathObjectNames
->IsEmpty()) {
230 if (fNextItemName
== KEY_CREATE_TIMESTAMP
) {
231 MetaData()->SetCreateTimestamp(
232 event
.ContentInteger());
235 if (fNextItemName
== KEY_DATA_MODIFIED_TIMESTAMP
) {
236 MetaData()->SetDataModifiedTimestamp(
237 event
.ContentInteger());
246 // ignore these atomic types as they are not required to fill the
250 case B_JSON_OBJECT_START
:
252 BStringList
* nextJsonPathObjectNames
= NULL
;
254 // if this next object is on the path then remove it from the
255 // path and carry on down. If it's not on the path then just
256 // drop the path from the next object.
258 if (fJsonPathObjectNames
!= NULL
259 && !fJsonPathObjectNames
->IsEmpty()
260 && fNextItemName
== fJsonPathObjectNames
->StringAt(0)) {
261 nextJsonPathObjectNames
= new BStringList(*fJsonPathObjectNames
);
262 nextJsonPathObjectNames
->Remove(0);
265 SetStackedListenerMainListener(
266 new SmdStackedObjectMessageEventListener(nextJsonPathObjectNames
,
267 fMainListener
, this));
271 case B_JSON_ARRAY_START
:
272 SetStackedListenerMainListener(new SmdStackedArrayEventListener(
273 fMainListener
, this));
276 case B_JSON_OBJECT_END
:
277 SetStackedListenerMainListener(fParent
);
281 case B_JSON_ARRAY_END
:
282 HandleError(B_NOT_ALLOWED
, JSON_EVENT_LISTENER_ANY_LINE
,
283 "illegal state when processing events in an array");
291 // #pragma mark - StandardMetaDataJsonEventListener
294 StandardMetaDataJsonEventListener::StandardMetaDataJsonEventListener(
295 const BString
& jsonPath
,
296 StandardMetaData
& metaData
)
298 fMetaData
= &metaData
;
299 SetJsonPath(jsonPath
);
301 fStackedListener
= NULL
;
305 StandardMetaDataJsonEventListener::~StandardMetaDataJsonEventListener()
307 if (fStackedListener
!= NULL
)
308 delete fStackedListener
;
313 StandardMetaDataJsonEventListener::SetJsonPath(const BString
& jsonPath
)
315 jsonPath
.Split(".", true, fJsonPathObjectNames
);
317 if (fJsonPathObjectNames
.IsEmpty()) {
318 HandleError(B_BAD_VALUE
, JSON_EVENT_LISTENER_ANY_LINE
,
319 "json path required");
321 if (fJsonPathObjectNames
.First() != "$") {
322 HandleError(B_BAD_VALUE
, JSON_EVENT_LISTENER_ANY_LINE
,
323 "illegal json path; should start with '$");
330 StandardMetaDataJsonEventListener::SetStackedListener(
331 SmdStackedEventListener
*listener
)
333 fStackedListener
= listener
;
338 StandardMetaDataJsonEventListener::Handle(const BJsonEvent
& event
)
340 if (fErrorStatus
!= B_OK
)
343 // best to exit early if the parsing has obtained all of the required
346 if (fMetaData
->IsPopulated())
349 if (fStackedListener
!= NULL
)
350 return fStackedListener
->Handle(event
);
352 // the first thing that comes in must be an object container. It is
353 // bad data if it does not start with an object container.
355 switch (event
.EventType()) {
357 case B_JSON_OBJECT_START
:
359 BStringList
* jsonPathObjectNames
= new BStringList(
360 fJsonPathObjectNames
);
361 jsonPathObjectNames
->Remove(0);
364 new SmdStackedObjectMessageEventListener(
365 jsonPathObjectNames
, this, NULL
)
371 HandleError(B_BAD_DATA
, JSON_EVENT_LISTENER_ANY_LINE
,
372 "the top level element must be an object");
382 StandardMetaDataJsonEventListener::HandleError(status_t status
, int32 line
,
385 fprintf(stderr
, "an error has arisen processing the standard "
386 "meta data; %s\n", message
);
387 fErrorStatus
= status
;
392 StandardMetaDataJsonEventListener::Complete()
398 StandardMetaDataJsonEventListener::ErrorStatus()
405 StandardMetaDataJsonEventListener::MetaData()