<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8145322922564078741</id><updated>2011-11-15T07:45:33.985-08:00</updated><title type='text'>Mike Schrag</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-7242846940439514773</id><published>2010-12-19T05:50:00.000-08:00</published><updated>2010-12-19T05:50:26.006-08:00</updated><title type='text'>Why The PS3 Drives Me Crazy</title><content type='html'>Let me lead with a compliment. The PS3 is an amazing piece of engineering. The possibilities for this device are huge, which makes its overall sucking that much more sad. The best of the PS3 games clearly surpass its other console competition. Uncharted 2, for instance, is like being inside of a movie -- I can't say enough about it.&lt;br /&gt;
&lt;br /&gt;
But that brings me to why I can't stand this device:&lt;br /&gt;
&lt;br /&gt;
* every time you turn it on it requires a system update&lt;br /&gt;
&lt;br /&gt;
* system updates block the entire UI ... oh you want to play a game? sitting for 10 minutes is pretty fun, too.&lt;br /&gt;
&lt;br /&gt;
* the store is organized in ridiculous ways. you can't find anything. want to see the highest rated game demos? instead, they give you "A-F" "G-M" categories.&lt;br /&gt;
&lt;br /&gt;
* buy something from the store. it doesn't download immediately. it brings you to a screen where you can decide to download it. bitch, i just spent $15 -- of course i want it now.&lt;br /&gt;
&lt;br /&gt;
* the sounds in the store are super annoying. every selection is a really high pitched "ping" and scrolling through a long list will drive you crazy.&lt;br /&gt;
&lt;br /&gt;
* the grid view in the store (which they use all over the place) has no linear navigation. you have to right, right, right, down, left, left, left, down, right, right ,right, down, left, left, left through it.&lt;br /&gt;
&lt;br /&gt;
* when you download something from the store, there's no direct way to see that it's actually doing it -- you go all the way back out of the store to the "Download Manager"&lt;br /&gt;
&lt;br /&gt;
* if you weren't sure it was downloading and clicked "download" more than once? yep .. you got it ... multiple concurrent downloads of the same fucking thing.&lt;br /&gt;
&lt;br /&gt;
* if you want to remove a download from the download manager, you'd think "select it and then pick delete". instead when you select it, it takes you to a full screen that shows the icon and its file size. no options. if you go back out and instead hit the triangle button, THEN you get a menu of choices to "cancel" it.&lt;br /&gt;
&lt;br /&gt;
* once you download something, it's not ready to play. you have to select it and then "install" it. are you serious? why in the world would i download something and not want it automatically installed?&lt;br /&gt;
&lt;br /&gt;
* it's a total ui for nerds ... the FIRST menu item (after the login) is "settings," which has hundreds of advanced settings. why is that front-and-center? presumably after configuring it the first time, I never want to see this again.&lt;br /&gt;
&lt;br /&gt;
* playing a blu-ray movie is a fun experience, too. you put the disc in ... and you sit ... and nothing happens ... so you start looking around, and the choice to play the movie is labeled something like "Play BD-ROM"&lt;br /&gt;
&lt;br /&gt;
* the controls INSIDE a blu-ray movie are fantastic. there is no simple, common, controls ui -- it's every button you can possibly press in a tiny grid and you arrow over to the thing you want to press. i was pretty quickly lost in the controls trying to just navigate the menus reliably using the controller&lt;br /&gt;
&lt;br /&gt;
* speaking of the controller, it took them quite a while top put out a system update that made it so your controller didn't just drain its batteries if you leave it sitting without remember to turn each one off. i'm still not sure that's the default setting even now.&lt;br /&gt;
&lt;br /&gt;
* if you ever use the apps they provide in the "internet browser," you'll notice they're custom built for the PS3 and look TERRIBLE. them main menu labels on the youtube app don't fit in the buttons and all have ellipsis. it's BUILT for PS3. why would you custom build something that doesn't fit?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-7242846940439514773?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/7242846940439514773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=7242846940439514773' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7242846940439514773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7242846940439514773'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2010/12/why-ps3-drives-me-crazy.html' title='Why The PS3 Drives Me Crazy'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-4861458776444978071</id><published>2010-11-10T06:52:00.000-08:00</published><updated>2010-11-10T06:52:53.210-08:00</updated><title type='text'>Switching from Subversive back to Subclipse</title><content type='html'>If you switch from Subversive to Subclipse, you will find that projects that were attached to subversive in existing workspaces will not offer you the option to Team=&gt;Share... There are a couple workarounds for this:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Annoying and Tedious Way&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Before switching to Subclipse, Team=&gt;Disconnect your subversive projects&lt;/li&gt;
&lt;li&gt;Uninstall Subversive&lt;/li&gt;
&lt;li&gt;Install Subclipse&lt;/li&gt;
&lt;li&gt;Team=&gt;Share away&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;b&gt;Annoying but Simple Way&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Toss everything and check it back out again with Subclipse&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;b&gt;Atomic but Quick Way&lt;/b&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Uninstall Subversive&lt;/li&gt;
&lt;li&gt;Install Subclipse&lt;/li&gt;
&lt;li&gt;Quit eclipse&lt;/li&gt;
&lt;li&gt;Go to your workspace folder and run:&lt;br /&gt;
find .metadata/.plugins/org.eclipse.core.resources/.projects -name 'properties.index' -delete&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Restart eclipse&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-4861458776444978071?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/4861458776444978071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=4861458776444978071' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4861458776444978071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4861458776444978071'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2010/11/switching-from-subversive-back-to.html' title='Switching from Subversive back to Subclipse'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-5018928460445651941</id><published>2010-02-22T06:38:00.000-08:00</published><updated>2010-02-22T06:38:41.376-08:00</updated><title type='text'>Are Generic Methods evil?</title><content type='html'>&lt;p&gt;
Over the weekend I ran into an interesting design issue inside of ERRest. Java supports declaring generic methods that can perform a simple type inference:
&lt;/p&gt;

&lt;pre&gt;
public class NonGenericClass {
    public &lt;T&gt; T objectForKey(String key) { ... }
}
&lt;/pre&gt;

&lt;p&gt;
What this allows you to do is:
&lt;/p&gt;

&lt;pre&gt;
Person p = new NonGenericClass().objectForKey("person")
&lt;/pre&gt;

&lt;p&gt;
Notice that we don't have to cast to Person like you would if objectForKey returned Object. So ... is this bad form? The closest examples of Sun using type inference in the core libraries is Collections.emptyList(), which can give you a type-inferred List. The difference, though, is that this is an inherently safe operation. In the example above, that code is inherently unsafe. On the upside, your API becomes easier to use -- your users don't need to think about the cast. On the downside, you might say the API is misleading, implying that this operation is in some way typesafe when it clearly is not.
&lt;/p&gt;

&lt;p&gt;
I came to a happy place with it. My decision was that if this API is impossible to make type-safe (think ResultSet.getObject(String)), and if that's fairly obvious to the user of the API, then taking advantage of type inference is OK and will just save your API users time.
&lt;/p&gt;

&lt;p&gt;
One catch, by the way, is that javac appears to not like a double indirection of type inference:
&lt;/p&gt;

&lt;pre&gt;
public class ClassOne {
    public &lt;T&gt; T methodOne() {
        return ...;
    }
}

public class ClassTwo {
    public &lt;T&gt; T methodTwo() {
      return new ClassOne().methodOne(); // this is a compile error in javac
    }
}
&lt;/pre&gt;

&lt;p&gt;
For some reason, javac is not capable of returning an inferred type for a method call to a method that returns and inferred type. You have to cast to T:
&lt;/p&gt;

&lt;pre&gt;
public class ClassTwo {
    public &lt;T&gt; T methodTwo() {
      return (T)new ClassOne().methodOne(); // this makes javac happy
    }
}
&lt;/pre&gt;

&lt;p&gt;
Incidentally, the Eclipse compiler is fine with the first one and doesn't need the cast. I think this is a javac bug, personally.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-5018928460445651941?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/5018928460445651941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=5018928460445651941' title='39 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5018928460445651941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5018928460445651941'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2010/02/are-generic-methods-evil.html' title='Are Generic Methods evil?'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>39</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-2164727605713206869</id><published>2009-05-17T05:21:00.000-07:00</published><updated>2009-05-17T05:26:49.842-07:00</updated><title type='text'>Maclipse 3.4.2 Fixed ... More</title><content type='html'>&lt;p&gt;
You may have noticed that Java=&gt;Editor=&gt;Templates throws an exception with Maclipse ... That's because there is some code that presumes there is a non-null vertical scrollbar.  With Maclipse, we autohide scrollbars on Leopard, which causes an NPE in that code.  I avoided fixing this because it brought in an entirely new plugin that we had to hack, but it's just one line, so .. meh.. at this point, why stop now.
&lt;/p&gt;

&lt;p&gt;
So to prevent that exception, you will want to grab the Workbench Texteditor UI plugin provided in the links area.
&lt;/p&gt;

&lt;pre&gt;
cd /Developer/Applications/eclipse/plugins &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.swt.carbon.macosx_3.4.1.v3452b.jar &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.ui.workbench_3.4.2.M20090127-1700.jar &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.ui.workbench.texteditor_3.4.1.r341_v20080827-1100.jar
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-2164727605713206869?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/2164727605713206869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=2164727605713206869' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2164727605713206869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2164727605713206869'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/05/maclipse-342-fixed-more.html' title='Maclipse 3.4.2 Fixed ... More'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-7958772190356687657</id><published>2009-05-17T04:39:00.001-07:00</published><updated>2009-05-17T04:39:44.544-07:00</updated><title type='text'>Maclipse 3.4.2 Fixed</title><content type='html'>The build from last night was missing a MANIFEST.MF, so it wasn't exporting the plugin info properly.  I think this would only be a problem if you do plugin development, but regardless, you should grab the new build.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-7958772190356687657?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/7958772190356687657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=7958772190356687657' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7958772190356687657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7958772190356687657'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/05/maclipse-342-fixed.html' title='Maclipse 3.4.2 Fixed'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-4207577940755853133</id><published>2009-05-16T19:59:00.000-07:00</published><updated>2009-05-17T05:27:05.080-07:00</updated><title type='text'>Maclipse Eclipse 3.4.2 Updates</title><content type='html'>&lt;p&gt;
Maclipse has been updated with all the changes merged in from Eclipse 3.4.2 finally. Links on the right, same install process applies.
&lt;/p&gt;

&lt;pre&gt;
cd /Developer/Applications/eclipse/plugins &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.swt.carbon.macosx_3.4.1.v3452b.jar &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.ui.workbench_3.4.2.M20090127-1700.jar
&lt;/pre&gt;

&lt;p&gt;
You may also need to remove your eclipse configuration/org.eclipse.osgi/bundles folder (which contains the unjar'd SWT jnilibs).
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-4207577940755853133?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/4207577940755853133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=4207577940755853133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4207577940755853133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4207577940755853133'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/05/maclipse-eclipse-342-updates.html' title='Maclipse Eclipse 3.4.2 Updates'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-6830003080245194448</id><published>2009-01-21T14:40:00.000-08:00</published><updated>2009-01-21T14:41:59.186-08:00</updated><title type='text'>Never hashCode on a mutable value Revisited</title><content type='html'>In the "Never hashCode on a mutable value" post, I talked about the pitfalls of using a mutable value in your hashCode/equals computation.  Another subtle variant of this is using a Comparator for a mutable value in a TreeSet (or other similar data structures).  Because the set is sorted internally, and optimized based on that sort information, if you change the sorted value of one of your objects in the set, it can "disappear" if you attempt to .contains(..) check it later.  I wonder how many more of these stupid mistakes I'll find ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-6830003080245194448?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/6830003080245194448/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=6830003080245194448' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6830003080245194448'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6830003080245194448'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/01/never-hashcode-on-mutable-value.html' title='Never hashCode on a mutable value Revisited'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-3537334635267874255</id><published>2009-01-19T20:40:00.001-08:00</published><updated>2009-01-19T20:41:06.583-08:00</updated><title type='text'>Slow PS3 Wireless Connection</title><content type='html'>props to &lt;a href = "http://boardsus.playstation.com/playstation/board/message?board.id=psnetwork&amp;thread.id=168428"&gt;this guy&lt;/a&gt; ... if your PS3 wireless connection is ungodly slow, change your router from Mixed to G-Only.  it's stupid, but it was about a 10x speed boost (... back to normal, basically).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-3537334635267874255?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/3537334635267874255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=3537334635267874255' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3537334635267874255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3537334635267874255'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/01/slow-ps3-wireless-connection.html' title='Slow PS3 Wireless Connection'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-2663619760170522381</id><published>2009-01-19T15:30:00.000-08:00</published><updated>2009-01-19T15:32:35.282-08:00</updated><title type='text'>Open Type can't find your class?</title><content type='html'>I ran into an annoying case when switching frequently between workspaces and doing some really mean things to a couple of them with swapping out external frameworks repeatedly.  Somehow I managed to corrupt my type caches in Eclipse so that the Open Type dialog would just be missing some entries (which is REALLY annoying, I might add).  This would also manifest as java type completion not working for the missing classes.  Maybe there's a nice way in Eclipse to do this, but I couldn't find it, but you can toss your type caches.  Quit Eclipse, go to workspace/.metadata/.plugins/org.eclipse.jdt.core and remove *.index and savedIndexNames.txt.  When you restart Eclipse it will rebuild the entire type cache and life should be happy again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-2663619760170522381?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/2663619760170522381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=2663619760170522381' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2663619760170522381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2663619760170522381'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2009/01/open-type-cant-find-your-class.html' title='Open Type can&apos;t find your class?'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-1675266308732187810</id><published>2008-11-24T14:09:00.000-08:00</published><updated>2008-11-24T14:10:44.194-08:00</updated><title type='text'>JSEditor is gone, but not really</title><content type='html'>JSEditor disappeared from Adobe Labs and is not only available inside of Flex Builder, but it turns out that the install site is still there and is actually the same version included in Flex Builder.  You can add the install site:

http://download.macromedia.com/pub/labs/jseclipse/autoinstall/site.xml

and it will install.  You will probably need to set JSEditor to be your editor for *.js&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-1675266308732187810?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/1675266308732187810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=1675266308732187810' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1675266308732187810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1675266308732187810'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/11/jseditor-is-gone-but-not-really.html' title='JSEditor is gone, but not really'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-748503143356878738</id><published>2008-11-21T12:27:00.001-08:00</published><updated>2008-11-21T12:27:47.877-08:00</updated><title type='text'>Maclipse Eclipse 3.4.1 Updates</title><content type='html'>Maclipse has been updated with all the changes merged in from Eclipse 3.4.1 finally.  Links on the right, same install process applies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-748503143356878738?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/748503143356878738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=748503143356878738' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/748503143356878738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/748503143356878738'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/11/maclipse-eclipse-341-updates.html' title='Maclipse Eclipse 3.4.1 Updates'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-5917677575024715769</id><published>2008-11-20T13:00:00.003-08:00</published><updated>2008-11-20T13:02:19.417-08:00</updated><title type='text'>Never hashCode on a mutable value.</title><content type='html'>&lt;pre&gt;
public class Terrible {
 public static void main(String[] args) {
  HashSet&lt;Person&gt; people = new HashSet&lt;Person&gt;();
  Person originallyMike = new Person("Mike");
  people.add(originallyMike);
  System.out.println("Terrible.main: Contains Mike? " + people.contains(new Person("Mike")));
  System.out.println("Terrible.main: Changing stored name from Mike to Adam.");
  originallyMike._name = "Adam";
  System.out.println("Terrible.main: Contains Mike? " + people.contains(new Person("Mike")));
  System.out.println("Terrible.main: Contains Adam? " + people.contains(new Person("Adam")));

 }

 public static class Person {
  public String _name;

  public Person(String name) {
   _name = name;
  }

  @Override
  public int hashCode() {
   return _name.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
   return obj instanceof Person &amp;&amp; ((Person) obj)._name.equals(_name);
  }
 }
}
&lt;/pre&gt;

prints:
&lt;pre&gt;
Terrible.main: Contains Mike? true
Terrible.main: Changing stored name from Mike to Adam.
Terrible.main: Contains Mike? false
Terrible.main: Contains Adam? false
&lt;/pre&gt;

HashSet uses the hashcode of your object to select the bucket for your object.  If your hashCode changes, the object effectively disappears from the collection for the purposes of API calls like .contains(..).  So do yourself a favor and never use a mutable value in your .hashCode (which also, incidentally, means that you can't use a mutable value in your .equals(..) since those two methods are required to be mutually consistent).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-5917677575024715769?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/5917677575024715769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=5917677575024715769' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5917677575024715769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5917677575024715769'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/11/never-hashcode-on-mutable-value.html' title='Never hashCode on a mutable value.'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-6582402969595183293</id><published>2008-10-29T11:40:00.000-07:00</published><updated>2008-10-29T11:41:09.790-07:00</updated><title type='text'>Color is on the app store!</title><content type='html'>Enjoy!

&lt;a href = "http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=294562042&amp;mt=8"&gt;Color&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-6582402969595183293?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/6582402969595183293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=6582402969595183293' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6582402969595183293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6582402969595183293'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/10/color-is-on-app-store.html' title='Color is on the app store!'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-5925000749985136867</id><published>2008-10-18T07:55:00.000-07:00</published><updated>2010-08-07T13:26:48.232-07:00</updated><title type='text'>How does WOSwitchComponent actually work again?</title><content type='html'>(from the mailing list, but it really should have been a blog post :) )
&lt;p&gt;
jad WOSwitchComponent and walk through and explain to yourself why WOSwitchComponent doesn't show the same instance of a component for every session in your app, particularly given that there will only be one instance of a WOSwitchComponent on a given parsed page (meaning that if there's a WOSwitchComponent for an element in your Main component, there will only be ONE INSTANCE of WOSwitchComponent servicing that slot on the page for all of your users).  Prepare to get a much deeper understanding and appreciation of how WO works and how clever the original authors were.
&lt;/p&gt;

&lt;p&gt;
So the magic is WOComponentReference + WOComponentDefinition + WOComponent.  What happens is that when your template is parsed, it gets parsed into a bunch of WOComponentReferences.  If you understand WOAssociation, WOComponentReference is like the equivalent concept for components.  That is, you have a handle that says "I represent an AjaxInPlace with a set of bindings" but it's not a stateful instance, it just describes how you're going to use it.
&lt;/p&gt;

&lt;p&gt;
During parsing an entire tree of these is built up.  It represents your parsed template without state.  The sort of interesting part is that these things actually extend WODynamicElement, so they LOOK like components from the outside.
&lt;/p&gt;

&lt;p&gt;
What happens is, and this is the kind of neat and clever part, is that at runtime, you say pageWithName("MyPage").   You get a new instance of the top level component.  For each parsed element on the page (a WOComponentReference), the framework will walk down the tree and say "give me a stateful peer for this WOComponentReference for a component of this name, and use this set of bindings".  It's here, btw, that it can decide whether subcomponents get new instances or come from the shared pool.  Then the part that I DIDN'T know about -- the way these are connected is that the new instance of a child component is pushed into a dictionary in the WOComponent parent keyed off of element ID, so the framework can walk down the parsed tree and say to the parent, "give me your child component with the elementID x".  If this component has already been materialized, the component will hand back a subcomponent from its dictionary.  If one isn't there, it will make a new one and push it into the dictionary.  So this starts to make sense, now, why you always get a new top level component instance -- it's the root of the state tree.  There has to be a root node to hang all these stateful components off of.  The magic method for all of this is actually WOComponentDefinition._componentInstanceInContext(context), btw.
&lt;/p&gt;

&lt;p&gt;
So fundamentally, there's this stateless tree of elements that represents my entire parsed page and there's this stateful tree of WOComponent instances that represent the actual components of the page.  So in normal components, the structure of your page is basically predetermined -- you have a bunch of WOConditionals, WOStrings, AjaxInPlace's, etc, all in a tree and page state determines which path through this graph you take.  WOSwitchComponent, though, is a crazy twist on this.  WOSwitchComponent DYNAMICALLY determines its page structure -- that is, the "parsed side" is indeterminate for a WOSwitchComponent.  And if you look at WOSwitchComponent, this is exactly what it's doing.  When you ask for a "SomeComponent", the cache doesn't return to you a WOComponent of the class you asked for, but instead a WOComponentReference -- those stateless handles.  It's clever as hell.  When it needs the component to work on, it looks up the correct instance of WOComponent based on the reference that it has cached (that is shared by everyone!) by asking the context().component() for a child with the current elementID, and will make one if it doesn't exist.  So WOSwitchComponent takes advantage of this peer concept and basically builds this structure up itself on-the-fly.  When this clicked for me, it was a "woah .. that's really slick" moment.
&lt;/p&gt;

&lt;p&gt;
All of this finagling on my part was because I wanted to implement a new type of component that would allow you to, for instance, create a component on your page that would act like an "embedded page," where instead of having the result of invokeAction replace the entire page, it would instead just replace the embedded page component.  To do this, you have to muck with page structure on-the-fly, which is pretty similar to what WOSwitchComponent does, but changing over time.  So I just pulled up WOSwitchComponent and thought "I'll just base my code on this - -should be pretty easy" except that I looked at WOSwitchComponent and decided that it's impossible that it actually worked right :)  But it does, and I began my quest to find out how :)
&lt;/p&gt;

&lt;p&gt;
Incidentally, I THINK (haven't verified yet) that the third parameter to the constructor of a WODynamicElement, which I've always sort of wondered its exact purpose, is your stateless-parsed-element-peer.  So you're being handed the reference to your stateless equivalent in the parse tree.  This is my theory, at least.  This gives you access to the structure of your children components, which during the R-R loop can also be used to access the stateful peers, etc.
&lt;/p&gt;

&lt;p&gt;
So anyway ... That's the long story that probably nobody else cares about, but I think it's sort of a fascinating aspect of WO, because it's this crazy and clever underpinning that makes the entire framework function that I really had no idea about the inner workings of.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-5925000749985136867?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/5925000749985136867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=5925000749985136867' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5925000749985136867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5925000749985136867'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/10/how-does-woswitchcomponent-actually.html' title='How does WOSwitchComponent actually work again?'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-2853225993708933469</id><published>2008-10-09T22:57:00.000-07:00</published><updated>2008-10-09T22:59:43.520-07:00</updated><title type='text'>iPhone Layer Edge Antialiasing</title><content type='html'>Apply your rotation transform to that layer and look how beautiful it is in the simulator -- nicely antialiased rotated layer edges.  Drop it on the phone and you might be surprised to find that it looks like crap.  It turns out that layers don't have antialiased edges on the iPhone, so just keep that in mind if you're planning on using layer rotations, especially.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-2853225993708933469?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/2853225993708933469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=2853225993708933469' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2853225993708933469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2853225993708933469'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/10/iphone-layer-edge-antialiasing.html' title='iPhone Layer Edge Antialiasing'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-5705021313208870947</id><published>2008-10-09T22:22:00.000-07:00</published><updated>2008-10-09T23:01:56.946-07:00</updated><title type='text'>iPhone Image Benchmarks</title><content type='html'>&lt;p&gt;There are two functions you can call for encoding UIImages on the iPhone -- UIImageJPEGRepresentation and UIImagePNGRepresentation.  For my app, I was curious about the performance of the two image formats.  I ran some tests on JPEG with various compression qualities, PNG, and Simulator vs iPhone 3G on 2.1.&lt;/p&gt;

&lt;p&gt;The image tested was a 320x416 image (about 120k JPG @ max quality) of line drawing, repeated 10 times for each scenario and averaged.  For the writing tests, the images were encoded and then written to disk. For the reading tests, the image is read and then drawn to an offscreen bitmap to make sure the bytes were actually read off the drive.&lt;/p&gt;

&lt;p&gt;Note that q=0.0 is max compression, min quality; and q=1.0 is min compression, max quality.&lt;/p&gt;

&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;Simulator Writing&lt;/span&gt;
&lt;br/&gt;
jpg, q=0.000000, 0.018185 seconds avg
&lt;br/&gt;
jpg, q=1.000000, 0.017662 seconds avg
&lt;br/&gt;
png, 0.034456 seconds avg
&lt;/p&gt;

&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;Simulator Reading&lt;/span&gt;
&lt;br/&gt;
jpg @ q=0.000000, 0.005052 seconds avg
&lt;br/&gt;
jpg @ q=1.000000, 0.000838 seconds avg
&lt;br/&gt;
png, 0.021330 seconds avg
&lt;/p&gt;

&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;iPhone 3G 2.1 Writing&lt;/span&gt;
&lt;br/&gt;
jpg, q=0.000000, 0.255950 seconds avg
&lt;br/&gt;
jpg, q=1.000000, 0.265089 seconds avg
&lt;br/&gt;
png, 0.592170 seconds avg
&lt;/p&gt;

&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;iPhone 3G 2.1 Reading&lt;/span&gt;
&lt;br/&gt;
jpg @ q=0.000000, 0.138772 seconds avg
&lt;br/&gt;
jpg @ q=1.000000, 0.049013 seconds avg
&lt;br/&gt;
png, 0.065347 seconds avg
&lt;/p&gt;

&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;Conclusion&lt;/span&gt;
&lt;br/&gt;
In this test scenario, JPG writing is about 2.3 times faster than PNG writing on the 3G regardless of quality.  On the flip side, JPG reading at max quality is 1.3x faster than PNG, but 2.1x SLOWER than PNG at max compression.
&lt;/p&gt;

&lt;p&gt;So if we take the best quality comparison, JPG is 2x faster to write and 1.3x faster to read.  You'll have to compare image quality in your particular case, but JPG seems to win hands-down for me.&lt;/p&gt;

&lt;p&gt;You can also look at the comparisons between iPhone and Simulator and prove to yourself that you should definitely not use the simulator to judge anything about runtime performance of your app on the real device, which I don't guess anyone REALLY had to tell you.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-5705021313208870947?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/5705021313208870947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=5705021313208870947' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5705021313208870947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5705021313208870947'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/10/iphone-image-benchmarks.html' title='iPhone Image Benchmarks'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-7051178565844212268</id><published>2008-07-30T08:51:00.001-07:00</published><updated>2008-07-30T08:54:38.954-07:00</updated><title type='text'>Note for the New Version</title><content type='html'>&lt;p&gt;
There is a new Maclipse build that incorporates the disappearing cursor patch from the SWT guys (&lt;a href = "https://bugs.eclipse.org/bugs/show_bug.cgi?id=241671"&gt;https://bugs.eclipse.org/bugs/show_bug.cgi?id=241671&lt;/a&gt;) that will be in 3.4.1.
&lt;/p&gt;

&lt;p&gt;
The catch, though, is that it requires a patch to the jnilibs, which might break when you launch eclipse because the jnilibs are already "cached" in your bundles folder.  &lt;b&gt;If your Eclipse crashes right on startup, toss your "eclipse/configuration/org.eclipse.osgi/bundles" folder&lt;/b&gt;, which will cause it to unpack the jnilibs from the jar again at startup.  I may be able to set a custom version number in our SWT build to force this to happen, but at the moment, I didn't want to mess with it.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-7051178565844212268?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/7051178565844212268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=7051178565844212268' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7051178565844212268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7051178565844212268'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/note-for-new-version.html' title='Note for the New Version'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-4111851993345603687</id><published>2008-07-07T07:41:00.000-07:00</published><updated>2008-07-07T07:43:05.459-07:00</updated><title type='text'>SWT issue</title><content type='html'>&lt;p&gt;
If you grabbed the SWT plugin after I switched to github, grab it one more time.  When I imported into github, I rooted my branch at the R3_4_maintenance branch of SWT, but apparently that has all kinds of other commits in it (in particular some broken ones :) ).  I have since switched back to my original baseline of the v3448f version of SWT (which is what ships in 3.4):
&lt;/p&gt;

&lt;p&gt;
If you're following along at home, the new github link to my branch is:
&lt;/p&gt;

&lt;a href = "https://github.com/mschrag/maclipse_swt/commits/mschrag_v3448f"&gt;https://github.com/mschrag/maclipse_swt/commits/mschrag_v3448f&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-4111851993345603687?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/4111851993345603687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=4111851993345603687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4111851993345603687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4111851993345603687'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/swt-issue.html' title='SWT issue'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-8366155465296250207</id><published>2008-07-07T05:46:00.000-07:00</published><updated>2008-07-07T05:47:34.869-07:00</updated><title type='text'>Easy Jar Updating</title><content type='html'>&lt;p&gt;
From Anjo:
&lt;/p&gt;

&lt;p&gt;
cd /Applications/Eclipse/plugins &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.swt.carbon.macosx_3.4.0.v3448f.jar &amp;&amp; curl -O http://webobjects.mdimension.com/wolips/preview/org.eclipse.ui.workbench_3.4.0.I20080606-1300.jar
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-8366155465296250207?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/8366155465296250207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=8366155465296250207' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8366155465296250207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8366155465296250207'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/easy-jar-updating.html' title='Easy Jar Updating'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-8325110402130687124</id><published>2008-07-06T16:02:00.001-07:00</published><updated>2008-07-06T16:03:43.304-07:00</updated><title type='text'>All of Maclipse is on GitHub</title><content type='html'>&lt;p&gt;
The Equinox Executable plugin (which adds support for double-clickable eomodels opening in Entity Modeler, for instance)
&lt;/p&gt;

&lt;p&gt;
&lt;a href = "http://github.com/mschrag/maclipse_equinox_executable/commits/mschrag_R3_4_maintenance"&gt;http://github.com/mschrag/maclipse_equinox_executable/commits/mschrag_R3_4_maintenance&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
The Workbench UI plugin:
&lt;/p&gt;

&lt;p&gt;
&lt;a href = "http://github.com/mschrag/maclipse_ui_workbench/commits/mschrag_R3_4_maintenance"&gt;http://github.com/mschrag/maclipse_ui_workbench/commits/mschrag_R3_4_maintenance&lt;/a&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-8325110402130687124?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/8325110402130687124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=8325110402130687124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8325110402130687124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8325110402130687124'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/all-of-maclipse-is-on-github.html' title='All of Maclipse is on GitHub'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-1911411397897738250</id><published>2008-07-06T08:15:00.000-07:00</published><updated>2008-07-06T08:19:40.097-07:00</updated><title type='text'>Maclipse SWT on GitHub</title><content type='html'>&lt;p&gt;
I've imported the SWT CVS plugin history into GitHub and created a new branch "mschrag_R3_4_maintenance" where I'll be doing my Maclipse work.
&lt;/p&gt;

&lt;p&gt;
&lt;a href = "https://github.com/mschrag/maclipse_swt/commits/mschrag_R3_4_maintenance"&gt;https://github.com/mschrag/maclipse_swt/commits/mschrag_R3_4_maintenance&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I'm running a git cvsimport on the Eclipse workbench plugin now, then I will need to put up the Equinox plugin, and we'll be good to go.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-1911411397897738250?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/1911411397897738250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=1911411397897738250' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1911411397897738250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1911411397897738250'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/maclipse-swt-on-github.html' title='Maclipse SWT on GitHub'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-4611226886658674122</id><published>2008-07-05T13:17:00.000-07:00</published><updated>2008-11-13T11:00:40.737-08:00</updated><title type='text'>Who said "Scroll Bar Autohiding?"</title><content type='html'>&lt;p&gt;
The new build has a more mac-ish looking view menu that uses the standard Apple gear drop-down, and it has replacements for the maximize and minimize buttons that fit a little better with the new style.
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gRYgZfzU1BE/SG_XJFxDhxI/AAAAAAAAAIY/b-oSUINJU3w/s1600-h/Picture+2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_gRYgZfzU1BE/SG_XJFxDhxI/AAAAAAAAAIY/b-oSUINJU3w/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5219627044312418066" /&gt;&lt;/a&gt;

&lt;p&gt;
And more importantly, thanks to Greg Hulands via an Apple friend, we have scrollbar auto-hiding in the Carbon controls if you use Leopard!  This &lt;i&gt;really&lt;/i&gt; cleans up the look of the various views in Eclipse, I think.
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gRYgZfzU1BE/SG_W_qb_x4I/AAAAAAAAAIQ/tR4WbXXfp7E/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_gRYgZfzU1BE/SG_W_qb_x4I/AAAAAAAAAIQ/tR4WbXXfp7E/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5219626882357512066" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-4611226886658674122?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/4611226886658674122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=4611226886658674122' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4611226886658674122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/4611226886658674122'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/07/who-said-scroll-bar-autohiding.html' title='Who said &quot;Scroll Bar Autohiding?&quot;'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_gRYgZfzU1BE/SG_XJFxDhxI/AAAAAAAAAIY/b-oSUINJU3w/s72-c/Picture+2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-1115576506449193649</id><published>2008-06-30T06:40:00.000-07:00</published><updated>2008-11-13T11:00:41.330-08:00</updated><title type='text'>CCombo.  My arch nemesis.</title><content type='html'>&lt;p&gt;
CCombo is the emulated combo box that appears in Eclipse in, for instance, combos in table cell editors.  This widget constantly causes me problems throughout WOLips because it's one of the most glaringly non-native components in the SWT family.  Here are some pictures to illustrate:
&lt;/p&gt;

&lt;p&gt;
CCombo Closed:
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGjiz5Rbw4I/AAAAAAAAAHw/FUeBTRt9jdc/s1600-h/Picture+3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGjiz5Rbw4I/AAAAAAAAAHw/FUeBTRt9jdc/s320/Picture+3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217669549483869058" /&gt;&lt;/a&gt;

&lt;p&gt;
CCombo Opened:
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGjizx8qpZI/AAAAAAAAAH4/2YT_dJnH5QM/s1600-h/Picture+2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGjizx8qpZI/AAAAAAAAAH4/2YT_dJnH5QM/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217669547517715858" /&gt;&lt;/a&gt;

&lt;p&gt;
Native (Leopard) Closed:
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGji0H_ZPRI/AAAAAAAAAIA/6ADwTHs5WbE/s1600-h/Picture+4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGji0H_ZPRI/AAAAAAAAAIA/6ADwTHs5WbE/s320/Picture+4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217669553434737938" /&gt;&lt;/a&gt;

&lt;p&gt;
Native (Leopard) Opened:
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGji0BfK0GI/AAAAAAAAAII/8WbrxGjxtJQ/s1600-h/Picture+5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGji0BfK0GI/AAAAAAAAAII/8WbrxGjxtJQ/s320/Picture+5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217669551688962146" /&gt;&lt;/a&gt;

&lt;p&gt;
Notice that in the closed form, there's no designator that shows that it is a combo (the up/down arrow icon).  Currently there's not enough API in tables to add icons like this.  I haven't looked at what i would take to fix that.  In the open form, it's just all-sorts-a'-wrong.  It's not the Leopard window style, it doesn't have proper keyboard navigation like native.  Entity Modeler fixes some of this.  In fact, if you were to look at this control outside of Entity Modeler, the focus ring is offset incorrectly by several pixels as well (it hangs outside of its table cell by about 3 pixels).  Unfortunately, emulating is just never going to be right here.  We can get away with it for tabs, because there is no native tab widget (yet), but for combo's, there are just too many expectations.  I think the correct fix for this is to make CCombo a native widget on OS X, but currently C* widgets don't have native replacements (they are in the .custom instead of the .carbon package).
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-1115576506449193649?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/1115576506449193649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=1115576506449193649' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1115576506449193649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1115576506449193649'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/06/ccombo-my-arch-nemesis.html' title='CCombo.  My arch nemesis.'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_gRYgZfzU1BE/SGjiz5Rbw4I/AAAAAAAAAHw/FUeBTRt9jdc/s72-c/Picture+3.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-5449809102653401418</id><published>2008-06-29T17:20:00.000-07:00</published><updated>2008-11-13T11:00:42.271-08:00</updated><title type='text'>Maclipse</title><content type='html'>&lt;p&gt;
I've been working on custom SWT and Workbench plugins that look more Macish than the defaults.  After some discussion on the wolips list, I decided that ripping off Aperture would be a good way to go, because it comes the closest to showing samples of the layout widgets we need in Eclipse.
&lt;/p&gt;
&lt;p&gt;
Here are some screenshots (and links to an early preview download at the end):
&lt;/p&gt;

&lt;p&gt;
This screenshot shows the new CTabFolder/CTabItem.  The design is nearly pixel-for-pixel ripped off of Aperture.  Getting the view toolbars to layout properly in here took some hackery to ToolBar (because it doesn't, by default, support transparent backgrounds).
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gRYgZfzU1BE/SGgnm61c3zI/AAAAAAAAAHI/KuOP0snj-Yk/s1600-h/Picture+2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_gRYgZfzU1BE/SGgnm61c3zI/AAAAAAAAAHI/KuOP0snj-Yk/s320/Picture+2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217463717890678578" /&gt;&lt;/a&gt;

&lt;p&gt;
Here's the same screenshot, but with a middle tab selected.
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGgninSf0qI/AAAAAAAAAHA/TCunjqrhSbw/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGgninSf0qI/AAAAAAAAAHA/TCunjqrhSbw/s320/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217463643924320930" /&gt;&lt;/a&gt;

&lt;p&gt;
The close icon appears when you rollover the tab image.  This is nice because it keeps the layout fixed compared to Eclipse's default style, which shuffles around the left margin of tabs as you select and deselect them (to hide the close icon on unselected tabs).  I think this is the way FireFox works, as well.
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gRYgZfzU1BE/SGgpdYOLbnI/AAAAAAAAAHo/NNUfnxhSgGk/s1600-h/Picture+7.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_gRYgZfzU1BE/SGgpdYOLbnI/AAAAAAAAAHo/NNUfnxhSgGk/s320/Picture+7.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217465753003585138" /&gt;&lt;/a&gt;

&lt;p&gt;
The Sashes on Eclipse don't draw any drag handles.  Here we're showing that we now draw a drag handle (based on Aperture's style rather than the OS X standard "dot" drag handle).  If the Sash is less than 3 pixels, no handle is drawn.  If it's 3 or more, one is drawn, and if it's 5 or more, 2 are drawn.
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGgnsKWKfaI/AAAAAAAAAHQ/jsrhSWRwbhw/s1600-h/Picture+3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_gRYgZfzU1BE/SGgnsKWKfaI/AAAAAAAAAHQ/jsrhSWRwbhw/s320/Picture+3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217463807953763746" /&gt;&lt;/a&gt;

&lt;p&gt;
The CoolBar grabber has been changed from a rectangle to an Aperturish dotted line.
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGgny9ZiwZI/AAAAAAAAAHY/ekR5kAWhYB0/s1600-h/Picture+4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_gRYgZfzU1BE/SGgny9ZiwZI/AAAAAAAAAHY/ekR5kAWhYB0/s320/Picture+4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217463924737360274" /&gt;&lt;/a&gt;

&lt;p&gt;
And here's the full monty screenshot (toolbar hidden) ... 
&lt;/p&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gRYgZfzU1BE/SGgoXi0Kx_I/AAAAAAAAAHg/Qs23zIdBKt4/s1600-h/Picture+5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_gRYgZfzU1BE/SGgoXi0Kx_I/AAAAAAAAAHg/Qs23zIdBKt4/s320/Picture+5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5217464553256437746" /&gt;&lt;/a&gt;

&lt;p&gt;
There's still plenty more to do.  Most of the emulated widgets are very unmacish (CCombo being an egregious example that is very high on my hit list).  I'd like to get Eclipse using the unified toolbar window style as well, but just setting the flag doesn't cause it to render the unified look.  I'm guessing because top toolbar isn't registered as the window's actual toolbar (and instead is just a regular view inside the window).
&lt;/p&gt;
&lt;p&gt;
If you want to try this out, you can grab the binary build of the SWT and Workbench plugins from the WOLips build server and simply replace the corresponding jars in your plugins folder.  Note that these ONLY work on Eclipse 3.4 and they are &lt;b&gt;ALPHA QUALITY&lt;/b&gt; so make backups of your original plugin jars before replacing them!
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href = "http://webobjects.mdimension.com/wolips/preview/org.eclipse.swt.carbon.macosx_3.4.0.v3448f.jar"&gt;Maclipse SWT Plugin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href = "http://webobjects.mdimension.com/wolips/preview/org.eclipse.ui.workbench_3.4.0.I20080606-1300.jar"&gt;Maclipse Workbench Plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-5449809102653401418?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/5449809102653401418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=5449809102653401418' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5449809102653401418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/5449809102653401418'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/06/maclipse.html' title='Maclipse'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_gRYgZfzU1BE/SGgnm61c3zI/AAAAAAAAAHI/KuOP0snj-Yk/s72-c/Picture+2.png' height='72' width='72'/><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-2069733655538354230</id><published>2008-06-27T17:19:00.000-07:00</published><updated>2008-06-29T17:20:43.637-07:00</updated><title type='text'>WALL•E</title><content type='html'>Go see it.  That is all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-2069733655538354230?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/2069733655538354230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=2069733655538354230' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2069733655538354230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/2069733655538354230'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/06/walle.html' title='WALL•E'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-6958233363493828093</id><published>2008-05-05T16:52:00.000-07:00</published><updated>2008-05-05T16:56:25.911-07:00</updated><title type='text'>EOGlobalIDs for Abstract Entities</title><content type='html'>&lt;p&gt;
I just got burned by this and it was a bitch to figure out.  I had an ERXBatchingDisplayGroup that was fetching an abstract entity type that used Single Table Inheritance.  It turns out that the way ERXBDG was fetching, it fetched the page of PK's, turned those into faults, then fired the faults.  The problem with this is that if you turn a PK into a fault for an abstract entity type (note that it just has the PK, so it doesn't know the actual subentity yet), EOF decides to fetch the object so it can resolve the entity name for the global id.  You'll see this as a bunch of one-by-one fetches in your log.  Needless to say this is total crap.
&lt;/p&gt;
&lt;p&gt;
It turns out that you can instead turn each PK into a GID directly with entity.globalIDForRow(pkDict).  Inside of EOGlobalID, it already tracks the concept of not knowing the final subclass type.  When you attempt to turn this global ID into an EO (using ERXGlobalIDUtilities, or whatever), EOF will properly fetch the objects and everyone will be happy.  The nice thing here is that ERXGIDUtils can batch those fetches into a single query so you don't get 40, 50, 100 (or whatever your page size is) hits to the DB.  This SEEMS like a bug in EOF to me, though I won't say that this won't totally burn me at some point.  (by "me," I mean "all of us" since this has now been changed in ERXBatchingDisplayGroup).
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-6958233363493828093?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/6958233363493828093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=6958233363493828093' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6958233363493828093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/6958233363493828093'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/05/eoglobalids-for-abstract-entities.html' title='EOGlobalIDs for Abstract Entities'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-7033959716163045423</id><published>2008-04-23T14:29:00.000-07:00</published><updated>2008-04-23T14:50:53.604-07:00</updated><title type='text'>ActiveLDAP</title><content type='html'>&lt;p&gt;
ActiveLDAP has some annoying install warts, but it's a pretty cool library.
&lt;/p&gt;

&lt;b&gt;Installing&lt;/b&gt;
&lt;p&gt;
First download and build &lt;a href = "http://sourceforge.net/project/showfiles.php?group_id=66444"&gt;RubyLDAP&lt;/a&gt;.  Annoyingly this is NOT a gem, so you can't gem install it.
&lt;/p&gt;

Next, build it ...
&lt;pre name="code" class="bash"&gt;
ruby extconf.rb
make
sudo make install
&lt;/pre&gt;

&lt;p&gt;
Now install ActiveLDAP ...
&lt;/p&gt;
&lt;pre name="code" class="bash"&gt;
sudo gem install ruby-activeldap
&lt;/pre&gt;

&lt;b&gt;Quick Start&lt;/b&gt;
&lt;p&gt;
Many of the examples are talking to a default openldap install.  If you want to talk to a Mac OS X Open Dircetory server, you will need to change the prefix for users and groups, shown below in a quick sample app:
&lt;/p&gt;

&lt;pre name="code" class="ruby"&gt;
#!/usr/bin/env ruby

require 'rubygems'
require 'active_ldap'

class Group &lt; ActiveLdap::Base
  ldap_mapping :dn_attribute =&gt; 'cn',
               :prefix =&gt; 'cn=groups',
               :classes =&gt; ['top', 'posixGroup'],
               :scope =&gt; :one
  has_many :members,
           :class =&gt; "User",
           :wrap =&gt; "memberUid",
           :primary_key =&gt; 'uid'
end

class User &lt; ActiveLdap::Base
  ldap_mapping :dn_attribute =&gt; 'uid',
               :prefix =&gt; 'cn=users',
               :classes =&gt; ['top','inetOrgPerson']
  belongs_to :groups,
             :class =&gt; 'Group',
             :many =&gt; 'memberUid'
end

ActiveLdap::Base.establish_connection(
  :host =&gt; 'someldapserver.mdimension.com',
  :port =&gt; 389,
  :base =&gt; 'dc=mdimension,dc=com',
  :bind_dn =&gt; "uid=mschrag,cn=mdimension,dc=com",
  :password =&gt; 'mschragpw',
  :allow_anonymous =&gt; false,
  :try_sasl =&gt; false
)

#Group.find(:all, '*').each do |group|
  #puts "#{group.cn}"
  #group.members.each do |member|
    #puts "  #{member.cn}"
  #end
#end

user = User.find('mschrag');
user.givenName = 'NewFirstName'
user.save
&lt;/pre&gt;

And that's the quick start.  It should give you enough to experiment with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-7033959716163045423?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/7033959716163045423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=7033959716163045423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7033959716163045423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/7033959716163045423'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/04/activeldap.html' title='ActiveLDAP'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-8063339206239651912</id><published>2008-03-29T14:24:00.000-07:00</published><updated>2008-03-29T14:29:58.727-07:00</updated><title type='text'>git-cvsimport failure</title><content type='html'>&lt;p&gt;
I've been mirroring Project Wonder's CVS with &lt;a href = "http://www.github.com/mschrag/projectwonder"&gt;github&lt;/a&gt;, and unfortunately git-cvsimport has been a real problem.  If I try to run it directly on the repository, I get:
&lt;/p&gt;

&lt;pre&gt;
git-cvsimport: fatal: cvsps reported error 11
&lt;/pre&gt;

&lt;p&gt;
... which is really helpful.  Well it turns out that you can run cvsps outside of git-cvsimport and get this all to work.  Here's roughly what you need to do:
&lt;/p&gt;

&lt;pre&gt;
export CVSROOT=[your cvsroot]
cvsps -x --norc -u -A [your cvsmodule] &gt; /tmp/cvsps.out
cd /path/to/your/git/repos
git-cvsimport -o git_cvs_head_branch_name -P /tmp/cvsps.out [your cvsmodule]
&lt;/pre&gt;

So in my case, I do:
&lt;pre&gt;
export CVSROOT=/local/wonder/cvs
cvsps -x --norc -u -A Wonder &gt; /tmp/cvsps.out
cd /local/wonder/git
git-cvsimport -o Wonder_HEAD_Branch -P /tmp/cvsps.out Wonder
&lt;/pre&gt;

&lt;p&gt;
The key here is that we run cvsps manually, saving its output, then run git-cvsimport with a -P passing it the name of the cvsps output.  This allows us to manually ignore cvsps errors rather than have them kill git-cvsimport.
&lt;/p&gt;
&lt;p&gt;
Note that by default gitcvs-import will use "master" as your head branch, which can cause problems with later merges.  It's best to keep all CVS branches in their own git branch and don't touch them except with git-cvsimport.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-8063339206239651912?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/8063339206239651912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=8063339206239651912' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8063339206239651912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8063339206239651912'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/git-cvsimport-failure.html' title='git-cvsimport failure'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-1516301483579328438</id><published>2008-03-29T10:18:00.001-07:00</published><updated>2008-03-29T10:19:25.593-07:00</updated><title type='text'>VS 2008</title><content type='html'>Visual Studio 2008 has some really slick features ... &lt;a href = "http://blogs.msdn.com/brada/archive/2008/03/06/mix08-session-overview-building-great-ajax-applications-from-scratch-using-asp-net-3-5-and-visual-studio-2008.aspx"&gt;Check out&lt;/a&gt; the Javascript interpreter stuff in particular.  I plan to steal liberally from this for WOLips.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-1516301483579328438?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/1516301483579328438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=1516301483579328438' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1516301483579328438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1516301483579328438'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/vs-2008.html' title='VS 2008'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-1855649070612690979</id><published>2008-03-29T10:14:00.000-07:00</published><updated>2008-11-13T11:00:42.767-08:00</updated><title type='text'>Handy shell things</title><content type='html'>stick these in your ~/.bash_profile:

&lt;pre name="code" class="bash"&gt;
alias grep='grep --color=auto'
function ps() {
 /bin/ps $* | sed -E $'s#[0-9]+#\e[31m&amp;\e[0m#'
}
&lt;/pre&gt;

The grep one will make your grep matches change color, which makes it a lot easier to find in a line.  The ps one makes the pid turn red, which is really useful if you have processes with really long commandlines (like a WO app):

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_gRYgZfzU1BE/R-55pTNmPEI/AAAAAAAAAFQ/QC7byf6rJH0/s1600-h/Picture+1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_gRYgZfzU1BE/R-55pTNmPEI/AAAAAAAAAFQ/QC7byf6rJH0/s400/Picture+1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5183213971588922434" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-1855649070612690979?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/1855649070612690979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=1855649070612690979' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1855649070612690979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/1855649070612690979'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/handy-shell-things.html' title='Handy shell things'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_gRYgZfzU1BE/R-55pTNmPEI/AAAAAAAAAFQ/QC7byf6rJH0/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-8601804053236250759</id><published>2008-03-29T10:11:00.000-07:00</published><updated>2008-03-29T10:13:41.638-07:00</updated><title type='text'>LDAP EOF Adaptor</title><content type='html'>A word of warning if you're working with LDAP/JNDI and creating EOModels on them.  LDAP supports multi-value attributes, which means you could have, for instance, multiple "uid"'s (Apple provides for multiple "short names", for instance).  In your EOModel, you should be careful about how you define the types of these values.  If there is one value, it will return a String.  If there are multiple values, it will return an NSArray&lt;String&gt;, so you should declare the value type to be "java.lang.Object" and check for what you're getting back when you call the method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-8601804053236250759?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/8601804053236250759/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=8601804053236250759' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8601804053236250759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/8601804053236250759'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/ldap-eof-adaptor.html' title='LDAP EOF Adaptor'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-3810733526218919450</id><published>2008-03-29T10:08:00.000-07:00</published><updated>2008-03-29T10:09:11.841-07:00</updated><title type='text'>Apache Directory Studio</title><content type='html'>&lt;a href = "http://directory.apache.org/studio/"&gt;Apache Directory Studio&lt;/a&gt; -- actually "just worked" and is even sort of nice (I mean, for an Eclipse-based app).  Totally shocked.  So if you need an LDAP browser, check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-3810733526218919450?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/3810733526218919450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=3810733526218919450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3810733526218919450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3810733526218919450'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/apache-directory-studio.html' title='Apache Directory Studio'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8145322922564078741.post-3515796400645662529</id><published>2008-03-29T09:40:00.000-07:00</published><updated>2008-03-29T10:08:16.094-07:00</updated><title type='text'>JAAS + Kerberos Auth</title><content type='html'>&lt;p&gt;
After digging around for quite a while (the docs on this TOTALLY suck), if you need to do Kerberos authentication from your app with JAAS + 1.5:
&lt;/p&gt;

&lt;pre name="code" class="java"&gt;
package your.app;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

public class KerberosAuth {
 public static void main(String[] args) {
   String userName = "myuser@MYREALM.COM";
   char[] password = "mypassword".toCharArray();

   System.setProperty("java.security.auth.login.config", KerberosAuth.class.getResource("/kerberos.conf").toExternalForm());
   System.setProperty("java.security.krb5.realm", "MYREALM.COM");
   System.setProperty("java.security.krb5.kdc", "mykdc.MYREALM.COM");
   try {
     LoginContext lc = new LoginContext("primaryLoginContext", new UserNamePasswordCallbackHandler(userName, password));
     lc.login();
     System.out.println("KerberosAuth.main: " + lc.getSubject());
   }
   catch (LoginException le) {
     le.printStackTrace();
   }
 }

 public static class UserNamePasswordCallbackHandler implements CallbackHandler {
   private String _userName;
   private char[] _password;

   public UserNamePasswordCallbackHandler(String userName, char[] password) {
     _userName = userName;
     _password = password;
   }

   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
     for (Callback callback : callbacks) {
       if (callback instanceof NameCallback &amp;&amp; _userName != null) {
         ((NameCallback) callback).setName(_userName);
       }
       else if (callback instanceof PasswordCallback &amp;&amp; _password != null) {
         ((PasswordCallback) callback).setPassword(_password);
       }
     }
   }
 }
}
&lt;/pre&gt;

put kerberos.conf (in this example) inside your Sources folder with the contents:

&lt;pre name="code" class="java"&gt;
primaryLoginContext {
 com.sun.security.auth.module.Krb5LoginModule required client=true useTicketCache=false;
};
&lt;/pre&gt;

&lt;p&gt;
"java.security.auth.login.config" can map to a File or a URL.  Annoyingly it appears that it cannot map to the actual contents of the file -- it has to be loaded from a URL, which seems completely stupid to me (as does just about all of the JAAS/GSSAPI api's, which were clearly written by "cryptography engineers" and not "normal humans").
&lt;/p&gt;
&lt;p&gt;
I have not tried this against Active Directory, yet, just Open Directory ... I'll be trying Active Directory soon and post with info.  One thing that's actually pretty damn slick is that if you need this in a Java client application (i.e. non-web-app) you can set "useTicketCache=true" and it will actually use your Kerberos info from the OS ticket cache, which means it actually does proper single sign-on.  You can also combine this (which is what we plan to do) with SPNEGO using mod_krb5 on Apache.  So you can have mod_krb5 do SPNEGO auth (and just read the user info from the remote user header), and use this as a fall-back if the user is not using a SPNEGO-compatible browser.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8145322922564078741-3515796400645662529?l=mschrag.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mschrag.blogspot.com/feeds/3515796400645662529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8145322922564078741&amp;postID=3515796400645662529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3515796400645662529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8145322922564078741/posts/default/3515796400645662529'/><link rel='alternate' type='text/html' href='http://mschrag.blogspot.com/2008/03/jaas-kerberos-auth.html' title='JAAS + Kerberos Auth'/><author><name>Mike Schrag</name><uri>http://www.blogger.com/profile/07185879942719846837</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
