1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.notificationstore.service;
35
36 import com.fasterxml.jackson.core.JsonParseException;
37 import com.fasterxml.jackson.core.JsonProcessingException;
38 import com.fasterxml.jackson.databind.DeserializationFeature;
39 import com.fasterxml.jackson.databind.JsonMappingException;
40 import com.fasterxml.jackson.databind.ObjectMapper;
41 import fr.paris.lutece.plugins.grubusiness.business.customer.Customer;
42 import fr.paris.lutece.plugins.grubusiness.business.demand.Demand;
43 import fr.paris.lutece.plugins.grubusiness.business.demand.IDemandServiceProvider;
44 import fr.paris.lutece.plugins.grubusiness.business.demand.TemporaryStatus;
45 import fr.paris.lutece.plugins.grubusiness.business.notification.*;
46 import fr.paris.lutece.plugins.grubusiness.business.web.rs.EnumGenericStatus;
47 import fr.paris.lutece.plugins.grubusiness.service.notification.INotifierServiceProvider;
48 import fr.paris.lutece.plugins.grubusiness.service.notification.NotificationException;
49 import fr.paris.lutece.plugins.identitystore.web.exception.IdentityStoreException;
50 import fr.paris.lutece.plugins.notificationstore.business.DemandHome;
51 import fr.paris.lutece.plugins.notificationstore.business.NotificationHome;
52 import fr.paris.lutece.plugins.notificationstore.utils.NotificationStoreConstants;
53 import fr.paris.lutece.portal.service.spring.SpringContextService;
54 import fr.paris.lutece.portal.service.util.AppLogService;
55 import fr.paris.lutece.portal.service.util.AppPropertiesService;
56 import org.apache.commons.lang3.StringUtils;
57
58 import javax.ws.rs.core.Response;
59 import javax.ws.rs.core.Response.Status;
60 import java.io.IOException;
61 import java.time.Instant;
62 import java.time.LocalDateTime;
63 import java.time.ZoneId;
64 import java.time.format.DateTimeFormatter;
65 import java.util.ArrayList;
66 import java.util.List;
67 import java.util.Optional;
68
69 public class NotificationService
70 {
71
72
73 private static final String BEAN_STORAGE_SERVICE = "notificationstore.demandService";
74
75
76 private static final String RESPONSE_OK = "{ \"acknowledge\" : { \"status\": \"received\" } }";
77
78 private static final String TYPE_DEMAND = "DEMAND";
79 private static final String TYPE_NOTIFICATION = "NOTIFICATION";
80 private static final String STATUS_WARNING = "WARNING";
81 private static final String STATUS_ERROR = "ERROR";
82 private static final String STATUS_FAILED = "FAILED";
83 private static final String STATUS_SUCCESS = "SUCCESS";
84
85 private static final String TYPE_NOTIFICATION_GUICHET = "GUICHET";
86 private static final String TYPE_NOTIFICATION_AGENT = "AGENT";
87 private static final String TYPE_MERGE_NOTIFICATIONS = "MERGE";
88
89
90 private static final String WARNING_DEMAND_ID_MANDATORY = "Notification Demand_id field is mandatory";
91 private static final String WARNING_DEMAND_TYPE_ID_MANDATORY = "Notification Demand_type_id field is mandatory";
92 private static final String WARNING_CUSTOMER_IDS_MANDATORY = "Valid user connection id or customer id is mandatory";
93 private static final String WARNING_CUSTOMER_NOT_FOUND = "User not found in the identityStore";
94 private static final String ERROR_IDENTITYSTORE = "An error occured while retrieving user from identityStore";
95 private static final String MESSAGE_MISSING_MANDATORY_FIELD = "Missing value";
96 private static final String MESSAGE_MISSING_DEMAND_ID = "Demand Id and Demand type Id are mandatory";
97 private static final String MESSAGE_MISSING_USER_ID = "Valid user connection id or customer id is mandatory";
98 private static final String MESSAGE_INCORRECT_USER = "Incorrect User Ids";
99 private static final String WARNING_INCORRECT_DEMAND_TYPE_ID = "Demand Type Id not found";
100
101 private static final String PROPERTY_STORE_EVEN_CUSTOMER_ID_NOT_EXISTS = "notificationstore.notification.store.storeEventCustomerIdDoesNotExists";
102
103
104 private static IDemandServiceProvider _demandService;
105 private static NotificationService _instance;
106 private static List<INotifierServiceProvider> _notifiers;
107
108 private static ObjectMapper _mapper = new ObjectMapper( );
109
110
111
112
113 private NotificationService( )
114 {
115 }
116
117
118
119
120
121
122 public static NotificationService instance( )
123 {
124 if ( _instance == null )
125 {
126 _instance = new NotificationService( );
127 _demandService = SpringContextService.getBean( BEAN_STORAGE_SERVICE );
128 _notifiers = SpringContextService.getBeansOfType( INotifierServiceProvider.class );
129
130 _mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
131 _mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
132 }
133
134 return _instance;
135 }
136
137
138
139
140
141
142 public Response newNotification( String strJson )
143 {
144 List<StatusMessage> warnings = new ArrayList<>( );
145
146 try
147 {
148
149 Notification notification = getNotificationFromJson( strJson );
150
151
152 boolean customerExists = processCustomer( notification, warnings );
153
154
155 checkNotification( notification, warnings );
156
157
158
159
160 boolean storeEvenCustomerIfNotExists = AppPropertiesService.getPropertyBoolean( PROPERTY_STORE_EVEN_CUSTOMER_ID_NOT_EXISTS, false );
161 boolean customerIdNotEmpty = notification.getDemand( ).getCustomer( ) != null
162 && !StringUtils.isEmpty( notification.getDemand( ).getCustomer( ).getCustomerId( ) );
163
164 if ( customerIdNotEmpty && ( customerExists || storeEvenCustomerIfNotExists ) )
165 {
166 store( notification );
167 }
168
169
170 addEvents( notification, warnings );
171
172
173 forward( notification );
174
175 }
176 catch( JsonParseException ex )
177 {
178 return fail( ex, Response.Status.BAD_REQUEST );
179 }
180 catch( JsonMappingException | NullPointerException | NotificationException ex )
181 {
182 return fail( ex, Response.Status.BAD_REQUEST );
183 }
184 catch( IOException ex )
185 {
186 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
187 }
188 catch( IdentityStoreException ex )
189 {
190 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
191 }
192 catch( Exception ex )
193 {
194 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
195 }
196
197
198 if ( warnings.isEmpty( ) )
199 {
200 return success( );
201 }
202 else
203 {
204 return successWithWarnings( warnings );
205 }
206 }
207
208
209
210
211
212
213
214 private void checkNotification( Notification notification, List<StatusMessage> warnings )
215 {
216
217 if ( StringUtils.isBlank( notification.getDemand( ).getId( ) ) )
218 {
219 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_MANDATORY_FIELD, WARNING_DEMAND_ID_MANDATORY );
220 warnings.add( msg );
221 }
222
223
224 if ( StringUtils.isBlank( notification.getDemand( ).getTypeId( ) ) )
225 {
226 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_MANDATORY_FIELD, WARNING_DEMAND_TYPE_ID_MANDATORY );
227 warnings.add( msg );
228 }
229
230
231 if ( !_demandService.getDemandType( notification.getDemand( ).getTypeId( ) ).isPresent( ) )
232 {
233 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_DEMAND_ID, WARNING_INCORRECT_DEMAND_TYPE_ID );
234 warnings.add( msg );
235 }
236 }
237
238
239
240
241
242
243
244
245 private boolean processCustomer( Notification notification, List<StatusMessage> warnings ) throws IdentityStoreException
246 {
247
248 Customer customer = CustomerProvider.instance( ).decrypt( notification.getDemand( ) );
249
250
251 if ( AppPropertiesService.getPropertyBoolean( NotificationStoreConstants.PROPERTY_CONSIDER_GUID_AS_CUSTOMER_ID, false )
252 && StringUtils.isEmpty( customer.getId( ) ) && StringUtils.isEmpty( customer.getCustomerId( ) )
253 && !StringUtils.isEmpty( customer.getConnectionId( ) ) )
254 {
255 customer.setCustomerId( customer.getConnectionId( ) );
256 }
257
258
259 if ( CustomerProvider.instance( ).hasIdentityService( ) )
260 {
261
262 if ( customer == null || ( !CustomerProvider.isCustomerIdValid( customer.getCustomerId( ) )
263 && !CustomerProvider.isCustomerIdValid( customer.getId( ) ) && !CustomerProvider.isConnectionIdValid( customer.getConnectionId( ) ) ) )
264 {
265 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_INCORRECT_USER, WARNING_CUSTOMER_IDS_MANDATORY );
266 warnings.add( msg );
267 return false;
268 }
269
270
271 if ( !CustomerProvider.isCustomerIdValid( customer.getCustomerId( ) ) && CustomerProvider.isCustomerIdValid( customer.getId( ) ) )
272 {
273 customer.setCustomerId( customer.getId( ) );
274 }
275
276 try
277 {
278
279 Customer customerResult = CustomerProvider.instance( ).get( customer.getConnectionId( ), customer.getCustomerId( ) );
280 if ( customerResult != null )
281 {
282
283 customer.setCustomerId( customerResult.getCustomerId( ) );
284 }
285 else
286 {
287
288
289 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_INCORRECT_USER, WARNING_CUSTOMER_NOT_FOUND );
290 warnings.add( msg );
291 return false;
292 }
293 }
294 catch( Exception e )
295 {
296 customer = null;
297 AppLogService.error( "An error occured while accessing IdentityStore", e );
298 StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_ERROR, MESSAGE_INCORRECT_USER, ERROR_IDENTITYSTORE );
299 warnings.add( msg );
300
301 throw new IdentityStoreException( "An error occured while accessing IdentityStore", e );
302 }
303 }
304
305
306
307
308
309
310 notification.getDemand( ).setCustomer( customer );
311
312
313 return true;
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 public Notification getNotification( final String idDemand, final String idDemandType, final String customerId, final String notificationType,
332 final long notificationDate )
333 {
334
335 NotificationFilter filter = new NotificationFilter( );
336 filter.setDemandId( idDemand );
337 filter.setCustomerId( customerId );
338 filter.setDemandTypeId( idDemandType );
339 filter.setStartDate( notificationDate );
340 filter.setEndDate( notificationDate );
341 filter.getListNotificationType( ).add( EnumNotificationType.valueOf( notificationType ) );
342
343 return NotificationHome.findByFilter( filter ).stream( ).findFirst( ).orElse( null );
344
345 }
346
347
348
349
350
351
352
353 public Response reassignNotifications( String strJson )
354 {
355 try
356 {
357 _mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, false );
358 ReassignNotificationsRequest request = _mapper.readValue( strJson, ReassignNotificationsRequest.class );
359 _mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
360
361 AppLogService.debug( "notificationstore / ReassignNotificationsRequest - Received strJson : " + strJson );
362
363 if ( !CustomerProvider.isCustomerIdValid( request.getOldCustomerId( ) ) || !CustomerProvider.isCustomerIdValid( request.getNewCustomerId( ) ) )
364 {
365 return fail( new Exception( "Invalid CUIDs" ), Response.Status.BAD_REQUEST );
366 }
367
368 NotificationFilter filter = new NotificationFilter( );
369 filter.setCustomerId( request.getOldCustomerId( ) );
370 List<Notification> listNotifsToReassign = NotificationHome.getByFilter( filter );
371
372 if ( listNotifsToReassign.size( ) == 0 )
373 {
374 return ok( );
375 }
376
377 DemandHome.reassignDemands( request.getOldCustomerId( ), request.getNewCustomerId( ) );
378 NotificationHome.reassignNotifications( request.getOldCustomerId( ), request.getNewCustomerId( ) );
379
380
381 for ( Notification notif : listNotifsToReassign )
382 {
383 notif.getDemand( ).getCustomer( ).setCustomerId( request.getNewCustomerId( ) );
384 addMergeEvent( notif, request );
385 }
386 }
387 catch( JsonParseException ex )
388 {
389 return fail( ex, Response.Status.BAD_REQUEST );
390 }
391 catch( JsonMappingException | NullPointerException ex )
392 {
393 return fail( ex, Response.Status.BAD_REQUEST );
394 }
395 catch( IOException ex )
396 {
397 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
398 }
399 catch( Exception ex )
400 {
401 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
402 }
403 return success( );
404 }
405
406
407
408
409
410
411
412 public Response newNotificationEvent( String strJson )
413 {
414 try
415 {
416 NotificationEvent notificationEvent = _mapper.readValue( strJson, NotificationEvent.class );
417 AppLogService.debug( "notificationstore / notificationEvent - Received strJson : " + strJson );
418
419 store( notificationEvent );
420
421 }
422 catch( JsonParseException ex )
423 {
424 return fail( ex, Response.Status.BAD_REQUEST );
425 }
426 catch( JsonMappingException | NullPointerException ex )
427 {
428 return fail( ex, Response.Status.BAD_REQUEST );
429 }
430 catch( IOException ex )
431 {
432 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
433 }
434 catch( Exception ex )
435 {
436 return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
437 }
438
439 return success( );
440
441 }
442
443
444
445
446
447
448
449 private void store( NotificationEvent notificationEvent )
450 {
451
452
453 if ( notificationEvent.getDemand( ) != null && notificationEvent.getDemand( ).getCustomer( ) != null
454 && !CustomerProvider.isCustomerIdValid( notificationEvent.getDemand( ).getCustomer( ).getCustomerId( ) )
455 && CustomerProvider.isCustomerIdValid( notificationEvent.getDemand( ).getCustomer( ).getId( ) ) )
456 {
457 notificationEvent.getDemand( ).getCustomer( ).setCustomerId( notificationEvent.getDemand( ).getCustomer( ).getId( ) );
458 }
459
460 _demandService.create( notificationEvent );
461 }
462
463
464
465
466
467
468
469 private void store( Notification notification )
470 {
471 Demand demand = _demandService.findByPrimaryKey( notification.getDemand( ).getId( ), notification.getDemand( ).getTypeId( ),
472 notification.getDemand( ).getCustomer( ).getCustomerId( ) );
473
474 if ( demand == null || ( demand.getCustomer( ) != null && demand.getCustomer( ).getCustomerId( ) != null
475 && !demand.getCustomer( ).getCustomerId( ).equals( notification.getDemand( ).getCustomer( ).getCustomerId( ) ) ) )
476 {
477 demand = new Demand( );
478
479 demand.setId( notification.getDemand( ).getId( ) );
480 demand.setTypeId( notification.getDemand( ).getTypeId( ) );
481 demand.setSubtypeId( notification.getDemand( ).getSubtypeId( ) );
482 demand.setReference( notification.getDemand( ).getReference( ) );
483 demand.setCreationDate( notification.getDate( ) );
484 demand.setMaxSteps( notification.getDemand( ).getMaxSteps( ) );
485 demand.setCurrentStep( notification.getDemand( ).getCurrentStep( ) );
486 demand.setStatusId( getNewDemandStatusIdFromNotification( notification ) );
487 demand.setMetaData( notification.getDemand( ).getMetaData( ) );
488
489 Customer customerDemand = new Customer( );
490 customerDemand.setCustomerId( notification.getDemand( ).getCustomer( ).getId( ) );
491 customerDemand.setCustomerId( notification.getDemand( ).getCustomer( ).getCustomerId( ) );
492 customerDemand.setConnectionId( notification.getDemand( ).getCustomer( ).getConnectionId( ) );
493 demand.setCustomer( customerDemand );
494
495
496 _demandService.create( demand );
497 }
498 else
499 {
500
501 demand.setCurrentStep( notification.getDemand( ).getCurrentStep( ) );
502
503 demand.setModifyDate( notification.getDate( ) );
504
505 int nNewStatusId = getNewDemandStatusIdFromNotification( notification );
506
507 demand.setStatusId( nNewStatusId );
508
509 EnumGenericStatus oldStatus = EnumGenericStatus.getByStatusId( demand.getStatusId( ) );
510 EnumGenericStatus newStatus = EnumGenericStatus.getByStatusId( nNewStatusId );
511
512
513 if ( oldStatus != null && newStatus != null && !oldStatus.isFinalStatus( ) && newStatus.isFinalStatus( ) )
514 {
515 demand.setClosureDate( notification.getDate( ) );
516 }
517
518
519 if ( oldStatus != null && newStatus != null && oldStatus.isFinalStatus( ) && !newStatus.isFinalStatus( ) )
520 {
521 demand.setClosureDate( 0 );
522 }
523
524 _demandService.update( demand );
525 }
526 notification.setDemand( demand );
527
528
529 _demandService.create( notification );
530 }
531
532
533
534
535
536
537
538
539 private void addEvents( Notification notification, List<StatusMessage> warnings )
540 {
541
542 if ( warnings.isEmpty( ) )
543 {
544 return;
545 }
546
547 Event event = new Event( );
548 event.setEventDate( notification.getDate( ) );
549
550 if ( notification.getMyDashboardNotification( ) != null )
551 {
552 event.setType( TYPE_NOTIFICATION_GUICHET );
553 }
554 else
555 {
556 event.setType( TYPE_NOTIFICATION_AGENT );
557 }
558
559 event.setMessage( generateEventMessage( notification, warnings ) );
560 event.setStatus( STATUS_FAILED );
561
562 NotificationEvent notificationEvent = new NotificationEvent( );
563 notificationEvent.setEvent( event );
564 notificationEvent.setMsgId( StringUtils.EMPTY );
565 notificationEvent.setDemand( notification.getDemand( ) );
566 notificationEvent.setNotificationDate( notification.getDate( ) );
567
568 store( notificationEvent );
569 }
570
571
572
573
574
575
576
577
578 private void addMergeEvent( Notification notification, ReassignNotificationsRequest request )
579 {
580 Event event = new Event( );
581 event.setEventDate( notification.getDate( ) );
582
583 event.setType( TYPE_MERGE_NOTIFICATIONS );
584
585 event.setMessage( "Merged CUID : " + request.getOldCustomerId( ) + "\nConsolidated CUID : " + request.getNewCustomerId( ) );
586 event.setStatus( STATUS_WARNING );
587
588 NotificationEvent notificationEvent = new NotificationEvent( );
589 notificationEvent.setEvent( event );
590 notificationEvent.setMsgId( StringUtils.EMPTY );
591 notificationEvent.setDemand( notification.getDemand( ) );
592 notificationEvent.setNotificationDate( notification.getDate( ) );
593
594 store( notificationEvent );
595 }
596
597
598
599
600
601
602
603
604
605
606 private Response successWithWarnings( List<StatusMessage> warnings )
607 {
608 StringBuilder strWarnings = new StringBuilder( "[" );
609
610 if ( warnings != null )
611 {
612 for ( StatusMessage msg : warnings )
613 {
614 strWarnings.append( msg.asJson( ) ).append( "," );
615 }
616
617
618 strWarnings.setLength( strWarnings.length( ) - 1 );
619 }
620
621 strWarnings.append( "]" );
622
623 String strResponse = "{ \"acknowledge\" : { \"status\": \"warning\", \"warnings\" : " + strWarnings.toString( ) + " } }";
624
625 return Response.status( Response.Status.CREATED ).entity( strResponse ).build( );
626 }
627
628
629
630
631
632
633 private Response success( )
634 {
635 return Response.status( Response.Status.CREATED ).entity( RESPONSE_OK ).build( );
636 }
637
638
639
640
641
642
643 private Response ok( )
644 {
645 return Response.status( Response.Status.OK ).entity( RESPONSE_OK ).build( );
646 }
647
648
649
650
651
652
653
654
655
656
657 private Response fail( Throwable ex, Status httpStatus )
658 {
659 StringBuilder strMsg = new StringBuilder( "[" );
660
661 if ( ex != null )
662 {
663 AppLogService.error( ex.getMessage( ), ex );
664 strMsg.append( new StatusMessage( TYPE_NOTIFICATION, STATUS_ERROR, ex.toString( ), ex.getMessage( ) ).asJson( ) );
665 }
666
667 strMsg.append( "]" );
668 String strError = "{ \"acknowledge\" : { \"status\": \"error\", \"errors\" : " + strMsg + " } }";
669
670 return Response.status( httpStatus ).entity( strError ).build( );
671 }
672
673
674
675
676
677
678
679
680
681 private String generateEventMessage( Notification notification, List<StatusMessage> warnings )
682 {
683 StringBuilder message = new StringBuilder( );
684 message.append( "WARNINGS\n" );
685 message.append( "\n" );
686 message.append( "Demande id : " ).append( notification.getDemand( ).getId( ) ).append( "\n" );
687 message.append( "Demande Type id : " ).append( notification.getDemand( ).getTypeId( ) ).append( "\n" );
688 message.append( "Notification date : " ).append( Instant.ofEpochSecond( notification.getDate( ) ) ).append( "\n" );
689 message.append( "\n" );
690
691 if ( notification.getDemand( ).getCustomer( ) != null )
692 {
693 message.append( "Customer id: " ).append( notification.getDemand( ).getCustomer( ).getCustomerId( ) ).append( "\n" );
694 message.append( "Connection id: " ).append( notification.getDemand( ).getCustomer( ).getConnectionId( ) ).append( "\n" );
695 }
696 message.append( "-------------------------\n" );
697
698 for ( StatusMessage s : warnings )
699 {
700 message.append( "Type : " ).append( s.getType( ) ).append( "\n" );
701 message.append( "Status : " ).append( s.getStatus( ) ).append( "\n" );
702 message.append( "Message : " ).append( s.getStrMessage( ) ).append( "\n" );
703 message.append( "Reason : " ).append( s.getReason( ) ).append( "\n" );
704 message.append( "-------------------------\n" );
705
706 }
707
708 return message.toString( );
709 }
710
711
712
713
714
715
716
717 private int getNewDemandStatusIdFromNotification( Notification notification )
718 {
719
720 if ( notification.getDemand( ) != null && notification.getDemand( ).getStatusId( ) > 0
721 && EnumGenericStatus.exists( notification.getDemand( ).getStatusId( ) ) )
722 {
723 return notification.getDemand( ).getStatusId( );
724 }
725
726
727 if ( notification.getMyDashboardNotification( ) != null )
728 {
729 if ( notification.getMyDashboardNotification( ).getStatusId( ) > 0
730 && EnumGenericStatus.exists( notification.getMyDashboardNotification( ).getStatusId( ) ) )
731 {
732 return notification.getMyDashboardNotification( ).getStatusId( );
733 }
734
735
736 Optional<TemporaryStatus> status = _demandService.getStatusByLabel( notification.getMyDashboardNotification( ).getStatusText( ) );
737 if ( status.isPresent( ) && status.get( ).getGenericStatus( ) != null )
738 {
739 return status.get( ).getGenericStatus( ).getStatusId( );
740 }
741 }
742
743
744 return -1;
745 }
746
747
748
749
750
751
752
753
754
755 private Notification getNotificationFromJson( String strJson ) throws JsonMappingException, JsonProcessingException
756 {
757 AppLogService.debug( "notificationstore / notification - Received strJson : " + strJson );
758
759
760 ObjectMapper mapper = new ObjectMapper( );
761 mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
762 mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
763
764 Notification notification = mapper.readValue( strJson, Notification.class );
765
766 return notification;
767 }
768
769
770
771
772
773
774
775 public void forward( Notification notification ) throws NotificationException
776 {
777
778 for ( INotifierServiceProvider notifier : _notifiers )
779 {
780 notifier.process( notification );
781 }
782
783 }
784 }