blob: e51886d8484450bfba4d7d5229562d4ddc9b689e [file] [log] [blame]
<!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 JDT/UI's new <a href="../../downloads/tools/message_bundles/com.ibm.zrh.eclipse.nls_1.0.0.zip">version
1.0.0</a> of the tool 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>
<p>
Eclipse 3.1: Think Fast!
</p>
</body>
</html>