2012-10-05 12:59:59 -02:00
using System ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Linq ;
2012-10-11 13:11:17 -02:00
using System.Reflection ;
using Umbraco.Core.Configuration.InfrastructureSettings ;
using Umbraco.Core.Persistence.Caching ;
2012-10-05 12:59:59 -02:00
using Umbraco.Core.Persistence.Repositories ;
using Umbraco.Core.Persistence.UnitOfWork ;
namespace Umbraco.Core.Persistence
{
internal class RepositoryResolver
{
private static readonly ConcurrentDictionary < string , object > Repositories = new ConcurrentDictionary < string , object > ( ) ;
//GetRepository based on Repository Interface and Model Entity.
//Check if Dictionary contains the interface name of the Repository, ea. IContentRepository
//- If it does return the repository from the dictionary and set the new UnitOfWork object
//Otherwise look for the full type for the repository in config
//- If type exists check depedencies, create new object, add it to dictionary and return it
//Otherwise look for an entity type in the config
//- If type exists check dependencies, create new object, add it to dictionary and return it
//If we have come this far the correct types wasn't found and we throw an exception
2012-10-08 08:42:57 -02:00
internal static TRepository ResolveByType < TRepository , TEntity , TId > ( IUnitOfWork unitOfWork )
2012-10-09 08:12:03 -02:00
where TRepository : class , IRepository < TId , TEntity >
where TEntity : class
2012-10-05 12:59:59 -02:00
{
//Initialize the provider's default value
TRepository repository = default ( TRepository ) ;
string interfaceShortName = typeof ( TRepository ) . Name ;
string entityTypeName = typeof ( TEntity ) . Name ;
//Check if the repository has already been created and is in the cache
if ( Repositories . ContainsKey ( interfaceShortName ) )
{
repository = ( TRepository ) Repositories [ interfaceShortName ] ;
2012-11-02 11:54:42 -01:00
if ( unitOfWork ! = null & & ( typeof ( IRepository < TId , TEntity > ) . IsInstanceOfType ( repository ) ) )
2012-10-05 12:59:59 -02:00
{
repository . SetUnitOfWork ( unitOfWork ) ;
}
return repository ;
}
2012-10-11 13:11:17 -02:00
var settings = Infrastructure . Instance . Repositories ;
2012-10-05 12:59:59 -02:00
Type repositoryType = null ;
//Check if a valid interfaceShortName was passed in
2012-10-11 13:11:17 -02:00
if ( settings . Repository . ContainsKey ( interfaceShortName ) )
2012-10-05 12:59:59 -02:00
{
2012-10-11 13:11:17 -02:00
repositoryType = Type . GetType ( settings . Repository [ interfaceShortName ] . RepositoryFullTypeName ) ;
2012-10-05 12:59:59 -02:00
}
else
{
2012-10-11 13:11:17 -02:00
foreach ( Repository element in settings . Repository )
2012-10-05 12:59:59 -02:00
{
if ( element . InterfaceShortTypeName . Contains ( entityTypeName ) )
{
2012-10-11 13:11:17 -02:00
repositoryType = Type . GetType ( settings . Repository [ element . InterfaceShortTypeName ] . RepositoryFullTypeName ) ;
2012-10-05 12:59:59 -02:00
break ;
}
}
}
//If the repository type is null we should stop and throw an exception
if ( repositoryType = = null )
{
throw new Exception ( string . Format ( "No repository matching the Repository interface '{0}' or Entity type '{1}' could be resolved" ,
interfaceShortName , entityTypeName ) ) ;
}
//Resolve the repository with its constructor dependencies
2012-10-11 13:11:17 -02:00
repository = Resolve ( repositoryType , unitOfWork , interfaceShortName ) as TRepository ;
2012-10-05 12:59:59 -02:00
//Add the new repository instance to the cache
Repositories . AddOrUpdate ( interfaceShortName , repository , ( x , y ) = > repository ) ;
return repository ;
}
//Recursive create and dependency check
2012-10-11 13:11:17 -02:00
private static object Resolve ( Type repositoryType , IUnitOfWork unitOfWork , string interfaceShortName )
2012-10-05 12:59:59 -02:00
{
2012-10-11 13:11:17 -02:00
var constructors = repositoryType . GetConstructors ( ) ;
var constructor = constructors . LastOrDefault ( ) ;
2012-10-05 12:59:59 -02:00
if ( constructor = = null )
{
throw new Exception ( string . Format ( "No public constructor was found on {0}" , repositoryType . FullName ) ) ;
}
var constructorArgs = new List < object > ( ) ;
2012-10-11 13:11:17 -02:00
var settings = Infrastructure . Instance . Repositories ;
2012-10-05 12:59:59 -02:00
var parameters = constructor . GetParameters ( ) ;
foreach ( var parameter in parameters )
{
if ( parameter . ParameterType . Name . Equals ( "IUnitOfWork" ) )
{
constructorArgs . Add ( unitOfWork ) ;
}
else if ( Repositories . ContainsKey ( parameter . ParameterType . Name ) )
{
var repo = Repositories [ parameter . ParameterType . Name ] ;
constructorArgs . Add ( repo ) ;
}
2012-10-11 13:11:17 -02:00
else if ( parameter . ParameterType . Name . Equals ( typeof ( IRepositoryCacheProvider ) . Name ) )
{
//Get the Type of the cache provider and activate the singleton instance
var cacheType = Type . GetType ( settings . Repository [ interfaceShortName ] . CacheProviderFullTypeName ) ;
if ( cacheType = = null )
throw new Exception ( string . Format ( "Unable to get the type of cache provider '{0}' from configuration while creating an instance of {1}" ,
settings . Repository [ parameter . ParameterType . Name ] .
CacheProviderFullTypeName ,
parameter . ParameterType . Name ) ) ;
var cacheProvider = cacheType . InvokeMember ( "Current" , BindingFlags . GetProperty , null , cacheType , new object [ 0 ] ) ;
constructorArgs . Add ( cacheProvider ) ;
}
2012-10-05 12:59:59 -02:00
else
{
2012-10-11 13:11:17 -02:00
if ( settings . Repository . ContainsKey ( parameter . ParameterType . Name ) )
2012-10-05 12:59:59 -02:00
{
//Get the Type of the repository and resolve the object
2012-10-11 13:11:17 -02:00
var repoType = Type . GetType ( settings . Repository [ parameter . ParameterType . Name ] . RepositoryFullTypeName ) ;
var repo = Resolve ( repoType , unitOfWork , parameter . ParameterType . Name ) ;
2012-10-05 12:59:59 -02:00
// Add the new repository instance to the cache
Repositories . AddOrUpdate ( parameter . ParameterType . Name , repo , ( x , y ) = > repo ) ;
//Add the new repository to the constructor
constructorArgs . Add ( repo ) ;
}
else
{
2012-10-11 13:11:17 -02:00
throw new Exception ( "Cannot create the Repository. There was one or more invalid repository configuration settings." ) ;
2012-10-05 12:59:59 -02:00
}
}
}
2012-10-11 13:11:17 -02:00
if ( parameters . Count ( ) ! = constructorArgs . Count )
throw new Exception (
string . Format (
"The amount of expected parameters is different from the amount of constructed parameters, which is confusing! Repository of type '{0}' could not be created." ,
repositoryType . FullName ) ) ;
2012-10-05 12:59:59 -02:00
var repositoryObj = Activator . CreateInstance ( repositoryType , constructorArgs . ToArray ( ) ) ;
return repositoryObj ;
}
/// <summary>
/// Register all repositories by interating the configuration and adding the repositories to the internal cache (Dictionary)
/// </summary>
internal static void RegisterRepositories ( )
{
2012-10-11 13:11:17 -02:00
var settings = Infrastructure . Instance . Repositories ;
2012-10-05 12:59:59 -02:00
2012-10-11 13:11:17 -02:00
foreach ( Repository element in settings . Repository )
2012-10-05 12:59:59 -02:00
{
if ( Repositories . ContainsKey ( element . InterfaceShortTypeName ) ) continue ;
2012-10-11 13:11:17 -02:00
var repositoryType = Type . GetType ( settings . Repository [ element . InterfaceShortTypeName ] . RepositoryFullTypeName ) ;
var repository = Resolve ( repositoryType , null , element . InterfaceShortTypeName ) ;
2012-10-05 12:59:59 -02:00
//Add the new repository instance to the cache
Repositories . AddOrUpdate ( element . InterfaceShortTypeName , repository , ( x , y ) = > repository ) ;
}
}
/// <summary>
/// Returns the number of repositories that has been registered
/// </summary>
/// <returns></returns>
internal static int RegisteredRepositories ( )
{
return Repositories . Count ;
}
}
}