2018-02-13 09:23:53 -08:00
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
2016-03-30 14:20:52 -07:00
using System.Reflection ;
using System.Collections.Generic ;
using System.Resources ;
namespace System.Management.Automation
{
/// <summary>
/// </summary>
internal static class ResourceManagerCache
{
/// <summary>
/// Maintains a cache of ResourceManager objects. This is a dictionary that is keyed based on the path
2017-01-16 13:31:14 -08:00
/// to the default resource assembly. The value is another dictionary that is keyed based on the base
2016-03-30 14:20:52 -07:00
/// name for the resource that is being retrieved. The value for this dictionary is the ResourceManager.
/// </summary>
2016-08-02 19:00:50 -07:00
private static Dictionary < string , Dictionary < string , ResourceManager >> s_resourceManagerCache =
2016-03-30 14:20:52 -07:00
new Dictionary < string , Dictionary < string , ResourceManager >>( StringComparer . OrdinalIgnoreCase );
/// <summary>
/// Used to synchronize access to the ResourceManagerCache
/// </summary>
2016-07-29 13:02:49 -07:00
private static object s_syncRoot = new Object ();
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the ResourceManager from the cache or gets an instance of the ResourceManager
/// and returns it if it isn't already present in the cache.
/// </summary>
/// <param name="assembly">
/// The assembly to be used as the base for resource lookup.
/// </param>
/// <param name="baseName">
/// The base name of the resources to get the ResourceManager for.
/// </param>
/// <returns>
/// A ResourceManager instance for the assembly and base name that were specified.
/// </returns>
2016-08-02 19:00:50 -07:00
internal static ResourceManager GetResourceManager (
2016-03-30 14:20:52 -07:00
Assembly assembly ,
string baseName )
{
if ( assembly == null )
{
throw PSTraceSource . NewArgumentNullException ( "assembly" );
}
if ( String . IsNullOrEmpty ( baseName ))
{
throw PSTraceSource . NewArgumentException ( "baseName" );
}
// Check to see if the manager is already in the cache
ResourceManager manager = null ;
Dictionary < string , ResourceManager > baseNameCache ;
2016-04-28 13:41:25 -07:00
string assemblyManifestFileLocation = assembly . Location ;
2016-07-29 13:02:49 -07:00
lock ( s_syncRoot )
2016-03-30 14:20:52 -07:00
{
// First do the lookup based on the assembly location
2016-07-29 13:02:49 -07:00
if ( s_resourceManagerCache . TryGetValue ( assemblyManifestFileLocation , out baseNameCache ) && baseNameCache != null )
2016-03-30 14:20:52 -07:00
{
// Now do the lookup based on the resource base name
baseNameCache . TryGetValue ( baseName , out manager );
}
}
2016-08-28 11:50:08 +10:00
// If it's not in the cache, create it an add it.
2016-03-30 14:20:52 -07:00
if ( manager == null )
{
2016-07-29 13:02:49 -07:00
manager = InitRMWithAssembly ( baseName , assembly );
2016-03-30 14:20:52 -07:00
// Add the new resource manager to the hash
if ( baseNameCache != null )
{
2016-07-29 13:02:49 -07:00
lock ( s_syncRoot )
2016-03-30 14:20:52 -07:00
{
// Since the assembly is already cached, we just have
// to cache the base name entry
baseNameCache [ baseName ] = manager ;
}
}
else
{
// Since the assembly wasn't cached, we have to create base name
// cache entry and then add it into the cache keyed by the assembly
// location
2018-12-22 01:26:06 -08:00
var baseNameCacheEntry = new Dictionary < string , ResourceManager >();
2016-03-30 14:20:52 -07:00
baseNameCacheEntry [ baseName ] = manager ;
2016-07-29 13:02:49 -07:00
lock ( s_syncRoot )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
s_resourceManagerCache [ assemblyManifestFileLocation ] = baseNameCacheEntry ;
2016-03-30 14:20:52 -07:00
}
}
}
2016-07-29 13:02:49 -07:00
Diagnostics . Assert (
manager != null ,
2016-03-30 14:20:52 -07:00
"If the manager was not already created, it should have been dynamically created or an exception should have been thrown" );
return manager ;
2018-12-08 18:53:30 +02:00
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Design For Testability -- assert on failed resource lookup
/// </summary>
2016-07-29 13:02:49 -07:00
private static bool s_DFT_monitorFailingResourceLookup = true ;
2016-08-02 19:00:50 -07:00
internal static bool DFT_DoMonitorFailingResourceLookup
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
get { return ResourceManagerCache . s_DFT_monitorFailingResourceLookup ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
set { ResourceManagerCache . s_DFT_monitorFailingResourceLookup = value ; }
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Gets the string from the resource manager based on the assembly,
/// base name, resource ID, and culture specified
/// </summary>
/// <param name="assembly">
/// The base assembly from which to get the resources from.
/// </param>
/// <param name="baseName">
/// The base name of the resource to retrieve the string from.
/// </param>
/// <param name="resourceId">
/// Resource ID for which the localized string needs to be retrieved
/// </param>
/// <returns>
/// Localized String, or null if the string does not exist
/// </returns>
/// <remarks>
/// The current thread's UI culture is used.
/// </remarks>
/// <throws>
/// ArgumentException if <paramref name="baseName"/> or <paramref name="resourceId"/>
/// are null or empty..
/// InvalidOperationException if the value of the specified resource is not a string
/// MissingManifestResourceException if no usable set of resources have been found, and
/// there are no neutral culture resources.
/// </throws>
2016-08-02 19:00:50 -07:00
internal static string GetResourceString (
2016-03-30 14:20:52 -07:00
Assembly assembly ,
string baseName ,
string resourceId )
{
if ( assembly == null )
{
2016-07-29 13:02:49 -07:00
throw PSTraceSource . NewArgumentNullException ( "assembly" );
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
if ( String . IsNullOrEmpty ( baseName ))
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
throw PSTraceSource . NewArgumentException ( "baseName" );
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
if ( String . IsNullOrEmpty ( resourceId ))
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
throw PSTraceSource . NewArgumentException ( "resourceId" );
2016-03-30 14:20:52 -07:00
}
2017-08-04 15:39:26 -07:00
ResourceManager resourceManager = null ;
string text = string . Empty ;
// For a non-existing resource defined by {assembly,baseName,resourceId}
// MissingManifestResourceException is thrown only at the time when resource retrieval method
// such as ResourceManager.GetString or ResourceManager.GetObject is called,
// not when you instantiate a ResourceManager object.
try
{
// try with original baseName first
// if it fails then try with alternative resource path format
resourceManager = GetResourceManager ( assembly , baseName );
text = resourceManager . GetString ( resourceId );
}
catch ( MissingManifestResourceException )
{
const string resourcesSubstring = ".resources." ;
int resourcesSubstringIndex = baseName . IndexOf ( resourcesSubstring );
string newBaseName = string . Empty ;
if ( resourcesSubstringIndex != - 1 )
{
newBaseName = baseName . Substring ( resourcesSubstringIndex + resourcesSubstring . Length ); // e.g. "FileSystemProviderStrings"
}
else
{
newBaseName = string . Concat ( assembly . GetName (). Name , resourcesSubstring , baseName ); // e.g. "System.Management.Automation.resources.FileSystemProviderStrings"
}
resourceManager = GetResourceManager ( assembly , newBaseName );
text = resourceManager . GetString ( resourceId );
}
2016-07-29 13:02:49 -07:00
if ( String . IsNullOrEmpty ( text ) && s_DFT_monitorFailingResourceLookup )
2016-03-30 14:20:52 -07:00
{
Diagnostics . Assert ( false ,
"Lookup failure: baseName " + baseName + " resourceId " + resourceId );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return text ;
}
/// <summary>
/// Creates a Resource manager instance based on the assembly specified.
/// </summary>
/// <param name="baseName">
2017-01-16 13:31:14 -08:00
/// The root name of the resources.
/// For example, the root name for the resource file
/// named "MyResource.en-US.resources" is "MyResource".
2016-03-30 14:20:52 -07:00
/// </param>
/// <param name="assemblyToUse">
/// The main Assembly for the resources
/// </param>
/// <returns>Resource Manager instance</returns>
/// <exception cref="ArgumentException">
/// Thrown if the resource manager instance could not be created
/// </exception>
2016-08-02 19:00:50 -07:00
private static ResourceManager InitRMWithAssembly ( string baseName , Assembly assemblyToUse )
2016-03-30 14:20:52 -07:00
{
ResourceManager rm = null ;
if ( baseName != null && assemblyToUse != null )
{
2016-07-29 13:02:49 -07:00
rm = new ResourceManager ( baseName , assemblyToUse );
2016-03-30 14:20:52 -07:00
}
else
{
// 2004/10/11-JonN Do we need a better error message? I don't think so,
// since this is private.
throw PSTraceSource . NewArgumentException ( "assemblyToUse" );
}
return rm ;
}
2018-12-08 18:53:30 +02:00
}
}
2016-03-30 14:20:52 -07:00