<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2913369703414801920</id><updated>2011-12-03T03:09:00.266-08:00</updated><category term='eclipse-con'/><category term='eclipse-sapphire-0.4'/><category term='eclipse-con-2011-europe'/><category term='ui'/><category term='eclipse-wtp'/><category term='osgi'/><category term='ant'/><category term='java-language-puzzle'/><category term='java'/><category term='eclipse-fproj'/><category term='software engineering'/><category term='coding'/><category term='eclipse'/><category term='eclipse-jdt'/><category term='facets-faq'/><category term='eclipse-sapphire'/><category term='facets'/><title type='text'>Konstantin's Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-6315439418709942347</id><published>2011-12-01T06:53:00.001-08:00</published><updated>2011-12-01T06:53:47.035-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><title type='text'>Announcing Sapphire 0.4 Release</title><content type='html'>&lt;p&gt;It is with great pleasure that I announce availability of &lt;a href="http://www.eclipse.org/sapphire/releases/0.4/"&gt;Sapphire 0.4&lt;/a&gt; release. This release includes major &lt;a href="http://www.eclipse.org/sapphire/releases/0.4/documentation/releases/0.4/enhancements.html"&gt;enhancements&lt;/a&gt;, such as API improvements in services and XML binding, more powerful Sapphire EL and ability to use it in more places, content proposals in text fields, split form, regular multi-section form editor page for cases where master-details presentation isn't appropriate, and much more.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.4/documentation/releases/0.4/enhancements.html"&gt;Enhancements&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.4/documentation/releases/0.4/migration.html"&gt;Migration Guide&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.4/documentation/index.html"&gt;Developer Guide&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.4/"&gt;Downloads&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-6315439418709942347?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/6315439418709942347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=6315439418709942347' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/6315439418709942347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/6315439418709942347'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/12/announcing-sapphire-04-release.html' title='Announcing Sapphire 0.4 Release'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-4124677003022207631</id><published>2011-11-19T17:38:00.001-08:00</published><updated>2011-11-19T17:39:46.995-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='java-language-puzzle'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Java Language Puzzle 3</title><content type='html'>&lt;p&gt;Given the following source listing, explain why the compiler is producing a warning at invocation to the list method and give a solution for removing the warning without resorting to @SuppressWarnings annotation.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public class JavaLanguagePuzzle3
{
    public static void main( String[] args )
    {
        list( &amp;quot;1&amp;quot;, 2, new BigDecimal( &amp;quot;3.5&amp;quot; ) );
    }
    
    private static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; list( T... items )
    {
        return Arrays.asList( items );
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Warning:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;Type safety: A generic array of Object&amp;amp;Serializable&amp;amp;Comparable&amp;lt;?&amp;gt; is created for a varargs parameter&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-4124677003022207631?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/4124677003022207631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=4124677003022207631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/4124677003022207631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/4124677003022207631'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/11/java-language-puzzle-3.html' title='Java Language Puzzle 3'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-6828703229999721753</id><published>2011-10-07T21:21:00.001-07:00</published><updated>2011-10-07T21:25:10.956-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><title type='text'>Announcing Sapphire 0.3.1 Release</title><content type='html'>&lt;p&gt;It is with great pleasure that I announce availability of &lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/"&gt;Sapphire 0.3.1&lt;/a&gt; release. This maintenance release includes 64 bug fixes and &lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/documentation/releases/0.3.1/enhancements.html"&gt;enhancements&lt;/a&gt;. Adopters of 0.3 release can expect full backwards compatibility. No migration guide is being published.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/documentation/releases/0.3.1/enhancements.html"&gt;Enhancements&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/documentation/index.html"&gt;Developer Guide&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/"&gt;Downloads&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-6828703229999721753?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/6828703229999721753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=6828703229999721753' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/6828703229999721753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/6828703229999721753'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/10/announcing-sapphire-031-release.html' title='Announcing Sapphire 0.3.1 Release'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2272381244122136675</id><published>2011-08-24T22:41:00.001-07:00</published><updated>2011-08-24T22:45:01.655-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-jdt'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Using Sapphire to Work with Java Types</title><content type='html'>&lt;p&gt;This article covers an intermediate topic related to &lt;a href="http://www.eclipse.org/sapphire/"&gt;Sapphire&lt;/a&gt;. Those unfamiliar with Sapphire should first read &lt;a href="http://www.eclipse.org/sapphire/documentation/latest/introduction/index.html"&gt;the introduction&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;When implementing Eclipse tooling that works with Java projects, a frequent requirement is to deliver models and UI that reference Java types (classes, interfaces, enumerations and annotations). Implementing this from scratch, even using the excellent API provided by JDT is a challenge. Fortunately, Sapphire's JDT integration makes this quite easy.&lt;/p&gt;  &lt;p&gt;The first step is the model.&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; margin-left: 20px; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@Type( base = JavaTypeName.class )
@Reference( target = JavaType.class )
@Label( standard = &amp;quot;filter&amp;quot; )
@JavaTypeConstraint( kind = { JavaTypeKind.CLASS, JavaTypeKind.INTERFACE }, type = &amp;quot;java.io.FileFilter&amp;quot; )
@MustExist
@Required

ValueProperty PROP_FILTER = new ValueProperty( TYPE, &amp;quot;Filter&amp;quot; );

ReferenceValue&amp;lt;JavaTypeName,JavaType&amp;gt; getFilter();
void setFilter( String value );
void setFilter( JavaTypeName value );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we utilize reference value construct which states that the property holds a JavaTypeName which is resolvable to a JavaType. The resolution is provided by the framework and works as long as the model is loaded in the context of a Java project.&lt;/p&gt;

&lt;p&gt;The @JavaTypeConstraint annotation specifies that the referenced type must be a class or an interface and that it must derive from java.io.FileFilter type.&lt;/p&gt;

&lt;p&gt;The @MustExist annotation specifies that the named type must be present in the project.&lt;/p&gt;

&lt;p&gt;The @Required annotation specifies that the property must have a value (null is not ok).&lt;/p&gt;

&lt;p&gt;The next step is the UI definition. Here we create an editor section with a single property editor, but the property editor is, of course, not limited to editor sections. It can be used in any form context.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; margin-left: 20px; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&lt;font color="#888888"&gt;&amp;lt;section&amp;gt;
    &amp;lt;content&amp;gt;&lt;/font&gt;
        &amp;lt;property-editor&amp;gt;Filter&amp;lt;/property-editor&amp;gt;
    &lt;font color="#888888"&gt;&amp;lt;/content&amp;gt;
&amp;lt;/section&amp;gt;&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is all that is necessary to define a model property that references a Java type and to present that property in the UI. Once this example is executed, you will see a property editor that is composed of a label, a text box, two action buttons and a validation feedback marker.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-_lrC0LVflCE/TlXgYRjE2jI/AAAAAAAAAEc/4mT5C5RrXsY/s1600-h/Capture-14.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-1" border="0" alt="Capture-1" src="http://lh6.ggpht.com/-wPJzuROwFQo/TlXgY9O5syI/AAAAAAAAAEg/wfa4SqvPuOQ/Capture-1_thumb2.png?imgmax=800" width="504" height="21" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on the validation feedback marker shows the problem message along with wealth of semantic information about the property.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-IDs3KNNkZ2Y/TlXgZEQHh4I/AAAAAAAAAEk/6XsLL8Neyfo/s1600-h/Capture-24.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-2" border="0" alt="Capture-2" src="http://lh6.ggpht.com/-xP7F41xaAdU/TlXgZliC_qI/AAAAAAAAAEo/5jdY0t0OwMI/Capture-2_thumb2.png?imgmax=800" width="504" height="290" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The browse button provides the means to select from among existing Java types using JDT's type selection dialog. The framework automatically constraints the contents of the dialog based on @JavaTypeConstraint annotation.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/-PmHn5uHCyZI/TlXgaLn9y5I/AAAAAAAAAEs/vDxsBx9cFDw/s1600-h/Capture-34.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-3" border="0" alt="Capture-3" src="http://lh4.ggpht.com/-iBAwNPDAWOs/TlXgdsmU-DI/AAAAAAAAAEw/Se4b6B2fb5c/Capture-3_thumb2.png?imgmax=800" width="536" height="63" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-n99YdxSfmI4/TlXgefLadsI/AAAAAAAAAE0/TB6MfQfzw44/s1600-h/Capture-44.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-4" border="0" alt="Capture-4" src="http://lh5.ggpht.com/-O9z_3J4-SK8/TlXgfXZmf-I/AAAAAAAAAE4/OdSs_cTG3eU/Capture-4_thumb2.png?imgmax=800" width="501" height="526" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The create button provides the means to define a new Java type if the specified type name cannot be resolved.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-LKNcTQGOkuI/TlXgfi0R_EI/AAAAAAAAAE8/FSZaICW0AL8/s1600-h/Capture-54.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-5" border="0" alt="Capture-5" src="http://lh4.ggpht.com/-LbdaSyieoHE/TlXggDNqC0I/AAAAAAAAAFA/wulL-6AP4so/Capture-5_thumb2.png?imgmax=800" width="555" height="60" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since @JavaTypeConstraint annotation in this example specifies that the property can reference either a class or an interface, the user is presented with a choice after clicking on the create button.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-Qsf8-Ogaqcs/TlXggmXthVI/AAAAAAAAAFE/xXQEvIadoMk/s1600-h/Capture-64.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-6" border="0" alt="Capture-6" src="http://lh3.ggpht.com/-E9kQjteC76c/TlXghPCFK-I/AAAAAAAAAFI/H2bgJ9KNTWs/Capture-6_thumb2.png?imgmax=800" width="663" height="77" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the appropriate option is selected, the new type is created and opened in the Java editor. The created type derives from the type specified in @JavaTypeConstraint annotation and is formatted according to user's format preferences.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-SV8ZEsNlTkg/TlXghZhvsYI/AAAAAAAAAFM/EyWM8DSqhtQ/s1600-h/Capture-74.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Capture-7" border="0" alt="Capture-7" src="http://lh4.ggpht.com/-BgLI1OKT_Tc/TlXgh673RoI/AAAAAAAAAFQ/8_jrt41MVPs/Capture-7_thumb2.png?imgmax=800" width="676" height="275" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that this article covers features in &lt;a href="http://www.eclipse.org/sapphire/releases/0.3.1/"&gt;0.3.1&lt;/a&gt; and &lt;a href="http://www.eclipse.org/sapphire/releases/0.4/"&gt;0.4&lt;/a&gt; releases of Sapphire, which at the time of this writing are still in development. A subset of the described features is available in version &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/"&gt;0.3&lt;/a&gt;, which is the latest released version. Please direct all questions to &lt;a href="http://www.eclipse.org/forums/index.php?t=thread&amp;amp;frm_id=192"&gt;the forum&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2272381244122136675?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2272381244122136675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2272381244122136675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2272381244122136675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2272381244122136675'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/08/using-sapphire-to-work-with-java-types.html' title='Using Sapphire to Work with Java Types'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-wPJzuROwFQo/TlXgY9O5syI/AAAAAAAAAEg/wfa4SqvPuOQ/s72-c/Capture-1_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-87748889105061579</id><published>2011-08-01T18:18:00.001-07:00</published><updated>2011-08-01T18:18:39.851-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-con'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-con-2011-europe'/><title type='text'>From XML to Form to Diagram with Sapphire</title><content type='html'>&lt;p&gt;Many of the systems that developers and administrators interact with on the daily basis are configured via a menagerie of XML files. Even armed with a schema and a good XML editor, users have a hard time editing these files by hand. A good tooling strategy to address this difficulty is to create a multi-page editor where a user can flip back-n-forth between XML source view and a higher level form-based view. Going a notch further, certain relationships can be presented with one or more diagrams on separate pages.&lt;/p&gt;  &lt;p&gt;Unfortunately, building such multi-page editor using basic Eclipse platform facilities is a daunting challenge. It can take many months to create something half-decent for even smaller schemas. Sapphire can make this a much less daunting task by focusing developer attention on modeling semantics of the data rather than wiring individual widgets.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/-NyUVMofh30s/TjdQVKMMP4I/AAAAAAAAAEU/U1iQWTLKooc/s1600-h/properties-view-14.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="properties-view-1" border="0" alt="properties-view-1" src="http://lh4.ggpht.com/-iqeVwmdUDTs/TjdQVQuf79I/AAAAAAAAAEY/C_cKZQ9NxW8/properties-view-1_thumb2.png?imgmax=800" width="649" height="591" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I have &lt;a href="http://www.eclipsecon.org/europe2011/sessions/xml-form-diagram-sapphire"&gt;proposed a talk&lt;/a&gt; for &lt;a href="http://www.eclipsecon.org/europe2011"&gt;EclipseCon Europe 2011&lt;/a&gt; to present Sapphire as a whole and the new diagram editing features in Sapphire 0.3 (Indigo) release. You can comment and vote on the proposal if you are interested.&lt;/p&gt;  &lt;p&gt;Proposed Talk: &lt;a href="http://www.eclipsecon.org/europe2011/sessions/xml-form-diagram-sapphire"&gt;From XML to Form to Diagram with Sapphire&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Sapphire is a relatively new project at Eclipse started with an initial contribution from Oracle. It is a UI building framework that allows developers to specify UI in terms of higher level constructs like property editors instead of widgets and layouts. This paradigm results in several orders of magnitude improvement in developer productivity while simultaneously delivering better quality UI that is easier to maintain.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-87748889105061579?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/87748889105061579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=87748889105061579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/87748889105061579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/87748889105061579'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/08/from-xml-to-form-to-diagram-with.html' title='From XML to Form to Diagram with Sapphire'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/-iqeVwmdUDTs/TjdQVQuf79I/AAAAAAAAAEY/C_cKZQ9NxW8/s72-c/properties-view-1_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-5650736288938891785</id><published>2011-07-01T15:23:00.001-07:00</published><updated>2011-07-01T15:25:14.651-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire-0.4'/><title type='text'>Sapphire 0.4 : FactsService</title><content type='html'>&lt;p&gt;This is the first in what I hope to be a series of blog posts highlighting new features in the upcoming &lt;a href="http://www.eclipse.org/sapphire/releases/0.4/"&gt;Sapphire 0.4&lt;/a&gt; release. &lt;/p&gt;  &lt;p&gt;When a property is described to a user in documentation one does it with a series of short statements that define its semantics, such as &amp;quot;must be specified&amp;quot; or &amp;quot;maximum value is 100&amp;quot;. When a property is described to &lt;a href="http://www.eclipse.org/sapphire/"&gt;Sapphire&lt;/a&gt; one does it with a series of annotations, such as @Required or @NumericRange. This duplicate specification is a maintenance problem.&lt;/p&gt;  &lt;p&gt;A FactsService provides a means to dynamically derive statements about property's semantics based on property's metadata. The derived facts can then be presented to the user as part of documentation, property editor information popup and in other relevant places.&lt;/p&gt;  &lt;p&gt;A single facts service can produce multiple facts and multiple facts services can be active concurrently for a given property. FactsAggregationServices provides an easier way to consume all facts.&lt;/p&gt;  &lt;p&gt;Sapphire includes a number of FactsService implementations.&lt;/p&gt;  &lt;table style="border-collapse: collapse; margin-left: 20px; margin-right: 20px"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;th style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; background-color: #eee; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;ID&lt;/th&gt;        &lt;th style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; background-color: #eee; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Description&lt;/th&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.JavaTypeConstraint&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about Java type property's constraints by using semantical information specified by @JavaTypeConstraints annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.Static&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property by using static content specified in @Fact and @Facts annotations.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.DefaultValue&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's default value by using semantical information specified by DefaultValueService and @DefaultValue annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.NumericRange&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about numeric value property's range by using semantical information specified by @NumericRange annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.Required&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's optionality by using semantical information specified by @Required annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.ReadOnly&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's read-only state by using semantical information specified by @ReadOnly annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.CountConstraint&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about list property's count constraint by using semantical information specified by @CountConstraint annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.AbsolutePath&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's absolute path requirement by using semantical information specified by @AbsolutePath annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.MustExist&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about existence requirement on the entity referenced by property's value by using semantical information specified by @MustExist annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.NoDuplicates&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about value property's uniqueness constraint by using semantical information specified by @NoDuplicates annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.ValidFileExtensions&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about valid file extensions for property's value by using semantical information specified by @ValidFileExtensions annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.ValidFileSystemResourceType&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about valid file system resource type (file or folder) for property's value by using semantical information specified by @ValidFileSystemResourceType annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.ProjectRelativePath&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's relative to the project path requirement by using semantical information specified by @ProjectRelativePath annotation.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Sapphire.FactsService.WorkspaceRelativePath&lt;/td&gt;        &lt;td style="border-bottom: #000000 1px solid; text-align: left; border-left: #000000 1px solid; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; vertical-align: top; border-top: #000000 1px solid; border-right: #000000 1px solid; padding-top: 5px"&gt;Creates fact statements about property's relative to the workspace path requirement by using semantical information specified by @WorkspaceRelativePath annotation.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p style="margin-left: 20px"&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left: 20px"&gt;This screen capture shows user experience with some of the provided FactsService implementation. See if you can match facts in the screen capture to service implementations above.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-uU0mxmgY_q4/Tg5I-BezydI/AAAAAAAAAEM/r1ak7CzM-YI/s1600-h/FactsService%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="FactsService" border="0" alt="FactsService" src="http://lh3.ggpht.com/-Ed90Mjw4_SE/Tg5I-7rdeyI/AAAAAAAAAEQ/vWbkFDoZEOI/FactsService_thumb%25255B2%25255D.png?imgmax=800" width="672" height="310" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Adopters can provide custom FactService implementations either globally using Sapphire extension system or at the property level using @Service annotation.&lt;/p&gt;  &lt;p style="margin-left: 20px"&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;  &lt;p style="margin-left: 20px"&gt;A simple global FactsService implementation that is triggered by a hypothetical @Since property annotation.&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; margin-left: 20px; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public class SinceVersionFactsService extends FactsService
{
    @Override
    protected void facts( List facts )
    {
        Since since = property().getAnnotation( Since.class );
        facts.add( &amp;quot;Since version &amp;quot; + since.version() + &amp;quot;.&amp;quot; );
    }

    public static class Factory extends ModelPropertyServiceFactory
    {
        @Override
        public boolean applicable( IModelElement element,
                                   ModelProperty property,
                                   Class&amp;lt;? extends ModelPropertyService&amp;gt; service )
        {
            return property.hasAnnotation( Since.class );
        }
    
        @Override
        public ModelPropertyService create( IModelElement element,
                                            ModelProperty property,
                                            Class&amp;lt;? extends ModelPropertyService&amp;gt; service )
        {
            return new SinceVersionFactsService();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p style="margin-left: 20px"&gt;The service implementation is registered in META-INF/sapphire-extension.xml file.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; margin-left: 20px; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&lt;font color="#888888"&gt;&amp;lt;extension xmlns=&amp;quot;http://www.eclipse.org/sapphire/xmlns/extension&amp;quot;&amp;gt;&lt;/font&gt;
    &amp;lt;model-property-service&amp;gt;
        &amp;lt;id&amp;gt;Example.SinceVersionFactsService&amp;lt;/id&amp;gt;
        &amp;lt;type&amp;gt;org.eclipse.sapphire.services.FactsService&amp;lt;/type&amp;gt;
        &amp;lt;factory&amp;gt;example.SinceVersionFactsService$Factory&amp;lt;/factory&amp;gt;
    &amp;lt;/model-property-service&amp;gt;
&lt;font color="#888888"&gt;&amp;lt;/extension&amp;gt;&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Facts can also be statically specified for a given property by using @Fact annotation. Use @Facts annotation to specify multiple facts. The facts contained in these annotations are surfaced by an included FactsService implementation (id:Sapphire.FactsService.Static).&lt;/p&gt;

&lt;p style="margin-left: 20px"&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; margin-left: 20px; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&lt;font color="#888888"&gt;// *** ExampleOne ***&lt;/font&gt;
    
@Fact( statement = &amp;quot;Important fact.&amp;quot;)
    
&lt;font color="#888888"&gt;ValueProperty PROP_EXAMPLE_ONE = new ValueProperty( TYPE, &amp;quot;ExampleOne&amp;quot; );
    
Value&lt;string&gt; getExampleOne();
void setExampleOne( String value );

// *** ExampleMultiple ***&lt;/font&gt;
    
@Facts( { @Fact( statement = &amp;quot;First important fact.&amp;quot; ), @Fact( statement = &amp;quot;Second important fact.&amp;quot; ) } )
    
&lt;font color="#888888"&gt;ValueProperty PROP_EXAMPLE_MULTIPLE = new ValueProperty( TYPE, &amp;quot;ExampleMultiple&amp;quot; );
    
Value&lt;string&gt; getExampleMultiple();
void setExampleMultiple( String value );&lt;/font&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Please direct your comments and questions to &lt;a href="http://www.eclipse.org/forums/index.php/f/192/"&gt;Sapphire adopter forum&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-5650736288938891785?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/5650736288938891785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=5650736288938891785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5650736288938891785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5650736288938891785'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/07/sapphire-04-factsservice.html' title='Sapphire 0.4 : FactsService'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-Ed90Mjw4_SE/Tg5I-7rdeyI/AAAAAAAAAEQ/vWbkFDoZEOI/s72-c/FactsService_thumb%25255B2%25255D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-934339479004260218</id><published>2011-06-27T11:28:00.001-07:00</published><updated>2011-11-19T17:21:01.355-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='java-language-puzzle'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Java Language Puzzle 2</title><content type='html'>&lt;p&gt;Given the following source listing, explain why InstantiationException is thrown when running (via the main method entry point) and how the code should be fixed.&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;package puzzle;

public class Entity
{
    private Entity()
    {
    }
    
    public class Factory
    {
        public Entity create()
        {
            return new Entity();
        }
    }
    
    public static void main( String[] args ) throws Exception
    {
        Factory.class.newInstance();
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;Exception in thread &amp;quot;main&amp;quot; java.lang.InstantiationException: puzzle.Entity$Factory
	at java.lang.Class.newInstance0(Unknown Source)
	at java.lang.Class.newInstance(Unknown Source)
	at puzzle.Entity.main(Entity.java:19)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;ANSWER:&lt;/strong&gt;&amp;#160; It looks like everyone who responded correctly identified the fact that Factory class is not defined as static as the cause of this exception. The solution is to add the static keyword. I would imagine that vast majority of Java developers are pretty comfortable with static/non-static inner classes semantics. What raises this to a puzzle level is a rather unhelpful exception.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-934339479004260218?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/934339479004260218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=934339479004260218' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/934339479004260218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/934339479004260218'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/06/java-puzzle-2.html' title='Java Language Puzzle 2'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-9004685444911812561</id><published>2011-06-22T15:56:00.001-07:00</published><updated>2011-06-22T16:32:12.509-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><title type='text'>Announcing Sapphire 0.3 Release</title><content type='html'>&lt;p&gt;It is with great pleasure that I announce on-time availability of &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/"&gt;Sapphire 0.3&lt;/a&gt; release. This release includes numerous &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/releases/0.3/enhancements.html"&gt;enhancements&lt;/a&gt;, some of which I will briefly describe. Current users of 0.2.x line will want to consult the &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/releases/0.3/migration.html"&gt;migration guide&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Before we get to the new features, it is important to take a few minutes to thank all the people who made this release possible. Shenxue Zhou is a new committer on the project and has been working hard to bring us diagram editing support. A key new features in this release. The community around Sapphire has grown substantially in the last few months. Many of the enhancements that you will find in this release are based on ideas and requirements brought by the new adopters. All of the adopters deserve a thank you, but I will call out one by name. Greg Amerson (&lt;a href="http://www.liferay.com/"&gt;Liferay&lt;/a&gt;) has progressed very quickly from an adopter to a contributors. Five patches from Greg are in the 0.3 release. Greg has the distinction of being the first non-Oracle contributor to Sapphire. Last but not least, several members of Oracle QA has pitched in to verify enhancements and fixed bugs.&lt;/p&gt;  &lt;p&gt;Without further ado, I present the enhancements in the 0.3 release…&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Diagram Editing&lt;/strong&gt; – Define diagram UI just as easily as a form. Sapphire declarative UI language has been expanded to cover basic diagram concepts. This feature opens the door for very sophisticated editors that provide diagram, form and source views on the same data. Yet, no matter how many diagram, form and source views on the data you define, Sapphire keeps everything in sync with n-way synchronization.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Properties View Integration&lt;/strong&gt; – Easily attach properties view content to diagram nodes, connections, form outline nodes, etc. using the same UI definition facilities as the editor. Sapphire will automatically inject that content into the standard Eclipse properties view when that part has selection. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UI Definition Editor&lt;/strong&gt; – Spend less time trying to get sdef syntax right with the new form-based editor for Sapphire UI Definition files. The editor is, of course, itself built using Sapphire.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Expression Language Enhancements&lt;/strong&gt; – Use EL in more areas of model and UI specification than before. The EL itself is now even more powerful with better handling of collections and support for custom type casts among other features.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Modularity Improvements&lt;/strong&gt; – Use Sapphire in more scenarios than before. The core modeling framework now only requires Java. Add integration with OSGi, Eclipse platform resources, JDT, etc. by installing separate modules. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Miscellaneous Enhancements&lt;/strong&gt; – Embed snippets of HTML into a form, show related content next to a property editor, choose from three layouts for a checkbox, specify editor header image, define collapsible sections, the list goes on. Head over to the &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/releases/0.3/enhancements.html"&gt;enhancements guide&lt;/a&gt; for all the details.&lt;/p&gt;  &lt;p&gt;Of course, no release of a UI framework would be complete without screen captures. Here are a few to wet your appetite…&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-PwDTeybmlns/TgJzBf5LlUI/AAAAAAAAAD0/B7hj0oTBY9A/s1600-h/properties-view-1%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="properties-view-1" border="0" alt="properties-view-1" src="http://lh3.ggpht.com/-1Yj1tX2IdJc/TgJzB7qt4TI/AAAAAAAAAD4/rHx9tR0fGRo/properties-view-1_thumb%25255B2%25255D.png?imgmax=800" width="649" height="591" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-JjA6Tlom9R4/TgJzCL271iI/AAAAAAAAAD8/G37aGblKjb0/s1600-h/properties-view-3%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="properties-view-3" border="0" alt="properties-view-3" src="http://lh6.ggpht.com/-JEhfNsGUBSU/TgJzCog1u9I/AAAAAAAAAEA/SJu5lL4gSU0/properties-view-3_thumb%25255B2%25255D.png?imgmax=800" width="649" height="220" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-qAmaV6REvNA/TgJzDNsO3DI/AAAAAAAAAEE/wP4_QK1GvM4/s1600-h/properties-view-2%25255B4%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="properties-view-2" border="0" alt="properties-view-2" src="http://lh3.ggpht.com/-MHakoYIIML4/TgJzDgVCyXI/AAAAAAAAAEI/WyPaht3RgSc/properties-view-2_thumb%25255B2%25255D.png?imgmax=800" width="649" height="199" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/releases/0.3/enhancements.html"&gt;Enhancements&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/releases/0.3/migration.html"&gt;Migration Guide&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3/documentation/index.html"&gt;Developer Guide&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.3/"&gt;Downloads&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Concurrently with &lt;a href="http://www.eclipse.org/sapphire/releases/0.3/"&gt;0.3&lt;/a&gt;, we are also shipping &lt;a href="http://www.eclipse.org/sapphire/releases/0.2.3/"&gt;0.2.3&lt;/a&gt; release to bring support for Indigo to adopters who still rely on the 0.2.x line.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-9004685444911812561?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/9004685444911812561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=9004685444911812561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9004685444911812561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9004685444911812561'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/06/announcing-sapphire-03-release.html' title='Announcing Sapphire 0.3 Release'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-1Yj1tX2IdJc/TgJzB7qt4TI/AAAAAAAAAD4/rHx9tR0fGRo/s72-c/properties-view-1_thumb%25255B2%25255D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-151865241664148531</id><published>2011-06-17T12:11:00.001-07:00</published><updated>2011-06-17T13:32:59.413-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-wtp'/><title type='text'>Java EE Module Configuration Editors Draft Proposal</title><content type='html'>&lt;p&gt;I am working on a proposal for Java EE Module Configuration Editors project. The goal is to create a new project under WTP Java EE Tools project and build there editors for web.xml, application.xml, ejb-jar.xml and possibly all the rest of the module configuration files. The editors would be built using &lt;a href="http://www.eclipse.org/sapphire/"&gt;Sapphire&lt;/a&gt; and work across various versions of Java EE spec. For Java EE 5 or newer, the editors would be able to also edit Java annotations instead of the XML configuration file from the same interface.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://eclipse.org/proposals/webtools.jee-config-editors/"&gt;Draft Proposal&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;While I am working on the getting the new project created to hold this work, I’ve started implementing the web.xml editor in Sapphire repository as a sample. You can get a feel for what’s there now and what the final result will look like in the screencast that I put together.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/samples/jee/demo-1/"&gt;Screencast&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;To take the editor for a spin yourself, install everything from the following repository. Don't try to go to a newer build as this plugin has been removed from the Sapphire build in preparation for the 0.3 release.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://hudson.eclipse.org/hudson/job/sapphire-0.3.x/408/artifact/build/repository/"&gt;https://hudson.eclipse.org/hudson/job/sapphire-0.3.x/408/artifact/build/repository/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;To access the source code, point your Eclipse at the following location in CVS. Note that you will need WTP + Sapphire in your target platform and Sapphire SDK in your dev eclipse. The latter part is very important as the Sapphire SDK contains the code generate necessary to build this plugin.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://dev.eclipse.org/viewcvs/viewvc.cgi/org.eclipse.sapphire/plugins/org.eclipse.sapphire.samples.jee/?root=Technology_Project"&gt;Source Code&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you are interested in this work, leave a comment with your name on this blog post or send a note to wtp-dev mailing list so that I can add you to the list of interested parties in the project proposal. If you are interested in helping to implement these editors, state as much as well and we will discuss.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-151865241664148531?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/151865241664148531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=151865241664148531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/151865241664148531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/151865241664148531'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/06/java-ee-module-configuration-editors.html' title='Java EE Module Configuration Editors Draft Proposal'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-3431417107442370708</id><published>2011-03-18T17:15:00.001-07:00</published><updated>2011-03-18T17:31:21.308-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>State of Sapphire for Spring 2011</title><content type='html'>&lt;p&gt;It has been a busy five months for the Sapphire team since the project was created in October of 2010. The initial code contribution from Oracle has gone through the Eclipse Foundation’s IP review, we have &lt;a href="http://www.eclipse.org/sapphire/developers/CVS.php"&gt;source in CVS&lt;/a&gt;, &lt;a href="https://bugs.eclipse.org/bugs/buglist.cgi?query_format=advanced;bug_status=UNCONFIRMED;bug_status=NEW;bug_status=ASSIGNED;bug_status=REOPENED;classification=Technology;product=Sapphire"&gt;bugs in Bugzilla&lt;/a&gt; and &lt;a href="https://hudson.eclipse.org/hudson/job/sapphire-0.3.x/"&gt;builds&lt;/a&gt; running on every commit. Even though the current project team is only staffed by Oracle employees, we make it a point to communicate in the open on the &lt;a href="http://www.eclipse.org/forums/index.php?t=thread&amp;amp;frm_id=192"&gt;adopter forum&lt;/a&gt; and the &lt;a href="https://dev.eclipse.org/mailman/listinfo/sapphire-dev"&gt;developer mailing list&lt;/a&gt;.&lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Releases&lt;/h3&gt;  &lt;p&gt;Two feature releases and two service releases shipped so far.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.1/"&gt;Version 0.1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The initial stable code contribution from Oracle, but refactored for eclipse.org namespace, build and legal requirements.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.1.1/"&gt;Version 0.1.1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Some infrastructure work was still ongoing when 0.1 shipped. Version 0.1.1 delivered the binaries in signed form.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.2/"&gt;Version 0.2&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Major enhancements, such as a powerful resource abstraction for models, expression language, transient properties, derived properties, new property editors and many more. Despite shipping concurrently with the 0.1 release, version 0.2 represents roughly six months of new feature work that was happening as we were waiting on the project creation process.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.eclipse.org/sapphire/releases/0.2.1/"&gt;Version 0.2.1&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;No major release can happen without at least a few bugs getting through. &lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Adoption&lt;/h3&gt;  &lt;p&gt;You might ask… This technology does look promising, but how do I really know if it is ready for production? &lt;/p&gt;  &lt;p&gt;Sapphire may be young at Eclipse, but it has been in development since at least 2007 as part of BEA’s and later Oracle’s Eclipse tooling efforts. Oracle Enterprise Pack for Eclipse (OEPE) heavily leverages Sapphire to create a variety of form based user interfaces across the product.&amp;#160; During the transition to Eclipse, we worked quickly to close the feedback loop between the new Sapphire project and its big adopter. To that end, OEPE 11.1.1.7 shipped with Sapphire 0.1.1 and upcoming OEPE 11.1.1.7.1 will ship with Sapphire 0.2.1 release. The tight feedback loop from OEPE has enabled us to quickly stabilize the major new features delivered in the 0.2 release. &lt;/p&gt;  &lt;p&gt;We are also getting ready to announce a major new endeavor to, in part, promote adoption of Sapphire across Eclipse. In the next few weeks, we will formally propose a project under WTP to use Sapphire to create &lt;a href="http://dev.eclipse.org/mhonarc/lists/wtp-dev/msg07981.html"&gt;editors for standard Java EE deployment descriptors&lt;/a&gt;. &lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Little Miss Sapphire&lt;/h3&gt;  &lt;p&gt;On February 8th, Sapphire family grew by one with the birth of Little Miss Sapphire or Amelia as she is known when she is not voicing opinions on architectural issues. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NCRdXKS36yU/TYP1e-vOW8I/AAAAAAAAADc/ClNgOACujnM/s1600-h/3D2B2359%5B4%5D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px auto; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="3D2B2359" border="0" alt="3D2B2359" src="http://lh4.ggpht.com/_NCRdXKS36yU/TYP1fm7uEnI/AAAAAAAAADg/xBEr0Hi8uCU/3D2B2359_thumb%5B2%5D.jpg?imgmax=800" width="600" height="600" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I am still mastering the art of typing with one hand. My &lt;a href="http://www.daskeyboard.com/model-s-ultimate/"&gt;Das Keyboard&lt;/a&gt; doesn’t make this easy, but I like a good challenge.&lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Release 0.3 and Indigo&lt;/h3&gt;  &lt;p&gt;The next major Sapphire release is scheduled to go out concurrently with Indigo in June of 2011. We are pushing improvements on two fronts. &lt;/p&gt;  &lt;p&gt;First, we are adding support for creating diagram editors, defined and wired to the model in a similar way that forms are today. The current diagram parts renderer uses &lt;a href="http://www.eclipse.org/graphiti/"&gt;Graphiti&lt;/a&gt;, but the application developer will not interact with &lt;a href="http://www.eclipse.org/graphiti/"&gt;Graphiti&lt;/a&gt; directly, allowing renderer implementation to be changed or swapped out in the future.&lt;/p&gt;  &lt;p&gt;By the time 0.3 ships, you will be able to create slick three-page editors showing source, form and diagram views on the same data. Bi-directional editing is so yesterday. Welcome to tri-directional editing!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NCRdXKS36yU/TYP1gHaVUpI/AAAAAAAAADk/XHjp1Twf68Q/s1600-h/diagram%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px auto; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="diagram" border="0" alt="diagram" src="http://lh5.ggpht.com/_NCRdXKS36yU/TYP1gnobDpI/AAAAAAAAADo/L8-wny0b0pw/diagram_thumb%5B2%5D.png?imgmax=800" width="557" height="500" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Second, we are making a major push on improving the facilities provided by the SDK to make developing with Sapphire even easier. The big new feature is an editor for Sapphire UI definitions (aka sdef files). All the content assist and validation isn’t finished yet, but the editor is already much better than editing XML markup by hand. The editor is, naturally, built using Sapphire. Yesterday, I spent a good portion of the day using the sdef editor from a previous build to work on new editor features for the next build. Extreme dogfooding! &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NCRdXKS36yU/TYP1hKjRMwI/AAAAAAAAADs/aYQ1nh-RO70/s1600-h/sdef%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px auto; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="sdef" border="0" alt="sdef" src="http://lh6.ggpht.com/_NCRdXKS36yU/TYP1hwpjncI/AAAAAAAAADw/p6OTnkXLsMc/sdef_thumb%5B2%5D.png?imgmax=800" width="773" height="555" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Shenxue Zhou Becomes a Committer&lt;/h3&gt;  &lt;p&gt;Shenxue has been involved with Sapphire as a consumer for a long time, but over the last several months, she has progressed to contributor status with her work on the diagram editing support. After a number of high quality patches, we welcomed Shenxue as the first elected committer on the project.&lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;EclipseCon 2011&lt;/h3&gt;  &lt;p&gt;I am going to be giving a &lt;a href="http://www.eclipsecon.org/2011/sessions/?page=sessions&amp;amp;id=2263"&gt;20 minute talk on Sapphire&lt;/a&gt; at this year’s EclipseCon. No slides to bore you with. Just a live demo of building a project using Sapphire. If you are at all interested in this technology, come see the demo. It should be entertaining (one way or another).&lt;/p&gt;  &lt;p&gt;If you cannot make it to the talk, I will be at the conference all four days, so flag me down between sessions or at the bar. Another Sapphire committer, Ling Hao, will also be attending EclipseCon this year.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-3431417107442370708?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/3431417107442370708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=3431417107442370708' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3431417107442370708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3431417107442370708'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/03/state-of-sapphire-for-spring-2011.html' title='State of Sapphire for Spring 2011'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_NCRdXKS36yU/TYP1fm7uEnI/AAAAAAAAADg/xBEr0Hi8uCU/s72-c/3D2B2359_thumb%5B2%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2102303023040262500</id><published>2011-02-22T11:49:00.001-08:00</published><updated>2011-02-22T11:49:24.422-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><title type='text'>Announcing Sapphire logo</title><content type='html'>&lt;p&gt;Every noteworthy project requires a cool logo, so I am very pleased to announce that &lt;a href="http://www.eclipse.org/sapphire/"&gt;Sapphire&lt;/a&gt; now joins that distinguished circle with a brand new logo. The new logo is a contribution of Jean Yao, a talented graphics designer at Oracle. I think you will agree that she has done a great job.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NCRdXKS36yU/TWQTNsQ7LQI/AAAAAAAAADE/6GzgfM6zdfk/s1600-h/sapphire%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="sapphire" border="0" alt="sapphire" src="http://lh3.ggpht.com/_NCRdXKS36yU/TWQTOYgtJhI/AAAAAAAAADI/P_aQy1geO0U/sapphire_thumb%5B2%5D.png?imgmax=800" width="322" height="322" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The new logo is already featured on the &lt;a href="http://www.eclipse.org/sapphire/"&gt;project home page&lt;/a&gt; and you can also spot it in recent &lt;a href="https://hudson.eclipse.org/hudson/job/sapphire-0.2.x/"&gt;0.2.1&lt;/a&gt; and &lt;a href="https://hudson.eclipse.org/hudson/job/sapphire-0.3.x/"&gt;0.3.0&lt;/a&gt; builds. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NCRdXKS36yU/TWQTPNbd3mI/AAAAAAAAADM/FZ0toLs3Uk0/s1600-h/about%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="about" border="0" alt="about" src="http://lh5.ggpht.com/_NCRdXKS36yU/TWQTPt-26TI/AAAAAAAAADQ/4kccNMST3M4/about_thumb%5B2%5D.png?imgmax=800" width="558" height="349" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NCRdXKS36yU/TWQTQL0tP-I/AAAAAAAAADU/mbYnm6uJIiI/s1600-h/project-explorer%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="project-explorer" border="0" alt="project-explorer" src="http://lh6.ggpht.com/_NCRdXKS36yU/TWQTQo9jzWI/AAAAAAAAADY/Fm_h13zMQE8/project-explorer_thumb%5B2%5D.png?imgmax=800" width="260" height="161" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2102303023040262500?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2102303023040262500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2102303023040262500' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2102303023040262500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2102303023040262500'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2011/02/announcing-sapphire-logo.html' title='Announcing Sapphire logo'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_NCRdXKS36yU/TWQTOYgtJhI/AAAAAAAAADI/P_aQy1geO0U/s72-c/sapphire_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-68561399096134081</id><published>2010-09-14T17:35:00.001-07:00</published><updated>2011-11-19T17:22:01.145-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='java-language-puzzle'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Java Language Puzzle 1</title><content type='html'>&lt;p&gt;From the domain of stuff that makes you wonder if your debugger is lying to you, I give you a little puzzle. How many times does the following code print the line “Creating crumble…” and why?&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public class JavaLanguagePuzzle1
{
    private static abstract class CookieBase
    {
        public CookieBase()
        {
            init();
        }
        
        protected void init() {}
    }
    
    private static class Cookie extends CookieBase
    {
        private Crumble crumble = null;

        protected void init()
        {
            crumble();
        }
        
        public Crumble crumble()
        {
            if( this.crumble == null )
            {
                this.crumble = new Crumble();
            }
            
            return crumble;
        }
    }
    
    private static class Crumble
    {
        public Crumble()
        {
            System.err.println( &amp;quot;Creating crumble...&amp;quot; );
        }
    }
    
    public static void main( final String[] args )
    {
        ( new Cookie() ).crumble();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;SOLUTION:&lt;/strong&gt; Pretty much everyone who responded came up with the correct answer of two times. Most correctly explained why that happens. Part of the reason is that explicit member variable initialization in a class happens after the superclass constructor has executed. The part that might be tricky to realize is that explicitly initializing a member variable to null does not have the same runtime behavior as leaving it uninitialized. Removing explicit initialization of crumble to null makes this code behave as it appears to on the surface.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-68561399096134081?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/68561399096134081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=68561399096134081' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/68561399096134081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/68561399096134081'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/09/java-language-puzzle-1.html' title='Java Language Puzzle 1'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2437086252783456278</id><published>2010-08-26T18:57:00.001-07:00</published><updated>2010-08-31T13:48:18.680-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-wtp'/><title type='text'>Inconvenient process? Let’s fix it.</title><content type='html'>&lt;p&gt;Some of you may have noticed the debate happening regarding proper entry expectations for WTP incubator project following &lt;a href="http://eclipsehowl.wordpress.com/2010/08/26/an-inconvenient-process/"&gt;Holger’s veto&lt;/a&gt; of a committer election. Holger is acting well within the power granted to him by Eclipse Development Process (EDP), but is it a right and proper action?&lt;/p&gt;  &lt;p&gt;Every committer on a project has the veto power in an election. By extension, any entry criteria for a project (whether written or unwritten) is nothing more than a social convention. The reality is that every committer can choose to levy their own personal expectations. Most of the time it’s not a problem, except when it is. &lt;/p&gt;  &lt;p&gt;Here are some quotes from this particular event:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;“I found only some bug reports but not a single code contribution from any of the four nominated persons. Please attach the planned code contribution to a bug report. I'd like to vote for each of the nominated persons as soon as I know that the code is readable and covered by JUnit tests.”&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;“Have [snip] been asked if they like to become committers as individuals (and not only as employees of SAP)? Are these authors of the code or what is their motivation to maintain and enhance these editors?”&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In a regular project with established code base, established team and well-defined scope, you can argue that giving every committer veto power over elections is appropriate. After all, there is an established code base to protect. The same considerations do not apply when a new component is proposed in an incubator.&lt;/p&gt;  &lt;p&gt;The WTP incubator project was started with the intention to provide a low entry barrier playground for people to come and experiment on new ideas while gaining experience and proving their merit to committers on the core projects that will eventually be asked to admit matured functions. Incubators make sense because they provide a quicker way to get started than a separate project proposal. Unfortunately incubators have to rely on a social convention that existing committers act in a welcoming fashion to newcomers. Most of the time that happens, except when it doesn’t.&lt;/p&gt;  &lt;p&gt;I would posit that there is no legitimate purpose served by holding a committer election when a new component is proposed for an incubator. The situation is supposed to be very similar to new project creation and we don’t hold elections there. The party proposing a project gets to designate a group of individuals to be the initial committers without anyone questioning their credentials or motives. A similar process is needed to make incubators work better.&lt;/p&gt;  &lt;p&gt;The last revision of EDP has formalized the concept of a persistent incubator. I propose that we build on those revisions and amend EDP to remove the committer vote requirement for incubator projects when a new component is being proposed. The project’s PMC would still have the oversight and ability to decline a new component proposal. This change would also fix the rather awkward problem of having to have “seeder” committers when creating incubator projects. &lt;/p&gt;  &lt;p&gt;Note that my suggestion is for persistent incubator projects rather than normal projects during incubation phase. I am also not suggesting that we remove committer vote entirely from incubators. Anyone wishing to join existing effort already underway in the incubator should still be subject to committer vote. &lt;/p&gt;  &lt;p&gt;Thoughts?&lt;/p&gt;  &lt;p&gt;PS.1 : This situation has served to highlight a process problem and it is the process that I seek to improve. I have no beef with Holger. I am sure he is acting on what he believes in.&lt;/p&gt;  &lt;p&gt;PS.2 : I am further confident that this particular storm will blow over, Holger’s objections will be met, another election held, etc. That doesn’t mean we shouldn’t try to improve the process so that such situations do not happen again and we continue to have vibrant incubator projects at Eclipse.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;At Wayne’s request I &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=324133"&gt;created a bug&lt;/a&gt; to track this proposed improvement to Eclipse Development Process.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2437086252783456278?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2437086252783456278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2437086252783456278' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2437086252783456278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2437086252783456278'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/08/inconvenient-process-lets-fix-it.html' title='Inconvenient process? Let’s fix it.'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-7059273486381086969</id><published>2010-07-14T08:54:00.001-07:00</published><updated>2010-07-28T10:47:00.402-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Oracle JVM 6u21 and Eclipse</title><content type='html'>&lt;p&gt;A number of users have encountered frequent Eclipse crashes since the recent Oracle JVM 6u21 update. The crash cause is listed as follows:&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;java.lang.OutOfMemoryError: PermGen space&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The underlying problem if that in 6u21 (version 1.6.0_21), the vendor was changed from Sun to Oracle. Eclipse launcher reads the JVM vendor and if it detects a Sun JVM, it adds an extra –XX:MaxPermSize setting that is necessary for Eclipse to function. With the vendor change in 6u21, the launcher is no longer adding the necessary parameter on launch.&lt;/p&gt;

&lt;p&gt;There is an Eclipse Platform bug open, but so far it doesn't look like there is going to be an attempt to resolve this until Helios SR1 scheduled for September.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=319514"&gt;https://bugs.eclipse.org/bugs/show_bug.cgi?id=319514&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, there is an easy workaround. Open the eclipse.ini file in an editor. You will see something similar to this:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;-startup
plugins/org.eclipse.equinox.launcher_1.1.0.v20100307.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.0.v20100307
-showsplash
org.eclipse.platform
--launcher.XXMaxPermSize
256m
--launcher.defaultAction
openFile
-vmargs
-Xms40m
-Xmx384m&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is setting that's not having any effect after 6u21:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;--launcher.XXMaxPermSize
256m&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remove it. In it's place, add -XX:MaxPermSize=256m on a new line after the -Xmx setting. Better yet, while you are in there, bump the memory limits to a higher value. Nothing ruins your train of thought better than your IDE crashing with an OutOfMemoryError. Here is a sample eclipse.ini that works on 6u21.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;-startup
plugins/org.eclipse.equinox.launcher_1.1.0.v20100507.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.0.v20100503
-showsplash
org.eclipse.platform
--launcher.defaultAction
openFile
-vmargs
-Xms40m
-Xmx1024m
-XX:MaxPermSize=512m&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;IMPORTANT: I do work for Oracle, but this is not an official Oracle statement on this issue. Just some advice from one Eclipse developer to another.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; This problem is specific to Windows. On *nix variants, Eclipse launcher uses slower, but more robust logic for detecting JVM type. More information in &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=320005"&gt;&lt;nobr&gt;Bug 320005&lt;/nobr&gt;&lt;/a&gt; for those who are interested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Oracle has produced another build of 6u21 JVM that reverts the change that adversely affected Eclipse. If you have reverted back to an older JVM, you can safely move forward to 6u21. The build 1.6.0_21-b07 is safe to use. The version that Eclipse has trouble with is b06. You can check which version you have by running &amp;quot;java -version&amp;quot;. More information in &lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6969236"&gt;Sun Bug 6969236&lt;/a&gt; for those who are interested.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-7059273486381086969?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/7059273486381086969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=7059273486381086969' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/7059273486381086969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/7059273486381086969'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/07/oracle-jvm-6u21-and-eclipse.html' title='Oracle JVM 6u21 and Eclipse'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-8493781151031690138</id><published>2010-07-08T14:13:00.001-07:00</published><updated>2010-07-08T14:13:41.584-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Sapphire – Focus on Localization</title><content type='html'>&lt;p&gt;If you have missed the introduction to Sapphire, make sure to read it first… &lt;a href="http://lt-rider.blogspot.com/2010/06/sapphire.html"&gt;Introduction to Sapphire&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Localization is like build systems, something that most developers prefer not to think about. Unfortunately, the developer must take explicit steps to manually externalize all user-visible strings for the software to be localizable. The localizable strings go into a separate file and the code references them by a key. The developer must come up with a key and then must manage the list of externalized strings so that it stays in sync with the code. Some tools have been developed to make this a little easier, but two types of problems remain very common:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Strings that should be externalized are not. It’s too easy for the developer to put the string directly into code and then forget to externalize it later.&lt;/li&gt;    &lt;li&gt;The string resource files get out of sync with code. The case where the resource file is missing a string is easy enough to catch at runtime. The case where resource files contain orphaned strings not referenced in code is much harder to detect.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Since Sapphire is a UI framework, localization is very important. Since Sapphire is focused on ease of use and developer productivity, relying on current methods of localization is not satisfactory. &lt;/p&gt;  &lt;p&gt;Localizable strings largely occur in two places in Sapphire. You see them in the model annotations (such as the @Label annotation) and you see them throughout the UI definition files. Sapphire’s approach is to allow the developer to leave the strings in their original language at point of use. The string resource files that will be translated are created at build time. The build system takes the original string and applies a function to it to generate a key for the string resources file. The same function is applied at runtime to derive the key to lookup the translated string. &lt;/p&gt;  &lt;p&gt;The critical concept is that the developer does not take any explicit steps to enable localization. It just happens under the covers.&lt;/p&gt;  &lt;p&gt;The nature of the function that is used to derive the string resources file key is not particularly important as long as the resulting key is not overly long and is reasonably free from collisions. The current implementation takes the original string, chops it off at 20 characters and replaces some characters that are illegal in a property file key with an underscore. Decent approach for the first cut, but we will likely replace it with an md5 hash in the first version of Sapphire to ship at Eclipse Foundation.&lt;/p&gt;  &lt;p&gt;On top of the automatic externalization, Sapphire is architected to minimize the number of strings that must be externalized in the first place. In particular, when the developer specifies a property label, the string is expected to be all in lower case (except where acronyms or proper nouns are used). Sapphire is able to transform the capitalization of the label to make it suitable for different contexts. Three modes of capitalization are supported:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;NO_CAPS:&amp;#160; Basically the original string as specified by developer. This is most frequently used for embedding inside validation messages.&lt;/li&gt;    &lt;li&gt;FIRST_WORD_ONLY:&amp;#160; This is your typical label in the UI. The colon is added by the UI renderer where appropriate.&lt;/li&gt;    &lt;li&gt;TITLE_STYLE:&amp;#160; This is typically used in column headers, section headers, dialog titles, etc.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The current capitalization algorithm works well for English and reasonably well for other languages, but it will need to be made pluggable in the future.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-8493781151031690138?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/8493781151031690138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=8493781151031690138' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8493781151031690138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8493781151031690138'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/07/sapphire-focus-on-localization.html' title='Sapphire – Focus on Localization'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-8457926908460089604</id><published>2010-06-30T14:32:00.001-07:00</published><updated>2010-06-30T14:33:11.555-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Extension system when you cannot depend on OSGi?</title><content type='html'>&lt;p&gt;I've been developing with OSGi for so long that sometimes I forget that not everyone in the Java world can take advantage of all the benefits offerred by it. Recently I have been contemplating the approaches to framework extensibility when you cannot depend on OSGi. Note that I am not looking for other solutions to modularity. I am looking for an extension contribution system that is not specific to OSGi. We'd like to support &lt;a href="http://www.eclipse.org/proposals/sapphire/"&gt;Sapphire&lt;/a&gt; in all Java UI contexts and extensibility for implementing new UI parts, renderers, etc. is key.&lt;/p&gt;  &lt;p&gt;Before I start re-inventing the wheel... Have others faced similar requirements? If so, what was the approach that you chose?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-8457926908460089604?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/8457926908460089604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=8457926908460089604' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8457926908460089604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8457926908460089604'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/06/extension-system-when-you-cannot-depend.html' title='Extension system when you cannot depend on OSGi?'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-3922048759887721698</id><published>2010-06-29T12:15:00.001-07:00</published><updated>2010-06-29T12:18:46.279-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Sapphire - Focus on Browsing</title><content type='html'>&lt;p&gt;If you have missed the introduction to Sapphire, make sure to read it first... &lt;a href="http://lt-rider.blogspot.com/2010/06/sapphire.html"&gt;Introduction to Sapphire&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;One of the most enduring UI patterns is a browse button next to the text box for selecting among possible values. Very frequently the scenario is to browse for files or folders, but the pattern is more generic than that and has been used to browse for arbitrary items especially when the set of possible values can be large.&lt;/p&gt;  &lt;p&gt;In Sapphire, developers are not creating and wiring up individual UI widgets. This makes it possible to implement the browse button pattern at a higher level of abstraction. If a browse handler is active for a property, a browse button will be automatically created. The framework will even register a keyboard shortcut (Ctrl+L, 'L' is for locate) which can be used to open the browse dialog while focus is on the text field.&lt;/p&gt;  &lt;p&gt;Sapphire uses image-based buttons for compactness and to create a more modern look-n-feel. In the following screen capture you can see how the browse buttons appear to the user. Note a tiny browse image in the table cell editor. That's a browse button too.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="browse-buttons" border="0" alt="browse-buttons" src="http://lh3.ggpht.com/_NCRdXKS36yU/TCpGTxy9ilI/AAAAAAAAACU/dGtlkyUVn24/browse-buttons%5B5%5D.png?imgmax=800" width="567" height="194" /&gt; &lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;File System Paths&lt;/h3&gt;  &lt;p&gt;Sapphire provides a set of annotations that make it easier to deal with file system paths. The developer uses these annotations to specify the semantics of the property and Sapphire automatically adds validation and browsing support.&lt;/p&gt;  &lt;p&gt;Consider the case where a property must hold an absolute path to a file that must exist and must have &amp;quot;jar&amp;quot; or &amp;quot;zip&amp;quot; extension. Such a property could be declared as follows:&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@Type( base = IPath.class )
@AbsolutePath
@ValidFileSystemResourceType( FileSystemResourceType.FILE )
@ValidFileExtensions( { &amp;quot;jar&amp;quot;, &amp;quot;zip&amp;quot; } )
@MustExist
    
ValueProperty PROP_ABSOLUTE_FILE_PATH = new ValueProperty( TYPE, &amp;quot;AbsoluteFilePath&amp;quot; );
    
Value&amp;lt;IPath&amp;gt; getAbsoluteFilePath();
void setAbsoluteFilePath( String value );
void setAbsoluteFilePath( IPath value );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Based on the above specification, the framework will attach validation that will make sure that the entered path is absolute, that it references a file, that the referenced file exists and that it has the appropriate extension. That happens in the model layer. The UI framework will see these annotations and supply a browse button wired to open the operating system's native file browse dialog pre-filtered to only show jar and zip files.&lt;/p&gt;

&lt;p&gt;Similar support is available for absolute folder paths. Just remove @ValidFileExtensions and change @ValidFileSystemResourceType.&lt;/p&gt;

&lt;p&gt;Or maybe you are writing an extension to Eclipse IDE and your property needs to hold a workspace path instead of an absolute path... Just replace @AbsolutePath with @EclipseWorkspacePath in the above example. The validation will change to use Eclipse resources API and the native browse dialog will be replaced with the standard Eclipse workspace resources dialog.&lt;/p&gt;

&lt;p&gt;Or maybe you need to deal with relative paths, but you have custom requirements for how these relative paths are to be resolved. Sapphire still got you covered. Just replace @AbsolutePath with @BasePathsProvider annotations and implement a class that returns all possible roots...&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@Type( base = IPath.class )
@BasePathsProvider( CustomBasePathsProvider.class )
@ValidFileSystemResourceType( FileSystemResourceType.FILE )
@ValidFileExtensions( &amp;quot;dll&amp;quot; )
@MustExist
    
ValueProperty PROP_RELATIVE_FILE_PATH = new ValueProperty( TYPE, &amp;quot;RelativeFilePath&amp;quot; );
    
Value&amp;lt;IPath&amp;gt; getRelativeFilePath();
void setRelativeFilePath( String value );
void setRelativeFilePath( IPath value );&lt;/code&gt;&lt;/pre&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public final class CustomBasePathsProvider extends BasePathsProviderImpl
{
    @Override
    public List&amp;lt;IPath&amp;gt; getBasePaths( IModelElement element )
    {
        final List&amp;lt;IPath&amp;gt; roots = new ArrayList&amp;lt;IPath&amp;gt;();
        
        roots.add( new Path( &amp;quot;c:/Windows&amp;quot; ) );
        roots.add( new Path( &amp;quot;c:/Program Files&amp;quot; ) );

        return roots;
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will still get all the validation that you would get with an absolute path, including validation for existence which will try to locate your path using the roots returned by your base paths provider. On the UI side you will get a custom browse dialog box that lets you browse for resources in all the roots simultaneously. This can be very powerful in many contexts where the system that UI is being built for searches for the specified file in a set of defined locations.&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="relative-path" border="0" alt="relative-path" src="http://lh6.ggpht.com/_NCRdXKS36yU/TCpGUbsOTSI/AAAAAAAAACY/_0bZlQrfizU/relative-path%5B5%5D.png?imgmax=800" width="442" height="489" /&gt;&amp;#160; &lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;String Values&lt;/h3&gt;

&lt;p&gt;Another common scenario is the case where the value must come from a list possible values not necessarily tied to something specific like file system resources. For instance, consider the case where a property must reference an entity name from the set of entities defined elsewhere.&lt;/p&gt;

&lt;p&gt;Sapphire provides a set of three annotations to simplify these scenarios. The annotations are @PossibleValuesProvider, @PossibleValues and @PossibleValuesFromModel. Of the three annotations, the first one is the most generic one. It lets the developer implement a class that computes the set of possible values at runtime...&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@PossibleValuesProvider( impl = CityNameValuesProvider.class )
    
ValueProperty PROP_CITY = new ValueProperty( TYPE, &amp;quot;City&amp;quot; );
    
Value&amp;lt;String&amp;gt; getCity();
void setCity( String value );&lt;/code&gt;&lt;/pre&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public class CityNameValuesProvider extends PossibleValuesProviderImpl
{
    @Override
    protected abstract void fillPossibleValues( SortedSet&lt;string&gt; values )
    {
        // Your logic goes here.
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you find that in your scenario the set of possible values is static you can use the @PossibleValues annotation instead. This annotation lets you specify the set of possible values right in the annotation instead of implementing a custom values provider.&lt;/p&gt;

&lt;p&gt;Or maybe your scenario calls for a property to draw its possible values from another property in the model. The @PossibleValuesFromModel annotation has you covered. It lets you specify a path through the model where possible values should be harvested.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@PossibleValuesFromModel( path = &amp;quot;/Contacts/Name&amp;quot;, caseSensitive = false ) 
    
ValueProperty PROP_ASSISTANT = new ValueProperty( TYPE, &amp;quot;Assistant&amp;quot; );
    
Value&amp;lt;String&amp;gt; getAssistant();
void setAssistant( String value );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Regardless of which of the three annotations you use, you will get validation that will check that the specified value is in the set of possible values. Additional attributes are available on all three of these annotations that let you customize the validation. For instance, you can change the problem severity to warning or even disable validation completely. You can even specify whether the comparison should be case sensitive. On the UI front, you will get browse button wired to the standard list item selection dialog.&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="possible-values" border="0" alt="possible-values" src="http://lh6.ggpht.com/_NCRdXKS36yU/TCpGVHkj84I/AAAAAAAAACc/UM8HccaCLWU/possible-values%5B5%5D.png?imgmax=800" width="429" height="468" /&gt;&amp;#160; &lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Java Types&lt;/h3&gt;

&lt;p&gt;Sapphire even integrates with JDT to support properties that reference classes or interfaces visible to a given Java project. The developer uses the supplied JavaTypeName class as the type for a value property and then tunes the semantics using @JavaTypeConstraints and @MustExist annotations. Sapphire takes care of the rest. You get validation for type existence, kind of type (interface, class, etc.) and even whether type derives from another type. On the UI side, you get a browse button wired to JDT's type selection dialog.&lt;/p&gt;

&lt;p&gt;In the following example, the property is specified to take a name of a non-abstract class that must extend AbstractList class while also implementing Cloneable interface.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@Type( base = JavaTypeName.class )
@JavaTypeConstraints( kind = JavaTypeKind.CLASS, type = { &amp;quot;java.util.AbstractList&amp;quot;, &amp;quot;java.lang.Cloneable&amp;quot; } )
@MustExist
    
ValueProperty PROP_CUSTOM_LIST_CLASS = new ValueProperty( TYPE, &amp;quot;CustomListClass&amp;quot; );
    
Value&amp;lt;JavaTypeName&amp;gt; getCustomListClass();
void setCustomListClass( String value );
void setCustomListClass( JavaTypeName value );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="java-type" border="0" alt="java-type" src="http://lh6.ggpht.com/_NCRdXKS36yU/TCpGVov51hI/AAAAAAAAACg/clTXmP6xBWY/java-type%5B5%5D.png?imgmax=800" width="631" height="531" /&gt;&amp;#160; &lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Completely Custom&lt;/h3&gt;

&lt;p&gt;Sapphire browse handling support is extensible to support cases that do not fit one of the above molds. To do this, you create a custom class that extends BrowseHandler. You can then register your browse handler globally (to activate under a condition that you specify) or locally for a specific property editor in the UI definition. The second case is more common.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;property-editor&amp;gt;
  &amp;lt;property&amp;gt;Photo&amp;lt;/property&amp;gt;
  &amp;lt;browse-handler&amp;gt;
    &amp;lt;class&amp;gt;PhotosCatalogBrowseHandler&amp;lt;/class&amp;gt;
  &amp;lt;/browse-handler&amp;gt;
&amp;lt;/property-handler&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Multi-Way&lt;/h3&gt;

&lt;p&gt;One variant of the browse button pattern has baffled UI writers for years. In some cases, the semantics of the property require the use of more than one browse dialog. For instance, consider the case where the property can take an absolute path to an archive file or a folder. No established convention exists for how to handle this case and developers have tried a number of different options. Here are a few examples from Eclipse itself.&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="multi-way-1" border="0" alt="multi-way-1" src="http://lh6.ggpht.com/_NCRdXKS36yU/TCpGWDu7M7I/AAAAAAAAACk/bVyahHORzCk/multi-way-1%5B5%5D.png?imgmax=800" width="522" height="71" /&gt;&amp;#160; &lt;br /&gt;

  &lt;br /&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="multi-way-2" border="0" alt="multi-way-2" src="http://lh4.ggpht.com/_NCRdXKS36yU/TCpGWmGbDkI/AAAAAAAAACo/YWgz5aMdyL8/multi-way-2%5B5%5D.png?imgmax=800" width="589" height="106" /&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="multi-way-3" border="0" alt="multi-way-3" src="http://lh3.ggpht.com/_NCRdXKS36yU/TCpGXP-QlXI/AAAAAAAAACs/s_Ig6pOFDzI/multi-way-3%5B5%5D.png?imgmax=800" width="523" height="64" /&gt; &lt;/p&gt;

&lt;p&gt;Sapphire adopts the convention of using a drop-down menu from the browse button when multiple browse handlers are active concurrently. Here is what that looks like:&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="multi-way-sapphire" border="0" alt="multi-way-sapphire" src="http://lh4.ggpht.com/_NCRdXKS36yU/TCpGXsbbH8I/AAAAAAAAACw/S-IIL3mbh_c/multi-way-sapphire%5B5%5D.png?imgmax=800" width="480" height="107" /&gt; &lt;/p&gt;

&lt;p&gt;Currently, there are no model annotations that can fully describe the complex semantics of such scenarios. The developer must register the browse handlers in the UI definition. Validation should be done in a custom validator class attached via @Validator annotation.&lt;/p&gt;

&lt;p&gt;Here is the UI definition from the above screen capture. All the system-provided browse handlers that activate when certain annotations are used are also available for direct reference from the UI definitions as can be seen in this example.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;property-editor&amp;gt;
  &amp;lt;property&amp;gt;MultiOptionPath&amp;lt;/property&amp;gt;
  &amp;lt;browse-handler&amp;gt;
    &amp;lt;class&amp;gt;AbsoluteFilePathValueBrowseHandler&amp;lt;/class&amp;gt;
    &amp;lt;param&amp;gt;
      &amp;lt;name&amp;gt;extensions&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;jar,zip&amp;lt;/value&amp;gt;
    &amp;lt;/param&amp;gt;
  &amp;lt;/browse-handler&amp;gt;
  &amp;lt;browse-handler&amp;gt;
    &amp;lt;class&amp;gt;AbsoluteFolderPathValueBrowseHandler&amp;lt;/class&amp;gt;
  &amp;lt;/browse-handler&amp;gt;
  &amp;lt;browse-handler&amp;gt;
    &amp;lt;class&amp;gt;EclipseWorkspacePathValueBrowseHandler&amp;lt;/class&amp;gt;
    &amp;lt;param&amp;gt;
      &amp;lt;name&amp;gt;extensions&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;jar,zip&amp;lt;/value&amp;gt;
    &amp;lt;/param&amp;gt;
    &amp;lt;param&amp;gt;
      &amp;lt;name&amp;gt;leading-slash&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
    &amp;lt;/param&amp;gt;
  &amp;lt;/browse-handler&amp;gt;
&amp;lt;/property-editor&amp;gt;&lt;/code&gt;&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-3922048759887721698?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/3922048759887721698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=3922048759887721698' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3922048759887721698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3922048759887721698'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/06/sapphire-focus-on-browsing.html' title='Sapphire - Focus on Browsing'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_NCRdXKS36yU/TCpGTxy9ilI/AAAAAAAAACU/dGtlkyUVn24/s72-c/browse-buttons%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2263710889225019194</id><published>2010-06-25T22:45:00.001-07:00</published><updated>2010-06-25T22:59:38.943-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-sapphire'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Sapphire</title><content type='html'>&lt;p&gt;Little has changed in the way Java desktop UI is written since the original Java release. Technologies have changed (AWT, Swing, SWT, etc.), but fundamentals remain the same. The developer must choose which widgets to use, how to lay those widgets out, how to store the data being edited and how to synchronize the model with the UI. Even the best developers fall into traps of having UI components talk directly to other UI components rather than through the model. Inordinate amount of time is spent debugging layout and data-binding issues.&lt;/p&gt;  &lt;p&gt;Sapphire aims to raise UI writing to a higher level of abstraction. The core premise is that the basic building block of UI should not be a widget (text box, label, button, etc.), but rather a property editor. Unlike a widget, a property editor analyzes metadata associated with a given property, renders the appropriate widgets to edit that property and wires up data binding. Data is synchronized, validation is passed from the model to the UI, content assistance is made available, etc.&lt;/p&gt;  &lt;p&gt;This fundamentally changes the way developers interact with a UI framework. Instead of writing UI by telling the system how to do something, the developer tells the system what they intend to accomplish. When using Sapphire, the developer says &amp;quot;I want to edit LastName property of the person object&amp;quot;. When using widget toolkits like SWT, the developer says &amp;quot;create label, create text box, lay them out like so, configure their settings, setup data binding and so on&amp;quot;. By the time the developer is done, it is hard to see the original goal in the code that's produced. This results in UI that is inconsistent, brittle and difficult to maintain.&lt;/p&gt;  &lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;First, The Model&lt;/h3&gt;  &lt;p&gt;Sapphire includes a simple modeling framework that is tuned to the needs of the Sapphire UI framework and is designed to be easy to learn. It is also optimized for iterative development. A Sapphire model is defined by writing Java interfaces and using annotations to attach metadata. An annotation processor that is part of Sapphire SDK then generates the implementation classes. Sapphire leverages Eclipse Java compiler to provide quick and transparent code generation that runs in the background while you work on the model. The generated classes are treated as build artifacts and are not source controlled. In fact, you will rarely have any reason to look at them. All model authoring and consumption happens through the interfaces.&lt;/p&gt;  &lt;p&gt;In this article we will walk through a Sapphire sample called EzBug. The sample is based around a scenario of building a bug reporting system. Let's start by looking at IBugReport.&lt;/p&gt;  &lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@GenerateXmlBinding

public interface IBugReport extends IModelElementForXml, IRemovable
{
    ModelElementType TYPE = new ModelElementType( IBugReport.class );
    
    // *** CustomerId ***
    
    @XmlBinding( path = &amp;quot;customer&amp;quot; )
    @Label( standard = &amp;quot;customer ID&amp;quot; )

    ValueProperty PROP_CUSTOMER_ID = new ValueProperty( TYPE, &amp;quot;CustomerId&amp;quot; );

    Value&amp;lt;String&amp;gt; getCustomerId();
    void setCustomerId( String value );

    // *** Title ***
    
    @XmlBinding( path = &amp;quot;title&amp;quot; )
    @Label( standard = &amp;quot;title&amp;quot; )
    @NonNullValue

    ValueProperty PROP_TITLE = new ValueProperty( TYPE, &amp;quot;Title&amp;quot; );

    Value&amp;lt;String&amp;gt; getTitle();
    void setTitle( String value );
    
    // *** Details ***
    
    @XmlBinding( path = &amp;quot;details&amp;quot; )
    @Label( standard = &amp;quot;details&amp;quot; )
    @LongString
    @NonNullValue

    ValueProperty PROP_DETAILS = new ValueProperty( TYPE, &amp;quot;Details&amp;quot; );

    Value&amp;lt;String&amp;gt; getDetails();
    void setDetails( String value );
    
    // *** ProductVersion ***

    @Type( base = ProductVersion.class )
    @XmlBinding( path = &amp;quot;version&amp;quot; )
    @Label( standard = &amp;quot;version&amp;quot; )
    @DefaultValue( &amp;quot;2.5&amp;quot; )

    ValueProperty PROP_PRODUCT_VERSION = new ValueProperty( TYPE, &amp;quot;ProductVersion&amp;quot; );

    Value&amp;lt;ProductVersion&amp;gt; getProductVersion();
    void setProductVersion( String value );
    void setProductVersion( ProductVersion value );
    
    // *** ProductStage ***

    @Type( base = ProductStage.class )
    @XmlBinding( path = &amp;quot;stage&amp;quot; )
    @Label( standard = &amp;quot;stage&amp;quot; )
    @DefaultValue( &amp;quot;final&amp;quot; )

    ValueProperty PROP_PRODUCT_STAGE = new ValueProperty( TYPE, &amp;quot;ProductStage&amp;quot; );

    Value&amp;lt;ProductStage&amp;gt; getProductStage();
    void setProductStage( String value );
    void setProductStage( ProductStage value );
    
    // *** Hardware ***

    @Type( base = IHardwareItem.class )
    @ListPropertyXmlBinding( mappings = { @ListPropertyXmlBindingMapping( element = &amp;quot;hardware-item&amp;quot;, type = IHardwareItem.class ) } )
    @Label( standard = &amp;quot;hardware&amp;quot; )
    
    ListProperty PROP_HARDWARE = new ListProperty( TYPE, &amp;quot;Hardware&amp;quot; );
    
    ModelElementList&amp;lt;IHardwareItem&amp;gt; getHardware();
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see in the above code listing, a model element definition in Sapphire is composed of a series of blocks. These blocks define properties of the model element. Each property block has a PROP_* field that declares the property, the metadata in the form of annotations and the accessor methods. All metadata about the model element is stored in the interface. There are no external files. When this interface is compiled, Java persists these annotation in the .class file and Sapphire is able to read them at runtime.&lt;/p&gt;

&lt;p&gt;Sapphire has three types of properties: value, element and list. Value properties hold simple data, such as strings, integers, enums, etc. Any object that is immutable and can be serialized to a string can be stored in a value property. An element property holds a reference to another model element. You can specify whether this nested model element should always exist or if it should be possible to create and delete it. A list property holds zero or more model elements. A list can be homogeneous (only holds one type of elements) or heterogeneous (holds elements of various specified types).&lt;/p&gt;

&lt;p&gt;Using a combination of list and element properties, it is possible to create an arbitrary model hierarchy. In the above listing, there is one list property. It is homogeneous and references IHardwareItem element type. Let's look at that type next.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@GenerateXmlBinding

public interface IHardwareItem extends IModelElementForXml, IRemovable
{
    ModelElementType TYPE = new ModelElementType( IHardwareItem.class );
    
    // *** Type ***
    
    @Type( base = HardwareType.class )
    @XmlBinding( path = &amp;quot;type&amp;quot; )
    @Label( standard = &amp;quot;type&amp;quot; )
    @NonNullValue

    ValueProperty PROP_TYPE = new ValueProperty( TYPE, &amp;quot;Type&amp;quot; );

    Value&amp;lt;HardwareType&amp;gt; getType();
    void setType( String value );
    void setType( HardwareType value );
    
    // *** Make ***
    
    @XmlBinding( path = &amp;quot;make&amp;quot; )
    @Label( standard = &amp;quot;make&amp;quot; )
    @NonNullValue

    ValueProperty PROP_MAKE = new ValueProperty( TYPE, &amp;quot;Make&amp;quot; );

    Value&amp;lt;String&amp;gt; getMake();
    void setMake( String value );
    
    // *** ItemModel ***
    
    @XmlBinding( path = &amp;quot;model&amp;quot; )
    @Label( standard = &amp;quot;model&amp;quot; )

    ValueProperty PROP_ITEM_MODEL = new ValueProperty( TYPE, &amp;quot;ItemModel&amp;quot; );

    Value&amp;lt;String&amp;gt; getItemModel();
    void setItemModel( String value );

    // *** Description ***
    
    @XmlBinding( path = &amp;quot;description&amp;quot; )
    @Label( standard = &amp;quot;description&amp;quot; )
    @LongString

    ValueProperty PROP_DESCRIPTION = new ValueProperty( TYPE, &amp;quot;Description&amp;quot; );

    Value&amp;lt;String&amp;gt; getDescription();
    void setDescription( String value );
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The IHardwareItem listing should look very similar to IBugReport and that's the point. A Sapphire model is just a collection of Java interfaces that are annotated in a certain way and reference each other.&lt;/p&gt;

&lt;p&gt;A bug report is contained in IFileBugReportOp, which serves as the top level type in the model.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@GenerateXmlBindingModelImpl
@RootXmlBinding( elementName = &amp;quot;report&amp;quot; )

public interface IFileBugReportOp extends IModelForXml, IExecutableModelElement
{
    ModelElementType TYPE = new ModelElementType( IFileBugReportOp.class );
    
    // *** BugReport ***
    
    @Type( base = IBugReport.class )
    @Label( standard = &amp;quot;bug report&amp;quot; )
    @XmlBinding( path = &amp;quot;bug&amp;quot; )
    
    ElementProperty PROP_BUG_REPORT = new ElementProperty( TYPE, &amp;quot;BugReport&amp;quot; );
    
    IBugReport getBugReport();
    IBugReport getBugReport( boolean createIfNecessary );
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's now look at the last bit of code that goes with this model, which is the enums.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@Label( standard = &amp;quot;type&amp;quot;, full = &amp;quot;hardware type&amp;quot; )

public enum HardwareType
{
    @Label( standard = &amp;quot;CPU&amp;quot; )

    CPU,
    
    @Label( standard = &amp;quot;main board&amp;quot; )
    @EnumSerialization( primary = &amp;quot;Main Board&amp;quot; )
    
    MAIN_BOARD,

    @Label( standard = &amp;quot;RAM&amp;quot; )
    
    RAM,
    
    @Label( standard = &amp;quot;video controller&amp;quot; )
    @EnumSerialization( primary = &amp;quot;Video Controller&amp;quot; )
    
    VIDEO_CONTROLLER,

    @Label( standard = &amp;quot;storage&amp;quot; )
    @EnumSerialization( primary = &amp;quot;Storage&amp;quot; )
    
    STORAGE,
    
    @Label( standard = &amp;quot;other&amp;quot; )
    @EnumSerialization( primary = &amp;quot;Other&amp;quot; )
    
    OTHER
}


@Label( standard = &amp;quot;product stage&amp;quot; )

public enum ProductStage
{
    @Label( standard = &amp;quot;alpha&amp;quot; )
    
    ALPHA,

    @Label( standard = &amp;quot;beta&amp;quot; )
    
    BETA,

    @Label( standard = &amp;quot;final&amp;quot; )
    
    FINAL
}


@Label( standard = &amp;quot;product version&amp;quot; )

public enum ProductVersion
{
    @Label( standard = &amp;quot;1.0&amp;quot; )
    @EnumSerialization( primary = &amp;quot;1.0&amp;quot; )
    
    V_1_0,
    
    @Label( standard = &amp;quot;1.5&amp;quot; )
    @EnumSerialization( primary = &amp;quot;1.5&amp;quot; )

    V_1_5,
    
    @Label( standard = &amp;quot;1.6&amp;quot; )
    @EnumSerialization( primary = &amp;quot;1.6&amp;quot; )
    
    V_1_6,
    
    @Label( standard = &amp;quot;2.0&amp;quot; )
    @EnumSerialization( primary = &amp;quot;2.0&amp;quot; )
    
    V_2_0,
    
    @Label( standard = &amp;quot;2.3&amp;quot; )
    @EnumSerialization( primary = &amp;quot;2.3&amp;quot; )
    
    V_2_3,
    
    @Label( standard = &amp;quot;2.4&amp;quot; )
    @EnumSerialization( primary = &amp;quot;2.4&amp;quot; )
    
    V_2_4,
    
    @Label( standard = &amp;quot;2.5&amp;quot; )
    @EnumSerialization( primary = &amp;quot;2.5&amp;quot; )
    
    V_2_5
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can use any enum as a type for a Sapphire value property. Here, once again, you see Sapphire pattern of using Java annotations to attach metadata to model particles. In this case the annotations are specifying how Sapphire should present enum items to the user and how these items should be serialized to string form.&lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Then, The UI&lt;/h3&gt;

&lt;p&gt;The bulk of the work in writing UI using Sapphire is modeling the data that you want to present to the user. Once the model is done, defining the UI is simply a matter of arranging the properties on the screen. This is done via an XML file.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;definition&amp;gt;

  &amp;lt;import&amp;gt;
    &amp;lt;bundle&amp;gt;org.eclipse.sapphire.samples&amp;lt;/bundle&amp;gt;
    &amp;lt;package&amp;gt;org.eclipse.sapphire.samples.ezbug&amp;lt;/package&amp;gt;
  &amp;lt;/import&amp;gt;
  
  &amp;lt;composite&amp;gt;
    &amp;lt;id&amp;gt;bug.report&amp;lt;/id&amp;gt;
    &amp;lt;content&amp;gt;
      &amp;lt;property-editor&amp;gt;CustomerId&amp;lt;/property-editor&amp;gt;
      &amp;lt;property-editor&amp;gt;Title&amp;lt;/property-editor&amp;gt;
      &amp;lt;property-editor&amp;gt;
        &amp;lt;property&amp;gt;Details&amp;lt;/property&amp;gt;
        &amp;lt;hint&amp;gt;
          &amp;lt;name&amp;gt;expand.vertically&amp;lt;/name&amp;gt;
          &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
        &amp;lt;/hint&amp;gt;
      &amp;lt;/property-editor&amp;gt;
      &amp;lt;property-editor&amp;gt;ProductVersion&amp;lt;/property-editor&amp;gt;
      &amp;lt;property-editor&amp;gt;ProductStage&amp;lt;/property-editor&amp;gt;
      &amp;lt;property-editor&amp;gt;
        &amp;lt;property&amp;gt;Hardware&amp;lt;/property&amp;gt;
        &amp;lt;child-property&amp;gt;
          &amp;lt;name&amp;gt;Type&amp;lt;/name&amp;gt;
        &amp;lt;/child-property&amp;gt;
        &amp;lt;child-property&amp;gt;
          &amp;lt;name&amp;gt;Make&amp;lt;/name&amp;gt;
        &amp;lt;/child-property&amp;gt;
        &amp;lt;child-property&amp;gt;
          &amp;lt;name&amp;gt;ItemModel&amp;lt;/name&amp;gt;
        &amp;lt;/child-property&amp;gt;
      &amp;lt;/property-editor&amp;gt;
      &amp;lt;composite&amp;gt;
        &amp;lt;indent&amp;gt;true&amp;lt;/indent&amp;gt;
        &amp;lt;content&amp;gt;
          &amp;lt;separator&amp;gt;
            &amp;lt;label&amp;gt;Details&amp;lt;/label&amp;gt;
          &amp;lt;/separator&amp;gt;
          &amp;lt;switching-panel&amp;gt;
            &amp;lt;list-selection-controller&amp;gt;
              &amp;lt;property&amp;gt;Hardware&amp;lt;/property&amp;gt;
            &amp;lt;/list-selection-controller&amp;gt;
            &amp;lt;panel&amp;gt;
              &amp;lt;key&amp;gt;IHardwareItem&amp;lt;/key&amp;gt;
              &amp;lt;content&amp;gt;
                &amp;lt;property-editor&amp;gt;
                  &amp;lt;property&amp;gt;Description&amp;lt;/property&amp;gt;
                  &amp;lt;hint&amp;gt;
                    &amp;lt;name&amp;gt;show.label.above&amp;lt;/name&amp;gt;
                    &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
                  &amp;lt;/hint&amp;gt;
                  &amp;lt;hint&amp;gt;
                    &amp;lt;name&amp;gt;height&amp;lt;/name&amp;gt;
                    &amp;lt;value&amp;gt;5&amp;lt;/value&amp;gt;
                  &amp;lt;/hint&amp;gt;
                &amp;lt;/property-editor&amp;gt;
              &amp;lt;/content&amp;gt;
            &amp;lt;/panel&amp;gt;
            &amp;lt;default-panel&amp;gt;
              &amp;lt;content&amp;gt;
                &amp;lt;label&amp;gt;Select a hardware item above to view or edit additional parameters.&amp;lt;/label&amp;gt;
              &amp;lt;/content&amp;gt;
            &amp;lt;/default-panel&amp;gt;
          &amp;lt;/switching-panel&amp;gt;
        &amp;lt;/content&amp;gt;
      &amp;lt;/composite&amp;gt;
    &amp;lt;/content&amp;gt;
    &amp;lt;hint&amp;gt;
      &amp;lt;name&amp;gt;expand.vertically&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
    &amp;lt;/hint&amp;gt;
    &amp;lt;hint&amp;gt;
      &amp;lt;name&amp;gt;width&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;600&amp;lt;/value&amp;gt;
    &amp;lt;/hint&amp;gt;
    &amp;lt;hint&amp;gt;
      &amp;lt;name&amp;gt;height&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;500&amp;lt;/value&amp;gt;
    &amp;lt;/hint&amp;gt;
  &amp;lt;/composite&amp;gt;

  &amp;lt;dialog&amp;gt;
    &amp;lt;id&amp;gt;bug.report.dialog&amp;lt;/id&amp;gt;
    &amp;lt;label&amp;gt;Create Bug Report (Sapphire Sample)&amp;lt;/label&amp;gt;
    &amp;lt;initial-focus&amp;gt;Title&amp;lt;/initial-focus&amp;gt;
    &amp;lt;content&amp;gt;
      &amp;lt;composite-ref&amp;gt;
        &amp;lt;id&amp;gt;bug.report&amp;lt;/id&amp;gt;
      &amp;lt;/composite-ref&amp;gt;
    &amp;lt;/content&amp;gt;
    &amp;lt;hint&amp;gt;
      &amp;lt;name&amp;gt;expand.vertically&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
    &amp;lt;/hint&amp;gt;
  &amp;lt;/dialog&amp;gt;
  
&amp;lt;/definition&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A Sapphire UI definition is a hierarchy of parts. At the lowest level we have the property editor and a few other basic parts like separators. These are aggregated together into various kinds of composities until the entire part hierarchy is defined. Some hinting here and there to guide the UI renderer and the UI definition is complete. Note the top-level composite and dialog elements. These are parts that you can re-use to build more complex UI definitions or reference externally from Java code.&lt;/p&gt;

&lt;p&gt;Next we will write a little bit of Java code to open the dialog that we defined.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;final IFileBugReportOp op = new FileBugReportOp( new ModelStoreForXml( new ByteArrayModelStore() ) );
final IBugReport report = op.getBugReport( true );

final SapphireDialog dialog 
    = new SapphireDialog( shell, report, &amp;quot;org.eclipse.sapphire.samples/sdef/EzBug.sdef!bug.report.dialog&amp;quot; );
        
if( dialog.open() == Dialog.OK )
{
    // Do something. User input is found in the bug report model.
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty simple, right? We create the model and then use the provided SapphireDialog class to instantiate the UI by referencing the model instance and the UI definition. The pseudo-URI that's used to reference the UI definition is simply bundle id, followed by the path within that bundle to the file holding the UI definition, followed by the id of the definition to use.&lt;/p&gt;

&lt;p&gt;Let's run it and see what we get...&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="dialog" border="0" alt="dialog" src="http://lh5.ggpht.com/_NCRdXKS36yU/TCWT5vQV4SI/AAAAAAAAACE/n1m8OvHjat0/dialog%5B5%5D.png?imgmax=800" width="723" height="671" /&gt; &lt;/p&gt;

&lt;p&gt;There you have it. Professional rich UI backed by your model with none of the fuss of configuring widgets, trying to get layouts to do what you need them to do or debugging data binding issues.&lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;One Step Further&lt;/h3&gt;

&lt;p&gt;A dialog is nice, but really a wizard would be better suited for filing a bug report. Can Sapphire do that? Sure. Let's first go back to the model. A wizard is a UI pattern for configuring and then executing an operation. Our model is not really an operation yet. We can create and populate a bug report, but then we don't know what to do with it.&lt;/p&gt;

&lt;p&gt;Any Sapphire model element can be turned into an operation by adding an execute method. We will do that now with IFileBugReportOp. In particular, IFileBugReportOp will be changed to also extend IExecutableModelElement and will acquire the following method definition:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;// *** Method: execute ***
    
@DelegateImplementation( FileBugReportOpMethods.class )
    
IStatus execute( IProgressMonitor monitor );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note how the execute method is specified. We don't want to modify the generated code to implement it, so we use delegation instead. The @DelegateImplementation annotation can be used to delegate any method on a model element to an implementation located in another class. The Sapphire annotation processor will do the necessary hookup.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public class FileBugReportOpMethods
{
    public static final IStatus execute( IFileBugReportOp context, IProgressMonitor monitor )
    {
        // Do something here.
        
        return Status.OK_STATUS;
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The delegate method implementation must match the method being delegated with two changes: (a) it must be static, and (b) it must take the model element as the first parameter.&lt;/p&gt;

&lt;p&gt;Now that we have completed the bug reporting operation, we can return to the UI definition file and add the following:&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;wizard&amp;gt;
  &amp;lt;id&amp;gt;wizard&amp;lt;/id&amp;gt;
  &amp;lt;label&amp;gt;Create Bug Report (Sapphire Sample)&amp;lt;/label&amp;gt;
  &amp;lt;page&amp;gt;
    &amp;lt;id&amp;gt;main.page&amp;lt;/id&amp;gt;
    &amp;lt;label&amp;gt;Create Bug Report&amp;lt;/label&amp;gt;
    &amp;lt;description&amp;gt;Create and submit a bug report.&amp;lt;/description&amp;gt;
    &amp;lt;initial-focus&amp;gt;Title&amp;lt;/initial-focus&amp;gt;
    &amp;lt;content&amp;gt;
      &amp;lt;with&amp;gt;
        &amp;lt;property&amp;gt;BugReport&amp;lt;/property&amp;gt;
        &amp;lt;content&amp;gt;
          &amp;lt;composite-ref&amp;gt;
            &amp;lt;id&amp;gt;bug.report&amp;lt;/id&amp;gt;
          &amp;lt;/composite-ref&amp;gt;
        &amp;lt;/content&amp;gt;
      &amp;lt;/with&amp;gt;
    &amp;lt;/content&amp;gt;
    &amp;lt;hint&amp;gt;
      &amp;lt;name&amp;gt;expand.vertically&amp;lt;/name&amp;gt;
      &amp;lt;value&amp;gt;true&amp;lt;/value&amp;gt;
    &amp;lt;/hint&amp;gt;
  &amp;lt;/page&amp;gt;
&amp;lt;/wizard&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above defines a one page wizard by re-using the composite definition created earlier. Now back to Java to use the wizard...&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;final IFileBugReportOp op = new FileBugReportOp( new ModelStoreForXml( new ByteArrayModelStore() ) );
op.getBugReport( true );  // Force creation of the bug report.

final SapphireWizard&amp;lt;IFileBugReportOp&amp;gt; wizard 
    = new SapphireWizard&amp;lt;IFileBugReportOp&amp;gt;( op, &amp;quot;org.eclipse.sapphire.samples/sdef/EzBug.sdef!wizard&amp;quot; );
        
final WizardDialog dialog = new WizardDialog( shell, wizard );
        
dialog.open();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;SapphireWizard will invoke the operation's execute method when the wizard is finished. That means we don't have to act based on the result of the open call. The execute method will have completed by the time the open method returns to the caller.&lt;/p&gt;

&lt;p&gt;The above code pattern works well if you are launching the wizard from a custom action, but if you need to contribute a wizard to an extension point, you can extend SapphireWizard to give your wizard a zero-argument constructor that creates the operation and references the correct UI definition.&lt;/p&gt;

&lt;p&gt;Let's run it...&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="wizard" border="0" alt="wizard" src="http://lh5.ggpht.com/_NCRdXKS36yU/TCWT6NC3tiI/AAAAAAAAACI/94tgl0kdkzQ/wizard%5B5%5D.png?imgmax=800" width="722" height="759" /&gt; &lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;One More Step&lt;/h3&gt;

&lt;p&gt;Now that we have a system for submitting bug reports, it would be nice to have a way to maintain a collection of these reports. Even better if we can re-use some of our existing code to do this. Back to the model.&lt;/p&gt;

&lt;p&gt;The first step is to create IBugDatabase type which will hold a collection of bug reports. By now you should have a pretty good idea of what that will look like.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;@GenerateXmlBindingModelImpl
@RootXmlBinding( elementName = &amp;quot;bug-database&amp;quot; )

public interface IBugDatabase extends IModelForXml
{
    ModelElementType TYPE = new ModelElementType( IBugDatabase.class );

    // *** BugReports ***
    
    @Type( base = IBugReport.class )
    @Label( standard = &amp;quot;bug report&amp;quot; )
    @ListPropertyXmlBinding( mappings = { @ListPropertyXmlBindingMapping( element = &amp;quot;bug&amp;quot;, type = IBugReport.class ) } )
    
    ListProperty PROP_BUG_REPORTS = new ListProperty( TYPE, &amp;quot;BugReports&amp;quot; );
    
    ModelElementList&amp;lt;IBugReport&amp;gt; getBugReports();
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That was easy. Now let's go back to the UI definition file.&lt;/p&gt;

&lt;p&gt;Sapphire simplifies creation of multi-page editors. It also has very good integration with WTP XML editor that makes it easy to create the very typical two-page editor with a form-based page and a linked source page showing the underlying XML. The linkage is fully bi-directional.&lt;/p&gt;

&lt;p&gt;To create an editor, we start by defining the structure of the pages that will be rendered by Sapphire. Sapphire currently only supports one editor page layout, but it is a very flexible layout that works for a lot scenarios. You get a tree outline of content on the left and a series of sections on the right that change depending on the selection in the outline.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;editor-page&amp;gt;
  &amp;lt;id&amp;gt;editor.page&amp;lt;/id&amp;gt;
  &amp;lt;page-header-text&amp;gt;Bug Database (Sapphire Sample)&amp;lt;/page-header-text&amp;gt;
  &amp;lt;initial-selection&amp;gt;Bug Reports&amp;lt;/initial-selection&amp;gt;
  &amp;lt;root-node&amp;gt;
    &amp;lt;node&amp;gt;
      &amp;lt;label&amp;gt;Bug Reports&amp;lt;/label&amp;gt;
      &amp;lt;section&amp;gt;
        &amp;lt;description&amp;gt;Use this editor to manage your bug database.&amp;lt;/description&amp;gt;
        &amp;lt;content&amp;gt;
          &amp;lt;action-link&amp;gt;
            &amp;lt;action-id&amp;gt;node:add&amp;lt;/action-id&amp;gt;
            &amp;lt;label&amp;gt;Add a bug report&amp;lt;/label&amp;gt;
          &amp;lt;/action-link&amp;gt;
        &amp;lt;/content&amp;gt;
      &amp;lt;/section&amp;gt;
      &amp;lt;node-list&amp;gt;
        &amp;lt;property&amp;gt;BugReports&amp;lt;/property&amp;gt;
        &amp;lt;node-template&amp;gt;
          &amp;lt;dynamic-label&amp;gt;
            &amp;lt;property&amp;gt;Title&amp;lt;/property&amp;gt;
            &amp;lt;null-value-label&amp;gt;&amp;amp;lt;bug&amp;amp;gt;&amp;lt;/null-value-label&amp;gt;
          &amp;lt;/dynamic-label&amp;gt;
          &amp;lt;section&amp;gt;
            &amp;lt;label&amp;gt;Bug Report&amp;lt;/label&amp;gt;
            &amp;lt;content&amp;gt;
              &amp;lt;composite-ref&amp;gt;
                &amp;lt;id&amp;gt;bug.report&amp;lt;/id&amp;gt;
              &amp;lt;/composite-ref&amp;gt;
            &amp;lt;/content&amp;gt;
          &amp;lt;/section&amp;gt;
        &amp;lt;/node-template&amp;gt;
      &amp;lt;/node-list&amp;gt;
    &amp;lt;/node&amp;gt;
  &amp;lt;/root-node&amp;gt;
&amp;lt;/editor-page&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that the definition centers around the outline. The definition traverses the model as the outline is defined with sections attached to various nodes acquiring the context model element from their node. The outline can nest arbitrarily deep and you can even define recursive structures by externalizing node definitions, assigning ids to them and then referencing those definitions similarly to how this sample references an existing composite definition.&lt;/p&gt;

&lt;p&gt;The next step is to create the actual editor. Sapphire includes several editor classes for you to choose from. In this article we will use the editor class that's specialized for the case where you are editing an XML file and you want to have an editor page rendered by Sapphire along with an XML source page.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;public final class BugDatabaseEditor extends SapphireEditorForXml
{
    public BugDatabaseEditor()
    {
        super( &amp;quot;org.eclipse.sapphire.samples&amp;quot; );
        setEditorDefinitionPath( &amp;quot;org.eclipse.sapphire.samples/sdef/EzBug.sdef/editor.page&amp;quot; );
    }

    @Override
    protected IModel createModel( final ModelStore modelStore )
    {
        return new BugDatabase( (ModelStoreForXml) modelStore );
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, we need to register the editor. There are a variety of options for how to do this, but covering all of these options is outside the scope of this article. For simplicity we will register the editor as the default choice for files named &amp;quot;bugs.xml&amp;quot;.&lt;/p&gt;

&lt;pre style="border-bottom: #999999 1px dashed; border-left: #999999 1px dashed; padding-bottom: 5px; line-height: 14px; background-color: #eee; padding-left: 5px; width: 100%; padding-right: 5px; font-family: andale mono, lucida console, monaco, fixed, monospace; color: #000000; font-size: 12px; overflow: auto; border-top: #999999 1px dashed; border-right: #999999 1px dashed; padding-top: 5px"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.ui.editors&amp;quot;&amp;gt;
  &amp;lt;editor
    class=&amp;quot;org.eclipse.sapphire.samples.ezbug.ui.BugDatabaseEditor&amp;quot;
    default=&amp;quot;true&amp;quot;
    filenames=&amp;quot;bugs.xml&amp;quot;
    id=&amp;quot;org.eclipse.sapphire.samples.ezbug.ui.BugDatabaseEditor&amp;quot;
    name=&amp;quot;Bug Database Editor (Sapphire Sample)&amp;quot;/&amp;gt;
&amp;lt;/extension&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's it. We are done creating the editor. After launching Eclipse and creating a bug.xml file, you should see an editor that looks like this:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="editor-small" border="0" alt="editor-small" src="http://lh3.ggpht.com/_NCRdXKS36yU/TCWXSMzxSzI/AAAAAAAAACQ/3BV22TwX480/editor-small%5B5%5D.png?imgmax=800" width="796" height="728" /&gt; &lt;/p&gt;

&lt;p&gt;Sapphire really shines in complex cases like this where form UI is sitting on top a source file that users might edit by hand. In the above screen capture, what happened is that the user manually entered &amp;quot;BETA2&amp;quot; for the product stage in the source view. There is a problem marker next to the property editor and the yellow assistance popup is accessible by clicking on that marker. The problem message is displayed along with additional information about the property and available actions. The &amp;quot;Show in source&amp;quot; action, for instance, will immediately jump to the editor's source page and highlight the text region associated with this property. This is very valuable when you must deal with large files. These facilities and many others are available out of the box with Sapphire with no extra effort from the developer.&lt;/p&gt;

&lt;h3 style="border-bottom: #cccccc 1px dotted; padding-bottom: 2px; font-size: 15px" class="post-title entry-title"&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Now that you've been introduced to what Sapphire can do, compare it to how you are currently writing UI code. All of the code presented in this article can be written by a developer with just a few weeks of Sapphire experience in an hour or two. How long would it take you to create something comparable using your current method of choice?&lt;/p&gt;

&lt;p&gt;I hope that this article has piqued your interest in Sapphire. Oracle is committed to bringing this technology to the open source community. We have &lt;a href="http://www.eclipse.org/proposals/sapphire/"&gt;proposed a project&lt;/a&gt; at the Eclipse Foundation. If you are interested, you should post a message on &lt;a href="http://www.eclipse.org/forums/eclipse.sapphire"&gt;the project's forum&lt;/a&gt;. Introduce yourself and describe your interest. We are actively seeking both consumers of this technologies as well as potential partners to come join the effort and help us take this technology in the directions that we have not yet anticipated.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2263710889225019194?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2263710889225019194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2263710889225019194' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2263710889225019194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2263710889225019194'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/06/sapphire.html' title='Sapphire'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NCRdXKS36yU/TCWT5vQV4SI/AAAAAAAAACE/n1m8OvHjat0/s72-c/dialog%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2510867938075543279</id><published>2010-06-25T13:40:00.001-07:00</published><updated>2010-06-25T13:40:10.802-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Tool for exporting formatted code to HTML?</title><content type='html'>&lt;p&gt;Quick poll… When writing blogs or articles, what do you use to nicely format code snippets as HTML? I am particularly curious if anyone found an Eclipse plugin that simply exports the style that’s visible in the Eclipse editor rather than trying to implement parsing and styling on its own. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2510867938075543279?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2510867938075543279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2510867938075543279' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2510867938075543279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2510867938075543279'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/06/tool-for-exporting-formatted-code-to.html' title='Tool for exporting formatted code to HTML?'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-5911234654690473821</id><published>2010-05-27T14:58:00.001-07:00</published><updated>2010-05-27T18:26:43.327-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-jdt'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>JDT, Manifest Classpath, Classpath Containers and Helios</title><content type='html'>&lt;p&gt;In the interest of public service, thought I’d communicate a behavior change in Eclipse Java Developer Tools (JDT) coming in Helios (aka Eclipse 3.6). In Galileo (aka Eclipse 3.5), JDT started resolving manifest classpath in libraries added to project’s build path. This worked whether the library was added to project’s build path directly or via a classpath container, such as the user library facility provided by JDT or one implemented by a third party. In Helios, this behavior was changed to exclude classpath containers from manifest classpath resolution. &lt;/p&gt;  &lt;p&gt;This change in behavior has potential to affect users who have started relying on this facility in their projects. A workspace with projects that built fine in Galileo may not build in Helios. The cause may not be obvious as the only thing that the user will notice is build errors complaining of missing types. The user will need to figure out where those types were coming from originally and take steps to make sure those libraries are referenced directly. The exact way to do that is dependent on the implementation of the classpath container in question. For instance, if the container is based on JDT user library feature, then the definition of the user library will need to be adjusted in preferences. Alternatively, users can set a system property in their eclipse.ini file to revert to Galileo behavior. Adding the following line to the end of the file should to the trick:&lt;/p&gt;  &lt;p&gt;-DresolveReferencedLibrariesForContainers=true&lt;/p&gt;  &lt;p&gt;This change can also affect third parties shipping plugins on top of JDT that implement classpath containers. If the classpath container was implemented to rely on manifest classpath resolution, it will need to be updated to work properly on Helios. Fortunately, JDT provides an API to make this process less painful…&lt;/p&gt;  &lt;p&gt;JavaCore.getReferencedClasspathEntries( [IClasspathEntry], [IJavaProject] )&lt;/p&gt;  &lt;p&gt;The above API call will do manifest classpath resolution on the library referenced by the provided classpath entry. Pass in null for the second parameter. The result is an array of classpath entries that can be added to the original set in classpath container initialization. Several things to watch out for…&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Make sure not add the same library twice. This is fairly easy to do, especially if your container implementation gives user some control over the contents. The last time I ran into this, JDT threw an exception on container initialization. &lt;/li&gt;    &lt;li&gt;Check returned entries for existence before adding them to your container. The getReferencedClasspathEntries method does not check for existence, but if your container adds a reference to a non-existing file, JDT will put an error in the problems view and nothing will build. Could be an ugly surprise for your users as a code fix in the container implementation will be required to resolve this. &lt;/li&gt;    &lt;li&gt;The getReferencedClasspathEntries method is new for Helios, which means that your container implementation will no longer be compatible with Galileo. If you need to support Galileo and Helios from the same code base, you will need to implement your own manifest classpath resolution. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;References&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=305037"&gt;Bug 305037&lt;/a&gt; - missing story for attributes of referenced JARs in classpath containers &lt;/li&gt;    &lt;li&gt;&lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313965"&gt;Bug 313965&lt;/a&gt; - Breaking change in classpath container API &lt;/li&gt;    &lt;li&gt;&lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=313890"&gt;Bug 313890&lt;/a&gt; - Migration guide to 3.6 for containers with MANIFEST-referred entries &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Olivier Thomann has asked me to include the following clarifying statement:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“Galileo behavior was wrong as a container should control exactly what is inside the container. So Helios fixed this issue.”&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I have no disagreement with that statement. My purpose in writing this blog is purely to document a difference in behavior from Galileo to Helios that can appear to many as a regression. I do think this change could have been handled better, but that’s besides the point at this stage in Helios release and not the reason that I wrote this post.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-5911234654690473821?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/5911234654690473821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=5911234654690473821' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5911234654690473821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5911234654690473821'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2010/05/jdt-manifest-classpath-classpath.html' title='JDT, Manifest Classpath, Classpath Containers and Helios'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-294398242175678734</id><published>2009-04-03T08:06:00.001-07:00</published><updated>2009-04-03T08:06:20.631-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><title type='text'>Eclipse is a Product and that’s a Good Thing (tm)</title><content type='html'>&lt;p&gt;I know that Bjorn is just trying to stimulate the discussion and challenge the status quo with his recent blog posts. That’s a good thing. I do find myself disagreeing completely with his latest proposal to stop distribution of binaries from eclipse.org and instead shift the responsibility to various member companies. Basically, we would go from the FireFox model to the Linux model.&lt;/p&gt;  &lt;p&gt;Here is a quote from Bjorn’s blog post responding to some of the negative comments about his proposal:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Changing Things Will Kill Eclipse. I just don't see this. For example, &lt;a href="http://www.linuxfoundation.org/en/Main_Page"&gt;The Linux Foundation&lt;/a&gt; doesn't distribute a single binary and yet Linux is so popular that it is scaring Microsoft. Wayne also pointed this out.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The important question to ask here is could Linux have been much more successful if there was a single canonical distribution provided by the Linux Foundation. Yes, Linux is getting more popular, but not nearly as fast as people would have liked and its adoption curve against competition is not nearly as good as the adoption curve for other major open source projects that follow the product model. Why is that? The dozens of different Linux distros fragment the market, create confusion for new users (have to make a choice between distros that are potentially radically different when you don’t yet have a clue), create barriers to skill transition (just because you’ve learned how to use Linux on your machine doesn’t mean that you will be able to use Linux on friend’s machine), and make it significantly more expensive for vendors to deliver new software for the platform (what works on one distro may not work on another). Now compare that to FireFox. It is much younger project than Linux, but has already managed to make significantly more progress against competition than Linux. This is not an accident. You don’t have to take my word for it, a number of people have written about these problems with Linux and how they stand in the way of its growth. Why would we want to emulate the Linux model?&lt;/p&gt;  &lt;p&gt;Platform alone is not a good strategy. No matter how good the platform is, companies and individuals will only use the platform if it enables them to reach a significant user base. It takes a product to do that. Not dozens of different products that confuse the users and make it more difficult to build on the platform, but a single trusted canonical product. Eclipse as a Product helps ensure success of Eclipse as a Platform. &lt;/p&gt;  &lt;p&gt;Ultimately, what is the problem that we would be trying to solve by stopping distribution of binaries at eclipse.org? Bjorn makes the argument that Eclipse community delivers such a poor quality product and that users are having such a hard time receiving adequate support on the forums that we need to do something drastic to address the problem. How do we evaluate this argument? You cannot look at forum posts alone. The voices of a few disgruntled individuals drown out the opinions of thousands of satisfied users. After all, people only go to forums when they have problems. I would look at Eclipse adoption curves instead as a true measure of user satisfaction. A product that has significant quality problems would not keep growing. The growth would stall and we should see adoption numbers going down. We are not seeing that with Eclipse. The evidence just does not backup Bjorn’s argument.&lt;/p&gt;  &lt;p&gt;I do happen to agree that there is more that we could do to help users get better support through paid channels, but we do not need to resort to drastic measures like what Bjorn is proposing. The harm from going forward with this proposal would be far greater than potential benefits.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-294398242175678734?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/294398242175678734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=294398242175678734' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/294398242175678734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/294398242175678734'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2009/04/eclipse-is-product-and-thats-good-thing.html' title='Eclipse is a Product and that’s a Good Thing (tm)'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-643205745145288885</id><published>2009-03-01T16:22:00.001-08:00</published><updated>2009-03-01T16:22:40.638-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Count me out from p2 fan club</title><content type='html'>&lt;p&gt;I don’t make habit of ranting about technology, but p2 has been driving me up the wall. The old update manager may not have been perfect, but at least it didn’t have the bad habit of preventing installation cases that should work from working. &lt;/p&gt;  &lt;p&gt;So we are putting finishing touches on a new version of Oracle Enterprise Pack for Eclipse (OEPE) and it’s time to test various installation scenarios. Eclipse Ganymede SR2 was also just released last week, so we are verifying compatibility with it. One of the basic installation scenarios that we are testing starts out with an all-in-one kit that includes Eclipse Ganymede GA with the previous version of OEPE. The second step in the scenario is to update all of the Eclipse components in that installation. The new version of OEPE requires at least SR1. I let Eclipse search for updates and install everything that it finds. That works. Presumably at this point, the installation should be equivalent to a fresh Eclipse Ganymede SR2 install. The final step is to install the new version of OEPE from a local update site. P2 thinks for a while and then says there are problems that will prevent the installation from working and refuses to go forward. &lt;/p&gt;  &lt;p&gt;WTF? I know perfectly well that the plugins we are installing are compatible with Ganymede SR2. They’ve been built using SR2 as the target platform and they work just fine when simply added to the Eclipse installation. Now what? Taking a look at the problems reported by p2, I find about a hundred messages that look like the following. &lt;/p&gt;  &lt;p&gt;Cannot find a solution where both &amp;quot;bundle org.eclipse.wst.validation [1.2.0,1.3.0)&amp;quot; and &amp;quot;bundle org.eclipse.wst.validation [1.1.0,1.2.0)&amp;quot; are satisfied.   &lt;br /&gt;Unsatisfied dependency: [org.eclipse.jst.ws.axis.consumption.core 1.0.204.v200708151945] requiredCapability: osgi.bundle/org.eclipse.core.resources/[3.2.0,3.4.0)    &lt;br /&gt;Unsatisfied dependency: [org.eclipse.jst.ws.axis.consumption.ui 1.0.204.v200801222138] requiredCapability: osgi.bundle/org.eclipse.core.resources/[3.2.0,3.4.0)    &lt;br /&gt;Unsatisfied dependency: [org.eclipse.wst.ws 1.0.204.v200711140435] requiredCapability: osgi.bundle/org.eclipse.core.resources/[3.2.0,3.4.0)    &lt;br /&gt;Unsatisfied dependency: [org.eclipse.wst.command.env.ui 1.0.203.v200709052219] requiredCapability: osgi.bundle/org.eclipse.core.resources/[3.2.0,3.4.0)&lt;/p&gt;  &lt;p&gt;These messages don’t make a whole lot of sense. None of them reference plugins that I am trying to install and there is no hint in the messages regarding what actually caused the problem. I looked at one of them in detail to make sure I wasn’t missing something obvious. The second message says that a dependency of org.eclipse.jst.ws.axis.consumption.core plugin cannot be found. That makes sense since it’s a very old version of the plugin that’s not compatible with Ganymede. The question is why p2 trying to resolve that plugin? I look at my installation and I see versions 1.0.304.v200805140230 and 1.0.306.v200810082309. That makes sense. Those versions correspond to what shipped with Ganymede GA and Ganymede SR2. I do not find version 1.0.204.v200708151945 that p2 is complaining about anywhere. &lt;/p&gt;  &lt;p&gt;At this point, I gave up trying to make sense of the problem messages and proceeded to blindly try various changes to the way the OEPE update site is constructed to see if I would get a different result. Two alternatives I tried made this scenario work: (a) removing all version constraints from plugin dependencies and (b) reverting to the old-style update site with a site.xml file and no p2 metadata. We still need to do some more testing, but we probably will go with (b) and give up on p2-enabling our update site.&lt;/p&gt;  &lt;p&gt;I had reservations about p2 since the poor way in which it was rolled out roughly a year ago, but after a year of fighting with it and this recent experience, I can honestly say (without an ounce of exaggeration) that p2 is the worst regression ever introduced into the Eclipse Platform. I understand the problems that p2 is supposed to solve, but there is just no excuse for destroying the most basic of core scenarios in the process. If it wasn’t ready for Ganymede, it should have stayed as an incubator for a while longer. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-643205745145288885?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/643205745145288885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=643205745145288885' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/643205745145288885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/643205745145288885'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2009/03/count-me-out-from-p2-fan-club.html' title='Count me out from p2 fan club'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-3367835401904716643</id><published>2009-02-05T21:49:00.001-08:00</published><updated>2009-02-05T22:00:34.192-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Field-level key bindings</title><content type='html'>&lt;p&gt;Sometimes you need to create key bindings in Eclipse which are scoped to just a single control. I had one such case today. I have a table cell editor that’s based on the TextCellEditor, but adds a small graphical browse button. It works great as long as you are using a mouse, but I needed to make the browsing function keyboard accessible for people with disabilities.&lt;/p&gt;  &lt;p&gt;Eclipse has a nice command framework that lets you define commands in abstract sense, place them in contexts, define key bindings and finally associate handlers to do the actual work. Finding an example that puts all of these concepts to work together in a particular way can be challenging, so I thought I would share my solution to the above problem and explain some of this API along the way.&lt;/p&gt;  &lt;p&gt;The first step is to define the command. A command is an operation that a user can perform, but we don’t actually specify how to perform that operation when defining the command. That comes later when we add a handler. Every command must belong to a category. Here we define a category as well. You will typically want to create a category for each broad functional area to make it easier for users to find and manage your commands in the preferences.&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.ui.commands&amp;quot;&amp;gt;
  &amp;lt;category
    id=&amp;quot;my.category&amp;quot;
    name=&amp;quot;My Category&amp;quot;/&amp;gt;
  &amp;lt;command
    id=&amp;quot;my.browse.command&amp;quot;
    categoryId=&amp;quot;my.category&amp;quot;
    name=&amp;quot;Browse&amp;quot;/&amp;gt;
&amp;lt;/extension&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next step is to define the context. The context controls what commands are available via key bindings based on where in the workbench the user is working. Typically views and editors define contexts, but there is nothing stopping you from defining one that is more focused. In this example, we will create a context for fields with browsing capability.&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.ui.contexts&amp;quot;&amp;gt;
  &amp;lt;context
    id=&amp;quot;my.browseable.field.context&amp;quot;
    parentId=&amp;quot;org.eclipse.ui.contexts.window&amp;quot;
    name=&amp;quot;In Browseable Field&amp;quot;/&amp;gt;
&amp;lt;/extension&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The final declarative step is to define the key binding. The following assigns Ctrl+L to the browse command in the browseable field context. &lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.ui.bindings&amp;quot;&amp;gt;
  &amp;lt;key
    sequence=&amp;quot;M1+L&amp;quot;
    contextId=&amp;quot;my.browseable.field.context&amp;quot;
    commandId=&amp;quot;my.browse.command&amp;quot;
    schemeId=&amp;quot;org.eclipse.ui.defaultAcceleratorConfiguration&amp;quot;/&amp;gt;
&amp;lt;/extension&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now for the final bit of magic… The following function brings it all together by enabling the browseable field context and associating a handler with the browse command when the specified text field gains focus. When the focus is lost, the context and the handler are deactivated.&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;public static void addBrowseKeyBinding( final Text textField,
                                        final Runnable browseOperation )
{
    final IHandler browseCommandHandler = new AbstractHandler() 
    {
        public Object execute( final ExecutionEvent event )
        {
            browseOperation.run();
            return null;
        }
    };
        
    final IWorkbench workbench = PlatformUI.getWorkbench();
    
    final IHandlerService handlerService 
        = (IHandlerService) workbench.getService( IHandlerService.class );

    final IContextService contextService 
        = (IContextService) workbench.getService( IContextService.class );
        
    final IHandlerActivation[] handlerActivationRef = new IHandlerActivation[ 1 ];
    final IContextActivation[] contextActivationRef = new IContextActivation[ 1 ];
        
    textField.addFocusListener
    (
        new FocusListener()
        {
            public void focusGained( final FocusEvent event )
            {
                final IHandlerActivation handlerActivation
                    = handlerService.activateHandler( &amp;quot;my.browse.command&amp;quot;, browseCommandHandler );
                    
                handlerActivationRef[ 0 ] = handlerActivation;
                    
                final IContextActivation contextActivation
                    = contextService.activateContext( &amp;quot;my.browseable.field.context&amp;quot; );
                    
                contextActivationRef[ 0 ] = contextActivation;
            }

            public void focusLost( final FocusEvent event )
            {
                handlerService.deactivateHandler( handlerActivationRef[ 0 ] );
                contextService.deactivateContext( contextActivationRef[ 0 ] );
            }
        }
    );
}
&lt;/code&gt;&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-3367835401904716643?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/3367835401904716643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=3367835401904716643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3367835401904716643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/3367835401904716643'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2009/02/field-level-key-bindings.html' title='Field-level key bindings'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-5402217071075664024</id><published>2009-02-01T18:29:00.001-08:00</published><updated>2009-02-01T18:29:29.679-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='software engineering'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='osgi'/><title type='text'>Better way to manage dependency version ranges</title><content type='html'>&lt;p&gt;OSGi provides an extremely powerful and precise mechanism for controlling acceptable version ranges when specifying dependency on bundles or packages. In theory (as described by policies of various projects at Eclipse), the developer would take into account his plugin’s API and behavior needs, cross-reference that with version information about the bundle in question and carefully craft the version range in dependency declaration to accurately reflect his plugin’s actual needs while leaving the version range as open as possible to allow users maximum flexibility when composing an installation. Further, in theory, the developer should be continuously aware of dependency version ranges specified in his product’s various plugins and how they correlate to functionality exposed by those plugin. As development progresses, the developer is supposed to be able to spot when he started depending on functionality that’s not available in the specified min version and reset the min version accordingly. &lt;/p&gt;  &lt;p&gt;That’s the theory. In practice I haven’t met a single developer with sufficient time on their hands or sufficient mental capacity to keep all of the necessary information in his head at all times in order to properly apply this policy. What I’ve seen happen most often is that the min range gets set based on whatever the plugin version happens to be at the time the dependency is first added. PDE helpfully inserts this information in your manifest by default. The max version then gets set by applying a team policy (typically by bumping up either the major or the minor version). This happens when dependency is first introduced. As the code continues to evolve, the min version is typically not touched again. The max version is incremented when the build gets broken by the dependency bumping up their versions past a certain point. The cycle repeats. &lt;/p&gt;  &lt;p&gt;After many years of observing this situation, I am convinced that having developers manage version ranges creates a lot of overhead and does not yield satisfactory results no matter how hard people try.&amp;#160; To me, dependency version ranges are most useful when you have shipped your product in binary form. When taken collectively across a component (collection of bundles), they represent a statement of what your team is willing to support as a working configuration. Ideally, this information should be consistent across plugins and as accurate as possible. &lt;/p&gt;  &lt;p&gt;Any time you talk about setting version ranges, you are considering three versions:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The version that you developed and did most of your testing with. I call this the “target version”. Typically, this is what you would list as recommended configuration in your documentation.&lt;/li&gt;    &lt;li&gt;The minimum version that you are willing to support. The level of testing you can afford to allocate to this version is bound to be less than what you would allocate for the target version, so there is a certain amount of risk that an undetected issue is going to slip through. The further back you go from the target version when setting the minimum version, the greater your risk.&lt;/li&gt;    &lt;li&gt;The maximum version that you are willing to support. Since this version will typically not exists at the time of your ship date, setting this version involves an educated guess based on understanding of what policies your dependencies use when incrementing their versions and the degree to which you are relying on undocumented (internal) code and behaviors. The spread between the target version and the maximum version is where you highest risk lies. On one hand you’d like to assure long viability of your release in the field. On the other hand, the further out you go, the greater the risk that your product will not work and make a liar out of you in the eyes of your users.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Because getting the above version decisions right and consistent across a component is extremely important, it is not a good idea for individual developers to be making these decisions on a plugin-by-plugin basis. In an Open Source environment, this should be a component-wide decision made collectively by the committers. In a commercial environment, this decision is often made higher up in the organization based on availability of resources and target user base considerations. &lt;/p&gt;  &lt;p&gt;When the overall decision is made, it is typically expressed in broad terms. For instance… “this version will ship on Ganymede SR1, but should work with all versions of Ganymede starting with GA”. It is then up to developers to translate that requirement into version ranges in the manifest. &lt;/p&gt;  &lt;p&gt;That’s a ton of tedious manual work with lots of room for mistakes. In other words, a perfect candidate for automation. A few years ago, I wrote a set of two custom Ant tasks to automate this process. The first task reads an Eclipse installation and produces an inventory file that lists id and version of every bundle found. The second tasks takes as input an inventory file representing the minimum platform, an inventory file representing the target platform and a policy for setting the maximum versions.&amp;#160; For every dependency, the task looks up the version from the minimum platform inventory. That becomes the left-hand-side of the version range. It then looks up the bundle version in the target platform inventory and applies the policy function to it. Here are some examples of policy functions: “x.y.z -&amp;gt;x+1.0.0”, “x.y.z -&amp;gt;x.y+1.o” or the extremely conservative “x.y.z -&amp;gt;x.y.z+1”. You can set different policies for different plugins or components based on what you know of their versioning conventions. The version returned by the policy function becomes the right-hand-side of the version range.&lt;/p&gt;  &lt;p&gt;We have been using these two tasks to automate and improve the quality of our version ranges for several releases of Eclipse tooling products at BEA and now at Oracle. Developers don’t set the versions on the dependencies specified in the bundle manifests stored in the source repository. At the end of every build, a process runs that splices version ranges into the manifests just prior to packaging the bundles for distribution. The target inventory is always generated on the fly based on whatever the product is building against. The minimum platform inventory is generated once when the minimum platform decision is made. The inventory is then stored in the source repository.&lt;/p&gt;  &lt;p&gt;This has been an extremely useful process improvement for us. Not only do we have more confidence in the version ranges encoded in our product distributions, but it takes significantly less work for developers to manage all of this. The developers never have to think about dependency versions during normal course of development and integrating new versions of dependencies takes less work (since version ranges in manifest don’t have to be fixed manually to get the build to work).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-5402217071075664024?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/5402217071075664024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=5402217071075664024' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5402217071075664024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5402217071075664024'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2009/02/better-way-to-manage-dependency-version.html' title='Better way to manage dependency version ranges'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-775808722590417190</id><published>2009-01-31T16:12:00.001-08:00</published><updated>2009-01-31T16:14:50.536-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Ant Snippets : expand-to-single-dir</title><content type='html'>&lt;p&gt;I try to feign ignorance about anything Ant-related, but it hasn't been working very well for me. It seems that no matter which way I turn, I am elbows deep in some Ant-based project. I guess I just like automating the tedious aspects of software engineering and I hate shell scripts even more than I dislike Ant. So I decided to do something very evil. I figure if I start spreading some of the knowledge around, other people will pick up some of these automation tasks and I can take a break from Ant for a while. &lt;/p&gt;  &lt;p&gt;First, the most powerful tool in your Ant arsenal is the &lt;a href="http://ant-contrib.sourceforge.net/"&gt;Ant-Contrib&lt;/a&gt; package from &lt;a href="http://www.sourceforge.org"&gt;SourceForge&lt;/a&gt;. Pure Ant is declarative in nature and lacks basic code flow constructs such as loops and if statements that most engineers live by. This is intentional. The core Ant premise is that you should describe what you want to accomplish rather than spelling out how to accomplish it. That works for some people, but I am not one of those people. I take my Ant with a good dose of &lt;a href="http://ant-contrib.sourceforge.net/"&gt;Ant-Contrib&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Now that we got preliminaries out of the way, I will share a little snippet of Ant that I wrote a while ago to help wrangle various zip-based distributions into usable form. One of the more common chores that you run into is to take a bunch of zip files in a specified directory and expand them all into a single directory (overwriting files as necessary). In the context of Eclipse this scenario comes up often when setting up target platforms from integration builds of various relevant projects or when packaging your Eclipse-based product for distribution (aka the all-in-one kit). It is nice to be able to have a utility in your arsenal that can do this easily and without hard coding the names of all the zips that need to be extracted.&lt;/p&gt;  &lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;target name=&amp;quot;expand-to-single-dir&amp;quot;&amp;gt;
  &amp;lt;check-required-property name=&amp;quot;src&amp;quot;/&amp;gt;
  &amp;lt;property name=&amp;quot;dest&amp;quot; value=&amp;quot;${src}&amp;quot;/&amp;gt;
  &amp;lt;property name=&amp;quot;includes&amp;quot; value=&amp;quot;*.zip&amp;quot;/&amp;gt;
  &amp;lt;property name=&amp;quot;excludes&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;
  &amp;lt;property name=&amp;quot;strip.path.prefix&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;
  &amp;lt;expand-to-single-dir 
    src=&amp;quot;${src}&amp;quot; dest=&amp;quot;${dest}&amp;quot; includes=&amp;quot;${includes}&amp;quot; 
    excludes=&amp;quot;${excludes}&amp;quot; strip-path-prefix=&amp;quot;${strip.path.prefix}&amp;quot;/&amp;gt;
&amp;lt;/target&amp;gt;
  
&amp;lt;macrodef name=&amp;quot;expand-to-single-dir&amp;quot;&amp;gt;
  &amp;lt;attribute name=&amp;quot;src&amp;quot;/&amp;gt;
  &amp;lt;attribute name=&amp;quot;dest&amp;quot;/&amp;gt;
  &amp;lt;attribute name=&amp;quot;includes&amp;quot; default=&amp;quot;*.zip&amp;quot;/&amp;gt;
  &amp;lt;attribute name=&amp;quot;excludes&amp;quot; default=&amp;quot;&amp;quot;/&amp;gt;
  &amp;lt;attribute name=&amp;quot;strip-path-prefix&amp;quot; default=&amp;quot;&amp;quot;/&amp;gt;
  &amp;lt;sequential&amp;gt;
    &amp;lt;mkdir dir=&amp;quot;@{dest}&amp;quot;/&amp;gt;
    &amp;lt;for param=&amp;quot;component.archive&amp;quot;&amp;gt;
      &amp;lt;path&amp;gt;
        &amp;lt;fileset dir=&amp;quot;@{src}&amp;quot; includes=&amp;quot;@{includes}&amp;quot; excludes=&amp;quot;@{excludes}&amp;quot;/&amp;gt;
      &amp;lt;/path&amp;gt;
      &amp;lt;sequential&amp;gt;
        &amp;lt;unzip src=&amp;quot;@{component.archive}&amp;quot; dest=&amp;quot;@{dest}&amp;quot; overwrite=&amp;quot;true&amp;quot;&amp;gt;
          &amp;lt;mapper type=&amp;quot;regexp&amp;quot; from=&amp;quot;^@{strip-path-prefix}(.*)$$&amp;quot; to=&amp;quot;\1&amp;quot;/&amp;gt;
        &amp;lt;/unzip&amp;gt;
      &amp;lt;/sequential&amp;gt;
    &amp;lt;/for&amp;gt;
  &amp;lt;/sequential&amp;gt;
&amp;lt;/macrodef&amp;gt;
  
&amp;lt;macrodef name=&amp;quot;check-required-property&amp;quot;&amp;gt;
  &amp;lt;attribute name=&amp;quot;name&amp;quot;/&amp;gt;
  &amp;lt;sequential&amp;gt;
    &amp;lt;if&amp;gt;
      &amp;lt;not&amp;gt;&amp;lt;isset property=&amp;quot;@{name}&amp;quot;/&amp;gt;&amp;lt;/not&amp;gt;
      &amp;lt;then&amp;gt;
        &amp;lt;fail message=&amp;quot;Property '@{name}' must be specified.&amp;quot;/&amp;gt;
      &amp;lt;/then&amp;gt;
    &amp;lt;/if&amp;gt;
  &amp;lt;/sequential&amp;gt;
&amp;lt;/macrodef&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above snippet defines expand-to-single-dir macro that you can easily use when writing your Ant targets and it also defines a target with the same name. The target is useful as a stand-alone tool that can be invoked directly from the command line. Since I am an Eclipse developer these days, the second part of this snippet adds a convenience target that calls the above utility in a way that also strips the typically-unwanted leading “eclipse” directory that is present in all Eclipse distributions.&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;target name=&amp;quot;expand-eclipse-zips&amp;quot;&amp;gt;
  &amp;lt;check-required-property name=&amp;quot;src&amp;quot;/&amp;gt;
  &amp;lt;property name=&amp;quot;dest&amp;quot; value=&amp;quot;${src}&amp;quot;/&amp;gt;
  &amp;lt;expand-to-single-dir 
    src=&amp;quot;${src}&amp;quot; dest=&amp;quot;${dest}&amp;quot; includes=&amp;quot;*.zip&amp;quot; strip-path-prefix=&amp;quot;eclipse/&amp;quot;/&amp;gt;
&amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-775808722590417190?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/775808722590417190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=775808722590417190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/775808722590417190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/775808722590417190'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2009/01/ant-snippets-expand-to-single-dir.html' title='Ant Snippets : expand-to-single-dir'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-7775342528523993344</id><published>2008-10-29T11:04:00.001-07:00</published><updated>2008-10-29T11:12:23.159-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Are code generators dumbing down our models?</title><content type='html'>&lt;p&gt;I suspect that I am about to bring the Wrath of Ed down on me, but here it goes...&lt;/p&gt;  &lt;p&gt;There are quite a few Java code generators that can take an arbitrary XML Schema and spit out tons of code that a developer doesn't have to write. There is JAXB, Apache XMLBeans and of course EMF. I am sure there are others. While code generators save us a lot of time, the push-button approach can lead to dumbing down of our models. &lt;/p&gt;  &lt;p&gt;I would argue that there are relatively few core modeling patterns, but the flexibility of XML makes it easy to express these patterns in a variety of ways. The generated code then unintentionally surfaces (rather than hiding) these XML serialization details in the model layer. This forces the clients of the model to deal with inconsistent and often difficult to use API.&lt;/p&gt;  &lt;p&gt;Consider the basic example of a boolean property. I have seen at least three different ways of representing that in XML:&lt;/p&gt;  &lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;some-flag&amp;gt;true&amp;lt;/some-flag&amp;gt;
&amp;lt;some-flag-enabled/&amp;gt;  &amp;lt;!-- absence means false --&amp;gt; 
&amp;lt;some flag value=&amp;quot;true&amp;quot;/&amp;gt;  &amp;lt;!-- the attribute is required --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The above three cases would generate different model code even though from the modeling perspective, they represent the same construct. &lt;/p&gt;&lt;p&gt;A more complex pattern is the selector-details construct where selector is a type enumeration and details provide settings specific to the type. I stopped counting how many different ways I've seen that pattern represented. Here are two of the most common examples:&lt;/p&gt;&lt;p&gt;Example 1: An explicit type element controls which property elements are applicable. &lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;type&amp;gt;...&amp;lt;/type&amp;gt;  &amp;lt;!-- valid values are X and Y --&amp;gt;
&amp;lt;property-1&amp;gt;...&amp;lt;/property-2&amp;gt;  &amp;lt;!-- associated with type X --&amp;gt;
&amp;lt;property-2&amp;gt;...&amp;lt;/property-2&amp;gt;  &amp;lt;!-- associated with type Y --&amp;gt;
&amp;lt;property-3&amp;gt;...&amp;lt;/property-3&amp;gt;  &amp;lt;!-- associated with type X and type Y --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Example 2: In this case, the elements alternative-x and alternative-y are mutually exclusive. The element names are functioning as type selectors. &lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;alternative-x&amp;gt;
  &amp;lt;property-1&amp;gt;...&amp;lt;/property-1&amp;gt;
  &amp;lt;property-3&amp;gt;...&amp;lt;/property-3&amp;gt;
&amp;lt;/alternative-x&amp;gt;
&amp;lt;alternative-y&amp;gt;
  &amp;lt;property-2&amp;gt;...&amp;lt;/property-2&amp;gt;
  &amp;lt;property-3&amp;gt;...&amp;lt;/property-3&amp;gt;
&amp;lt;/alternative-y&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I would argue that the the above cases are semantically identical and therefore should have the same representation in the Java model. Of course, that doesn't happen. All of the existing code generators that I am aware of will produce drastically different code for these two alternatives.&lt;/p&gt;&lt;p&gt;So why should we care? I would argue that in many cases, while we are saving time by generating model code, the cost savings are at the expense of complicating the model consumer code. Recently, I took over a project at Oracle that was building a form-based editors for several rather complicated WebLogic Server deployment descriptors. The schemas of these descriptors evolved over many server releases and many people had a hand at augmenting them. The result is a complete lack of consistency. You could say that perhaps the schemas should have been more carefully evolved, but I would argue that they represent a rather realistic example of what real world complex schemas look like. In any case, the first attempt at building these editors was to generate an EMF model based on the XSDs and to build UI that would bind to EMF. That worked ok for a while, but eventually the UI code started to get too complicated. Many of the UI binding code had to be hand-written. It ultimately made sense to throw away the generated model code and to hand-code the model. That allowed us to arbitrarily control how model surfaces XML constructs and made it possible to reduce the amount of custom UI code that was necessary by literally several orders of magnitude. &lt;/p&gt;&lt;p&gt;I am certainly not trying to say that generated model code is a bad idea, but the ease with which it is possible to toss an XSD into a code generator and get a bunch of model code in return plays part in encouraging developers to pay less attention than is really necessary to the model layer. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-7775342528523993344?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/7775342528523993344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=7775342528523993344' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/7775342528523993344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/7775342528523993344'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/10/are-code-generators-dumbing-down-our.html' title='Are code generators dumbing down our models?'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-5835202211722513893</id><published>2008-10-23T16:13:00.001-07:00</published><updated>2008-10-29T08:49:07.496-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-wtp'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Common Servers View for Eclipse</title><content type='html'>&lt;p&gt;There is a cool collaboration happening right now between WTP and DTP to build a shared Servers view that will replace the separate WTP's Servers view and DTP's Data Source Explorer view. The new view is built using the Common Navigator framework and will make it easy for other Eclipse Projects to contribute content. One of the important goals is to reduce clutter on user's workbench by collapsing many individual views into one. If you are interested in this effort, you should check out &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=252239"&gt;Bug 252239&lt;/a&gt;. There has also been some relevant discussion on &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=245013"&gt;Bug 245013&lt;/a&gt; and &lt;a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=247934"&gt;Bug 247934&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;So, I am looking at you... CVS Tooling, Subversive, DSDP Target Management, SOA Tools, etc. You know who you are. Come join the party.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-5835202211722513893?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/5835202211722513893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=5835202211722513893' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5835202211722513893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5835202211722513893'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/10/common-servers-view-for-eclipse.html' title='Common Servers View for Eclipse'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-1215170685696492798</id><published>2008-10-23T11:54:00.001-07:00</published><updated>2008-10-23T11:54:51.877-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-fproj'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-wtp'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Eclipse Project Declaration : Faceted Project Framework</title><content type='html'>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;I am blogging today to raise awareness of a project declaration that might have gone unnoticed in the inboxes of Eclipse committers and other members. The goal of the Faceted Project Framework is to provide a re-usable system that facilitates treating Eclipse projects as composed of units of functionality (called facets) that can be easily added or removed by users. The initial code contribution will come from a mature and a rather successful component in the Eclipse Web Tools Platform (WTP), but the ultimate goal for creating this independent project is to encourage broader adoption in contexts beyond that of WTP. I expect this project will evolve substantially as others bring their use cases to the table.&lt;/p&gt;  &lt;p&gt;Anyone who has ever wondered if there was a better solution that a multitude of &amp;quot;Enable function X&amp;quot; menu items or has ever thought that users should be able to add and remove natures without hacking the .project file should get involved. I am looking for both potential contributors and potential consumers. If you have use cases or just random thoughts on this subject, I encourage you to jump in and get involved at the newly-created newsgroup.&lt;/p&gt;  &lt;p&gt;Project Proposal: &lt;a href="http://www.eclipse.org/proposals/fproj/"&gt;http://www.eclipse.org/proposals/fproj/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Newsgroup: &lt;a href="http://www.eclipse.org/newsportal/thread.php?group=eclipse.fproj"&gt;http://www.eclipse.org/newsportal/thread.php?group=eclipse.fproj&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-1215170685696492798?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/1215170685696492798/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=1215170685696492798' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/1215170685696492798'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/1215170685696492798'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/10/eclipse-project-declaration-faceted.html' title='Eclipse Project Declaration : Faceted Project Framework'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-253392432953692460</id><published>2008-10-21T14:13:00.001-07:00</published><updated>2008-10-21T14:13:16.383-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse-wtp'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Creating API, Lessons Learned</title><content type='html'>&lt;p&gt;The subject of how to properly create and declare API is frequently debated at various communities within the Eclipse ecosystem. One of the thorniest issues is the disagreement over how to treat the so-called &amp;quot;provisional API&amp;quot;, basically the API that either has not yet received sufficient feedback or has known issues that cannot be addressed prior to the release. There is a lively debate going on right now on this very subject on the mailing list of the Eclipse E4 project (the effort to build the next generation Eclipse platform - sometimes referred to as Eclipse 4.0), so I thought I should jump in and share our experience in this area at the Eclipse Web Tools Platform (WTP) project in hopes that others don't repeat the mistakes that were made.&lt;/p&gt;  &lt;p&gt;It's important to note that opinions expressed here are mine alone. Other involved parties may not agree. Names and other identifying information is withheld to protect the guilty.&lt;/p&gt;  &lt;h3&gt;History&lt;/h3&gt;  &lt;p&gt;The start of WTP project was pretty rough. Large code contributions had to be rationalized in the context of a platform that is supposed to be extensible for many external adopters. One of the challenges was the belief by many of the committers from the company that made the code contribution that the APIs are good as is because they existed like that for a long time inside that company's commercial products and are therefore proven. Aligned against that was the growing feedback from new adopters who were saying that the APIs were insufficient and in some cases just plain wrong. Creating good APIs that are flexible enough to address variety of adopter usecases takes a very long time, but unfortunately time was running out. Major companies involved in WTP were pressuring the project to make a release so that they can build commercial products with it. After much debate, a compromise was reached. WTP was going to make a release, but we were not going to declare any API as stable. Everything will be labeled as provisional. &lt;/p&gt;  &lt;p&gt;Sounds good in theory, right? What went wrong is that the concept of provisional API was not concretely defined as part of the initial agreement. Everyone (from committers to adopters) ended up with their own ideas about the meaning of the concept. The first release happened and WTP team went to work on the next release trying to improve the APIs based on the growing feedback. That's when the fireworks really started. Certain adopters were not particularly happy that WTP was continuously breaking them despite the fact that they were leveraging code clearly placed in internal packages or otherwise marked as provisional. Granted, adopters didn't have much choice if they wanted to build products on top of WTP, but that's what you get when a project is starting out. None of that seemed to matter and eventually WTP PMC bowed under the pressure by instituting a very restrictive code change policy. An &amp;quot;adopter usage scan tool&amp;quot; was created that could be used by WTP adopters to scan their code base for references to WTP code and send these reports back to WTP where they would be collected and used as a reference for determine whether a change is allowed or not. This new policy effectively negated the original promise that was made with regard to provisional API. The new contract covered everything including code previously designated as provisional and purely internal code. Instead of committers promoting API, anything that an adopter touched (as represented by these reports) effectively became API. &lt;/p&gt;  &lt;p&gt;Work on improving API essentially ground to a halt. It just became too expensive to fix many of the larger problems. Technically, a committer could seek PMC approval to break code referenced in adopter scans, but exceptions were rarely granted. The argument that was frequently made is that by making a proposed change, many lines of code in adopter products would be effected. It's &amp;quot;cheaper&amp;quot; for committers to not make the change in question or at least make it in a way that's completely backwards compatible. I will leave it as an exercise for the reader to see the fallacy of that argument.&lt;/p&gt;  &lt;p&gt;The end result is that WTP was left with large amounts of &amp;quot;in progress&amp;quot; API code in random internal packages that was effectively frozen because it became too expensive for committers to continue to work on this API within the imposed constraints. In many cases, providing the requisite backwards compatibility would have effectively doubled the amount of work. Some improvements that were easy to make in additive fashion continued to be made over the next few releases, but real progress essentially stopped. &lt;/p&gt;  &lt;p&gt;Finally, last year a group of committers was convened to try to improve the situation by proposing a new API policy for WTP. The &lt;a href="http://wiki.eclipse.org/WTP_API_Policy"&gt;end result&lt;/a&gt; formally defined provisional API and started the process of phasing out the flawed adopter usage scans policy. As someone who was involved in drafting the new API policy, I can tell you that I still see many flaws in it, but it is an effort to take a step in the right direction. Only time will tell for sure.&lt;/p&gt;  &lt;h3&gt;Thoughts on API Creation&lt;/h3&gt;  &lt;p&gt;The following is a collection of my somewhat random thoughts on API creation and the related processes.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Ability to declare provisional API is an essential step in API creation. You cannot be sure that the API is right until you received sufficient and diverse feedback. It is impossible to attain that level of feedback with one release cycle. Most external adopters will not start looking at a release until it's close to being finished. They will not start building products on it until even later. The best you will get early on is &amp;quot;yeah, that looks about right&amp;quot;, which is not good enough.&lt;/li&gt;    &lt;li&gt;Placing provisional API in an internal package (such as internal.provisonal convention sometimes used by Eclipse Platform ) creates unnecessary churn for adopters and committers. Consider the case where provisional API turns out to be 90% correct. The advantage of the internal.provisional approach is that you don't have to separately define expectations for provisional code (it gets treated as internal by virtue of the package name), but I would argue that it's worth taking the time to define a separate contract for provisional API since allowing provisional API in non-internal packages results in less work for both adopters and committers.&lt;/li&gt;    &lt;li&gt;It's important to have a good system for determining whether API is ready to be declared as fully supported (not provisional any more). Leaving the decision completely in the hands of committers or even project leads can lead to problems since people are inherently biased towards their own code. Some things to check when deciding if API is ready to be declared are level of documentation, unit test coverage, presence of outstanding API issues in bugzilla and level (as well as diversity) of adopter feedback. I prefer a system where a committer nominates the API for declaration and there is a process where other committers and adopters can raise objections.&lt;/li&gt;    &lt;li&gt;It's important to carefully balance the needs of committers working on the API and adopters consuming the API. It's a mistake to only look at the problem from the perspective of resource expenditure. For any successful platform, there will always be far fewer resources working on the platform than consuming the platform. Trying to add too much protection for platform adopters can inhibit innovation in the platform and ultimately hurt those same adopters.&lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-253392432953692460?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/253392432953692460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=253392432953692460' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/253392432953692460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/253392432953692460'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/10/creating-api-lessons-learned.html' title='Creating API, Lessons Learned'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-9051589777112906213</id><published>2008-09-30T10:53:00.001-07:00</published><updated>2008-09-30T10:53:27.618-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='facets'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Eclipse Nexus Project Proposal</title><content type='html'>&lt;p&gt;It's an unfortunate fact that many Eclipse projects operate in their own little worlds without knowledge of or collaboration with other projects. This leads to code duplication and visible seams in the finished Eclipse product. Part of the problem is social. It's hard to keep track of all the projects out there and even harder to reach out to discuss collaboration, but a big part of it is also due to the lack of infrastructure that facilitates code sharing efforts. Consider the situation where two sibling projects (no dependency on each other) want to collaborate on some shared code. There is really no effective way for this collaboration to take place. Where would you put the shared code? &lt;/p&gt;  &lt;p&gt;In order to try to address this problem, I have been working a proposal for Eclipse Nexus Project that would take on facilitating such collaboration. Right now, I am discussing the draft proposal with the Eclipse Technology Project PMC which would serve as a host for Nexus as it gets off the ground.&lt;/p&gt;  &lt;p&gt;Anyone interested in learning more or in joining the effort can read the draft proposal, add themselves to the wiki, contact me directly, etc.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wiki.eclipse.org/Nexus_Project"&gt;Eclipse Nexus Project Proposal Wiki&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-9051589777112906213?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/9051589777112906213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=9051589777112906213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9051589777112906213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9051589777112906213'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/eclipse-nexus-project-proposal.html' title='Eclipse Nexus Project Proposal'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2949807698278275417</id><published>2008-09-18T18:01:00.001-07:00</published><updated>2008-09-18T18:04:05.954-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='facets'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='facets-faq'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Facets FAQ : Supporting modular runtimes</title><content type='html'>&lt;p&gt;This is the first entry in a series of posts where I will answer some frequently asked questions about the Faceted Project Framework in Eclipse. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Question: &lt;/strong&gt;Some application servers such as WebLogic and JBoss are modular in nature. Various components of the server can be selectively present or absent. Further, even if the component is present, a particular configuration of the server might turn that component on or off. So say I have a portal server component and a corresponding facet for enabling tooling related to that portal component. I want the portal facet to only be available for selection if the targeted runtime includes the portal component. How do I set that up?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Answer: &lt;/strong&gt;Faceted Project Framework models runtimes as made up of one or more runtime components. When you create a facet, you get to declare which runtime components it is supported on. In addition to what's specified explicitly, the facet will have implicit constraints on runtimes based on the dependencies that it declares on other facets.&lt;/p&gt;  &lt;p&gt;Let's take the portal example described in the question. A Java application server will typically be modeled as composed of at least two runtime components. One will represent the JRE that the server is running on. The other will represent the base application server with all of its core capabilities. In the portal example, we will want to add a third runtime component to the mix to represent the portal module. Once we do that, we can easily map the portal facet to the portal component and facet will only be shown to the user if the runtime component is present in the runtime.&lt;/p&gt;  &lt;p&gt;The following little snippet declares a portal runtime component and maps portal facet (assumed to be already declared) to it.&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.wst.common.project.facet.core.runtimes&amp;quot;&amp;gt;
  &amp;lt;runtime-component-type id=&amp;quot;sample-portal-component&amp;quot;/&amp;gt;
  &amp;lt;runtime-component-version type=&amp;quot;sample-portal-component&amp;quot; version=&amp;quot;1.0&amp;quot;/&amp;gt;
  &amp;lt;supported&amp;gt;
    &amp;lt;runtime-component id=&amp;quot;sample-portal-component&amp;quot; version=&amp;quot;1.0&amp;quot;/&amp;gt;
    &amp;lt;facet id=&amp;quot;sample-portal-facet&amp;quot; version=&amp;quot;1.0&amp;quot;/&amp;gt;
  &amp;lt;/supported&amp;gt;
&amp;lt;/extension&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So how do I add runtime components to my runtime? In WTP there is a bridge that translates runtimes defined using WTP Server Tools API to API that's understood by Faceted Project Framework. The default behavior of the bridge is to create two-component runtimes as described in the previous paragraph, but there is an extension point that lets you add a component provider that will be called when bridge is converting the runtime. Here is how you add declare a component provider:&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;&amp;lt;extension point=&amp;quot;org.eclipse.jst.server.core.internalRuntimeComponentProviders&amp;quot;&amp;gt;
  &amp;lt;runtimeComponentProvider
    id=&amp;quot;[extension-id]&amp;quot;
    class=&amp;quot;[provider-class-name]&amp;quot;
    runtimeTypeIds=&amp;quot;[server-tools-runtime-id]&amp;quot;/&amp;gt;
&amp;lt;/extension&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once invoked, the component provider can examine various aspects of the runtime (such as state on disk at the location pointed to by the runtime or settings in the workspace). It can then construct and return the appropriate runtime components that will be merged with components created by the bridge to create a fully-specified runtime definition. Here is a sketch of how such component provider might look like:&lt;/p&gt;&lt;pre style="border-right: #999999 1px dashed; padding-right: 5px; border-top: #999999 1px dashed; padding-left: 5px; font-size: 12px; padding-bottom: 5px; overflow: auto; border-left: #999999 1px dashed; width: 100%; color: #000000; line-height: 14px; padding-top: 5px; border-bottom: #999999 1px dashed; font-family: andale mono, lucida console, monaco, fixed, monospace; background-color: #eee"&gt;&lt;code&gt;import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponent;
import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponentType;
import org.eclipse.wst.common.project.facet.core.runtime.IRuntimeComponentVersion;
import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager;
import org.eclipse.wst.server.core.IRuntime;
import org.eclipse.wst.server.core.internal.facets.RuntimeFacetComponentProviderDelegate;

public final class SampleRuntimeComponentProvider extends RuntimeFacetComponentProviderDelegate
{
    private static final IRuntimeComponentType PORTAL_TYPE 
        = RuntimeManager.getRuntimeComponentType( &amp;quot;sample.portal.component&amp;quot; );
    
    private static final IRuntimeComponentVersion PORTAL_VERSION_1 
        = PORTAL_TYPE.getVersion( &amp;quot;1.0&amp;quot; );
    
    public List&amp;lt;IRuntimeComponent&amp;gt; getRuntimeComponents( final IRuntime runtime )
    {
        final File location = runtime.getLocation().toFile();
        final List&amp;lt;IRuntimeComponent&amp;gt; components = new ArrayList&amp;lt;IRuntimeComponent&amp;gt;();
        
        if( isPortalPresent( location ) )
        {
            final IRuntimeComponent portalComponent
                = RuntimeManager.createRuntimeComponent( PORTAL_VERSION_1, null );
            
            components.add( portalComponent );
        }
    }
    
    private static boolean isPortalPresent( final File location )
    {
        return false;  // TODO: Implement the check for portal.
    }
}&lt;/code&gt;&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2949807698278275417?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2949807698278275417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2949807698278275417' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2949807698278275417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2949807698278275417'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/facets-faq-supporting-modular-runtimes.html' title='Facets FAQ : Supporting modular runtimes'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-2252768660450914361</id><published>2008-09-18T16:43:00.001-07:00</published><updated>2008-09-18T16:44:53.341-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='ui'/><title type='text'>Calling all UI experts</title><content type='html'>&lt;p&gt;So I was working on an Eclipse form-based editor the other day when I came across a rather interesting UI puzzle. In my model, I have an enumeration field. Depending on what the user selects, certain other detail fields become relevant and need to be shown. Previously, I have solved this problem by putting the master combo field first followed by a details frame that contains all the detail fields and is updated when combo selection is made. That worked relatively well when that master-details block was in a section by itself, but as soon as it got surrounded by other fields, it started to become difficult to tell at a glance that the combo and the frame belonged together and were separate from other fields in the section.   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;See for yourself...&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="279" alt="loggingSection" src="http://lh5.ggpht.com/kosta0120/SNLnopIwvqI/AAAAAAAAABk/KproI91TenQ/loggingSection%5B5%5D.png?imgmax=800" width="427" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;Besides dancing around the problem by adding a little white space above the master combo or putting the entire master-details block into a section by itself, one other approach occurred to me. Here, the master and detail fields are next to each other and enclosed together in a frame.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/kosta0120/SNLnpqwLyTI/AAAAAAAAABo/Ho0zAgQXtqk/s1600-h/loggingSectionAllInFrame%5B4%5D.png"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="293" alt="loggingSectionAllInFrame" src="http://lh6.ggpht.com/kosta0120/SNLnqMiX_5I/AAAAAAAAAB0/8TeQC3BSXbM/loggingSectionAllInFrame_thumb%5B2%5D.png?imgmax=800" width="425" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Both approaches have their pluses and minuses. The second approach does make it more clear that master and details are tied together, but we loose the ability to identify what is master and what is details. My question for the UI experts out there is how do you typically render such master-details blocks? Do you use one of these approaches that I described? Something else entirely?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-2252768660450914361?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/2252768660450914361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=2252768660450914361' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2252768660450914361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/2252768660450914361'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/calling-all-ui-experts_18.html' title='Calling all UI experts'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/kosta0120/SNLnopIwvqI/AAAAAAAAABk/KproI91TenQ/s72-c/loggingSection%5B5%5D.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-8523395196727204549</id><published>2008-09-18T16:29:00.001-07:00</published><updated>2008-09-18T16:29:39.291-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><title type='text'>In San Francisco area next week</title><content type='html'>&lt;p&gt;I will be in the San Francisco area visiting Oracle HQ next week. Send me an &lt;a href="mailto:kosta@lt-rider.net"&gt;e-mail&lt;/a&gt; if you are in the area and want to get together for drinks after work and talk about Eclipse, WTP, etc.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-8523395196727204549?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/8523395196727204549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=8523395196727204549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8523395196727204549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/8523395196727204549'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/in-san-francisco-area-next-week.html' title='In San Francisco area next week'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-5638569838413585470</id><published>2008-09-10T09:02:00.000-07:00</published><updated>2008-09-10T09:25:44.693-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Are Eclipse committer elections a little too open?</title><content type='html'>Since I became a committer on Eclipse WTP project a few years ago, I have witnessed and participated in many committer elections. One aspect of the way elections are conducted struck me as somewhat problematic. Clearly having transparent processes is important to an open source community, but I wonder if there is such thing as too much of a good thing. 

In all the committer elections that I observed, I have never seen a single negative vote. That somewhat defeats the point of having an election in the first place. As you can imagine, I have a theory for why negative votes don't happen and I am curious if other people agree with my observations...

Consider that a nominated contributor likely knows a few existing committers on the project in other ways than just interactions over past contributions. Perhaps the nominee works for the same employer. These committers might have a vested interest in getting the nominee elected. Then suppose, you have another committer on the project who has a real objection to the nominee getting elected. What options does this committer have? He can vote his true opinion and likely face retribution from other committers on the project (thus making it more difficult for him to work on the project). He can bite his tongue and abstain. Or he might actually feel compelled to vote +1. Since voting record is visible, he might feel that even abstaining would jeopardize his working relationship with other committers on the project.

I wonder if a system where only EMO knows who voted how and public record hides the names (comments would still be shown) would create an environment for more effective committer elections?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-5638569838413585470?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/5638569838413585470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=5638569838413585470' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5638569838413585470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/5638569838413585470'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/are-eclipse-committer-elections-little.html' title='Are Eclipse committer elections a little too open?'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2913369703414801920.post-9163778119617362954</id><published>2008-09-05T09:16:00.000-07:00</published><updated>2008-09-09T09:58:39.284-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='eclipse'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Designing API for fragile content</title><content type='html'>Just as with any other profession, programming involves quite a bit of monotonous and repetitive work. Interesting problems do come up, of course, but not so frequently that encountering one always brings a smile to my face. One of my deep interests in the programming profession is API design, so it would be fair to say that when I recently encountered a tricky API design puzzle I got pretty excited.

So I was tasked with building a forms-based editor in Eclipse for an XML file with a certain schema. I started out by extending the XML source editor that's part of WTP. That gave the source view tab for my editor and I could access XML DOM that the source editor exposed. Any changes I made to the DOM would propagate to the source buffer. That's a pretty good start, but I did not want my forms UI working directly with DOM. I don't know if DOM API has any fans, but I am certainly not one of them. I didn't want my UI code getting cluttered with it. Ok, easy enough. Just take DOM and wrap it in API custom-created for the schema.

Many of the elements in this particular document schema are tightly-typed. There are integers, class names, file paths, etc. My first cut at the API used these types in the getters and setters...
&lt;div style=" border: 1px; border-color: black; border-style: dotted; font-family: Courier New; font-size: 10pt;margin:25px;padding-left:5px;padding-right:5px;padding-top:5px;padding-bottom:5px"&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDuration();&lt;/span&gt;&lt;span style=""&gt;&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;/div&gt;That works well enough when content is well-formed, but this is an XML file that's edited directly by users. Handling of malformed content is very important. Let's say that the min-duration element is found, but it's content cannot be parsed as an integer. The only option that the above API left me was to return null. That might be acceptable in some cases, but it's produces a rather poor user experience in the context of an editor. The text field that would be bound to this property would be blank, forcing the user to either type in a new value or revert to the source view in order to fix the existing value. What I wanted to do is show the malformed value in the text field together with a problem decoration so that the user can see and fix it easily.  Ok, so let's augment the API a bit...&lt;div style=" border: 1px; border-color: black; border-style: dotted; font-family: Courier New; font-size: 10pt;margin:25px;padding-left:5px;padding-right:5px;padding-top:5px;padding-bottom:5px"&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDuration();&lt;/span&gt;
&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDurationUnparsed();&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;/div&gt;That's better, but min duration has a default value and only positive integers are valid. A bit more API augmentation was in order...&lt;div style=" border: 1px; border-color: black; border-style: dotted; font-family: Courier New; font-size: 10pt;margin:25px;padding-left:5px;padding-right:5px;padding-top:5px;padding-bottom:5px"&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDuration();&lt;/span&gt;
&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDurationUnparsed();&lt;/span&gt;
&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDurationDefault();&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&lt;span style="color: #000000;"&gt;IStatus&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;validateMinDuration();&lt;/span&gt;&lt;/div&gt;Now I had enough information in the API to build the UI that I needed, but the API was starting to smell a bit. That's six methods for one element in the schema that has dozens of elements. There has to be a better way to structure this API. After some head-scratching, I decided to try returning a surrogate object from the getter method instead of the actual value. The surrogate would handle parsing, default values and validation...&lt;div style=" border: 1px; border-color: black; border-style: dotted; font-family: Courier New; font-size: 10pt;margin:25px;padding-left:5px;padding-right:5px;padding-top:5px;padding-bottom:5px"&gt;&lt;span style="color: #000000;"&gt;IntegerValue&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getMinDuration();&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&lt;span style="color: #7f0055; font-weight: bold;"&gt;void&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;setMinDuration(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;minDuration&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;

&lt;span style="color: #7f0055; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;IntegerValue&lt;/span&gt;
&lt;span style="color: #000000;"&gt;{&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getString();&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getString(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;boolean&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;useDefault&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getParsedValue();&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;Integer&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getParsedValue(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;boolean&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;useDefault&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;IStatus&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;validate();&lt;/span&gt;
&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/div&gt;The getMinDuration() method would always return a non-null surrogate object. The caller then decides what aspect of value they are interested in querying. The IntegerValue class supplies default validation logic for handling unparsable content, but additional validation can be added. For instance, in this case only integers greater than zero are valid. Since range is a pretty common constraint, I made the IntegerValue constructor take the min and max values (in addition to the raw string value of the property and the default value). More complicated validation scenarios can be handled by subclassing the IntegerValue class.

Note that only the getter deals with surrogate object. I wanted to keep the surrogate objects immutable so that they can be handled in a manner similar to basic value types without worrying about synchronization. When setting a value, you either have a raw value (either it can't be parsed or the code in question doesn't want to deal with parsing it) or you have a tightly-typed value. An overloaded setter method takes care of both of these scenarios.

As you can imagine, it was simple at this point to extend this pattern to other types. I created a base class for all value types, which made it possible for some code to handle variety of types without knowing what they actually are. A good example of this is text field data binding code. Since any value can be retrieved and set as a string, any value can be bound to a text field.&lt;div style=" border: 1px; border-color: black; border-style: dotted; font-family: Courier New; font-size: 10pt;margin:25px;padding-left:5px;padding-right:5px;padding-top:5px;padding-bottom:5px"&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;abstract&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Value&amp;lt;T&amp;gt;&lt;/span&gt;
&lt;span style="color: #000000;"&gt;{&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getString();&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;String&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getString(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;boolean&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;useDefault&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;T&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getParsedValue();&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;T&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;getParsedValue(&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;boolean&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;useDefault&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;IStatus&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;validate();&lt;/span&gt;
&lt;span style="color: #000000;"&gt;}&lt;/span&gt;

&lt;span style="color: #7f0055; font-weight: bold;"&gt;class&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;IntegerValue&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #7f0055; font-weight: bold;"&gt;extends&lt;/span&gt;&lt;span style=""&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Value&amp;lt;Integer&amp;gt;&lt;/span&gt;
&lt;span style="color: #000000;"&gt;{&lt;/span&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #000000;"&gt;...&lt;/span&gt;
&lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/div&gt;I actually ended up using the same pattern even for properties that were strings by creating a StringValue class. Even though there is no parsing involved, the benefit of having consistent access to default value handling and validation made it worth it.

So what do you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2913369703414801920-9163778119617362954?l=lt-rider.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://lt-rider.blogspot.com/feeds/9163778119617362954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2913369703414801920&amp;postID=9163778119617362954' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9163778119617362954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2913369703414801920/posts/default/9163778119617362954'/><link rel='alternate' type='text/html' href='http://lt-rider.blogspot.com/2008/09/designing-api-for-fragile-content.html' title='Designing API for fragile content'/><author><name>Konstantin Komissarchik</name><uri>http://www.blogger.com/profile/12487640637368516721</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry></feed>
