2015-03-04 12:16:28 +01:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2015-04-08 14:21:58 +02:00
using Newtonsoft.Json ;
2015-03-04 12:16:28 +01:00
using Umbraco.Core.Cache ;
2017-05-30 15:46:25 +02:00
using Umbraco.Core.Composing ;
2015-03-04 12:16:28 +01:00
using Umbraco.Core.Logging ;
namespace Umbraco.Core.Sync
{
/// <summary>
/// Provides a base class for all <see cref="IServerMessenger"/> implementations.
/// </summary>
public abstract class ServerMessengerBase : IServerMessenger
{
protected bool DistributedEnabled { get ; set ; }
protected ServerMessengerBase ( bool distributedEnabled )
{
DistributedEnabled = distributedEnabled ;
}
/// <summary>
/// Determines whether to make distributed calls when messaging a cache refresher.
/// </summary>
/// <param name="servers">The registered servers.</param>
/// <param name="refresher">The cache refresher.</param>
/// <param name="messageType">The message type.</param>
/// <returns>true if distributed calls are required; otherwise, false, all we have is the local server.</returns>
2018-05-01 10:39:04 +10:00
protected virtual bool RequiresDistributed ( ICacheRefresher refresher , MessageType messageType )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
return DistributedEnabled ;
2015-03-04 12:16:28 +01:00
}
// ensures that all items in the enumerable are of the same type, either int or Guid.
protected static bool GetArrayType ( IEnumerable < object > ids , out Type arrayType )
{
arrayType = null ;
if ( ids = = null ) return true ;
foreach ( var id in ids )
{
// only int and Guid are supported
if ( ( id is int ) = = false & & ( ( id is Guid ) = = false ) )
return false ;
// initialize with first item
if ( arrayType = = null )
arrayType = id . GetType ( ) ;
// check remaining items
if ( arrayType ! = id . GetType ( ) )
return false ;
}
return true ;
}
#region IServerMessenger
2018-05-01 10:39:04 +10:00
public void PerformRefresh < TPayload > ( ICacheRefresher refresher , TPayload [ ] payload )
2015-04-08 14:21:58 +02:00
{
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
if ( payload = = null ) throw new ArgumentNullException ( nameof ( payload ) ) ;
2015-04-08 14:21:58 +02:00
2018-05-01 10:39:04 +10:00
Deliver ( refresher , payload ) ;
2015-04-08 14:21:58 +02:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefresh ( ICacheRefresher refresher , string jsonPayload )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
if ( jsonPayload = = null ) throw new ArgumentNullException ( nameof ( jsonPayload ) ) ;
2015-03-04 12:16:28 +01:00
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshByJson , json : jsonPayload ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefresh < T > ( ICacheRefresher refresher , Func < T , int > getNumericId , params T [ ] instances )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
if ( getNumericId = = null ) throw new ArgumentNullException ( nameof ( getNumericId ) ) ;
2015-03-04 12:16:28 +01:00
if ( instances = = null | | instances . Length = = 0 ) return ;
Func < T , object > getId = x = > getNumericId ( x ) ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshByInstance , getId , instances ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefresh < T > ( ICacheRefresher refresher , Func < T , Guid > getGuidId , params T [ ] instances )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
if ( getGuidId = = null ) throw new ArgumentNullException ( nameof ( getGuidId ) ) ;
2015-03-04 12:16:28 +01:00
if ( instances = = null | | instances . Length = = 0 ) return ;
Func < T , object > getId = x = > getGuidId ( x ) ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshByInstance , getId , instances ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRemove < T > ( ICacheRefresher refresher , Func < T , int > getNumericId , params T [ ] instances )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
if ( getNumericId = = null ) throw new ArgumentNullException ( nameof ( getNumericId ) ) ;
2015-03-04 12:16:28 +01:00
if ( instances = = null | | instances . Length = = 0 ) return ;
Func < T , object > getId = x = > getNumericId ( x ) ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RemoveByInstance , getId , instances ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRemove ( ICacheRefresher refresher , params int [ ] numericIds )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
if ( numericIds = = null | | numericIds . Length = = 0 ) return ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RemoveById , numericIds . Cast < object > ( ) ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefresh ( ICacheRefresher refresher , params int [ ] numericIds )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
if ( numericIds = = null | | numericIds . Length = = 0 ) return ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshById , numericIds . Cast < object > ( ) ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefresh ( ICacheRefresher refresher , params Guid [ ] guidIds )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
if ( guidIds = = null | | guidIds . Length = = 0 ) return ;
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshById , guidIds . Cast < object > ( ) ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
public void PerformRefreshAll ( ICacheRefresher refresher )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
2018-05-01 10:39:04 +10:00
Deliver ( refresher , MessageType . RefreshAll ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
//public void PerformNotify(ICacheRefresher refresher, object payload)
2015-03-04 12:16:28 +01:00
//{
// if (servers == null) throw new ArgumentNullException("servers");
// if (refresher == null) throw new ArgumentNullException("refresher");
2018-05-01 10:39:04 +10:00
// Deliver(refresher, payload);
2015-03-04 12:16:28 +01:00
//}
#endregion
#region Deliver
2016-05-26 17:12:04 +02:00
protected void DeliverLocal < TPayload > ( ICacheRefresher refresher , TPayload [ ] payload )
2015-04-08 14:21:58 +02:00
{
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-04-08 14:21:58 +02:00
2018-08-14 15:08:32 +01:00
Current . Logger . Debug < ServerMessengerBase > ( "Invoking refresher {RefresherType} on local server for message type RefreshByPayload" , refresher . GetType ( ) ) ;
2015-04-08 14:21:58 +02:00
2016-05-26 17:12:04 +02:00
var payloadRefresher = refresher as IPayloadCacheRefresher < TPayload > ;
2015-04-08 14:21:58 +02:00
if ( payloadRefresher = = null )
2016-05-26 17:12:04 +02:00
throw new InvalidOperationException ( "The cache refresher " + refresher . GetType ( ) + " is not of type " + typeof ( IPayloadCacheRefresher < TPayload > ) ) ;
2015-04-08 14:21:58 +02:00
payloadRefresher . Refresh ( payload ) ;
}
2015-03-27 12:37:03 +11:00
/// <summary>
/// Executes the non strongly typed <see cref="ICacheRefresher"/> on the local/current server
/// </summary>
/// <param name="refresher"></param>
/// <param name="messageType"></param>
/// <param name="ids"></param>
/// <param name="json"></param>
/// <remarks>
/// Since this is only for non strongly typed <see cref="ICacheRefresher"/> it will throw for message types that by instance
/// </remarks>
2015-03-04 12:16:28 +01:00
protected void DeliverLocal ( ICacheRefresher refresher , MessageType messageType , IEnumerable < object > ids = null , string json = null )
{
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
2018-08-14 15:08:32 +01:00
Current . Logger . Debug < ServerMessengerBase > ( "Invoking refresher {RefresherType} on local server for message type {MessageType}" , refresher . GetType ( ) , messageType ) ;
2015-03-04 12:16:28 +01:00
switch ( messageType )
{
case MessageType . RefreshAll :
refresher . RefreshAll ( ) ;
break ;
case MessageType . RefreshById :
if ( ids ! = null )
foreach ( var id in ids )
{
if ( id is int )
refresher . Refresh ( ( int ) id ) ;
else if ( id is Guid )
refresher . Refresh ( ( Guid ) id ) ;
else
throw new InvalidOperationException ( "The id must be either an int or a Guid." ) ;
}
break ;
case MessageType . RefreshByJson :
var jsonRefresher = refresher as IJsonCacheRefresher ;
if ( jsonRefresher = = null )
throw new InvalidOperationException ( "The cache refresher " + refresher . GetType ( ) + " is not of type " + typeof ( IJsonCacheRefresher ) ) ;
jsonRefresher . Refresh ( json ) ;
break ;
case MessageType . RemoveById :
if ( ids ! = null )
foreach ( var id in ids )
{
if ( id is int )
refresher . Remove ( ( int ) id ) ;
else
throw new InvalidOperationException ( "The id must be an int." ) ;
}
break ;
default :
//case MessageType.RefreshByInstance:
//case MessageType.RemoveByInstance:
throw new NotSupportedException ( "Invalid message type " + messageType ) ;
}
}
2017-07-20 11:21:28 +02:00
2015-03-27 12:37:03 +11:00
/// <summary>
/// Executes the strongly typed <see cref="ICacheRefresher{T}"/> on the local/current server
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="refresher"></param>
/// <param name="messageType"></param>
/// <param name="getId"></param>
/// <param name="instances"></param>
/// <remarks>
/// Since this is only for strongly typed <see cref="ICacheRefresher{T}"/> it will throw for message types that are not by instance
/// </remarks>
2015-03-04 12:16:28 +01:00
protected void DeliverLocal < T > ( ICacheRefresher refresher , MessageType messageType , Func < T , object > getId , IEnumerable < T > instances )
{
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
2018-08-14 15:08:32 +01:00
Current . Logger . Debug < ServerMessengerBase > ( "Invoking refresher {RefresherType} on local server for message type {MessageType}" , refresher . GetType ( ) , messageType ) ;
2015-03-04 12:16:28 +01:00
var typedRefresher = refresher as ICacheRefresher < T > ;
switch ( messageType )
{
case MessageType . RefreshAll :
refresher . RefreshAll ( ) ;
break ;
case MessageType . RefreshByInstance :
if ( typedRefresher = = null )
throw new InvalidOperationException ( "The refresher must be a typed refresher." ) ;
foreach ( var instance in instances )
typedRefresher . Refresh ( instance ) ;
break ;
case MessageType . RemoveByInstance :
if ( typedRefresher = = null )
throw new InvalidOperationException ( "The cache refresher " + refresher . GetType ( ) + " is not a typed refresher." ) ;
foreach ( var instance in instances )
typedRefresher . Remove ( instance ) ;
break ;
default :
//case MessageType.RefreshById:
//case MessageType.RemoveById:
//case MessageType.RefreshByJson:
throw new NotSupportedException ( "Invalid message type " + messageType ) ;
}
}
//protected void DeliverLocal(ICacheRefresher refresher, object payload)
//{
// if (refresher == null) throw new ArgumentNullException("refresher");
2016-09-11 19:57:33 +02:00
// Current.Logger.Debug<ServerMessengerBase>("Invoking refresher {0} on local server for message type Notify",
2015-03-04 12:16:28 +01:00
// () => refresher.GetType());
// refresher.Notify(payload);
//}
2018-05-01 10:39:04 +10:00
protected abstract void DeliverRemote ( ICacheRefresher refresher , MessageType messageType , IEnumerable < object > ids = null , string json = null ) ;
2015-03-04 12:16:28 +01:00
2018-05-01 10:39:04 +10:00
//protected abstract void DeliverRemote(ICacheRefresher refresher, object payload);
2015-03-04 12:16:28 +01:00
2018-05-01 10:39:04 +10:00
protected virtual void Deliver < TPayload > ( ICacheRefresher refresher , TPayload [ ] payload )
2015-04-08 14:21:58 +02:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-04-08 14:21:58 +02:00
// deliver local
DeliverLocal ( refresher , payload ) ;
// distribute?
2018-05-01 10:39:04 +10:00
if ( RequiresDistributed ( refresher , MessageType . RefreshByJson ) = = false )
2015-04-08 14:21:58 +02:00
return ;
// deliver remote
var json = JsonConvert . SerializeObject ( payload ) ;
2018-05-01 10:39:04 +10:00
DeliverRemote ( refresher , MessageType . RefreshByJson , null , json ) ;
2015-04-08 14:21:58 +02:00
}
2018-05-01 10:39:04 +10:00
protected virtual void Deliver ( ICacheRefresher refresher , MessageType messageType , IEnumerable < object > ids = null , string json = null )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
2016-05-26 17:12:04 +02:00
var idsA = ids ? . ToArray ( ) ;
2015-03-04 12:16:28 +01:00
// deliver local
DeliverLocal ( refresher , messageType , idsA , json ) ;
// distribute?
2018-05-01 10:39:04 +10:00
if ( RequiresDistributed ( refresher , messageType ) = = false )
2015-03-04 12:16:28 +01:00
return ;
// deliver remote
2018-05-01 10:39:04 +10:00
DeliverRemote ( refresher , messageType , idsA , json ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
protected virtual void Deliver < T > ( ICacheRefresher refresher , MessageType messageType , Func < T , object > getId , IEnumerable < T > instances )
2015-03-04 12:16:28 +01:00
{
2018-05-01 10:39:04 +10:00
2016-05-26 17:12:04 +02:00
if ( refresher = = null ) throw new ArgumentNullException ( nameof ( refresher ) ) ;
2015-03-04 12:16:28 +01:00
var instancesA = instances . ToArray ( ) ;
// deliver local
DeliverLocal ( refresher , messageType , getId , instancesA ) ;
// distribute?
2018-05-01 10:39:04 +10:00
if ( RequiresDistributed ( refresher , messageType ) = = false )
2015-03-04 12:16:28 +01:00
return ;
// deliver remote
// map ByInstance to ById as there's no remote instances
if ( messageType = = MessageType . RefreshByInstance ) messageType = MessageType . RefreshById ;
if ( messageType = = MessageType . RemoveByInstance ) messageType = MessageType . RemoveById ;
// convert instances to identifiers
var idsA = instancesA . Select ( getId ) . ToArray ( ) ;
2018-05-01 10:39:04 +10:00
DeliverRemote ( refresher , messageType , idsA ) ;
2015-03-04 12:16:28 +01:00
}
2018-05-01 10:39:04 +10:00
//protected virtual void Deliver(ICacheRefresher refresher, object payload)
2015-03-04 12:16:28 +01:00
//{
// if (servers == null) throw new ArgumentNullException("servers");
// if (refresher == null) throw new ArgumentNullException("refresher");
// var serversA = servers.ToArray();
// // deliver local
// DeliverLocal(refresher, payload);
// // distribute?
// if (RequiresDistributed(serversA, refresher, messageType) == false)
// return;
// // deliver remote
// DeliverRemote(serversA, refresher, payload);
//}
#endregion
}
}