| /******************************************************************************* |
| * Copyright (c) 2000, 2013 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.aspectj.org.eclipse.jdt.internal.compiler.util; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Modifier; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| @SuppressWarnings({"rawtypes", "unchecked"}) |
| public final class Messages { |
| 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 Map fields; |
| |
| public MessagesProperties(Field[] fieldArray, String bundleName) { |
| super(); |
| final int len = fieldArray.length; |
| this.fields = new HashMap(len * 2); |
| for (int i = 0; i < len; i++) { |
| this.fields.put(fieldArray[i].getName(), fieldArray[i]); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object) |
| */ |
| public synchronized Object put(Object key, Object value) { |
| try { |
| Field field = (Field) this.fields.get(key); |
| if (field == null) { |
| return null; |
| } |
| //can only set value of public static non-final fields |
| if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED) |
| return null; |
| // 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. |
| try { |
| field.set(null, value); |
| } catch (Exception e) { |
| // ignore |
| } |
| } catch (SecurityException e) { |
| // ignore |
| } |
| return null; |
| } |
| } |
| |
| |
| private static String[] nlSuffixes; |
| private static final String EXTENSION = ".properties"; //$NON-NLS-1$ |
| |
| private static final String BUNDLE_NAME = "org.aspectj.org.eclipse.jdt.internal.compiler.messages";//$NON-NLS-1$ |
| |
| private Messages() { |
| // Do not instantiate |
| } |
| |
| public static String compilation_unresolvedProblem; |
| public static String compilation_unresolvedProblems; |
| public static String compilation_request; |
| public static String compilation_loadBinary; |
| public static String compilation_process; |
| public static String compilation_write; |
| public static String compilation_done; |
| public static String compilation_units; |
| public static String compilation_unit; |
| public static String compilation_internalError; |
| public static String compilation_beginningToCompile; |
| public static String compilation_processing; |
| public static String output_isFile; |
| public static String output_notValidAll; |
| public static String output_notValid; |
| public static String problem_noSourceInformation; |
| public static String problem_atLine; |
| public static String abort_invalidAttribute; |
| public static String abort_invalidExceptionAttribute; |
| public static String abort_invalidOpcode; |
| public static String abort_missingCode; |
| public static String abort_againstSourceModel; |
| public static String accept_cannot; |
| public static String parser_incorrectPath; |
| public static String parser_moveFiles; |
| public static String parser_syntaxRecovery; |
| public static String parser_regularParse; |
| public static String parser_missingFile; |
| public static String parser_corruptedFile; |
| public static String parser_endOfFile; |
| public static String parser_endOfConstructor; |
| public static String parser_endOfMethod; |
| public static String parser_endOfInitializer; |
| public static String ast_missingCode; |
| public static String constant_cannotCastedInto; |
| public static String constant_cannotConvertedTo; |
| |
| static { |
| initializeMessages(BUNDLE_NAME, Messages.class); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @return the manipulated String |
| */ |
| public static String bind(String message) { |
| return bind(message, null); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @param binding the object to be inserted into the message |
| * @return the manipulated String |
| */ |
| public static String bind(String message, Object binding) { |
| return bind(message, new Object[] {binding}); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @param binding1 An object to be inserted into the message |
| * @param binding2 A second object to be inserted into the message |
| * @return the manipulated String |
| */ |
| public static String bind(String message, Object binding1, Object binding2) { |
| return bind(message, new Object[] {binding1, binding2}); |
| } |
| |
| /** |
| * Bind the given message's substitution locations with the given string values. |
| * |
| * @param message the message to be manipulated |
| * @param bindings An array of objects to be inserted into the message |
| * @return the manipulated String |
| */ |
| public static String bind(String message, Object[] bindings) { |
| return MessageFormat.format(message, bindings); |
| } |
| |
| /* |
| * Build an array of directories to search |
| */ |
| private static String[] buildVariants(String root) { |
| if (nlSuffixes == 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 == -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; |
| } |
| public static void initializeMessages(String bundleName, Class clazz) { |
| // load the resource bundle and set the fields |
| final Field[] fields = clazz.getDeclaredFields(); |
| load(bundleName, clazz.getClassLoader(), fields); |
| |
| // 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 = fields.length; |
| for (int i = 0; i < numFields; i++) { |
| Field field = fields[i]; |
| if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED) |
| continue; |
| try { |
| // Set the value into the field if its empty. 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. |
| if (field.get(clazz) == null) { |
| String value = "Missing message: " + field.getName() + " in: " + bundleName; //$NON-NLS-1$ //$NON-NLS-2$ |
| field.set(null, value); |
| } |
| } catch (IllegalArgumentException e) { |
| // ignore |
| } catch (IllegalAccessException e) { |
| // ignore |
| } |
| } |
| } |
| /** |
| * Load the given resource bundle using the specified class loader. |
| */ |
| public static void load(final String bundleName, final ClassLoader loader, final Field[] fields) { |
| final String[] variants = buildVariants(bundleName); |
| // search the dirs in reverse order so the cascading defaults is set correctly |
| for (int i = variants.length; --i >= 0;) { |
| InputStream input = (loader == null) |
| ? ClassLoader.getSystemResourceAsStream(variants[i]) |
| : loader.getResourceAsStream(variants[i]); |
| if (input == null) continue; |
| try { |
| final MessagesProperties properties = new MessagesProperties(fields, bundleName); |
| properties.load(input); |
| } catch (IOException e) { |
| // ignore |
| } finally { |
| try { |
| input.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| } |
| } |
| } |