/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using Lucene.Net.Support;
namespace Lucene.Net.Messages
{
/// MessageBundles classes extend this class, to implement a bundle.
///
/// For Native Language Support (NLS), system of software internationalization.
///
/// This interface is similar to the NLS class in eclipse.osgi.util.NLS class -
/// initializeMessages() method resets the values of all static strings, should
/// only be called by classes that extend from NLS (see TestMessages.java for
/// reference) - performs validation of all message in a bundle, at class load
/// time - performs per message validation at runtime - see NLSTest.java for
/// usage reference
///
/// MessageBundle classes may subclass this type.
///
public class NLS
{
public interface IPriviligedAction
{
///
/// Performs the priviliged action.
///
/// A value that may represent the result of the action.
System.Object Run();
}
private class AnonymousClassPrivilegedAction : IPriviligedAction
{
public AnonymousClassPrivilegedAction(System.Reflection.FieldInfo field)
{
InitBlock(field);
}
private void InitBlock(System.Reflection.FieldInfo field)
{
this.field = field;
}
private System.Reflection.FieldInfo field;
public virtual System.Object Run()
{
// field.setAccessible(true); // {{Aroush-2.9}} java.lang.reflect.AccessibleObject.setAccessible
return null;
}
}
private static IDictionary bundles = new HashMap(0);
protected internal NLS()
{
// Do not instantiate
}
public static System.String GetLocalizedMessage(System.String key)
{
return GetLocalizedMessage(key, System.Threading.Thread.CurrentThread.CurrentCulture);
}
public static System.String GetLocalizedMessage(System.String key, System.Globalization.CultureInfo locale)
{
System.Object message = GetResourceBundleObject(key, locale);
if (message == null)
{
return "Message with key:" + key + " and locale: " + locale + " not found.";
}
return message.ToString();
}
public static System.String GetLocalizedMessage(System.String key, System.Globalization.CultureInfo locale, params System.Object[] args)
{
System.String str = GetLocalizedMessage(key, locale);
if (args.Length > 0)
{
str = System.String.Format(str, args);
}
return str;
}
public static System.String GetLocalizedMessage(System.String key, params System.Object[] args)
{
return GetLocalizedMessage(key, System.Threading.Thread.CurrentThread.CurrentCulture, args);
}
/// Initialize a given class with the message bundle Keys Should be called from
/// a class that extends NLS in a static block at class load time.
///
///
/// Property file with that contains the message bundle
///
/// where constants will reside
///
//@SuppressWarnings("unchecked")
protected internal static void InitializeMessages(System.String bundleName)
{
try
{
Load();
if (!bundles.ContainsKey(bundleName))
bundles[bundleName] = typeof(T);
}
catch (System.Exception)
{
// ignore all errors and exceptions
// because this function is supposed to be called at class load time.
}
}
private static System.Object GetResourceBundleObject(System.String messageKey, System.Globalization.CultureInfo locale)
{
// slow resource checking
// need to loop thru all registered resource bundles
for (var it = bundles.Keys.GetEnumerator(); it.MoveNext(); )
{
System.Type clazz = bundles[it.Current];
System.Threading.Thread.CurrentThread.CurrentUICulture = locale;
System.Resources.ResourceManager resourceBundle = System.Resources.ResourceManager.CreateFileBasedResourceManager(clazz.Name, "Messages", null); //{{Lucene.Net-2.9.1}} Can we make resourceDir "Messages" more general?
if (resourceBundle != null)
{
try
{
System.Object obj = resourceBundle.GetObject(messageKey);
if (obj != null)
return obj;
}
catch (System.Resources.MissingManifestResourceException)
{
// just continue it might be on the next resource bundle
}
}
}
// if resource is not found
return null;
}
private static void Load()
{
var clazz = typeof (T);
System.Reflection.FieldInfo[] fieldArray = clazz.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Static);
bool isFieldAccessible = clazz.IsPublic;
// build a map of field names to Field objects
int len = fieldArray.Length;
var fields = new HashMap(len * 2);
for (int i = 0; i < len; i++)
{
fields[fieldArray[i].Name] = fieldArray[i];
LoadfieldValue(fieldArray[i], isFieldAccessible);
}
}
///
///
private static void LoadfieldValue(System.Reflection.FieldInfo field, bool isFieldAccessible)
{
var clazz = typeof (T);
/*
int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED)
return ;
*/
if (!(field.IsPublic || field.IsStatic))
return ;
// Set a value for this empty field.
if (!isFieldAccessible)
MakeAccessible(field);
try
{
field.SetValue(null, field.Name);
ValidateMessage(field.Name);
}
catch (System.ArgumentException)
{
// should not happen
}
catch (System.UnauthorizedAccessException)
{
// should not happen
}
}
/// - Message Key
///
private static void ValidateMessage(System.String key)
{
// Test if the message is present in the resource bundle
var clazz = typeof (T);
try
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Resources.ResourceManager resourceBundle = System.Resources.ResourceManager.CreateFileBasedResourceManager(clazz.FullName, "", null);
if (resourceBundle != null)
{
System.Object obj = resourceBundle.GetObject(key);
if (obj == null)
{
System.Console.Error.WriteLine("WARN: Message with key:" + key + " and locale: " + System.Threading.Thread.CurrentThread.CurrentCulture + " not found.");
}
}
}
catch (System.Resources.MissingManifestResourceException)
{
System.Console.Error.WriteLine("WARN: Message with key:" + key + " and locale: " + System.Threading.Thread.CurrentThread.CurrentCulture + " not found.");
}
catch (System.Exception)
{
// ignore all other errors and exceptions
// since this code is just a test to see if the message is present on the
// system
}
}
/*
* Make a class field accessible
*/
//@SuppressWarnings("unchecked")
private static void MakeAccessible(System.Reflection.FieldInfo field)
{
if (System.Security.SecurityManager.SecurityEnabled)
{
//field.setAccessible(true); // {{Aroush-2.9}} java.lang.reflect.AccessibleObject.setAccessible
}
else
{
//AccessController.doPrivileged(new AnonymousClassPrivilegedAction(field)); // {{Aroush-2.9}} java.security.AccessController.doPrivileged
}
}
}
}