NotificationService.java
/*
* Copyright (c) 2002-2025, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.plugins.notificationstore.service;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import fr.paris.lutece.plugins.grubusiness.business.notification.ReassignNotificationsRequest;
import fr.paris.lutece.plugins.notificationstore.business.DemandHome;
import fr.paris.lutece.plugins.notificationstore.business.NotificationHome;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.paris.lutece.plugins.grubusiness.business.customer.Customer;
import fr.paris.lutece.plugins.grubusiness.business.demand.Demand;
import fr.paris.lutece.plugins.grubusiness.business.demand.IDemandServiceProvider;
import fr.paris.lutece.plugins.grubusiness.business.demand.TemporaryStatus;
import fr.paris.lutece.plugins.grubusiness.business.notification.Event;
import fr.paris.lutece.plugins.grubusiness.business.notification.Notification;
import fr.paris.lutece.plugins.grubusiness.business.notification.NotificationEvent;
import fr.paris.lutece.plugins.grubusiness.business.notification.NotificationFilter;
import fr.paris.lutece.plugins.grubusiness.business.notification.StatusMessage;
import fr.paris.lutece.plugins.grubusiness.business.web.rs.EnumGenericStatus;
import fr.paris.lutece.plugins.grubusiness.service.notification.INotifyerServiceProvider;
import fr.paris.lutece.plugins.grubusiness.service.notification.NotificationException;
import fr.paris.lutece.plugins.identitystore.web.exception.IdentityStoreException;
import fr.paris.lutece.plugins.notificationstore.utils.NotificationStoreConstants;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
public class NotificationService
{
// Bean names
private static final String BEAN_STORAGE_SERVICE = "notificationstore.demandService";
// Other constants
private static final String RESPONSE_OK = "{ \"acknowledge\" : { \"status\": \"received\" } }";
private static final String TYPE_DEMAND = "DEMAND";
private static final String TYPE_NOTIFICATION = "NOTIFICATION";
private static final String STATUS_WARNING = "WARNING";
private static final String STATUS_ERROR = "ERROR";
private static final String STATUS_FAILED = "FAILED";
private static final String STATUS_SUCCESS = "SUCCESS";
private static final String TYPE_NOTIFICATION_GUICHET = "GUICHET";
private static final String TYPE_NOTIFICATION_AGENT = "AGENT";
private static final String TYPE_MERGE_NOTIFICATIONS = "MERGE";
// Messages
private static final String WARNING_DEMAND_ID_MANDATORY = "Notification Demand_id field is mandatory";
private static final String WARNING_DEMAND_TYPE_ID_MANDATORY = "Notification Demand_type_id field is mandatory";
private static final String WARNING_CUSTOMER_IDS_MANDATORY = "Valid user connection id or customer id is mandatory";
private static final String WARNING_CUSTOMER_NOT_FOUND = "User not found in the identityStore";
private static final String ERROR_IDENTITYSTORE = "An error occured while retrieving user from identityStore";
private static final String MESSAGE_MISSING_MANDATORY_FIELD = "Missing value";
private static final String MESSAGE_MISSING_DEMAND_ID = "Demand Id and Demand type Id are mandatory";
private static final String MESSAGE_MISSING_USER_ID = "Valid user connection id or customer id is mandatory";
private static final String MESSAGE_INCORRECT_USER = "Incorrect User Ids";
private static final String WARNING_INCORRECT_DEMAND_TYPE_ID = "Demand Type Id not found";
// instance variables
private static IDemandServiceProvider _demandService;
private static NotificationService _instance;
private static List<INotifyerServiceProvider> _notifyers;
private static ObjectMapper _mapper = new ObjectMapper( );
/**
* private constructor
*/
private NotificationService( )
{
}
/**
* get unique instance of the service
*
* @return the notification service
*/
public static NotificationService instance( )
{
if ( _instance == null )
{
_instance = new NotificationService( );
_demandService = SpringContextService.getBean( BEAN_STORAGE_SERVICE );
_notifyers = SpringContextService.getBeansOfType( INotifyerServiceProvider.class );
_mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
_mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
}
return _instance;
}
/**
* process Notification
*
* @param notification
*/
public Response newNotification( String strJson )
{
List<StatusMessage> warnings = new ArrayList<>( );
try
{
// parse json
Notification notification = getNotificationFromJson( strJson );
// control customer
boolean isCustomerValid = processCustomer( notification, warnings );
// check Notification
checkNotification( notification, warnings );
// store notification only if customer is valid (or if property "store all" is set)
if ( isCustomerValid )
{
store( notification );
}
// add event (success, or failure if customer not found for example)
addEvents( notification, warnings );
// forward notification to registred notifyers (if exists)
forward( notification );
}
catch( JsonParseException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( JsonMappingException | NullPointerException | NotificationException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( IOException ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
catch( Exception ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
// success
if ( warnings.isEmpty( ) )
{
return success( );
}
else
{
return successWithWarnings( warnings );
}
}
/**
* Notification check
*
* @param notification
* @param warnings
*/
private void checkNotification( Notification notification, List<StatusMessage> warnings )
{
// notification should be associated to a demand id
if ( StringUtils.isBlank( notification.getDemand( ).getId( ) ) )
{
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_MANDATORY_FIELD, WARNING_DEMAND_ID_MANDATORY );
warnings.add( msg );
}
// notification should be associated to a demand type id
if ( StringUtils.isBlank( notification.getDemand( ).getTypeId( ) ) )
{
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_MANDATORY_FIELD, WARNING_DEMAND_TYPE_ID_MANDATORY );
warnings.add( msg );
}
// check if demand type id exists
if ( !_demandService.getDemandType( notification.getDemand( ).getTypeId( ) ).isPresent( ) )
{
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_MISSING_DEMAND_ID, WARNING_INCORRECT_DEMAND_TYPE_ID );
warnings.add( msg );
}
}
/**
* Process customer data
*
* @param notification
* @param warnings
* @throws IdentityStoreException
*/
private boolean processCustomer( Notification notification, List<StatusMessage> warnings ) throws IdentityStoreException
{
Customer customer = CustomerProvider.instance( ).decrypt( notification.getDemand( ) );
// use connection id as customer id (if set in properties, and the other ids are empty)
if ( AppPropertiesService.getPropertyBoolean( NotificationStoreConstants.PROPERTY_CONSIDER_GUID_AS_CUSTOMER_ID, false )
&& StringUtils.isEmpty( customer.getId( ) ) && StringUtils.isEmpty( customer.getCustomerId( ) )
&& !StringUtils.isEmpty( customer.getConnectionId( ) ) )
{
customer.setCustomerId( customer.getConnectionId( ) );
}
// check customer identity
if ( CustomerProvider.instance( ).hasIdentityService( ) )
{
// check customer ids
if ( customer == null || ( !CustomerProvider.isCustomerIdValid( customer.getCustomerId( ) )
&& !CustomerProvider.isCustomerIdValid( customer.getId( ) ) && !CustomerProvider.isConnectionIdValid( customer.getConnectionId( ) ) ) )
{
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_INCORRECT_USER, WARNING_CUSTOMER_IDS_MANDATORY );
warnings.add( msg );
return false;
}
// set customer id if provided by ID customer attribute (if valid)
if ( !CustomerProvider.isCustomerIdValid( customer.getCustomerId( ) ) && CustomerProvider.isCustomerIdValid( customer.getId( ) ) )
{
customer.setCustomerId( customer.getId( ) );
}
try
{
// search identity
Customer customerResult = CustomerProvider.instance( ).get( customer.getConnectionId( ), customer.getCustomerId( ) );
if ( customerResult != null )
{
// could be different (in case of consolidated identities for example)
customer.setCustomerId( customerResult.getCustomerId( ) );
}
else
{
// add a warning : the identity does not exists (incorrect ids, identity deleted...)
// A customer must have a valid customer_id of connection_id
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_WARNING, MESSAGE_INCORRECT_USER, WARNING_CUSTOMER_NOT_FOUND );
warnings.add( msg );
return false;
}
}
catch( IdentityStoreException e )
{
customer = null;
AppLogService.error( "An error occured while accessing IdentityStore", e );
StatusMessage msg = new StatusMessage( TYPE_DEMAND, STATUS_ERROR, MESSAGE_INCORRECT_USER, ERROR_IDENTITYSTORE );
warnings.add( msg );
}
}
/*
* // reset customer ??? if ( !warnings.isEmpty( ) ) { customer = new Customer( ); customer.setConnectionId( StringUtils.EMPTY );
* customer.setCustomerId( StringUtils.EMPTY ); }
*/
notification.getDemand( ).setCustomer( customer );
// return true if customer_id exists
return !StringUtils.isEmpty( customer.getCustomerId( ) );
}
/**
* Link a notification to another
*
* @param strJson
* @return the response
*/
public Response reassignNotifications( String strJson )
{
try
{
_mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, false );
ReassignNotificationsRequest request = _mapper.readValue( strJson, ReassignNotificationsRequest.class );
_mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
AppLogService.debug( "notificationstore / ReassignNotificationsRequest - Received strJson : " + strJson );
if ( !CustomerProvider.isCustomerIdValid( request.getOldCustomerId( ) ) || !CustomerProvider.isCustomerIdValid( request.getNewCustomerId( ) ) )
{
return fail( new Exception( "Invalid CUIDs" ), Response.Status.BAD_REQUEST );
}
NotificationFilter filter = new NotificationFilter( );
filter.setCustomerId( request.getOldCustomerId( ) );
List<Notification> listNotifsToReassign = NotificationHome.getByFilter( filter );
if ( listNotifsToReassign.size( ) == 0 )
{
return ok( );
}
DemandHome.reassignDemands( request.getOldCustomerId( ), request.getNewCustomerId( ) );
NotificationHome.reassignNotifications( request.getOldCustomerId( ), request.getNewCustomerId( ) );
// generate events (for history)
for ( Notification notif : listNotifsToReassign )
{
notif.getDemand( ).getCustomer( ).setCustomerId( request.getNewCustomerId( ) );
addMergeEvent( notif, request );
}
}
catch( JsonParseException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( JsonMappingException | NullPointerException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( IOException ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
catch( Exception ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
return success( );
}
/**
* store a notification event
*
* @param strJson
* @return the response
*/
public Response newNotificationEvent( String strJson )
{
try
{
NotificationEvent notificationEvent = _mapper.readValue( strJson, NotificationEvent.class );
AppLogService.debug( "notificationstore / notificationEvent - Received strJson : " + strJson );
store( notificationEvent );
}
catch( JsonParseException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( JsonMappingException | NullPointerException ex )
{
return fail( ex, Response.Status.BAD_REQUEST );
}
catch( IOException ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
catch( Exception ex )
{
return fail( ex, Response.Status.INTERNAL_SERVER_ERROR );
}
return success( );
}
/**
* Stores a notification and the associated demand
*
* @param notification
* the notification to store
*/
private void store( NotificationEvent notificationEvent )
{
// set customer id if provided by ID customer attribute (if valid)
if ( notificationEvent.getDemand( ) != null && notificationEvent.getDemand( ).getCustomer( ) != null
&& !CustomerProvider.isCustomerIdValid( notificationEvent.getDemand( ).getCustomer( ).getCustomerId( ) )
&& CustomerProvider.isCustomerIdValid( notificationEvent.getDemand( ).getCustomer( ).getId( ) ) )
{
notificationEvent.getDemand( ).getCustomer( ).setCustomerId( notificationEvent.getDemand( ).getCustomer( ).getId( ) );
}
_demandService.create( notificationEvent );
}
/**
* Stores a notification and the associated demand
*
* @param notification
* the notification to store
*/
private void store( Notification notification )
{
Demand demand = _demandService.findByPrimaryKey( notification.getDemand( ).getId( ), notification.getDemand( ).getTypeId( ),
notification.getDemand( ).getCustomer( ).getCustomerId( ) );
if ( demand == null || ( demand.getCustomer( ) != null && demand.getCustomer( ).getCustomerId( ) != null
&& !demand.getCustomer( ).getCustomerId( ).equals( notification.getDemand( ).getCustomer( ).getCustomerId( ) ) ) )
{
demand = new Demand( );
demand.setId( notification.getDemand( ).getId( ) );
demand.setTypeId( notification.getDemand( ).getTypeId( ) );
demand.setSubtypeId( notification.getDemand( ).getSubtypeId( ) );
demand.setReference( notification.getDemand( ).getReference( ) );
demand.setCreationDate( notification.getDate( ) );
demand.setMaxSteps( notification.getDemand( ).getMaxSteps( ) );
demand.setCurrentStep( notification.getDemand( ).getCurrentStep( ) );
demand.setStatusId( getNewDemandStatusIdFromNotification( notification ) );
demand.setMetaData( notification.getDemand( ).getMetaData( ) );
Customer customerDemand = new Customer( );
customerDemand.setCustomerId( notification.getDemand( ).getCustomer( ).getId( ) );
customerDemand.setCustomerId( notification.getDemand( ).getCustomer( ).getCustomerId( ) );
customerDemand.setConnectionId( notification.getDemand( ).getCustomer( ).getConnectionId( ) );
demand.setCustomer( customerDemand );
// create demand
_demandService.create( demand );
}
else
{
// update demand status
demand.setCurrentStep( notification.getDemand( ).getCurrentStep( ) );
demand.setModifyDate( notification.getDate( ) );
int nNewStatusId = getNewDemandStatusIdFromNotification( notification );
EnumGenericStatus oldStatus = EnumGenericStatus.getByStatusId( demand.getStatusId( ) );
EnumGenericStatus newStatus = EnumGenericStatus.getByStatusId( nNewStatusId );
// Demand opened to closed
if ( oldStatus != null && newStatus != null && !oldStatus.isFinalStatus( ) && newStatus.isFinalStatus( ) )
{
demand.setClosureDate( notification.getDate( ) );
}
// Demand closed to opened
if ( oldStatus != null && newStatus != null && oldStatus.isFinalStatus( ) && !newStatus.isFinalStatus( ) )
{
demand.setClosureDate( 0 );
}
_demandService.update( demand );
}
notification.setDemand( demand );
// create notification
_demandService.create( notification );
}
/**
* Values and store the NotificationEvent object if failure
*
* @param notification
* @param warnings
* @param strMessage
*/
private void addEvents( Notification notification, List<StatusMessage> warnings )
{
// no event
if ( warnings.isEmpty( ) )
{
return;
}
Event event = new Event( );
event.setEventDate( notification.getDate( ) );
if ( notification.getMyDashboardNotification( ) != null )
{
event.setType( TYPE_NOTIFICATION_GUICHET );
}
else
{
event.setType( TYPE_NOTIFICATION_AGENT );
}
event.setMessage( generateEventMessage( notification, warnings ) );
event.setStatus( STATUS_FAILED );
NotificationEvent notificationEvent = new NotificationEvent( );
notificationEvent.setEvent( event );
notificationEvent.setMsgId( StringUtils.EMPTY );
notificationEvent.setDemand( notification.getDemand( ) );
notificationEvent.setNotificationDate( notification.getDate( ) );
store( notificationEvent );
}
/**
* Values and store the NotificationEvent object if failure
*
* @param notification
* @param warnings
* @param strMessage
*/
private void addMergeEvent( Notification notification, ReassignNotificationsRequest request )
{
Event event = new Event( );
event.setEventDate( notification.getDate( ) );
event.setType( TYPE_MERGE_NOTIFICATIONS );
event.setMessage( "Merged CUID : " + request.getOldCustomerId( ) + "\nConsolidated CUID : " + request.getNewCustomerId( ) );
event.setStatus( STATUS_WARNING );
NotificationEvent notificationEvent = new NotificationEvent( );
notificationEvent.setEvent( event );
notificationEvent.setMsgId( StringUtils.EMPTY );
notificationEvent.setDemand( notification.getDemand( ) );
notificationEvent.setNotificationDate( notification.getDate( ) );
store( notificationEvent );
}
/**
* Build an error response
*
* @param strMessage
* The error message
* @param ex
* An exception
* @return The response
*/
private Response successWithWarnings( List<StatusMessage> warnings )
{
StringBuilder strWarnings = new StringBuilder( "[" );
if ( warnings != null )
{
for ( StatusMessage msg : warnings )
{
strWarnings.append( msg.asJson( ) ).append( "," );
}
// remove last ","
strWarnings.setLength( strWarnings.length( ) - 1 );
}
strWarnings.append( "]" );
String strResponse = "{ \"acknowledge\" : { \"status\": \"warning\", \"warnings\" : " + strWarnings.toString( ) + " } }";
return Response.status( Response.Status.CREATED ).entity( strResponse ).build( );
}
/**
* success case
*
* @return a successful response
*/
private Response success( )
{
return Response.status( Response.Status.CREATED ).entity( RESPONSE_OK ).build( );
}
/**
* ok case
*
* @return a successful response
*/
private Response ok( )
{
return Response.status( Response.Status.OK ).entity( RESPONSE_OK ).build( );
}
/**
* Build an error response
*
* @param strMessage
* The error message
* @param ex
* An exception
* @return The response
*/
private Response fail( Throwable ex, Status httpStatus )
{
StringBuilder strMsg = new StringBuilder( "[" );
if ( ex != null )
{
AppLogService.error( ex.getMessage( ), ex );
strMsg.append( new StatusMessage( TYPE_NOTIFICATION, STATUS_ERROR, ex.toString( ), ex.getMessage( ) ).asJson( ) );
}
strMsg.append( "]" );
String strError = "{ \"acknowledge\" : { \"status\": \"error\", \"errors\" : " + strMsg + " } }";
return Response.status( httpStatus ).entity( strError ).build( );
}
/**
* Generates the error message
*
* @param notification
* @param strResponseStatus
* @param strErrorMessage
* @return
*/
private String generateEventMessage( Notification notification, List<StatusMessage> warnings )
{
StringBuilder message = new StringBuilder( );
message.append( "WARNINGS\n" );
message.append( "\n" );
message.append( "Demande id : " ).append( notification.getDemand( ).getId( ) ).append( "\n" );
message.append( "Demande Type id : " ).append( notification.getDemand( ).getTypeId( ) ).append( "\n" );
message.append( "Notification date : " ).append( Instant.ofEpochSecond( notification.getDate( ) ) ).append( "\n" );
message.append( "\n" );
if ( notification.getDemand( ).getCustomer( ) != null )
{
message.append( "Customer id: " ).append( notification.getDemand( ).getCustomer( ).getCustomerId( ) ).append( "\n" );
message.append( "Connection id: " ).append( notification.getDemand( ).getCustomer( ).getConnectionId( ) ).append( "\n" );
}
message.append( "-------------------------\n" );
for ( StatusMessage s : warnings )
{
message.append( "Type : " ).append( s.getType( ) ).append( "\n" );
message.append( "Status : " ).append( s.getStatus( ) ).append( "\n" );
message.append( "Message : " ).append( s.getStrMessage( ) ).append( "\n" );
message.append( "Reason : " ).append( s.getReason( ) ).append( "\n" );
message.append( "-------------------------\n" );
}
return message.toString( );
}
/**
* Calculates the generic status id for new notifications.
*
* @param notification
* @return
*/
private int getNewDemandStatusIdFromNotification( Notification notification )
{
// consider first the status sent in the demand
if ( notification.getDemand( ) != null && notification.getDemand( ).getStatusId( ) > 0
&& EnumGenericStatus.exists( notification.getDemand( ).getStatusId( ) ) )
{
return notification.getDemand( ).getStatusId( );
}
// Otherwise, consider the MyDashBoard notification status id
if ( notification.getMyDashboardNotification( ) != null )
{
if ( notification.getMyDashboardNotification( ).getStatusId( ) > 0
&& EnumGenericStatus.exists( notification.getMyDashboardNotification( ).getStatusId( ) ) )
{
return notification.getMyDashboardNotification( ).getStatusId( );
}
// Otherwise, try to guess the status id from the label
Optional<TemporaryStatus> status = _demandService.getStatusByLabel( notification.getMyDashboardNotification( ).getStatusText( ) );
if ( status.isPresent( ) && status.get( ).getGenericStatus( ) != null )
{
return status.get( ).getGenericStatus( ).getStatusId( );
}
}
// default
return -1;
}
/**
* parse json
*
* @param strJson
* @return the notification
* @throws JsonMappingException
* @throws JsonProcessingException
*/
private Notification getNotificationFromJson( String strJson ) throws JsonMappingException, JsonProcessingException
{
AppLogService.debug( "notificationstore / notification - Received strJson : " + strJson );
// Format from JSON
ObjectMapper mapper = new ObjectMapper( );
mapper.configure( DeserializationFeature.UNWRAP_ROOT_VALUE, true );
mapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
Notification notification = mapper.readValue( strJson, Notification.class );
return notification;
}
/**
* call the registred notifyers
*
* @param notification
* @throws NotificationException
*/
public void forward( Notification notification ) throws NotificationException
{
for ( INotifyerServiceProvider notifyer : _notifyers )
{
notifyer.process( notification );
}
}
}