platform-core-home/documents/3.1/message_bundles.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (download) (as text) (annotate)
Tue Feb 22 20:19:56 2005 UTC (4 years, 9 months ago) by johna
Branch: MAIN
Changes since 1.5: +1 -1 lines
Revert previous change
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<title>Eclipse Platform/Core</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" href="http://dev.eclipse.org/default_style.css" type="text/css">
<STYLE TYPE="text/css">
<!--
CODE { font-size: 80% }
-->
</STYLE>
</head>
<body>
<center>
	<font class=indextop>core</font><br>
	<font class=indexsub>the foundation of the platform</font><p></p>
	<a href="../../main.html">[home]</a>
	<a href="../../documents.html">[documents]</a>
	<a href="../../downloads.html">[downloads]</a>
	<a href="../../resources.html">[resources]</a>
	<a href="../../planning.html">[planning]</a>
	<a href="../../testing.html">[testing]</a>
</center>
<br>
<table BORDER=0 CELLPADDING=2 WIDTH="100%" >
	<tr> 
		<td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF">Message Bundles</font></b></td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><b>Description</b> <p>Standard Java ResourceBundles have quite 
        inefficient space characteristics. Since a running Eclipse tends to have 
        many externalized messages we have implemented a new message bundle story 
        to be used in Eclipse. The mechanism is quite simple and completely generic 
        - it can be used anywhere.</p>
      <p>Summary of the new approach:</p>
      <ul>
        <li>messages.properties - this file is same as before except all keys 
          need to be valid Java identifiers.
        <li>Each message file has a corresponding Java class.
        <li>Each key/value pair in the file has a public static String field whose 
          name is the same as the message key.
        <li>When message bundles are loaded, the values of the fields are set 
          to be the values from the messages.properties files.
        <li>The message properties files are purged from memory.
      </ul>
      <p>When creating a new message:</p>
      <ul>
        <li>create a field in your Messages.java file</li>
        <li>create a key/value pair in your messages.properties file where the 
          key name matches the field name</li>
        <li>to reference the message, simply reference the field (e.g. Messages.my_key) 
          rather than the standard lookup</li>
      </ul>
      <p>&nbsp;</p></td>
	</tr>
		<tr> 
		<td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF">File Formats</font></b></td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><p><b>Client Code</b></p>
Old Code: 
<p>
      <pre><code>public class MyClass {
&nbsp;&nbsp;&nbsp;public void myMethod() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String message;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// no args
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message = Messages.getString("key.one"); //$NON-NLS-1$
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// bind one arg
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message = MessageFormat.format(Messages.getString("key.two"), new Object[] {"example usage"}); //$NON-NLS-1$ //$NON-NLS-2$
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;}
}</code></pre>
      </p>

New Code: 
<p><pre><code>
public class MyClass {
&nbsp;&nbsp;&nbsp;public void myMethod() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String message;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// no args
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message = Messages.key_one;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// bind one arg
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message = NLS.bind(Messages.key_two, "example usage"); //$NON-NLS-1$
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;}
}</code></pre></p>
      <p>&nbsp;</p>
	  </td>
	  </tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><p><b>Messages.java</b></p>
Old Code: 
      <pre><code>public class Messages {
&nbsp;&nbsp;&nbsp;private static final String BUNDLE_NAME = &quot;org.eclipse.core.utils.messages&quot;; //$NON-NLS-1$
&nbsp;&nbsp;&nbsp;private static final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME);
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;public static String getString(String key) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return bundle.getString(key);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (MissingResourceException e) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return key;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;}
}</code></pre>

New Code: 
<pre><code>
import org.eclipse.osgi.util.NLS;

public class Messages extends NLS {
&nbsp;&nbsp;&nbsp;private static final String BUNDLE_NAME = &quot;org.eclipse.core.utils.messages&quot;; //$NON-NLS-1$
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;public static String key_one;
&nbsp;&nbsp;&nbsp;public static String key_two;
&nbsp;&nbsp;&nbsp;...
&nbsp;&nbsp;&nbsp;static {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NLS.initializeMessages(BUNDLE_NAME, Messages.class);
&nbsp;&nbsp;&nbsp;}
}</code></pre>
      <p>&nbsp;</p>
	  </td>
	  </tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><p><b>messages.properties</b></p>
Old Code:
<pre><code>key.one = Hello world.
key.two = This is an {0} of binding with one argument.
</code></pre>
New Code:
<pre><code>key_one = Hello world.
key_two = This is an {0} of binding with one argument.
</code></pre>
      </p>
      <p>&nbsp; </p></td>
	  </td>
	</tr>
	<tr> 
		<td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF">Performance</font></b></td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><p><b>Time</b> </p>
      <ul>
        <li>Using a message is marginally faster since it is just a field access 
          rather than a lookup in the resource bundle.</li>
        <li>Time to load and initialize a bundle is VM dependant but we have seen 
          5% to 46% improvements. </li>
      </ul>
      <p>&nbsp;</p>
      </td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><p><b>Memory Footprint</b> </p>
      <ul>
        <li>This is very much a scalability play. The more you use, the more you 
          save.</li>
        <li>The rough space savings is 88 + 4N bytes per message where N is the 
          number of characters in the key.</li>
        <li>The absolute best-case scenerio for the Eclipse SDK, if every property 
          file is loaded and every key referenced, is roughly 4.5M of memory. 
          (based on the January 11, 2005 integration build)</li>
        <li>Realistic scenarios for the Eclipse IDE should see savings on the 
          order of 500KB </li>
      </ul>
      <p>&nbsp;</p>
      </td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><b>Other benefits</b> <ul>
        <li>Easily catch missing keys - Message lookups are now field accesses 
          so you cannot reference a key that doesn't exist or you will get a compile 
          error. </li>
        <li>Easily find typos in code when referencing keys - Each key is represented 
          by a field in the class so if the referencing code makes a spelling 
          error, then you will get a compile error.</li>
        <li>Find unused keys - During the development cycle code is deleted, moved 
          and messages are changed. As a result there are keys in the messages.properties 
          file which are never referenced.These can easily be found now since 
          you can just do a search for references to the field. If there are no 
          references, then delete the field from the class and the key/value pair 
          from the file.</li>
      </ul>
      <p>&nbsp;</p></td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><b>Drawbacks</b> 
	<ul>
	<li>There are now 2 files to maintain - Now the messages.properties and the java file must be kept in sync. There
	is an opportunity for tooling to help with this; a validation tool could indicate problems with markers. Currently
	there are debug options which log entries which exsit in one file but not the other.</li>
	</ul>
	<p>&nbsp;
	</p>
	</td>
	</tr>
	

	<tr> 
		<td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF">Tools</font></b></td>
	</tr>
	<tr> 
		<td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td>
    	
    <td WIDTH="98%"><b>Conversion</b> <p>We have written a tool which aids in 
        converting from the basic Java resource bundle look-up mechanism, to the 
        new format. There is no requirement to do this conversion unless you want 
        to take advantage of the new mechanism.</p>
      <p><em>Note that the message bundle access class is replaced when the tool 
        is run. If you define extra code, constants, etc in that class then please 
        read the notes below to ensure that you don't have problems.</em></p>
      <p>Here are the steps to use when converting your code.</p>
      <ul>
        <li>Download <a href="../../downloads/tools/message_bundles/com.example.nls_1.0.0.zip">version 1.0.0</a> 
          and install the plug-in.</li>
        <li>Run Eclipse.</li>
        <li>Synchronize with the repository. (you will be using the Synchronize 
          view as your compare browser to view changes)</li>
        <li>Select your message bundle access class. (e.g. the class which has 
          the <code>#getString(String)</code> method in it)</li>
        <li>From the context menu, choose &quot;Convert Message Bundle&quot;.</li>
        <li>Choose the class's associated .properties file from the resulting 
          &quot;Open Resource...&quot; dialog.</li>
        <li>Use the Synchronize view to review the changes.</li>
        <li>Release the new code.</li>
      </ul>
      <p><strong>Notes:</strong> </p>
      <p>When using the NLS tooling from previous Eclipse releases, the java file 
        which was created had the format of the &quot;old&quot; Messages.java 
        file as described above. (basic class with <code>#getString(String)</code> method) Some plug-in owners have created extra helper 
        methods on the class to aid in their message bundle lookup. Since the 
        conversion tool has only basic functionality, these plug-in developers 
        must perform a couple of extra steps before running the tool.</p>
      <p>Essentially what you want to do is get your java file into the basic 
        template form. This is possible via using existing refactorings. For instance, 
        if your class defines a method like this:</p>
      <pre><code>public String getString(String key, Object binding) {
&nbsp;&nbsp;&nbsp;return MessageFormat.format(getString(key), new Object[] {binding});
}</code></pre>
<p>Then you want to do the following:</p>
<ol>
<li>Change the method body to be: <code>return NLS.bind(getString(key), binding);</code></li>
<li>Select the method name and from the context menu choose the &quot;Inline&quot; 
        refactoring. This will replace calls to this method in your code with 
        calls to the code in step 1.</li>
        <li>Run the tool. Since only calls to <code>#getString(String)</code> exist now, 
          the tool will run sucessfully.</li>
</ol>
	</tr>
</table>

<table width="100%">
<tr><td style="background:#0080C0"><b><span style="color:white">Eclipse 3.1: Think Fast!</span></b></td></tr>
</table>

</body>
</html>