diff org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/NLS.d @ 105:bbe49769ec18

...
author Frank Benoit <benoit@tionex.de>
date Sun, 08 Nov 2009 12:42:30 +0100
parents 8594250b1d1c
children
line wrap: on
line diff
--- a/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/NLS.d	Sat May 02 11:27:24 2009 +0200
+++ b/org.eclipse.osgi/supplement/src/org/eclipse/osgi/util/NLS.d	Sun Nov 08 12:42:30 2009 +0100
@@ -7,28 +7,29 @@
  *
  * Contributors:
  *     IBM - Initial API and implementation
- * Port to the D programming language:
- *     Frank Benoit <benoit@tionex.de>
  *******************************************************************************/
+// Port to the D programming language:
+//     Frank Benoit <benoit@tionex.de>
 module org.eclipse.osgi.util.NLS;
 
 import java.lang.all;
 
-// import java.io.IOException;
-// import java.io.InputStream;
-// import java.lang.reflect.Field;
-// import java.lang.reflect.Modifier;
-// import java.security.AccessController;
-// import java.security.PrivilegedAction;
-// import java.util.ArrayList;
-// import java.util.HashMap;
-// import java.util.Locale;
-// import java.util.Map;
-// import java.util.Properties;
-//
-// import org.eclipse.osgi.framework.debug.Debug;
-// import org.eclipse.osgi.framework.log.FrameworkLog;
-// import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+
+import org.eclipse.osgi.framework.debug_.Debug;
+import org.eclipse.osgi.framework.log.FrameworkLog;
+import org.eclipse.osgi.framework.log.FrameworkLogEntry;
 
 /**
  * Common superclass for all message bundle classes.  Provides convenience
@@ -60,28 +61,28 @@
  */
 public abstract class NLS {
 
-//     private static final Object[] EMPTY_ARGS = new Object[0];
-//     private static final String EXTENSION = ".properties"; //$NON-NLS-1$
-//     private static String[] nlSuffixes;
-//     /*
-//      * NOTE do not change the name of this field; it is set by the Framework using reflection
-//      */
-//     private static FrameworkLog frameworkLog;
-//
-//     static final int SEVERITY_ERROR = 0x04;
-//     static final int SEVERITY_WARNING = 0x02;
-//     /*
-//      * This object is assigned to the value of a field map to indicate
-//      * that a translated message has already been assigned to that field.
-//      */
-//     static final Object ASSIGNED = new Object();
-//
-//     /**
-//      * Creates a new NLS instance.
-//      */
-//     protected NLS() {
-//         super();
-//     }
+    private static final Object[] EMPTY_ARGS = null;
+    private static final String EXTENSION = ".properties"; //$NON-NLS-1$
+    private static String[] nlSuffixes;
+    /*
+     * NOTE do not change the name of this field; it is set by the Framework using reflection
+     */
+    private static FrameworkLog frameworkLog;
+
+    static final int SEVERITY_ERROR = 0x04;
+    static final int SEVERITY_WARNING = 0x02;
+    /*
+     * This object is assigned to the value of a field map to indicate
+     * that a translated message has already been assigned to that field.
+     */
+    static final Object ASSIGNED = new Object();
+
+    /**
+     * Creates a new NLS instance.
+     */
+    protected this() {
+        super();
+    }
 
     /**
      * Bind the given message's substitution locations with the given string value.
@@ -92,14 +93,7 @@
      * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer
      */
     public static String bind(String message, Object binding) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, null, String.valueOf(binding), null);
-    }
-    public static String bind(String message, String binding) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, null, String.valueOf(binding), null);
+        return internalBind(message, null, String.valueOf(binding), null);
     }
 
     /**
@@ -112,14 +106,7 @@
      * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer
      */
     public static String bind(String message, Object binding1, Object binding2) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, null, String.valueOf(binding1), String.valueOf(binding2));
-    }
-    public static String bind(String message, String binding1, String binding2) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, null, String.valueOf(binding1), String.valueOf(binding2));
+        return internalBind(message, null, String.valueOf(binding1), String.valueOf(binding2));
     }
 
     /**
@@ -131,316 +118,309 @@
      * @throws IllegalArgumentException if the text appearing within curly braces in the given message does not map to an integer
      */
     public static String bind(String message, Object[] bindings) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, bindings, null, null);
+        return internalBind(message, bindings, null, null);
+    }
+
+    /**
+     * Initialize the given class with the values from the specified message bundle.
+     *
+     * @param bundleName fully qualified path of the class name
+     * @param clazz the class where the constants will exist
+     */
+    public static void initializeMessages(/+FIXFINAL+/ String bundleName, /+FIXFINAL+/ Class clazz) {
+        if (System.getSecurityManager() is null) {
+            load(bundleName, clazz);
+            return;
+        }
+        AccessController.doPrivileged(new class() PrivilegedAction {
+            public Object run() {
+                load(bundleName, clazz);
+                return null;
+            }
+        });
     }
-    public static String bind(String message, String[] bindings) {
-        implMissing( __FILE__, __LINE__ );
-        return null;
-//         return internalBind(message, bindings, null, null);
+
+    /*
+     * Perform the string substitution on the given message with the specified args.
+     * See the class comment for exact details.
+     */
+    private static String internalBind(String message, Object[] args, String argZero, String argOne) {
+        if (message is null)
+            return "No message available."; //$NON-NLS-1$
+        if (args is null || args.length_ is 0)
+            args = EMPTY_ARGS;
+
+        int length_ = message.length();
+        //estimate correct size of string buffer to avoid growth
+        int bufLen = length_ + (args.length_ * 5);
+        if (argZero !is null)
+            bufLen += argZero.length() - 3;
+        if (argOne !is null)
+            bufLen += argOne.length() - 3;
+        StringBuffer buffer = new StringBuffer(bufLen < 0 ? 0 : bufLen);
+        for (int i = 0; i < length_; i++) {
+            char c = message.charAt(i);
+            switch (c) {
+                case '{' :
+                    int index = message.indexOf('}', i);
+                    // if we don't have a matching closing brace then...
+                    if (index is -1) {
+                        buffer.append(c);
+                        break;
+                    }
+                    i++;
+                    if (i >= length_) {
+                        buffer.append(c);
+                        break;
+                    }
+                    // look for a substitution
+                    int number = -1;
+                    try {
+                        number = Integer.parseInt(message.substring(i, index));
+                    } catch (NumberFormatException e) {
+                        throw new IllegalArgumentException();
+                    }
+                    if (number is 0 && argZero !is null)
+                        buffer.append(argZero);
+                    else if (number is 1 && argOne !is null)
+                        buffer.append(argOne);
+                    else {
+                        if (number >= args.length_ || number < 0) {
+                            buffer.append("<missing argument>"); //$NON-NLS-1$
+                            i = index;
+                            break;
+                        }
+                        buffer.append(args[number]);
+                    }
+                    i = index;
+                    break;
+                case '\'' :
+                    // if a single quote is the last char on the line then skip it
+                    int nextIndex = i + 1;
+                    if (nextIndex >= length_) {
+                        buffer.append(c);
+                        break;
+                    }
+                    char next = message.charAt(nextIndex);
+                    // if the next char is another single quote then write out one
+                    if (next is '\'') {
+                        i++;
+                        buffer.append(c);
+                        break;
+                    }
+                    // otherwise we want to read until we get to the next single quote
+                    index = message.indexOf('\'', nextIndex);
+                    // if there are no more in the string, then skip it
+                    if (index is -1) {
+                        buffer.append(c);
+                        break;
+                    }
+                    // otherwise write out the chars inside the quotes
+                    buffer.append(message.substring(nextIndex, index));
+                    i = index;
+                    break;
+                default :
+                    buffer.append(c);
+            }
+        }
+        return buffer.toString();
+    }
+
+    /*
+     * Build an array of property files to search.  The returned array contains
+     * the property fields in order from most specific to most generic.
+     * So, in the FR_fr locale, it will return file_fr_FR.properties, then
+     * file_fr.properties, and finally file.properties.
+     */
+    private static String[] buildVariants(String root) {
+        if (nlSuffixes is null) {
+            //build list of suffixes for loading resource bundles
+            String nl = Locale.getDefault().toString();
+            ArrayList result = new ArrayList(4);
+            int lastSeparator;
+            while (true) {
+                result.add('_' + nl + EXTENSION);
+                lastSeparator = nl.lastIndexOf('_');
+                if (lastSeparator is -1)
+                    break;
+                nl = nl.substring(0, lastSeparator);
+            }
+            //add the empty suffix last (most general)
+            result.add(EXTENSION);
+            nlSuffixes = stringcast( result.toArray)(new String[result.size()]);
+        }
+        root = root.replace('.', '/');
+        String[] variants = new String[nlSuffixes.length_];
+        for (int i = 0; i < variants.length_; i++)
+            variants[i] = root + nlSuffixes[i];
+        return variants;
     }
 
-//     /**
-//      * Initialize the given class with the values from the specified message bundle.
-//      *
-//      * @param bundleName fully qualified path of the class name
-//      * @param clazz the class where the constants will exist
-//      */
-//     public static void initializeMessages(final String bundleName, final Class clazz) {
-//         if (System.getSecurityManager() is null) {
-//             load(bundleName, clazz);
-//             return;
-//         }
-//         AccessController.doPrivileged(new PrivilegedAction() {
-//             public Object run() {
-//                 load(bundleName, clazz);
-//                 return null;
-//             }
-//         });
-//     }
-//
-//     /*
-//      * Perform the string substitution on the given message with the specified args.
-//      * See the class comment for exact details.
-//      */
-//     private static String internalBind(String message, Object[] args, String argZero, String argOne) {
-//         if (message is null)
-//             return "No message available."; //$NON-NLS-1$
-//         if (args is null || args.length is 0)
-//             args = EMPTY_ARGS;
-//
-//         int length = message.length();
-//         //estimate correct size of string buffer to avoid growth
-//         int bufLen = length + (args.length * 5);
-//         if (argZero !is null)
-//             bufLen += argZero.length() - 3;
-//         if (argOne !is null)
-//             bufLen += argOne.length() - 3;
-//         StringBuffer buffer = new StringBuffer(bufLen < 0 ? 0 : bufLen);
-//         for (int i = 0; i < length; i++) {
-//             char c = message.charAt(i);
-//             switch (c) {
-//                 case '{' :
-//                     int index = message.indexOf('}', i);
-//                     // if we don't have a matching closing brace then...
-//                     if (index is -1) {
-//                         buffer.append(c);
-//                         break;
-//                     }
-//                     i++;
-//                     if (i >= length) {
-//                         buffer.append(c);
-//                         break;
-//                     }
-//                     // look for a substitution
-//                     int number = -1;
-//                     try {
-//                         number = Integer.parseInt(message.substring(i, index));
-//                     } catch (NumberFormatException e) {
-//                         throw new IllegalArgumentException();
-//                     }
-//                     if (number is 0 && argZero !is null)
-//                         buffer.append(argZero);
-//                     else if (number is 1 && argOne !is null)
-//                         buffer.append(argOne);
-//                     else {
-//                         if (number >= args.length || number < 0) {
-//                             buffer.append("<missing argument>"); //$NON-NLS-1$
-//                             i = index;
-//                             break;
-//                         }
-//                         buffer.append(args[number]);
-//                     }
-//                     i = index;
-//                     break;
-//                 case '\'' :
-//                     // if a single quote is the last char on the line then skip it
-//                     int nextIndex = i + 1;
-//                     if (nextIndex >= length) {
-//                         buffer.append(c);
-//                         break;
-//                     }
-//                     char next = message.charAt(nextIndex);
-//                     // if the next char is another single quote then write out one
-//                     if (next is '\'') {
-//                         i++;
-//                         buffer.append(c);
-//                         break;
-//                     }
-//                     // otherwise we want to read until we get to the next single quote
-//                     index = message.indexOf('\'', nextIndex);
-//                     // if there are no more in the string, then skip it
-//                     if (index is -1) {
-//                         buffer.append(c);
-//                         break;
-//                     }
-//                     // otherwise write out the chars inside the quotes
-//                     buffer.append(message.substring(nextIndex, index));
-//                     i = index;
-//                     break;
-//                 default :
-//                     buffer.append(c);
-//             }
-//         }
-//         return buffer.toString();
-//     }
-//
-//     /*
-//      * Build an array of property files to search.  The returned array contains
-//      * the property fields in order from most specific to most generic.
-//      * So, in the FR_fr locale, it will return file_fr_FR.properties, then
-//      * file_fr.properties, and finally file.properties.
-//      */
-//     private static String[] buildVariants(String root) {
-//         if (nlSuffixes is null) {
-//             //build list of suffixes for loading resource bundles
-//             String nl = Locale.getDefault().toString();
-//             ArrayList result = new ArrayList(4);
-//             int lastSeparator;
-//             while (true) {
-//                 result.add('_' + nl + EXTENSION);
-//                 lastSeparator = nl.lastIndexOf('_');
-//                 if (lastSeparator is -1)
-//                     break;
-//                 nl = nl.substring(0, lastSeparator);
-//             }
-//             //add the empty suffix last (most general)
-//             result.add(EXTENSION);
-//             nlSuffixes = (String[]) result.toArray(new String[result.size()]);
-//         }
-//         root = root.replace('.', '/');
-//         String[] variants = new String[nlSuffixes.length];
-//         for (int i = 0; i < variants.length; i++)
-//             variants[i] = root + nlSuffixes[i];
-//         return variants;
-//     }
-//
-//     private static void computeMissingMessages(String bundleName, Class clazz, Map fieldMap, Field[] fieldArray, bool isAccessible) {
-//         // iterate over the fields in the class to make sure that there aren't any empty ones
-//         final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
-//         final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
-//         final int numFields = fieldArray.length;
-//         for (int i = 0; i < numFields; i++) {
-//             Field field = fieldArray[i];
-//             if ((field.getModifiers() & MOD_MASK) !is MOD_EXPECTED)
-//                 continue;
-//             //if the field has a a value assigned, there is nothing to do
-//             if (fieldMap.get(field.getName()) is ASSIGNED)
-//                 continue;
-//             try {
-//                 // Set a value for this empty field. We should never get an exception here because
-//                 // we know we have a public static non-final field. If we do get an exception, silently
-//                 // log it and continue. This means that the field will (most likely) be un-initialized and
-//                 // will fail later in the code and if so then we will see both the NPE and this error.
-//                 String value = "NLS missing message: " + field.getName() + " in: " + bundleName; //$NON-NLS-1$ //$NON-NLS-2$
-//                 if (Debug.DEBUG_MESSAGE_BUNDLES)
-//                     System.out.println(value);
-//                 log(SEVERITY_WARNING, value, null);
-//                 if (!isAccessible)
-//                     field.setAccessible(true);
-//                 field.set(null, value);
-//             } catch (Exception e) {
-//                 log(SEVERITY_ERROR, "Error setting the missing message value for: " + field.getName(), e); //$NON-NLS-1$
-//             }
-//         }
-//     }
-//
-//     /*
-//      * Load the given resource bundle using the specified class loader.
-//      */
-//     static void load(final String bundleName, Class clazz) {
-//         long start = System.currentTimeMillis();
-//         final Field[] fieldArray = clazz.getDeclaredFields();
-//         ClassLoader loader = clazz.getClassLoader();
-//
-//         bool isAccessible = (clazz.getModifiers() & Modifier.PUBLIC) !is 0;
-//
-//         //build a map of field names to Field objects
-//         final int len = fieldArray.length;
-//         Map fields = new HashMap(len * 2);
-//         for (int i = 0; i < len; i++)
-//             fields.put(fieldArray[i].getName(), fieldArray[i]);
-//
-//         // search the variants from most specific to most general, since
-//         // the MessagesProperties.put method will mark assigned fields
-//         // to prevent them from being assigned twice
-//         final String[] variants = buildVariants(bundleName);
-//         for (int i = 0; i < variants.length; i++) {
-//             // loader is null if we're launched off the Java boot classpath
-//             final InputStream input = loader is null ? ClassLoader.getSystemResourceAsStream(variants[i]) : loader.getResourceAsStream(variants[i]);
-//             if (input is null)
-//                 continue;
-//             try {
-//                 final MessagesProperties properties = new MessagesProperties(fields, bundleName, isAccessible);
-//                 properties.load(input);
-//             } catch (IOException e) {
-//                 log(SEVERITY_ERROR, "Error loading " + variants[i], e); //$NON-NLS-1$
-//             } finally {
-//                 if (input !is null)
-//                     try {
-//                         input.close();
-//                     } catch (IOException e) {
-//                         // ignore
-//                     }
-//             }
-//         }
-//         computeMissingMessages(bundleName, clazz, fields, fieldArray, isAccessible);
-//         if (Debug.DEBUG_MESSAGE_BUNDLES)
-//             System.out.println("Time to load message bundle: " + bundleName + " was " + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-//     }
-//
-//     /*
-//      * The method adds a log entry based on the error message and exception.
-//      * The output is written to the System.err.
-//      *
-//      * This method is only expected to be called if there is a problem in
-//      * the NLS mechanism. As a result, translation facility is not available
-//      * here and messages coming out of this log are generally not translated.
-//      *
-//      * @param severity - severity of the message (SEVERITY_ERROR or SEVERITY_WARNING)
-//      * @param message - message to log
-//      * @param e - exception to log
-//      */
-//     static void log(int severity, String message, Exception e) {
-//         if (frameworkLog !is null) {
-//             frameworkLog.log(new FrameworkLogEntry("org.eclipse.osgi", severity, 1, message, 0, e, null)); //$NON-NLS-1$
-//             return;
-//         }
-//         String statusMsg;
-//         switch (severity) {
-//             case SEVERITY_ERROR :
-//                 statusMsg = "Error: "; //$NON-NLS-1$
-//                 break;
-//             case SEVERITY_WARNING :
-//                 // intentionally fall through:
-//             default :
-//                 statusMsg = "Warning: "; //$NON-NLS-1$
-//         }
-//         if (message !is null)
-//             statusMsg += message;
-//         if (e !is null)
-//             statusMsg += ": " + e.getMessage(); //$NON-NLS-1$
-//         System.err.println(statusMsg);
-//         if (e !is null)
-//             e.printStackTrace();
-//     }
-//
-//     /*
-//      * Class which sub-classes java.util.Properties and uses the #put method
-//      * to set field values rather than storing the values in the table.
-//      */
-//     private static class MessagesProperties extends Properties {
-//
-//         private static final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
-//         private static final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
-//         private static final long serialVersionUID = 1L;
-//
-//         private final String bundleName;
-//         private final Map fields;
-//         private final bool isAccessible;
-//
-//         public MessagesProperties(Map fieldMap, String bundleName, bool isAccessible) {
-//             super();
-//             this.fields = fieldMap;
-//             this.bundleName = bundleName;
-//             this.isAccessible = isAccessible;
-//         }
-//
-//         /* (non-Javadoc)
-//          * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
-//          */
-//         public synchronized Object put(Object key, Object value) {
-//             Object fieldObject = fields.put(key, ASSIGNED);
-//             // if already assigned, there is nothing to do
-//             if (fieldObject is ASSIGNED)
-//                 return null;
-//             if (fieldObject is null) {
-//                 final String msg = "NLS unused message: " + key + " in: " + bundleName;//$NON-NLS-1$ //$NON-NLS-2$
-//                 if (Debug.DEBUG_MESSAGE_BUNDLES)
-//                     System.out.println(msg);
-//                 log(SEVERITY_WARNING, msg, null);
-//                 return null;
-//             }
-//             final Field field = (Field) fieldObject;
-//             //can only set value of public static non-final fields
-//             if ((field.getModifiers() & MOD_MASK) !is MOD_EXPECTED)
-//                 return null;
-//             try {
-//                 // Check to see if we are allowed to modify the field. If we aren't (for instance
-//                 // if the class is not public) then change the accessible attribute of the field
-//                 // before trying to set the value.
-//                 if (!isAccessible)
-//                     field.setAccessible(true);
-//                 // Set the value into the field. We should never get an exception here because
-//                 // we know we have a public static non-final field. If we do get an exception, silently
-//                 // log it and continue. This means that the field will (most likely) be un-initialized and
-//                 // will fail later in the code and if so then we will see both the NPE and this error.
-//                 field.set(null, value);
-//             } catch (Exception e) {
-//                 log(SEVERITY_ERROR, "Exception setting field value.", e); //$NON-NLS-1$
-//             }
-//             return null;
-//         }
-//     }
-}
+    private static void computeMissingMessages(String bundleName, Class clazz, Map fieldMap, Field[] fieldArray, bool isAccessible) {
+        // iterate over the fields in the class to make sure that there aren't any empty ones
+        final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
+        final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
+        final int numFields = fieldArray.length_;
+        for (int i = 0; i < numFields; i++) {
+            Field field = fieldArray[i];
+            if ((field.getModifiers() & MOD_MASK) !is MOD_EXPECTED)
+                continue;
+            //if the field has a a value assigned, there is nothing to do
+            if (fieldMap.get(field.getName()) is ASSIGNED)
+                continue;
+            try {
+                // Set a value for this empty field. We should never get an exception here because
+                // we know we have a public static non-final field. If we do get an exception, silently
+                // log it and continue. This means that the field will (most likely) be un-initialized and
+                // will fail later in the code and if so then we will see both the NPE and this error.
+                String value = "NLS missing message: " + field.getName() + " in_: " + bundleName; //$NON-NLS-1$ //$NON-NLS-2$
+                if (Debug.DEBUG_MESSAGE_BUNDLES)
+                    System.out_.println(value);
+                log(SEVERITY_WARNING, value, null);
+                if (!isAccessible)
+                    field.setAccessible(true);
+                field.set(null, value);
+            } catch (Exception e) {
+                log(SEVERITY_ERROR, "Error setting the missing message value for: " + field.getName(), e); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /*
+     * Load the given resource bundle using the specified class loader.
+     */
+    static void load(/+FIXFINAL+/ String bundleName, Class clazz) {
+        long start = System.currentTimeMillis();
+        final Field[] fieldArray = clazz.getDeclaredFields();
+        ClassLoader loader = clazz.getClassLoader();
+
+        bool isAccessible = (clazz.getModifiers() & Modifier.PUBLIC) !is 0;
+
+        //build a map of field names to Field objects
+        final int len = fieldArray.length_;
+        Map fields = new HashMap(len * 2);
+        for (int i = 0; i < len; i++)
+            fields.put(fieldArray[i].getName(), fieldArray[i]);
+
+        // search the variants from most specific to most general, since
+        // the MessagesProperties.put method will mark assigned fields
+        // to prevent them from being assigned twice
+        final String[] variants = buildVariants(bundleName);
+        for (int i = 0; i < variants.length_; i++) {
+            // loader==null if we're launched off the Java boot classpath
+            final InputStream input = loader is null ? ClassLoader.getSystemResourceAsStream(variants[i]) : loader.getResourceAsStream(variants[i]);
+            if (input is null)
+                continue;
+            try {
+                final MessagesProperties properties = new MessagesProperties(fields, bundleName, isAccessible);
+                properties.load(input);
+            } catch (IOException e) {
+                log(SEVERITY_ERROR, "Error loading " + variants[i], e); //$NON-NLS-1$
+            } finally {
+                if (input !is null)
+                    try {
+                        input.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+            }
+        }
+        computeMissingMessages(bundleName, clazz, fields, fieldArray, isAccessible);
+        if (Debug.DEBUG_MESSAGE_BUNDLES)
+            System.out_.println("Time to load message bundle: " + bundleName + " was " + (System.currentTimeMillis() - start) + "ms."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+    /*
+     * The method adds a log entry based on the error message and exception.
+     * The output is written to the System.err.
+     *
+     * This method is only expected to be called if there is a problem in
+     * the NLS mechanism. As a result, translation facility is not available
+     * here and messages coming out of this log are generally not translated.
+     *
+     * @param severity - severity of the message (SEVERITY_ERROR or SEVERITY_WARNING)
+     * @param message - message to log
+     * @param e - exception to log
+     */
+    static void log(int severity, String message, Exception e) {
+        if (frameworkLog !is null) {
+            frameworkLog.log(new FrameworkLogEntry("org.eclipse.osgi", severity, 1, message, 0, e, null)); //$NON-NLS-1$
+            return;
+        }
+        String statusMsg;
+        switch (severity) {
+            case SEVERITY_ERROR :
+                statusMsg = "Error: "; //$NON-NLS-1$
+                break;
+            case SEVERITY_WARNING :
+                // intentionally fall through:
+            default :
+                statusMsg = "Warning: "; //$NON-NLS-1$
+        }
+        if (message !is null)
+            statusMsg += message;
+        if (e !is null)
+            statusMsg += ": " + e.getMessage(); //$NON-NLS-1$
+        System.err.println(statusMsg);
+        if (e !is null)
+            e.printStackTrace();
+    }
+
+    /*
+     * Class which sub-classes java.util.Properties and uses the #put method
+     * to set field values rather than storing the values in the table.
+     */
+    private static class MessagesProperties : Properties {
+
+        private static final int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC;
+        private static final int MOD_MASK = MOD_EXPECTED | Modifier.FINAL;
+        private static final long serialVersionUID = 1L;
+
+        private final String bundleName;
+        private final Map fields;
+        private final bool isAccessible;
+
+        public this(Map fieldMap, String bundleName, bool isAccessible) {
+            super();
+            this.fields = fieldMap;
+            this.bundleName = bundleName;
+            this.isAccessible = isAccessible;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
+         */
+        public synchronized Object put(Object key, Object value) {
+            Object fieldObject = fields.put(key, ASSIGNED);
+            // if already assigned, there is nothing to do
+            if (fieldObject is ASSIGNED)
+                return null;
+            if (fieldObject is null) {
+                final String msg = "NLS unused message: " + key + " in_: " + bundleName;//$NON-NLS-1$ //$NON-NLS-2$
+                if (Debug.DEBUG_MESSAGE_BUNDLES)
+                    System.out_.println(msg);
+                log(SEVERITY_WARNING, msg, null);
+                return null;
+            }
+            final Field field = cast(Field) fieldObject;
+            //can only set value of public static non-final fields
+            if ((field.getModifiers() & MOD_MASK) !is MOD_EXPECTED)
+                return null;
+            try {
+                // Check to see if we are allowed to modify the field. If we aren't (for instance
+                // if the class is not public) then change the accessible attribute of the field
+                // before trying to set the value.
+                if (!isAccessible)
+                    field.setAccessible(true);
+                // Set the value into the field. We should never get an exception here because
+                // we know we have a public static non-final field. If we do get an exception, silently
+                // log it and continue. This means that the field will (most likely) be un-initialized and
+                // will fail later in the code and if so then we will see both the NPE and this error.
+                field.set(null, value);
+            } catch (Exception e) {
+                log(SEVERITY_ERROR, "Exception setting field value.", e); //$NON-NLS-1$
+            }
+            return null;
+        }
+    }
+}
\ No newline at end of file