tag:blogger.com,1999:blog-43080549586272075302024-03-08T06:07:02.091-08:00Serge BeauchampSerge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.comBlogger17125tag:blogger.com,1999:blog-4308054958627207530.post-19075473690100010052011-03-28T11:21:00.000-07:002013-11-01T08:32:35.350-07:00Have you missed this presentation?Have you missed 'Deadlocks: the beginning of the end" at EclipseCon last week?<div><br /></div><div>Here's your chance of having your own personal copy in high definition!</div><div><br /></div><div><iframe width="420" height="315" src="//www.youtube.com/embed/0UOQ0098LKY" frameborder="0" allowfullscreen></iframe></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com26tag:blogger.com,1999:blog-4308054958627207530.post-52117919615450669782010-12-31T14:22:00.001-08:002010-12-31T14:22:44.397-08:00Optimizing concurrency with Freescale’s Deadlock Preventer<p>The overall concurrency of a program, given it already uses an optimal number of threads, will depend on how much lock contention is occurring.</p> <p>To avoid both deadlocks and lock contention, synchronization primitives should be the most granular possible given a fixed number of primitives.</p> <p>For example, in the following snippet:</p> <blockquote> <p><font face="Courier New">public synchronized void setProperty(Object newValue) { <br />    value = newValue; <br />    notifyPropertyChange(); <br />}</font></p> <p><font face="Courier New">private void notifyPropertyChange() { <br />    synchronized(listeners) { <br />        for (IListener listener : listeners) <br />            listener.changed(); <br />    } <br />}</font></p> </blockquote> <p>The <font face="Courier New">setProperty()</font> method is synchronized in order to protect the “value” data from concurrent data access.  Inadvertently, the synchronized block will cause all the code path executed by the listener.changed() invocation to needlessly have the <font face="Courier New">synchronized(this)</font> lock as a precedent.</p> <p>This will not only cause the code to have a sub-optimal concurrent execution, but also introduce a lock order dependency between ‘this’, ‘listeners’, and whatever lock is acquired by the listener’s <font face="Courier New">changed()</font> implementation, possibly eventually causing a deadlock (in the Deadlock' Preventer’s terminology, the ‘listeners’ lock is then a ‘follower’ of the ‘this’ lock, and the ‘this’ lock a precedent of the ‘listeners’ lock).</p> <p>The code could be re-written as follows:</p> <blockquote> <p><font face="Courier New">public void setProperty(Object newValue) { <br />    synchronized(this) { <br />        value = newValue; <br />    } <br />    notifyPropertyChange(); <br />}</font></p> </blockquote> <p>By simply reducing the granularity of the ‘this’ lock acquisition, we improve possible concurrent execution, eliminate the lock dependency, and avoid lock ordering acquisition problems between ‘this’ and ‘listeners’, and ‘this’ and all listener’s <font face="Courier New">changed()</font> implementations, without any negative effect whatsoever.</p> <p>We could also re-write the <font face="Courier New">notifyPropertyChange()</font> implementation as follows:</p> <blockquote> <p><font face="Courier New">private void notifyPropertyChange() { <br />    IListener[] tmp; <br />    synchronized(listeners) { <br />        tmp = listeners.clone(); <br />    } <br />    for (IListener listener : tmp) <br />        listener.changed(); <br />}</font></p> </blockquote> <p>At the cost of the <font face="Courier New">clone()</font> statement (something probably insignificant compared to the code executed in the listeners), the lock dependency is completely removed between ‘this’, ‘listeners’, and all lock acquisitions in the listener’s <font face="Courier New">changed()</font> implementations.</p> <p>In a java program, the locks with the most number of followers are not only the most likely to cause deadlocks, but also the locks that are likely to reduce overall system concurrency.</p> <p>It is unfortunately very easy to induce unnecessary dependencies between synchronization primitives, and hard to discover which locks have effectively a large number of followers. </p> <p>Without a tool such as the Deadlock Preventer, which helps identifying which locks have the most followers, developers would be reduced to half hazardly trying to improve lock granularity without knowing where to start.</p> <p>This is very similar to performance optimization without using a profiler:  without knowing what takes the most time, developer’s time is easily wasted, and so is concurrency optimization.</p> <p><strong>Help with the Deadlock Preventer</strong></p> <p>With the <a href="https://github.com/sbeauchamp/Deadlock-Preventer/zipball/master">latest release</a> of the Deadlock Preventer, it is now possible to use the Deadlock Preventer view to download lock statistics for a java program.</p> <p><a href="http://lh6.ggpht.com/_xRUrqZpshsQ/TR5Xgknln-I/AAAAAAAAAD4/5ClojH2ae-s/s1600-h/image%5B16%5D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_xRUrqZpshsQ/TR5Xi6x_RTI/AAAAAAAAAD8/uAgJQm9LoiA/image_thumb%5B12%5D.png?imgmax=800" width="582" height="484" /></a></p> <p align="left">By right-clicking on the process name in the “Conflicts” tab, and selecting the “Statistics…” menu, the following dialog appears:</p> <p align="center"><a href="http://lh6.ggpht.com/_xRUrqZpshsQ/TR5Xj6aMYdI/AAAAAAAAAEA/XA7mPZybOgo/s1600-h/image%5B8%5D.png"><img style="border-bottom: ; border-left: ; margin: ; padding-left: ; padding-right: ; display: inline; border-top: ; border-right: ; padding-top: " title="image" alt="image" src="http://lh4.ggpht.com/_xRUrqZpshsQ/TR5XlJj9f1I/AAAAAAAAAEE/cQKmlho0lzw/image_thumb%5B6%5D.png?imgmax=800" width="640" height="289" /></a></p> <p align="left">The table lists all locks in the program, the number of followers and precedents, and their acquisition locations.  More information can be obtained for each lock by selecting its row and doing copy, which puts the following information in the clipboard (for the first lock in the table above):</p> <blockquote> <p align="left"><font face="Courier New">lock: java.lang.Object (id=2), precedents(1) followers(1) <br />  zzz.Main.test(Main.java:14) <br />  zzz.Main.main(Main.java:6) <br />  precedents: <br />    java.lang.Object (id=1), thread id(1 (main)) <br />     zzz.Main.test(Main.java:13) <br />     zzz.Main.main(Main.java:6) <br />  followers: <br />    java.lang.Object (id=1), thread id(13 (Thread-2)) <br />     zzz.Main$1.run(Main.java:22) <br />     java.lang.Thread.run(Thread.java:619) <br /></font></p> </blockquote> <p>The text contains detailed information about each precedents and followers, along with the stack trace in which their relationship to the lock were recorded.</p> <p>The information for all locks can also be exported to a single text file by using the “Export…” button.</p> <p>One very useful way to use the statistics generated by the Deadlock Preventer is to sort all the locks by their follower count.</p> <p>To give an example of what large programs lock statistics look like, the following table shows what the Eclipse IDE synchronization primitives statistics just after opening the workbench window:</p> <p><a href="http://lh6.ggpht.com/_xRUrqZpshsQ/TR5Xol_BZ-I/AAAAAAAAAEI/jUJFB29RHCg/s1600-h/image%5B25%5D.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: ; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_xRUrqZpshsQ/TR5Xr9xIcQI/AAAAAAAAAEM/eA6SX5yE8jE/image_thumb%5B19%5D.png?imgmax=800" width="1028" height="425" /></a></p> <p>Listing the top followers’ count locks out of a total of 21 830 locks.</p> Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com2tag:blogger.com,1999:blog-4308054958627207530.post-84747964041083617582010-12-31T10:28:00.001-08:002010-12-31T10:28:58.283-08:00Running Freescale’s Deadlock Preventer from the command line<p>One of the best ways to detect potential deadlocks is to integrate the Deadlock Preventer in a release engineering process, so it can run with the java program executing the automated tests, and have an excellent code coverage to analyze the system’s synchronization primitives.</p> <p>To integrate the Deadlock Preventer in a release engineering process, although, means being able to configure the test scripts to run the Deadlock Preventer.</p> <p>Adding the Deadlock preventer is as simple as adding the following two arguments to the “java” executable:</p> <p><font face="Courier New">-javaagent:path-to\com.freescale.deadlockPreventer.wrapper_1.0.0\com.freescale.deadlockpreventer.jar</font></p> <p><font face="Courier New">-Xbootclasspath/a:path-to\com.freescale.deadlockPreventer.wrapper_1.0.0\com.freescale.deadlockpreventer.jar;path-to\javassist.wrapper_1.0.0\javassist.jar</font></p> <p>Where the two plugins “com.freescale.deadlockPreventer.wrapper” and “javassist.wrapper” can be obtained from the following link(in the build/eclipse/plugins sub-folder):</p> <p><a title="https://github.com/sbeauchamp/Deadlock-Preventer/zipball/master" href="https://github.com/sbeauchamp/Deadlock-Preventer/zipball/master">https://github.com/sbeauchamp/Deadlock-Preventer/zipball/master</a></p> <p>The following java property can be specified to write the Deadlock Preventer output to a file:</p> <blockquote> <p><font face="Courier New">-Dcom.freescale.deadlockpreventer.logToFile=path-to\deadlock_preventer_output.log</font></p> </blockquote> <p>Alternatively, the output can be re-directed to the standard output with the following property:</p> <blockquote> <p><font face="Courier New">-Dcom.freescale.deadlockpreventer.logToStream=out</font></p> </blockquote> <p>or </p> <blockquote> <p><font face="Courier New">-Dcom.freescale.deadlockpreventer.logToStream=err</font></p> </blockquote> <p><strong>Memory Requirements</strong></p> <p>An important factor to keep in mind, is that running a java program with the Deadlock Preventer will cause all locks ever acquired to be referenced in memory by the analysis engine, so they will not be garbage collected for the life time of the program.</p> <p>This can cause some significant memory consumption increase, and may require the –Xmx flag to be passed to java to be increased.</p> <p>For example, running an eclipse.exe instance with the the Deadlock Preventer can increase its memory usage by several hundred MBs.</p> <p><strong>Running the Deadlock Preventer interactively</strong></p> <p>Another alternative to either running the Deadlock Preventer in the Eclipse workbench with the UI or running it in an automated build, is to use the built-in command line server/client.</p> <p>To start the server, the following command can be used:</p> <blockquote> <p><font face="Courier New">java –cp path-to\com.freescale.deadlockPreventer.wrapper_1.0.0\com.freescale.deadlockpreventer.jar com.freescale.deadlockpreventer.ConsoleNetworkServer 43537</font></p> </blockquote> <p>The last argument is the port number of the server, which can be omitted, in which case the default port will be used, 43537.</p> <p>The following output will then appear to the command line:</p> <blockquote> <p><font face="Courier New">Server started on port: 43537 <br />services: <br />  report: report.2 <br />  query: query.1 <br />Type 'help' for a list of commands.</font></p> </blockquote> <p>This information can then be used to pass the following two properties to the java instance that is running the Deadlock Preventer (the one that is getting the –javagent flag):</p> <blockquote> <p><font face="Courier New">-Dcom.freescale.deadlockpreventer.reportService=localhost:43537:report.2 </font></p> <p><font face="Courier New">-Dcom.freescale.deadlockpreventer.queryService=localhost:43537:query.1</font></p> </blockquote> <p>Note that if the server is started on a different machine, the “localhost” string must be replaced by the IP address of the server.</p> <p>When the Deadlock Preventer is connected to the server, any inconsistent locking detected will be displayed on the server’s console interactively, so that the user can decide to continue, or abort the program.  The server console can also be used to query lock statistics with the following commands:</p> <blockquote> <p><strong>getLockCount</strong></p> <p>      Returns the number of locks in the program. <br /><strong>getDetails index end</strong></p> <p>      Return detailed information on the lock(s) from index to end (being numbers between 0 and the number of locks in the program) <br /><strong>getAll</strong></p> <p>      Return all lock information as output on the standard out stream <br /><strong>writeAll file-path</strong></p> <p>      Download all lock information and write the complete output in a file</p> </blockquote> <p>Note that downloading lock statistics can require quite a lot of memory and bandwidth (several hundred MBs for an eclipse workbench, for example).</p> Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com4tag:blogger.com,1999:blog-4308054958627207530.post-24303863498451993062010-12-06T14:13:00.001-08:002010-12-06T14:45:20.374-08:00Freescale's Deadlock Preventer is now released!<div> </div> <div>To try it out:</div> <div> </div> <div> <ol> <li>Be sure to have an Eclipse 3.6.1 SDK layout, and using JDK 1.6 as your default JRE (jdk 1.7 doesn't work yet)</li> <li><a href="http://help.github.com/win-git-installation/">Install Git</a></li> <li><a href="http://help.github.com/git-email-settings">Set your user and email in Git</a></li> <li>Type in the shell (cygwin on windows):</li> </ol> </div> <div><b><span style="white-space: pre" class="Apple-tab-span"> </span>git clone git@github.com:sbeauchamp/Deadlock-Preventer.git</b></div> <div><span style="white-space: pre" class="Apple-tab-span"> </span></div> <div>This will create a directory on your file system containing all the deadlock preventer plugins.</div> <div> </div> <div>If you simply want to run the deadlock preventer tool, get the 4 plugins under</div> <div><span style="white-space: pre" class="Apple-tab-span"> </span></div> <div><b><span style="white-space: pre" class="Apple-tab-span"> </span>./Deadlock-Preventer/build/eclipse/plugins/</b></div> <div><span style="white-space: pre" class="Apple-tab-span"> </span></div> <div>And copy them in the eclipse/dropins of your eclipse directory:</div> <div> </div> <div>You will see that a new view is available from "Other/Deadlock Preventer".</div> <div> <br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/TP1gmIMLX9I/AAAAAAAAADc/mVoOJjLNfJU/s1600/screen_deadlock.JPG"><img style="text-align: center; margin: 0px auto 10px; width: 227px; display: block; height: 320px; cursor: hand" id="BLOGGER_PHOTO_ID_5547696524140175314" border="0" alt="alt" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/TP1gmIMLX9I/AAAAAAAAADc/mVoOJjLNfJU/s320/screen_deadlock.JPG" /></a></div> <div>The easiest way to try is out is to create a new java project, with the following sample code in Main.java:</div> <div> </div> <div> <div></div> </div> <blockquote> <div> <div><span style="font-family:Courier New;">public class Main {</span></div> <div><span style="white-space: pre" class="Apple-tab-span"><span style="font-family:Courier New;"> </span></span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>public static void main(String[] args) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>new Main().test();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="white-space: pre" class="Apple-tab-span"><span style="font-family:Courier New;"> </span></span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>Object lock = new Object();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>Object lock2 = new Object();</span></div> <div><span style="white-space: pre" class="Apple-tab-span"><span style="font-family:Courier New;"> </span></span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>private void test() {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>synchronized(lock) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>synchronized(lock2) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>code();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>Thread thread = new Thread(new Runnable() {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>public void run() {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>synchronized(lock2) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>synchronized(lock) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>code();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>});</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>thread.start();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>try {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>thread.join();</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>} catch (InterruptedException e1) {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;"></span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>private void code() {</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>System.out.println("test");</span></div> <div><span style="font-family:Courier New;"><span style="white-space: pre" class="Apple-tab-span"> </span>}</span></div> <div><span style="font-family:Courier New;">}</span></div> </div> <div></div> </blockquote> <div>Then create a new launch configuration to run the program. The new configuration will automatically appear in the combo box under the tab "Eclipse JDT Debugging" of the "Deadlock Preventer" view.</div> <div> </div> <div>Once you click "Debug" from that tab (using the "Run/Debug" menu does not have the same effect), the program runs with the deadlock preventer automatically instrumenting the byte code.</div> <div> </div> <div>You will then see the following error being reported:</div> <br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_xRUrqZpshsQ/TP1hgukHvNI/AAAAAAAAADk/FLOOwT8tiug/s1600/error.JPG"><img style="text-align: center; margin: 0px auto 10px; width: 400px; display: block; height: 56px; cursor: hand" id="BLOGGER_PHOTO_ID_5547697530873560274" border="0" alt="alt" src="http://1.bp.blogspot.com/_xRUrqZpshsQ/TP1hgukHvNI/AAAAAAAAADk/FLOOwT8tiug/s400/error.JPG" /></a>And if double-clicked the full information is displayed: <div> </div> <br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/TP1hxZyt8ZI/AAAAAAAAADs/my1j4H3YakY/s1600/error2.JPG"><img style="text-align: center; margin: 0px auto 10px; width: 400px; display: block; height: 158px; cursor: hand" id="BLOGGER_PHOTO_ID_5547697817355415954" border="0" alt="alt" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/TP1hxZyt8ZI/AAAAAAAAADs/my1j4H3YakY/s400/error2.JPG" /></a> <br /> <div>By setting a breakpoint on "RuntimeException"s and using the 'Interactive' or “throw exception" mode, you are able to break in the debugger at the exact point where the inconsistent locking order is detected.</div> <div> </div> <div>This should be enough to get your started with using the deadlock preventer, and investigating potential deadlocks in your programs.</div> <div> </div> <div>In a next post, I will post the different options and runtime settings of the deadlock preventer including those useful to integrate it in a release engineering process.</div> <div> </div> <div>P.S. I <a href="https://www.eclipsecon.org/submissions/2011/view_talk.php?id=2200&search=deadlock">submitted a talk</a> to <a href="http://www.eclipsecon.org/2011/">EclipseCon 2011</a> on the deadlock preventer and using it to prevent deadlocks in Eclipse plugins. Please drop a comment in the submission if you think it would be an interesting talk.</div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com5tag:blogger.com,1999:blog-4308054958627207530.post-1475543410784370432010-11-30T02:06:00.000-08:002010-11-30T05:21:05.813-08:00How to Debug and Detect Deadlocks<p><strong><font size="3">Deadlocks in 2 minutes</font></strong></p> <p>Deadlocks are software bugs where multiple threads (typically one of them being the main thread) wait indefinitely on common synchronization primitives (locks) because their resolution is mutually interdependent.</p> <p>Thread A waits on lock L1 to be released, but it held by thread B, who in turns waits on lock L2 to be released while it is held by thread A.</p> <p>The scenario above is by far the most common source of deadlocks. The fundamental cause is that the locks are acquired in a different order by two different threads, and depending on an unpredictable race condition, can deadlock at runtime.</p> <p>For example, the following snippet can cause a deadlock when Property.get() and Property.set() are accessed by two different threads: <br /></p> <blockquote> <p><font face="Courier New">class Property { <br />    static final public String DEFAULT_VALUE = "..."; <br />    HashMap map = new HashMap(); <br />    ArrayList listeners = new ArrayList();</font></p> <p><font face="Courier New">    synchronized void set(String key, String value) { <br />        synchronized (map) { <br />            map.put(key, value); <br />        } <br />        for (Listener listener : listeners) <br />            listener.notifyChanged(); <br />    }</font></p> <p><font face="Courier New">    String get(String key) { <br />        synchronized (map) { <br />            String value = map.get(key); <br />            if (value == null) { <br />                value = DEFAULT_VALUE; <br />                set(key, value); <br />            } <br />            return value; <br />        } <br />    } <br />}</font></p> </blockquote> <p>When the method <font face="Courier New">Property.set()</font> is called, the lock for "this" and "map" are acquired (using the <em>synchronized</em> keyword), while when <font face="Courier New">Property.get()</font> is called, the locks "map" and "this" are acquired, in the opposite order than <font face="Courier New">Property.set()</font>.</p> <p>This can cause a random deadlock when Property.get() and Property.set() are called from two different threads.</p> <p>The example illustrate that:</p> <ol> <li>It is easy to write code that has incorrect lock acquisition order. </li> <li>It is hard to detect such errors, until a deadlock occurs randomly at runtime, and it might not be consistently reproducible. </li> </ol> <p>Considering large source base where thousand of line of code acquire locks and have a very complex code path, it is often nearly impossible to prevent deadlocks from occurring at runtime, at the developer are faced with reducing the concurrency of the software, leading to poor usability, and sub-optimal performance.</p> <p>Here is where the deadlock preventer tool comes to help.</p> <p> <br /><strong><font size="3">The Deadlock Preventer</font></strong></p> <p>The deadlock preventer is a tool that dynamically instruments the java bytecode of an application when running in a java virtual machine in order to analyze the lock ordering and detect potential deadlocks without the need to rely on unpredictable and unreliable race conditions.</p> <p>By running the deadlock preventer while executing the java program (the Eclipse IDE in our case) with a good code coverage (basically covering all features that the customers are susceptible to use), we can ensure that the code does not contain incorrect lock order, and is prone to deadlocks at runtime.</p> <p>When we run the Property class in the example above with the following junit test code: <br /></p> <blockquote> <p><font face="Courier New">@Test <br />public void testProperty() { <br />    final Property property = new Property(); <br />    Thread thread = new Thread(new Runnable() { <br />        @Override <br />        public void run() { <br />            property.get("foo"); <br />        } <br />    }); <br />    thread.start(); <br />    try { <br />        thread.join(); <br />    } catch (InterruptedException e) { <br />        e.printStackTrace(); <br />    } <br />    try { <br />        property.set("bar", "value"); <br />        fail("should throw an exception"); <br />    } catch (RuntimeException e) { <br />        assertTrue(e.getMessage().contains("ERROR")); <br />    } <br />}</font></p> </blockquote> <p>We obtain a <font face="Courier New">RuntimeException</font> (as validated by the junit test case - something optional for the deadlock preventer to issue), but also the following error report on the console:</p> <blockquote> <p><font face="Courier New">***DEADLOCK PREVENTER*** ERROR: Inconsistent locking order while acquiring lock: java.util.HashMap (id=0) in thread: 1 (main) <br />Property.set(Main.java:812) <br />Main.testProperty(Main.java:38) <br />... <br />(junit stack) <br />with predecent : Property (id=1) <br />Property.set(Main.java:811) <br />Main.testProperty(Main.java:38) <br />... <br />(junit stack) <br />Previously acquired lock: java.util.HashMap (id=0) in thread: 9 (Thread-0) <br />Property.get(Main.java:818) <br />Main$1.run(Main.java:28) <br />java.lang.Thread.run(Thread.java:619) <br />Previously acquired precedent: Property (id=1) <br />Property.set(Main.java:811) <br />Property.get(Main.java:822) <br />Main$1.run(Main.java:28) <br />java.lang.Thread.run(Thread.java:619) <br /></font></p> </blockquote> <p>The important aspect is that we receive this error report deterministically, each time the code runs, whether or not the code actually deadlocks at runtime given a race condition (something we made impossible with the thread.join() call).</p> <p>Once the error is detected, it can then be corrected by the developer. <br /></p> <p>Note also that the deadlock preventer will report the error whether or not the code is actually susceptible to run concurrently or not, which in our case was impossible because we made the main thread block until the second thread finished execution (something that defeats the purpose to have a separate thread to begin with).</p> <p>The deadlock preventer can also issue warnings when an inverse lock acquisition is detected in the same thread, but never run in different thread - it is always a good programming practice to have consistent lock order.</p> <p>Using the deadlock preventer agent in a java program does not change any of the application logic and code path, but it does change its performance characteristics. Specifically, acquiring and releasing locks become computationally expensive. Ricks of actual deadlocks are effectively increased too, since the time spent while an incorrect lock acquisition order is progress is longer, especially if the 'Interactive' setting is used (see below).</p> <p>Therefor, if the java program deadlocks, the last conflict reported by the deadlock preventer agent will be the out that refers to the deadlock obtained. <br /></p> <p><strong><font size="3">Using the Deadlock Preventer Agent</font></strong></p> <p>The deadlock preventer agent is available in two forms for two different development role.</p> <ol> <li>As a set of eclipse plugins for developers to test existing code, and investigate potential deadlocks. </li> <li>As a standalone launcher for testers, to run on a test machine in the background while the Eclipse Workbench is performing automated tests. </li> </ol> <p><font size="3"><strong>The Deadlock Preventer Eclipse integration.</strong></font></p> <p align="center"><font size="3"><strong></strong><a href="http://lh3.ggpht.com/_xRUrqZpshsQ/TPTd-TmJSCI/AAAAAAAAADU/gr9NR9CoGLw/s1600-h/agent_view%5B5%5D.png"><img style="background-image: none; border-right-width: 0px; margin: ; 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="agent_view" border="0" alt="agent_view" src="http://lh4.ggpht.com/_xRUrqZpshsQ/TPTd_3uMEcI/AAAAAAAAADY/i7pr2SNZL_k/agent_view_thumb%5B3%5D.png?imgmax=800" width="418" height="445" /></a></font></p> <p>The deadlock preventer Eclipse integration consist of 3 plugins that contribute a new view in eclipse, as shown above (the view is accessible from the menu "Menu / Show View/Other..." under the "Other/Deadlock Preventer" section).</p> <p>The Deadlock Preventer view allows the developer to select an existing launch configuration (only launch configurations for "Eclipse Application" as listed), configure settings, and click "Debug". The debugged Eclipse session will be automatically instrumented, and report any error in the view, under the "Conflicts" tab.</p> <p>The best way to use the tool for an Eclipse developer, is first to add a breakpoint on the RuntimeException, then use the 'Interactive' mode, which allows to skip over some errors that are not of interest, and throw an exception for the relevant one.</p> <p>Important: Note that if the 'throw exception' mode is selected, it will cause the code path to divert from the normal execution path, so it could cause sub-sequent errors, and bugs that would not otherwise happen.</p> <p><font size="3"><strong>Correcting incorrect lock acquisition order</strong></font></p> <p>Generally speaking, when two locks (A, B) are acquired in an inverse order by two different code paths susceptible to be called concurrently (i.e. by two different threads), a deadlock can occur.</p> <p>For example, if thread 1 acquires the locks A and then B, while thread 2 acquires the locks B and then A, a deadlock is possible.</p> <p>Thread 1: A -> B</p> <p>Thread 2: B -> A</p> <p>There are only 2 ways to avoid the problem:</p> <ol> <li>Re-order the lock acquisition, so that both threads acquire the locks in the same order </li> </ol> <p>or</p> <ol> <li>Introduce a third lock, C, and make both threads acquire it before acquiring either A or B. </li> </ol> <p>In the last case, the pattern would become:</p> <p>Thread 1: C-> A –> B</p> <p>Thread 2: C-> B -> A</p> <p>The lock "C" would be in effect a "guard", preventing the locks A and B to be acquired concurrently, and avoiding the deadlock. The deadlock preventer agent recognize such patterns, and do not report any errors.</p> <p>Obviously, the first solution is optimal, since it does not reduce concurrency as the second does, but it is sometimes impractical to re-order lock acquisition order, especially when access or modification of existing code is not possible.</p> <p>Needless to say, removing (even partially) the locks is probably not a good solution, since the deadlock preventer agent does not report data corruption due to concurrent data access.</p> <p><font size="3"><strong>Miscellaneous comments</strong></font></p> <p>Running a full instrumented Eclipse workbench while the deadlock preventer agent analyzes the lock acquisition order, especially through the debugger, is demanding in computational resources. A recent (preferably 4 core or more) CPU is highly recommended. </p> <p> <br />Not all causes of deadlocks are detected at the moment by the deadlock preventer engine, such as Semaphore release leaks, or async execution from a background thread to the main thread. </p> <p><em>(source code of the deadlock preventer to be posted within a few days)</em></p> Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com7tag:blogger.com,1999:blog-4308054958627207530.post-34073688609881811512010-04-16T12:20:00.000-07:002010-04-16T12:40:54.218-07:00Use the new Resource Filters in 3.6M7 and JDK 1.7 to simulate snapshotsSuppose you are working in a project in Eclipse, but after updating from your source control server, new files were populated in your workspace that cause some build errors. <div><br /></div><div>How to continue to work in your project without being temporarily distracted by the newly created files?</div><div><br /></div><div>In Eclipse 3.6, <a href="http://download.eclipse.org/eclipse/downloads/">Helios</a>, some new powerful features were added to the Eclipse project management that allows the users to configure exactly what files get to populate a project hierarchy.</div><div><br /></div><div>By using the new Resource Filter feature (improved in M7), the user can either include only or exclude all files based on a rich set of configurable and extensible filters.</div><div><br /></div><div>When running on JDK 1.7, another condition is available for filtering, the file<i> creation date</i>.</div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_xRUrqZpshsQ/S8i7t3VTUGI/AAAAAAAAAC8/7OgbG5e1Y5g/s1600/Screen+shot+2010-04-16+at+8.20.14+PM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 329px;" src="http://1.bp.blogspot.com/_xRUrqZpshsQ/S8i7t3VTUGI/AAAAAAAAAC8/7OgbG5e1Y5g/s400/Screen+shot+2010-04-16+at+8.20.14+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5460820944808530018" /></a>By creating a resource filter that excludes all files having a creation date newer than a given date, you can prevent those files from even appearing in the workspace, so they not be seen by JDT and generate build errors.<div><br /></div><div>The condition for filtering files and folders are broad, including file name, location, workspace path, last modified, file length, etc... The user can also group those condition in logical prepositions with <i>and</i>, <i>or</i>, and <i>not</i> operators.</div><div><br /></div><div>3rd party plugins can even contribute new matchers through a core.resources extension point to further extend the filtering ability available to the user (think filtering by CVS status, etc...).</div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-1827595107203392042010-03-31T01:48:00.000-07:002010-03-31T01:54:52.117-07:00Tip: How to Debug SWT components in Modal Dialogs<!--StartFragment--><p> SWT and JFace components, and especially layouts can be quite time consuming to debug when some unexpected behavior is observed at runtime. </p><p>Some tools (such as the <a href="http://marketplace.eclipse.org/node/901">YARI</a> tool set) can be used to debug SWT components and layouts at runtime, but when modal dialogs are displayed, such tools can't be used because the developer can't setup the inspector window and inspect the components in the list while the dialog is up. </p><p> To resolve this issue, one can </p><p></p><ol><li>Detach the inspector view so it displays in a floating window outside of the workbench.</li><li>Put a breakpoint in the modal dialog source code, few lines after the setShellStyle() call, with a breakpoint condition so that it removes the MODAL SWT flag.</li></ol><p></p><p> </p><p> </p><p> For example, for making the <span class="twikiNewLink">WizardDialog</span> non modal, a breakpoint with the following condition:</p><pre> setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER </pre><pre> | SWT.RESIZE | getDefaultOrientation()); </pre><pre> return false; </pre> <p> needs to be added to the "setWizard(newWizard)" line below:</p><p> </p><pre> public WizardDialog(Shell parentShell, IWizard newWizard) {</pre><pre> super(parentShell); </pre><pre> setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER</pre><pre> | SWT.APPLICATION_MODAL | SWT.RESIZE | getDefaultOrientation());</pre><pre> setWizard(newWizard); </pre> <p> This way, you will be able to debug the SWT components at runtime even in modal dialogs:</p><p><br /></p><!--EndFragment--><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/S7MNnb2XveI/AAAAAAAAAC0/Wj4TdYI2__s/s1600/Screen+shot+2010-03-30+at+9.45.10+PM.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 238px;" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/S7MNnb2XveI/AAAAAAAAAC0/Wj4TdYI2__s/s400/Screen+shot+2010-03-30+at+9.45.10+PM.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5454718544817667554" /></a>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com3tag:blogger.com,1999:blog-4308054958627207530.post-45973661177274324212009-04-01T10:23:00.000-07:002009-04-01T12:07:01.843-07:00EclipseCon last week was quite rewarding. The talks were great and finally being able to meet face to face with the people I've been collaborating with for the last year is priceless.<div><br /></div><div>Here's a video I made of the talk I gave on Tuesday about the e4 project file structure improvements:</div><br /><object width="660" height="525"><param name="movie" value="http://www.youtube.com/v/NuPZKZmAPFY&hl=en&fs=1&border=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/NuPZKZmAPFY&hl=en&fs=1&border=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="660" height="525"></embed></object><br /><object width="660" height="525"><param name="movie" value="http://www.youtube.com/v/4fXbsLDSUAY&hl=en&fs=1&border=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/4fXbsLDSUAY&hl=en&fs=1&border=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="660" height="525"></embed></object><div>Note that the format isn't ideal, since it contains screenshots that are hard to read in the youtube format.</div><div><br /></div><div>The slides (without audio) are available below (best seen in full screen mode):</div><div><br /></div><br /><div style="width:425px;text-align:left" id="__ss_1198736"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/sergebeauchamp/project-file-structure-and-core-resources-changes-in-e4?type=presentation" title="Project File Structure and Core Resources changes in e4">Project File Structure and Core Resources changes in e4</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eclipsecon200908-090325174314-phpapp01&stripped_title=project-file-structure-and-core-resources-changes-in-e4"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eclipsecon200908-090325174314-phpapp01&stripped_title=project-file-structure-and-core-resources-changes-in-e4" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/sergebeauchamp">sergebeauchamp</a>.</div></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-55484533410095803072009-02-02T04:21:00.000-08:002009-02-02T04:31:46.531-08:00Hello to Planet EclipseHello all Planet Eclipse readers :)<div><br /></div><div>My blog has just been included today, so I'd like to say two words to introduce myself.</div><div><br /></div><div>I've been working for Metrowerks/Motorola now Freescale since the old days of CodeWarrior on the C/C++ IDE, and with Eclipse since we switched to Eclipse in 2005-2006.</div><div><br /></div><div>I'm interested in a lot of different components in Eclipse that helps it be a great C/C++ IDE for our customers, and have been especially involved lately in the e4 project (where I am a committer) to bring improvements to the Core Resources plugin so that it can now brag to be more powerful and feature complete than the old CW IDE or Visual Studio - at least in terms of project file structure :)</div><div><br /></div><div>You can see more of my recents posts in the following links:</div><div><br /></div><div><a href="http://sergebeauchamp.blogspot.com/2009/01/latest-e4-resource-changes.html">Latest e4 resource changes</a></div><div><a href="http://sergebeauchamp.blogspot.com/2008/10/new-resource-filters-for-eclipse-core.html">New Resource Filters for the Core Resources</a></div><div><a href="http://sergebeauchamp.blogspot.com/2008/09/improving-linked-resources-in-gandymede.html">Improving Core Resources in Ganymede</a></div><div><br /></div><div>I will give a <a href="http://www.eclipsecon.org/2009/sessions?id=277">short talk</a> at EclipseCon 2009, so I hope to see a lot of you there, thanks! :)</div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com3tag:blogger.com,1999:blog-4308054958627207530.post-88651490338901496162009-01-30T02:21:00.000-08:002009-01-30T09:28:11.010-08:00Latest e4 resource changes<div>Here is an overview of the changes in the e4 resources available in the <a href="http://download.eclipse.org/e4/downloads/drops/I20090129-1930/index.html">latest e4 build</a>:<br /></div><div><br /></div><div><ol><li><span class="Apple-style-span" style="font-weight: bold;">Editable linked resource locations</span>.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/SYLnPcfMsuI/AAAAAAAAAB4/y-98l88hrHk/s1600-h/EditVariables.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 242px;" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/SYLnPcfMsuI/AAAAAAAAAB4/y-98l88hrHk/s320/EditVariables.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5297050364272227042" /></a><br />The user can now conveniently change the location of a linked resource by clicking the "Edit..." button in the resource property page.</li><br /><li><span class="Apple-style-span" style="font-weight: bold;">Project Linked Resource Variables</span><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLp78EDiKI/AAAAAAAAACA/l1SMcjqaGAM/s1600-h/projectPathVariables.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 194px;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLp78EDiKI/AAAAAAAAACA/l1SMcjqaGAM/s320/projectPathVariables.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5297053327685814434" /></a><br />Linked resources that are variable relative can now use a variable list that is defined in the project itself, instead of only relying on the workspace variables. The linked resources can also be specified as relative to the project directory itself, making projects referencing other files outside of the project directory portable across workspace and computers.<br /></li><br /><li><span class="Apple-style-span" style="font-weight: bold;">Groups</span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLt4QSdkjI/AAAAAAAAACI/K04QiZox5wU/s1600-h/groups.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 213px;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLt4QSdkjI/AAAAAAAAACI/K04QiZox5wU/s320/groups.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5297057662441984562" /></a><br />Groups are virtual folders that the user can use to create an arbitrarily complex logical project independent of the file system hierarchy.<br /><br />Groups, as opposed to regular folders, do not exist on the file system and therefor a) do not pickup any additional resources underneath them when a refreshLocal() is performed, and b) can only contain other groups or linked resources as children.<br /><br />Groups are fully compatible with the existing 3.4 Core Resource API, and all plugins work just as expected. Groups are seen internally by clients as an linked resource folder with an invalid location (that returns null from getLocation()).<br /></li><br /><li><span class="Apple-style-span" style="font-weight: bold;">Resource Filters</span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLxNvMgcQI/AAAAAAAAACQ/qBz59B5W8Ak/s1600-h/filters.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 187px;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYLxNvMgcQI/AAAAAAAAACQ/qBz59B5W8Ak/s320/filters.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5297061330050642178" /></a><br />Resource filters can be added on any project, folder, linked resource folder or group to automatically build the project structure by limiting what files and folders are visible to the resource workspace layer when a refreshLocal() is performed.<br /><br />Resource filters is a powerful feature that allows an Eclipse project to include folders that contains thousands of elements, but only including a fraction of them in the project. As opposed to UI view filters, resource filters are applied at the lowest level, and do not cause resources to be wasted for elements excluded from the directory.<br /></li><br /><li><span class="Apple-style-span" style="font-weight: bold;">Drag and Drop auto-generation of linked resources</span><br /><p align="center"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dwVOMhRfizlsNuI2Yj-54x26ecnlZy2DdatecTiEJi13Ae0vTj52fxHS8RmVkC4A1ldM5rIibvq9wissmYHng' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />(A somewhat better version of the video is available <a href="http://www.youtube.com/watch?v=ej-diQ9ClV0">here</a>)</p><br /><br />When files are dragged and dropped from Windows Explorer on a projet in the Navigator, the user can choose either to <ol> <li>Copy the files under the target directory (the previous operation)</li> <li>Create a hierarchy of groups and linked resources replicating the file system file and folder hierarchy<</li> <li>Create only linked resources</li> </ol><br /> Linked resources can also be creating when dragging resources from one project to another, transparently transfering the path variables the linked resource might be referring to. <br /><br />Note that this linked-resource drag and drop awareness is currently only available to the Navigator view. </li><br /><li><span class="Apple-style-span" style="font-weight: bold;">Linked Resource Editor</span><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYM4iph_WAI/AAAAAAAAACY/mMQSRjJtD3I/s1600-h/Picture+6.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 210px;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SYM4iph_WAI/AAAAAAAAACY/mMQSRjJtD3I/s320/Picture+6.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5297139754632960002" /></a><br />Under the new Linked Resource project property page, a new Linked Resources tab is available. This tab shows a list of all resources in the project, and group them by their location path, being either invalid (for broken paths), absolute paths (which makes them non-portable) and correct paths.<br /><br />The user can then easily see which linked resource requires modification, and change it directly in the dialog by choosing the "Edit..." button.<br /><br />The user can also automatically convert one or many linked resources to absolute or relatives paths by clicking on the Convert Relative/Absolute button. This command will automatically generate linked resources if needed and try to make the path as portable as possible. </li></ol></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com2tag:blogger.com,1999:blog-4308054958627207530.post-38380800673383592452009-01-22T05:37:00.000-08:002009-01-23T08:45:13.813-08:00Flexible Project Improvements in e4Several improvements to the Core Resources have been made for e4.<div><br /></div><div><span class="Apple-style-span" style="font-weight: bold;">Installing the new build</span></div><div><span class="Apple-style-span" style="font-weight: bold;"><br /></span></div><div>In order to try them out, go to the following web site:</div><br /><a href="http://download.eclipse.org/e4/downloads/">http://download.eclipse.org/e4/downloads/</a><br /><div><br /></div><div>Select a recent build, and use the link under the "update" column to use in an Eclipse 3.5M4 installation in the UI available from the menu "Help | Install New Software ...".</div><div><br /></div><div>Once the "Install" dialog comes up, click on "Add Site..." and enter the update site you selected from the download page ( <a href="http://download.eclipse.org/e4/downloads/drops/I20090108-1930/repository">http://download.eclipse.org/e4/downloads/drops/I20090108-1930/repository</a> for example).</div><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_xRUrqZpshsQ/SXnz92sa7ZI/AAAAAAAAABw/3VdsFDfHaho/s1600-h/Picture+13.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 242px;" src="http://1.bp.blogspot.com/_xRUrqZpshsQ/SXnz92sa7ZI/AAAAAAAAABw/3VdsFDfHaho/s320/Picture+13.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5294531080930127250" /></a><br /></div><div>The list will refresh, and you can them select the item "org.eclipse.e4.resources.feature" and click "Next, "Finish", etc...</div><div><br /></div><div>This will enable all the current e4 Core Resources in the current 3.5M4 layout.</div><div><span class="Apple-style-span" style="font-style: italic;"><br /></span></div><div><span class="Apple-style-span" style="font-style: italic;">more to come...</span></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-35617966274074930852008-11-12T05:41:00.001-08:002008-11-12T05:43:44.441-08:00Updated Resource Filter UIHere is a screenshot of the Resource Filter updated UI, as discussed in the <a href="http://sergebeauchamp.blogspot.com/2008/11/resource-filter-ui.html">previous post</a>.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRrdLuY3DzI/AAAAAAAAABo/y_tXoI6sQ3Q/s1600-h/newUIShadow.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 234px;" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRrdLuY3DzI/AAAAAAAAABo/y_tXoI6sQ3Q/s320/newUIShadow.png" alt="" id="BLOGGER_PHOTO_ID_5267765907663818546" border="0" /></a>There is now support for OR, AND and NOT filter groups that allow the user to build arbitrarily complex logical propositions for filtering resources.Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-48996671342688236052008-11-07T08:33:00.001-08:002008-11-07T09:16:48.309-08:00Resource Filter UIAn update to the <a href="http://sergebeauchamp.blogspot.com/2008/10/new-resource-filters-for-eclipse-core.html">previous post</a>, I now included to the <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=252996">Resource Filter bug report a <span class="blsp-spelling-error" id="SPELLING_ERROR_0">UI</span></a> implementation.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRRuSoJtR8I/AAAAAAAAABY/-rDsZ9A5V8E/s1600-h/resource_filters.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 218px;" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRRuSoJtR8I/AAAAAAAAABY/-rDsZ9A5V8E/s320/resource_filters.png" alt="" id="BLOGGER_PHOTO_ID_5265955130597787586" border="0" /></a><br />The <span class="blsp-spelling-error" id="SPELLING_ERROR_1">UI</span> consist of a property page available when the user right clicks <span class="blsp-spelling-error" id="SPELLING_ERROR_2">IContainer</span> objects (basically folders, projects and linked resource folders), and allows him to add, edit, remove and reorder resource filters.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRRu2xfkphI/AAAAAAAAABg/HOiupVY0W40/s1600-h/edit_resource.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 222px;" src="http://2.bp.blogspot.com/_xRUrqZpshsQ/SRRu2xfkphI/AAAAAAAAABg/HOiupVY0W40/s320/edit_resource.png" alt="" id="BLOGGER_PHOTO_ID_5265955751580706322" border="0" /></a>The interface allows the user to choose which resource filter type (currently either a regular expression or a String Matcher), the mode ("Include Only" or "Exclude All"), the target ("Files", "Folders" or "Files and Folders" the filter type arguments, and finally whether it is inheritable to the container's children or not.<br /><br />Unless I'm mistaken, the result of the filter operation is always the same no matter the order of the filters (i.e. (A & B & !C == A & !C & B), so why allow the user to order them?<br /><br />The reason why filters can be reordered is <span class="blsp-spelling-corrected" id="SPELLING_ERROR_3">mainly</span> for performance reason, since one can imagine filter types that are slower than others (one that check for file content types, for instance), and it is more efficient to put faster filters first so the slower filters have a smaller set to iterate through.<br /><br />A side note, an interesting test is to put an "Exclude all" filter for files and folders matching "*" on a project itself: Will it cause the ".project" file to be filtered out as well? Thankfully, it doesn't, since the code path to <span class="blsp-spelling-corrected" id="SPELLING_ERROR_4">retrieve</span> the ".project" file is different than the regular local refresh. So the project still opens fine, although it is indeed an extreme case.Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-32303199175911072072008-10-31T09:27:00.000-07:002008-11-07T08:56:18.256-08:00New Resource Filters for the Eclipse Core ResourcesOur customers have to work with large source trees, where creating projects with those trees can be cumbersome.<br /><br />Often the user wants to deal only with a subset of files in those hierarchies, but each file system object gets created an a resource in the resource tree and causes performance and scalability problems.<br /><br />To address those limitations, we implemented the "Resource Filter" feature which we provided a patch to the core.resources <span class="blsp-spelling-error" id="SPELLING_ERROR_0">plugin</span> today (<span class="blsp-spelling-error" id="SPELLING_ERROR_1">UI</span> to come shortly).<div><br /></div><div>With this feature, the Core Resources <span class="blsp-spelling-error" id="SPELLING_ERROR_2">plugin</span> now support adding resource filters onto <span class="blsp-spelling-error" id="SPELLING_ERROR_3">IFolder</span> objects that limits at a low level which file system objects are available to the resource tree so that large source trees can scale easily when filters are used.<br /><br />How does it work:<br /><ul><br /><li> The .project file now contains <filteredresource> tags that specify which filters exist on which folder.<br /></filteredresource></li><li> A folder can contain a list of Filters (from 0 to n)<il><br /></il></li><li>Filters can be optionally "inheritable", in which case they apply not only to the folder's children, but also to it's sub-folder children as well.</li><li> Each filter has the following attributes:<br /><ol><br /><li>The project relative path of the folder it applies.</li><br /><li>The id of the filter type provider (ex: "org.eclipse.core.resources.regexFilterProvider").</li><br /><li>The arguments of the filter. This is filter dependent. (ex: ".*\.c") </li><br /><li>The filter type. This is a integer that can contain any of the following flags:<br /><ul><br /><li>Filters can be set to include only files or folders matching a criteria, or exclude all file and folders matching a criteria. The two following flags choose between the two modes:<br /><br />public static final int INCLUDE_ONLY = 1;<br />public static final int EXCLUDE_ALL = 2;<br /><br />Note that multiple filters on the same folder can be of a mix of "include_only" and "exclude_all" types.<br /></li><br /><li>Filters can be applicable to files or folders or both, the following flags indicate the preference:<br /><br />public static final int FILES = 4;<br />public static final int FOLDERS= 8;<br /></li><br /><li>Filters can be inheritable to sub-folders, the following flag indicate that:<br /><br />public static final int INHERITABLE = 16;<br /></li> </ul> </li> </ol><br />Note that all those flags are declared in the org.eclipse.core.resources.IFilter interface.<br /></li></ul><br />Something important to realize is that only real files that are located under a folder and appear in the workspace tree by a local refresh can be filtered out. Linked resource explicitly added under a folder still appear no matter what filters are put.<br /><br />This is by design, since linked resources and resource filters are complementary to each other. Where linked resources allow the user to build the project structure by <span class="blsp-spelling-corrected" id="SPELLING_ERROR_4">explicitly</span> including files and folders, resource filters allows the user to build the project structure by explicitly <span class="blsp-spelling-corrected" id="SPELLING_ERROR_5">excluding</span> files and folders.<br /><br />One practical thing to do, though, is to put resource filters on linked resource folders, which work perfectly.<br /><br />Some interesting behavior:<br /><ul><li>If the user creates a new file from the "File | New..." wizard that is actually filtered out by its parent resource filters, it will show up just after creation, but it will disappear from the resource tree when the user manually refreshes the view. I believe this is the proper behavior.</li><br /><li>Deleting folders that contain filtered out children work as expected (hidden children are deleted with their parent), but might cause the user to delete files that he's not aware are present on the file system. This should be addressed by the <span class="blsp-spelling-error" id="SPELLING_ERROR_6">UI</span> showing a warning in such case.</li><br /><li>Copying folders that have filters is interesting. While the filters get applied to the destination folder, only the visible objects are copied, which may or may not be what the user expects. Again, this issue should be resolved by having a <span class="blsp-spelling-error" id="SPELLING_ERROR_7">UI</span> giving the user the option (or at least the information) about what will happen</li><br /><li>Moving folders with filters, on the other hand, moves the whole content, including the hidden files invisible from the resource tree. This is because the move operation moves the underlying directory, and then copy the resource tree. The filters are moved as expected as well.</li></ul><br />How to try it out:<br /><ol><li>Get the patch from:<br /><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=252996">https://bugs.eclipse.org/bugs/show_bug.cgi?id=252996</a><br /><br /></li><li>Apply the patch to the org.eclipse.core.resources project.</li><br /><li>Import the test project provided in this patch. The project contains two filters:<br /><ul><li>One filter on "folder" which "includes only" all files ending with ".c" (and is inheritable)</li><li>Another filter on "folder/sub_folder" that "excludes all" files matching "output.c".</li></ul> </li><br /><li>Observe that the following objects are hidden from the resource tree:<br /><ul><br /><li>"folder/foo.h" (the include_only *.c filter on "folder")</li><br /><li>"folder/bar.h" (the include_only *.c filter on "folder")</li><br /><li>"folder/sub_folder/file.h" (the inherited include_only *.c filter on "folder")</li><br /><li>"folder/sub_folder/output.c" (the exclude_all "output.c" on "sub_folder")</li><br /></ul></li></ol><br /></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-91570765458258850062008-09-25T05:09:00.000-07:002008-09-25T12:12:54.898-07:00Drag and Drop Improvements in EclipseOne feature that IDE users are accustomed to is dragging files from Windows Explorer and dropping them on the application window to have them handled by that app.<br /><br />With the 3.3 Platform, Eclipse added the "Editor area drag and drop" functionality, which aims at implementing this feature.<br /><br />Unfortunately, there is still some limitations that need to be overcome to handle how users expect a native application to behave.<br /><h4>Handling files that open with external editors</h4>The first thing that the user can notice about Eclipe's handling of dropped files is that for some file types dropped onto the workbench, external editors are launched to open the file type instead of Eclipse itself.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SNuTuITt8EI/AAAAAAAAABA/A0FcNitnuV0/s1600-h/drag_and_drop_promt.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SNuTuITt8EI/AAAAAAAAABA/A0FcNitnuV0/s400/drag_and_drop_promt.png" alt="" id="BLOGGER_PHOTO_ID_5249952211343896642" border="0" /></a><br /><div>The most obvious example is when the user drags and drops a .bat file in the Eclipse workbench.<br /><br />Instead of editing the content of the file in a text editor, as the user would expect, Eclipse actually launches the .bat file in a Windows command prompt, mimicking the same behavior as if the user double-clicked it in the navigator pane.<br /><br />This is very inconsistent, since if the same file is dragged not from Windows Explorer but from an Eclipse project and dropped on the same editor, the .bat file is now properly open in an editor window instead of being launched in a command prompt.<br /><br />This issue doesn't only affect .bat files, but all files that map to a system editor in Eclipse.<br /><br />If the user wanted to simply have Windows to handle the .bat file and not Eclipse, he would have simply double-clicked it, and not took the effort to drop it on top of the Eclipse workbench.<br /><br />Obviously, Eclipse doesn't do what user expect with those kind of files.<br /><h4>Lack of extensibility<br /></h4>Drag and dropping files in an Eclipse workbench demonstrate the general intent of the user to have Eclipse handle that file.<br /><br />For some files, that may coincide with opening them in the editor, but with other files, Eclipse <span style="font-style: italic;">handling</span> of the file may mean something very different.<br /><br />For example, dropping an Eclipse project directory on the Eclipse workbench demonstrate that the user doesn't want to edit the folder, but import the project in the current workspace. The same is most likely with <span style="font-style: italic;">.project </span>files as well.<br /><br />Note that since the user can't currently double-click the <span style="font-style: italic;">.project</span> file in Windows explorer and have Eclipse be open and handle the project, this is the only way he can have to conveniently import projects without having to go through the import wizard.<br /><br />By dropping a<span style="font-style: italic;"> .mcp</span> or <span style="font-style: italic;">.vcproj </span>file on the Eclipse workbench, the user demonstrate his intent of having those CodeWarrior and Visual Studio projects be imported in Eclipse, preferably by having a wizard come up.<br /><br />Another thing that is typical for C/C++ IDE is dropping an executable on the IDE in order to start a debugging session for that executable.<br /><br />In all those case, the expected Eclipse behavior by the user is different from what he would expect if he double-clicked the same files in the Eclipse navigator (in which case, he would expect to expand the project directory, to launch CodeWarrior or Visual Studio, and to run the executable respectively).<br /><br />All those features are impossible to implement with the current Drag and Drop feature which is not extensible.<br /><h4> Our improvements to the Editor area Drag and Drop feature.</h4>In order to overcome the limitations mentioned above, we made the following improvements in the Editor area drag and drop feature:<br /><br /><ol><li>We extended the drop target for the general drag and drop workbench mechanism. Since the Eclipse workbench in general should handle file and folders dropped from Windows Explorer, the user can now use the top part of the Eclipse Workbench window to drop files.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_xRUrqZpshsQ/SNuaBVusmXI/AAAAAAAAABI/NNmVxm_uAzw/s1600-h/new_drop_zone.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_xRUrqZpshsQ/SNuaBVusmXI/AAAAAAAAABI/NNmVxm_uAzw/s400/new_drop_zone.png" alt="" id="BLOGGER_PHOTO_ID_5249959138433997170" border="0" /></a><br />Note that we wanted to include the top most section of the workbench window, but we couldn't find a way to include it without including the whole shell at the same time.</li><li>We added the <code>org.eclipse.ui.ide.dropHandler</code> extension point to allow a flexible implementation and resolution of the handling of files and folders dropped on the Eclipse workbench (see more details below).</li><li>We provided default dropHandlers to handle files in a proper way (without resorting to external editors) and to handle project directories and .project files by importing the project in the current workspace.</li><li>We provided a conflict resolution mechanism that detects when two or more handlers declare supporting the same file and let the user choose between them in a convenient dialog.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_xRUrqZpshsQ/SNuds28bv4I/AAAAAAAAABQ/p-1aWhNu3zA/s1600-h/dropConflict.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_xRUrqZpshsQ/SNuds28bv4I/AAAAAAAAABQ/p-1aWhNu3zA/s400/dropConflict.png" alt="" id="BLOGGER_PHOTO_ID_5249963184619241346" border="0" /></a></li></ol><h4>Algorithm and Extensibility API</h4>The general workbench Drop Handler algorithm relies solely on the dropHandler extensions to be able to handle dropped files and folders on the Eclipse workbench.<br /><br />Each handler must have the following attributes:<br /><ul><li>A user visible name</li><li>An icon</li><li>A handler class, implementing the IDropHandler interface (as described below)</li><li>A unique string ID.</li><li>A set of rules determining if a given file or folder is supported by the DropHandler.<br /></li></ul>The rules can be any combination of the following:<br /><ol><li>An inspector class, implementing the IDropHandlerInspector</li><li>Any number of typenames, which consist of the type of the object (file or directory) along with a regex pattern for the file name (such as "\.project").</li><li>Any number of file extensions, which consist of a pattern matching a file extension, such as "txt".</li><li>Any number of content types, which consist of the Eclipse content type IDs used in the Platform ContentTypeManager.</li><li>A lastInspector class implementing the IDropHandlerInspector as well.</li></ol>When a file or folder is dropped on the Eclipse workbench, the workbench drop feature will iterate through all inspectors for all existing dropHandlers. If one inspector matches the file or folder, its handler class will be used to handle the file or folder and the matching process will end.<br /><br />If no matching inspectors are found, all typenames will be tested, then all extensions, followed by all content types and finally all lastInspectors.<br /><br />If two or more dropHandlers are found matching for the same rule level, the Conflict Resolution dialog will be displayed to the user to know which dropHandler to choose, unless a precedence already has been recorded by the user.<br /><br />The following is an example of a Project Handler extension point:<br /><br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><extension point="<span style="color:magenta;">org.eclipse.ui.ide.dropHandler</span>"><br /> <handler <span style="color:blue;">class</span>="<span style="color:magenta;">org.eclipse.ui.internal.ide.dnd.ProjectDropHandler</span>"<br /> icon="<span style="color:magenta;">icons/full/obj16/prj_obj.gif</span>"<br /> id="<span style="color:magenta;">org.eclipse.ui.ide.dnd.ProjectDropHandler</span>"<br /> name="<span style="color:magenta;">%DropHandlers.ProjectDropHandler</span>"><br /> <inspector <span style="color:blue;">class</span>="<span style="color:magenta;">org.eclipse.ui.internal.ide.dnd.ProjectDropHandler</span>"><br /> </inspector><br /> <typeName name="<span style="color:magenta;">\.project</span>"<br /> type="<span style="color:magenta;">file</span>"><br /> </typeName><br /> </handler><br /></extension><br /></pre>The IDropHandler interface is defined as follows:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><span style="color:blue;">package</span> <span style="color:olive;">org</span>.eclipse.ui.ide.<span style="color:olive;">dnd</span>;<br /><br /><span style="color:blue;">import</span> <span style="color:olive;">org</span>.eclipse.core.runtime.IPath;<br /><br /><span style="color:green;">/**<br />* Interface implemented by a dropSupport extension point to<br />* handle a file or folder dropped on the workbench.<br />*<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">interface</span> IDropHandler {<br /><br /> <span style="color:green;">/** Handles a dropped file or folder on top of the workbench.<br /> * @param path The full absolute path of the file or folder dropped.<br /> */</span><br /> <span style="color:blue;">public</span> <span style="color:blue;">void</span> handle(IPath path);<br />}<br /></pre><br />And the IDropHandlerInspector as follows:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><span style="color:blue;">package</span> <span style="color:olive;">org</span>.eclipse.ui.ide.<span style="color:olive;">dnd</span>;<br /><br /><span style="color:blue;">import</span> <span style="color:olive;">org</span>.eclipse.core.runtime.IPath;<br /><br /><span style="color:green;">/**<br />* Interface implemented by a dropSupport extension point to<br />* handle a file or folder dropped on the workbench.<br />*<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">interface</span> IDropHandlerInspector {<br /><br /> <span style="color:green;">/**Returns true or false whether a handler support the type<br /> * of file or folder that was dropped on the workbench.<br /> * @param path The full absolute path of the file or folder dropped.<br /> * @return true if the handler support handling the file or folder pointer by path, false otherwise.<br /> */</span><br /> <span style="color:blue;">public</span> <span style="color:blue;">boolean</span> handles(IPath path);<br />}<br /></pre><br /><h4>Conclusion</h4><br /><div>We hope that our improvements can be useful to other Eclipse users, and welcome your comments, questions and criticisms!</div><div><br /></div><div>Our changes are freely available in the following Eclipse bug report, and we hope to be able to contribute the changes back to the Eclipse standard distribution:</div><br /></div><div><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=248462">https://bugs.eclipse.org/bugs/show_bug.cgi?id=248462</a><br /></div><div><br />That contains a patch with the implementation of our drag and drop feature improvement.<br /></div>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-34768134384566484952008-09-22T03:49:00.000-07:002008-10-02T02:10:06.459-07:00Improving Linked Resources in Ganymede - API ChangesFollowing up on the <a href="http://sergebeauchamp.blogspot.com/2008/09/improving-linked-resources-in-gandymede.html">last post</a> describing the user level changes of our linked resource improvements in Ganymede, I will now go over the underlying API changes.<br /><br />A important requirement of the implementation of the linked resources improvement was to keep the resource API fully backward compatible: All code previously using the core.resources API should work just fine without any changes.<br /><br />This is very critical, since so many plugins depend on the core.resources framework that breaking any contract would be unworkable.<br /><h4> Core Resources </h4>The first change is the IResource.setLocation() methods as shown below:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><span style="color:blue;">class</span> IResource […]<br /><span style="color:green;">/**<br />* Sets the value of the link location for a linked resource.<br />*<br />* @param location<br />* the new location of the target link resource<br />* @param updateFlags<br />* bit-wise or of update flag constants ({@link #FORCE},<br />* {@link #KEEP_HISTORY}, {@link #SHALLOW},<br />* {@link #BACKGROUND_REFRESH} and {@link #REPLACE}).<br />* @param monitor<br />* a progress monitor, or <code>null</code> if progress<br />* reporting is not desired<br />* @exception CoreException<br />* if isLinked() returns false.<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">void</span> setLinkLocation(URI location, <span style="color:blue;">int</span> updateFlags, IProgressMonitor monitor) <span style="color:blue;">throws</span> CoreException;<br /><br /><span style="color:green;">/**<br />* Sets the value of the link location for a linked resource.<br />*<br />* @param location<br />* the new location of the target link resource<br />* @param updateFlags<br />* bit-wise or of update flag constants ({@link #FORCE},<br />* {@link #KEEP_HISTORY}, {@link #SHALLOW},<br />* {@link #BACKGROUND_REFRESH} and {@link #REPLACE}).<br />* @param monitor<br />* a progress monitor, or <code>null</code> if progress<br />* reporting is not desired<br />* @exception CoreException<br />* if isLinked() returns false.<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">void</span> setLinkLocation(IPath location, <span style="color:blue;">int</span> updateFlags, IProgressMonitor monitor) <span style="color:blue;">throws</span> CoreException;<br />}<br /></pre>As documented above, the IResource.setLocation() methods allow changing a linked resource location. The notifiers are then fired appropriatly, so that the UI is automatically updated when a location changes.<br /><br />Second, since each project now has its own IPathVariableManager, its definition has been updated with the following methods:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><span style="color:blue;">class</span> IProject […]<br /><br /><span style="color:green;">/**<br />* Returns the path variable manager for this project.<br />*<br />* @return the path variable manager<br />* @see IPathVariableManager<br />*/</span><br /><span style="color:blue;">public</span> IPathVariableManager getPathVariableManager();<br /><br /><span style="color:green;">/**<br />* Returns a variable relative path equivalent to an absolute path for a<br />* file or folder in the file system, according to the variables defined in<br />* this project PathVariableManager. The file or folder need not to exist.<br />* <p><br />*<br />* @param location<br />* a path in the local file system<br />* @return the corresponding variable relative path, or <code>null</code><br />* if no such path is available<br />*/</span><br /><span style="color:blue;">public</span> IPath getVariableRelativePathLocation(IPath location);<br /></pre>The method getVariableRelativePathLocation() will converts paths such as "C:\foo\bar.c" into "FOO\bar.c", granted than the path variable FOO exists already in the project PathVariableManager and it points to "C:\foo".<br /><br />A more powerful method is the one available in the IPathVariableManager:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><span style="color:blue;">class</span> IPathVariableManager […]<br /><br /><span style="color:green;">/** Convert an absolute path to path variable relative path.<br />* For example, converts "C:/foo/bar.txt" into "FOO/bar.txt",<br />* granted that the path variable "FOO" value is "C:/foo".<br />*<br />* The "force" argument allows intermediate path variable to<br />* be created if for a given path can be relative only to a parent<br />* of an existing path variable.<br />*<br />* For example, if the path "C:/other/file.txt" is to be converted<br />* and no path variables point to "C:/" or "C:/other" but "FOO"<br />* points to "C:/foo", an intermediate "OTHER" variable will be<br />* created relative to "FOO" containing the value "${PARENT-1-FOO}"<br />* so that the final path returned will be "OTHER/file.txt".<br />*<br />* The argument "variableHint" can be used to specify to which<br />* path variable the path should be made relative to.<br />*<br />* @param path The absolute path to be converted<br />* @param force Set to true if intermediate path variables need to be created if the path is relative only to a parent of an existing path variable.<br />* @param variableHint The name of the variable to which the path should be relative to, or null for the nearest one.<br />* @return The converted path<br />* @exception CoreException if this method fails. Reasons include:<br />* <ul><br />* <li>The variable name is not valid</li><br />*/</span><br /><span style="color:blue;">public</span> IPath convertToRelative(IPath path, <span style="color:blue;">boolean</span> force, <span style="color:olive;">String</span> variableHint) <span style="color:blue;">throws</span> CoreException;<br />}<br /></pre><br />Also, a new extension point "variableProviders" is available in the core.resources plugins that allows extending the default path variable list if need be.<br /><br />Variable providers can be pecified as follows:<br /><div class="xml xml" style="border: 1px solid rgb(208, 208, 208); font-family: courier new; font-size: 12px; color: rgb(0, 0, 102); background-color: rgb(240, 240, 240);"><extension<br /><br /> point="org.eclipse.core.resources.variableProviders"><br /><br /><variableProvider<br /><br /> class="org.myPackage.myPlugin.MyPathVariable"<br /><br /> name="MY_PATH_VARIABLE"><br /><br /></variableProvider><br /><br /></extension><br /></div>where "MyPathVariable" must inherit from the "IProjectVariableProvider", defined as follows:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden;font-family:courier new;font-size:12px;"><br /><span style="color:blue;">public</span> <span style="color:blue;">interface</span> IProjectVariableProvider {<br /><br /> <span style="color:green;">/**<br /> * Returns a variable value<br /> *<br /> * @param variable<br /> * The current variable name.<br /> * @param project<br /> * The project that the variable is being resolved for.<br /> * @return the variable value.<br /> */</span><br /> <span style="color:blue;">public</span> <span style="color:olive;">String</span> getValue(<span style="color:olive;">String</span> variable, IProject project);<br /><br /> <span style="color:green;">/**<br /> * If the variable supports extensions (specified as<br /> * "${VARNAME-EXTENSIONNAME}"), this method can return the list of possible<br /> * extensions, or null if none are supported.<br /> *<br /> * @param variable<br /> * The current variable name.<br /> * @param project<br /> * The project that the variable is being resolved for.<br /> * @return the possible variable extensions or null if none are supported.<br /> */</span><br /> <span style="color:blue;">public</span> <span style="color:olive;">Object</span>[] getExtensions(<span style="color:olive;">String</span> variable, IProject project);<br />}<br /></pre><br /><br /><h4>Groups</h4>Groups are seen by clients as a broken folder linked resource. Since groups do not exist on the file system, calling IResource.getLocation() returns null, just as broken folder linked resource do.<br /><br />All code that handle properly IResource.getLocation() returning null, as they should to support the possibility that a folder linked resource is not resolvable, will work transparently with groups as well.<br /><br />The groups API changes are as follow:<br /><pre style="padding: 0pt 0pt 20px; overflow-x: auto; overflow-y: hidden; font-family: courier new; font-size: 12px;"><span style="color:blue;">class</span> IFolder […]<br /><span style="color:green;">/**<br />* Creates a new group resource as a member of this handle's parent<br />* resource. A group is not located anywhere in the file system, and can<br />* contain only linked files, linked folders and other groups.<br />* <p><br />* This method changes resources; these changes will be reported in a<br />* subsequent resource change event, including an indication that the folder<br />* has been added to its parent.<br />* </p><br />* <p><br />* This method is long-running; progress and cancellation are provided by<br />* the given progress monitor.<br />* </p><br />*<br />* @param updateFlags<br />* bit-wise or of update flag constants (currently no flags are<br />* relevant here)<br />* @param monitor<br />* a progress monitor, or <code>null</code> if progress<br />* reporting is not desired<br />* @exception CoreException<br />* if this method fails. Reasons include:<br />* <ul><br />* <li> This resource already exists in the workspace.</li><br />* <li> The workspace contains a resource of a different type<br />* at the same path as this resource.</li><br />* <li> The parent of this resource does not exist.</li><br />* <li> The parent of this resource is not an open project</li><br />* <li> The name of this resource is not valid (according to<br />* <code>IWorkspace.validateName</code>).</li><br />* <li> Resource changes are disallowed during certain types<br />* of resource change event notification. See<br />* <code>IResourceChangeEvent</code> for more details.</li><br />* <li>The team provider for the project which contains this<br />* folder does not permit groups.</li><br />* <li>This folder's project contains a nature which does<br />* not permit groups.</li><br />* </ul><br />* @exception OperationCanceledException<br />* if the operation is canceled. Cancelation can occur even<br />* if no progress monitor is provided.<br />* @see IResource#isGroup()<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">void</span> createGroup(<span style="color:blue;">int</span> updateFlags, IProgressMonitor monitor) <span style="color:blue;">throws</span> CoreException;<br /><br /><span style="color:blue;">class</span> IResource […]<br /><br /><span style="color:green;">/**<br />* Returns whether this resource is a group.<br />*<br />* @return <code>true</code> if this resource is a group, and<br />* <code>false</code> otherwise<br />* @see IFolder#createGroup(int, IProgressMonitor)<br />*/</span><br /><span style="color:blue;">public</span> <span style="color:blue;">boolean</span> isGroup();<br /></pre>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0tag:blogger.com,1999:blog-4308054958627207530.post-15700895282458079902008-09-17T08:53:00.000-07:002008-10-02T02:09:23.203-07:00Improving Linked Resources in GanymedeComing from a C/C++ developer background, moving to the Eclipse CDT tools can sometimes be challenging.<div><br /></div><div>C/C++ developers are used to work with standard IDE such as Microsoft Visual Studio and CodeWarrior, two products that have been designed from the start to be C/C++ IDEs.</div><div><br /></div><div>One area that is specific with developing in C/C++ is the source file layout. C/C++ source files are divided in headers and sources files, are often shared between projects, and have no rigid layout in the file system.</div><div><br /></div><div>Some teams group the C/C++ files by software component, some by framework, some by teams, and some by a bit of every division imaginable. C/C++ source trees end up being very complex, and it is of course out of the question to ask developers to structure their sources according to the way an IDE works, the IDE has to adapt itself to the way developers work!</div><div><br /></div><div>Eclipse's solution for creating arbitrarily complex project structure is using <i> linked resources</i>.</div><div><br /></div><div>Unfortunately, Eclipse's linked resources have the following limitations:</div><div><ul><br /><li>Linked resources tend to contain absolute paths, unless the workspace's path variables are used.</li><br /><li> When path variables are used to avoid using absolute paths, the variable list is maintained in the workspace only, and if the user switches workspace, the project becomes broken.</li><br /><li>The linked resource's targets can't be changed by the user in the workbench!</li><br /><li>Linked resources can't be specified as being in a parent directory relative to a path variable (i.e. "PROJECT_LOCATION/../../dir/foo.c").</li><br /><li>Creating linked resources is very time-consuming, the user has to create each single file one by one through the new file wizards.</li></ul></div><div>What we have done for our customers at Freescale is improve Eclipse's support for linked resources while maintaining full compatibility with standard Eclipse IDEs.</div><div><br /></div><div>We can divide our improvements in 4 different sections:<br /><h4>Project Path Variable Manager</h4></div><div>The first improvement consists of creating a IPathVariableManager implementation in each project, analogous to the one at the workspace level.</div><div><br /><p align="center"><a href="http://s361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/?action=view&current=Project_linked_resources.png" target="_blank"><img src="http://i361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/Project_linked_resources-small.png" border="0" alt="Project Linked Resources" /></a></p><br /></div><div>Then, the path variable list is extensible through an extension point, which allows default variable to be specified (such as PROJECT_LOCATION, ECLIPSE_HOME, etc...) and custom variable to be provided by 3rd party plugins.</div><div><br /></div><div>For instance, a StarCore tool plugin may want to expose its SDK root as a path variable, so that each project can contain sources from the SDK, while having the source locations always pointing to the correct location.</div><div><br /></div><div>A dialog has been added to handle <b>drag and drop </b> of files in the project, so the user can easily and quickly create a path variable relative project structure.</div><div><p align="center"><a href="http://s361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/?action=view&current=drag_and_drop.png" target="_blank"><img src="http://i361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/drag_and_drop-small.png" border="0" alt="Drag and Drop dialog" /></a></p></div><div>Special path variables are provided, such as "PARENT" which allows path variables to be specified as relative to the parent directory of another variable, effectively allowing arbitrarily complex project structure to be specified while keeping the project fully portable across computers, or "ENV" which allows linked resources to be relative to environment variables.</div><div><br /></div><div>Since each project has its own PathVariableManager, special care had to be taken to be sure that copying linked resources that contain path variables between different projects causes the proper path variables to be copied as well.</div><div><br /></div><div>Also, the user can now change the linked resource target in the file property page.</div><br /><p align="center"><a href="http://s361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/?action=view&current=file_property.png" target="_blank"><img src="http://i361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/file_property-small.png" border="0" alt="File Properties" /></a></p><div><h4>Groups</h4></div><p align="center"><a href="http://s361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/?action=view&current=grouptree.png" target="_blank"><img src="http://i361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/grouptree.png" border="0" alt="Group_tree" /></a></p><div>C/C++ developers are used to group source and header files differently than they are structured on the file system. In Visual Studio, the user can create filters in a solution, while with CodeWarrior, groups can be created. In Eclipse, the user has currently no choice but to create a set of empty directories, which is then cumbersome to maintain in a source repository and awkward to use.</div><div><br /></div><div>For that purpose, we have added support for <i>groups </i>in Eclipse that the user can easily create anywhere in a project. A group works just like a folder, and is fully compatible with the existing core.resources API and all its clients, the only difference between a group and a folder is that:</div><ul><br /><li> Groups are not created on the file system, they are instead recorded in the .project file. </li><br /><li>Only linked resources and groups can be created under a group, no real files or folder can, since a group is only a virtual container.</li></ul><div>Internally, groups are implemented as folder linked resources.<h4>Additional features</h4></div><div>We have also provided a dialog that allows the user to list all the linked resources in a project and easily manage them.</div><div><br /><p align="center"><a href="http://s361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/?action=view¤t=tool-1.png" target="_blank"><img src="http://i361.photobucket.com/albums/oo55/sergebeauchamp/Linked_Resources/tool-small.png" border="0" alt="Edit Linked Resources"></a></p><br /></div><div>The user can automatically convert absolute path linked resources to path variable relative, and fix broken linked resources.</div><div><br /></div><div>We hope that our improvements can be useful to other Eclipse users, and welcome your comments, questions and criticisms!</div><div><br /></div><div>Our changes are freely available in the following Eclipse bug report, and we hope to be able to contribute the changes back to the Eclipse standard distribution:</div><div><br /></div><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=229633">https://bugs.eclipse.org/bugs/show_bug.cgi?id=229633</a>Serge Beauchamphttp://www.blogger.com/profile/07166227267587165456noreply@blogger.com0